Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
1eaf523
fix(api/docs/history): 兼容 fumadocs 的相对路径参数
longsizhuo Apr 15, 2026
001fd16
style(ui): 对齐 editorial 设计系统,修复 6 处视觉一致性问题
longsizhuo Apr 15, 2026
967b07b
fix(settings): 修复主题切换双 Provider 冲突 + 双向同步
longsizhuo Apr 15, 2026
cf6997d
fix(nav): 非首页点击 Header 也能回主页
longsizhuo Apr 15, 2026
5335ca6
feat(i18n): 文档站双语切换 locale (cookie + middleware IP 判断)
longsizhuo Apr 15, 2026
4e511ae
feat(home): 首页 Leaderboard 右侧新增'本周最热'面板 (HotDocsPreview)
longsizhuo Apr 15, 2026
93c1648
feat(scripts): contributors 脚本跳过翻译版文档
longsizhuo Apr 15, 2026
32031b7
feat(docs): i18n MVP — 翻译 5 篇代表性文档
longsizhuo Apr 15, 2026
db1a25c
feat(docs): i18n CommunityShare 全部翻译完成 (13 篇)
longsizhuo Apr 15, 2026
7a15e9b
feat(docs): i18n ai/ 前半部分全部翻译完成 (24 篇)
longsizhuo Apr 15, 2026
07bd538
feat(docs): i18n computer-science + jobs + all-projects 翻译完成 (23 篇)
longsizhuo Apr 15, 2026
35c96b5
feat(docs): i18n Leetcode 目录翻译完成 (42 篇)
longsizhuo Apr 15, 2026
0ee40fa
feat(docs): i18n ai/ 后半部分翻译完成 + MDX 语法修复 (32 篇)
longsizhuo Apr 15, 2026
a90ccef
fix(docs): 翻译格式微调 — 补 H1 标题、修标题层级
longsizhuo Apr 15, 2026
2643421
fix(lint): Header.tsx 的 <a href="/..."> 改 next/link <Link>
longsizhuo Apr 15, 2026
fcd0d7a
Merge branch 'main' into feat/i18n-and-ux-iteration
longsizhuo Apr 15, 2026
c001f95
feat(home): 用 DispatchNetwork 横条替代 Features + Community 两段 useless 区块
longsizhuo Apr 15, 2026
94d8de4
fix(pr281): 修复 Copilot Review 提出的 6 处问题
longsizhuo Apr 15, 2026
d9c86e8
fix(search): 按语言分片 search.json,规避 Vercel 19MB ISR 上限
longsizhuo Apr 15, 2026
6793dda
feat(analytics): 埋点迁到 Java 后端 /analytics/events
longsizhuo Apr 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 0 additions & 32 deletions app/api/analytics/route.ts

This file was deleted.

