diff --git a/src/app/globals.css b/src/app/globals.css index c8cb48f..28dd959 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -63,9 +63,10 @@ --shadow-sm: 0 1px 2px rgba(17, 24, 39, 0.05), 0 3px 10px rgba(17, 24, 39, 0.04); - --shadow-md: 0 10px 28px rgba(17, 24, 39, 0.07); + --shadow-md: 0 8px 24px rgba(17, 24, 39, 0.08), 0 2px 6px rgba(17, 24, 39, 0.06); --shadow-soft: 0 1px 2px rgba(17, 24, 39, 0.04), 0 8px 20px rgba(17, 24, 39, 0.05); + --shadow-lg: 0 12px 32px rgba(17, 24, 39, 0.10), 0 4px 12px rgba(17, 24, 39, 0.08); --radius-lg: 0.75rem; --radius-xl: 1rem; diff --git a/src/app/page.tsx b/src/app/page.tsx index 5f41d7f..c2e09eb 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -2,6 +2,7 @@ export const dynamic = "error"; +import { useState } from "react"; import { AppWindow, ArrowRight, @@ -15,29 +16,29 @@ import { Terminal, Users, } from "lucide-react"; +import { useRouter } from "next/navigation"; import useSWR from "swr"; -import { OpenClawAssistantPane } from "@/components/openclaw/OpenClawAssistantPane"; import type { IntegrationDefaults } from "@/lib/openclaw/types"; +import { useUserStore } from "@/lib/userStore"; +import { XWorkmateAssistantShell } from "@/components/xworkmate/XWorkmateAssistantShell"; import Footer from "../components/Footer"; import UnifiedNavigation from "../components/UnifiedNavigation"; import { useLanguage } from "../i18n/LanguageProvider"; import { translations } from "../i18n/translations"; import { DEFAULT_HOMEPAGE_VIDEO_SETTINGS, - resolveHomepageVideoPresentation, - type HomepageVideoPresentation, type ResolvedHomepageVideoResponse, } from "../lib/home/homepageVideo"; import { useMoltbotStore } from "../lib/moltbotStore"; import { cn } from "../lib/utils"; const HOME_SECTION_CLASS = - "rounded-[1rem] border border-slate-900/8 bg-white/88 shadow-[var(--shadow-soft)]"; + "rounded-[1.25rem] border border-slate-900/8 bg-white/92 shadow-[var(--shadow-md)] backdrop-blur-sm"; const HOME_SECTION_LABEL_CLASS = - "text-[0.68rem] font-semibold uppercase tracking-[0.26em] text-text-subtle"; + "text-[0.7rem] font-semibold uppercase tracking-[0.32em] text-text-subtle flex items-center gap-2"; const HOME_LIST_CARD_CLASS = - "rounded-[0.9rem] border border-slate-900/8 bg-white/82 transition duration-200"; + "rounded-[1rem] border border-slate-900/6 bg-white/90 shadow-sm hover:shadow-lg transition-all duration-300 hover:-translate-y-0.5 hover:bg-white/95"; const EMPTY_ASSISTANT_DEFAULTS: IntegrationDefaults = { openclawUrl: "", openclawOrigin: "", @@ -129,7 +130,7 @@ export default function HomePage() { >
-
+
@@ -147,6 +148,9 @@ export default function HomePage() { export function HeroSection() { const { language } = useLanguage(); const isChinese = language === "zh"; + const router = useRouter(); + const user = useUserStore((state) => state.user); + const [heroPrompt, setHeroPrompt] = useState(""); const assistantDefaultsSWR = useSWR( "/api/integrations/defaults", jsonFetcher, @@ -164,93 +168,258 @@ export function HeroSection() { revalidateOnFocus: false, }, ); + const homeStatsSWR = useSWR( + "/api/marketing/home-stats", + async (url: string) => { + const response = await fetch(url, { cache: "no-store" }); + if (!response.ok) { + throw new Error(`Failed to load home stats: ${response.status}`); + } + return (await response.json()) as HomeStatsResponse; + }, + { + refreshInterval: 60 * 60 * 1000, + revalidateOnFocus: false, + shouldRetryOnError: false, + }, + ); const entry = homepageVideoSWR.data?.resolved ?? DEFAULT_HOMEPAGE_VIDEO_SETTINGS.defaultEntry; - const presentation = resolveHomepageVideoPresentation(entry); + const stats = homeStatsSWR.data; + const locale = isChinese ? "zh-CN" : "en-US"; + const compactFormatter = new Intl.NumberFormat(locale, { + notation: "compact", + maximumFractionDigits: 1, + }); + const displayName = + user?.name?.trim() || + user?.username?.trim() || + user?.email?.split("@")[0] || + (isChinese ? "朋友" : "there"); + const dailyVisitsValue = + typeof stats?.visits?.daily === "number" + ? compactFormatter.format(stats.visits.daily) + : isChinese + ? "同步中" + : "Syncing"; + const registeredUsersValue = + typeof stats?.registeredUsers === "number" + ? compactFormatter.format(stats.registeredUsers) + : isChinese + ? "同步中" + : "Syncing"; const heroCopy = isChinese ? { eyebrow: "AI Native Workspace", subtitle: "从想法到上线,AI 自动完成构建、部署与优化。", - demoLabel: "产品演示", + demoLabel: "动态欢迎", + greeting: "早上好", + todayStatus: "今日状态", + statusItems: [ + { label: "服务", value: "正常" }, + { label: "今日访问", value: dailyVisitsValue }, + { label: "注册用户", value: registeredUsersValue }, + ], + prompt: "有什么想问的?", + quickLinksLabel: "快速入口", + quickLinks: ["常用工具", "最近使用", "产品演示"], + helperNote: "个性化、状态感知、即时信息", + sourceLink: "打开原始链接", + maximizeLabel: "最大化到 XWorkmate", } : { eyebrow: "AI Native Workspace", subtitle: "From idea to launch, AI can assemble, deploy, and optimize the work.", - demoLabel: "Product demo", + demoLabel: "Dynamic welcome", + greeting: "Good morning", + todayStatus: "Today", + statusItems: [ + { label: "Service", value: "Healthy" }, + { label: "Daily visits", value: dailyVisitsValue }, + { label: "Registered", value: registeredUsersValue }, + ], + prompt: "What would you like to ask?", + quickLinksLabel: "Quick access", + quickLinks: ["Tools", "Recent", "Demo"], + helperNote: "Personal, status-aware, and instantly actionable.", + sourceLink: "Open source link", + maximizeLabel: "Open in XWorkmate", }; + const openXWorkmate = () => { + const query = heroPrompt.trim(); + router.push( + query.length > 0 + ? `/xworkmate?prompt=${encodeURIComponent(query)}` + : "/xworkmate", + ); + }; + return ( -
+
-
-
-
+
+
+
-
-
-
-
-
-
-

- {heroCopy.demoLabel} +

+
+
+
+
+

+ + {heroCopy.demoLabel} +

+
+
+
+ +
+
+
+
+
+ {isChinese ? "☀️" : "☀"} + + {heroCopy.greeting}, {displayName} + +
+
+ +
+

+ {heroCopy.todayStatus}:

+
+ {heroCopy.statusItems.map((item) => ( +

+ ├ {item.label}:{" "} + + {item.value} + +

+ ))} +
+
+ +
+