HeatmapCalendar
heatmapcalendar-1779379671883.tsx
'use client'
import { useState } from 'react'
const WEEKS = 26
const DAYS = 7
function randomActivity(): number {
const r = Math.random()
if (r < 0.3) return 0
if (r < 0.55) return 1
if (r < 0.75) return 2
if (r < 0.9) return 3
return 4
}
const DATA = Array.from({ length: WEEKS }, () => Array.from({ length: DAYS }, randomActivity))
const COLORS = ['rgba(255,255,255,0.06)', 'rgba(201,168,76,0.25)', 'rgba(201,168,76,0.5)', 'rgba(201,168,76,0.75)', '#C9A84C']
const MONTH_LABELS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']
const DAY_LABELS = ['', 'Mon', '', 'Wed', '', 'Fri', '']
export default function HeatmapCalendar() {
const [tooltip, setTooltip] = useState<{ text: string; x: number; y: number } | null>(null)
const total = DATA.flat().reduce((a, v) => a + v, 0)
const days = DATA.flat().filter(v => v > 0).length
return (
<div style={{ background: '#0D0D0D', border: '1px solid rgba(255,255,255,0.06)', borderRadius: 16, padding: 24, position: 'relative' }}>
<div style={{ color: '#F5F5F0', fontSize: 14, fontWeight: 600, marginBottom: 16 }}>
{total} contributions in the last 6 months
</div>
<div style={{ display: 'flex', gap: 24 }}>
{/* Day labels */}
<div style={{ display: 'grid', gridTemplateRows: `repeat(7, 12px)`, gap: 3, marginTop: 20 }}>
{DAY_LABELS.map((d, i) => (
<div key={i} style={{ color: 'rgba(255,255,255,0.3)', fontSize: 10, lineHeight: '12px', height: 12 }}>{d}</div>
))}
</div>
<div style={{ flex: 1 }}>
{/* Month labels */}
<div style={{ display: 'grid', gridTemplateColumns: `repeat(${WEEKS}, 12px)`, gap: 3, marginBottom: 6 }}>
{Array.from({ length: WEEKS }, (_, i) => (
<div key={i} style={{ color: 'rgba(255,255,255,0.3)', fontSize: 10, height: 12 }}>
{i % 4 === 0 && i < WEEKS ? MONTH_LABELS[Math.floor(i / 4)] : ''}
</div>
))}
</div>
{/* Grid */}
<div style={{ display: 'grid', gridTemplateColumns: `repeat(${WEEKS}, 12px)`, gridTemplateRows: `repeat(7, 12px)`, gap: 3 }}>
{Array.from({ length: WEEKS }, (_, w) =>
Array.from({ length: DAYS }, (_, d) => {
const v = DATA[w][d]
return (
<div key={`${w}-${d}`}
style={{ width: 12, height: 12, borderRadius: 2, background: COLORS[v], cursor: 'pointer', transition: 'opacity 0.15s' }}
onMouseEnter={e => setTooltip({ text: v === 0 ? 'No activity' : `${v} ${v === 1 ? 'component' : 'components'}`, x: e.clientX, y: e.clientY })}
onMouseLeave={() => setTooltip(null)} />
)
})
)}
</div>
{/* Legend */}
<div style={{ display: 'flex', alignItems: 'center', gap: 4, marginTop: 12, justifyContent: 'flex-end' }}>
<span style={{ color: 'rgba(255,255,255,0.3)', fontSize: 11 }}>Less</span>
{COLORS.map((c, i) => <div key={i} style={{ width: 12, height: 12, borderRadius: 2, background: c }} />)}
<span style={{ color: 'rgba(255,255,255,0.3)', fontSize: 11 }}>More</span>
</div>
</div>
</div>
{/* Stats */}
<div style={{ display: 'flex', gap: 20, marginTop: 16, flexWrap: 'wrap' }}>
<div style={{ color: 'rgba(255,255,255,0.4)', fontSize: 12 }}>Active days: <strong style={{ color: '#F5F5F0' }}>{days}</strong></div>
<div style={{ color: 'rgba(255,255,255,0.4)', fontSize: 12 }}>Best streak: <strong style={{ color: '#C9A84C' }}>12 days</strong></div>
<div style={{ color: 'rgba(255,255,255,0.4)', fontSize: 12 }}>Avg/week: <strong style={{ color: '#F5F5F0' }}>{(total / WEEKS).toFixed(1)}</strong></div>
</div>
{/* Tooltip */}
{tooltip && (
<div style={{ position: 'fixed', top: tooltip.y - 36, left: tooltip.x - 40, background: '#1a1a1a', border: '1px solid rgba(255,255,255,0.15)', borderRadius: 6, padding: '4px 10px', fontSize: 11, color: '#F5F5F0', pointerEvents: 'none', zIndex: 9999 }}>
{tooltip.text}
</div>
)}
</div>
)
}Component info
CategoryData Display
Frameworkreact
TierFREE
Views1
Copies0
About
GitHub-style contribution heatmap calendar with week labels, tooltip, and activity stats
More from Data Display
'use client'
import { useState, useRef, useCallback, useEffect } from 'react'
export default function ComparisonSlider() {
const [position, setPosition] = useState(50)
const [dragging, setDragging] = useState(false)
const containerRef = useRefComparisonSlider
Data Display
'use client'
import { useState } from 'react'
const events = [
{ id: 1, icon: '🚀', title: 'Wave 7 generation complete', desc: '57 new components published across 14 categories', time: '14:32', type: 'success', day: 'Today' },
{ id: 2, icon: '👥TimelineActivity
Data Display