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;