File size: 3,630 Bytes
372711a fdb7c58 d088c21 fdb7c58 cd201c7 dbb3299 cd201c7 fdb7c58 d088c21 929d75e cd201c7 fdb7c58 cd201c7 372711a 98fcc8e 372711a 98fcc8e 372711a 98fcc8e 372711a cd201c7 dbb3299 fdb7c58 d088c21 929d75e d088c21 929d75e fdb7c58 cd201c7 372711a dbb3299 372711a cd201c7 372711a cd201c7 fdb7c58 372711a |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
import React, { useEffect, useState } from "react";
import ActivityCalendar from "react-activity-calendar";
import { Tooltip, Avatar } from "@mui/material";
import Link from "next/link";
import { aggregateToWeeklyData } from "../utils/weeklyCalendar";
import WeeklyHeatmap from "./WeeklyHeatmap";
import { getHeatmapTheme, getHeatmapColorIntensity } from "../utils/heatmapColors";
type ViewMode = 'daily' | 'weekly';
type HeatmapProps = {
data: Array<{ date: string; count: number; level: number }>;
color: string;
providerName: string;
fullName: string;
avatarUrl: string;
authorId: string;
showHeader?: boolean;
viewMode: ViewMode;
};
const Heatmap: React.FC<HeatmapProps> = ({
data,
color,
providerName,
fullName,
avatarUrl,
authorId,
showHeader = true,
viewMode
}) => {
// Process data based on view mode
const processedData = viewMode === 'weekly' ? aggregateToWeeklyData(data) : data;
// Track theme state for proper ActivityCalendar theming
const [isDarkMode, setIsDarkMode] = useState(false);
useEffect(() => {
// Check initial theme
const checkTheme = () => {
setIsDarkMode(document.documentElement.classList.contains('dark'));
};
checkTheme();
// Watch for theme changes
const observer = new MutationObserver(checkTheme);
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ['class']
});
return () => observer.disconnect();
}, []);
// Use theme-aware colors
const emptyColor = isDarkMode ? "#374151" : "#d1d5db";
// Create intensity levels for daily view (same as weekly)
const intensityColors = [
emptyColor, // level 0
getHeatmapColorIntensity(1, color), // level 1 (40% intensity)
getHeatmapColorIntensity(2, color), // level 2 (60% intensity)
getHeatmapColorIntensity(3, color), // level 3 (80% intensity)
getHeatmapColorIntensity(4, color) // level 4 (100% intensity)
].filter((color): color is string => color !== null); // Remove any null values and type guard
return (
<div className="flex flex-col items-center w-full mx-auto">
{showHeader && (
<div className="flex flex-col sm:flex-row items-center mb-4 w-full justify-center">
{avatarUrl && (
<Avatar src={avatarUrl} alt={fullName} className="mb-2 sm:mb-0 sm:mr-4" sx={{ width: 48, height: 48 }} />
)}
<div className="text-center sm:text-left">
<h2 className="text-lg font-semibold">
<Link
href={`https://huggingface.co/${authorId}`}
target="_blank"
rel="noopener noreferrer"
className="hover:text-blue-500 hover:underline"
>
{fullName}
</Link>
</h2>
</div>
</div>
)}
<div className="w-full overflow-x-auto flex justify-center">
{viewMode === 'weekly' ? (
<WeeklyHeatmap data={processedData} color={color} />
) : (
<ActivityCalendar
data={processedData}
theme={{
light: intensityColors,
dark: intensityColors
}}
blockSize={11}
blockMargin={2}
hideTotalCount
renderBlock={(block, activity) => (
<Tooltip
title={`${activity.count} new repos on ${activity.date}`}
arrow
>
{block}
</Tooltip>
)}
/>
)}
</div>
</div>
);
};
export default Heatmap;
|