Skip to content

Conversation

@alwaysmavs
Copy link
Contributor

No description provided.

…t/dark themes

style(Navbar): enhance light mode styles and adjust footer background color
config: enable color mode switch and respect user preferences
…ol-cloud, oomol-studio, open-source, and system-status
…dencies as peer dependencies in package-lock.json
refactor(docusaurus.config.js): add onUntruncatedBlogPosts option for blog configuration
…igation and enhance styles for better layout
…ibility; update rendering logic for anchor and button elements

style(Navbar): update background color to use CSS variables for consistency and improved theming
style(Downloads): replace hardcoded colors with CSS variables for dark theme support
style(Pricing): update background colors and text colors to use CSS variables for better theme management
style(Support): change border color to use CSS variable for consistency across components
- Added logo-en-light.svg for the English light theme.
- Added logo-symbol-dark.svg for the dark theme symbol.
- Added logo-symbol-light.svg for the light theme symbol.
- Added logo-zh-dark.svg for the Chinese dark theme.
- Added logo-zh-light.svg for the Chinese light theme.
alwaysmavs and others added 15 commits December 3, 2025 15:28
…ing; add Downloads page with download options
…ge; update Navbar to use Link component for navigation
…ations

- Added @radix-ui/themes to package.json for enhanced theming support.
- Refactored translation calls in the pricing page for better readability.
- Removed unused styles related to free and standard plans in styles.module.scss.
- Cleaned up the pricing table styles and adjusted responsive design.
@vercel
Copy link

vercel bot commented Dec 5, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
oomol-com Ready Ready Preview Comment Dec 5, 2025 8:46am

@coderabbitai
Copy link

coderabbitai bot commented Dec 5, 2025

Summary by CodeRabbit

发布说明

  • 新功能

    • 完整支持浅色/深色主题切换
    • 新增生命周期、核心功能、产品对比等页面组件
    • 增强的下载和支持页面功能
  • UI/UX 改进

    • 实施设计系统令牌化,提升视觉一致性
    • 优化响应式布局和页面间距
    • 改进导航栏和页脚结构
  • 文档

    • 新增执行器概念完整指南
    • 更新通用块设置和工作流引擎文档
  • 其他

    • 配置和依赖包更新优化

✏️ Tip: You can customize this high-level summary in your review settings.

浏览概览

此次更改涉及网站基础设施的广泛重构,包括导航栏重组、设计系统实现(CSS变量)、新增Radix UI组件库、文档和国际化更新、主页组件优化、以及对齐多个页面和样式的现代化工作。

更改内容

