diff --git a/app/api/chat/route.ts b/app/api/chat/route.ts index 5e872c6e..ed2ba00d 100644 --- a/app/api/chat/route.ts +++ b/app/api/chat/route.ts @@ -8,7 +8,6 @@ export const maxDuration = 30; interface ChatRequest { messages: UIMessage[]; system?: string; - tools?: unknown; pageContext?: { title?: string; description?: string; diff --git a/app/components/ActivityTicker.tsx b/app/components/ActivityTicker.tsx index 6c0f981b..8de66dd0 100644 --- a/app/components/ActivityTicker.tsx +++ b/app/components/ActivityTicker.tsx @@ -1,14 +1,4 @@ -"use client"; - -import Image from "next/image"; -import Link from "next/link"; -import React, { useCallback, useEffect, useMemo, useState } from "react"; -import { ChevronLeft, ChevronRight, X } from "lucide-react"; -import { - activityEventsConfig, - type ActivityEvent, - type ActivityTickerSettings, -} from "@/app/types/event"; +import { activityEventsConfig } from "@/app/types/event"; import { cn } from "@/lib/utils"; const { events: rawEvents, settings } = activityEventsConfig; @@ -16,11 +6,10 @@ const { events: rawEvents, settings } = activityEventsConfig; const { maxItems: configuredMaxItems = 3, rotationIntervalMs: configuredRotationIntervalMs = 8000, -}: ActivityTickerSettings = settings; +} = settings; // 默认配置,从data/event.json中读取配置 const MAX_ITEMS = configuredMaxItems; -const ROTATION_INTERVAL_MS = configuredRotationIntervalMs; /** ActivityTicker 外部传入的样式配置 */ type ActivityTickerProps = { @@ -31,151 +20,70 @@ type ActivityTickerProps = { /** * 首页活动轮播组件: * - 读取 event.json 配置的活动数量 - * - 自动轮播封面图,顶部指示器支持手动切换 - * - 底部两个毛玻璃按钮:Discord 永远可见,Playback 仅在 deprecated=true 时显示 + * - 横向跑马灯自动滚动,悬停暂停 + * - 每条活动可点击跳转到 Discord */ export function ActivityTicker({ className }: ActivityTickerProps) { - // 预处理活动列表,保持初次渲染后的引用稳定 - const events = useMemo(() => { - return rawEvents.slice(0, MAX_ITEMS); - }, []); - - // 当前展示的活动索引 - const [activeIndex, setActiveIndex] = useState(0); - const totalEvents = events.length; - - // 控制浮窗显隐 - const [isClosed, setIsClosed] = useState(false); - - useEffect(() => { - if (isClosed || totalEvents <= 1) { - return; - } - - // 定时轮播,间隔 ROTATION_INTERVAL_MS - const timer = window.setInterval(() => { - setActiveIndex((prev) => (prev + 1) % totalEvents); - }, ROTATION_INTERVAL_MS); - - return () => window.clearInterval(timer); - }, [totalEvents, activeIndex, isClosed]); - - const handlePrev = useCallback(() => { - if (totalEvents <= 1) { - return; - } - setActiveIndex((prev) => (prev - 1 + totalEvents) % totalEvents); - }, [totalEvents]); - - const handleNext = useCallback(() => { - if (totalEvents <= 1) { - return; - } - setActiveIndex((prev) => (prev + 1) % totalEvents); - }, [totalEvents]); + const events = rawEvents.slice(0, MAX_ITEMS); + const animationDurationMs = + configuredRotationIntervalMs * Math.max(events.length, 1); + const lastEventIndex = events.length - 1; - if (totalEvents === 0) { + if (events.length === 0) { return null; } - if (isClosed) { - return null; - } - - const activeEvent = events[activeIndex]; - const coverSrc = activeEvent.coverUrl; - const showPlayback = activeEvent.deprecated && Boolean(activeEvent.playback); + const renderEvent = ( + event: (typeof events)[number], + keyPrefix: string, + idx: number, + ) => ( +
+ {idx === lastEventIndex ? ( + + Update + + ) : null} + + {event.name} —{" "} + {event.deprecated ? "Archives Available" : "Event Active"} + + + + Edition 1.0.0 + +
+ ); return ( -
- - +
); } diff --git a/app/components/BrandMark.tsx b/app/components/BrandMark.tsx index a0407d71..efbfa1f2 100644 --- a/app/components/BrandMark.tsx +++ b/app/components/BrandMark.tsx @@ -58,7 +58,10 @@ export function BrandMark({ /> {BRAND_NAME} diff --git a/app/components/Community.tsx b/app/components/Community.tsx index b1d1201a..65ffcefb 100644 --- a/app/components/Community.tsx +++ b/app/components/Community.tsx @@ -1,5 +1,4 @@ -import { Button } from "../../components/ui/button"; -import { Card, CardContent } from "../../components/ui/card"; +import { Button } from "@/components/ui/button"; import { ExternalLink, MessageCircle, @@ -10,123 +9,125 @@ import { export function Community() { return ( -
+
-
-

- 成为{" "} - - 社区 - {" "} - 的一员 +
+

+ Community
Archives

-

- 与来自世界各地的开发者一起学习、成长、创造。每个人的贡献都让社区变得更好。 -

+
+ Join thousands of researchers and developers in our distributed + network. +
- {/* Main CTA Card */} -
- - -
-
- -
-

- 内卷知识库 -

-

- 探索我们精心整理的技术文档、教程和工具。从基础到进阶,应有尽有。 -

- -
-
-
+ {/* Main CTA Section */} +
+
+
+ +
+

+ 内卷知识库 +

+

+ 探索我们精心整理的技术文档、教程和工具。从基础到进阶,应有尽有。我们不仅是在分享知识,更是在构建共识。 +

+ +
+ {/* Halftone background effect */} +
- {/* Action Cards */} -
- - -
-
- -
-

GitHub 仓库

-

- 查看源代码,提交 Issue,参与项目讨论。 -

- -
-
-
+ {/* Action Cards Grid */} +
+
+
+ +
+

+ GitHub 仓库 +

+

+ 查看源代码,提交 Issue,参与项目讨论。每一个 Commit + 都是对社区的贡献。 +

+ +
- - -
-
- -
-

Discord 社区

-

- 实时交流,分享经验,结识志同道合的朋友。 -

- -
-
-
+
+
+ +
+

+ Discord 社区 +

+

+ 实时交流,分享经验,结识志同道合的朋友。打破孤岛,共同成长。 +

+ +
- - -
-
- -
-

文献资料

-

- 访问我们在 Zotero 的文献库,获取精选学术资源。 -

- -
-
-
+
+
+ +
+

+ 文献资料 +

+

+ 访问我们在 Zotero 的文献库,获取精选学术资源。连接前沿科技。 +

+ +

diff --git a/app/components/Contribute.tsx b/app/components/Contribute.tsx index 670f72d8..dff5ce03 100644 --- a/app/components/Contribute.tsx +++ b/app/components/Contribute.tsx @@ -13,7 +13,6 @@ import { } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { ExternalLink, Sparkles } from "lucide-react"; -import styles from "./Contribute.module.css"; import { useRouter } from "next/navigation"; // --- antd @@ -159,62 +158,18 @@ export function Contribute() { @@ -225,9 +180,9 @@ export function Contribute() { rel="noopener noreferrer" aria-label="查看投稿指南" title="查看投稿指南" - className="absolute top-0 right-0 flex h-11 w-11 translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full border border-white/80 bg-white text-sky-600 shadow-lg ring-1 ring-sky-400/60 transition-transform hover:-translate-y-1/2 hover:translate-x-1/2 hover:scale-105 hover:shadow-xl focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring dark:border-slate-700 dark:bg-slate-900 dark:text-sky-300" + className="absolute top-0 right-0 flex h-10 w-10 translate-x-1/2 -translate-y-1/2 items-center justify-center border border-[var(--foreground)] bg-[var(--background)] text-[var(--foreground)] font-mono hover:bg-[#CC0000] hover:text-white transition-colors z-20" > - ? + ? 查看投稿指南 diff --git a/app/components/DocsAssistant.tsx b/app/components/DocsAssistant.tsx index 576bb723..e877ed8e 100644 --- a/app/components/DocsAssistant.tsx +++ b/app/components/DocsAssistant.tsx @@ -93,9 +93,29 @@ interface AssistantErrorState { showSettingsCTA: boolean; } +type AssistantProvider = "openai" | "gemini" | "intern"; + +type AssistantErrorData = { + error?: string; +}; + +type AssistantErrorPayload = { + message?: string; + statusCode?: number; + responseBody?: string; + data?: AssistantErrorData; +}; + +type AssistantErrorInput = + | AssistantErrorPayload + | Error + | string + | null + | undefined; + function deriveAssistantError( - err: unknown, - provider: "openai" | "gemini" | "intern", + err: AssistantErrorInput, + provider: AssistantProvider, ): AssistantErrorState { const providerLabel = provider === "gemini" @@ -113,12 +133,7 @@ function deriveAssistantError( return fallback; } - const maybeError = err as Partial<{ - message?: string; - statusCode?: number; - responseBody?: string; - data?: unknown; - }>; + const maybeError = coerceAssistantErrorPayload(err); let message = ""; @@ -139,15 +154,8 @@ function deriveAssistantError( } } - if (!message && err instanceof Error && typeof err.message === "string") { - message = err.message.trim(); - } - - if (!message && maybeError.data && typeof maybeError.data === "object") { - const dataError = (maybeError.data as { error?: unknown }).error; - if (typeof dataError === "string" && dataError.trim().length > 0) { - message = dataError.trim(); - } + if (!message && maybeError.data?.error) { + message = maybeError.data.error.trim(); } const statusCode = @@ -193,6 +201,21 @@ function deriveAssistantError( }; } +function coerceAssistantErrorPayload( + err: AssistantErrorInput, +): AssistantErrorPayload { + if (!err) { + return {}; + } + if (typeof err === "string") { + return { message: err }; + } + if (err instanceof Error) { + return { message: err.message }; + } + return err; +} + function extractErrorFromResponseBody(body: string): string | undefined { const trimmed = body.trim(); if (!trimmed) { @@ -200,16 +223,16 @@ function extractErrorFromResponseBody(body: string): string | undefined { } try { - const parsed = JSON.parse(trimmed); + const parsed = JSON.parse(trimmed) as string | AssistantErrorData; if (typeof parsed === "string") { return parsed.trim(); } if ( parsed && typeof parsed === "object" && - typeof (parsed as { error?: unknown }).error === "string" + typeof parsed.error === "string" ) { - return (parsed as { error: string }).error.trim(); + return parsed.error.trim(); } } catch { // Ignore JSON parsing issues and fall back to the raw body text. diff --git a/app/components/Features.tsx b/app/components/Features.tsx index d8009fd5..44e1c67b 100644 --- a/app/components/Features.tsx +++ b/app/components/Features.tsx @@ -1,10 +1,16 @@ -import { Card, CardContent } from "@/components/ui/card"; -import { Badge } from "@/components/ui/badge"; +import React from "react"; import { Users, Zap, Heart } from "lucide-react"; import { Github as GithubIcon } from "./icons/Github"; +import { cn } from "@/lib/utils"; export function Features() { - const features = [ + const features: { + icon: React.ReactElement<{ className?: string }>; + title: string; + description: string; + highlight: string; + color: string; + }[] = [ { icon: , title: "完全开源", @@ -40,47 +46,55 @@ export function Features() { ]; return ( -
+
-
-

- - 内卷地狱 - - 想做什么{" "} -

- -

- 我们致力于创造一个真正属于开发者的学习环境,让每个人都能在这里获得成长。 +

+

+ Mission
Statement +

+

+ 我们致力于创造一个真正属于开发者的学习环境,让每个人都能在这里获得成长。在这里,知识是流动的,门槛是不存在的,而内卷是被鄙视的。

-
+
{features.map((feature, index) => ( - - -
-
{feature.icon}
-
-
-

{feature.title}

- - {feature.highlight} - +
+
+
+ {/* Simplified icon styling */} +
+ {React.cloneElement(feature.icon, { + className: cn("h-8 w-8", feature.icon.props.className), + })}
-

- {feature.description} -

+
+ SEC. 0{index + 1} +
+
+ +
+

+ {feature.title} +

+ + {feature.highlight} +
- {/* Hover effect decoration */} -
- - +

+ {feature.description} +

+
+
))}
diff --git a/app/components/Footer.tsx b/app/components/Footer.tsx index db7016c7..e19f569a 100644 --- a/app/components/Footer.tsx +++ b/app/components/Footer.tsx @@ -1,32 +1,35 @@ import Link from "next/link"; -import { Github, MessageCircle, ExternalLink } from "lucide-react"; +import { Github, MessageCircle } from "lucide-react"; import { BrandMark } from "./BrandMark"; import { LicenseNotice } from "./LicenseNotice"; export function Footer() { return ( -