github-contributions-ui 1.0.15 → 1.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.cjs +202 -171
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +196 -165
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +22 -6
- package/readme.md +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/GithubActivity.tsx"],"sourcesContent":[" \"use client\";\n export { default as GithubActivity } from \"./GithubActivity\";\n","\"use client\";\r\n\r\nimport { memo, useEffect, useState, useMemo } from \"react\";\r\n\r\ntype Theme = \"light\" | \"dark\" | \"blue\" | \"purple\";\r\n\r\ninterface Day {\r\n date: string;\r\n count: number;\r\n level: 0 | 1 | 2 | 3 | 4;\r\n}\r\n\r\ninterface Props {\r\n username: string;\r\n theme?: Theme;\r\n className?: string;\r\n}\r\n\r\nconst MONTHS = [\r\n \"Jan\",\r\n \"Feb\",\r\n \"Mar\",\r\n \"Apr\",\r\n \"May\",\r\n \"Jun\",\r\n \"Jul\",\r\n \"Aug\",\r\n \"Sep\",\r\n \"Oct\",\r\n \"Nov\",\r\n \"Dec\",\r\n];\r\nconst DAY_LABELS: Record<number, string> = { 1: \"Mon\", 3: \"Wed\", 5: \"Fri\" };\r\n\r\nconst CELL = 13;\r\nconst GAP = 3;\r\nconst STEP = CELL + GAP;\r\nconst DAY_COL_W = 30;\r\n\r\nconst LIGHT = [\"#ebedf0\", \"#9be9a8\", \"#40c463\", \"#30a14e\", \"#216e39\"];\r\nconst DARK = [\"#21262d\", \"#0e4429\", \"#006d32\", \"#26a641\", \"#39d353\"];\r\nconst BLUE = [\"#21262d\", \"#a3c9ff\", \"#5fa3ff\", \"#2f7bff\", \"#0b5cff\"];\r\nconst PURPLE = [\"#21262d\", \"#d8b4ff\", \"#c084fc\", \"#a855f7\", \"#7e22ce\"];\r\n\r\nconst COLOR_MAP: Record<Theme, string[]> = {\r\n light: LIGHT,\r\n dark: DARK,\r\n blue: BLUE,\r\n purple: PURPLE,\r\n};\r\n\r\nfunction toLevel(count: number): 0 | 1 | 2 | 3 | 4 {\r\n if (count === 0) return 0;\r\n if (count <= 3) return 1;\r\n if (count <= 6) return 2;\r\n if (count <= 9) return 3;\r\n return 4;\r\n}\r\n\r\nfunction buildGrid(\r\n dayMap: Map<string, Day>,\r\n year: number | \"last\",\r\n): (Day | null)[][] {\r\n let start: Date;\r\n let end: Date;\r\n\r\n if (year === \"last\") {\r\n end = new Date();\r\n start = new Date(end);\r\n start.setFullYear(start.getFullYear() - 1);\r\n start.setDate(start.getDate() + 1);\r\n } else {\r\n start = new Date(year, 0, 1);\r\n end =\r\n year === new Date().getFullYear() ? new Date() : new Date(year, 11, 31);\r\n }\r\n\r\n start.setDate(start.getDate() - start.getDay());\r\n\r\n const weeks: (Day | null)[][] = [];\r\n const cur = new Date(start);\r\n\r\n while (cur <= end) {\r\n const week: (Day | null)[] = [];\r\n for (let d = 0; d < 7; d++) {\r\n const iso = cur.toISOString().slice(0, 10);\r\n if (cur > end) week.push(null);\r\n else week.push(dayMap.get(iso) ?? { date: iso, count: 0, level: 0 });\r\n cur.setDate(cur.getDate() + 1);\r\n }\r\n weeks.push(week);\r\n }\r\n return weeks;\r\n}\r\n\r\nfunction monthLabels(grid: (Day | null)[][]) {\r\n const out: { label: string; col: number }[] = [];\r\n let last = -1;\r\n grid.forEach((week, i) => {\r\n const first = week.find(Boolean);\r\n if (!first) return;\r\n const m = new Date(first.date).getMonth();\r\n if (m !== last) {\r\n out.push({ label: MONTHS[m], col: i });\r\n last = m;\r\n }\r\n });\r\n return out;\r\n}\r\n\r\nfunction Tooltip({ day, x, y }: { day: Day; x: number; y: number }) {\r\n const label = new Date(day.date).toLocaleDateString(\"en-US\", {\r\n weekday: \"long\",\r\n year: \"numeric\",\r\n month: \"long\",\r\n day: \"numeric\",\r\n });\r\n return (\r\n <div\r\n className=\"gcu fixed z-50 pointer-events-none -translate-x-1/2 -translate-y-full px-2.5 py-1.5 rounded-md text-xs font-mono whitespace-nowrap shadow-xl bg-neutral-900 text-white\"\r\n style={{ left: x, top: y - 8 }}\r\n >\r\n <b>\r\n {day.count} contribution{day.count !== 1 ? \"s\" : \"\"}\r\n </b>{\" \"}\r\n · {label}\r\n </div>\r\n );\r\n}\r\n\r\nfunction Skeleton() {\r\n return (\r\n <div className=\"flex gap-[3px] animate-pulse opacity-40\">\r\n {Array.from({ length: 45 }).map((_, w) => (\r\n <div key={w} className=\"flex flex-col gap-[3px]\">\r\n {Array.from({ length: 7 }).map((_, d) => (\r\n <div\r\n key={d}\r\n className=\"w-[13px] h-[13px] rounded-[3px] bg-neutral-700\"\r\n />\r\n ))}\r\n </div>\r\n ))}\r\n </div>\r\n );\r\n}\r\n\r\n// ─── YearPill — fully inline styles, zero Tailwind dependency ─────────────────\r\ntype YearPillProps = { label: string; active: boolean; onClick: () => void };\r\n\r\nexport function YearPill({ label, active, onClick }: YearPillProps) {\r\n const [hovered, setHovered] = useState(false);\r\n\r\n const baseStyle: React.CSSProperties = {\r\n padding: \"2px 10px\",\r\n fontSize: 12,\r\n fontWeight: 500,\r\n borderRadius: 9999,\r\n border: \"none\",\r\n cursor: \"pointer\",\r\n transition: \"background-color 0.15s ease, color 0.15s ease\",\r\n userSelect: \"none\",\r\n outline: \"none\",\r\n // Active = white pill with dark text\r\n // Inactive = dark pill with muted text, slightly lighter on hover\r\n backgroundColor: active ? \"#ffffff\" : hovered ? \"#3f3f46\" : \"#262626\",\r\n color: active ? \"#000000\" : \"#ffffff\",\r\n };\r\n\r\n return (\r\n <button\r\n type=\"button\"\r\n onClick={onClick}\r\n style={baseStyle}\r\n onMouseEnter={() => setHovered(true)}\r\n onMouseLeave={() => setHovered(false)}\r\n >\r\n {label}\r\n </button>\r\n );\r\n}\r\n\r\n// ─── Main ─────────────────────────────────────────────────────────────────────\r\nfunction GithubActivity({ username, theme = \"dark\", className }: Props) {\r\n const STYLES = `\r\n .gcu .relative{position:relative}\r\n .gcu .absolute{position:absolute}\r\n .gcu .fixed{position:fixed}\r\n .gcu .z-50{z-index:50}\r\n .gcu .pointer-events-none{pointer-events:none}\r\n .gcu .flex{display:flex}\r\n .gcu .flex-col{flex-direction:column}\r\n .gcu .flex-wrap{flex-wrap:wrap}\r\n .gcu .items-center{align-items:center}\r\n .gcu .justify-start{justify-content:flex-start}\r\n .gcu .inline-block{display:inline-block}\r\n .gcu .w-full{width:100%}\r\n .gcu .w-\\\\[10px\\\\]{width:10px}\r\n .gcu .w-\\\\[13px\\\\]{width:13px}\r\n .gcu .h-\\\\[10px\\\\]{height:10px}\r\n .gcu .h-\\\\[13px\\\\]{height:13px}\r\n .gcu .h-\\\\[18px\\\\]{height:18px}\r\n .gcu .-translate-x-1\\\\/2{transform:translateX(-50%)}\r\n .gcu .-translate-y-full{transform:translateY(-100%)}\r\n .gcu .gap-\\\\[3px\\\\]{gap:3px}\r\n .gcu .gap-1{gap:0.25rem}\r\n .gcu .gap-1\\\\.5{gap:0.375rem}\r\n .gcu .gap-x-6{column-gap:1.5rem}\r\n .gcu .gap-y-1{row-gap:0.25rem}\r\n .gcu .mb-4{margin-bottom:1rem}\r\n .gcu .mt-3{margin-top:0.75rem}\r\n .gcu .mt-4{margin-top:1rem}\r\n .gcu .mr-1{margin-right:0.25rem}\r\n .gcu .ml-1{margin-left:0.25rem}\r\n .gcu .p-4{padding:1rem}\r\n .gcu .pt-3{padding-top:0.75rem}\r\n .gcu .pt-px{padding-top:1px}\r\n .gcu .pb-1{padding-bottom:0.25rem}\r\n .gcu .pr-1\\\\.5{padding-right:0.375rem}\r\n .gcu .px-2\\\\.5{padding-left:0.625rem;padding-right:0.625rem}\r\n .gcu .py-1\\\\.5{padding-top:0.375rem;padding-bottom:0.375rem}\r\n .gcu .rounded-\\\\[2px\\\\]{border-radius:2px}\r\n .gcu .rounded-\\\\[3px\\\\]{border-radius:3px}\r\n .gcu .rounded-md{border-radius:0.375rem}\r\n .gcu .rounded-xl{border-radius:0.75rem}\r\n .gcu .text-right{text-align:right}\r\n .gcu .text-\\\\[10px\\\\]{font-size:10px}\r\n .gcu .text-\\\\[11px\\\\]{font-size:11px}\r\n .gcu .text-xs{font-size:0.75rem}\r\n .gcu .text-sm{font-size:0.875rem}\r\n .gcu .font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace}\r\n .gcu .font-medium{font-weight:500}\r\n .gcu .font-semibold{font-weight:600}\r\n .gcu .select-none{-webkit-user-select:none;-ms-user-select:none;user-select:none}\r\n .gcu .whitespace-nowrap{white-space:nowrap}\r\n .gcu .overflow-x-auto{overflow-x:auto}\r\n .gcu .border{border-width:1px;border-style:solid;border-color:#262626}\r\n .gcu .border-neutral-800{border-color:#262626}\r\n .gcu .border-t{border-top-width:1px;border-top-style:solid;border-top-color:#262626}\r\n .gcu .transition-transform{transition-property:transform;transition-duration:0.1s;transition-timing-function:ease}\r\n @keyframes gcu-pulse{50%{opacity:.5}}\r\n .gcu .animate-pulse{animation:gcu-pulse 2s cubic-bezier(0.4,0,0.6,1) infinite}\r\n .gcu .hover\\\\:scale-125:hover{transform:scale(1.25)}\r\n .gcu .text-neutral-400{color:#9ca3af}\r\n .gcu .text-neutral-200{color:#e5e7eb}\r\n .gcu .bg-neutral-700{background-color:#3f3f46}\r\n .gcu .bg-neutral-900{background-color:#171717}\r\n .gcu .bg-neutral-950{background-color:#0a0a0a}\r\n .gcu .text-white{color:#fff}\r\n .gcu .shadow-xl{box-shadow:0 20px 25px -5px rgba(0,0,0,0.1),0 10px 10px -5px rgba(0,0,0,0.04)}\r\n `;\r\n\r\n useEffect(() => {\r\n if (typeof document === \"undefined\") return;\r\n const id = \"github-contributions-ui-inline\";\r\n if (document.getElementById(id)) return;\r\n const style = document.createElement(\"style\");\r\n style.id = id;\r\n style.textContent = STYLES;\r\n document.head.appendChild(style);\r\n }, []);\r\n\r\n const [allDays, setAllDays] = useState<Map<string, Day>>(new Map());\r\n const [years, setYears] = useState<number[]>([]);\r\n const [selectedYear, setSelectedYear] = useState<number | \"last\">(\"last\");\r\n const [total, setTotal] = useState<number | null>(null);\r\n const [bestDay, setBestDay] = useState<Day | null>(null);\r\n const [loading, setLoading] = useState(true);\r\n const [error, setError] = useState(false);\r\n const [tip, setTip] = useState<{ day: Day; x: number; y: number } | null>(\r\n null,\r\n );\r\n\r\n const colors = COLOR_MAP[theme] ?? COLOR_MAP.dark;\r\n\r\n useEffect(() => {\r\n if (!username) return;\r\n let mounted = true;\r\n\r\n (async () => {\r\n try {\r\n setLoading(true);\r\n const res = await fetch(\r\n `https://github-contributions-api.jogruber.de/v4/${username}?y=all`,\r\n );\r\n if (!res.ok) throw new Error();\r\n const json = await res.json();\r\n\r\n const map = new Map<string, Day>();\r\n const yearSet = new Set<number>();\r\n\r\n json.contributions.forEach((c: { date: string; count: number }) => {\r\n map.set(c.date, {\r\n date: c.date,\r\n count: c.count,\r\n level: toLevel(c.count),\r\n });\r\n yearSet.add(new Date(c.date).getFullYear());\r\n });\r\n\r\n if (!mounted) return;\r\n setAllDays(map);\r\n setYears(Array.from(yearSet).sort((a, b) => b - a));\r\n setError(false);\r\n } catch {\r\n if (mounted) setError(true);\r\n } finally {\r\n if (mounted) setLoading(false);\r\n }\r\n })();\r\n\r\n return () => {\r\n mounted = false;\r\n };\r\n }, [username]);\r\n\r\n useEffect(() => {\r\n if (!allDays.size) return;\r\n\r\n const entries = Array.from(allDays.values()).filter((d) => {\r\n if (selectedYear === \"last\") {\r\n const oneYearAgo = new Date();\r\n oneYearAgo.setFullYear(oneYearAgo.getFullYear() - 1);\r\n return new Date(d.date) >= oneYearAgo;\r\n }\r\n return new Date(d.date).getFullYear() === selectedYear;\r\n });\r\n\r\n setTotal(entries.reduce((s, d) => s + d.count, 0));\r\n const best = entries.reduce<Day | null>(\r\n (b, d) => (!b || d.count > b.count ? d : b),\r\n null,\r\n );\r\n setBestDay(best && best.count > 0 ? best : null);\r\n }, [allDays, selectedYear]);\r\n\r\n const grid = useMemo(\r\n () => (allDays.size ? buildGrid(allDays, selectedYear) : []),\r\n [allDays, selectedYear],\r\n );\r\n const labels = useMemo(() => monthLabels(grid), [grid]);\r\n const outlineColor = theme === \"light\" ? \"#333\" : \"#f0f0f0\";\r\n\r\n return (\r\n <section\r\n className={[\"gcu w-full font-mono\", className].filter(Boolean).join(\" \")}\r\n >\r\n {/* Stats */}\r\n <div className=\"flex flex-wrap items-center gap-x-6 gap-y-1 mb-4 text-xs text-neutral-400\">\r\n {loading\r\n ? \"Loading…\"\r\n : error\r\n ? \"Unavailable\"\r\n : `${total?.toLocaleString()} contributions ${selectedYear === \"last\" ? \"in the last year\" : `in ${selectedYear}`}`}\r\n\r\n {bestDay && !loading && (\r\n <span className=\"flex items-center gap-1.5\">\r\n <span\r\n className=\"inline-block w-[10px] h-[10px] rounded-[2px]\"\r\n style={{ backgroundColor: colors[4] }}\r\n />\r\n Best day:\r\n <span className=\"text-neutral-200 font-semibold\">\r\n {bestDay.count} contributions on {bestDay.date}\r\n </span>\r\n </span>\r\n )}\r\n </div>\r\n\r\n {/* Card */}\r\n <div className=\"border border-neutral-800 rounded-xl p-4 bg-neutral-950\">\r\n {error ? (\r\n <p className=\"text-sm text-neutral-400 italic\">\r\n GitHub activity unavailable.\r\n </p>\r\n ) : loading ? (\r\n <Skeleton />\r\n ) : (\r\n <>\r\n <div className=\"overflow-x-auto pb-1\">\r\n <div\r\n className=\"relative\"\r\n style={{ minWidth: grid.length * STEP + DAY_COL_W + 8 }}\r\n >\r\n {/* Month labels */}\r\n <div\r\n className=\"relative h-[18px] mb-1\"\r\n style={{ marginLeft: DAY_COL_W }}\r\n >\r\n {labels.map(({ label, col }) => (\r\n <span\r\n key={label + col}\r\n className=\"absolute text-[11px] text-neutral-400\"\r\n style={{ left: col * STEP }}\r\n >\r\n {label}\r\n </span>\r\n ))}\r\n </div>\r\n\r\n {/* Grid */}\r\n <div className=\"flex gap-[3px]\">\r\n <div\r\n className=\"flex flex-col gap-[3px]\"\r\n style={{ width: DAY_COL_W - GAP }}\r\n >\r\n {Array.from({ length: 7 }).map((_, i) => (\r\n <div\r\n key={i}\r\n className=\"h-[13px] text-[10px] text-right pr-1.5 text-neutral-400\"\r\n >\r\n {DAY_LABELS[i] ?? \"\"}\r\n </div>\r\n ))}\r\n </div>\r\n\r\n {grid.map((week, wi) => (\r\n <div key={wi} className=\"flex flex-col gap-[3px]\">\r\n {week.map((day, di) => (\r\n <div\r\n key={di}\r\n className=\"w-[13px] h-[13px] rounded-[3px] transition-transform hover:scale-125\"\r\n style={{\r\n backgroundColor: day\r\n ? colors[day.level]\r\n : \"transparent\",\r\n outline:\r\n bestDay && day?.date === bestDay.date\r\n ? `2px solid ${outlineColor}`\r\n : \"none\",\r\n outlineOffset: \"1px\",\r\n }}\r\n onMouseEnter={(e) => {\r\n if (!day) return;\r\n const r = e.currentTarget.getBoundingClientRect();\r\n setTip({ day, x: r.left + r.width / 2, y: r.top });\r\n }}\r\n onMouseLeave={() => setTip(null)}\r\n />\r\n ))}\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* Legend */}\r\n <div className=\"flex items-center gap-1 mt-3 text-[11px] text-neutral-400\">\r\n Less\r\n {colors.map((c, i) => (\r\n <div\r\n key={i}\r\n className=\"w-[13px] h-[13px] rounded-[3px]\"\r\n style={{ backgroundColor: c }}\r\n />\r\n ))}\r\n More\r\n </div>\r\n\r\n {/* Year selector */}\r\n <div className=\"flex flex-wrap items-center gap-1.5 mt-4 pt-3 border-t border-neutral-800\">\r\n <span className=\"text-[11px] text-neutral-400 mr-1\">Year:</span>\r\n <YearPill\r\n label=\"Last year\"\r\n active={selectedYear === \"last\"}\r\n onClick={() => setSelectedYear(\"last\")}\r\n />\r\n {years.map((y) => (\r\n <YearPill\r\n key={y}\r\n label={String(y)}\r\n active={selectedYear === y}\r\n onClick={() => setSelectedYear(y)}\r\n />\r\n ))}\r\n </div>\r\n </>\r\n )}\r\n </div>\r\n\r\n {tip && <Tooltip day={tip.day} x={tip.x} y={tip.y} />}\r\n </section>\r\n );\r\n}\r\n\r\nexport default memo(GithubActivity);\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEA,mBAAmD;AAwH7C;AAxGN,IAAM,SAAS;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AACA,IAAM,aAAqC,EAAE,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM;AAE1E,IAAM,OAAO;AACb,IAAM,MAAM;AACZ,IAAM,OAAO,OAAO;AACpB,IAAM,YAAY;AAElB,IAAM,QAAQ,CAAC,WAAW,WAAW,WAAW,WAAW,SAAS;AACpE,IAAM,OAAO,CAAC,WAAW,WAAW,WAAW,WAAW,SAAS;AACnE,IAAM,OAAO,CAAC,WAAW,WAAW,WAAW,WAAW,SAAS;AACnE,IAAM,SAAS,CAAC,WAAW,WAAW,WAAW,WAAW,SAAS;AAErE,IAAM,YAAqC;AAAA,EACzC,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,QAAQ;AACV;AAEA,SAAS,QAAQ,OAAkC;AACjD,MAAI,UAAU,EAAG,QAAO;AACxB,MAAI,SAAS,EAAG,QAAO;AACvB,MAAI,SAAS,EAAG,QAAO;AACvB,MAAI,SAAS,EAAG,QAAO;AACvB,SAAO;AACT;AAEA,SAAS,UACP,QACA,MACkB;AA9DpB;AA+DE,MAAI;AACJ,MAAI;AAEJ,MAAI,SAAS,QAAQ;AACnB,UAAM,oBAAI,KAAK;AACf,YAAQ,IAAI,KAAK,GAAG;AACpB,UAAM,YAAY,MAAM,YAAY,IAAI,CAAC;AACzC,UAAM,QAAQ,MAAM,QAAQ,IAAI,CAAC;AAAA,EACnC,OAAO;AACL,YAAQ,IAAI,KAAK,MAAM,GAAG,CAAC;AAC3B,UACE,UAAS,oBAAI,KAAK,GAAE,YAAY,IAAI,oBAAI,KAAK,IAAI,IAAI,KAAK,MAAM,IAAI,EAAE;AAAA,EAC1E;AAEA,QAAM,QAAQ,MAAM,QAAQ,IAAI,MAAM,OAAO,CAAC;AAE9C,QAAM,QAA0B,CAAC;AACjC,QAAM,MAAM,IAAI,KAAK,KAAK;AAE1B,SAAO,OAAO,KAAK;AACjB,UAAM,OAAuB,CAAC;AAC9B,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,YAAM,MAAM,IAAI,YAAY,EAAE,MAAM,GAAG,EAAE;AACzC,UAAI,MAAM,IAAK,MAAK,KAAK,IAAI;AAAA,UACxB,MAAK,MAAK,YAAO,IAAI,GAAG,MAAd,YAAmB,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,EAAE,CAAC;AACnE,UAAI,QAAQ,IAAI,QAAQ,IAAI,CAAC;AAAA,IAC/B;AACA,UAAM,KAAK,IAAI;AAAA,EACjB;AACA,SAAO;AACT;AAEA,SAAS,YAAY,MAAwB;AAC3C,QAAM,MAAwC,CAAC;AAC/C,MAAI,OAAO;AACX,OAAK,QAAQ,CAAC,MAAM,MAAM;AACxB,UAAM,QAAQ,KAAK,KAAK,OAAO;AAC/B,QAAI,CAAC,MAAO;AACZ,UAAM,IAAI,IAAI,KAAK,MAAM,IAAI,EAAE,SAAS;AACxC,QAAI,MAAM,MAAM;AACd,UAAI,KAAK,EAAE,OAAO,OAAO,CAAC,GAAG,KAAK,EAAE,CAAC;AACrC,aAAO;AAAA,IACT;AAAA,EACF,CAAC;AACD,SAAO;AACT;AAEA,SAAS,QAAQ,EAAE,KAAK,GAAG,EAAE,GAAuC;AAClE,QAAM,QAAQ,IAAI,KAAK,IAAI,IAAI,EAAE,mBAAmB,SAAS;AAAA,IAC3D,SAAS;AAAA,IACT,MAAM;AAAA,IACN,OAAO;AAAA,IACP,KAAK;AAAA,EACP,CAAC;AACD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,OAAO,EAAE,MAAM,GAAG,KAAK,IAAI,EAAE;AAAA,MAE7B;AAAA,qDAAC,OACE;AAAA,cAAI;AAAA,UAAM;AAAA,UAAc,IAAI,UAAU,IAAI,MAAM;AAAA,WACnD;AAAA,QAAK;AAAA,QAAI;AAAA,QACN;AAAA;AAAA;AAAA,EACL;AAEJ;AAEA,SAAS,WAAW;AAClB,SACE,4CAAC,SAAI,WAAU,2CACZ,gBAAM,KAAK,EAAE,QAAQ,GAAG,CAAC,EAAE,IAAI,CAAC,GAAG,MAClC,4CAAC,SAAY,WAAU,2BACpB,gBAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAACA,IAAG,MACjC;AAAA,IAAC;AAAA;AAAA,MAEC,WAAU;AAAA;AAAA,IADL;AAAA,EAEP,CACD,KANO,CAOV,CACD,GACH;AAEJ;AAKO,SAAS,SAAS,EAAE,OAAO,QAAQ,QAAQ,GAAkB;AAClE,QAAM,CAAC,SAAS,UAAU,QAAI,uBAAS,KAAK;AAE5C,QAAM,YAAiC;AAAA,IACrC,SAAS;AAAA,IACT,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,SAAS;AAAA;AAAA;AAAA,IAGT,iBAAiB,SAAS,YAAY,UAAU,YAAY;AAAA,IAC5D,OAAO,SAAS,YAAY;AAAA,EAC9B;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL;AAAA,MACA,OAAO;AAAA,MACP,cAAc,MAAM,WAAW,IAAI;AAAA,MACnC,cAAc,MAAM,WAAW,KAAK;AAAA,MAEnC;AAAA;AAAA,EACH;AAEJ;AAGA,SAAS,eAAe,EAAE,UAAU,QAAQ,QAAQ,UAAU,GAAU;AAvLxE;AAwLE,QAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoEf,8BAAU,MAAM;AACd,QAAI,OAAO,aAAa,YAAa;AACrC,UAAM,KAAK;AACX,QAAI,SAAS,eAAe,EAAE,EAAG;AACjC,UAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,UAAM,KAAK;AACX,UAAM,cAAc;AACpB,aAAS,KAAK,YAAY,KAAK;AAAA,EACjC,GAAG,CAAC,CAAC;AAEL,QAAM,CAAC,SAAS,UAAU,QAAI,uBAA2B,oBAAI,IAAI,CAAC;AAClE,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAmB,CAAC,CAAC;AAC/C,QAAM,CAAC,cAAc,eAAe,QAAI,uBAA0B,MAAM;AACxE,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAwB,IAAI;AACtD,QAAM,CAAC,SAAS,UAAU,QAAI,uBAAqB,IAAI;AACvD,QAAM,CAAC,SAAS,UAAU,QAAI,uBAAS,IAAI;AAC3C,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAS,KAAK;AACxC,QAAM,CAAC,KAAK,MAAM,QAAI;AAAA,IACpB;AAAA,EACF;AAEA,QAAM,UAAS,eAAU,KAAK,MAAf,YAAoB,UAAU;AAE7C,8BAAU,MAAM;AACd,QAAI,CAAC,SAAU;AACf,QAAI,UAAU;AAEd,KAAC,YAAY;AACX,UAAI;AACF,mBAAW,IAAI;AACf,cAAM,MAAM,MAAM;AAAA,UAChB,mDAAmD,QAAQ;AAAA,QAC7D;AACA,YAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM;AAC7B,cAAM,OAAO,MAAM,IAAI,KAAK;AAE5B,cAAM,MAAM,oBAAI,IAAiB;AACjC,cAAM,UAAU,oBAAI,IAAY;AAEhC,aAAK,cAAc,QAAQ,CAAC,MAAuC;AACjE,cAAI,IAAI,EAAE,MAAM;AAAA,YACd,MAAM,EAAE;AAAA,YACR,OAAO,EAAE;AAAA,YACT,OAAO,QAAQ,EAAE,KAAK;AAAA,UACxB,CAAC;AACD,kBAAQ,IAAI,IAAI,KAAK,EAAE,IAAI,EAAE,YAAY,CAAC;AAAA,QAC5C,CAAC;AAED,YAAI,CAAC,QAAS;AACd,mBAAW,GAAG;AACd,iBAAS,MAAM,KAAK,OAAO,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC,CAAC;AAClD,iBAAS,KAAK;AAAA,MAChB,QAAQ;AACN,YAAI,QAAS,UAAS,IAAI;AAAA,MAC5B,UAAE;AACA,YAAI,QAAS,YAAW,KAAK;AAAA,MAC/B;AAAA,IACF,GAAG;AAEH,WAAO,MAAM;AACX,gBAAU;AAAA,IACZ;AAAA,EACF,GAAG,CAAC,QAAQ,CAAC;AAEb,8BAAU,MAAM;AACd,QAAI,CAAC,QAAQ,KAAM;AAEnB,UAAM,UAAU,MAAM,KAAK,QAAQ,OAAO,CAAC,EAAE,OAAO,CAAC,MAAM;AACzD,UAAI,iBAAiB,QAAQ;AAC3B,cAAM,aAAa,oBAAI,KAAK;AAC5B,mBAAW,YAAY,WAAW,YAAY,IAAI,CAAC;AACnD,eAAO,IAAI,KAAK,EAAE,IAAI,KAAK;AAAA,MAC7B;AACA,aAAO,IAAI,KAAK,EAAE,IAAI,EAAE,YAAY,MAAM;AAAA,IAC5C,CAAC;AAED,aAAS,QAAQ,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,OAAO,CAAC,CAAC;AACjD,UAAM,OAAO,QAAQ;AAAA,MACnB,CAAC,GAAG,MAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,MACzC;AAAA,IACF;AACA,eAAW,QAAQ,KAAK,QAAQ,IAAI,OAAO,IAAI;AAAA,EACjD,GAAG,CAAC,SAAS,YAAY,CAAC;AAE1B,QAAM,WAAO;AAAA,IACX,MAAO,QAAQ,OAAO,UAAU,SAAS,YAAY,IAAI,CAAC;AAAA,IAC1D,CAAC,SAAS,YAAY;AAAA,EACxB;AACA,QAAM,aAAS,sBAAQ,MAAM,YAAY,IAAI,GAAG,CAAC,IAAI,CAAC;AACtD,QAAM,eAAe,UAAU,UAAU,SAAS;AAElD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,CAAC,wBAAwB,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA,MAGvE;AAAA,qDAAC,SAAI,WAAU,6EACZ;AAAA,oBACG,kBACA,QACE,gBACA,GAAG,+BAAO,gBAAgB,kBAAkB,iBAAiB,SAAS,qBAAqB,MAAM,YAAY,EAAE;AAAA,UAEpH,WAAW,CAAC,WACX,6CAAC,UAAK,WAAU,6BACd;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,OAAO,EAAE,iBAAiB,OAAO,CAAC,EAAE;AAAA;AAAA,YACtC;AAAA,YAAE;AAAA,YAEF,6CAAC,UAAK,WAAU,kCACb;AAAA,sBAAQ;AAAA,cAAM;AAAA,cAAmB,QAAQ;AAAA,eAC5C;AAAA,aACF;AAAA,WAEJ;AAAA,QAGA,4CAAC,SAAI,WAAU,2DACZ,kBACC,4CAAC,OAAE,WAAU,mCAAkC,0CAE/C,IACE,UACF,4CAAC,YAAS,IAEV,4EACE;AAAA,sDAAC,SAAI,WAAU,wBACb;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,OAAO,EAAE,UAAU,KAAK,SAAS,OAAO,YAAY,EAAE;AAAA,cAGtD;AAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAU;AAAA,oBACV,OAAO,EAAE,YAAY,UAAU;AAAA,oBAE9B,iBAAO,IAAI,CAAC,EAAE,OAAO,IAAI,MACxB;AAAA,sBAAC;AAAA;AAAA,wBAEC,WAAU;AAAA,wBACV,OAAO,EAAE,MAAM,MAAM,KAAK;AAAA,wBAEzB;AAAA;AAAA,sBAJI,QAAQ;AAAA,oBAKf,CACD;AAAA;AAAA,gBACH;AAAA,gBAGA,6CAAC,SAAI,WAAU,kBACb;AAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,WAAU;AAAA,sBACV,OAAO,EAAE,OAAO,YAAY,IAAI;AAAA,sBAE/B,gBAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,MAAG;AAtZ1D,4BAAAC;AAuZsB;AAAA,0BAAC;AAAA;AAAA,4BAEC,WAAU;AAAA,4BAET,WAAAA,MAAA,WAAW,CAAC,MAAZ,OAAAA,MAAiB;AAAA;AAAA,0BAHb;AAAA,wBAIP;AAAA,uBACD;AAAA;AAAA,kBACH;AAAA,kBAEC,KAAK,IAAI,CAAC,MAAM,OACf,4CAAC,SAAa,WAAU,2BACrB,eAAK,IAAI,CAAC,KAAK,OACd;AAAA,oBAAC;AAAA;AAAA,sBAEC,WAAU;AAAA,sBACV,OAAO;AAAA,wBACL,iBAAiB,MACb,OAAO,IAAI,KAAK,IAChB;AAAA,wBACJ,SACE,YAAW,2BAAK,UAAS,QAAQ,OAC7B,aAAa,YAAY,KACzB;AAAA,wBACN,eAAe;AAAA,sBACjB;AAAA,sBACA,cAAc,CAAC,MAAM;AACnB,4BAAI,CAAC,IAAK;AACV,8BAAM,IAAI,EAAE,cAAc,sBAAsB;AAChD,+BAAO,EAAE,KAAK,GAAG,EAAE,OAAO,EAAE,QAAQ,GAAG,GAAG,EAAE,IAAI,CAAC;AAAA,sBACnD;AAAA,sBACA,cAAc,MAAM,OAAO,IAAI;AAAA;AAAA,oBAjB1B;AAAA,kBAkBP,CACD,KAtBO,EAuBV,CACD;AAAA,mBACH;AAAA;AAAA;AAAA,UACF,GACF;AAAA,UAGA,6CAAC,SAAI,WAAU,6DAA4D;AAAA;AAAA,YAExE,OAAO,IAAI,CAAC,GAAG,MACd;AAAA,cAAC;AAAA;AAAA,gBAEC,WAAU;AAAA,gBACV,OAAO,EAAE,iBAAiB,EAAE;AAAA;AAAA,cAFvB;AAAA,YAGP,CACD;AAAA,YAAE;AAAA,aAEL;AAAA,UAGA,6CAAC,SAAI,WAAU,6EACb;AAAA,wDAAC,UAAK,WAAU,qCAAoC,mBAAK;AAAA,YACzD;AAAA,cAAC;AAAA;AAAA,gBACC,OAAM;AAAA,gBACN,QAAQ,iBAAiB;AAAA,gBACzB,SAAS,MAAM,gBAAgB,MAAM;AAAA;AAAA,YACvC;AAAA,YACC,MAAM,IAAI,CAAC,MACV;AAAA,cAAC;AAAA;AAAA,gBAEC,OAAO,OAAO,CAAC;AAAA,gBACf,QAAQ,iBAAiB;AAAA,gBACzB,SAAS,MAAM,gBAAgB,CAAC;AAAA;AAAA,cAH3B;AAAA,YAIP,CACD;AAAA,aACH;AAAA,WACF,GAEJ;AAAA,QAEC,OAAO,4CAAC,WAAQ,KAAK,IAAI,KAAK,GAAG,IAAI,GAAG,GAAG,IAAI,GAAG;AAAA;AAAA;AAAA,EACrD;AAEJ;AAEA,IAAO,6BAAQ,mBAAK,cAAc;","names":["_","_a"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/GithubActivity.tsx","../src/components/Styles.ts","../src/components/Colors.ts","../src/components/BuildGrid.ts","../src/components/Tooltip.tsx","../src/components/YearPillProps.tsx","../src/components/MonthLabels.ts","../src/components/Skeleton.tsx"],"sourcesContent":[" \"use client\";\n export { default as GithubActivity } from \"./GithubActivity\";\n","\"use client\";\r\nimport { memo, useEffect, useState, useMemo } from \"react\";\r\nimport { STYLES } from \"./components/Styles\";\r\nimport { LIGHT, DARK, BLUE, PURPLE, GRAY } from \"./components/Colors\";\r\nimport { buildGrid } from \"./components/BuildGrid\";\r\nimport { Tooltip } from \"./components/Tooltip\";\r\nimport { YearPill } from \"./components/YearPillProps\";\r\nimport { monthLabels } from \"./components/MonthLabels\";\r\nimport { Skeleton } from \"./components/Skeleton\";\r\nimport { Day } from \"./types/Day\";\r\n\r\ntype Theme = \"light\" | \"dark\" | \"blue\" | \"purple\" | \"gray\";\r\n\r\ninterface Props {\r\n username: string;\r\n theme?: Theme;\r\n className?: string;\r\n}\r\n\r\nconst DAY_LABELS: Record<number, string> = { 1: \"Mon\", 3: \"Wed\", 5: \"Fri\" };\r\n\r\nconst CELL = 13;\r\nconst GAP = 3;\r\nconst STEP = CELL + GAP;\r\nconst DAY_COL_W = 30;\r\n\r\nconst COLOR_MAP: Record<Theme, string[]> = {\r\n light: LIGHT,\r\n dark: DARK,\r\n blue: BLUE,\r\n purple: PURPLE,\r\n gray: GRAY,\r\n};\r\n\r\nfunction toLevel(count: number): 0 | 1 | 2 | 3 | 4 {\r\n if (count === 0) return 0;\r\n if (count <= 3) return 1;\r\n if (count <= 6) return 2;\r\n if (count <= 9) return 3;\r\n return 4;\r\n}\r\n\r\n// ─── YearPill ─────────────────────────────────────────────────────────────────\r\n\r\n// ─── Main ─────────────────────────────────────────────────────────────────────\r\nfunction GithubActivity({ username, theme = \"dark\", className }: Props) {\r\n useEffect(() => {\r\n if (typeof document === \"undefined\") return;\r\n const id = \"github-contributions-ui-inline\";\r\n if (document.getElementById(id)) return;\r\n const style = document.createElement(\"style\");\r\n style.id = id;\r\n style.textContent = STYLES;\r\n document.head.appendChild(style);\r\n }, []);\r\n\r\n const [allDays, setAllDays] = useState<Map<string, Day>>(new Map());\r\n const [years, setYears] = useState<number[]>([]);\r\n const [selectedYear, setSelectedYear] = useState<number | \"last\">(\"last\");\r\n const [total, setTotal] = useState<number | null>(null);\r\n const [bestDay, setBestDay] = useState<Day | null>(null);\r\n const [loading, setLoading] = useState(true);\r\n const [error, setError] = useState(false);\r\n const [tip, setTip] = useState<{ day: Day; x: number; y: number } | null>(\r\n null,\r\n );\r\n\r\n const colors = COLOR_MAP[theme] ?? COLOR_MAP.dark;\r\n\r\n useEffect(() => {\r\n if (!username) return;\r\n let mounted = true;\r\n\r\n (async () => {\r\n try {\r\n setLoading(true);\r\n const res = await fetch(\r\n `https://github-contributions-api.jogruber.de/v4/${username}?y=all`,\r\n );\r\n if (!res.ok) throw new Error();\r\n const json = await res.json();\r\n\r\n const map = new Map<string, Day>();\r\n const yearSet = new Set<number>();\r\n\r\n json.contributions.forEach((c: { date: string; count: number }) => {\r\n map.set(c.date, {\r\n date: c.date,\r\n count: c.count,\r\n level: toLevel(c.count),\r\n });\r\n yearSet.add(new Date(c.date).getFullYear());\r\n });\r\n\r\n if (!mounted) return;\r\n setAllDays(map);\r\n setYears(Array.from(yearSet).sort((a, b) => b - a));\r\n setError(false);\r\n } catch {\r\n if (mounted) setError(true);\r\n } finally {\r\n if (mounted) setLoading(false);\r\n }\r\n })();\r\n\r\n return () => {\r\n mounted = false;\r\n };\r\n }, [username]);\r\n\r\n useEffect(() => {\r\n if (!allDays.size) return;\r\n\r\n const entries = Array.from(allDays.values()).filter((d) => {\r\n if (selectedYear === \"last\") {\r\n const oneYearAgo = new Date();\r\n oneYearAgo.setFullYear(oneYearAgo.getFullYear() - 1);\r\n return new Date(d.date) >= oneYearAgo;\r\n }\r\n return new Date(d.date).getFullYear() === selectedYear;\r\n });\r\n\r\n setTotal(entries.reduce((s, d) => s + d.count, 0));\r\n const best = entries.reduce<Day | null>(\r\n (b, d) => (!b || d.count > b.count ? d : b),\r\n null,\r\n );\r\n setBestDay(best && best.count > 0 ? best : null);\r\n }, [allDays, selectedYear]);\r\n\r\n const grid = useMemo(\r\n () => (allDays.size ? buildGrid(allDays, selectedYear) : []),\r\n [allDays, selectedYear],\r\n );\r\n const labels = useMemo(\r\n () => monthLabels(grid, selectedYear),\r\n [grid, selectedYear],\r\n );\r\n const outlineColor = theme === \"light\" ? \"#333\" : \"#f0f0f0\";\r\n\r\n return (\r\n <section\r\n className={[\"gcu w-full font-mono\", className].filter(Boolean).join(\" \")}\r\n style={{}}\r\n >\r\n {/* Stats */}\r\n <div className=\"flex flex-wrap items-center gap-x-6 gap-y-1 mb-4 text-xs text-neutral-400\">\r\n {loading\r\n ? \"Loading…\"\r\n : error\r\n ? \"Unavailable\"\r\n : `${total?.toLocaleString()} contributions ${selectedYear === \"last\" ? \"in the last year\" : `in ${selectedYear}`}`}\r\n\r\n {bestDay && !loading && (\r\n <span className=\"flex items-center gap-1.5\">\r\n <span\r\n className=\"inline-block w-[10px] h-[10px] rounded-[2px]\"\r\n style={{ backgroundColor: colors[4] }}\r\n />\r\n Best day:\r\n <span className=\"text-neutral-200 font-semibold\">\r\n {bestDay.count} contributions on {bestDay.date}\r\n </span>\r\n </span>\r\n )}\r\n </div>\r\n\r\n {/* Card */}\r\n <div className=\"border border-neutral-800 rounded-xl p-4 bg-neutral-950\">\r\n {error ? (\r\n <p className=\"text-sm text-neutral-400 italic\">\r\n GitHub activity unavailable.\r\n </p>\r\n ) : loading ? (\r\n <Skeleton />\r\n ) : (\r\n <>\r\n <div className=\"overflow-x-auto pb-1\">\r\n <div\r\n className=\"relative\"\r\n style={{ minWidth: grid.length * STEP + DAY_COL_W + 8 }}\r\n >\r\n {/* Month labels */}\r\n <div\r\n className=\"relative h-[18px] mb-1\"\r\n style={{ marginLeft: DAY_COL_W }}\r\n >\r\n {labels.map(({ label, col }) => (\r\n <span\r\n key={label + col}\r\n className=\"absolute text-[11px] text-neutral-400\"\r\n style={{ left: col * STEP }}\r\n >\r\n {label}\r\n </span>\r\n ))}\r\n </div>\r\n\r\n {/* Grid */}\r\n <div className=\"flex gap-[3px]\">\r\n <div\r\n className=\"flex flex-col gap-[3px]\"\r\n style={{ width: DAY_COL_W - GAP }}\r\n >\r\n {Array.from({ length: 7 }).map((_, i) => (\r\n <div\r\n key={i}\r\n className=\"h-[13px] text-[10px] text-right pr-1.5 text-neutral-400\"\r\n >\r\n {DAY_LABELS[i] ?? \"\"}\r\n </div>\r\n ))}\r\n </div>\r\n\r\n {grid.map((week, wi) => (\r\n <div key={wi} className=\"flex flex-col gap-[3px]\">\r\n {week.map((day, di) => (\r\n <div\r\n key={di}\r\n className=\"w-[13px] h-[13px] rounded-[3px] transition-transform hover:scale-125\"\r\n style={{\r\n backgroundColor: day\r\n ? colors[day.level]\r\n : \"transparent\",\r\n outline:\r\n bestDay && day?.date === bestDay.date\r\n ? `2px solid ${outlineColor}`\r\n : \"none\",\r\n outlineOffset: \"1px\",\r\n }}\r\n onMouseEnter={(e) => {\r\n if (!day) return;\r\n const r = e.currentTarget.getBoundingClientRect();\r\n setTip({ day, x: r.left + r.width / 2, y: r.top });\r\n }}\r\n onMouseLeave={() => setTip(null)}\r\n />\r\n ))}\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* Legend */}\r\n <div className=\"flex items-center gap-1 mt-3 text-[11px] text-neutral-400\">\r\n Less\r\n {colors.map((c, i) => (\r\n <div\r\n key={i}\r\n className=\"w-[13px] h-[13px] rounded-[3px]\"\r\n style={{ backgroundColor: c }}\r\n />\r\n ))}\r\n More\r\n </div>\r\n\r\n {/* Year selector */}\r\n <div className=\"flex flex-wrap items-center gap-1.5 mt-4 pt-3 border-t border-neutral-800\">\r\n <span className=\"text-[11px] text-neutral-400 mr-1\">Year:</span>\r\n <YearPill\r\n label=\"Last year\"\r\n active={selectedYear === \"last\"}\r\n onClick={() => setSelectedYear(\"last\")}\r\n />\r\n {years.map((y) => (\r\n <YearPill\r\n key={y}\r\n label={String(y)}\r\n active={selectedYear === y}\r\n onClick={() => setSelectedYear(y)}\r\n />\r\n ))}\r\n </div>\r\n </>\r\n )}\r\n </div>\r\n\r\n {tip && <Tooltip day={tip.day} x={tip.x} y={tip.y} />}\r\n </section>\r\n );\r\n}\r\n\r\nexport default memo(GithubActivity);\r\n","export const STYLES = `\r\n .gcu .relative{position:relative}\r\n .gcu .absolute{position:absolute}\r\n .gcu .fixed{position:fixed}\r\n .gcu .z-50{z-index:50}\r\n .gcu .pointer-events-none{pointer-events:none}\r\n .gcu .flex{display:flex}\r\n .gcu .flex-col{flex-direction:column}\r\n .gcu .flex-wrap{flex-wrap:wrap}\r\n .gcu .items-center{align-items:center}\r\n .gcu .justify-start{justify-content:flex-start}\r\n .gcu .inline-block{display:inline-block}\r\n .gcu .w-full{width:100%}\r\n .gcu .w-\\\\[10px\\\\]{width:10px}\r\n .gcu .w-\\\\[13px\\\\]{width:13px}\r\n .gcu .h-\\\\[10px\\\\]{height:10px}\r\n .gcu .h-\\\\[13px\\\\]{height:13px}\r\n .gcu .h-\\\\[18px\\\\]{height:18px}\r\n .gcu .-translate-x-1\\\\/2{transform:translateX(-50%)}\r\n .gcu .-translate-y-full{transform:translateY(-100%)}\r\n .gcu .gap-\\\\[3px\\\\]{gap:3px}\r\n .gcu .gap-1{gap:0.25rem}\r\n .gcu .gap-1\\\\.5{gap:0.375rem}\r\n .gcu .gap-x-6{column-gap:1.5rem}\r\n .gcu .gap-y-1{row-gap:0.25rem}\r\n .gcu .mb-4{margin-bottom:1rem}\r\n .gcu .mt-3{margin-top:0.75rem}\r\n .gcu .mt-4{margin-top:1rem}\r\n .gcu .mr-1{margin-right:0.25rem}\r\n .gcu .ml-1{margin-left:0.25rem}\r\n .gcu .p-4{padding:1rem}\r\n .gcu .pt-3{padding-top:0.75rem}\r\n .gcu .pt-px{padding-top:1px}\r\n .gcu .pb-1{padding-bottom:0.25rem}\r\n .gcu .pr-1\\\\.5{padding-right:0.375rem}\r\n .gcu .px-2\\\\.5{padding-left:0.625rem;padding-right:0.625rem}\r\n .gcu .py-1\\\\.5{padding-top:0.375rem;padding-bottom:0.375rem}\r\n .gcu .rounded-\\\\[2px\\\\]{border-radius:2px}\r\n .gcu .rounded-\\\\[3px\\\\]{border-radius:3px}\r\n .gcu .rounded-md{border-radius:0.375rem}\r\n .gcu .rounded-xl{border-radius:0.75rem}\r\n .gcu .text-right{text-align:right}\r\n .gcu .text-\\\\[10px\\\\]{font-size:10px}\r\n .gcu .text-\\\\[11px\\\\]{font-size:11px}\r\n .gcu .text-xs{font-size:0.75rem}\r\n .gcu .text-sm{font-size:0.875rem}\r\n .gcu .font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace}\r\n .gcu .font-medium{font-weight:500}\r\n .gcu .font-semibold{font-weight:600}\r\n .gcu .select-none{-webkit-user-select:none;-ms-user-select:none;user-select:none}\r\n .gcu .whitespace-nowrap{white-space:nowrap}\r\n .gcu .overflow-x-auto{overflow-x:auto}\r\n .gcu .border{border-width:1px;border-style:solid;border-color:#262626}\r\n .gcu .border-neutral-800{border-color:#262626}\r\n .gcu .border-t{border-top-width:1px;border-top-style:solid;border-top-color:#262626}\r\n .gcu .transition-transform{transition-property:transform;transition-duration:0.1s;transition-timing-function:ease}\r\n @keyframes gcu-pulse{50%{opacity:.5}}\r\n .gcu .animate-pulse{animation:gcu-pulse 2s cubic-bezier(0.4,0,0.6,1) infinite}\r\n .gcu .hover\\\\:scale-125:hover{transform:scale(1.25)}\r\n .gcu .text-neutral-400{color:#9ca3af}\r\n .gcu .text-neutral-200{color:#e5e7eb}\r\n .gcu .bg-neutral-700{background-color:#3f3f46}\r\n .gcu .bg-neutral-900{background-color:#171717}\r\n .gcu .bg-neutral-950{background-color:#0a0a0a}\r\n .gcu .text-white{color:#fff}\r\n .gcu .shadow-xl{box-shadow:0 20px 25px -5px rgba(0,0,0,0.1),0 10px 10px -5px rgba(0,0,0,0.04)}\r\n `;\r\n","export const LIGHT = [\"#ebedf0\", \"#9be9a8\", \"#40c463\", \"#30a14e\", \"#216e39\"];\r\nexport const DARK = [\"#21262d\", \"#0e4429\", \"#006d32\", \"#26a641\", \"#39d353\"];\r\nexport const BLUE = [\"#21262d\", \"#a3c9ff\", \"#5fa3ff\", \"#2f7bff\", \"#0b5cff\"];\r\nexport const PURPLE = [\"#21262d\", \"#d8b4ff\", \"#c084fc\", \"#a855f7\", \"#7e22ce\"];\r\nexport const GRAY = [\"#21262d\", \"#6a737d\", \"#8b949e\", \"#c0c0c8\", \"#e0e0e0\"];","import { Day } from \"../types/Day\";\r\n\r\nexport function buildGrid(\r\n dayMap: Map<string, Day>,\r\n year: number | \"last\",\r\n): (Day | null)[][] {\r\n // Determine the logical range\r\n let rangeStart: Date;\r\n let end: Date;\r\n\r\n if (year === \"last\") {\r\n end = new Date();\r\n rangeStart = new Date(end);\r\n rangeStart.setFullYear(rangeStart.getFullYear() - 1);\r\n rangeStart.setDate(rangeStart.getDate() + 1);\r\n } else {\r\n rangeStart = new Date(year, 0, 1);\r\n end =\r\n year === new Date().getFullYear() ? new Date() : new Date(year, 11, 31);\r\n }\r\n\r\n // Rewind to the Sunday of the week containing rangeStart.\r\n // Days in that partial first week that fall before rangeStart render as null.\r\n const gridStart = new Date(rangeStart);\r\n gridStart.setDate(gridStart.getDate() - gridStart.getDay());\r\n\r\n const weeks: (Day | null)[][] = [];\r\n const cur = new Date(gridStart);\r\n\r\n while (cur <= end) {\r\n const week: (Day | null)[] = [];\r\n for (let d = 0; d < 7; d++) {\r\n if (cur < rangeStart || cur > end) {\r\n week.push(null);\r\n } else {\r\n const iso = cur.toISOString().slice(0, 10);\r\n week.push(dayMap.get(iso) ?? { date: iso, count: 0, level: 0 });\r\n }\r\n cur.setDate(cur.getDate() + 1);\r\n }\r\n weeks.push(week);\r\n }\r\n\r\n return weeks;\r\n}\r\n","import { Day } from \"../types/Day\";\r\n\r\nexport function Tooltip({ day, x, y }: { day: Day; x: number; y: number }) {\r\n const label = new Date(day.date).toLocaleDateString(\"en-US\", {\r\n weekday: \"long\",\r\n year: \"numeric\",\r\n month: \"long\",\r\n day: \"numeric\",\r\n });\r\n return (\r\n <div\r\n className=\"gcu fixed z-50 pointer-events-none -translate-x-1/2 -translate-y-full px-2.5 py-1.5 rounded-md text-xs font-mono whitespace-nowrap shadow-xl bg-neutral-900 text-white\"\r\n style={{ left: x, top: y - 8 }}\r\n >\r\n <b>\r\n {day.count} contribution{day.count !== 1 ? \"s\" : \"\"}\r\n </b>{\" \"}\r\n · {label}\r\n </div>\r\n );\r\n}","\"use client\";\r\n\r\nimport React, { useState } from \"react\";\r\n\r\ntype YearPillProps = { label: string; active: boolean; onClick: () => void };\r\n\r\nexport function YearPill({ label, active, onClick }: YearPillProps) {\r\n const [hovered, setHovered] = useState(false);\r\n\r\n const baseStyle: React.CSSProperties = {\r\n padding: \"2px 10px\",\r\n fontSize: 12,\r\n fontWeight: 500,\r\n borderRadius: 9999,\r\n border: \"none\",\r\n cursor: \"pointer\",\r\n transition: \"background-color 0.15s ease, color 0.15s ease\",\r\n userSelect: \"none\",\r\n outline: \"none\",\r\n backgroundColor: active ? \"#ffffff\" : hovered ? \"#3f3f46\" : \"#262626\",\r\n color: active ? \"#000000\" : \"#ffffff\",\r\n };\r\n\r\n return (\r\n <button\r\n type=\"button\"\r\n onClick={onClick}\r\n style={baseStyle}\r\n onMouseEnter={() => setHovered(true)}\r\n onMouseLeave={() => setHovered(false)}\r\n >\r\n {label}\r\n </button>\r\n );\r\n}\r\n","import { Day } from \"../types/Day\";\r\n\r\nconst MONTHS = [\r\n \"Jan\",\r\n \"Feb\",\r\n \"Mar\",\r\n \"Apr\",\r\n \"May\",\r\n \"Jun\",\r\n \"Jul\",\r\n \"Aug\",\r\n \"Sep\",\r\n \"Oct\",\r\n \"Nov\",\r\n \"Dec\",\r\n];\r\n\r\nexport function monthLabels(grid: (Day | null)[][], year: number | \"last\") {\r\n const out: { label: string; col: number }[] = [];\r\n let lastMonth = -1;\r\n grid.forEach((week, i) => {\r\n const first = week.find(Boolean);\r\n if (!first) return;\r\n const m = new Date(first.date).getMonth();\r\n if (m !== lastMonth) {\r\n // If the very first column is a partial week whose first real day\r\n // isn't Sunday (index > 0), the month label belongs to a prior-month\r\n // sliver and would collide with the next label. Suppress it.\r\n const isOrphanedSliver =\r\n i === 0 &&\r\n week.findIndex(Boolean) > 0 &&\r\n (year !== \"last\" ? m !== 0 : true);\r\n if (!isOrphanedSliver) {\r\n out.push({ label: MONTHS[m], col: i });\r\n }\r\n lastMonth = m;\r\n }\r\n });\r\n return out;\r\n}\r\n","export function Skeleton() {\r\n return (\r\n <div className=\"flex gap-[3px] mx-auto animate-pulse opacity-40\">\r\n {Array.from({ length: 40 }).map((_, w) => (\r\n <div key={w} className=\"flex flex-col gap-[3px]\">\r\n {Array.from({ length: 7 }).map((_, d) => (\r\n <div\r\n key={d}\r\n className=\"w-[13px] h-[13px] rounded-[3px] bg-neutral-700\"\r\n />\r\n ))}\r\n </div>\r\n ))}\r\n </div>\r\n );\r\n}\r\n"],"mappings":"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","names":["import_react","import_jsx_runtime","import_jsx_runtime","_","import_jsx_runtime","_a"]}
|
package/dist/index.d.cts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -2,86 +2,120 @@
|
|
|
2
2
|
"use client";
|
|
3
3
|
|
|
4
4
|
// src/GithubActivity.tsx
|
|
5
|
-
import { memo, useEffect, useState, useMemo } from "react";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
5
|
+
import { memo, useEffect, useState as useState2, useMemo } from "react";
|
|
6
|
+
|
|
7
|
+
// src/components/Styles.ts
|
|
8
|
+
var STYLES = `
|
|
9
|
+
.gcu .relative{position:relative}
|
|
10
|
+
.gcu .absolute{position:absolute}
|
|
11
|
+
.gcu .fixed{position:fixed}
|
|
12
|
+
.gcu .z-50{z-index:50}
|
|
13
|
+
.gcu .pointer-events-none{pointer-events:none}
|
|
14
|
+
.gcu .flex{display:flex}
|
|
15
|
+
.gcu .flex-col{flex-direction:column}
|
|
16
|
+
.gcu .flex-wrap{flex-wrap:wrap}
|
|
17
|
+
.gcu .items-center{align-items:center}
|
|
18
|
+
.gcu .justify-start{justify-content:flex-start}
|
|
19
|
+
.gcu .inline-block{display:inline-block}
|
|
20
|
+
.gcu .w-full{width:100%}
|
|
21
|
+
.gcu .w-\\[10px\\]{width:10px}
|
|
22
|
+
.gcu .w-\\[13px\\]{width:13px}
|
|
23
|
+
.gcu .h-\\[10px\\]{height:10px}
|
|
24
|
+
.gcu .h-\\[13px\\]{height:13px}
|
|
25
|
+
.gcu .h-\\[18px\\]{height:18px}
|
|
26
|
+
.gcu .-translate-x-1\\/2{transform:translateX(-50%)}
|
|
27
|
+
.gcu .-translate-y-full{transform:translateY(-100%)}
|
|
28
|
+
.gcu .gap-\\[3px\\]{gap:3px}
|
|
29
|
+
.gcu .gap-1{gap:0.25rem}
|
|
30
|
+
.gcu .gap-1\\.5{gap:0.375rem}
|
|
31
|
+
.gcu .gap-x-6{column-gap:1.5rem}
|
|
32
|
+
.gcu .gap-y-1{row-gap:0.25rem}
|
|
33
|
+
.gcu .mb-4{margin-bottom:1rem}
|
|
34
|
+
.gcu .mt-3{margin-top:0.75rem}
|
|
35
|
+
.gcu .mt-4{margin-top:1rem}
|
|
36
|
+
.gcu .mr-1{margin-right:0.25rem}
|
|
37
|
+
.gcu .ml-1{margin-left:0.25rem}
|
|
38
|
+
.gcu .p-4{padding:1rem}
|
|
39
|
+
.gcu .pt-3{padding-top:0.75rem}
|
|
40
|
+
.gcu .pt-px{padding-top:1px}
|
|
41
|
+
.gcu .pb-1{padding-bottom:0.25rem}
|
|
42
|
+
.gcu .pr-1\\.5{padding-right:0.375rem}
|
|
43
|
+
.gcu .px-2\\.5{padding-left:0.625rem;padding-right:0.625rem}
|
|
44
|
+
.gcu .py-1\\.5{padding-top:0.375rem;padding-bottom:0.375rem}
|
|
45
|
+
.gcu .rounded-\\[2px\\]{border-radius:2px}
|
|
46
|
+
.gcu .rounded-\\[3px\\]{border-radius:3px}
|
|
47
|
+
.gcu .rounded-md{border-radius:0.375rem}
|
|
48
|
+
.gcu .rounded-xl{border-radius:0.75rem}
|
|
49
|
+
.gcu .text-right{text-align:right}
|
|
50
|
+
.gcu .text-\\[10px\\]{font-size:10px}
|
|
51
|
+
.gcu .text-\\[11px\\]{font-size:11px}
|
|
52
|
+
.gcu .text-xs{font-size:0.75rem}
|
|
53
|
+
.gcu .text-sm{font-size:0.875rem}
|
|
54
|
+
.gcu .font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}
|
|
55
|
+
.gcu .font-medium{font-weight:500}
|
|
56
|
+
.gcu .font-semibold{font-weight:600}
|
|
57
|
+
.gcu .select-none{-webkit-user-select:none;-ms-user-select:none;user-select:none}
|
|
58
|
+
.gcu .whitespace-nowrap{white-space:nowrap}
|
|
59
|
+
.gcu .overflow-x-auto{overflow-x:auto}
|
|
60
|
+
.gcu .border{border-width:1px;border-style:solid;border-color:#262626}
|
|
61
|
+
.gcu .border-neutral-800{border-color:#262626}
|
|
62
|
+
.gcu .border-t{border-top-width:1px;border-top-style:solid;border-top-color:#262626}
|
|
63
|
+
.gcu .transition-transform{transition-property:transform;transition-duration:0.1s;transition-timing-function:ease}
|
|
64
|
+
@keyframes gcu-pulse{50%{opacity:.5}}
|
|
65
|
+
.gcu .animate-pulse{animation:gcu-pulse 2s cubic-bezier(0.4,0,0.6,1) infinite}
|
|
66
|
+
.gcu .hover\\:scale-125:hover{transform:scale(1.25)}
|
|
67
|
+
.gcu .text-neutral-400{color:#9ca3af}
|
|
68
|
+
.gcu .text-neutral-200{color:#e5e7eb}
|
|
69
|
+
.gcu .bg-neutral-700{background-color:#3f3f46}
|
|
70
|
+
.gcu .bg-neutral-900{background-color:#171717}
|
|
71
|
+
.gcu .bg-neutral-950{background-color:#0a0a0a}
|
|
72
|
+
.gcu .text-white{color:#fff}
|
|
73
|
+
.gcu .shadow-xl{box-shadow:0 20px 25px -5px rgba(0,0,0,0.1),0 10px 10px -5px rgba(0,0,0,0.04)}
|
|
74
|
+
`;
|
|
75
|
+
|
|
76
|
+
// src/components/Colors.ts
|
|
26
77
|
var LIGHT = ["#ebedf0", "#9be9a8", "#40c463", "#30a14e", "#216e39"];
|
|
27
78
|
var DARK = ["#21262d", "#0e4429", "#006d32", "#26a641", "#39d353"];
|
|
28
79
|
var BLUE = ["#21262d", "#a3c9ff", "#5fa3ff", "#2f7bff", "#0b5cff"];
|
|
29
80
|
var PURPLE = ["#21262d", "#d8b4ff", "#c084fc", "#a855f7", "#7e22ce"];
|
|
30
|
-
var
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
blue: BLUE,
|
|
34
|
-
purple: PURPLE
|
|
35
|
-
};
|
|
36
|
-
function toLevel(count) {
|
|
37
|
-
if (count === 0) return 0;
|
|
38
|
-
if (count <= 3) return 1;
|
|
39
|
-
if (count <= 6) return 2;
|
|
40
|
-
if (count <= 9) return 3;
|
|
41
|
-
return 4;
|
|
42
|
-
}
|
|
81
|
+
var GRAY = ["#21262d", "#6a737d", "#8b949e", "#c0c0c8", "#e0e0e0"];
|
|
82
|
+
|
|
83
|
+
// src/components/BuildGrid.ts
|
|
43
84
|
function buildGrid(dayMap, year) {
|
|
44
85
|
var _a;
|
|
45
|
-
let
|
|
86
|
+
let rangeStart;
|
|
46
87
|
let end;
|
|
47
88
|
if (year === "last") {
|
|
48
89
|
end = /* @__PURE__ */ new Date();
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
90
|
+
rangeStart = new Date(end);
|
|
91
|
+
rangeStart.setFullYear(rangeStart.getFullYear() - 1);
|
|
92
|
+
rangeStart.setDate(rangeStart.getDate() + 1);
|
|
52
93
|
} else {
|
|
53
|
-
|
|
94
|
+
rangeStart = new Date(year, 0, 1);
|
|
54
95
|
end = year === (/* @__PURE__ */ new Date()).getFullYear() ? /* @__PURE__ */ new Date() : new Date(year, 11, 31);
|
|
55
96
|
}
|
|
56
|
-
|
|
97
|
+
const gridStart = new Date(rangeStart);
|
|
98
|
+
gridStart.setDate(gridStart.getDate() - gridStart.getDay());
|
|
57
99
|
const weeks = [];
|
|
58
|
-
const cur = new Date(
|
|
100
|
+
const cur = new Date(gridStart);
|
|
59
101
|
while (cur <= end) {
|
|
60
102
|
const week = [];
|
|
61
103
|
for (let d = 0; d < 7; d++) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
else
|
|
104
|
+
if (cur < rangeStart || cur > end) {
|
|
105
|
+
week.push(null);
|
|
106
|
+
} else {
|
|
107
|
+
const iso = cur.toISOString().slice(0, 10);
|
|
108
|
+
week.push((_a = dayMap.get(iso)) != null ? _a : { date: iso, count: 0, level: 0 });
|
|
109
|
+
}
|
|
65
110
|
cur.setDate(cur.getDate() + 1);
|
|
66
111
|
}
|
|
67
112
|
weeks.push(week);
|
|
68
113
|
}
|
|
69
114
|
return weeks;
|
|
70
115
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
grid.forEach((week, i) => {
|
|
75
|
-
const first = week.find(Boolean);
|
|
76
|
-
if (!first) return;
|
|
77
|
-
const m = new Date(first.date).getMonth();
|
|
78
|
-
if (m !== last) {
|
|
79
|
-
out.push({ label: MONTHS[m], col: i });
|
|
80
|
-
last = m;
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
return out;
|
|
84
|
-
}
|
|
116
|
+
|
|
117
|
+
// src/components/Tooltip.tsx
|
|
118
|
+
import { jsxs } from "react/jsx-runtime";
|
|
85
119
|
function Tooltip({ day, x, y }) {
|
|
86
120
|
const label = new Date(day.date).toLocaleDateString("en-US", {
|
|
87
121
|
weekday: "long",
|
|
@@ -107,15 +141,10 @@ function Tooltip({ day, x, y }) {
|
|
|
107
141
|
}
|
|
108
142
|
);
|
|
109
143
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
className: "w-[13px] h-[13px] rounded-[3px] bg-neutral-700"
|
|
115
|
-
},
|
|
116
|
-
d
|
|
117
|
-
)) }, w)) });
|
|
118
|
-
}
|
|
144
|
+
|
|
145
|
+
// src/components/YearPillProps.tsx
|
|
146
|
+
import { useState } from "react";
|
|
147
|
+
import { jsx } from "react/jsx-runtime";
|
|
119
148
|
function YearPill({ label, active, onClick }) {
|
|
120
149
|
const [hovered, setHovered] = useState(false);
|
|
121
150
|
const baseStyle = {
|
|
@@ -128,8 +157,6 @@ function YearPill({ label, active, onClick }) {
|
|
|
128
157
|
transition: "background-color 0.15s ease, color 0.15s ease",
|
|
129
158
|
userSelect: "none",
|
|
130
159
|
outline: "none",
|
|
131
|
-
// Active = white pill with dark text
|
|
132
|
-
// Inactive = dark pill with muted text, slightly lighter on hover
|
|
133
160
|
backgroundColor: active ? "#ffffff" : hovered ? "#3f3f46" : "#262626",
|
|
134
161
|
color: active ? "#000000" : "#ffffff"
|
|
135
162
|
};
|
|
@@ -145,75 +172,75 @@ function YearPill({ label, active, onClick }) {
|
|
|
145
172
|
}
|
|
146
173
|
);
|
|
147
174
|
}
|
|
175
|
+
|
|
176
|
+
// src/components/MonthLabels.ts
|
|
177
|
+
var MONTHS = [
|
|
178
|
+
"Jan",
|
|
179
|
+
"Feb",
|
|
180
|
+
"Mar",
|
|
181
|
+
"Apr",
|
|
182
|
+
"May",
|
|
183
|
+
"Jun",
|
|
184
|
+
"Jul",
|
|
185
|
+
"Aug",
|
|
186
|
+
"Sep",
|
|
187
|
+
"Oct",
|
|
188
|
+
"Nov",
|
|
189
|
+
"Dec"
|
|
190
|
+
];
|
|
191
|
+
function monthLabels(grid, year) {
|
|
192
|
+
const out = [];
|
|
193
|
+
let lastMonth = -1;
|
|
194
|
+
grid.forEach((week, i) => {
|
|
195
|
+
const first = week.find(Boolean);
|
|
196
|
+
if (!first) return;
|
|
197
|
+
const m = new Date(first.date).getMonth();
|
|
198
|
+
if (m !== lastMonth) {
|
|
199
|
+
const isOrphanedSliver = i === 0 && week.findIndex(Boolean) > 0 && (year !== "last" ? m !== 0 : true);
|
|
200
|
+
if (!isOrphanedSliver) {
|
|
201
|
+
out.push({ label: MONTHS[m], col: i });
|
|
202
|
+
}
|
|
203
|
+
lastMonth = m;
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
return out;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// src/components/Skeleton.tsx
|
|
210
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
211
|
+
function Skeleton() {
|
|
212
|
+
return /* @__PURE__ */ jsx2("div", { className: "flex gap-[3px] mx-auto animate-pulse opacity-40", children: Array.from({ length: 40 }).map((_, w) => /* @__PURE__ */ jsx2("div", { className: "flex flex-col gap-[3px]", children: Array.from({ length: 7 }).map((_2, d) => /* @__PURE__ */ jsx2(
|
|
213
|
+
"div",
|
|
214
|
+
{
|
|
215
|
+
className: "w-[13px] h-[13px] rounded-[3px] bg-neutral-700"
|
|
216
|
+
},
|
|
217
|
+
d
|
|
218
|
+
)) }, w)) });
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// src/GithubActivity.tsx
|
|
222
|
+
import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
223
|
+
var DAY_LABELS = { 1: "Mon", 3: "Wed", 5: "Fri" };
|
|
224
|
+
var CELL = 13;
|
|
225
|
+
var GAP = 3;
|
|
226
|
+
var STEP = CELL + GAP;
|
|
227
|
+
var DAY_COL_W = 30;
|
|
228
|
+
var COLOR_MAP = {
|
|
229
|
+
light: LIGHT,
|
|
230
|
+
dark: DARK,
|
|
231
|
+
blue: BLUE,
|
|
232
|
+
purple: PURPLE,
|
|
233
|
+
gray: GRAY
|
|
234
|
+
};
|
|
235
|
+
function toLevel(count) {
|
|
236
|
+
if (count === 0) return 0;
|
|
237
|
+
if (count <= 3) return 1;
|
|
238
|
+
if (count <= 6) return 2;
|
|
239
|
+
if (count <= 9) return 3;
|
|
240
|
+
return 4;
|
|
241
|
+
}
|
|
148
242
|
function GithubActivity({ username, theme = "dark", className }) {
|
|
149
243
|
var _a;
|
|
150
|
-
const STYLES = `
|
|
151
|
-
.gcu .relative{position:relative}
|
|
152
|
-
.gcu .absolute{position:absolute}
|
|
153
|
-
.gcu .fixed{position:fixed}
|
|
154
|
-
.gcu .z-50{z-index:50}
|
|
155
|
-
.gcu .pointer-events-none{pointer-events:none}
|
|
156
|
-
.gcu .flex{display:flex}
|
|
157
|
-
.gcu .flex-col{flex-direction:column}
|
|
158
|
-
.gcu .flex-wrap{flex-wrap:wrap}
|
|
159
|
-
.gcu .items-center{align-items:center}
|
|
160
|
-
.gcu .justify-start{justify-content:flex-start}
|
|
161
|
-
.gcu .inline-block{display:inline-block}
|
|
162
|
-
.gcu .w-full{width:100%}
|
|
163
|
-
.gcu .w-\\[10px\\]{width:10px}
|
|
164
|
-
.gcu .w-\\[13px\\]{width:13px}
|
|
165
|
-
.gcu .h-\\[10px\\]{height:10px}
|
|
166
|
-
.gcu .h-\\[13px\\]{height:13px}
|
|
167
|
-
.gcu .h-\\[18px\\]{height:18px}
|
|
168
|
-
.gcu .-translate-x-1\\/2{transform:translateX(-50%)}
|
|
169
|
-
.gcu .-translate-y-full{transform:translateY(-100%)}
|
|
170
|
-
.gcu .gap-\\[3px\\]{gap:3px}
|
|
171
|
-
.gcu .gap-1{gap:0.25rem}
|
|
172
|
-
.gcu .gap-1\\.5{gap:0.375rem}
|
|
173
|
-
.gcu .gap-x-6{column-gap:1.5rem}
|
|
174
|
-
.gcu .gap-y-1{row-gap:0.25rem}
|
|
175
|
-
.gcu .mb-4{margin-bottom:1rem}
|
|
176
|
-
.gcu .mt-3{margin-top:0.75rem}
|
|
177
|
-
.gcu .mt-4{margin-top:1rem}
|
|
178
|
-
.gcu .mr-1{margin-right:0.25rem}
|
|
179
|
-
.gcu .ml-1{margin-left:0.25rem}
|
|
180
|
-
.gcu .p-4{padding:1rem}
|
|
181
|
-
.gcu .pt-3{padding-top:0.75rem}
|
|
182
|
-
.gcu .pt-px{padding-top:1px}
|
|
183
|
-
.gcu .pb-1{padding-bottom:0.25rem}
|
|
184
|
-
.gcu .pr-1\\.5{padding-right:0.375rem}
|
|
185
|
-
.gcu .px-2\\.5{padding-left:0.625rem;padding-right:0.625rem}
|
|
186
|
-
.gcu .py-1\\.5{padding-top:0.375rem;padding-bottom:0.375rem}
|
|
187
|
-
.gcu .rounded-\\[2px\\]{border-radius:2px}
|
|
188
|
-
.gcu .rounded-\\[3px\\]{border-radius:3px}
|
|
189
|
-
.gcu .rounded-md{border-radius:0.375rem}
|
|
190
|
-
.gcu .rounded-xl{border-radius:0.75rem}
|
|
191
|
-
.gcu .text-right{text-align:right}
|
|
192
|
-
.gcu .text-\\[10px\\]{font-size:10px}
|
|
193
|
-
.gcu .text-\\[11px\\]{font-size:11px}
|
|
194
|
-
.gcu .text-xs{font-size:0.75rem}
|
|
195
|
-
.gcu .text-sm{font-size:0.875rem}
|
|
196
|
-
.gcu .font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}
|
|
197
|
-
.gcu .font-medium{font-weight:500}
|
|
198
|
-
.gcu .font-semibold{font-weight:600}
|
|
199
|
-
.gcu .select-none{-webkit-user-select:none;-ms-user-select:none;user-select:none}
|
|
200
|
-
.gcu .whitespace-nowrap{white-space:nowrap}
|
|
201
|
-
.gcu .overflow-x-auto{overflow-x:auto}
|
|
202
|
-
.gcu .border{border-width:1px;border-style:solid;border-color:#262626}
|
|
203
|
-
.gcu .border-neutral-800{border-color:#262626}
|
|
204
|
-
.gcu .border-t{border-top-width:1px;border-top-style:solid;border-top-color:#262626}
|
|
205
|
-
.gcu .transition-transform{transition-property:transform;transition-duration:0.1s;transition-timing-function:ease}
|
|
206
|
-
@keyframes gcu-pulse{50%{opacity:.5}}
|
|
207
|
-
.gcu .animate-pulse{animation:gcu-pulse 2s cubic-bezier(0.4,0,0.6,1) infinite}
|
|
208
|
-
.gcu .hover\\:scale-125:hover{transform:scale(1.25)}
|
|
209
|
-
.gcu .text-neutral-400{color:#9ca3af}
|
|
210
|
-
.gcu .text-neutral-200{color:#e5e7eb}
|
|
211
|
-
.gcu .bg-neutral-700{background-color:#3f3f46}
|
|
212
|
-
.gcu .bg-neutral-900{background-color:#171717}
|
|
213
|
-
.gcu .bg-neutral-950{background-color:#0a0a0a}
|
|
214
|
-
.gcu .text-white{color:#fff}
|
|
215
|
-
.gcu .shadow-xl{box-shadow:0 20px 25px -5px rgba(0,0,0,0.1),0 10px 10px -5px rgba(0,0,0,0.04)}
|
|
216
|
-
`;
|
|
217
244
|
useEffect(() => {
|
|
218
245
|
if (typeof document === "undefined") return;
|
|
219
246
|
const id = "github-contributions-ui-inline";
|
|
@@ -223,14 +250,14 @@ function GithubActivity({ username, theme = "dark", className }) {
|
|
|
223
250
|
style.textContent = STYLES;
|
|
224
251
|
document.head.appendChild(style);
|
|
225
252
|
}, []);
|
|
226
|
-
const [allDays, setAllDays] =
|
|
227
|
-
const [years, setYears] =
|
|
228
|
-
const [selectedYear, setSelectedYear] =
|
|
229
|
-
const [total, setTotal] =
|
|
230
|
-
const [bestDay, setBestDay] =
|
|
231
|
-
const [loading, setLoading] =
|
|
232
|
-
const [error, setError] =
|
|
233
|
-
const [tip, setTip] =
|
|
253
|
+
const [allDays, setAllDays] = useState2(/* @__PURE__ */ new Map());
|
|
254
|
+
const [years, setYears] = useState2([]);
|
|
255
|
+
const [selectedYear, setSelectedYear] = useState2("last");
|
|
256
|
+
const [total, setTotal] = useState2(null);
|
|
257
|
+
const [bestDay, setBestDay] = useState2(null);
|
|
258
|
+
const [loading, setLoading] = useState2(true);
|
|
259
|
+
const [error, setError] = useState2(false);
|
|
260
|
+
const [tip, setTip] = useState2(
|
|
234
261
|
null
|
|
235
262
|
);
|
|
236
263
|
const colors = (_a = COLOR_MAP[theme]) != null ? _a : COLOR_MAP.dark;
|
|
@@ -290,17 +317,21 @@ function GithubActivity({ username, theme = "dark", className }) {
|
|
|
290
317
|
() => allDays.size ? buildGrid(allDays, selectedYear) : [],
|
|
291
318
|
[allDays, selectedYear]
|
|
292
319
|
);
|
|
293
|
-
const labels = useMemo(
|
|
320
|
+
const labels = useMemo(
|
|
321
|
+
() => monthLabels(grid, selectedYear),
|
|
322
|
+
[grid, selectedYear]
|
|
323
|
+
);
|
|
294
324
|
const outlineColor = theme === "light" ? "#333" : "#f0f0f0";
|
|
295
|
-
return /* @__PURE__ */
|
|
325
|
+
return /* @__PURE__ */ jsxs2(
|
|
296
326
|
"section",
|
|
297
327
|
{
|
|
298
328
|
className: ["gcu w-full font-mono", className].filter(Boolean).join(" "),
|
|
329
|
+
style: {},
|
|
299
330
|
children: [
|
|
300
|
-
/* @__PURE__ */
|
|
331
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-1 mb-4 text-xs text-neutral-400", children: [
|
|
301
332
|
loading ? "Loading\u2026" : error ? "Unavailable" : `${total == null ? void 0 : total.toLocaleString()} contributions ${selectedYear === "last" ? "in the last year" : `in ${selectedYear}`}`,
|
|
302
|
-
bestDay && !loading && /* @__PURE__ */
|
|
303
|
-
/* @__PURE__ */
|
|
333
|
+
bestDay && !loading && /* @__PURE__ */ jsxs2("span", { className: "flex items-center gap-1.5", children: [
|
|
334
|
+
/* @__PURE__ */ jsx3(
|
|
304
335
|
"span",
|
|
305
336
|
{
|
|
306
337
|
className: "inline-block w-[10px] h-[10px] rounded-[2px]",
|
|
@@ -308,26 +339,26 @@ function GithubActivity({ username, theme = "dark", className }) {
|
|
|
308
339
|
}
|
|
309
340
|
),
|
|
310
341
|
"Best day:",
|
|
311
|
-
/* @__PURE__ */
|
|
342
|
+
/* @__PURE__ */ jsxs2("span", { className: "text-neutral-200 font-semibold", children: [
|
|
312
343
|
bestDay.count,
|
|
313
344
|
" contributions on ",
|
|
314
345
|
bestDay.date
|
|
315
346
|
] })
|
|
316
347
|
] })
|
|
317
348
|
] }),
|
|
318
|
-
/* @__PURE__ */
|
|
319
|
-
/* @__PURE__ */
|
|
349
|
+
/* @__PURE__ */ jsx3("div", { className: "border border-neutral-800 rounded-xl p-4 bg-neutral-950", children: error ? /* @__PURE__ */ jsx3("p", { className: "text-sm text-neutral-400 italic", children: "GitHub activity unavailable." }) : loading ? /* @__PURE__ */ jsx3(Skeleton, {}) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
350
|
+
/* @__PURE__ */ jsx3("div", { className: "overflow-x-auto pb-1", children: /* @__PURE__ */ jsxs2(
|
|
320
351
|
"div",
|
|
321
352
|
{
|
|
322
353
|
className: "relative",
|
|
323
354
|
style: { minWidth: grid.length * STEP + DAY_COL_W + 8 },
|
|
324
355
|
children: [
|
|
325
|
-
/* @__PURE__ */
|
|
356
|
+
/* @__PURE__ */ jsx3(
|
|
326
357
|
"div",
|
|
327
358
|
{
|
|
328
359
|
className: "relative h-[18px] mb-1",
|
|
329
360
|
style: { marginLeft: DAY_COL_W },
|
|
330
|
-
children: labels.map(({ label, col }) => /* @__PURE__ */
|
|
361
|
+
children: labels.map(({ label, col }) => /* @__PURE__ */ jsx3(
|
|
331
362
|
"span",
|
|
332
363
|
{
|
|
333
364
|
className: "absolute text-[11px] text-neutral-400",
|
|
@@ -338,15 +369,15 @@ function GithubActivity({ username, theme = "dark", className }) {
|
|
|
338
369
|
))
|
|
339
370
|
}
|
|
340
371
|
),
|
|
341
|
-
/* @__PURE__ */
|
|
342
|
-
/* @__PURE__ */
|
|
372
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex gap-[3px]", children: [
|
|
373
|
+
/* @__PURE__ */ jsx3(
|
|
343
374
|
"div",
|
|
344
375
|
{
|
|
345
376
|
className: "flex flex-col gap-[3px]",
|
|
346
377
|
style: { width: DAY_COL_W - GAP },
|
|
347
378
|
children: Array.from({ length: 7 }).map((_, i) => {
|
|
348
379
|
var _a2;
|
|
349
|
-
return /* @__PURE__ */
|
|
380
|
+
return /* @__PURE__ */ jsx3(
|
|
350
381
|
"div",
|
|
351
382
|
{
|
|
352
383
|
className: "h-[13px] text-[10px] text-right pr-1.5 text-neutral-400",
|
|
@@ -357,7 +388,7 @@ function GithubActivity({ username, theme = "dark", className }) {
|
|
|
357
388
|
})
|
|
358
389
|
}
|
|
359
390
|
),
|
|
360
|
-
grid.map((week, wi) => /* @__PURE__ */
|
|
391
|
+
grid.map((week, wi) => /* @__PURE__ */ jsx3("div", { className: "flex flex-col gap-[3px]", children: week.map((day, di) => /* @__PURE__ */ jsx3(
|
|
361
392
|
"div",
|
|
362
393
|
{
|
|
363
394
|
className: "w-[13px] h-[13px] rounded-[3px] transition-transform hover:scale-125",
|
|
@@ -379,9 +410,9 @@ function GithubActivity({ username, theme = "dark", className }) {
|
|
|
379
410
|
]
|
|
380
411
|
}
|
|
381
412
|
) }),
|
|
382
|
-
/* @__PURE__ */
|
|
413
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-1 mt-3 text-[11px] text-neutral-400", children: [
|
|
383
414
|
"Less",
|
|
384
|
-
colors.map((c, i) => /* @__PURE__ */
|
|
415
|
+
colors.map((c, i) => /* @__PURE__ */ jsx3(
|
|
385
416
|
"div",
|
|
386
417
|
{
|
|
387
418
|
className: "w-[13px] h-[13px] rounded-[3px]",
|
|
@@ -391,9 +422,9 @@ function GithubActivity({ username, theme = "dark", className }) {
|
|
|
391
422
|
)),
|
|
392
423
|
"More"
|
|
393
424
|
] }),
|
|
394
|
-
/* @__PURE__ */
|
|
395
|
-
/* @__PURE__ */
|
|
396
|
-
/* @__PURE__ */
|
|
425
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex flex-wrap items-center gap-1.5 mt-4 pt-3 border-t border-neutral-800", children: [
|
|
426
|
+
/* @__PURE__ */ jsx3("span", { className: "text-[11px] text-neutral-400 mr-1", children: "Year:" }),
|
|
427
|
+
/* @__PURE__ */ jsx3(
|
|
397
428
|
YearPill,
|
|
398
429
|
{
|
|
399
430
|
label: "Last year",
|
|
@@ -401,7 +432,7 @@ function GithubActivity({ username, theme = "dark", className }) {
|
|
|
401
432
|
onClick: () => setSelectedYear("last")
|
|
402
433
|
}
|
|
403
434
|
),
|
|
404
|
-
years.map((y) => /* @__PURE__ */
|
|
435
|
+
years.map((y) => /* @__PURE__ */ jsx3(
|
|
405
436
|
YearPill,
|
|
406
437
|
{
|
|
407
438
|
label: String(y),
|
|
@@ -412,7 +443,7 @@ function GithubActivity({ username, theme = "dark", className }) {
|
|
|
412
443
|
))
|
|
413
444
|
] })
|
|
414
445
|
] }) }),
|
|
415
|
-
tip && /* @__PURE__ */
|
|
446
|
+
tip && /* @__PURE__ */ jsx3(Tooltip, { day: tip.day, x: tip.x, y: tip.y })
|
|
416
447
|
]
|
|
417
448
|
}
|
|
418
449
|
);
|