功能聚类 / 文件 更改摘要
配置和构建工具
babel.config.js, docusaurus.config.js, eslint.config.mjs, package.json
删除Babel配置;更新Docusaurus至3.9.2并优化blog配置;新增ESLint配置(TypeScript、React支持);添加Radix UI依赖、ESLint工具和lint脚本
设计系统与样式基础
src/css/custom.scss, src/css/design-tokens.scss
迁移至@use模块语法;引入comprehensive设计系统(CSS变量)支持亮暗主题、完整排版体系、8点栅栏间距系统、响应式断点和过渡策略
新增UI组件库
src/components/ui/button.tsx, src/components/ui/card.tsx, src/components/ui/dropdown-menu.tsx, src/components/ui/popover.tsx
基于Radix UI和class-variance-authority的可组合UI组件库,支持多种变体、尺寸和可访问性
首屏及核心组件重构
src/components/HomepageFirstScreen/*, src/components/magic-ui/AuroraText.tsx, src/components/HomepageFirstScreen/GridBackground.tsx, src/components/Popover/index.tsx, src/components/Spin/Spin.tsx
新增GridBackground组件;为AuroraText添加主题感知;重构Popover使用Radix UI;优化Spin动画逻辑;更新首屏布局和配色
已移除的主页组件
src/components/HomepageCreate/*, src/components/HomepageCreateScenes/*, src/components/HomepageGuide/*, src/components/HomepageFeatures/*, src/components/HomepageVideo/*, src/components/HomepageProducts/*, src/components/HomepageScenes/*, src/components/TypewriterText/*, src/components/CyclicTypewriterText/*, src/components/Button/*, src/components/ComingSoon/*, src/components/ResponsiveImage/*
删除多个旧的主页小节组件、通用Button组件和文字效果组件;按照设计系统重构
新增内容组件
src/components/HomepageBuiltInLLM/*, src/components/HomepageCoreFeatures/*, src/components/HomepageLifecycle/*, src/components/HomepagePdfCraftShowcase/*, src/components/HomepageProductComparison/*, src/components/StudioPdfCraftCase/*
新增内置LLM展示、核心功能、生命周期、PDF Craft展示、产品对比、Studio PDF案例等组件
现有组件更新
src/components/DownloadButton/*, src/components/HomepageCommunityShare/*, src/components/HomePagePricing/*, src/components/GetStartedPrompt/*, src/components/HomepageStarter/*, src/components/AssetBlock/*, src/components/FeatureBlockList/*
迁移至新Button/Card组件;采用CSS变量;实现主题感知;优化样式结构
页面层级更新
src/pages/chat/index.tsx, src/pages/cloud/index.tsx, src/pages/contact-us/index.tsx, src/pages/brand-assets/index.tsx, src/pages/about-us/index.tsx
重构Chat/Cloud页面为卡片网格布局;更新Contact Us为Card结构;删除About Us;优化Contact Us和Brand Assets样式
文档更新(英文)
docs/advanced-guide/universal-block-settings.mdx, docs/concepts/executor.mdx, docs/faq.mdx, docs/workflow-engine/principle.mdx, blog/2025-07-05-Export-Workflow-as-Image/index.mdx
扩展Block设置文档;新增Executor概念文档;更新FAQ链接;完善工作流引擎文档;修正info块分隔符
文档与i18n(中文)
i18n/zh-CN/code.json, i18n/zh-CN/docusaurus-theme-classic/*, i18n/zh-CN/docusaurus-plugin-content-docs/*, i18n/zh-CN/docusaurus-plugin-content-pages/*, i18n/zh-CN/docusaurus-plugin-content-blog/*
大规模翻译更新(导航、主页、产品、生态、定价等);新增隐私政策、服务条款、下载、支持页面;新增blog文章
英文i18n
i18n/en/code.json, i18n/en/docusaurus-theme-classic/navbar.json, i18n/en/docusaurus-theme-classic/footer.json
补充英文翻译键值;扩展导航栏和页脚国际化覆盖
工具类更新
src/lib/utils.ts, .gitignore
增强downloadStable类型安全;忽略Claude本地设置文件

评估代码审查工作量

🎯 5 (关键) | ⏱️ ~120-150 分钟

重点关注区域:

  • 设计系统实现 (src/css/design-tokens.scss, src/css/custom.scss):大量CSS变量定义和主题映射,需验证亮暗主题一致性和响应式断点覆盖
  • Radix UI集成 (src/components/ui/*):新增受信任库的组件,需检查无障碍属性、props转发和样式继承
  • 主页组件大规模重构:删除>10个组件,新增6个,需验证迁移的完整性、样式过渡和国际化链接
  • Docusaurus配置 (docusaurus.config.js):导航栏/页脚重组、配置选项新增,需测试渲染和链接有效性
  • i18n规模更新 (i18n/zh-CN/code.json等):数百个新/修改的翻译键,需抽样验证关键客户端字符串
  • 页面层级迁移 (src/pages/chat, src/pages/cloud):新Card结构和数据驱动渲染,需确保SEO、状态管理和用户交互
  • 工具函数类型增强 (src/lib/utils.ts):虽然变化小,但涉及事件处理和外部导航,需验证回调流和副作用

Pre-merge checks

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Description check ❓ Inconclusive PR描述为空,无法判断其是否与变更相关。 建议作者添加详细的PR描述,说明此次重构的主要目标、影响范围和关键改动。
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed PR标题遵循了指定的格式 (): ,使用了英文,且清晰概括了本次变更的主要内容(网站重构和设计改进)。

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Dec 5, 2025

Deploying oomol-com with  Cloudflare Pages  Cloudflare Pages

Latest commit: 671eecf
Status: ✅  Deploy successful!
Preview URL: https://3819558b.oomol-com.pages.dev
Branch Preview URL: https://frp.oomol-com.pages.dev

View logs

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 16

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/pages/contact-us/index.tsx (1)

319-356: 仓库卡片缺少键盘可访问性支持。

当前仓库卡片使用 onClick 处理点击事件,但 div 元素不支持键盘导航。建议添加 tabIndexroleonKeyDown 处理,或改用 <a> 标签。

 <div
   className={styles.repository}
   key={repo.url}
+  role="link"
+  tabIndex={0}
   onClick={() => {
     window.open(`https://github.com/${repo.url}`, "_blank");
   }}
+  onKeyDown={(e) => {
+    if (e.key === "Enter" || e.key === " ") {
+      window.open(`https://github.com/${repo.url}`, "_blank");
+    }
+  }}
 >

或者更好的方式是使用语义化的 <a> 标签:

<a
  className={styles.repository}
  key={repo.url}
  href={`https://github.com/${repo.url}`}
  target="_blank"
  rel="noopener noreferrer"
>
🧹 Nitpick comments (47)
src/components/HomepageCommunityShare/index.tsx (1)

37-48: 建议:图片 alt 走翻译,并考虑启用 lazy loading

当前两张大图的 alt 文案是硬编码英文字符串,页面如果有多语言,建议改为使用 translate 提供可本地化的文案,同时可以顺便加上 loading="lazy" 降低首屏加载压力,类似:

-          <img
-            src={isDark ? communityHomeDark : communityHomeLight}
-            alt="Community Home"
-            className={styles.image}
-          />
+          <img
+            src={isDark ? communityHomeDark : communityHomeLight}
+            alt={translate({
+              id: "HOME.CommunityShare.imageHomeAlt",
+              message: "Community Home",
+            })}
+            loading="lazy"
+            className={styles.image}
+          />
@@
-          <img
-            src={isDark ? communityDetailDark : communityDetailLight}
-            alt="Community Detail"
-            className={styles.image}
-          />
+          <img
+            src={isDark ? communityDetailDark : communityDetailLight}
+            alt={translate({
+              id: "HOME.CommunityShare.imageDetailAlt",
+              message: "Community Detail",
+            })}
+            loading="lazy"
+            className={styles.image}
+          />

(对应的翻译 key 需要在 i18n 文件中补上。)

src/components/HomepageCommunityShare/styles.module.scss (1)

3-23: 可以合并 .container 的 padding 声明以减少冗余

现在先写了一次 padding: 100px 0 50px;,随后又单独设置 padding-left/right,最终效果是对的,但可读性稍差一点,可以直接合并成一个声明,例如:

-  padding: 100px 0 50px;
-  gap: 60px;
-  max-width: 1440px;
-  margin: 0 auto;
-  padding-left: 32px;
-  padding-right: 32px;
+  padding: 100px 32px 50px;
+  gap: 60px;
+  max-width: 1440px;
+  margin: 0 auto;

下方几个 media query 里如果有类似模式,也可以按需做同类整理,仅为样式层的小优化。

src/components/Spin/Spin.tsx (1)

106-125: 整体逻辑正确!

使用 RAF + 定时器的模式可以正确触发 CSS 过渡动画:

  • 当 progress 有值时,通过 RAF 延迟更新状态
  • 当 progress 为 undefined 时,先设为 0,然后延迟 50ms 设为 100,确保浏览器渲染初始状态后再触发过渡
  • cleanup 函数正确清理了 RAF 和定时器,避免内存泄漏

可选优化:类型注解的跨平台兼容性

Line 108 使用 NodeJS.Timeout 类型在纯浏览器环境中可能不可用。虽然在大多数配置中可以正常工作,但为了更好的跨平台兼容性,可以考虑使用 numberReturnType<typeof setTimeout>:

-    let timer: NodeJS.Timeout;
+    let timer: ReturnType<typeof setTimeout>;

另外,Line 115 的 50ms 延迟是为了触发 CSS 过渡的关键值,建议添加注释说明其用途。

src/components/HomepageLifecycle/index.tsx (6)

16-16: 建议保持注释语言一致性。

代码中混合使用了中英文注释。建议根据团队规范统一注释语言。


19-21: 列表格式检测逻辑可以更健壮。

当前检测逻辑只检查是否包含 和换行符,但不验证格式是否正确。如果描述文本中意外包含这些字符但不是列表格式,可能会导致错误的渲染。

可以考虑使用更严格的检测:

 const checkIsListFormat = (description: string): boolean => {
-  return description.includes("•") && description.includes("\n");
+  const lines = description.trim().split("\n");
+  return lines.length > 1 && lines.every(line => line.trim().startsWith("•"));
 };

103-107: 建议添加显式的 button type 属性。

按钮元素应该明确指定 type="button" 以防止在表单内意外触发提交行为。

 <button
+  type="button"
   className={`${styles.stepItem} ${
     index === activeStep ? styles.active : ""
   }`}
   onClick={() => handleStepClick(index)}
 >

103-157: 可访问性改进:添加 ARIA 属性。

步骤导航按钮应该包含适当的 ARIA 属性,以改善屏幕阅读器用户的体验。

 <button
   type="button"
   className={`${styles.stepItem} ${
     index === activeStep ? styles.active : ""
   }`}
   onClick={() => handleStepClick(index)}
+  aria-label={`${step.title}: ${step.subtitle}`}
+  aria-current={index === activeStep ? "step" : undefined}
 >

144-146: 优化渲染性能:避免在渲染中进行字符串处理。

在渲染函数中执行 split()replace() 操作会在每次重新渲染时重复执行。建议将处理逻辑提取到 useMemo 中或者在 steps 数据准备阶段就完成格式化。

可以创建一个辅助函数来处理描述文本:

const formatDescription = (description: string) => {
  if (checkIsListFormat(description)) {
    return description.split("\n").map(line => line.replace("• ", ""));
  }
  return description;
};

// 在 useMemo 中缓存格式化后的步骤
const formattedSteps = useMemo(() => 
  steps.map(step => ({
    ...step,
    formattedDescription: formatDescription(step.description)
  })),
  [steps]
);

164-169: 硬编码的占位符文本应该国际化。

占位符文本 "Step {activeStep + 1} Image/Video Placeholder" 是硬编码的英文文本,与组件的其他部分使用 i18n 不一致。

建议使用 translate 函数:

 <div className={styles.placeholderText}>
-  Step {activeStep + 1} Image/Video Placeholder
+  {translate(
+    { message: "HOME.Lifecycle.placeholder" },
+    { step: activeStep + 1 }
+  )}
 </div>
src/components/HomepageLifecycle/styles.module.scss (5)

54-66: 移除注释掉的代码。

第 59 行有注释掉的 CSS 属性。如果不再需要,建议删除;如果需要保留用于未来调整,请添加说明注释。

 .mainContent {
   display: grid;
   grid-template-columns: 420px 1fr;
   gap: 60px;
-  // margin-bottom: 100px;
   align-items: start;

69-82: 考虑固定高度的灵活性。

.stepsNavigation 使用了固定高度 height: 580px。如果将来步骤数量或内容长度发生变化,这可能会导致布局问题。建议考虑使用 min-height 或让高度自适应内容。

 .stepsNavigation {
   display: flex;
   flex-direction: column;
   gap: 0;
   position: sticky;
   top: 100px;
-  height: 580px;
+  min-height: 580px;
   margin-top: 20px;

100-117: 移除或更新中文注释。

第 106 行的中文注释应该与代码库的注释规范保持一致。

   &.active {
     background: rgba(var(--ifm-color-primary-rgb), 0.08);
 
     .stepNumber {
       background: var(--ifm-color-primary);
       color: white;
-      // 移除 scale 动画,数字大小已统一
     }

242-253: 动画的 max-height 可能需要调整。

expandContent 动画中的 max-height: 500px 可能不足以容纳较长的步骤描述内容。如果内容超过这个高度,动画效果会被截断。

考虑使用更大的值或根据实际内容调整:

 @keyframes expandContent {
   from {
     opacity: 0;
     max-height: 0;
     transform: translateY(-8px);
   }
   to {
     opacity: 1;
-    max-height: 500px;
+    max-height: 800px;
     transform: translateY(0);
   }
 }

297-318: 移除注释掉的代码。

第 298 行有注释掉的 CSS 属性。如果不再需要,建议删除。

 .stepDescription {
-  // margin-bottom: 8px;
-
   p {
     font-size: 1rem;
     color: var(--ifm-color-emphasis-700);
eslint.config.mjs (1)

30-74: 考虑使用 globals 包简化全局变量定义。

当前手动定义了 40+ 个全局变量,这种方式冗长且难以维护。推荐使用 globals 包来提供预定义的全局变量集合。

首先安装 globals 包:

npm install -D globals

然后重构配置:

+import globals from 'globals';
 import js from '@eslint/js';
 import tseslint from '@typescript-eslint/eslint-plugin';
 import tsparser from '@typescript-eslint/parser';
 import react from 'eslint-plugin-react';
 import reactHooks from 'eslint-plugin-react-hooks';

在配置中使用:

     languageOptions: {
       parser: tsparser,
       parserOptions: {
         ecmaVersion: 'latest',
         sourceType: 'module',
         ecmaFeatures: {
           jsx: true,
         },
       },
       globals: {
-        // Browser globals
-        window: 'readonly',
-        document: 'readonly',
-        console: 'readonly',
-        navigator: 'readonly',
-        location: 'readonly',
-        localStorage: 'readonly',
-        sessionStorage: 'readonly',
-        setTimeout: 'readonly',
-        clearTimeout: 'readonly',
-        setInterval: 'readonly',
-        clearInterval: 'readonly',
-        fetch: 'readonly',
-        XMLHttpRequest: 'readonly',
-        MediaQueryList: 'readonly',
-        MediaQueryListEvent: 'readonly',
-        MouseEvent: 'readonly',
-        HTMLElement: 'readonly',
-        HTMLDivElement: 'readonly',
-        HTMLButtonElement: 'readonly',
-        HTMLSpanElement: 'readonly',
-        HTMLTableElement: 'readonly',
-        HTMLTableSectionElement: 'readonly',
-        HTMLTableRowElement: 'readonly',
-        HTMLTableCellElement: 'readonly',
-        HTMLTableCaptionElement: 'readonly',
-        Element: 'readonly',
-        AbortController: 'readonly',
+        ...globals.browser,
+        ...globals.node,
         gtag: 'readonly',
-
-        // Node globals
-        module: 'readonly',
-        require: 'readonly',
-        process: 'readonly',
-        __dirname: 'readonly',
-        __filename: 'readonly',
-
-        // TypeScript
-        NodeJS: 'readonly',
-
-        // React/JSX
-        React: 'readonly',
-        JSX: 'readonly',
       },
     },
i18n/zh-CN/docusaurus-plugin-content-pages/terms/styles.module.scss (1)

1-11: .box 固定宽度 1200px 在小屏上可能导致横向滚动

当前 .box 直接设为 width: 1200px;,在移动端或窄屏上会溢出视口。建议改为「最大宽度 1200px + 自适应宽度」,提升响应式体验。

可以参考:

-.box {
-    width: 1200px;
-}
+.box {
+    max-width: 1200px;
+    width: 100%;
+}

这样在大屏仍保持 1200px 内容宽度,小屏则可以自动压缩,不会产生横向滚动条。

src/components/GetStartedPrompt/index.tsx (1)

4-17: 新增 logo 加载逻辑清晰,可考虑补充懒加载属性

使用 useBaseUrl("/img/logo2x.png") 注入图片路径,并在文本上方渲染 <img>,整体实现没问题。

如果该组件不在首屏最上方,可考虑给图片增加懒加载以减少首屏外资源的开销,例如:

           <img
             className={styles.logo}
             src={logoSrc}
-            alt="OOMOL Logo"
+            alt="OOMOL Logo"
+            loading="lazy"
           />

属于体验级优化,可按需采纳。

src/components/HomepageStarter/index.tsx (1)

1-19: i18n 增加可选链和默认值,避免未配置多语言时的潜在运行时错误

现在通过:

const { i18n } = useDocusaurusContext() as unknown as DocusaurusContext & {
  i18n: { currentLocale: string };
};
const locale = i18n.currentLocale;

假设 i18n 一定存在且结构固定。如果未来站点关闭 i18n 或 Docusaurus 类型结构调整,这里会在运行时报错。

可以稍微放宽类型并提供安全默认值,例如:

-  const { i18n } = useDocusaurusContext() as unknown as DocusaurusContext & {
-    i18n: { currentLocale: string };
-  };
-  const locale = i18n.currentLocale;
+  const { i18n } = useDocusaurusContext() as unknown as DocusaurusContext & {
+    i18n?: { currentLocale?: string };
+  };
+  const locale = i18n?.currentLocale ?? "en";

这样即便未启用 i18n 或字段缺失,也会回退到英文,不会中断渲染。

src/lib/utils.ts (1)

8-27: callback 的参数类型与对 undefined 的判断略不一致,可统一一下

现在的实现:

const callback = function (url: string) {
  if (typeof url != "undefined") {
    window.location.href = url;
  }
};
...
export function downloadStable(
  event: null | React.MouseEvent<HTMLElement, MouseEvent>,
  url: string
) { ... }

TS 类型已经保证 urlstring,正常调用时不会是 undefined,但运行时代码仍在做 typeof url != "undefined" 判断,两者语义不完全一致。

可以考虑两种方向(二选一即可):

  1. 保留判断,让类型也接受可选参数:
-const callback = function (url: string) {
-  if (typeof url != "undefined") {
+const callback = function (url?: string) {
+  if (typeof url !== "undefined") {
     window.location.href = url;
   }
 };
 
 export function downloadStable(
   event: null | React.MouseEvent<HTMLElement, MouseEvent>,
-  url: string
+  url?: string
 ) {
  1. 如果业务上保证一定有 URL,则去掉运行时判断,仅保留更严格的类型:
-const callback = function (url: string) {
-  if (typeof url != "undefined") {
-    window.location.href = url;
-  }
-};
+const callback = function (url: string) {
+  window.location.href = url;
+};

看你期望的调用约束强度来选,当前实现虽能正常工作,但略显多余。

src/pages/cloud/index.tsx (2)

96-117: Hero 区域部分文案硬编码,建议也接入 i18n

目前:

<h1 className={styles.heroTitle}>OOMOL Cloud</h1>
...
<span className={styles.statValue}>自动扩缩容</span>
<span className={styles.statValue}>RESTful API</span>
<span className={styles.statValue}>MCP 协议</span>

这些内容在英文站点上也会原样展示,且无法通过 i18n JSON 做本地化配置。既然 use cases / features 已经用 translate,建议 hero 标题和指标主文案也走同一套机制,例如:

-          <h1 className={styles.heroTitle}>OOMOL Cloud</h1>
+          <h1 className={styles.heroTitle}>
+            {translate({ message: "CLOUD.hero.title" })}
+          </h1>
...
-              <span className={styles.statValue}>自动扩缩容</span>
+              <span className={styles.statValue}>
+                {translate({ message: "CLOUD.hero.stat1.value" })}
+              </span>

对应再在 i18n/*/code.json 里补充这些 key,即可在不同语言中自由调整文案。


140-158: 列表渲染建议避免使用数组索引作为 React key

