draupnir4all-web

git clone git://archive.git.mtrnord.blog/MTRNord/draupnir4all-web.git
Log | Files | Refs | README | LICENSE

heatmap.tsx (3424B)


      1 "use client"
      2 
      3 import { Calendar } from "lucide-react"
      4 
      5 export interface HeatmapDay {
      6   date: string
      7   count: number
      8 }
      9 
     10 interface HeatmapProps {
     11   data: HeatmapDay[]
     12   title: string
     13   colorIntensityLabel?: string
     14   className?: string
     15 }
     16 
     17 export function Heatmap({ data, title, colorIntensityLabel = "Activity", className = "" }: HeatmapProps) {
     18   // Get intensity color based on count
     19   const getColor = (count: number) => {
     20     if (count === 0) return "bg-gray-900"
     21     if (count < 3) return "bg-purple-950"
     22     if (count < 6) return "bg-purple-900"
     23     if (count < 9) return "bg-purple-800"
     24     return "bg-purple-600"
     25   }
     26 
     27   // Group data by week
     28   const weeks: HeatmapDay[][] = []
     29   let currentWeek: HeatmapDay[] = []
     30 
     31   // Process data to create weeks (7 days per week)
     32   data.forEach((day, index) => {
     33     currentWeek.push(day)
     34     if (currentWeek.length === 7 || index === data.length - 1) {
     35       weeks.push([...currentWeek])
     36       currentWeek = []
     37     }
     38   })
     39 
     40   return (
     41     <div className={`space-y-2 ${className}`}>
     42       <div className="flex items-center justify-between">
     43         <div className="flex items-center gap-2">
     44           <Calendar className="h-4 w-4 text-gray-400" />
     45           <h3 className="text-sm font-medium">{title}</h3>
     46         </div>
     47         <div className="flex items-center gap-1 text-xs text-gray-400">
     48           <span>Less</span>
     49           <div className="flex gap-1">
     50             <div className="h-3 w-3 rounded-sm bg-gray-900"></div>
     51             <div className="h-3 w-3 rounded-sm bg-purple-950"></div>
     52             <div className="h-3 w-3 rounded-sm bg-purple-900"></div>
     53             <div className="h-3 w-3 rounded-sm bg-purple-800"></div>
     54             <div className="h-3 w-3 rounded-sm bg-purple-600"></div>
     55           </div>
     56           <span>More</span>
     57         </div>
     58       </div>
     59 
     60       <div className="flex gap-2">
     61         {/* Days of week labels */}
     62         <div className="flex flex-col pr-2 text-xs text-gray-500">
     63           <div className="h-[18px] mb-[2px]">Mon</div>
     64           <div className="h-[18px] mb-[2px]">Tue</div>
     65           <div className="h-[18px] mb-[2px]">Wed</div>
     66           <div className="h-[18px] mb-[2px]">Thu</div>
     67           <div className="h-[18px] mb-[2px]">Fri</div>
     68           <div className="h-[18px] mb-[2px]">Sat</div>
     69           <div className="h-[18px]">Sun</div>
     70         </div>
     71 
     72         {/* Heatmap grid */}
     73         <div className="overflow-x-auto">
     74           <div className="flex gap-1 min-w-[650px]">
     75             {weeks.map((week, weekIndex) => (
     76               <div key={weekIndex} className="flex flex-col gap-[2px]">
     77                 {week.map((day, dayIndex) => (
     78                   <div
     79                     key={`${weekIndex}-${dayIndex}`}
     80                     className={`h-[18px] w-[18px] rounded-sm ${getColor(day.count)} transition-opacity hover:opacity-80 cursor-pointer`}
     81                     title={`${day.date}: ${day.count} ${colorIntensityLabel}`}
     82                   ></div>
     83                 ))}
     84               </div>
     85             ))}
     86           </div>
     87 
     88           {/* Month labels */}
     89           <div className="flex text-xs text-gray-500 mt-1 min-w-[650px]">
     90             {["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"].map((month, i) => (
     91               <div key={i} className="flex-1">
     92                 {month}
     93               </div>
     94             ))}
     95           </div>
     96         </div>
     97       </div>
     98     </div>
     99   )
    100 }