File size: 4,013 Bytes
3857bd9
fdb7c58
d088c21
fdb7c58
cd201c7
 
494bbae
cd201c7
 
fdb7c58
 
 
 
 
d088c21
 
929d75e
 
cd201c7
fdb7c58
 
cd201c7
 
 
 
 
 
 
 
 
 
3857bd9
 
98fcc8e
3857bd9
 
98fcc8e
3857bd9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98fcc8e
3857bd9
 
cd201c7
fbae805
 
494bbae
fbae805
 
 
 
 
 
 
 
 
 
 
 
 
494bbae
fdb7c58
d088c21
929d75e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d088c21
929d75e
fdb7c58
cd201c7
 
 
 
 
3857bd9
fbae805
 
3857bd9
cd201c7
 
 
3857bd9
 
 
 
 
 
 
 
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
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 separate intensity levels for light and dark modes
  const lightIntensityColors = [
    emptyColor,  // level 0
    getHeatmapColorIntensity(1, color, false), // level 1 (bright for light mode)
    getHeatmapColorIntensity(2, color, false), // level 2
    getHeatmapColorIntensity(3, color, false), // level 3
    getHeatmapColorIntensity(4, color, false)  // level 4 (darkest for light mode)
  ].filter((color): color is string => color !== null);
  
  const darkIntensityColors = [
    emptyColor,  // level 0
    getHeatmapColorIntensity(1, color, true), // level 1 (darker for dark mode)
    getHeatmapColorIntensity(2, color, true), // level 2
    getHeatmapColorIntensity(3, color, true), // level 3
    getHeatmapColorIntensity(4, color, true)  // level 4 (brightest for dark mode)
  ].filter((color): color is string => color !== null);
  
  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: lightIntensityColors,
              dark: darkIntensityColors
            }}
            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;