当前:

{useCases.map((useCase, index) => (
  <UseCaseCard key={index} useCase={useCase} />
))}
...
{coreFeatures.map((feature, index) => (
  <FeatureCard key={index} feature={feature} />
))}

虽然 useCases / coreFeatures 目前是静态数组,但用 index 作为 key 在未来需要插入、删除或重排时容易触发不必要的重渲染甚至状态错乱。这里每项都有稳定的 title,可以直接用它做 key:

-            {useCases.map((useCase, index) => (
-              <UseCaseCard key={index} useCase={useCase} />
+            {useCases.map((useCase) => (
+              <UseCaseCard key={useCase.title} useCase={useCase} />
             ))}
...
-            {coreFeatures.map((feature, index) => (
-              <FeatureCard key={index} feature={feature} />
+            {coreFeatures.map((feature) => (
+              <FeatureCard key={feature.title} feature={feature} />
             ))}

这样在未来调整卡片顺序时更安全。

src/components/HomepagePdfCraftShowcase/index.tsx (1)

34-35: 考虑动态获取 GitHub star 数量

硬编码的 "3000+ Stars" 会随时间变得过时。建议使用 GitHub API 在构建时获取实际的 star 数量,或使用 GitHub 的动态徽章。

可以考虑在构建时通过 GitHub API 获取:

// 示例:在构建时获取 star 数
const response = await fetch('https://api.github.com/repos/oomol-lab/pdf-craft');
const data = await response.json();
const starCount = data.stargazers_count;

或使用 GitHub shields.io 徽章实现动态更新。

src/css/design-tokens.scss (1)

441-469: 考虑过渡动画的性能影响

虽然代码注释提到避免全局通配符的性能问题,但 [class*="oomol-"] 等选择器仍可能匹配大量元素。在复杂页面中可能影响渲染性能。

如果遇到性能问题,可以考虑:

  1. 进一步缩小选择器范围,只针对确实需要过渡的组件类
  2. 使用 will-change 属性提示浏览器优化
  3. 监控实际性能指标,按需优化

当前实现对于大多数场景应该是可接受的。

src/components/HomepageFirstScreen/GridBackground.tsx (2)

216-298: 监控高斯模糊滤镜的性能影响

代码中使用了多个高斯模糊滤镜,其中 stdDeviation="240" 的模糊强度特别高,在低端设备上可能影响渲染性能。虽然组件已使用 memo 优化,但 SVG 滤镜本身的计算成本仍然存在。

建议:

  1. 在不同设备上测试渲染性能
  2. 考虑在移动设备上降低模糊强度或简化效果
  3. 可以根据设备性能动态调整滤镜复杂度

当前实现对于大多数现代设备应该可以接受。


8-11: 考虑为 memo 组件添加 displayName

虽然函数名称作为参数传递给 memo(),但显式设置 displayName 可以提高在 React DevTools 中的调试体验。

 export const GridBackground = memo(function GridBackground({
   opacity = 0.6,
   className,
 }: GridBackgroundProps) {
+  // ...
+});
+
+GridBackground.displayName = "GridBackground";
src/css/custom.scss (2)

107-119: 浅色和深色模式的 navbar 样式完全相同,可以合并简化。

两个选择器 [data-theme="light"] .navbar[data-theme="dark"] .navbar 的样式规则完全一致,建议合并以减少代码重复。

-/* Light mode navbar styles */
-[data-theme="light"] .navbar {
-  background: var(--oomol-bg-base);
-  opacity: 0.9;
-  border-bottom: 1px solid var(--oomol-border-subtle);
-}
-
-/* Dark mode navbar styles */
-[data-theme="dark"] .navbar {
+/* Navbar theme styles */
+[data-theme="light"] .navbar,
+[data-theme="dark"] .navbar {
   background: var(--oomol-bg-base);
   opacity: 0.9;
   border-bottom: 1px solid var(--oomol-border-subtle);
 }

40-40: !important 的使用需要注意。

--ifm-background-color 上使用 !important 可能是为了覆盖 Docusaurus 的默认样式。如果确实需要,建议添加注释说明原因,以便后续维护。

src/pages/chat/index.tsx (1)

83-86: 使用数组索引作为 key。

在静态数据渲染中使用 idx 作为 key 是可以接受的,因为 feature.features 数组在运行时不会重新排序或修改。但如果后续数据变为动态,需要考虑使用更稳定的 key。

i18n/zh-CN/docusaurus-plugin-content-pages/support/styles.module.scss (2)

20-25: 建议添加响应式设计

.supportCellBox 使用固定宽度 1080px,在小屏幕设备上可能导致水平滚动。建议添加响应式断点或使用 max-width 配合百分比宽度。

 .supportCellBox {
-  width: 1080px;
+  width: 100%;
+  max-width: 1080px;
   display: flex;
   align-items: center;
   justify-content: space-between;
+  flex-wrap: wrap;
+  gap: 24px;
 }
+
+@media (max-width: 768px) {
+  .supportCellBox {
+    flex-direction: column;
+  }
+  
+  .supportCell {
+    width: 100%;
+    max-width: 320px;
+  }
+}

36-38: 缺少 border-width 属性

设置了 border-style: solid 但未指定 border-width,浏览器会使用默认值(通常为 medium 约 3px)。建议显式指定宽度以确保一致性。

   border-style: solid;
+  border-width: 1px;
   border-color: var(--oomol-border-default);
i18n/zh-CN/docusaurus-plugin-content-pages/privacy/styles.module.scss (1)

9-11: 建议添加响应式样式以支持小屏幕设备。

.box 使用固定宽度 1200px,在小于 1200px 的屏幕上会导致水平溢出。

建议使用 max-width 配合 width: 100% 实现响应式布局:

 .box {
-    width: 1200px;
+    width: 100%;
+    max-width: 1200px;
+    padding: 0 16px;
 }
src/components/HomepageCoreFeatures/styles.module.scss (1)

125-138: 建议使用 CSS 变量替代硬编码的颜色值。

featureHighlight 和深色模式适配中使用了硬编码的颜色值:

  • Line 135: #667eea
  • Line 189: #8b9bff

为了与项目的设计令牌系统保持一致,建议将这些颜色值替换为相应的 CSS 自定义属性(如 var(--oomol-primary) 等)。

考虑应用类似的修改:

 .featureHighlight {
   display: flex;
   align-items: flex-start;
   gap: 12px;
   padding: 20px 24px;
   background: linear-gradient(
     135deg,
-    rgba(102, 126, 234, 0.1) 0%,
-    rgba(118, 75, 162, 0.1) 100%
+    rgba(var(--oomol-primary-rgb), 0.1) 0%,
+    rgba(var(--oomol-secondary-rgb), 0.1) 100%
   );
-  border-left: 4px solid #667eea;
+  border-left: 4px solid var(--oomol-primary);
   border-radius: 8px;
   margin-top: 8px;
 }

Also applies to: 182-191

src/components/HomepageDownloads/styles.module.scss (1)

1-61: 补充按钮的可访问状态并收紧 transition 范围

.download-btn 使用设计 token 和 hover/active 动效整体不错,不过可以考虑两点优化:

  • .download-btn:focus-visible(或至少 :focus)增加与 :hover 一致的样式,方便键盘用户识别当前焦点。
  • transition: all 0.3s ease; 收紧到实际需要的属性(如 background-color, color, border-color, transform),避免未来新增属性被意外动画、也更利于性能。
src/components/HomepageProductComparison/index.tsx (1)

4-88: 为产品数据声明类型并避免使用 index 作为 key

实现整体清晰,不过这里可以稍微加强类型安全和 React 最佳实践:

  • products 声明类型(包含 color 的联合类型),这样 styles[product.color] 出错时能在编译期暴露。
  • map 中建议使用稳定字段(如 product.name 或一个显式的 id)作为 key,而不是 index,便于未来重排或动态增删项。

示例:

type ProductColor = "primary" | "secondary" | "tertiary";

interface Product {
  name: string;
  stage: string;
  capability: string;
  scenario: string;
  tech: string;
  icon: string;
  color: ProductColor;
}

const products: Product[] = [/* ... */];

// ...
{products.map(product => (
  <div key={product.name} className={`${styles.productCard} ${styles[product.color]}`}>
    {/* ... */}
  </div>
))}
i18n/zh-CN/docusaurus-plugin-content-pages/terms/_terms.mdx (1)

178-188: 12.3 条“可分割性”的中文表述可略作润色

当前句子“如果本服务条款的任何条款被认定为无效或不可执行,该条款应在必要范围内进行修改以使其有效,或在无法修改的情况下予以删除,其余条款继续有效。”语义是清楚的,不过可以考虑稍作拆分或调整,使法律文本更顺口一些,例如:

如果本服务条款的任何条款被认定为无效或不可执行,该条款可以在必要范围内进行修改以使其有效;若无法修改,则应予以删除,其余条款仍继续有效。

纯属文风上的小优化,不影响现有含义。

src/components/HomepageProductComparison/styles.module.scss (1)

89-113: 建议将硬编码的颜色值替换为 CSS 变量

secondary 和 tertiary 主题使用了硬编码的颜色值(#5d63a3、#3d3c60),以及 box-shadow 中的硬编码 RGBA 值。为了提高主题一致性和可维护性,建议将这些颜色定义为 CSS 变量。

考虑在 design tokens 文件中定义这些颜色:

// 在 design-tokens.scss 中添加
--oomol-secondary: #5d63a3;
--oomol-tertiary: #3d3c60;

然后在此文件中使用:

  &.secondary {
-    border-color: #5d63a3;
+    border-color: var(--oomol-secondary);

    .cardHeader {
-      background: #5d63a3;
+      background: var(--oomol-secondary);
    }

    &:hover {
-      border-color: #5d63a3;
+      border-color: var(--oomol-secondary);
      box-shadow: 0 12px 40px rgba(0, 119, 182, 0.25);
    }
  }

  &.tertiary {
-    border-color: #3d3c60;
+    border-color: var(--oomol-tertiary);

    .cardHeader {
-      background: #3d3c60;
+      background: var(--oomol-tertiary);
    }

    &:hover {
-      border-color: #3d3c60;
+      border-color: var(--oomol-tertiary);
      box-shadow: 0 12px 40px rgba(72, 202, 228, 0.25);
    }
  }
src/components/HomePagePricing/index.tsx (1)

66-95: 建议使用 clsx 优化 className 拼接

当前使用字符串拼接处理 className,可以使用 clsx 库(项目中已经使用)来更优雅地处理条件类名。

+import clsx from "clsx";

  {pricingData.map((item, index) => {
-    const cardClassName = item.className ? item.className : "";
    return (
-      <Card key={index} className={styles.card + " " + cardClassName}>
+      <Card key={index} className={clsx(styles.card, item.className)}>
        <CardHeader>

同样适用于 Line 98 的 top-up 卡片:

-  <Card key={index} className={styles.card + " " + styles["top-up"]}>
+  <Card key={index} className={clsx(styles.card, styles["top-up"])}>
src/components/StudioPdfCraftCase/index.tsx (1)

137-154: 考虑将统计数据改为动态获取或添加更新提醒

统计数据(特别是 "3000+ GitHub Stars")是硬编码的,可能会随时间过时。

建议考虑以下方案之一:

  1. 使用 GitHub API 动态获取 star 数量
  2. 将这些数值移到配置文件或 i18n 文件中,方便定期更新
  3. 在代码中添加注释,提醒定期检查和更新这些数值

示例(动态获取 GitHub stars):

const [githubStars, setGithubStars] = useState("3000+");

useEffect(() => {
  fetch("https://api.github.com/repos/oomol/oomol")
    .then(res => res.json())
    .then(data => setGithubStars(`${Math.floor(data.stargazers_count / 1000)}k+`))
    .catch(() => setGithubStars("3000+")); // fallback
}, []);
src/components/HomepageFirstScreen/index.tsx (1)

58-78: 可以简化重复的代码

中文和其他语言版本的 AuroraText 实现完全相同,可以简化为单一实现。

-                {i18n.currentLocale === "zh-CN" ? (
-                  <AuroraText className={styles["aurora-slogan"]}>
-                    {translate({
-                      message: "HOME.FirstScreen.slogan.line1",
-                    })}
-                    <br />
-                    {translate({
-                      message: "HOME.FirstScreen.slogan.line2",
-                    })}
-                  </AuroraText>
-                ) : (
-                  <AuroraText className={styles["aurora-slogan"]}>
-                    {translate({
-                      message: "HOME.FirstScreen.slogan.line1",
-                    })}
-                    <br />
-                    {translate({
-                      message: "HOME.FirstScreen.slogan.line2",
-                    })}
-                  </AuroraText>
-                )}
+                <AuroraText className={styles["aurora-slogan"]}>
+                  {translate({
+                    message: "HOME.FirstScreen.slogan.line1",
+                  })}
+                  <br />
+                  {translate({
+                    message: "HOME.FirstScreen.slogan.line2",
+                  })}
+                </AuroraText>

如果将来需要针对不同语言做差异化处理,可以保留条件判断。但目前两个分支完全相同。

src/components/HomePageBuiltInLLM/styles.module.scss (1)

163-165: 考虑减少 !important 的使用。

虽然在覆盖第三方库样式时 !important 可能是必要的,但建议在可能的情况下通过增加选择器特异性来避免使用,以提高样式的可维护性。

-  :global(.margin-top--md) {
-    margin-top: 0 !important;
-  }
+  // 如果可以通过更高特异性的选择器实现,考虑替换
+  :global(.tabs + .margin-top--md) {
+    margin-top: 0;
+  }
src/components/HomepageCoreFeatures/index.tsx (1)

110-117: 描述文本拆分存在重复计算。

feature.description.split("\n") 在渲染时被调用了两次,建议提取为变量以避免重复计算。

+          const lines = feature.description.split("\n");
           <div className={styles.featureDescription}>
-            {feature.description.split("\n").map((line, i) => (
+            {lines.map((line, i) => (
               <React.Fragment key={i}>
                 {line}
-                {i < feature.description.split("\n").length - 1 && <br />}
+                {i < lines.length - 1 && <br />}
               </React.Fragment>
             ))}
           </div>
i18n/zh-CN/docusaurus-plugin-content-docs/current/concepts/executor.mdx (1)

5-6: 存在未使用的导入。

ImageuseBaseUrl 被导入但未在文档中使用。如果不需要这些导入,建议移除。

---
sidebar_position: 4
---

-import Image from "@theme/ThemedImage";
-import useBaseUrl from "@docusaurus/useBaseUrl";
-
# 执行器 (Executor)
src/components/HomepageFirstScreen/styles.module.scss (3)

31-53: GPU 优化和 SVG 性能优化实现合理

will-changetransform: translateZ(0)backface-visibility: hidden 用于启用 GPU 加速。但需要确认背景 SVG 的复杂度——如果 SVG 较简单,这些优化可能不必要。同时,建议验证 shape-rendering: optimizeSpeed 在不同浏览器中的表现。

考虑添加注释说明为什么需要这些 GPU 优化(例如:SVG 动画性能原因)。


37-37: 中文注释需要考虑本地化

第 37 行的注释 // 临时背景色用于测试 表明这是临时代码。建议:

  1. 将背景色值提取为 CSS 变量
  2. 移除"临时"注释或用 TODO 替代
  3. 确保此颜色值是最终设计

这是临时颜色还是最终设计色?如果是临时的,建议创建一个 issue 追踪。

Also applies to: 37-37


55-84: CSS 变量系统迁移完整且一致

所有颜色值已系统性地替换为 CSS 变量(如 --oomol-primary--oomol-text-primary--oomol-bg-elevated 等)。这支持了设计系统的令牌化方案。

几点验证建议:

  1. 确保 custom.scss 中定义了所有使用的 CSS 变量
  2. 检查色彩对比度是否满足 WCAG 可访问性标准(特别是文本颜色)
  3. .go-to-hub 类使用了 !important 标志(行 427-429),这可能表明存在样式冲突

建议移除 .go-to-hub 中的 !important 标志,改为调整选择器特异性或 CSS 顺序来解决冲突。

Also applies to: 401-436

i18n/zh-CN/code.json (2)

744-749: 代码示例翻译中的多行字符串处理

第 744-748 行包含 Python 和 TypeScript 代码示例。代码块被转义为 JSON 字符串,包含实际的代码注释(中英文混合)。

几点观察:

  1. Python 示例的注释是中文的("融合 API 基础地址"等),这可能导致编码问题
  2. 代码中的变量名和 API 路由保持了英文,这是正确的
  3. 需要确保这些代码示例在前端渲染时正确处理换行符和缩进

建议验证代码块在 UI 中的显示效果,特别是缩进和行数。

考虑将长代码块分解为多个行,或使用专门的代码块组件来处理格式化。当前的 JSON 转义方式可能在渲染时造成可读性问题。


1-1: 整体国际化结构和最佳实践

此文件已扩展为包含完整产品生态的国际化翻译,结构化程度高。建议:

  1. 建立翻译键命名规范文档,确保新增键遵循一致的命名模式
  2. 实施自动化检查:检测重复键、缺失键、未使用的键
  3. 为翻译贡献者建立审核流程,确保术语一致性
  4. 定期同步与英文版本 (i18n/en/code.json) 的新增内容

建议创建一个 i18n 键映射文档或前端组件映射表,追踪每个键的使用位置。这有助于防止重复和孤立的翻译键。

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bcbe229 and 794f925.

⛔ Files ignored due to path filters (63)
  • package-lock.json is excluded by !**/package-lock.json
  • static/img/cases-1.svg is excluded by !**/*.svg
  • static/img/cases-2.svg is excluded by !**/*.svg
  • static/img/community-discord.svg is excluded by !**/*.svg
  • static/img/community-discussion.svg is excluded by !**/*.svg
  • static/img/community-github.svg is excluded by !**/*.svg
  • static/img/community-we-com.svg is excluded by !**/*.svg
  • static/img/community-x.svg is excluded by !**/*.svg
  • static/img/community-youtube.svg is excluded by !**/*.svg
  • static/img/create-workflow.svg is excluded by !**/*.svg
  • static/img/discord_line.svg is excluded by !**/*.svg
  • static/img/feature_1.png is excluded by !**/*.png
  • static/img/feature_3.jpg is excluded by !**/*.jpg
  • static/img/interactive.svg is excluded by !**/*.svg
  • static/img/logo-en-dark.svg is excluded by !**/*.svg
  • static/img/logo-en-light.svg is excluded by !**/*.svg
  • static/img/logo-symbol.svg is excluded by !**/*.svg
  • static/img/logo-zh-dark.svg is excluded by !**/*.svg
  • static/img/logo-zh-light.svg is excluded by !**/*.svg
  • static/img/logo.svg is excluded by !**/*.svg
  • static/img/logo_black.svg is excluded by !**/*.svg
  • static/img/macos-apple-silicon.svg is excluded by !**/*.svg
  • static/img/macos-intel.svg is excluded by !**/*.svg
  • static/img/pages/features/feature-1.svg is excluded by !**/*.svg
  • static/img/pages/features/feature-2.svg is excluded by !**/*.svg
  • static/img/pages/features/feature-3.svg is excluded by !**/*.svg
  • static/img/pages/features/feature-4.svg is excluded by !**/*.svg
  • static/img/pages/features/feature-5.svg is excluded by !**/*.svg
  • static/img/pages/features/feature-6.svg is excluded by !**/*.svg
  • static/img/pages/features/feature-7.svg is excluded by !**/*.svg
  • static/img/pages/headless/docker-deploy.svg is excluded by !**/*.svg
  • static/img/pages/headless/package-management.svg is excluded by !**/*.svg
  • static/img/pages/headless/remote-access.svg is excluded by !**/*.svg
  • static/img/pages/home/code-block-dark.png is excluded by !**/*.png
  • static/img/pages/home/code-block-light.png is excluded by !**/*.png
  • static/img/pages/home/community-detail-dark.png is excluded by !**/*.png
  • static/img/pages/home/community-detail-light.png is excluded by !**/*.png
  • static/img/pages/home/community-home-dark.png is excluded by !**/*.png
  • static/img/pages/home/community-home-light.png is excluded by !**/*.png
  • static/img/pages/home/connect-dark.png is excluded by !**/*.png
  • static/img/pages/home/connect-light.png is excluded by !**/*.png
  • static/img/pages/home/copilot-highlight.svg is excluded by !**/*.svg
  • static/img/pages/home/copilot.svg is excluded by !**/*.svg
  • static/img/pages/home/grok-dark-highlight.svg is excluded by !**/*.svg
  • static/img/pages/home/hero-dark.png is excluded by !**/*.png
  • static/img/pages/home/hero-light.png is excluded by !**/*.png
  • static/img/pages/home/openai-dark-highlight.svg is excluded by !**/*.svg
  • static/img/pages/home/ovm-dark.png is excluded by !**/*.png
  • static/img/pages/home/ovm-light.png is excluded by !**/*.png
  • static/img/pages/home/publish-dark.png is excluded by !**/*.png
  • static/img/pages/home/publish-light.png is excluded by !**/*.png
  • static/img/pages/home/share.png is excluded by !**/*.png
  • static/img/pages/home/siliconcloud-highlight.svg is excluded by !**/*.svg
  • static/img/pages/home/siliconcloud.svg is excluded by !**/*.svg
  • static/img/pricing.svg is excluded by !**/*.svg
  • static/img/scenes/chat.svg is excluded by !**/*.svg
  • static/img/scenes/data.svg is excluded by !**/*.svg
  • static/img/scenes/epub.svg is excluded by !**/*.svg
  • static/img/scenes/magic.svg is excluded by !**/*.svg
  • static/img/scenes/pdf.svg is excluded by !**/*.svg
  • static/img/scenes/zip.svg is excluded by !**/*.svg
  • static/img/screen1.svg is excluded by !**/*.svg
  • static/img/tech-background.svg is excluded by !**/*.svg
📒 Files selected for processing (107)
  • .claude/settings.local.json (1 hunks)
  • babel.config.js (0 hunks)
  • blog/2025-07-05-Export-Workflow-as-Image/index.mdx (1 hunks)
  • docs/advanced-guide/universal-block-settings.mdx (2 hunks)
  • docs/concepts/executor.mdx (1 hunks)
  • docs/faq.mdx (1 hunks)
  • docs/workflow-engine/principle.mdx (1 hunks)
  • docusaurus.config.js (7 hunks)
  • eslint.config.mjs (1 hunks)
  • i18n/en/code.json (11 hunks)
  • i18n/en/docusaurus-theme-classic/footer.json (1 hunks)
  • i18n/en/docusaurus-theme-classic/navbar.json (2 hunks)
  • i18n/zh-CN/code.json (11 hunks)
  • i18n/zh-CN/docusaurus-plugin-content-blog/2025-07-05-Export-Workflow-as-Image/index.mdx (1 hunks)
  • i18n/zh-CN/docusaurus-plugin-content-blog/2025-07-14-Convert-scanned-PDF-books-to-EPUB/index.mdx (1 hunks)
  • i18n/zh-CN/docusaurus-plugin-content-docs/current/advanced-guide/universal-block-settings.mdx (2 hunks)
  • i18n/zh-CN/docusaurus-plugin-content-docs/current/concepts/executor.mdx (1 hunks)
  • i18n/zh-CN/docusaurus-plugin-content-docs/current/faq.mdx (1 hunks)
  • i18n/zh-CN/docusaurus-plugin-content-docs/current/workflow-engine/principle.mdx (1 hunks)
  • i18n/zh-CN/docusaurus-plugin-content-pages/downloads/index.tsx (1 hunks)
  • i18n/zh-CN/docusaurus-plugin-content-pages/privacy/_privacy.mdx (1 hunks)
  • i18n/zh-CN/docusaurus-plugin-content-pages/privacy/index.tsx (1 hunks)
  • i18n/zh-CN/docusaurus-plugin-content-pages/privacy/styles.module.scss (1 hunks)
  • i18n/zh-CN/docusaurus-plugin-content-pages/support/index.tsx (1 hunks)
  • i18n/zh-CN/docusaurus-plugin-content-pages/support/styles.module.scss (1 hunks)
  • i18n/zh-CN/docusaurus-plugin-content-pages/terms/_terms.mdx (1 hunks)
  • i18n/zh-CN/docusaurus-plugin-content-pages/terms/index.tsx (1 hunks)
  • i18n/zh-CN/docusaurus-plugin-content-pages/terms/styles.module.scss (1 hunks)
  • i18n/zh-CN/docusaurus-theme-classic/footer.json (1 hunks)
  • i18n/zh-CN/docusaurus-theme-classic/navbar.json (1 hunks)
  • package.json (2 hunks)
  • src/components/AssetBlock/styles.module.scss (4 hunks)
  • src/components/Button/LinkBtn.module.scss (0 hunks)
  • src/components/Button/LinkBtn.tsx (0 hunks)
  • src/components/Button/index.tsx (0 hunks)
  • src/components/Button/styles.module.scss (0 hunks)
  • src/components/ComingSoon/index.tsx (0 hunks)
  • src/components/ComingSoon/styles.module.scss (0 hunks)
  • src/components/CyclicTypewriterText/index.tsx (0 hunks)
  • src/components/CyclicTypewriterText/styles.module.scss (0 hunks)
  • src/components/DownloadButton/index.tsx (4 hunks)
  • src/components/DownloadButton/styles.module.scss (3 hunks)
  • src/components/FeatureBlockList/FeatureBlockList.module.scss (1 hunks)
  • src/components/GetStartedPrompt/index.tsx (1 hunks)
  • src/components/GetStartedPrompt/styles.module.scss (2 hunks)
  • src/components/HomePageBuiltInLLM/CodeExample.tsx (1 hunks)
  • src/components/HomePageBuiltInLLM/index.tsx (4 hunks)
  • src/components/HomePageBuiltInLLM/styles.module.scss (2 hunks)
  • src/components/HomePagePricing/index.tsx (2 hunks)
  • src/components/HomePagePricing/style.module.scss (7 hunks)
  • src/components/HomepageCommunityShare/index.tsx (1 hunks)
  • src/components/HomepageCommunityShare/styles.module.scss (1 hunks)
  • src/components/HomepageCoreFeatures/index.tsx (1 hunks)
  • src/components/HomepageCoreFeatures/styles.module.scss (1 hunks)
  • src/components/HomepageCreate/index.tsx (0 hunks)
  • src/components/HomepageCreate/styles.module.scss (0 hunks)
  • src/components/HomepageCreateScenes/index.tsx (0 hunks)
  • src/components/HomepageCreateScenes/styles.module.scss (0 hunks)
  • src/components/HomepageDownloads/index.tsx (2 hunks)
  • src/components/HomepageDownloads/styles.module.scss (3 hunks)
  • src/components/HomepageFeatures/index.tsx (0 hunks)
  • src/components/HomepageFeatures/styles.module.scss (0 hunks)
  • src/components/HomepageFirstScreen/GridBackground.tsx (1 hunks)
  • src/components/HomepageFirstScreen/index.tsx (2 hunks)
  • src/components/HomepageFirstScreen/styles.module.scss (8 hunks)
  • src/components/HomepageGuide/index.tsx (0 hunks)
  • src/components/HomepageGuide/styles.module.scss (0 hunks)
  • src/components/HomepageLifecycle/index.tsx (1 hunks)
  • src/components/HomepageLifecycle/styles.module.scss (1 hunks)
  • src/components/HomepagePdfCraftShowcase/index.tsx (1 hunks)
  • src/components/HomepagePdfCraftShowcase/styles.module.scss (1 hunks)
  • src/components/HomepageProductComparison/index.tsx (1 hunks)
  • src/components/HomepageProductComparison/styles.module.scss (1 hunks)
  • src/components/HomepageProducts/index.tsx (0 hunks)
  • src/components/HomepageProducts/styles.module.scss (0 hunks)
  • src/components/HomepageScenes/FirstSceneCard.tsx (0 hunks)
  • src/components/HomepageScenes/index.tsx (0 hunks)
  • src/components/HomepageScenes/styles.module.scss (0 hunks)
  • src/components/HomepageStarter/index.tsx (1 hunks)
  • src/components/HomepageVideo/index.tsx (0 hunks)
  • src/components/HomepageVideo/styles.module.scss (0 hunks)
  • src/components/Popover/index.tsx (2 hunks)
  • src/components/ResponsiveImage/index.tsx (0 hunks)
  • src/components/Spin/Spin.tsx (4 hunks)
  • src/components/StudioPdfCraftCase/index.tsx (1 hunks)
  • src/components/StudioPdfCraftCase/styles.module.scss (1 hunks)
  • src/components/TypewriterText/index.tsx (0 hunks)
  • src/components/TypewriterText/styles.module.scss (0 hunks)
  • src/components/magic-ui/AuroraText.tsx (2 hunks)
  • src/components/magic-ui/GradualSpacing.tsx (0 hunks)
  • src/components/ui/button.tsx (1 hunks)
  • src/components/ui/card.tsx (1 hunks)
  • src/components/ui/dropdown-menu.tsx (1 hunks)
  • src/components/ui/popover.tsx (1 hunks)
  • src/css/custom.scss (9 hunks)
  • src/css/design-tokens.scss (1 hunks)
  • src/lib/utils.ts (1 hunks)
  • src/pages/about-us/index.tsx (0 hunks)
  • src/pages/about-us/styles.module.scss (0 hunks)
  • src/pages/brand-assets/index.tsx (3 hunks)
  • src/pages/brand-assets/styles.module.scss (9 hunks)
  • src/pages/chat/index.tsx (1 hunks)
  • src/pages/chat/styles.module.scss (1 hunks)
  • src/pages/cloud/index.tsx (1 hunks)
  • src/pages/cloud/styles.module.scss (1 hunks)
  • src/pages/contact-us/index.tsx (6 hunks)
  • src/pages/contact-us/styles.module.scss (11 hunks)
⛔ Files not processed due to max files limit (30)
  • src/pages/downloads/index.tsx
  • src/pages/downloads/styles.module.scss
  • src/pages/headless/index.tsx
  • src/pages/headless/styles.module.scss
  • src/pages/hub/index.tsx
  • src/pages/hub/styles.module.scss
  • src/pages/index.tsx
  • src/pages/oomol-api/index.tsx
  • src/pages/oomol-api/styles.module.scss
  • src/pages/oomol-cloud/index.tsx
  • src/pages/oomol-cloud/styles.module.scss
  • src/pages/oomol-studio/index.tsx
  • src/pages/oomol-studio/styles.module.scss
  • src/pages/open-source/index.tsx
  • src/pages/open-source/styles.module.scss
  • src/pages/pricing/index.tsx
  • src/pages/pricing/styles.module.scss
  • src/pages/privacy/_privacy.mdx
  • src/pages/privacy/index.tsx
  • src/pages/privacy/privacy.mdx
  • src/pages/studio/index.tsx
  • src/pages/studio/styles.module.scss
  • src/pages/support/index.tsx
  • src/pages/support/styles.module.scss
  • src/pages/system-status/index.tsx
  • src/pages/system-status/styles.module.scss
  • src/pages/terms/_terms.mdx
  • src/pages/terms/index.tsx
  • src/pages/terms/terms.mdx
  • src/theme/Footer/index.tsx
💤 Files with no reviewable changes (30)
  • babel.config.js
  • src/components/Button/index.tsx
  • src/components/HomepageVideo/index.tsx
  • src/components/ResponsiveImage/index.tsx
  • src/components/HomepageGuide/index.tsx
  • src/components/Button/styles.module.scss
  • src/components/HomepageCreateScenes/index.tsx
  • src/components/HomepageCreate/styles.module.scss
  • src/components/HomepageFeatures/index.tsx
  • src/pages/about-us/styles.module.scss
  • src/components/TypewriterText/index.tsx
  • src/components/CyclicTypewriterText/index.tsx
  • src/pages/about-us/index.tsx
  • src/components/HomepageProducts/styles.module.scss
  • src/components/magic-ui/GradualSpacing.tsx
  • src/components/HomepageScenes/FirstSceneCard.tsx
  • src/components/ComingSoon/styles.module.scss
  • src/components/ComingSoon/index.tsx
  • src/components/CyclicTypewriterText/styles.module.scss
  • src/components/HomepageScenes/styles.module.scss
  • src/components/HomepageCreateScenes/styles.module.scss
  • src/components/HomepageGuide/styles.module.scss
  • src/components/HomepageProducts/index.tsx
  • src/components/Button/LinkBtn.tsx
  • src/components/TypewriterText/styles.module.scss
  • src/components/Button/LinkBtn.module.scss
  • src/components/HomepageCreate/index.tsx
  • src/components/HomepageScenes/index.tsx
  • src/components/HomepageVideo/styles.module.scss
  • src/components/HomepageFeatures/styles.module.scss
🧰 Additional context used
🧬 Code graph analysis (15)
i18n/zh-CN/docusaurus-plugin-content-pages/downloads/index.tsx (3)
src/download_url.ts (1)
  • DownloadUrl (1-29)
src/pages/downloads/index.tsx (1)
  • Downloads (77-143)
src/lib/utils.ts (1)
  • downloadStable (14-28)
i18n/zh-CN/docusaurus-plugin-content-pages/support/index.tsx (1)
src/components/ui/button.tsx (1)
  • Button (57-57)
i18n/zh-CN/docusaurus-plugin-content-pages/terms/index.tsx (1)
i18n/zh-CN/docusaurus-plugin-content-pages/privacy/index.tsx (1)
  • Index (13-25)
i18n/zh-CN/docusaurus-plugin-content-pages/privacy/index.tsx (1)
i18n/zh-CN/docusaurus-plugin-content-pages/terms/index.tsx (1)
  • Index (12-24)
src/components/ui/button.tsx (1)
src/lib/utils.ts (1)
  • cn (4-6)
src/pages/contact-us/index.tsx (2)
src/components/ui/card.tsx (3)
  • Card (76-76)
  • CardHeader (76-76)
  • CardTitle (76-76)
src/components/Popover/index.tsx (1)
  • Popover (16-60)
src/components/ui/card.tsx (1)
src/lib/utils.ts (1)
  • cn (4-6)
src/components/DownloadButton/index.tsx (3)
src/components/ui/button.tsx (1)
  • Button (57-57)
src/lib/utils.ts (1)
  • downloadStable (14-28)
src/download_url.ts (1)
  • DownloadUrl (1-29)
src/components/ui/popover.tsx (2)
src/components/Popover/index.tsx (1)
  • Popover (16-60)
src/lib/utils.ts (1)
  • cn (4-6)
src/pages/cloud/index.tsx (1)
src/components/GetStartedPrompt/index.tsx (1)
  • GetStartedPrompt (6-29)
src/components/HomepageFirstScreen/index.tsx (3)
src/components/HomepageFirstScreen/GridBackground.tsx (1)
  • GridBackground (8-370)
src/components/magic-ui/AuroraText.tsx (1)
  • AuroraText (59-59)
src/components/DownloadButton/index.tsx (1)
  • DownloadButton (57-127)
src/pages/chat/index.tsx (1)
src/components/GetStartedPrompt/index.tsx (1)
  • GetStartedPrompt (6-29)
src/components/HomePageBuiltInLLM/index.tsx (1)
src/components/HomePageBuiltInLLM/CodeExample.tsx (1)
  • CodeExample (91-107)
src/components/ui/dropdown-menu.tsx (1)
src/lib/utils.ts (1)
  • cn (4-6)
src/components/Popover/index.tsx (1)
src/components/ui/popover.tsx (2)
  • PopoverTrigger (31-31)
  • PopoverContent (31-31)
🪛 Biome (2.1.2)
i18n/en/code.json

[error] 1633-1633: The key STUDIO.hero.description was already declared.

This where a duplicated key was declared again.

If a key is defined multiple times, only the last definition takes effect. Previous definitions are ignored.

(lint/suspicious/noDuplicateObjectKeys)


[error] 2047-2047: The key HEADLESS.hero.description was already declared.

This where a duplicated key was declared again.

If a key is defined multiple times, only the last definition takes effect. Previous definitions are ignored.

(lint/suspicious/noDuplicateObjectKeys)

i18n/zh-CN/code.json

[error] 1552-1553: The key STUDIO.hero.description was already declared.

This where a duplicated key was declared again.

If a key is defined multiple times, only the last definition takes effect. Previous definitions are ignored.

(lint/suspicious/noDuplicateObjectKeys)

🪛 LanguageTool
i18n/zh-CN/docusaurus-plugin-content-blog/2025-07-14-Convert-scanned-PDF-books-to-EPUB/index.mdx

[uncategorized] ~37-~37: "间"不能与“模式”搭配,请换量词
Context: ...在自己喜欢的 EPUB 阅读器上,以最适合自己的方式浏览这些内容:调整字号、切换夜间模式,甚至可以让 AI 朗读。 [pdf-craft](https://git...

(wa5)


[uncategorized] ~39-~39: 动词的修饰一般为‘形容词(副词)+地+动词’。您的意思是否是:正确"地"阅读
Context: ...DF 文件中的文本内容、页眉页脚、参考注释等。能够保持跨页内容的连贯性,还原正确的阅读顺序。此外,它还会使用 LLM 来构建完整的 EPUB 目录结构。 在 o...

(wb4)

i18n/zh-CN/docusaurus-plugin-content-pages/privacy/_privacy.mdx

[uncategorized] ~154-~154: 动词的修饰一般为‘形容词(副词)+地+动词’。您的意思是否是:合理"地"预防
Context: ...控系统 - 建立安全事件响应计划 ### 4.3. 安全限制 虽然我们采取合理的预防措施,但没有任何通过互联网传输数据或电子存储的方法是 100% 安全的。我们...

(wb4)


[uncategorized] ~251-~251: 数量词修饰并列短语,可能产生歧义
Context: .... 第三方链接和服务 ### 8.1. 第三方网站 Oomol 可能包含指向第三方网站、插件或服务的链接。我们不对这些第三方的隐私做法或内容负责。 ### 8.2. ...

(s5)

i18n/zh-CN/docusaurus-plugin-content-docs/current/concepts/executor.mdx

[uncategorized] ~164-~164: 动词的修饰一般为‘形容词(副词)+地+动词’。您的意思是否是:正确"地"执行
Context: ...码启用独立进程执行** 4. 遵循 OOMOL 提供的代码模板以确保正确的执行器集成: - [Node.js 模板](/zh-CN/docs/wor...

(wb4)

i18n/zh-CN/docusaurus-plugin-content-pages/terms/_terms.mdx

[uncategorized] ~182-~182: 能愿动词不能成为‘把’字句、‘被’字句的谓语动词。应该是:"可被……认定"。
Context: ...于使用服务的完整协议。 12.3. 可分割性:如果本服务条款的任何条款被认定为无效或不可执行,该条款应在必要范围内进行修改以使其有效,或在无法修改的情况下予以删除,其余...

(wa3)

i18n/zh-CN/docusaurus-plugin-content-docs/current/advanced-guide/universal-block-settings.mdx

[grammar] ~200-~200: Ensure spelling is correct
Context: ...执行器由 oomol 团队内部实现,可支持 Python 以及 Node.js 运行环境,因此有对应的两个可选项。 Python 执行器: - 在 Python 运行时环境中执行 Python...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Cloudflare Pages

Comment on lines 1 to 48
{
"permissions": {
"allow": [
"Bash(npm run build:*)",
"Bash(npm run start:*)",
"Bash(lsof:*)",
"Bash(xargs kill:*)",
"Bash(npm run start:en:*)",
"Bash(npm run)",
"Bash(npm run lint:*)",
"Bash(npm run type-check:*)",
"Bash(npx tsc:*)",
"Bash(npm run typecheck:*)",
"Bash(cat:*)",
"Bash(i18n/zh-CN/code.json)",
"Bash(node -e:*)",
"Bash(find:*)",
"Bash(rm /Users/wushuang/code/oomol.com/src/components/ui/accordion.tsx /Users/wushuang/code/oomol.com/src/components/ui/popover.tsx /Users/wushuang/code/oomol.com/src/components/ui/tooltip.tsx /Users/wushuang/code/oomol.com/src/components/ui/dialog.tsx /Users/wushuang/code/oomol.com/src/components/ui/table.tsx)",
"Bash(rm /Users/wushuang/code/oomol.com/src/components/magic-ui/GradualSpacing.tsx)",
"Bash(rm -rf /Users/wushuang/code/oomol.com/src/components/HomepageChatAgent /Users/wushuang/code/oomol.com/src/components/HomepageCommunityShare /Users/wushuang/code/oomol.com/src/components/HomepageCoreTech /Users/wushuang/code/oomol.com/src/components/HomepageEcosystem /Users/wushuang/code/oomol.com/src/components/HomepageGuide /Users/wushuang/code/oomol.com/src/components/HomepageValueProps /Users/wushuang/code/oomol.com/src/components/HomepageVideo /Users/wushuang/code/oomol.com/src/components/HomepageWhyOomol /Users/wushuang/code/oomol.com/src/components/ResponsiveImage /Users/wushuang/code/oomol.com/src/components/TypewriterText)",
"Bash(git checkout HEAD -- /Users/wushuang/code/oomol.com/src/components/ui/popover.tsx)",
"Bash(rm -rf /Users/wushuang/code/oomol.com/.docusaurus /Users/wushuang/code/oomol.com/build /Users/wushuang/code/oomol.com/node_modules/.cache)",
"Bash(rm -rf /Users/wushuang/code/oomol.com/src/components/HomepageFeatures)",
"Bash(done)",
"Bash(xargs -I {} bash -c 'echo \"\"\"\"=== $(basename {}) ===\"\"\"\" && find {} -type f \\( -name \"\"\"\"*.tsx\"\"\"\" -o -name \"\"\"\"*.ts\"\"\"\" \\) 2>/dev/null')",
"Bash(mkdir -p /Users/wushuang/code/oomol.com/src/components/HomepageCoreFeatures)",
"Bash(npm run build:zh-CN)",
"Bash(npm run start:zh-cn)",
"Bash(kill 69546 96927)",
"Bash(node --version)",
"Bash(npm --version)",
"Bash(npm run clear)",
"Bash(kill 74240 78577)",
"Bash(rm -rf .docusaurus build node_modules/.cache)",
"Bash(kill 7420 86602)",
"Bash(tree -L 3 /Users/wushuang/code/oomol.com/src/pages/terms /Users/wushuang/code/oomol.com/i18n/zh-CN/docusaurus-plugin-content-pages/terms)",
"Bash(mkdir -p /Users/wushuang/code/oomol.com/src/components/HomepageCommunityShare)",
"Bash(npm run build-unocss)",
"Bash(kill 88270 88442)",
"Bash(npm install @radix-ui/themes)",
"Bash(mkdir -p /Users/wushuang/code/oomol.com/i18n/zh-CN/docusaurus-plugin-content-pages/support)",
"Bash(cp /Users/wushuang/code/oomol.com/src/pages/support/styles.module.scss /Users/wushuang/code/oomol.com/i18n/zh-CN/docusaurus-plugin-content-pages/support/styles.module.scss)",
"Bash(kill 25847 26430)"
],
"deny": [],
"ask": []
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Check if .gitignore exists and its contents
if [ -f .gitignore ]; then
  echo "=== .gitignore contents ==="
  cat .gitignore | grep -i "claude\|\.local"
else
  echo "No .gitignore found"
fi

Repository: oomol/oomol.com

Length of output: 158


🏁 Script executed:

# Check .claude directory structure and what exists
echo "=== .claude directory contents ==="
ls -la .claude/ 2>/dev/null || echo ".claude directory does not exist"

Repository: oomol/oomol.com

Length of output: 276


🏁 Script executed:

# Check git status to see if this file is tracked
echo "=== Git status for .claude/settings.local.json ==="
git status .claude/settings.local.json 2>/dev/null || echo "File not in git"

# Check if file is staged
echo "=== Check if file is staged in this commit ==="
git diff --cached --name-only 2>/dev/null | grep "\.claude"

Repository: oomol/oomol.com

Length of output: 222


🏁 Script executed:

# Check if there's a .claude/settings.json (team-shared version)
echo "=== Checking for .claude/settings.json ==="
ls -la .claude/settings.json 2>/dev/null || echo "No team settings.json found"

Repository: oomol/oomol.com

Length of output: 129


🌐 Web query:

Claude Code settings.local.json version control gitignore

💡 Result:

Short answer: Claude Code creates a project-local settings file at .claude/settings.local.json and will configure git to ignore it. If you need to add/verify this yourself, add this line to your .gitignore:

.claude/settings.local.json

If the file was already committed, remove it from the repo while keeping it locally:

git rm --cached .claude/settings.local.json
git commit -m "Remove local Claude settings from repo"

Sources: Claude Code docs (settings files). [1][2]


.claude/settings.local.json should not be committed to version control and must be removed from git history.

Per Claude Code documentation, .claude/settings.local.json is a personal local settings file that should be automatically ignored by git. This file is currently committed and not excluded by .gitignore.

Issues:

  1. Missing .gitignore entry: Add .claude/settings.local.json to .gitignore.
  2. Machine-specific absolute paths: The file contains hardcoded paths like /Users/wushuang/code/oomol.com/src/... (lines 18–22, 26, 36–37, 41–42) that do not work on other developers' machines.
  3. Temporary development commands: Includes process kill commands with specific PIDs (lines 29, 33, 35, 39, 43) and file deletions that have no place in a shared repository.

Remove the file from git history using git rm --cached .claude/settings.local.json and update .gitignore before merging this PR.

🤖 Prompt for AI Agents
In .claude/settings.local.json (lines 1–48) the file is a personal local
settings file containing machine-specific absolute paths, ephemeral kill/PID
entries, and other temporary commands and must be removed from version control:
add .claude/settings.local.json to .gitignore, remove the tracked file with git
rm --cached .claude/settings.local.json and commit the removal, replace the
committed file in the repo (if you need a repo-safe example) with a sanitized
template that omits absolute paths and PIDs (or move the real file to each
developer’s local .claude/), and if you need to purge it from history run a
history-rewrite tool (git filter-repo or BFG) to remove the file from previous
commits before force-pushing the cleaned branch.

Comment on lines 14 to 15
'*.config.js',
'*.config.mjs',
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

配置文件自我排除可能导致配置错误未被检测。

第 14-15 行排除了所有 *.config.js*.config.mjs 文件,这意味着当前的 eslint.config.mjs 本身不会被 lint。如果配置文件中存在代码质量问题,将无法被检测到。

如果希望对配置文件也进行 lint,可以更精确地指定忽略模式:

       'static/**',
-      '*.config.js',
-      '*.config.mjs',
+      'webpack.config.js',
+      'postcss.config.js',
+      'tailwind.config.js',
       'src/styles/uno.css',
🤖 Prompt for AI Agents
In eslint.config.mjs around lines 14-15, the patterns '*.config.js' and
'*.config.mjs' globally exclude config files (including eslint.config.mjs) from
linting; update the ignore patterns to stop excluding your ESLint config itself
— either remove these two patterns or narrow them to specific directories/files
you truly want ignored (e.g., only third-party or legacy config folders), and
ensure eslint.config.mjs is included for linting so configuration issues are
detected.

Comment on lines +82 to +85
...js.configs.recommended.rules,
...tseslint.configs.recommended.rules,
...react.configs.recommended.rules,
...reactHooks.configs.recommended.rules,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, check if eslint.config.mjs exists and read the relevant section
cat -n eslint.config.mjs | head -100

Repository: oomol/oomol.com

Length of output: 3555


🏁 Script executed:

# Check the imports at the top of the file
head -50 eslint.config.mjs

Repository: oomol/oomol.com

Length of output: 1406


🏁 Script executed:

# Verify that the config objects have the expected properties
rg "js\.configs|tseslint\.configs|react\.configs|reactHooks\.configs" -A 2 -B 2 eslint.config.mjs

Repository: oomol/oomol.com

Length of output: 270


🏁 Script executed:

# Check package.json for lint script
cat package.json | grep -A 5 '"scripts"'

Repository: oomol/oomol.com

Length of output: 309


🏁 Script executed:

# Check the actual TypeScript ESLint plugin export structure
# by looking at node_modules if available
ls -la node_modules/@typescript-eslint/ 2>/dev/null | head -20 || echo "node_modules not available, checking package docs"

Repository: oomol/oomol.com

Length of output: 41


🏁 Script executed:

# Search for how tseslint is actually used elsewhere in the config
rg "tseslint\." eslint.config.mjs

Repository: oomol/oomol.com

Length of output: 103


🌐 Web query:

@typescript-eslint/eslint-plugin flat config recommended rules exports

💡 Result:

Use the plugin's shared flat configs. Example eslint.config.mjs enabling the recommended rules (and the typed rules variant if you want type-aware rules):

eslint.config.mjs
import eslint from '@eslint/js';
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';

export default defineConfig(
eslint.configs.recommended,
tseslint.configs.recommended, // basic recommended rules
// tseslint.configs.recommendedTypeChecked // add this for rules that require type information
);

Docs: typescript-eslint shared configs and package usage. [1][2]

Sources
[1] typescript-eslint package / usage (flat config).
[2] Shared configs (recommended, recommended-type-checked) — typescript-eslint.


The recommended rules configuration contains critical errors that will cause runtime failures.

Line 83 has two issues:

  1. Import path: @typescript-eslint/eslint-plugin should be typescript-eslint
  2. Property access: tseslint.configs.recommended.rules is incorrect; it should be tseslint.configs.recommended without .rules

The flat config pattern for TypeScript ESLint is:

import tseslint from 'typescript-eslint';
// Then use directly:
tseslint.configs.recommended

The same issue applies to js.configs.recommended.rules and react.configs.recommended.rules on lines 82 and 84—remove the .rules suffix. The config objects themselves are the rule sets, not nested under a .rules property.

🤖 Prompt for AI Agents
In eslint.config.mjs around lines 82 to 85, the config spreads are using the
wrong property and an incorrect import path for TypeScript ESLint: remove the
trailing ".rules" from js.configs.recommended, tseslint.configs.recommended,
react.configs.recommended and reactHooks.configs.recommended so you spread the
config objects themselves (e.g., ...js.configs.recommended), and ensure the
TypeScript ESLint import uses 'typescript-eslint' (not
'@typescript-eslint/eslint-plugin') so you reference
tseslint.configs.recommended rather than tseslint.configs.recommended.rules.

@Cheerego7 Cheerego7 changed the title Frp refactor: overhaul website with new design and improved user experience Dec 5, 2025
@alwaysmavs alwaysmavs merged commit 714db6c into main Dec 5, 2025
5 of 6 checks passed
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (8)
i18n/en/code.json (2)

1632-1634: 重复的 STUDIO.hero.description 键定义需要删除

STUDIO.hero.description 在第 1632-1634 行和第 2349-2351 行中定义了两次。在 JSON 中,重复的键定义会导致第一个定义被忽略,只有最后一个定义生效。两个定义的内容不同:

  • 第 1632 行:"Visual Workflow + Full Code with VSCode, Build and Share AI Tools Fast"
  • 第 2349 行:"Local development environment for developers, VSCode-based visual programming tool with FRP protocol for P2P computing power sharing"

第二个定义更加详细,应该保留第二个定义,删除第一个重复的定义。

删除以下重复定义:

-  "STUDIO.hero.description": {
-    "message": "Visual Workflow + Full Code with VSCode, Build and Share AI Tools Fast"
-  },

Also applies to: 2349-2351


2049-2051: 重复的 HEADLESS.hero.description 键定义需要删除

HEADLESS.hero.description 在第 2049-2051 行和第 2352-2354 行中定义了两次。只有最后一个定义会生效,前面的定义被忽略。

  • 第 2049 行:"Docker containerized deployment to easily run OOMOL applications on servers and NAS"
  • 第 2352 行:"Containerized deployment solution, packaging workflows as standalone Docker images for cloud servers, private clouds and K8s clusters"

第二个定义更加完整,应该保留第二个定义,删除第一个重复的。

删除以下重复定义:

-  "HEADLESS.hero.description": {
-    "message": "Docker containerized deployment to easily run OOMOL applications on servers and NAS"
-  },

Also applies to: 2352-2354

i18n/zh-CN/code.json (1)

1184-1186: 重复的 STUDIO.hero.description 键定义需要删除

STUDIO.hero.description 在第 1184-1186 行和第 2352-2354 行中定义了两次。JSON 规范中,重复的键只有最后一个定义会生效,前面的定义会被忽略。

  • 第 1184 行:"可视化工作流 + VSCode 全代码,快速构建并分享 AI 工具"
  • 第 2352 行:"面向开发者的本地开发环境,基于 VSCode 的可视化编程工具,结合 FRP 协议实现 P2P 算力共享"

第二个定义更详细完整,应保留第二个定义,删除第一个重复的定义。

删除以下重复定义:

-  "STUDIO.hero.description": {
-    "message": "可视化工作流 + VSCode 全代码,快速构建并分享 AI 工具"
-  },

Also applies to: 2352-2354

eslint.config.mjs (3)

2-2: TypeScript ESLint 的导入路径不正确。

当前导入路径 @typescript-eslint/eslint-plugin 在 flat config 模式下不正确。应该从 typescript-eslint 包导入。这会导致后续使用 tseslint.configs.recommended 时出现运行时错误。

应用此修复:

-import tseslint from "@typescript-eslint/eslint-plugin";
+import tseslint from "typescript-eslint";

14-15: 配置文件排除模式过于宽泛。

当前的排除模式会导致 eslint.config.mjs 自身不被检查。如果配置文件中存在代码质量问题,将无法被检测到。

建议更精确地指定需要忽略的配置文件:

-      '*.config.js',
-      '*.config.mjs',
+      'webpack.config.js',
+      'postcss.config.js',
+      'tailwind.config.js',

82-85: 规则配置的属性访问错误。

第 82-85 行错误地使用了 .rules 后缀。在 ESLint flat config 中,配置对象本身就是规则集,不应该访问嵌套的 .rules 属性。这会导致运行时错误,因为这些配置对象没有 .rules 属性。

应用此修复:

-      ...js.configs.recommended.rules,
-      ...tseslint.configs.recommended.rules,
-      ...react.configs.recommended.rules,
-      ...reactHooks.configs.recommended.rules,
+      ...js.configs.recommended,
+      ...tseslint.configs.recommended,
+      ...react.configs.recommended,
+      ...reactHooks.configs.recommended,
src/css/design-tokens.scss (2)

26-32: 文本颜色对比度注释与实际值不符。

代码注释声称 --oomol-text-quaternary--oomol-text-disabled(均为 rgba(0, 0, 0, 0.45))符合 WCAG AA 标准(4.5:1),但实际上:

  • rgba(0, 0, 0, 0.45) 在白色背景上的对比度约为 3.0:1
  • WCAG AA 要求正常文本的对比度至少为 4.5:1
  • 大文本(≥18pt 或 ≥14pt 粗体)的对比度至少为 3:1

建议:

  1. 如果这些令牌仅用于大文本或装饰性元素,请更新注释说明其用途限制
  2. 如果用于正常文本,需要将 alpha 值提高到至少 0.65 以满足 WCAG AA 标准
  3. 或者添加单独的令牌用于装饰性用途
-  --oomol-text-quaternary: rgba(
-    0,
-    0,
-    0,
-    0.45
-  ); /* WCAG AA: 4.5:1 minimum for text */
-  --oomol-text-disabled: rgba(0, 0, 0, 0.45); /* WCAG AA compliant */
+  --oomol-text-quaternary: rgba(0, 0, 0, 0.45); /* For large text or decorative elements only (3:1 contrast) */
+  --oomol-text-disabled: rgba(0, 0, 0, 0.45); /* For large text or decorative elements only (3:1 contrast) */

或者提高对比度以支持正常文本:

-  --oomol-text-quaternary: rgba(
-    0,
-    0,
-    0,
-    0.45
-  ); /* WCAG AA: 4.5:1 minimum for text */
-  --oomol-text-disabled: rgba(0, 0, 0, 0.45); /* WCAG AA compliant */
+  --oomol-text-quaternary: rgba(0, 0, 0, 0.65); /* WCAG AA compliant for normal text (4.5:1) */
+  --oomol-text-disabled: rgba(0, 0, 0, 0.65); /* WCAG AA compliant for normal text (4.5:1) */

218-225: 暗色模式文本对比度仍未达到 WCAG AA 标准。

虽然代码注释表明对比度已从之前的值改进(tertiary 从 0.50 到 0.55,quaternary 从 0.25 到 0.45),但 --oomol-text-quaternary--oomol-text-disabled(均为 rgba(255, 255, 255, 0.45))在暗色背景(#141414)上的对比度约为 3.3:1,仍低于 WCAG AA 要求的 4.5:1

建议与浅色模式相同:

  1. 在注释中明确这些令牌仅用于大文本或装饰性元素
  2. 或将 alpha 值提高到至少 0.65 以满足正常文本的 WCAG AA 标准
-  --oomol-text-quaternary: rgba(
-    255,
-    255,
-    255,
-    0.45
-  ); /* WCAG AA: improved from 0.25 */
-  --oomol-text-disabled: rgba(255, 255, 255, 0.45); /* WCAG AA compliant */
+  --oomol-text-quaternary: rgba(255, 255, 255, 0.45); /* For large text or decorative elements only (~3.3:1 contrast) */
+  --oomol-text-disabled: rgba(255, 255, 255, 0.45); /* For large text or decorative elements only (~3.3:1 contrast) */

或者提高对比度:

-  --oomol-text-quaternary: rgba(
-    255,
-    255,
-    255,
-    0.45
-  ); /* WCAG AA: improved from 0.25 */
-  --oomol-text-disabled: rgba(255, 255, 255, 0.45); /* WCAG AA compliant */
+  --oomol-text-quaternary: rgba(255, 255, 255, 0.65); /* WCAG AA compliant for normal text (~5:1 contrast) */
+  --oomol-text-disabled: rgba(255, 255, 255, 0.65); /* WCAG AA compliant for normal text (~5:1 contrast) */
🧹 Nitpick comments (7)
src/pages/chat/index.tsx (2)

69-94: 优化类型声明与列表 key,可读性与健壮性更好

这里的实现是正确的,不过有两点可以作为小优化考虑:

  1. 显式类型别名
    目前 props 使用 ({ useCase }: { useCase: (typeof useCases)[0] }) / ({ feature }: { feature: (typeof coreFeatures)[0] }),类型推断没问题,但可读性稍差。可以考虑提取类型别名,让结构更直观,例如:
type UseCase = {
  icon: string;
  title: string;
  description: string;
};

type CoreFeature = {
  icon: string;
  title: string;
  description: string;
  features: string[];
};

const useCases: UseCase[] = [/* ... */];
const coreFeatures: CoreFeature[] = [/* ... */];

const UseCaseCard = ({ useCase }: { useCase: UseCase }) => { /* ... */ };
const FeatureCard = ({ feature }: { feature: CoreFeature }) => { /* ... */ };
  1. features 列表的 key 使用文案本身而非索引
    feature.features.map((item, idx) => <li key={idx}> 在当前静态数组场景下能工作,但从 React 最佳实践看,更推荐使用稳定标识以避免未来改动时出现不必要的重渲染。这里文案本身是唯一字符串,可直接作为 key:
-      <ul className={styles.featureList}>
-        {feature.features.map((item, idx) => (
-          <li key={idx}>{item}</li>
-        ))}
-      </ul>
+      <ul className={styles.featureList}>
+        {feature.features.map((item) => (
+          <li key={item}>{item}</li>
+        ))}
+      </ul>

这两点都属于可选优化,不影响当前功能。


96-178: 内部导航与国际化文案可以进一步统一

整体页面结构(Hero + Use Cases + Features + CTA)清晰,DOM 语义也合理;有几点可以考虑优化:

  1. 内部链接建议使用 Docusaurus 的 Link 而非原生 <a>
    href="/downloads"href="/docs" 是站内路径,在 Docusaurus 中一般推荐用 @docusaurus/Linkto 属性,这样可以自动处理 baseUrl、语言前缀以及避免整页刷新。例如:
-import Layout from "../../theme/Layout";
+import Layout from "../../theme/Layout";
+import Link from "@docusaurus/Link";

-          <div className={styles.heroCTA}>
-            <a href="/downloads" className={styles.primaryButton}>
-              {translate({ message: "CHAT.hero.cta.download" })}
-            </a>
-            <a href="/docs" className={styles.secondaryButton}>
-              {translate({ message: "CHAT.hero.cta.docs" })}
-            </a>
-          </div>
+          <div className={styles.heroCTA}>
+            <Link to="/downloads" className={styles.primaryButton}>
+              {translate({ message: "CHAT.hero.cta.download" })}
+            </Link>
+            <Link to="/docs" className={styles.secondaryButton}>
+              {translate({ message: "CHAT.hero.cta.docs" })}
+            </Link>
+          </div>
  1. Hero 标题与部分 stat 文案是否需要国际化(取决于产品定位)
    • OOMOL Chat 一般可以视为产品名,保持英文常见且可以不翻译;
    • MCP 通常是缩写/品牌词,也可以不翻译;
    • AI Agent 更偏概念性用语,如果你们希望在中文页面里也完全本地化文案,可以考虑也包一层 translate(),例如新增 key:CHAT.hero.statValue3

这些都属于体验与本地化层面的改进点,不影响当前功能正确性。

请在你们项目使用的 Docusaurus 版本文档中再确认一次 @docusaurus/Link 的推荐用法及 to 属性的路径写法是否与上述示例一致。

src/components/HomepageFirstScreen/index.tsx (5)

16-30: parseHighlightText 实现合理,之前的 key 问题也已妥善修复

现在普通文本部分通过带 key 的 React.Fragment 返回,React 列表 key 告警已经不会再出现;按 **...** 拆分并包一层高亮样式也比较直观、易维护。如果后续文案里可能出现把 ** 当普通字符使用的场景,再考虑调整正则或约定转义即可,当前实现完全可以先稳定使用。


32-38: 可以考虑去掉对 DocusaurusContext 的双重类型断言

useDocusaurusContext() 这里用了 as unknown as DocusaurusContext & { i18n: { currentLocale: string } },有点重,会掩盖类型变化带来的问题。Docusaurus 的上下文本身就带 i18n 信息的话,其实可以直接:

const { i18n } = useDocusaurusContext();

或者只做一次更窄的断言即可,让类型系统多帮一点忙。


39-41: 脚本文案高亮逻辑 OK,如需微优化可用 useMemo 缓存解析结果

scriptText 每次 render 都会重新走 translate + parseHighlightText,在当前复杂度和调用频率下没什么问题。如果后面脚本文案变长、解析规则变复杂,可以考虑:

const parsedScript = useMemo(
  () => parseHighlightText(scriptText),
  [scriptText],
);
...
{parsedScript}

在不改变行为的前提下,避免重复拆分。

Also applies to: 82-85


50-78: 中英文 slogan 结构目前完全一致,可以视情况去掉 JSX 分支重复

i18n.currentLocale === "zh-CN" 已经在 className 上做了区分,而 AuroraText 两个分支里 JSX 结构是相同的,只是依赖同一组翻译 key 输出不同语言。若短期内不打算让中英文在结构上分叉,其实可以收敛成一份 JSX,locale 仅通过 translate 处理文案:

<AuroraText className={styles["aurora-slogan"]}>
  {translate({ message: "HOME.FirstScreen.slogan.line1" })}
  <br />
  {translate({ message: "HOME.FirstScreen.slogan.line2" })}
</AuroraText>

这样后面改样式或结构时维护成本更低。


93-105: 暗/亮模式截图切换实现正确,可考虑本地化 alt 文案并评估双图加载

手动用 colorMode 切换 hero-dark.png / hero-light.png 很直观,配合 loading="eager"fetchPriority="high" 对首屏也比较友好。两个小建议供参考:

  1. alt="OOMOL Product Screenshot" 可以通过 translate 本地化一下,和整页 i18n 策略保持一致。
  2. 当前切换主题会在两张图之间来回请求,如果图片体积较大,可以评估是否需要使用 Docusaurus 提供的 ThemedImage 或 CSS 方案来减少额外网络开销。
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dcc7c81 and 671eecf.

📒 Files selected for processing (10)
  • .gitignore (1 hunks)
  • eslint.config.mjs (1 hunks)
  • i18n/en/code.json (11 hunks)
  • i18n/zh-CN/code.json (11 hunks)
  • src/components/HomepageFirstScreen/index.tsx (2 hunks)
  • src/components/HomepageLifecycle/index.tsx (1 hunks)
  • src/components/HomepagePdfCraftShowcase/index.tsx (1 hunks)
  • src/css/design-tokens.scss (1 hunks)
  • src/pages/chat/index.tsx (1 hunks)
  • src/pages/contact-us/index.tsx (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/components/HomepageLifecycle/index.tsx
  • src/components/HomepagePdfCraftShowcase/index.tsx
🧰 Additional context used
🧬 Code graph analysis (2)
src/components/HomepageFirstScreen/index.tsx (3)
src/components/HomepageFirstScreen/GridBackground.tsx (1)
  • GridBackground (8-370)
src/components/magic-ui/AuroraText.tsx (1)
  • AuroraText (59-59)
src/components/DownloadButton/index.tsx (1)
  • DownloadButton (57-127)
src/pages/chat/index.tsx (1)
src/components/GetStartedPrompt/index.tsx (1)
  • GetStartedPrompt (6-29)
🪛 Biome (2.1.2)
i18n/en/code.json

[error] 1633-1633: The key STUDIO.hero.description was already declared.

This where a duplicated key was declared again.

If a key is defined multiple times, only the last definition takes effect. Previous definitions are ignored.

(lint/suspicious/noDuplicateObjectKeys)


[error] 2050-2050: The key HEADLESS.hero.description was already declared.

This where a duplicated key was declared again.

If a key is defined multiple times, only the last definition takes effect. Previous definitions are ignored.

(lint/suspicious/noDuplicateObjectKeys)

i18n/zh-CN/code.json

[error] 1550-1550: The key STUDIO.hero.description was already declared.

This where a duplicated key was declared again.

If a key is defined multiple times, only the last definition takes effect. Previous definitions are ignored.

(lint/suspicious/noDuplicateObjectKeys)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (11)
.gitignore (1)

18-19: 新增条目简洁合理。

将 Claude 本地设置文件添加到 .gitignore 是一个很好的做法,可以防止机器特定的配置被提交。条目放置位置恰当,与其他本地/环境特定文件(如 .env.local)逻辑分组,注释清晰易懂。

src/pages/chat/index.tsx (1)

7-67: 使用场景与核心功能数据结构整体合理

useCasescoreFeatures 用数组 + translate 的方式组织文案和图标,结构清晰、易于扩展,也方便后续在同一位置维护多语言文案,当前实现没有明显问题。

src/pages/contact-us/index.tsx (6)

6-6: 导入语句正确。

新增的 Card 组件和 useBaseUrl hook 导入正确,且在文件中被正确使用。

Also applies to: 9-9


129-130: 正确使用 useBaseUrl 处理静态资源。

使用 useBaseUrl hook 来构建图片路径是 Docusaurus 的最佳实践,能够正确处理不同的部署环境和 base URL 配置。


257-276: 卡片式联系方式列表实现正确。

新的实现使用了语义化的锚点标签包裹卡片,并正确应用了 target="_blank"rel="noopener noreferrer" 来确保安全性,防止反向标签劫持攻击。卡片结构清晰,符合最佳实践。


277-300: Popover 实现符合新的设计系统。

将触发器改为卡片式布局,并使用右侧定位(position="right"),提升了用户体验。二维码图片正确使用了 useBaseUrl


317-358: 仓库列表实现正确,具有良好的回退机制。

实现包括:

  • 正确的外部链接安全属性
  • GitHub 统计数据的条件渲染,当 API 数据不可用时回退到默认值
  • 统一的仓库图标使用 useBaseUrl 处理

代码逻辑清晰,错误处理得当。


66-66: Icon classes are auto-generated by UnoCSS and will be properly available.

The icon classes (i-bi-discord, i-bi-youtube, i-bi-twitter-x, i-bi-github, i-octicon-comment-discussion-16) are not manually defined in CSS. They are generated by UnoCSS during the build process via the build-unocss command. The project's uno.config.ts properly configures the presetIcons preset with @iconify/json collections for Bootstrap Icons (bi) and Octicons (octicon). These icons will be bundled into src/styles/uno.css at build time, so they will display correctly.

src/css/design-tokens.scss (3)

387-456: 排版和间距系统设计合理。

设计令牌系统实现了完整的排版(字体大小、字重、行高)和基于 8pt 网格的间距系统,符合现代设计系统的最佳实践。令牌命名清晰,数值设置合理且一致。


462-491: 过渡动画实现考虑周全,避免了性能问题。

实现亮点:

  • 选择性地仅对特定元素应用过渡,避免使用全局通配符导致的性能问题
  • 明确排除不需要过渡的媒体元素(img、video、canvas、svg、iframe)
  • 使用合适的缓动函数和持续时间(0.3s)

这是处理主题切换动画的最佳实践。


263-265: The primary text color provides excellent contrast for dark backgrounds, exceeding WCAG AAA standards.

The --oomol-primary-text: #a8a9f0 color choice on a #141414 dark background achieves an actual contrast ratio of 8.42:1, which exceeds both WCAG AA (4.5:1) and WCAG AAA (7:1) standards for normal text. The code is correct and requires no changes.

@Cheerego7 Cheerego7 deleted the frp branch December 5, 2025 09:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants