cgeorgiaw's picture
cgeorgiaw HF Staff
avi_tag_selector (#1)
cd201c7 verified
raw
history blame
3.86 kB
import React, { useState, useEffect, useMemo } from "react";
import { ProviderInfo, ModelData, CalendarData } from "../types/heatmap";
import OrganizationButton from "../components/OrganizationButton";
import HeatmapGrid from "../components/HeatmapGrid";
import Navbar from "../components/Navbar";
import TagSelector from "../components/TagSelector";
import { getProviders } from "../utils/ranking";
import { ORGANIZATIONS, SCIENTIFIC_TAGS } from "../constants/organizations";
interface PageProps {
calendarData: CalendarData;
providers: ProviderInfo[];
}
function Page({
calendarData,
providers,
}: PageProps) {
const [isLoading, setIsLoading] = useState(true);
const [selectedTags, setSelectedTags] = useState<string[]>([]);
useEffect(() => {
if (calendarData && Object.keys(calendarData).length > 0) {
setIsLoading(false);
}
}, [calendarData]);
// Filter providers based on selected tags
const filteredProviders = useMemo(() => {
if (selectedTags.length === 0) {
return providers;
}
return providers.filter(provider => {
if (!provider.tags) return false;
return selectedTags.some(tag => provider.tags!.includes(tag));
});
}, [providers, selectedTags]);
const handleTagToggle = (tagId: string) => {
setSelectedTags(prev => {
if (prev.includes(tagId)) {
return prev.filter(t => t !== tagId);
} else {
return [...prev, tagId];
}
});
};
return (
<div className="w-full">
<Navbar />
<div className="w-full p-4 py-16">
<div className="text-center mb-16 max-w-4xl mx-auto">
<h1 className="text-2xl sm:text-3xl md:text-4xl lg:text-6xl font-bold text-foreground mb-6 bg-gradient-to-r from-foreground to-foreground/80 bg-clip-text">
<span className="inline-flex items-center gap-1 sm:gap-2">
Hugging Science Heatmap
<img
src="/hf-icon.svg"
alt="Hugging Face icon"
className="size-6 sm:size-8 md:size-10"
/>
</span>
</h1>
<p className="text-base sm:text-lg lg:text-xl text-muted-foreground max-w-2xl mx-auto leading-relaxed px-4">
Open models, datasets, and apps from orgs contributing to AI4Science in the last year.
</p>
</div>
{/* Tag Selector */}
<div className="mb-16">
<TagSelector
tags={SCIENTIFIC_TAGS}
selectedTags={selectedTags}
onTagToggle={handleTagToggle}
/>
</div>
<div className="mb-16 mx-auto">
<div className="overflow-x-auto scrollbar-hide">
<div className="flex gap-6 px-4 py-2 min-w-max justify-center">
{filteredProviders.map((provider, index) => (
<OrganizationButton
key={provider.fullName || provider.authors[0]}
provider={provider}
calendarData={calendarData}
rank={index + 1}
/>
))}
</div>
</div>
</div>
<HeatmapGrid
sortedProviders={filteredProviders}
calendarData={calendarData}
isLoading={isLoading}
/>
</div>
</div>
);
}
export async function getStaticProps() {
try {
const { calendarData, providers } = await getProviders(ORGANIZATIONS);
return {
props: {
calendarData,
providers,
},
revalidate: 3600, // regenerate every hour
};
} catch (error) {
console.error("Error fetching data:", error);
return {
props: {
calendarData: {},
providers: ORGANIZATIONS,
},
revalidate: 60, // retry after 1 minute if there was an error
};
}
}
export default Page;