5 changes: 5 additions & 0 deletions app/api/docs/history/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ function normalizeDocsPath(raw: string): string | null {
if (normalized.startsWith("docs/")) {
normalized = `app/${normalized}`;
}
// fumadocs 的 page.file.path 返回"相对 app/docs/"路径(如 ai/xxx/index.mdx)
// 而不是仓库根。这里补上前缀,和 page.tsx 传参保持兼容。
if (!normalized.startsWith("app/")) {
normalized = `app/docs/${normalized}`;
}
// 必须落在 app/docs/ 下才放行
if (!normalized.startsWith("app/docs/")) {
return null;
Expand Down
5 changes: 3 additions & 2 deletions app/components/BrandMark.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* @param {boolean} priority - 是否优先加载
*/
import Image from "next/image";
import Link from "next/link";
import { cn } from "@/lib/utils";

export const BRAND_NAME = "Involution Hell";
Expand All @@ -38,7 +39,7 @@ export function BrandMark({
const width = Math.round(imageSize * BRAND_LOGO_ASPECT_RATIO);

return (
<div className={cn("flex items-center gap-2", className)}>
<Link href="/" className={cn("flex items-center gap-2", className)}>
<div className="relative">
<Image
src={BRAND_LOGO_LIGHT_SRC}
Expand All @@ -65,6 +66,6 @@ export function BrandMark({
>
{BRAND_NAME}
</span>
</div>
</Link>
);
}
85 changes: 85 additions & 0 deletions app/components/DispatchNetwork.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import Link from "next/link";
import { Github as GithubIcon } from "./icons/Github";
import { MessageCircle, BookMarked, ArrowRight } from "lucide-react";

/**
* DispatchNetwork — 主页 Top Rank 之后的极简网络入口横条
* 替代原先 Features(口号四格)+ Community(链接三卡)两个 section
* 设计意图:报纸末版的"发行网络"小栏,48px 高横条,不重复 Footer
*/
export function DispatchNetwork() {
return (
<section
id="community"
className="border-t-4 border-[var(--foreground)] bg-[var(--background)]"
>
<div className="container mx-auto px-6">
<div className="flex items-center justify-between gap-4 py-3 font-mono text-[11px] uppercase tracking-[0.25em] text-[var(--foreground)] md:text-xs">
{/* 左:栏目标签 */}
<span className="font-bold whitespace-nowrap">
Dispatch Network
<span className="mx-2 hidden text-neutral-400 md:inline">·</span>
<span className="hidden font-normal text-neutral-500 md:inline">
Sec. Net-01
</span>
</span>

{/* 中:三个外链 */}
<nav className="flex items-center gap-3 md:gap-6">
<Link
href="https://github.com/involutionhell"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-1.5 hover:text-[#CC0000] transition-colors"
data-umami-event="social_click"
data-umami-event-platform="github"
data-umami-event-location="dispatch_network"
>
<GithubIcon className="h-3.5 w-3.5" />
<span>GitHub</span>
</Link>
<span className="text-neutral-400">·</span>
<Link
href="https://discord.com/invite/6CGP73ZWbD"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-1.5 hover:text-[#CC0000] transition-colors"
data-umami-event="social_click"
data-umami-event-platform="discord"
data-umami-event-location="dispatch_network"
>
<MessageCircle className="h-3.5 w-3.5" />
<span>Discord</span>
</Link>
<span className="text-neutral-400">·</span>
<Link
href="https://www.zotero.org/groups/6053219/involution_hell"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-1.5 hover:text-[#CC0000] transition-colors"
data-umami-event="social_click"
data-umami-event-platform="zotero"
data-umami-event-location="dispatch_network"
>
<BookMarked className="h-3.5 w-3.5" />
<span>Zotero</span>
</Link>
</nav>

{/* 右:加入 CTA */}
<Link
href="https://discord.com/invite/6CGP73ZWbD"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-1 font-bold whitespace-nowrap hover:text-[#CC0000] transition-colors"
data-umami-event="cta_click"
data-umami-event-label="join_dispatch"
>
<span className="hidden sm:inline">Join</span>
<ArrowRight className="h-3.5 w-3.5" />
</Link>
</div>
</div>
</section>
);
}
10 changes: 5 additions & 5 deletions app/components/DocHistoryPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ function relativeTime(dateStr: string): string {
function SkeletonRow() {
return (
<div className="flex items-center gap-3 py-2.5 animate-pulse">
<div className="w-6 h-6 rounded-full bg-neutral-200 dark:bg-neutral-700 shrink-0" />
<div className="w-6 h-6 bg-neutral-200 dark:bg-neutral-700 shrink-0" />
<div className="flex-1 flex flex-col gap-1">
<div className="h-3 w-2/3 rounded bg-neutral-200 dark:bg-neutral-700" />
<div className="h-2.5 w-1/3 rounded bg-neutral-100 dark:bg-neutral-800" />
<div className="h-3 w-2/3 bg-neutral-200 dark:bg-neutral-700" />
<div className="h-2.5 w-1/3 bg-neutral-100 dark:bg-neutral-800" />
</div>
</div>
);
Expand Down Expand Up @@ -129,15 +129,15 @@ export function DocHistoryPanel({ path }: DocHistoryPanelProps) {
href={item.htmlUrl}
target="_blank"
rel="noopener noreferrer"
className="flex items-start gap-3 py-2.5 group hover:bg-neutral-50 dark:hover:bg-neutral-900 rounded transition-colors px-1 -mx-1"
className="flex items-start gap-3 py-2.5 group hover:bg-neutral-50 dark:hover:bg-neutral-900 transition-colors px-1 -mx-1"
>
{/* 头像 */}
<Image
src={item.avatarUrl || FALLBACK_AVATAR}
alt={item.authorLogin}
width={24}
height={24}
className="rounded-full mt-0.5 shrink-0"
className="mt-0.5 shrink-0"
unoptimized
/>

Expand Down
2 changes: 1 addition & 1 deletion app/components/DocShareButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export function DocShareButton() {
<button
type="button"
onClick={handleCopy}
className="inline-flex items-center gap-2 rounded-md px-4 h-11 text-base font-medium hover:bg-muted/80 hover:text-foreground"
className="inline-flex items-center gap-2 px-3 py-1.5 font-mono text-xs uppercase tracking-widest border border-[var(--foreground)] hover:bg-[var(--foreground)] hover:text-[var(--background)] transition-colors"
aria-label="复制页面链接"
>
<svg
Expand Down
4 changes: 2 additions & 2 deletions app/components/EditOnGithub.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ export function EditOnGithub({ href }: { href: string }) {
return (
<Link
href={href}
className="inline-flex items-center gap-2 rounded-md px-4 h-11 text-base font-medium hover:bg-muted/80 hover:text-foreground no-underline"
className="inline-flex items-center gap-2 px-3 py-1.5 font-mono text-xs uppercase tracking-widest border border-[var(--foreground)] hover:bg-[var(--foreground)] hover:text-[var(--background)] transition-colors no-underline"
data-umami-event="docs_edit_click"
data-umami-event-page={href}
>
<svg
aria-hidden="true"
className="h-8 w-8"
className="h-4 w-4"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
Expand Down
28 changes: 19 additions & 9 deletions app/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Link from "next/link";
import { ThemeToggle } from "./ThemeToggle";
import { Button } from "@/components/ui/button";
import { MessageCircle } from "lucide-react";
Expand Down Expand Up @@ -30,33 +31,42 @@ export function Header() {

<div className="flex items-center justify-between h-10">
<nav className="hidden md:flex items-center gap-8 font-sans text-xs font-bold uppercase tracking-widest text-[var(--foreground)]">
<a
href="#features"
<Link
href="/"
className="hover:text-[#CC0000] transition-colors"
data-umami-event="navigation_click"
data-umami-event-region="header"
data-umami-event-label="home"
>
首页
</Link>
<Link
href="/#features"
className="hover:text-[#CC0000] transition-colors"
data-umami-event="navigation_click"
data-umami-event-region="header"
data-umami-event-label="features"
>
特点
</a>
<a
href="#community"
</Link>
<Link
href="/#community"
className="hover:text-[#CC0000] transition-colors"
data-umami-event="navigation_click"
data-umami-event-region="header"
data-umami-event-label="community"
>
社区
</a>
<a
href="#contact"
</Link>
<Link
href="/#contact"
className="hover:text-[#CC0000] transition-colors"
data-umami-event="navigation_click"
data-umami-event-region="header"
data-umami-event-label="contact"
>
联系我们
</a>
</Link>
</nav>

<div className="flex items-center gap-2">
Expand Down
86 changes: 45 additions & 41 deletions app/components/Hero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Image from "next/image";
import { ActivityTicker } from "@/app/components/ActivityTicker";
import { cn } from "@/lib/utils";
import { AnimatedBar } from "@/app/components/rank/AnimatedBar";
import { HotDocsPreview } from "@/app/components/HotDocsPreview";
import leaderboardData from "@/generated/site-leaderboard.json";
import { MAINTAINERS } from "@/lib/admins";

Expand Down Expand Up @@ -169,49 +170,52 @@ export function Hero() {
</Link>
</div>

<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{(() => {
const rawData = leaderboardData as {
id: string;
name: string;
points: number;
avatarUrl: string;
}[];
const filteredData = rawData.filter(
(user) => !MAINTAINERS.includes(user.name),
);
const top3 = filteredData.slice(0, 3);
const maxPoints = top3.length > 0 ? top3[0].points : 100;
<div className="grid grid-cols-1 lg:grid-cols-12 gap-6">
<div className="lg:col-span-8 grid grid-cols-1 md:grid-cols-3 gap-6">
{(() => {
const rawData = leaderboardData as {
id: string;
name: string;
points: number;
avatarUrl: string;
}[];
const filteredData = rawData.filter(
(user) => !MAINTAINERS.includes(user.name),
);
const top3 = filteredData.slice(0, 3);
const maxPoints = top3.length > 0 ? top3[0].points : 100;

return top3.map((user, idx) => (
<div
key={user.id}
className="border border-[var(--foreground)] p-6 bg-[var(--background)] relative hard-shadow-hover transition-all group"
>
<div className="absolute top-0 right-0 w-12 h-12 bg-[var(--foreground)] text-[var(--background)] flex items-center justify-center font-mono font-bold text-xl border-b border-l border-[var(--foreground)] z-10">
#{idx + 1}
</div>
<div className="w-16 h-16 bg-neutral-100 dark:bg-neutral-800 border border-[var(--foreground)] mb-4 transition-transform group-hover:scale-110 overflow-hidden">
<Image
src={user.avatarUrl}
alt={user.name}
width={64}
height={64}
className="w-full h-full object-cover transition-all duration-300"
/>
</div>
<div className="font-serif text-2xl font-bold uppercase text-[var(--foreground)] mb-1 truncate">
{user.name}
</div>
<div className="font-mono text-xs text-neutral-500 uppercase tracking-widest mb-4">
{user.points.toLocaleString()} PTS
return top3.map((user, idx) => (
<div
key={user.id}
className="border border-[var(--foreground)] p-6 bg-[var(--background)] relative hard-shadow-hover transition-all group"
>
<div className="absolute top-0 right-0 w-12 h-12 bg-[var(--foreground)] text-[var(--background)] flex items-center justify-center font-mono font-bold text-xl border-b border-l border-[var(--foreground)] z-10">
#{idx + 1}
</div>
<div className="w-16 h-16 bg-neutral-100 dark:bg-neutral-800 border border-[var(--foreground)] mb-4 transition-transform group-hover:scale-110 overflow-hidden">
<Image
src={user.avatarUrl}
alt={user.name}
width={64}
height={64}
className="w-full h-full object-cover transition-all duration-300"
/>
</div>
<div className="font-serif text-2xl font-bold uppercase text-[var(--foreground)] mb-1 truncate">
{user.name}
</div>
<div className="font-mono text-xs text-neutral-500 uppercase tracking-widest mb-4">
{user.points.toLocaleString()} PTS
</div>
<AnimatedBar value={user.points} max={maxPoints} />
</div>

{/* Visual bar chart representing points using motion */}
<AnimatedBar value={user.points} max={maxPoints} />
</div>
));
})()}
));
})()}
</div>
<div className="lg:col-span-4">
<HotDocsPreview />
</div>
</div>
</div>
</div>
Expand Down
Loading
Loading