"use client";
import { useEffect, useState } from "react";
import Link from "next/link";
import {
CodeXml, Copy, Eye, MessageSquare, GitFork, Users,
Plus, Zap, ShieldCheck, Binary,
} from "lucide-react";
import type { SnippetStats } from "@/lib/api";
import { snippetLangColor } from "@/lib/snippetLangColors";
const MONO = "var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace)";
function useRollIn(target: number, duration = 1000) {
const [value, setValue] = useState(0);
useEffect(() => {
const start = performance.now();
let raf = 0;
const tick = (t: number) => {
const p = Math.min((t - start) / duration, 1);
const ease = 1 - Math.pow(1 - p, 3);
setValue(Math.round(target * ease));
if (p < 1) raf = requestAnimationFrame(tick);
};
raf = requestAnimationFrame(tick);
return () => cancelAnimationFrame(raf);
}, [target, duration]);
return value;
}
function formatK(n: number) {
if (n >= 100_000) return `${(n / 1000).toFixed(0)}k`;
if (n >= 10_000) return `${(n / 1000).toFixed(0)}k`;
if (n >= 1000) return `${(n / 1000).toFixed(1).replace(/\.0$/, "")}k`;
return `${n}`;
}
function StatBlock({
icon,
label,
value,
delay,
}: {
icon: React.ReactNode;
label: string;
value: string;
delay: number;
}) {
return (
);
}
function LangMatrix({
topLanguages,
total,
}: {
topLanguages: SnippetStats["top_languages"];
total: number;
}) {
const max = Math.max(1, ...topLanguages.map((l) => l.count));
return (
{topLanguages.map((l, i) => {
const c = snippetLangColor(l.language);
const pct = total > 0 ? Math.round((l.count / total) * 100) : 0;
return (
);
})}
);
}
/** 语言跑马灯:10 种热门语言 ×2 循环 */
function LangTicker({ langs }: { langs: string[] }) {
const doubled = [...langs, ...langs];
return (
{doubled.map((l, i) => (
{l}
))}
);
}
export default function SnippetHero({
stats,
isLoggedIn,
}: {
stats: SnippetStats | null;
isLoggedIn: boolean;
}) {
const s = stats;
const total = useRollIn(s?.total_snippets ?? 0);
const copies = useRollIn(s?.total_copies ?? 0);
const views = useRollIn(s?.total_views ?? 0);
const comments = useRollIn(s?.total_comments ?? 0);
const forks = useRollIn(s?.total_forks ?? 0);
const contributors = useRollIn(s?.contributors ?? 0);
// 跑马灯展示的热门语言(去重后取前 10,兜底硬编码)
const tickerLangs = Array.from(new Set([
...topLangNames(s?.top_languages),
"go", "rust", "typescript", "python", "javascript", "bash", "dockerfile", "kotlin", "yaml", "sql",
])).slice(0, 10);
return (
{/* 网格底纹 */}
{/* 扫描光束 */}
{/* 内容层 */}
{/* 顶部栏 */}
$ jiang13/snippets
--public --summary
代码片段广场
ONLINE
{isLoggedIn && (
新建
)}
{/* 统计区 */}
} label="Snippets" value={formatK(total)} delay={0} />
} label="Views" value={formatK(views)} delay={60} />
} label="Copies" value={formatK(copies)} delay={120} />
} label="Forks" value={formatK(forks)} delay={180} />
} label="Comments" value={formatK(comments)} delay={240} />
} label="Devs" value={formatK(contributors)} delay={300} />
{/* 语言矩阵 */}
{s && s.top_languages.length > 0 &&
}
{/* 底栏 */}
{s ? "DATA_SYNCED" : "OFFLINE"}
LAT 37.7749°N LNG 122.4194°W
{/* 语言跑马灯 */}
);
}
function topLangNames(arr?: { language: string; count: number }[]) {
if (!arr) return [];
return arr.map((a) => a.language).filter(Boolean);
}