File size: 4,165 Bytes
3857bd9 fdb7c58 d088c21 fdb7c58 cd201c7 494bbae cd201c7 fdb7c58 d088c21 929d75e cd201c7 fdb7c58 cd201c7 3857bd9 98fcc8e 3857bd9 98fcc8e 3857bd9 98fcc8e 3857bd9 cd201c7 4c668a3 fbae805 4c668a3 494bbae fdb7c58 d088c21 929d75e d088c21 929d75e fdb7c58 cd201c7 4c668a3 cd201c7 3857bd9 4c668a3 3857bd9 cd201c7 66f319d cd201c7 fdb7c58 3857bd9 |
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 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
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 the correct color progression based on current theme
const getThemeAwareColors = () => {
const colors = [emptyColor]; // level 0
for (let level = 1; level <= 4; level++) {
const intensity = getHeatmapColorIntensity(level, color, isDarkMode);
if (intensity) {
colors.push(intensity);
}
}
return colors;
};
const themeColors = getThemeAwareColors();
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
key={`${isDarkMode}-${color}`} // Force re-render on theme change
data={processedData}
theme={{
light: themeColors,
dark: themeColors
}}
blockSize={11}
blockMargin={2}
hideTotalCount
renderBlock={(block, activity) => {
const activityData = activity as any; // Type assertion since react-activity-calendar may not have our extended type
const itemsText = activityData.items && activityData.items.length > 0
? activityData.items.join(', ')
: 'No releases';
const tooltipTitle = activity.count > 0
? `${activity.count} new repos on ${activity.date}: ${itemsText}`
: `No repos on ${activity.date}`;
return (
<Tooltip
title={tooltipTitle}
arrow
>
{block}
</Tooltip>
);
}}
/>
)}
</div>
</div>
);
};
export default Heatmap;
|