+
+
-
- {placeholderLabel}
+
+
+ {isChinese ? "更多服务即将上线" : "More services coming soon"}
+
+
+ {isChinese
+ ? "预留卡片位置,持续扩充入口。"
+ : "Reserved slots for new service entries."}
+
-
- {placeholderDescription}
-
-
+
{isChinese ? "敬请期待" : "Stay tuned"}
);
-};
-
-const ServiceGrid = ({
- view,
- services,
- isChinese,
-}: {
- view: "classic" | "material";
- services: ServiceCardData[];
- isChinese: boolean;
-}) => {
- return (
-
- {services.map((service) => (
-
- ))}
- {Array.from({ length: placeholderCount }).map((_, index) => (
-
- ))}
-
- );
-};
-
-const ClawdbotLogo = (props: any) => (
-

-);
+}
export default function ServicesPage() {
- const { view, isHydrated } = useViewStore();
const { language } = useLanguage();
const isChinese = language === "zh";
@@ -299,71 +211,83 @@ export default function ServicesPage() {
external: true,
},
{
- key: "moltbot",
+ key: "xworkmate",
name: "XWorkmate",
description: isChinese
? "在线版 XWorkmate 工作区,底层由 OpenClaw gateway 驱动。"
: "Online XWorkmate workspace powered by the OpenClaw gateway.",
href: "/xworkmate",
- icon: ClawdbotLogo,
+ icon: Command,
},
];
- if (!isHydrated) {
- return null;
- }
-
- if (view === "material") {
- return (
-
-
-
- Service Overview
-
-
- Real-time metrics and system health for your current production
- environment.
-
-
-
-
- );
- }
-
return (
-
-
-
-
-
-
-
- {isChinese ? "更多服务" : "More services"}
-
-
- {isChinese ? "扩展服务与工具箱" : "Extended Services & Toolbox"}
-
-
- {isChinese
- ? "汇聚开发辅助、运维监控与核心制品,构建无缝衔接的云原生工作台。"
- : "A unified hub for development aids, operations monitoring, and core artifacts."}
-
-
-
+
+
+
+
+ {isChinese ? "页面原则" : "Page rhythm"}
+
+
+ {isChinese
+ ? "保持结构不变,但去掉 classic / material 的风格分裂。"
+ : "Keep the structure, remove the classic/material visual split."}
+
+
+
+
+
+
+
+
+
+ {isChinese ? "服务目录" : "Service directory"}
+
+
+ {isChinese
+ ? "每个入口都使用同一种卡片语法:白底、细边框、轻阴影、明确标题。"
+ : "Every entry now follows the same card grammar: pale surface, fine border, light shadow, and clear hierarchy."}
+
+
+
+ {services.length} {isChinese ? "个入口" : "entries"}
+
+
+
+
+ {services.map((service) => (
+
+ ))}
+ {Array.from({ length: placeholderCount }).map((_, index) => (
+
+ ))}
+
+
+
);
}
diff --git a/src/components/doc/DocArticle.tsx b/src/components/doc/DocArticle.tsx
index fc0af0d..fb7e9b1 100644
--- a/src/components/doc/DocArticle.tsx
+++ b/src/components/doc/DocArticle.tsx
@@ -1,17 +1,17 @@
-import { marked } from 'marked'
+import { marked } from "marked";
interface DocArticleProps {
- content: string
+ content: string;
}
export default async function DocArticle({ content }: DocArticleProps) {
// Convert markdown to HTML
- const htmlContent = await marked(content)
+ const htmlContent = await marked(content);
return (
- )
+ );
}
diff --git a/src/components/doc/DocMetaPanel.tsx b/src/components/doc/DocMetaPanel.tsx
index bec7fb4..41407a4 100644
--- a/src/components/doc/DocMetaPanel.tsx
+++ b/src/components/doc/DocMetaPanel.tsx
@@ -1,29 +1,40 @@
-import ClientTime from '@/app/components/ClientTime'
+import ClientTime from "@/app/components/ClientTime";
interface DocMetaPanelProps {
- description?: string
- updatedAt?: string
- tags?: string[]
+ description?: string;
+ updatedAt?: string;
+ tags?: string[];
}
-export default function DocMetaPanel({ description, updatedAt, tags }: DocMetaPanelProps) {
+export default function DocMetaPanel({
+ description,
+ updatedAt,
+ tags,
+}: DocMetaPanelProps) {
return (
-
- {description &&
{description}
}
- {tags && tags.length > 0 && (
+
+ {description ? (
+
{description}
+ ) : null}
+
+ {tags && tags.length > 0 ? (
{tags.map((tag) => (
-
+
{tag}
))}
- )}
- {updatedAt && (
-
+ ) : null}
+
+ {updatedAt ? (
+
Updated
- )}
+ ) : null}
- )
+ );
}
diff --git a/src/components/public/PublicPageShell.tsx b/src/components/public/PublicPageShell.tsx
new file mode 100644
index 0000000..b4b360a
--- /dev/null
+++ b/src/components/public/PublicPageShell.tsx
@@ -0,0 +1,82 @@
+import Footer from "@/components/Footer";
+import UnifiedNavigation from "@/components/UnifiedNavigation";
+import { cn } from "@/lib/utils";
+
+type PublicPageShellProps = {
+ children: React.ReactNode;
+ mainClassName?: string;
+ containerClassName?: string;
+};
+
+type PublicPageIntroProps = {
+ eyebrow?: string;
+ title: string;
+ subtitle?: string;
+ titleClassName?: string;
+ className?: string;
+};
+
+export function PublicPageShell({
+ children,
+ mainClassName,
+ containerClassName,
+}: PublicPageShellProps) {
+ return (
+
+
+
+
+
+
+ {children}
+
+
+
+
+
+ );
+}
+
+export function PublicPageIntro({
+ eyebrow,
+ title,
+ subtitle,
+ titleClassName,
+ className,
+}: PublicPageIntroProps) {
+ return (
+
+ {eyebrow ? (
+
+ {eyebrow}
+
+ ) : null}
+
+ {title}
+
+ {subtitle ? (
+
+ {subtitle}
+
+ ) : null}
+
+ );
+}
diff --git a/src/lib/home/heroVideoMedia.ts b/src/lib/home/heroVideoMedia.ts
new file mode 100644
index 0000000..1f34c30
--- /dev/null
+++ b/src/lib/home/heroVideoMedia.ts
@@ -0,0 +1,44 @@
+export type HeroVideoMedia = {
+ posterUrl?: string;
+ videoUrl?: string;
+ title: {
+ zh: string;
+ en: string;
+ };
+ description: {
+ zh: string;
+ en: string;
+ };
+ statusLabel: {
+ zh: string;
+ en: string;
+ };
+ durationLabel: string;
+ chapters: {
+ zh: string;
+ en: string;
+ }[];
+};
+
+export const heroVideoMedia: HeroVideoMedia = {
+ posterUrl: "",
+ videoUrl: "",
+ title: {
+ zh: "用一段视频解释从灵感到上线的完整路径",
+ en: "Show the full path from idea to launch in one video",
+ },
+ description: {
+ zh: "建议后续放 60 到 120 秒的产品导览、集成配置流程,或真实部署 walkthrough。",
+ en: "Best used for a 60-120 second product tour, integration setup flow, or real deployment walkthrough.",
+ },
+ statusLabel: {
+ zh: "视频待接入",
+ en: "Video pending",
+ },
+ durationLabel: "00:00 / 02:18",
+ chapters: [
+ { zh: "开场介绍", en: "Intro" },
+ { zh: "集成配置", en: "Setup" },
+ { zh: "上线演示", en: "Launch" },
+ ],
+};