[
  {
    "path": ".gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n.yarn/install-state.gz\n.pnpm-store/\n\n# testing\n/coverage\n\n# next.js\n/.next/\n/out/\n\n# production\n/build\n_pagefind/\n\n# misc\n.DS_Store\n*.pem\n\n# debug\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# local env files\n.env*.local\n\n# vercel\n.vercel\n\n# typescript\n*.tsbuildinfo\n\n# sitemap and robots.txt\npublic/robots.txt\npublic/sitemap.xml\npublic/sitemap-*.xml\n"
  },
  {
    "path": ".npmrc",
    "content": "enable-pre-post-scripts=true\nstore-dir=.pnpm-store/v10\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n  \"css.customData\": [\".vscode/tailwind.json\"],\n  \"editor.formatOnSave\": false,\n  \"editor.codeActionsOnSave\": {\n    \"source.fixAll.eslint\": \"explicit\",\n    \"source.organizeImports\": \"never\",\n    \"source.fixAll.stylelint\": \"explicit\"\n  },\n  \"eslint.run\": \"onType\",\n  \"eslint.format.enable\": true,\n  \"files.autoSaveDelay\": 500,\n  \"eslint.validate\": [\n    \"javascript\",\n    \"javascriptreact\",\n    \"typescript\",\n    \"typescriptreact\",\n    \"vue\",\n    \"html\",\n    \"markdown\",\n    \"json\",\n    \"jsonc\",\n    \"yaml\",\n    \"toml\",\n    \"gql\",\n    \"graphql\"\n  ],\n  \"javascript.preferences.importModuleSpecifier\": \"project-relative\",\n  \"typescript.suggest.jsdoc.generateReturns\": false,\n  \"typescript.tsserver.experimental.enableProjectDiagnostics\": true,\n  \"typescript.tsdk\": \"node_modules/typescript/lib\"\n}\n"
  },
  {
    "path": ".vscode/tailwind.json",
    "content": "{\n  \"version\": 1.1,\n  \"atDirectives\": [\n    {\n      \"name\": \"@tailwind\",\n      \"description\": \"Use the `@tailwind` directive to insert Tailwind's `base`, `components`, `utilities` and `screens` styles into your CSS.\",\n      \"references\": [\n        {\n          \"name\": \"Tailwind Documentation\",\n          \"url\": \"https://tailwindcss.com/docs/functions-and-directives#tailwind\"\n        }\n      ]\n    },\n    {\n      \"name\": \"@apply\",\n      \"description\": \"Use the `@apply` directive to inline any existing utility classes into your own custom CSS. This is useful when you find a common utility pattern in your HTML that you’d like to extract to a new component.\",\n      \"references\": [\n        {\n          \"name\": \"Tailwind Documentation\",\n          \"url\": \"https://tailwindcss.com/docs/functions-and-directives#apply\"\n        }\n      ]\n    },\n    {\n      \"name\": \"@responsive\",\n      \"description\": \"You can generate responsive variants of your own classes by wrapping their definitions in the `@responsive` directive:\\n```css\\n@responsive {\\n  .alert {\\n    background-color: #E53E3E;\\n  }\\n}\\n```\\n\",\n      \"references\": [\n        {\n          \"name\": \"Tailwind Documentation\",\n          \"url\": \"https://tailwindcss.com/docs/functions-and-directives#responsive\"\n        }\n      ]\n    },\n    {\n      \"name\": \"@screen\",\n      \"description\": \"The `@screen` directive allows you to create media queries that reference your breakpoints by **name** instead of duplicating their values in your own CSS:\\n```css\\n@screen sm {\\n  /* ... */\\n}\\n```\\n…gets transformed into this:\\n```css\\n@media (min-width: 640px) {\\n  /* ... */\\n}\\n```\\n\",\n      \"references\": [\n        {\n          \"name\": \"Tailwind Documentation\",\n          \"url\": \"https://tailwindcss.com/docs/functions-and-directives#screen\"\n        }\n      ]\n    },\n    {\n      \"name\": \"@variants\",\n      \"description\": \"Generate `hover`, `focus`, `active` and other **variants** of your own utilities by wrapping their definitions in the `@variants` directive:\\n```css\\n@variants hover, focus {\\n   .btn-brand {\\n    background-color: #3182CE;\\n  }\\n}\\n```\\n\",\n      \"references\": [\n        {\n          \"name\": \"Tailwind Documentation\",\n          \"url\": \"https://tailwindcss.com/docs/functions-and-directives#variants\"\n        }\n      ]\n    },\n    {\n      \"name\": \"@reference\",\n      \"description\": \"If you want to use @apply or @variant in the <style> block of a Vue or Svelte component, or within CSS modules, you will need to import your theme configuration to make those values available in that context.\",\n      \"references\": [\n        {\n          \"name\": \"Tailwind Documentation\",\n          \"url\": \"https://tailwindcss.com/docs/functions-and-directives#reference-directive\"\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020-PRESENT Wisdom\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README-en.md",
    "content": "<p style=\"text-align:center;\" align=\"center\"><a href=\"https://github.com/pdsuwwz/nextjs-nextra-starter\"><picture align=\"center\">\n  <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://i.stardots.io/wisdom/1745917125609.png\"  width=\"100%\" align=\"center\" style=\"margin-bottom:20px;\">\n  <source media=\"(prefers-color-scheme: light)\" srcset=\"https://i.stardots.io/wisdom/1745917153483.png\" width=\"100%\" align=\"center\" style=\"margin-bottom:20px;\">\n  <img alt=\"color mode\" src=\"https://i.stardots.io/wisdom/1745917153483.png\" width=\"100%\" align=\"center\" style=\"margin-bottom:20px;\">\n</picture></a><br /><br /></p>\n\n# Nextjs Nextra Starter\n\nEnglish | [中文](README.md)\n\n[![Deploy](https://img.shields.io/badge/passing-black?style=flat&logo=Netlify&label=Netlify&color=3bb92c&labelColor=black)](https://github.com/pdsuwwz/nextjs-nextra-starter/deployments)\n[![GitHub Workflow Status (branch)](https://img.shields.io/badge/passing-black?style=flat&label=build&color=3bb92c)](https://github.com/pdsuwwz/nextjs-nextra-starter/deployments/Production)\n[![thanks](https://badgen.net/badge/thanks/♥/pink)](https://github.com/pdsuwwz)\n[![License](https://img.shields.io/github/license/pdsuwwz/nextjs-nextra-starter?color=466fe8)](https://github.com/pdsuwwz/nextjs-nextra-starter/blob/main/LICENSE)\n\n🔥 A Next.js 16 starter for indie developers and small teams: Tailwind CSS 4, React 19, Nextra 4, TypeScript, Shadcn UI, Radix UI, Aceternity UI, Sass, ESLint 9, Iconify, and i18n multilingual support. Built for Blog, Docs, and AI SaaS landing pages with responsive layout, dark mode, login page, and frontend auth examples. Deploy-ready for Vercel and Netlify.\n\n- [🚀 Live Demo](https://nextjs-nextra.netlify.app/en)\n- [🤖 AI Demo Landing Page](https://nextjs-nextra.netlify.app/en/ai-demo)\n- [✨ Alternative address 1](https://nextjs-nextra-starter-green.vercel.app/en)\n- [✨ Alternative address 2](https://nextra.likemashang.com/en)\n\n## 🛠️ Maintenance Commitment\n\n<div align=\"center\">\n\n<table>\n  <tr>\n    <td><strong>🔄 Continuous update</strong><br/>Dependency and features are updated irregularly</td>\n    <td><strong>🐛 Fast Response</strong><br/>Reply within 2 hours on average Issue</td>\n  </tr>\n  <tr>\n    <td><strong>💎 Elaboration</strong><br/>Spend 100+ hours to perfect template details</td>\n    <td><strong>🛡️ Stable and Reliable</strong><br/>Ensure that each function is fully tested</td>\n  </tr>\n</table>\n\n</div>\n\n<div align=\"center\">\n\n<img src=\"https://media.giphy.com/media/a5viI92PAF89q/giphy.gif\" width=\"400\"/>\n\n💝 **If you appreciate this effort, please show your support with a ⭐ Star.**\n\n</div>\n\n## 🚀 What's New\n\n- **Tailwind CSS v4 Upgrade**: Fully upgraded to Tailwind CSS v4, optimizing performance and introducing new features.\n- **Nextra v4 Refactoring**: Upgraded to Nextra v4, enhancing document generation efficiency and development experience.\n\n👉 [Click to view detailed upgrade notes](https://nextjs-nextra.netlify.app/en/upgrade)\n\n## 🎉 Features\n\n- ⚡️ **Next.js 16 + React 19 + TypeScript**: Modern core stack with strong type safety and developer productivity\n- 🎨 **Tailwind CSS v4 + Sass**: Utility-first styling with scalable style organization\n- 📚 **Nextra v4 (content-driven)**: Great fit for docs, knowledge bases, and blogs\n- 🧩 **Shadcn UI + Radix UI + Aceternity UI**: Composable UI system for fast product page building\n- 🌍 **i18n multilingual support**: Built-in structure for localized content and routes\n- 🌙 **Dark mode + responsive design**: Consistent UX across desktop and mobile\n- 🔐 **Login page + frontend auth examples**: Practical auth flow reference for rapid integration\n- 🖼️ **Iconify icon support**: Unified icon strategy with low integration cost\n- 🛠️ **ESLint v9**: Consistent code quality and team-friendly standards\n- 🚀 **Deployment-ready**: Works smoothly with Vercel / Netlify\n\n## 🎯 Use Cases\n\n- Personal blog (Blog Starter Template)\n- Developer docs and product documentation sites\n- AI product websites and conversion-focused SaaS landing pages\n- Personal projects and small team product showcases\n\n## Prerequisites\n\n- React 19.x\n- Node >= 20.x\n- Pnpm 9.x\n- **VS Code plugin `dbaeumer.vscode-eslint` >= v3.0.5 (pre-release)**\n\n## Preview\n\n![image](https://github.com/user-attachments/assets/f732afa6-5fce-4e4d-af1c-acadd1bf50e7)\n\n![image](https://github.com/user-attachments/assets/5cac69dc-601a-41db-a3aa-d75bad6fc4be)\n\n![image](https://github.com/user-attachments/assets/b655981c-7658-4bf4-a118-82cf96cb1d7a)\n\n![image](https://github.com/user-attachments/assets/b69a5f77-2a76-45b3-8468-11bf8fb1de89)\n\n![image](https://github.com/user-attachments/assets/a0a07f3f-a457-4521-a45f-4c0f970044f6)\n\n## Installation and Running\n\n- Install dependencies\n\n```bash\npnpm i\n```\n\n- Local development\n\n```bash\npnpm dev\n```\n\nThen open http://localhost:8000 in your browser to access the service\n\n🎉 **Successfully running?** If you like the clean setup of this template, don’t forget to show some support!\n\n[![Star this repo](https://img.shields.io/badge/⭐-Star%20this%20repo-yellow?style=flat&logo=github)](https://github.com/pdsuwwz/nextjs-nextra-starter)\n\n## Using Shadcn UI Components\n\nThis project has integrated [Shadcn UI](https://ui.shadcn.com). Follow these steps to install/edit components and use them:\n\n### Shadcn Structure Initialization\n\nExecute `pnpm dlx shadcn@latest init` command to initialize the basic project structure for `Shadcn UI` (if not already initialized)\n\n💡 Note\n\n> This initialization command is used to create the basic project structure for `Shadcn UI`\n>\n> **This project has already been initialized, so there's no need to run this command again**\n\n### Component Installation\n\n1. Use `Shadcn CLI` to add components:\n\n   ```bash\n   pnpm dlx shadcn@latest add <component-name>\n   ```\n\n   For example, to add the `<Alert />` component, execute the following command, [see documentation](https://ui.shadcn.com/docs/components/alert#installation)\n\n   ```bash\n   pnpm dlx shadcn@latest add alert\n   ```\n\n2. Using components\n\n```tsx\nimport { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'\n\nexport default function Home() {\n  return (\n    <Alert>\n      <AlertTitle>Heads up!</AlertTitle>\n      <AlertDescription>\n        You can add components and dependencies to your app using the cli.\n      </AlertDescription>\n    </Alert>\n  )\n}\n```\n\n3. Customizing component styles (optional)\n\n`Shadcn UI` components typically provide popular default styles and functionality that meet most needs. If you truly need to customize, you can edit the respective component files, such as:\n\nOpen [`src/components/ui/alert.tsx`](src/components/ui/alert.tsx) to modify the styles of the `Alert` component\n\n> Tips: In most cases, the default styles provided by `Shadcn UI` are sufficient to meet requirements without additional modifications\n\n## 🐱 A Word from the Heart\n\n<div align=\"center\">\n\nIf you've made it this far and still haven't starred the repo, then all I can say is...\n\n<img src=\"https://media.giphy.com/media/l0HlKrB02QY0f1mbm/giphy.gif\" width=\"500\"/>\n\n**Pretty please, drop a ⭐ Star!** 🥺👉👈\n\nRight now, my bug count is still higher than my star count 😭\n\n<a href=\"https://github.com/pdsuwwz/nextjs-nextra-starter\">\n<img src=\"https://img.shields.io/badge/Discovered%20with%20care-Drop%20a%20Star%20%E2%AD%90-orange?style=for-the-badge&logo=github&logoColor=white\" alt=\"Give a Star\"/>\n</a>\n\n</div>\n\n## 🌟 Related Projects\n\nHere are some projects that developers and teams are using, referencing, or inspired by this project:\n\n| Project Name                                                           | Description                                                                                                                       |\n| ---------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |\n| [ClaudeCode101](https://www.claudecode101.com)                         | A Chinese tutorial site for Claude Code, featuring best practices and hands-on guides.                                            |\n| [EdgeOne Saas Starter](https://github.com/TencentEdgeOne/saas-starter) | [The fastest way to create and deploy your SaaS product with EdgeOne and Tencent Cloud](https://saas-starter-docs.edgeone.app/en) |\n| [Talking Web3](https://talkingweb3.io/en)                              | A Web3 project accelerator dedicated to creating outstanding Web3 projects.                                                       |\n| [CodeCrack](https://www.codecrack.cn/en)                               | A free and in-depth interview preparation website helping developers improve their technical skills and prepare for interviews.   |\n\n### 📢 Community Contributions\n\n💡 If your project is also using or referencing this project, we sincerely welcome you to:\n\n- Share your project link by submitting an [Issue](https://github.com/pdsuwwz/nextjs-nextra-starter/issues)\n- Submit a Pull Request (PR) to add your project to the list\n\n## 🚨 Disclaimer\n\nThis template is provided as a technical reference solution. Users must acknowledge the following risks and obligations:\n\n- **Technical Risks**:\n  Dependent frameworks (Next.js/Nextra/Tailwind CSS) carry version iteration risks. Third-party components (e.g. Shadcn UI) follow their original repositories' specifications. Environment configuration changes may cause unforeseen build exceptions\n\n- **Usage Restrictions**:\n  Prohibited for use in scenarios violating open-source licenses or applicable laws/regulations. Users must conduct independent code security audits and production environment validation\n\n- **Liability Exclusion**:\n  No guarantees are provided regarding:\n\n1. Business applicability of technical solutions\n2. Security assurance of dependencies\n3. Official customization support\n\nUsers assume full responsibility for any direct/indirect consequences arising from usage or modifications. Continued use constitutes acceptance of these terms\n\n## License\n\n[MIT](./LICENSE) License | Copyright © 2020-PRESENT [Wisdom](https://github.com/pdsuwwz)\n"
  },
  {
    "path": "README.md",
    "content": "<p style=\"text-align:center;\" align=\"center\"><a href=\"https://github.com/pdsuwwz/nextjs-nextra-starter\"><picture align=\"center\">\n  <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://i.stardots.io/wisdom/1745917125609.png\"  width=\"100%\" align=\"center\" style=\"margin-bottom:20px;\">\n  <source media=\"(prefers-color-scheme: light)\" srcset=\"https://i.stardots.io/wisdom/1745917153483.png\" width=\"100%\" align=\"center\" style=\"margin-bottom:20px;\">\n  <img alt=\"color mode\" src=\"https://i.stardots.io/wisdom/1745917153483.png\" width=\"100%\" align=\"center\" style=\"margin-bottom:20px;\">\n</picture></a><br /><br /></p>\n\n# Nextjs Nextra Starter\n\n中文 | [English](README-en.md)\n\n[![Deploy](https://img.shields.io/badge/passing-black?style=flat&logo=Netlify&label=Netlify&color=3bb92c&labelColor=black)](https://github.com/pdsuwwz/nextjs-nextra-starter/deployments)\n[![GitHub Workflow Status (branch)](https://img.shields.io/badge/passing-black?style=flat&label=build&color=3bb92c)](https://github.com/pdsuwwz/nextjs-nextra-starter/deployments/Production)\n[![thanks](https://badgen.net/badge/thanks/♥/pink)](https://github.com/pdsuwwz)\n[![License](https://img.shields.io/github/license/pdsuwwz/nextjs-nextra-starter?color=466fe8)](https://github.com/pdsuwwz/nextjs-nextra-starter/blob/main/LICENSE)\n\n🔥 面向独立开发者与小团队的 Next.js 16 启动模板：集成 Tailwind CSS 4、React 19、Nextra 4、TypeScript、Shadcn UI、Radix UI、Aceternity UI、Sass、ESLint 9、Iconify 与 i18n 多语言。覆盖 Blog、Docs、AI SaaS Landing Page 等核心场景，支持响应式布局、暗黑模式、登录页与前端鉴权示例，兼顾快速起步与长期可维护性，支持 Vercel / Netlify 部署。\n\n- [🚀 Live Demo 在线体验](https://nextjs-nextra.netlify.app/zh)\n- [🤖 AI Demo 落地页](https://nextjs-nextra.netlify.app/zh/ai-demo)\n- [✨ 备用地址1](https://nextjs-nextra-starter-green.vercel.app/zh)\n- [✨ 备用地址2](https://nextra.likemashang.com/zh)\n\n## 🛠️ 项目维护承诺\n\n<div align=\"center\">\n\n<table>\n  <tr>\n    <td><strong>🔄 持续更新</strong><br/>不定期更新依赖和功能</td>\n    <td><strong>🐛 快速响应</strong><br/>平均 2 小时内回复 Issue</td>\n  </tr>\n  <tr>\n    <td><strong>💎 精心打磨</strong><br/>花费 100+ 小时完善模板细节</td>\n    <td><strong>🛡️ 稳定可靠</strong><br/>确保每个功能都充分测试</td>\n  </tr>\n</table>\n\n</div>\n\n<div align=\"center\">\n\n<img src=\"https://media.giphy.com/media/a5viI92PAF89q/giphy.gif\" width=\"400\"/>\n\n💝 **如果你感受到了这份用心，请用 Star ⭐ 给予支持**\n\n</div>\n\n## 🚀 更新说明\n\n- **Tailwind CSS v4 升级**：全面升级至 Tailwind CSS v4，优化性能并引入新特性。\n- **Nextra v4 重构**：升级至 Nextra v4，提升文档生成效率和开发体验。\n\n👉 [点击查看详细升级说明](https://nextjs-nextra.netlify.app/zh/upgrade)\n\n## 🎉 Features\n\n- ⚡️ **Next.js 16 + React 19 + TypeScript**：现代前端核心栈，类型安全与开发效率兼顾\n- 🎨 **Tailwind CSS v4 + Sass**：支持原子化样式与工程化样式组织，快速构建响应式 UI\n- 📚 **Nextra v4（内容驱动）**：适合文档站、知识库、博客等内容型项目\n- 🧩 **Shadcn UI + Radix UI + Aceternity UI**：可组合、可扩展的组件体系，便于快速搭建产品页面\n- 🌍 **i18n 多语言国际化**：中英文内容组织与路由支持，适配多语言产品站点\n- 🌙 **暗黑模式 + 响应式设计**：覆盖桌面端与移动端体验，支持主题切换\n- 🔐 **登录页与前端鉴权示例**：提供基础鉴权流程参考，便于业务快速接入\n- 🖼️ **Iconify 图标集支持**：统一图标方案，降低图标接入成本\n- 🛠️ **ESLint v9 规范化**：统一代码风格与质量约束，适合团队协作\n- 🚀 **部署友好**：开箱支持 Vercel / Netlify 部署\n\n## 🎯 适用场景\n\n- 个人博客（Blog Starter Template）\n- 技术文档与产品文档站（Docs Site）\n- AI 产品官网与营销落地页（AI SaaS Landing Page）\n- 个人项目主页与小团队产品展示站\n\n## 前置条件\n\n- React 19.x\n- Node >= 20.x\n- Pnpm 9.x\n- **VS Code 插件 `dbaeumer.vscode-eslint` >= v3.0.5 (pre-release)**\n\n## 运行效果\n\n![image](https://github.com/user-attachments/assets/f732afa6-5fce-4e4d-af1c-acadd1bf50e7)\n\n![image](https://github.com/user-attachments/assets/5cac69dc-601a-41db-a3aa-d75bad6fc4be)\n\n![image](https://github.com/user-attachments/assets/b655981c-7658-4bf4-a118-82cf96cb1d7a)\n\n![image](https://github.com/user-attachments/assets/b69a5f77-2a76-45b3-8468-11bf8fb1de89)\n\n![image](https://github.com/user-attachments/assets/a0a07f3f-a457-4521-a45f-4c0f970044f6)\n\n## 安装和运行\n\n- 安装依赖\n\n```bash\npnpm i\n```\n\n- 本地开发\n\n```bash\npnpm dev\n```\n\n接着用浏览器打开 http://localhost:8000 即可访问服务\n\n🎉 **成功运行了？** 如果你喜欢这个模板的简洁配置，别忘了鼓励一下：\n\n[![Star this repo](https://img.shields.io/badge/⭐-Star%20this%20repo-yellow?style=flat&logo=github)](https://github.com/pdsuwwz/nextjs-nextra-starter)\n\n## 使用 Shadcn UI 组件\n\n本项目已集成 [Shadcn UI](https://ui.shadcn.com), 按照以下步骤安装/编辑组件并使用:\n\n### Shadcn 结构初始化\n\n首次执行 `pnpm dlx shadcn@latest init` 命令初始化 `Shadcn UI` 基本项目结构（如果尚未初始化）\n\n> [!IMPORTANT]\n\n> 该初始化命令用于创建 `Shadcn UI` 的基本项目结构\n>\n> **本项目已完成初始化，无需再次运行此命令**\n\n### 组件安装\n\n1. 使用 `Shadcn CLI` 添加组件:\n\n   ```bash\n   pnpm dlx shadcn@latest add <组件名>\n   ```\n\n   如添加 `<Alert />` 组件，执行以下命令即可，[详见文档](https://ui.shadcn.com/docs/components/alert#installation)\n\n   ```bash\n   pnpm dlx shadcn@latest add alert\n   ```\n\n2. 使用组件\n\n```tsx\nimport { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'\n\nexport default function Home() {\n  return (\n    <Alert>\n      <AlertTitle>Heads up!</AlertTitle>\n      <AlertDescription>\n        You can add components and dependencies to your app using the cli.\n      </AlertDescription>\n    </Alert>\n  )\n}\n```\n\n3. 自定义组件样式（可选）\n\n`Shadcn UI` 组件通常已提供了流行的默认样式和功能，能满足大多数需求，若确实需要进行自定义定制，可编辑相应的组件文件，如：\n\n打开 [`src/components/ui/alert.tsx`](src/components/ui/alert.tsx) 文件来修改 `Alert` 组件的样式\n\n> 注意：在大多数情况下，`Shadcn UI` 提供的默认样式已经足够满足需求，无需进行额外修改\n\n## 🐱 说句心里话\n\n<div align=\"center\">\n\n如果你看到这里还没有点 Star, 那我只能说...\n\n<img src=\"https://media.giphy.com/media/l0HlKrB02QY0f1mbm/giphy.gif\" width=\"500\"/>\n\n**求求了，给个 Star 吧！** 🥺👉👈\n\n我的 Star 数量还不如我的 Bug 数量多 😭\n\n<a href=\"https://github.com/pdsuwwz/nextjs-nextra-starter\">\n<img src=\"https://img.shields.io/badge/%E8%89%AF%E5%BF%83%E5%8F%91%E7%8E%B0-%E8%B5%8F%E4%B8%AAStar%20%E2%AD%90%EF%B8%8F%EF%B8%8F-orange?style=for-the-badge&logo=github&logoColor=white\" alt=\"给个Star\"/>\n</a>\n\n</div>\n\n## 🌟 相关项目\n\n以下是一些开发者和团队正在使用、参考或受本项目启发的项目：\n\n| 项目名                                                              | 简介                                                                                                   |\n| ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |\n| [ClaudeCode101 中文教程](https://www.claudecode101.com/zh)          | 面向中文用户的 Claude Code AI 编程助手教程网站，汇集官方最佳实践与社区经验，助你高效掌握 AI 编程技能。 |\n| [EdgeOne Saas 模板](https://github.com/TencentEdgeOne/saas-starter) | [腾讯云官方模板：助你快速构建并部署下一款 SaaS 应用](https://saas-starter-docs.edgeone.app/zh)         |\n| [Talking Web3](https://talkingweb3.io/zh)                           | 一个 Web3 项目出圈加速器，致力于打造卓越的Web3项目。                                                   |\n| [面试宝典](https://www.codecrack.cn/zh)                             | 一个免费且深入的八股文网站，帮助开发者提升技术能力并应对面试。                                         |\n\n### 📢 社区贡献\n\n💡 如果您的项目也在使用或借鉴了本项目，我们诚挚欢迎您：\n\n- 通过提交 [Issue](https://github.com/pdsuwwz/nextjs-nextra-starter/issues) 分享您的项目链接\n- 提交 Pull Request (PR) 将您的项目添加到列表中\n\n## 🚨 免责声明\n\n本模板作为技术方案参考提供，使用者需知悉以下风险及义务：\n\n- **技术风险**：依赖框架（Next.js/Nextra/Tailwind CSS等）存在版本迭代风险，第三方组件（如 Shadcn UI）的行为规范以原始仓库为准，环境配置变更可能导致不可预见的构建异常\n- **使用限制**：禁止用于违反开源协议或法律法规的场景，使用者需自行完成代码安全审查及生产环境验证\n- **责任免除**：不承诺技术方案的业务适用性、安全性担保及定制支持，因使用/修改引发的直接或间接后果均由使用者自行承担\n\n## License\n\n[MIT](./LICENSE) License | Copyright © 2020-PRESENT [Wisdom](https://github.com/pdsuwwz)\n"
  },
  {
    "path": "components.json",
    "content": "{\n  \"$schema\": \"https://ui.shadcn.com/schema.json\",\n  \"style\": \"new-york\",\n  \"rsc\": true,\n  \"tsx\": true,\n  \"tailwind\": {\n    \"config\": \"\",\n    \"css\": \"src/app/[lang]/styles/index.css\",\n    \"baseColor\": \"neutral\",\n    \"cssVariables\": true,\n    \"prefix\": \"\"\n  },\n  \"iconLibrary\": \"lucide\",\n  \"aliases\": {\n    \"components\": \"@/components\",\n    \"utils\": \"@/lib/utils\",\n    \"ui\": \"@/components/ui\",\n    \"lib\": \"@/lib\",\n    \"hooks\": \"@/hooks\"\n  },\n  \"registries\": {\n    \"@aceternity\": \"https://ui.aceternity.com/registry/{name}.json\"\n  }\n}\n"
  },
  {
    "path": "eslint.config.js",
    "content": "import antfu from '@antfu/eslint-config'\n\nconst OFF = 0\nconst WARN = 1\nconst ERROR = 2\n\nexport default antfu({\n  ignores: [\n    'public',\n    'build',\n    'dist',\n    'node_modules',\n    'coverage',\n    'src/assets/**',\n  ],\n  stylistic: {\n    indent: 2,\n    quotes: 'single',\n    overrides: {\n      'antfu/top-level-function': 'off',\n      'style/arrow-parens': 'off',\n      curly: 'off',\n    },\n  },\n  jsonc: true,\n  formatters: {\n    markdown: true,\n  },\n  typescript: true,\n  react: true,\n  markdown: true,\n  extends: [\n    'next/core-web-vitals',\n  ],\n  rules: {\n    'antfu/top-level-function': OFF,\n    'react-dom/no-unsafe-target-blank': OFF,\n    'react-dom/no-missing-button-type': OFF,\n    'react-hooks/exhaustive-deps': WARN,\n    'react/no-useless-fragment': OFF,\n    'react/no-array-index-key': OFF,\n    'react-hooks/rules-of-hooks': OFF,\n    'react/no-comment-textnodes': OFF,\n    'react-refresh/only-export-components': OFF,\n    'react-hooks-extra/no-unnecessary-use-prefix': OFF,\n    'react-hooks-extra/prefer-use-state-lazy-initialization': OFF,\n    'react-dom/no-dangerously-set-innerhtml': OFF,\n\n    'unused-imports/no-unused-vars': WARN,\n    curly: [ERROR, 'multi-line', 'consistent'],\n\n    'no-multiple-empty-lines': [\n      ERROR,\n      {\n        max: 3,\n      },\n    ],\n    'no-console': WARN,\n\n    'style/jsx-self-closing-comp': [ERROR, {\n      component: true,\n      html: false,\n    }],\n    'style/no-multiple-empty-lines': [ERROR, {\n      max: 2,\n      maxEOF: 0,\n    }],\n    'style/max-statements-per-line': ERROR,\n    'style/quote-props': [ERROR, 'as-needed'],\n\n    'ts/no-use-before-define': OFF,\n    'ts/ban-ts-comment': OFF,\n  },\n})\n"
  },
  {
    "path": "next-env.d.ts",
    "content": "/// <reference types=\"next\" />\n/// <reference types=\"next/image-types/global\" />\nimport \"./.next/types/routes.d.ts\";\n\n// NOTE: This file should not be edited\n// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.\n"
  },
  {
    "path": "next-sitemap.config.mjs",
    "content": "/** @type {import('next-sitemap').IConfig} */\nexport default {\n  siteUrl: process.env.SITE_URL || 'https://example.com',\n  generateRobotsTxt: true,\n}\n"
  },
  {
    "path": "next.config.ts",
    "content": "import createWithNextra from 'nextra'\n\nconst withNextra = createWithNextra({\n  defaultShowCopyCode: true,\n  unstable_shouldAddLocaleToLinks: true,\n})\n\n\n/**\n * @type {import(\"next\").NextConfig}\n */\nexport default withNextra({\n  images: {\n    unoptimized: true,\n  },\n  reactStrictMode: true,\n  cleanDistDir: true,\n  i18n: {\n    locales: ['zh', 'en'],\n    defaultLocale: 'zh',\n  },\n  sassOptions: {\n    silenceDeprecations: ['legacy-js-api'],\n  },\n})\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"nextjs-nextra-starter\",\n  \"type\": \"module\",\n  \"version\": \"0.0.1\",\n  \"description\": \"Next.js Nextra (v4) Tailwind CSS (v4) docs starter\",\n  \"author\": \"Wisdom <pdsu.wwz@foxmail.com>\",\n  \"license\": \"MIT\",\n  \"homepage\": \"https://github.com/pdsuwwz/nextjs-nextra-starter#readme\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/pdsuwwz/nextjs-nextra-starter.git\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/pdsuwwz/nextjs-nextra-starter/issues\"\n  },\n  \"engines\": {\n    \"node\": \">=20.x\",\n    \"pnpm\": \">=9.x\"\n  },\n  \"scripts\": {\n    \"dev\": \"next dev --turbopack -p 8000\",\n    \"build\": \"next build\",\n    \"postbuild\": \"next-sitemap --config next-sitemap.config.mjs && pagefind --site .next/server/app --output-path public/_pagefind\",\n    \"start\": \"next start -p 7000\",\n    \"lint\": \"eslint --fix .\"\n  },\n  \"dependencies\": {\n    \"@emotion/react\": \"^11.14.0\",\n    \"@emotion/styled\": \"^11.14.1\",\n    \"@radix-ui/react-accordion\": \"^1.2.12\",\n    \"@radix-ui/react-hover-card\": \"^1.1.15\",\n    \"@radix-ui/react-separator\": \"^1.1.8\",\n    \"@radix-ui/react-slot\": \"^1.2.4\",\n    \"@radix-ui/react-toggle\": \"^1.1.10\",\n    \"@tsparticles/engine\": \"^3.9.1\",\n    \"@tsparticles/react\": \"^3.0.0\",\n    \"class-variance-authority\": \"^0.7.1\",\n    \"clsx\": \"^2.1.1\",\n    \"framer-motion\": \"^12.38.0\",\n    \"lucide-react\": \"^1.8.0\",\n    \"motion\": \"^12.38.0\",\n    \"next\": \"16.2.4\",\n    \"next-sitemap\": \"^4.2.3\",\n    \"next-themes\": \"^0.4.6\",\n    \"nextra\": \"^4.6.1\",\n    \"nextra-theme-docs\": \"4.6.1\",\n    \"qss\": \"^3.0.0\",\n    \"radix-ui\": \"^1.4.3\",\n    \"react\": \"^19.2.5\",\n    \"react-dom\": \"^19.2.5\",\n    \"react-fast-marquee\": \"^1.6.5\",\n    \"sonner\": \"^2.0.7\",\n    \"tailwind-merge\": \"^3.5.0\",\n    \"tailwindcss-animate\": \"^1.0.7\",\n    \"tsparticles\": \"^3.9.1\"\n  },\n  \"devDependencies\": {\n    \"@antfu/eslint-config\": \"^8.2.0\",\n    \"@eslint-react/eslint-plugin\": \"^3.0.0\",\n    \"@eslint/compat\": \"^2.0.5\",\n    \"@iconify/json\": \"^2.2.464\",\n    \"@iconify/tailwind4\": \"^1.2.3\",\n    \"@next/third-parties\": \"16.2.4\",\n    \"@svgr/core\": \"^8.1.0\",\n    \"@svgr/plugin-jsx\": \"^8.1.0\",\n    \"@svgr/plugin-svgo\": \"^8.1.0\",\n    \"@svgr/webpack\": \"^8.1.0\",\n    \"@tailwindcss/postcss\": \"^4.2.3\",\n    \"@tailwindcss/typography\": \"^0.5.19\",\n    \"@types/node\": \"^25.6.0\",\n    \"@types/react\": \"^19.2.14\",\n    \"@types/react-dom\": \"^19.2.3\",\n    \"eslint\": \"^10.2.1\",\n    \"eslint-config-next\": \"16.2.4\",\n    \"eslint-plugin-format\": \"^2.0.1\",\n    \"eslint-plugin-react\": \"^7.37.5\",\n    \"eslint-plugin-react-hooks\": \"7.1.1\",\n    \"eslint-plugin-react-refresh\": \"^0.5.2\",\n    \"pagefind\": \"^1.5.2\",\n    \"postcss\": \"^8.5.10\",\n    \"react-responsive\": \"^10.0.1\",\n    \"sass\": \"^1.99.0\",\n    \"tailwindcss\": \"^4.2.3\",\n    \"typescript\": \"^5.9.3\"\n  }\n}\n"
  },
  {
    "path": "postcss.config.mjs",
    "content": "/** @type {import('postcss').Postcss} */\nconst config = {\n  plugins: {\n    '@tailwindcss/postcss': {},\n  },\n}\n\nexport default config\n"
  },
  {
    "path": "src/app/[lang]/[[...mdxPath]]/page.tsx",
    "content": "import { generateStaticParamsFor, importPage } from 'nextra/pages'\nimport { useMDXComponents } from '@/mdx-components'\n\nexport const generateStaticParams = generateStaticParamsFor('mdxPath')\n\nexport async function generateMetadata(props: PageProps) {\n  const params = await props.params\n  const { metadata } = await importPage(params.mdxPath, params.lang)\n  return metadata\n}\n\ntype PageProps = Readonly<{\n  params: Promise<{\n    mdxPath: string[]\n    lang: string\n  }>\n}>\nconst Wrapper = useMDXComponents().wrapper\n\nexport default async function Page(props: PageProps) {\n  const params = await props.params\n  const result = await importPage(params.mdxPath, params.lang)\n  const { default: MDXContent, toc, metadata, sourceCode } = result\n\n\n  return (\n    <Wrapper toc={toc} metadata={metadata} sourceCode={sourceCode}>\n      <MDXContent {...props} params={params} />\n    </Wrapper>\n  )\n}\n"
  },
  {
    "path": "src/app/[lang]/_components/ThemeProvider.tsx",
    "content": "'use client'\n\nimport { ThemeProvider as NextThemesProvider } from 'next-themes'\nimport * as React from 'react'\n\nexport function ThemeProvider({\n  children,\n  ...props\n}: React.ComponentProps<typeof NextThemesProvider>) {\n  return <NextThemesProvider {...props}>{children}</NextThemesProvider>\n}\n"
  },
  {
    "path": "src/app/[lang]/_components/ThirdPartyScripts.tsx",
    "content": "'use client'\n\nimport { useEffect } from 'react'\n\nconst GA_ID = 'G-VCR6017LB8'\nconst BAIDU_SRC = 'https://hm.baidu.com/hm.js?d5ad5e04e6af914c01767926567602be'\n\nexport default function ThirdPartyScripts() {\n  useEffect(() => {\n    if (typeof window === 'undefined') {\n      return\n    }\n\n    if (!document.querySelector(`script[src*=\"${GA_ID}\"]`)) {\n      const gtagScript = document.createElement('script')\n      gtagScript.async = true\n      gtagScript.src = `https://www.googletagmanager.com/gtag/js?id=${GA_ID}`\n      document.head.appendChild(gtagScript)\n\n      const inline = document.createElement('script')\n      inline.text = `\n        window.dataLayer = window.dataLayer || [];\n        function gtag(){window.dataLayer.push(arguments);}\n        gtag('js', new Date());\n        gtag('config', '${GA_ID}');\n      `\n      document.head.appendChild(inline)\n    }\n\n    if (!document.querySelector(`script[src=\"${BAIDU_SRC}\"]`)) {\n      const hmScript = document.createElement('script')\n      hmScript.src = BAIDU_SRC\n      document.head.appendChild(hmScript)\n    }\n  }, [])\n\n  return null\n}\n"
  },
  {
    "path": "src/app/[lang]/layout.tsx",
    "content": "import type { Metadata } from 'next'\n\n\nimport type { I18nLangAsyncProps, I18nLangKeys } from '@/i18n'\nimport ThirdPartyScripts from './_components/ThirdPartyScripts'\nimport { Footer, LastUpdated, Layout, Navbar } from 'nextra-theme-docs'\nimport { Banner, Head, Search } from 'nextra/components'\nimport { getPageMap } from 'nextra/page-map'\nimport { CustomFooter } from '@/components/CustomFooter'\nimport { Toaster } from '@/components/ui/sonner'\nimport { useServerLocale } from '@/hooks'\nimport NavbarExtras from '@/widgets/navbar-extras'\n\nimport { getDictionary, getDirection } from '../_dictionaries/get-dictionary'\nimport './styles/index.css'\n\nexport const metadata = {\n  // Define your metadata here\n  // For more information on metadata API, see: https://nextjs.org/docs/app/building-your-application/optimizing/metadata\n  metadataBase: new URL('https://nextjs-nextra-starter-green.vercel.app'),\n  icons: '/img/favicon.svg',\n} satisfies Metadata\n\nconst repo = 'https://github.com/pdsuwwz/nextjs-nextra-starter'\n\nconst CustomBanner = async ({ lang }: I18nLangAsyncProps) => {\n  const { t } = await useServerLocale(lang)\n  return (\n    <Banner\n      storageKey=\"starter-banner\"\n    >\n      <div className=\"flex justify-center items-center gap-1\">\n        { t('banner.title') }\n        {' '}\n        <a\n          className=\"max-sm:hidden text-warning hover:underline\"\n          target=\"_blank\"\n          href={repo}\n        >\n          { t('banner.more') }\n        </a>\n      </div>\n    </Banner>\n  )\n}\n\n\nconst CustomNavbar = async ({ lang }: I18nLangAsyncProps) => {\n  const { t } = await useServerLocale(lang)\n  return (\n    <Navbar\n      logo={(\n        <span>{ t('systemTitle') }</span>\n      )}\n      logoLink={`/${lang}`}\n      projectLink={repo}\n    >\n      <NavbarExtras />\n\n    </Navbar>\n  )\n}\n\nconst BaiduTrack = () => null\n\n\n// interface Props {\n//   children: ReactNode\n//   params: Promise<{ lang: I18nLangKeys }>\n// }\n\nexport default async function RootLayout({ children, params }: LayoutProps<'/[lang]'>) {\n  const getterParams = await params\n\n  const { lang } = getterParams as { lang: I18nLangKeys }\n\n  const dictionary = await getDictionary(lang)\n  const pageMap = await getPageMap(lang)\n\n  const title = 'My Nextra Starter'\n  const description = 'A Starter template with Next.js, Nextra'\n\n  const { t } = await useServerLocale(lang)\n\n  return (\n    <html\n      // Not required, but good for SEO\n      lang={lang}\n      // Required to be set\n      // dir=\"ltr\"\n      // Suggested by `next-themes` package https://github.com/pacocoursey/next-themes#with-app\n      dir={getDirection(lang)}\n      suppressHydrationWarning\n    >\n      <Head\n      // ... Your additional head options\n      >\n        {/* <title>{asPath !== '/' ? `${normalizePagesResult.title} - ${title}` : title}</title> */}\n        <meta property=\"og:title\" content={title} />\n        <meta name=\"description\" content={description} />\n        <meta property=\"og:description\" content={description} />\n        <link rel=\"canonical\" href={repo} />\n      </Head>\n      <body>\n        <Layout\n          copyPageButton={false}\n          banner={\n            <CustomBanner lang={lang} />\n          }\n          navbar={\n            <CustomNavbar lang={lang} />\n          }\n          lastUpdated={(\n            <LastUpdated>\n              { t('lastUpdated') }\n            </LastUpdated>\n          )}\n          editLink={null}\n          docsRepositoryBase=\"https://github.com/pdsuwwz/nextjs-nextra-starter\"\n          footer={(\n            <Footer className=\"bg-background py-5!\">\n              <CustomFooter />\n            </Footer>\n          )}\n          search={(\n            <Search\n              placeholder={t('search.placeholder')}\n              emptyResult={t('search.noResults')}\n              errorText={t('search.errorText')}\n              loading={t('search.loading')}\n            />\n          )}\n          i18n={[\n            { locale: 'en', name: 'English' },\n            { locale: 'zh', name: '简体中文' },\n          ]}\n          toc={{\n            backToTop: t('backToTop'),\n            title: t('pageTitle'),\n          }}\n          pageMap={pageMap}\n          feedback={{ content: '' }}\n          nextThemes={{\n            attribute: 'class',\n            defaultTheme: 'system',\n            storageKey: 'starter-theme-provider',\n            disableTransitionOnChange: true,\n          }}\n        // ... Your additional layout options\n        >\n          {children}\n        </Layout>\n        <Toaster position=\"top-center\" />\n        <ThirdPartyScripts />\n      </body>\n      <BaiduTrack />\n    </html>\n  )\n}\n"
  },
  {
    "path": "src/app/[lang]/not-found.ts",
    "content": "export { NotFoundPage as default } from 'nextra-theme-docs'\n"
  },
  {
    "path": "src/app/[lang]/styles/index.css",
    "content": "@import 'tailwindcss';\n@import 'nextra-theme-docs/style.css';\n\n@plugin 'tailwindcss-animate';\n@plugin \"@iconify/tailwind4\";\n@plugin '@tailwindcss/typography';\n\n@custom-variant dark (&:where(.dark, .dark *));\n\n@theme {\n  --color-warning: hsl(var(--warning));\n  --color-border: hsl(var(--border));\n  --color-input: hsl(var(--input));\n  --color-ring: hsl(var(--ring));\n  --color-background: hsl(var(--background));\n  --color-foreground: hsl(var(--foreground));\n\n  --color-primary: hsl(var(--primary));\n  --color-primary-foreground: hsl(var(--primary-foreground));\n\n  --color-secondary: hsl(var(--secondary));\n  --color-secondary-foreground: hsl(var(--secondary-foreground));\n\n  --color-destructive: hsl(var(--destructive));\n  --color-destructive-foreground: hsl(var(--destructive-foreground));\n\n  --color-muted: hsl(var(--muted));\n  --color-muted-foreground: hsl(var(--muted-foreground));\n\n  --color-accent: hsl(var(--accent));\n  --color-accent-foreground: hsl(var(--accent-foreground));\n\n  --color-popover: hsl(var(--popover));\n  --color-popover-foreground: hsl(var(--popover-foreground));\n\n  --color-card: hsl(var(--card));\n  --color-card-foreground: hsl(var(--card-foreground));\n\n  --radius-lg: calc(var(--radius) + 2px);\n  --radius-md: calc(var(--radius));\n  --radius-sm: calc(var(--radius) - 2px);\n\n  --animate-accordion-down: accordion-down 0.2s ease-out;\n  --animate-accordion-up: accordion-up 0.2s ease-out;\n\n  @keyframes accordion-down {\n    from {\n      height: 0;\n    }\n    to {\n      height: var(--radix-accordion-content-height);\n    }\n  }\n  @keyframes accordion-up {\n    from {\n      height: var(--radix-accordion-content-height);\n    }\n    to {\n      height: 0;\n    }\n  }\n}\n\n@utility container {\n  margin-inline: auto;\n  padding-inline: 2rem;\n  @media (width >= --theme(--breakpoint-sm)) {\n    max-width: none;\n  }\n  @media (width >= 1400px) {\n    max-width: 1400px;\n  }\n}\n\n@theme inline {\n  --color-background: var(--background);\n  --color-foreground: var(--foreground);\n  --color-card: var(--card);\n  --color-card-foreground: var(--card-foreground);\n  --color-warning: var(--warning);\n  --color-popover: var(--popover);\n  --color-popover-foreground: var(--popover-foreground);\n  --color-primary: var(--primary);\n  --color-primary-foreground: var(--primary-foreground);\n  --color-secondary: var(--secondary);\n  --color-secondary-foreground: var(--secondary-foreground);\n  --color-muted: var(--muted);\n  --color-muted-foreground: var(--muted-foreground);\n  --color-accent: var(--accent);\n  --color-accent-foreground: var(--accent-foreground);\n  --color-destructive: var(--destructive);\n  --color-destructive-foreground: var(--destructive-foreground);\n  --color-border: var(--border);\n  --color-input: var(--input);\n  --color-ring: var(--ring);\n  --color-chart-1: var(--chart-1);\n  --color-chart-2: var(--chart-2);\n  --color-chart-3: var(--chart-3);\n  --color-chart-4: var(--chart-4);\n  --color-chart-5: var(--chart-5);\n  --radius-sm: calc(var(--radius) - 4px);\n  --radius-md: calc(var(--radius) - 2px);\n  --radius-lg: var(--radius);\n  --radius-xl: calc(var(--radius) + 4px);\n}\n\n/*\n  The default border color has changed to `currentColor` in Tailwind CSS v4,\n  so we've added these compatibility styles to make sure everything still\n  looks the same as it did with Tailwind CSS v3.\n\n  If we ever want to remove these styles, we need to add an explicit border\n  color utility to any element that depends on these defaults.\n*/\n@layer base {\n  *,\n  ::after,\n  ::before,\n  ::backdrop,\n  ::file-selector-button {\n    border-color: var(--color-gray-200, currentColor);\n  }\n}\n\n@reference \"./overrides.css\";\n\n.x\\:bg-gray-100 {\n  @apply bg-background;\n}\n.nextra-sidebar-footer,\n.nextra-navbar-blur {\n  @apply bg-background;\n}\n.nextra-mobile-nav .nextra-sidebar-footer {\n  @apply mx-0 px-4;\n}\n\n@keyframes heartbeat {\n  0%,100% {\n    transform: scale(.75)\n  }\n  20% {\n    transform: scale(1)\n  }\n  40% {\n    transform: scale(.75)\n  }\n  60% {\n    transform: scale(1)\n  }\n  80% {\n    transform: scale(.75)\n  }\n}\n\n/*\n  ---break---\n*/\n:root {\n  --warning: hsl(38.21 94.06% 60.39%);\n  --background: hsl(0 0% 100%);\n  --foreground: hsl(0 0% 3.9%);\n  --card: hsl(0 0% 100%);\n  --card-foreground: hsl(0 0% 3.9%);\n  --popover: hsl(0 0% 100%);\n  --popover-foreground: hsl(0 0% 3.9%);\n  --primary: hsl(221.2, 83.2%, 53.3%);\n  --primary-foreground: hsl(0 0% 98%);\n  --secondary: hsl(210, 40%, 96.1%);\n  --secondary-foreground: hsl(222.2, 47.4%, 11.2%);\n  --muted: hsl(0 0% 96.1%);\n  --muted-foreground: hsl(215.4, 16.3%, 46.9%);\n  --accent: hsl(0 0% 96.1%);\n  --accent-foreground: hsl(222.2, 47.4%, 11.2%);\n  --destructive: hsl(0 84.2% 60.2%);\n  --destructive-foreground: hsl(0 0% 98%);\n  --border: hsl(0 0% 89.8%);\n  --input: hsl(0 0% 89.8%);\n  --ring: hsl(221.2, 83.2%, 53.3%);\n  --chart-1: hsl(12 76% 61%);\n  --chart-2: hsl(173 58% 39%);\n  --chart-3: hsl(197 37% 24%);\n  --chart-4: hsl(43 74% 66%);\n  --chart-5: hsl(27 87% 67%);\n  --radius: 0.6rem;\n}\n/*\n  ---break---\n*/\n.dark {\n  --background: hsl(0 0% 3.9%);\n  --foreground: hsl(0 0% 98%);\n  --card: hsl(0 0% 3.9%);\n  --card-foreground: hsl(0 0% 98%);\n  --popover: hsl(0 0% 3.9%);\n  --popover-foreground: hsl(0 0% 98%);\n  --primary: hsl(217.2, 91.2%, 59.8%);\n  --primary-foreground: hsl(222.2, 47.4%, 11.2%);\n  --secondary: hsl(217.2, 32.6%, 17.5%);\n  --secondary-foreground: hsl(210, 40%, 98%);\n  --muted: hsl(217.2, 32.6%, 17.5%);\n  --muted-foreground: hsl(215, 20.2%, 65.1%);\n  --accent: hsl(0 0% 14.9%);\n  --accent-foreground: hsl(0 0% 98%);\n  --destructive: hsl(0 62.8% 30.6%);\n  --destructive-foreground: hsl(0 0% 98%);\n  --border: hsl(0 0% 14.9%);\n  --input: hsl(0 0% 14.9%);\n  --ring: hsl(0 0% 83.1%);\n  --chart-1: hsl(220 70% 50%);\n  --chart-2: hsl(160 60% 45%);\n  --chart-3: hsl(30 80% 55%);\n  --chart-4: hsl(280 65% 60%);\n  --chart-5: hsl(340 75% 55%);\n}\n/*\n  ---break---\n*/\n@layer base {\n  * {\n    @apply border-border outline-ring/50;\n  }\n  body {\n    @apply bg-background text-foreground;\n  }\n}\n\n@layer base {\n  button:not(:disabled),\n  [role=\"button\"]:not(:disabled) {\n    cursor: pointer;\n  }\n}\n"
  },
  {
    "path": "src/app/[lang]/styles/overrides.css",
    "content": "body {\n  font-family: 'sans-serif', 'Arial', 'Microsoft Yahei';\n  text-rendering: optimizeLegibility;\n  overflow-x: hidden;\n}\na,\nsummary,\nbutton,\ninput,\n[tabindex]:not([tabindex='-1']) {\n  &:focus-visible {\n    box-shadow: none;\n  }\n}\n\n.button-switch {\n  @apply max-md:hidden;\n  svg {\n    @apply size-[14px];\n  }\n}\n"
  },
  {
    "path": "src/app/_dictionaries/get-dictionary.ts",
    "content": "import type Zh from '@/i18n/zh'\nimport 'server-only'\n\n// We enumerate all dictionaries here for better linting and TypeScript support\n// We also get the default import for cleaner types\nconst dictionaries = {\n  en: () => import('@/i18n/en'),\n  zh: () => import('@/i18n/zh'),\n} as const satisfies Record<string, () => Promise<{ default: typeof Zh }>>\n\nexport const getDictionary = async (\n  locale: keyof typeof dictionaries,\n): Promise<typeof Zh> => (await dictionaries[locale]()).default\n\nexport const getDirection = (locale: keyof typeof dictionaries) => {\n  switch (locale) {\n    case 'en':\n    case 'zh':\n    default:\n      return 'ltr' as const\n  }\n}\n"
  },
  {
    "path": "src/components/AIDemoLanding/EntryCard.tsx",
    "content": "'use client'\n\nimport { ArrowUpRight } from 'lucide-react'\nimport { useLocale } from '@/hooks'\n\nexport default function EntryCard() {\n  const { currentLocale } = useLocale()\n  const isZh = currentLocale === 'zh'\n\n  return (\n    <div className=\"relative z-2 mx-auto mt-8 w-full max-w-5xl px-6\">\n      <section className=\"relative overflow-hidden rounded-2xl border border-slate-200/80 bg-white/88 p-5 shadow-[0_16px_34px_-26px_rgba(15,23,42,0.75)] backdrop-blur-sm md:p-6 dark:border-slate-700/80 dark:bg-slate-900/75 dark:shadow-[0_20px_38px_-28px_rgba(0,0,0,0.9)]\">\n        <div className=\"pointer-events-none absolute -left-16 -top-16 h-40 w-40 rounded-full bg-[#2563EB]/12 blur-3xl dark:bg-cyan-500/10\" aria-hidden />\n        <div className=\"pointer-events-none absolute -bottom-20 right-0 h-44 w-44 rounded-full bg-[#22C55E]/10 blur-3xl dark:bg-emerald-400/10\" aria-hidden />\n        <div className=\"grid gap-4 md:grid-cols-[minmax(0,1fr)_220px] md:items-center\">\n          <div className=\"relative\">\n            <span className=\"inline-flex items-center gap-2 rounded-full border border-blue-200/70 bg-blue-50/80 px-3 py-1 text-xs font-medium text-blue-700 dark:border-cyan-500/25 dark:bg-cyan-500/10 dark:text-cyan-300\">\n              <span className=\"h-1.5 w-1.5 rounded-full bg-[#22C55E]\" aria-hidden />\n              AI Landing Reference\n            </span>\n            <h2 className=\"text-xl font-semibold tracking-tight text-slate-900 md:text-[1.75rem] md:leading-9 dark:text-slate-100\">\n              {isZh ? '参考案例：AI 产品落地页' : 'Reference: AI Product Landing Page'}\n            </h2>\n            <p className=\"mt-2 text-sm leading-7 text-slate-700 md:text-base dark:text-slate-300\">\n              {isZh\n                ? '这是一个专门设计的落地页参考页，用来展示此模板可实现的页面结构、文案节奏与响应式效果。'\n                : 'A dedicated reference page showing what this starter can deliver: structure, copy rhythm, and responsive quality.'}\n            </p>\n            <p className=\"mt-2 text-sm text-slate-500 dark:text-slate-400\">\n              {isZh ? '包含英文与中文两套内容，可直接用于产品演示。' : 'Includes both English and Chinese content for direct product demos.'}\n            </p>\n          </div>\n          <div className=\"flex md:justify-end\">\n            <a\n              href={`/${currentLocale}/ai-demo`}\n              className=\"inline-flex w-full min-h-11 items-center justify-center gap-1.5 rounded-xl bg-linear-to-r from-[#2563EB] to-[#1D4ED8] px-4 py-2.5 text-sm font-semibold text-white shadow-[0_14px_28px_-18px_rgba(37,99,235,0.95)] transition duration-300 hover:-translate-y-0.5 hover:shadow-[0_20px_34px_-18px_rgba(37,99,235,0.9)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#2563EB] focus-visible:ring-offset-2 dark:from-blue-500 dark:to-cyan-500 dark:focus-visible:ring-cyan-400 md:w-auto\"\n            >\n              {isZh ? '打开参考页' : 'Open Reference Page'}\n              <ArrowUpRight className=\"h-4 w-4\" aria-hidden />\n            </a>\n          </div>\n        </div>\n      </section>\n    </div>\n  )\n}\n"
  },
  {
    "path": "src/components/AIDemoLanding/index.tsx",
    "content": "'use client'\n\nimport type { ReactNode } from 'react'\nimport { Bot, CheckCircle2, FileText, GaugeCircle, Layers, ShieldCheck, Sparkles, WandSparkles } from 'lucide-react'\nimport { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion'\nimport { useLocale } from '@/hooks'\nimport { getLandingCopy, type LandingCopy } from '@/i18n/ai-demo'\nimport { InteractiveDemoPanel, InteractivePricingCards } from './interactions'\n\ntype SectionProps = {\n  id: string\n  title: string\n  children: ReactNode\n  compact?: boolean\n}\n\nconst panelClass = 'rounded-2xl border border-slate-200/80 bg-white/85 shadow-[0_14px_40px_-24px_rgba(37,99,235,0.5)] backdrop-blur-sm dark:border-zinc-700/70 dark:bg-zinc-900/80 dark:shadow-[0_16px_44px_-30px_rgba(34,197,94,0.42)]'\nconst primaryCtaClass = 'inline-flex min-h-11 items-center justify-center rounded-xl bg-gradient-to-r from-[#2563EB] to-[#1D4ED8] px-5 py-2.5 text-sm font-semibold text-white shadow-[0_14px_26px_-18px_rgba(37,99,235,0.95)] transition duration-300 hover:-translate-y-0.5 hover:shadow-[0_20px_32px_-18px_rgba(37,99,235,0.9)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#2563EB] focus-visible:ring-offset-2 focus-visible:ring-offset-white motion-reduce:transition-none dark:focus-visible:ring-[#60A5FA] dark:focus-visible:ring-offset-zinc-950'\nconst softCardClass = 'rounded-2xl border border-slate-200/80 bg-white/90 p-5 shadow-[0_10px_24px_-20px_rgba(15,23,42,0.7)] transition duration-300 hover:-translate-y-0.5 hover:shadow-[0_20px_30px_-22px_rgba(37,99,235,0.45)] motion-reduce:transition-none dark:border-zinc-700/80 dark:bg-zinc-900/75 dark:shadow-[0_16px_30px_-26px_rgba(0,0,0,0.8)]'\n\nfunction Section({ id, title, children, compact }: SectionProps) {\n  return (\n    <section id={id} className={compact ? 'py-12' : 'py-16 sm:py-20'} aria-labelledby={`${id}-title`}>\n      <div className=\"mx-auto max-w-6xl px-4 sm:px-6 lg:px-8\">\n        <h2 id={`${id}-title`} className=\"text-2xl font-semibold tracking-tight text-slate-900 sm:text-3xl dark:text-zinc-100\">\n          {title}\n        </h2>\n        <div className=\"mt-8\">{children}</div>\n      </div>\n    </section>\n  )\n}\n\nfunction FeatureIcon({ index }: { index: number }) {\n  const icons = [WandSparkles, Bot, Layers, ShieldCheck, GaugeCircle, FileText]\n  const Icon = icons[index] ?? CheckCircle2\n  return <Icon className=\"h-5 w-5 text-[#2563EB] dark:text-[#60A5FA]\" aria-hidden />\n}\n\nfunction TopNav({ copy }: { copy: LandingCopy }) {\n  return (\n    <header className=\"sticky top-0 z-50 border-b border-slate-200/70 bg-white/70 backdrop-blur-xl dark:border-zinc-800/70 dark:bg-zinc-950/75\">\n      <div className=\"mx-auto flex h-16 max-w-6xl items-center justify-between px-4 sm:px-6 lg:px-8\">\n        <a href=\"#top\" className=\"inline-flex items-center gap-2 text-base font-semibold text-slate-900 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#2563EB] focus-visible:ring-offset-2 dark:text-zinc-100 dark:focus-visible:ring-[#60A5FA] dark:focus-visible:ring-offset-zinc-950\">\n          <span className=\"inline-flex h-2.5 w-2.5 animate-[heartbeat_3.4s_ease-in-out_infinite] rounded-full bg-[#22C55E]\" aria-hidden />\n          {copy.nav.product}\n        </a>\n        <nav aria-label=\"Primary\" className=\"flex items-center gap-2 sm:gap-3\">\n          <a\n            href=\"#demo\"\n            className=\"rounded-xl border border-slate-300/80 bg-white/70 px-3 py-2 text-sm font-medium text-slate-700 transition duration-200 hover:border-slate-400 hover:bg-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#2563EB] focus-visible:ring-offset-2 dark:border-zinc-700 dark:bg-zinc-900/80 dark:text-zinc-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-900 dark:focus-visible:ring-[#60A5FA] dark:focus-visible:ring-offset-zinc-950\"\n          >\n            {copy.nav.tryDemo}\n          </a>\n          <a\n            href=\"#final-cta\"\n            className=\"hidden rounded-xl border border-slate-300/80 bg-white/70 px-3 py-2 text-sm font-medium text-slate-700 transition duration-200 hover:border-slate-400 hover:bg-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#2563EB] focus-visible:ring-offset-2 sm:inline-flex dark:border-zinc-700 dark:bg-zinc-900/80 dark:text-zinc-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-900 dark:focus-visible:ring-[#60A5FA] dark:focus-visible:ring-offset-zinc-950\"\n          >\n            {copy.nav.bookCall}\n          </a>\n          <a href=\"#pricing\" className={primaryCtaClass}>\n            {copy.nav.startTrial}\n          </a>\n        </nav>\n      </div>\n    </header>\n  )\n}\n\nfunction Hero({ copy }: { copy: LandingCopy }) {\n  return (\n    <section\n      id=\"top\"\n      className=\"relative overflow-hidden border-b border-slate-200/80 bg-[linear-gradient(150deg,#eff6ff_0%,#ffffff_46%,#ecfdf5_100%)] py-16 sm:py-20 dark:border-zinc-800/80 dark:bg-[linear-gradient(150deg,#0f172a_0%,#111827_45%,#0b1322_100%)]\"\n      aria-labelledby=\"hero-title\"\n    >\n      <div className=\"pointer-events-none absolute -top-24 left-[12%] h-64 w-64 rounded-full bg-[#2563EB]/20 blur-3xl motion-safe:animate-pulse dark:bg-[#38BDF8]/18\" aria-hidden />\n      <div className=\"pointer-events-none absolute -bottom-24 right-[8%] h-72 w-72 rounded-full bg-[#22C55E]/18 blur-3xl motion-safe:animate-pulse dark:bg-[#34D399]/15\" aria-hidden />\n      <div className=\"mx-auto grid max-w-6xl gap-10 px-4 sm:px-6 lg:grid-cols-[1.18fr_0.82fr] lg:items-center lg:px-8\">\n        <div className=\"relative z-10\">\n          <div className=\"mb-4 inline-flex items-center gap-2 rounded-full border border-[#2563EB]/20 bg-white/70 px-3 py-1 text-xs font-medium text-[#1E3A8A] backdrop-blur dark:border-[#60A5FA]/25 dark:bg-zinc-900/60 dark:text-[#93C5FD]\">\n            <Sparkles className=\"h-3.5 w-3.5\" aria-hidden />\n            AI Workflow Assistant for Lean Teams\n          </div>\n          <h1 id=\"hero-title\" className=\"text-balance text-3xl font-semibold tracking-tight text-slate-900 sm:text-5xl dark:text-zinc-100\">\n            {copy.hero.title}\n          </h1>\n          <p className=\"mt-4 max-w-xl text-base leading-7 text-slate-700 sm:text-lg dark:text-zinc-300\">\n            {copy.hero.subtitle}\n          </p>\n          <div className=\"mt-8 flex flex-wrap gap-3\">\n            <a href=\"#demo\" className={primaryCtaClass}>\n              {copy.hero.tryDemo}\n            </a>\n            <a href=\"#final-cta\" className=\"inline-flex min-h-11 items-center justify-center rounded-xl border border-slate-300/80 bg-white/80 px-5 py-2.5 text-sm font-semibold text-slate-800 shadow-[0_10px_20px_-18px_rgba(15,23,42,0.8)] transition duration-300 hover:-translate-y-0.5 hover:bg-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#2563EB] focus-visible:ring-offset-2 motion-reduce:transition-none dark:border-zinc-700 dark:bg-zinc-900/80 dark:text-zinc-100 dark:hover:bg-zinc-900 dark:focus-visible:ring-[#60A5FA] dark:focus-visible:ring-offset-zinc-950\">\n              {copy.hero.bookCall}\n            </a>\n          </div>\n          <p className=\"mt-3 text-sm font-medium text-slate-600 dark:text-zinc-400\">{copy.hero.trust}</p>\n        </div>\n\n        <div className={`${panelClass} relative overflow-hidden p-5 sm:p-6`}>\n          <div className=\"absolute -right-10 -top-10 h-32 w-32 animate-[spin_18s_linear_infinite] rounded-full border border-[#2563EB]/20\" aria-hidden />\n          <div className=\"rounded-xl border border-slate-200/80 bg-white/80 p-4 dark:border-zinc-700/80 dark:bg-zinc-950/80\">\n            <div className=\"flex items-center justify-between\">\n              <p className=\"text-sm font-semibold text-slate-900 dark:text-zinc-100\">Pipeline Health</p>\n              <span className=\"inline-flex items-center gap-1 rounded-full bg-emerald-100/80 px-2 py-0.5 text-xs font-medium text-emerald-700 dark:bg-emerald-500/20 dark:text-emerald-300\">\n                <span className=\"h-1.5 w-1.5 rounded-full bg-emerald-500\" aria-hidden />\n                Live\n              </span>\n            </div>\n            <div className=\"mt-4 space-y-3 text-sm text-slate-700 dark:text-zinc-300\">\n              <div className=\"rounded-lg border border-slate-200/70 bg-white/85 p-3 dark:border-zinc-700 dark:bg-zinc-900/80\">\n                <div className=\"mb-1.5 flex items-center justify-between\">\n                  <span>Lead triage</span>\n                  <span className=\"font-semibold text-[#22C55E]\">98% success</span>\n                </div>\n                <div className=\"h-1.5 rounded-full bg-slate-200 dark:bg-zinc-700\">\n                  <div className=\"h-1.5 w-[88%] rounded-full bg-gradient-to-r from-[#22C55E] to-[#16A34A] motion-safe:animate-pulse\" />\n                </div>\n              </div>\n              <div className=\"rounded-lg border border-slate-200/70 bg-white/85 p-3 dark:border-zinc-700 dark:bg-zinc-900/80\">\n                <div className=\"flex items-center justify-between\">\n                  <span>Onboarding emails</span>\n                  <span className=\"font-semibold text-[#22C55E]\">4 min avg</span>\n                </div>\n              </div>\n              <div className=\"rounded-lg border border-slate-200/70 bg-white/85 p-3 dark:border-zinc-700 dark:bg-zinc-900/80\">\n                <div className=\"flex items-center justify-between\">\n                  <span>Weekly report</span>\n                  <span className=\"font-semibold text-[#22C55E]\">Auto-generated</span>\n                </div>\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n    </section>\n  )\n}\n\nfunction SocialProof({ copy }: { copy: LandingCopy }) {\n  return (\n    <Section id=\"social-proof\" title={copy.socialProofTitle} compact>\n      <div className=\"grid gap-6 lg:grid-cols-[1.12fr_0.88fr]\">\n        <ul className=\"grid auto-rows-fr grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-5\" aria-label=\"Customer logos\">\n          {copy.socialProof.logos.map(logo => (\n            <li key={logo} className={`${softCardClass} flex min-h-[86px] items-center justify-center px-4 text-center text-sm font-semibold text-slate-700 dark:text-zinc-200`}>\n              {logo}\n            </li>\n          ))}\n        </ul>\n        <ul className=\"grid gap-3 sm:grid-cols-3 lg:grid-cols-1\" aria-label=\"Key metrics\">\n          {copy.socialProof.stats.map(stat => (\n            <li key={stat.label} className={`${softCardClass} min-h-[118px]`}>\n              <p className=\"text-3xl font-semibold tracking-tight text-slate-900 dark:text-zinc-100\">{stat.value}</p>\n              <p className=\"mt-2 text-sm leading-6 text-slate-600 dark:text-zinc-400\">{stat.label}</p>\n            </li>\n          ))}\n        </ul>\n      </div>\n    </Section>\n  )\n}\n\nfunction Features({ copy }: { copy: LandingCopy }) {\n  return (\n    <Section id=\"features\" title={copy.featureTitle}>\n      <ul className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n        {copy.features.map((feature, index) => (\n          <li key={feature.title} className={`${softCardClass} relative overflow-hidden`}>\n            <div className=\"pointer-events-none absolute right-0 top-0 h-24 w-24 rounded-full bg-[#2563EB]/10 blur-2xl dark:bg-[#22C55E]/10\" aria-hidden />\n            <div className=\"mb-4 inline-flex rounded-xl border border-slate-200/80 bg-slate-50/90 p-2.5 dark:border-zinc-700 dark:bg-zinc-950/80\">\n              <FeatureIcon index={index} />\n            </div>\n            <h3 className=\"text-lg font-semibold text-slate-900 dark:text-zinc-100\">{feature.title}</h3>\n            <p className=\"mt-2 text-sm leading-6 text-slate-700 dark:text-zinc-300\">{feature.description}</p>\n          </li>\n        ))}\n      </ul>\n    </Section>\n  )\n}\n\nfunction HowItWorks({ copy }: { copy: LandingCopy }) {\n  return (\n    <Section id=\"how-it-works\" title={copy.howItWorksTitle}>\n      <ol className=\"grid gap-4 md:grid-cols-3\">\n        {copy.steps.map((step, index) => (\n          <li key={step.title} className={softCardClass}>\n            <span className=\"inline-flex h-7 min-w-7 items-center justify-center rounded-full bg-[#2563EB]/12 px-2 text-xs font-semibold text-[#1D4ED8] dark:bg-[#60A5FA]/20 dark:text-[#93C5FD]\">\n              {index + 1}\n            </span>\n            <h3 className=\"mt-3 text-base font-semibold text-slate-900 dark:text-zinc-100\">{step.title}</h3>\n            <p className=\"mt-2 text-sm leading-6 text-slate-700 dark:text-zinc-300\">{step.description}</p>\n          </li>\n        ))}\n      </ol>\n    </Section>\n  )\n}\n\nfunction UseCases({ copy }: { copy: LandingCopy }) {\n  return (\n    <Section id=\"use-cases\" title={copy.useCasesTitle}>\n      <ul className=\"grid gap-4 md:grid-cols-3\">\n        {copy.useCases.map(useCase => (\n          <li key={useCase.title} className={softCardClass}>\n            <h3 className=\"text-base font-semibold text-slate-900 dark:text-zinc-100\">{useCase.title}</h3>\n            <p className=\"mt-2 text-sm leading-6 text-slate-700 dark:text-zinc-300\">{useCase.description}</p>\n          </li>\n        ))}\n      </ul>\n    </Section>\n  )\n}\n\nfunction DemoPreview({ copy, lang }: { copy: LandingCopy, lang: string }) {\n  return (\n    <Section id=\"demo\" title={copy.demoTitle}>\n      <div className=\"grid gap-6 lg:grid-cols-[1.3fr_0.7fr] lg:items-center\">\n        <InteractiveDemoPanel lang={lang} ctaText={copy.hero.startTrial} />\n        <div className={panelClass + ' p-5 sm:p-6'}>\n          <p className=\"text-base leading-7 text-slate-700 dark:text-zinc-300\">{copy.demoDescription}</p>\n          <a href=\"#pricing\" className={`${primaryCtaClass} mt-6`}>\n            {copy.hero.startTrial}\n          </a>\n        </div>\n      </div>\n    </Section>\n  )\n}\n\nfunction Testimonials({ copy }: { copy: LandingCopy }) {\n  return (\n    <Section id=\"testimonials\" title={copy.testimonialsTitle} compact>\n      <ul className=\"grid gap-4 md:grid-cols-2\">\n        {copy.testimonials.map(item => (\n          <li key={item.name} className={softCardClass}>\n            <blockquote className=\"text-base leading-7 text-slate-700 dark:text-zinc-300\">“{item.quote}”</blockquote>\n            <p className=\"mt-4 text-sm font-semibold text-slate-900 dark:text-zinc-100\">{item.name}</p>\n            <p className=\"text-sm text-slate-600 dark:text-zinc-400\">{item.role}</p>\n          </li>\n        ))}\n      </ul>\n    </Section>\n  )\n}\n\nfunction Pricing({ copy, lang }: { copy: LandingCopy, lang: string }) {\n  return (\n    <Section id=\"pricing\" title={copy.pricingTitle}>\n      <p className=\"mb-6 text-sm text-slate-600 dark:text-zinc-400\">{copy.pricingSubtitle}</p>\n      <InteractivePricingCards lang={lang} plans={copy.plans} />\n    </Section>\n  )\n}\n\nfunction FAQ({ copy }: { copy: LandingCopy }) {\n  return (\n    <Section id=\"faq\" title={copy.faqTitle}>\n      <Accordion type=\"single\" collapsible className={`${panelClass} px-5`}>\n        {copy.faqs.map((faq, index) => (\n          <AccordionItem key={faq.question} value={`faq-${index}`}>\n            <AccordionTrigger className=\"text-left text-base font-medium text-slate-900 dark:text-zinc-100\">\n              {faq.question}\n            </AccordionTrigger>\n            <AccordionContent className=\"text-sm leading-7 text-slate-700 dark:text-zinc-300\">\n              {faq.answer}\n            </AccordionContent>\n          </AccordionItem>\n        ))}\n      </Accordion>\n    </Section>\n  )\n}\n\nfunction FinalCta({ copy }: { copy: LandingCopy }) {\n  return (\n    <section\n      id=\"final-cta\"\n      className=\"relative overflow-hidden border-y border-slate-200/80 bg-[linear-gradient(150deg,#eff6ff_0%,#ffffff_46%,#ecfdf5_100%)] py-16 dark:border-zinc-800/80 dark:bg-[linear-gradient(150deg,#0f172a_0%,#111827_45%,#0b1322_100%)]\"\n      aria-labelledby=\"final-cta-title\"\n    >\n      <div className=\"pointer-events-none absolute left-1/2 top-0 h-48 w-48 -translate-x-1/2 rounded-full bg-[#2563EB]/20 blur-3xl motion-safe:animate-pulse dark:bg-[#34D399]/12\" aria-hidden />\n      <div className=\"mx-auto max-w-6xl px-4 text-center sm:px-6 lg:px-8\">\n        <h2 id=\"final-cta-title\" className=\"text-balance text-3xl font-semibold tracking-tight text-slate-900 sm:text-4xl dark:text-zinc-100\">\n          {copy.finalCta.title}\n        </h2>\n        <p className=\"mx-auto mt-4 max-w-2xl text-base leading-7 text-slate-700 dark:text-zinc-300\">\n          {copy.finalCta.description}\n        </p>\n        <div className=\"mt-8 flex flex-wrap justify-center gap-3\">\n          <a href=\"#top\" className={primaryCtaClass}>\n            {copy.finalCta.primary}\n          </a>\n          <a href={`mailto:${copy.footer.contactEmail}`} className=\"inline-flex min-h-11 items-center justify-center rounded-xl border border-slate-300/80 bg-white/80 px-5 py-2.5 text-sm font-semibold text-slate-800 shadow-[0_10px_20px_-18px_rgba(15,23,42,0.8)] transition duration-300 hover:-translate-y-0.5 hover:bg-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#2563EB] focus-visible:ring-offset-2 motion-reduce:transition-none dark:border-zinc-700 dark:bg-zinc-900/80 dark:text-zinc-100 dark:hover:bg-zinc-900 dark:focus-visible:ring-[#60A5FA] dark:focus-visible:ring-offset-zinc-950\">\n            {copy.finalCta.secondary}\n          </a>\n        </div>\n      </div>\n    </section>\n  )\n}\n\nfunction Footer({ copy }: { copy: LandingCopy }) {\n  return (\n    <footer className=\"py-10\" aria-label=\"Footer\">\n      <div className=\"mx-auto flex max-w-6xl flex-col gap-2 px-4 text-sm text-slate-600 sm:px-6 lg:flex-row lg:items-center lg:justify-between lg:px-8 dark:text-zinc-400\">\n        <p>\n          {copy.footer.productName}\n          {' · '}\n          {copy.footer.copyright}\n        </p>\n        <p>\n          {copy.footer.contactTitle}\n          {': '}\n          <a className=\"font-medium text-slate-700 transition-colors hover:text-[#2563EB] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#2563EB] focus-visible:ring-offset-2 dark:text-zinc-300 dark:hover:text-[#60A5FA] dark:focus-visible:ring-[#60A5FA] dark:focus-visible:ring-offset-zinc-950\" href={`mailto:${copy.footer.contactEmail}`}>\n            {copy.footer.contactEmail}\n          </a>\n          {' · '}\n          <a className=\"font-medium text-slate-700 transition-colors hover:text-[#2563EB] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#2563EB] focus-visible:ring-offset-2 dark:text-zinc-300 dark:hover:text-[#60A5FA] dark:focus-visible:ring-[#60A5FA] dark:focus-visible:ring-offset-zinc-950\" href={`tel:${copy.footer.contactPhone.replace(/\\s+/g, '')}`}>\n            {copy.footer.contactPhone}\n          </a>\n        </p>\n      </div>\n    </footer>\n  )\n}\n\nexport default function AIDemoLanding() {\n  const { currentLocale } = useLocale()\n  const copy = getLandingCopy(currentLocale)\n\n  return (\n    <main className=\"relative left-1/2 w-dvw -translate-x-1/2 overflow-x-clip bg-white text-slate-900 dark:bg-zinc-950 dark:text-zinc-100\">\n      <TopNav copy={copy} />\n      <Hero copy={copy} />\n      <SocialProof copy={copy} />\n      <Features copy={copy} />\n      <HowItWorks copy={copy} />\n      <UseCases copy={copy} />\n      <DemoPreview copy={copy} lang={currentLocale} />\n      <Testimonials copy={copy} />\n      <Pricing copy={copy} lang={currentLocale} />\n      <FAQ copy={copy} />\n      <FinalCta copy={copy} />\n      <Footer copy={copy} />\n    </main>\n  )\n}\n"
  },
  {
    "path": "src/components/AIDemoLanding/interactions.tsx",
    "content": "'use client'\n\nimport { useMemo, useState } from 'react'\nimport { CheckCircle2 } from 'lucide-react'\nimport type { Plan } from '@/i18n/ai-demo'\n\ntype BillingCycle = 'monthly' | 'yearly'\n\ntype InteractiveDemoProps = {\n  lang: string\n  ctaText: string\n}\n\ntype InteractivePricingProps = {\n  lang: string\n  plans: Plan[]\n}\n\ntype Scenario = {\n  key: string\n  label: string\n  summary: string\n  metrics: Array<{ label: string, value: string }>\n}\n\nfunction getDemoScenarios(lang: string): Scenario[] {\n  if (lang === 'zh') {\n    return [\n      {\n        key: 'support',\n        label: '客服分诊',\n        summary: '自动分类工单、提取摘要，并分发给对应处理人。',\n        metrics: [\n          { label: '平均首响时间', value: '-38%' },\n          { label: '自动分发准确率', value: '96%' },\n          { label: '人工预处理耗时', value: '-4.2h/周' },\n        ],\n      },\n      {\n        key: 'reporting',\n        label: '周报生成',\n        summary: '定时汇总核心指标，自动输出可执行周报结论。',\n        metrics: [\n          { label: '周报产出时间', value: '-72%' },\n          { label: '数据同步时效', value: 'T+0' },\n          { label: '跨团队对齐效率', value: '+2.1x' },\n        ],\n      },\n      {\n        key: 'launch',\n        label: '上线协同',\n        summary: '自动推进素材、审批与发布清单，降低上线遗漏。',\n        metrics: [\n          { label: '发布延期率', value: '-29%' },\n          { label: '清单遗漏项', value: '-64%' },\n          { label: '协作往返沟通', value: '-31%' },\n        ],\n      },\n    ]\n  }\n\n  return [\n    {\n      key: 'support',\n      label: 'Support Triage',\n      summary: 'Classify tickets, generate summaries, and route to the right owner automatically.',\n      metrics: [\n        { label: 'First response time', value: '-38%' },\n        { label: 'Auto-routing accuracy', value: '96%' },\n        { label: 'Manual prep time', value: '-4.2h/week' },\n      ],\n    },\n    {\n      key: 'reporting',\n      label: 'Weekly Reporting',\n      summary: 'Collect key metrics on schedule and draft action-ready weekly reports.',\n      metrics: [\n        { label: 'Reporting time', value: '-72%' },\n        { label: 'Data freshness', value: 'T+0' },\n        { label: 'Team alignment speed', value: '+2.1x' },\n      ],\n    },\n    {\n      key: 'launch',\n      label: 'Launch Ops',\n      summary: 'Coordinate assets, approvals, and checklists with fewer missed steps.',\n      metrics: [\n        { label: 'Launch delay rate', value: '-29%' },\n        { label: 'Checklist misses', value: '-64%' },\n        { label: 'Back-and-forth handoffs', value: '-31%' },\n      ],\n    },\n  ]\n}\n\nfunction parsePriceNumber(price: string): number | null {\n  const match = price.match(/\\d+(?:\\.\\d+)?/)\n  if (!match) {\n    return null\n  }\n  return Number(match[0])\n}\n\nfunction formatPlanPrice(price: string, cycle: BillingCycle, lang: string): string {\n  if (price === 'Custom' || price === '定制') {\n    return price\n  }\n\n  const value = parsePriceNumber(price)\n  if (value === null) {\n    return price\n  }\n\n  const isDollar = price.includes('$')\n  const isYuan = price.includes('¥')\n  const prefix = isDollar ? '$' : isYuan ? '¥' : ''\n\n  if (cycle === 'monthly') {\n    return lang === 'zh' ? `${prefix}${value}/月` : `${prefix}${value}/mo`\n  }\n\n  const yearly = Math.round(value * 10)\n  return lang === 'zh' ? `${prefix}${yearly}/年` : `${prefix}${yearly}/yr`\n}\n\nexport function InteractiveDemoPanel({ lang, ctaText }: InteractiveDemoProps) {\n  const scenarios = useMemo(() => getDemoScenarios(lang), [lang])\n  const [activeKey, setActiveKey] = useState(scenarios[0]?.key ?? 'support')\n\n  const activeScenario = scenarios.find(item => item.key === activeKey) ?? scenarios[0]\n  if (!activeScenario) {\n    return null\n  }\n\n  return (\n    <div className=\"relative overflow-hidden rounded-2xl border border-slate-200/80 bg-white/90 p-4 shadow-[0_14px_40px_-24px_rgba(37,99,235,0.5)] backdrop-blur-sm dark:border-zinc-700/80 dark:bg-zinc-900/80 dark:shadow-[0_16px_44px_-30px_rgba(34,197,94,0.42)] sm:p-5\">\n      <div className=\"pointer-events-none absolute -right-10 -top-10 h-28 w-28 rounded-full bg-[#2563EB]/12 blur-2xl motion-safe:animate-pulse dark:bg-[#22C55E]/10\" aria-hidden />\n      <div className=\"mb-4 flex flex-wrap gap-2\" role=\"tablist\" aria-label={lang === 'zh' ? '场景切换' : 'Scenario switcher'}>\n        {scenarios.map(scenario => (\n          <button\n            key={scenario.key}\n            type=\"button\"\n            role=\"tab\"\n            aria-selected={activeScenario.key === scenario.key}\n            className={[\n              'rounded-xl border px-3 py-1.5 text-sm font-medium transition duration-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#2563EB] focus-visible:ring-offset-2 motion-reduce:transition-none dark:focus-visible:ring-[#60A5FA] dark:focus-visible:ring-offset-zinc-900',\n              activeScenario.key === scenario.key\n                ? 'border-[#2563EB]/40 bg-gradient-to-r from-blue-50 to-blue-100/70 text-[#1D4ED8] shadow-[0_10px_22px_-20px_rgba(37,99,235,0.9)] dark:border-[#60A5FA]/40 dark:bg-[#1E3A8A]/25 dark:text-[#93C5FD]'\n                : 'border-slate-300/80 bg-white/85 text-slate-700 hover:border-slate-400 hover:bg-white dark:border-zinc-700 dark:bg-zinc-900/80 dark:text-zinc-300 dark:hover:border-zinc-600 dark:hover:bg-zinc-900',\n            ].join(' ')}\n            onClick={() => setActiveKey(scenario.key)}\n          >\n            {scenario.label}\n          </button>\n        ))}\n      </div>\n\n      <div className=\"rounded-xl border border-slate-200/80 bg-slate-50/80 p-4 dark:border-zinc-700/80 dark:bg-zinc-950/70\">\n        <p className=\"text-sm text-slate-700 dark:text-zinc-300\">{activeScenario.summary}</p>\n        <ul className=\"mt-4 space-y-2\">\n          {activeScenario.metrics.map(metric => (\n            <li key={metric.label} className=\"flex items-center justify-between rounded-xl border border-slate-200/80 bg-white/90 px-3 py-2 text-sm shadow-[0_10px_20px_-22px_rgba(15,23,42,0.8)] transition duration-300 hover:-translate-y-0.5 hover:shadow-[0_16px_28px_-22px_rgba(37,99,235,0.5)] motion-reduce:transition-none dark:border-zinc-700 dark:bg-zinc-900/85\">\n              <span className=\"text-slate-600 dark:text-zinc-400\">{metric.label}</span>\n              <span className=\"font-semibold text-slate-900 dark:text-zinc-100\">{metric.value}</span>\n            </li>\n          ))}\n        </ul>\n        <a\n          href=\"#pricing\"\n          className=\"mt-5 inline-flex min-h-11 items-center justify-center rounded-xl bg-gradient-to-r from-[#2563EB] to-[#1D4ED8] px-4 py-2.5 text-sm font-semibold text-white shadow-[0_14px_26px_-18px_rgba(37,99,235,0.95)] transition duration-300 hover:-translate-y-0.5 hover:shadow-[0_20px_32px_-18px_rgba(37,99,235,0.9)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#2563EB] focus-visible:ring-offset-2 focus-visible:ring-offset-white motion-reduce:transition-none dark:focus-visible:ring-[#60A5FA] dark:focus-visible:ring-offset-zinc-900\"\n        >\n          {ctaText}\n        </a>\n      </div>\n    </div>\n  )\n}\n\nexport function InteractivePricingCards({ lang, plans }: InteractivePricingProps) {\n  const [cycle, setCycle] = useState<BillingCycle>('monthly')\n\n  return (\n    <>\n      <div className=\"mb-5 inline-flex rounded-xl border border-slate-300/80 bg-white/85 p-1 shadow-[0_10px_18px_-18px_rgba(15,23,42,0.75)] dark:border-zinc-700/80 dark:bg-zinc-900/75\" role=\"group\" aria-label={lang === 'zh' ? '计费周期' : 'Billing cycle'}>\n        <button\n          type=\"button\"\n          onClick={() => setCycle('monthly')}\n          className={[\n            'rounded-lg px-3 py-1.5 text-sm font-medium transition duration-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#2563EB] focus-visible:ring-offset-2 motion-reduce:transition-none dark:focus-visible:ring-[#60A5FA] dark:focus-visible:ring-offset-zinc-900',\n            cycle === 'monthly' ? 'bg-slate-100 text-slate-900 dark:bg-zinc-800 dark:text-zinc-100' : 'text-slate-600 hover:bg-slate-50 dark:text-zinc-400 dark:hover:bg-zinc-800',\n          ].join(' ')}\n          aria-pressed={cycle === 'monthly'}\n        >\n          {lang === 'zh' ? '月付' : 'Monthly'}\n        </button>\n        <button\n          type=\"button\"\n          onClick={() => setCycle('yearly')}\n          className={[\n            'rounded-lg px-3 py-1.5 text-sm font-medium transition duration-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#2563EB] focus-visible:ring-offset-2 motion-reduce:transition-none dark:focus-visible:ring-[#60A5FA] dark:focus-visible:ring-offset-zinc-900',\n            cycle === 'yearly' ? 'bg-slate-100 text-slate-900 dark:bg-zinc-800 dark:text-zinc-100' : 'text-slate-600 hover:bg-slate-50 dark:text-zinc-400 dark:hover:bg-zinc-800',\n          ].join(' ')}\n          aria-pressed={cycle === 'yearly'}\n        >\n          {lang === 'zh' ? '年付（约 2 个月优惠）' : 'Yearly (approx. 2 months free)'}\n        </button>\n      </div>\n\n      <ul className=\"grid gap-4 lg:grid-cols-3\">\n        {plans.map(plan => (\n          <li\n            key={plan.name}\n            className={[\n              'relative overflow-hidden rounded-2xl border bg-white/90 p-5 shadow-[0_14px_30px_-24px_rgba(15,23,42,0.75)] transition duration-300 hover:-translate-y-1 hover:shadow-[0_22px_40px_-28px_rgba(37,99,235,0.5)] motion-reduce:transition-none dark:bg-zinc-900/75 dark:shadow-[0_16px_32px_-28px_rgba(0,0,0,0.85)]',\n              plan.highlight ? 'border-[#2563EB]/45 dark:border-[#60A5FA]/45' : 'border-slate-200/80 dark:border-zinc-700/80',\n            ].join(' ')}\n          >\n            {plan.highlight && (\n              <span className=\"mb-3 inline-flex rounded-full border border-[#2563EB]/25 bg-[#2563EB]/10 px-2.5 py-1 text-xs font-semibold text-[#1D4ED8] dark:border-[#60A5FA]/30 dark:bg-[#60A5FA]/15 dark:text-[#93C5FD]\">\n                {lang === 'zh' ? '推荐方案' : 'Most Popular'}\n              </span>\n            )}\n            <div className=\"pointer-events-none absolute -right-12 -top-12 h-32 w-32 rounded-full bg-[#2563EB]/10 blur-3xl dark:bg-[#22C55E]/10\" aria-hidden />\n            <h3 className=\"text-lg font-semibold text-slate-900 dark:text-zinc-100\">{plan.name}</h3>\n            <p className=\"mt-1 text-2xl font-semibold text-slate-900 dark:text-zinc-100\">{formatPlanPrice(plan.price, cycle, lang)}</p>\n            <p className=\"mt-2 text-sm text-slate-700 dark:text-zinc-300\">{plan.description}</p>\n            <ul className=\"mt-4 space-y-2\">\n              {plan.points.map(point => (\n                <li key={point} className=\"flex items-start gap-2 text-sm text-slate-700 dark:text-zinc-300\">\n                  <CheckCircle2 className=\"mt-0.5 h-4 w-4 text-[#22C55E]\" aria-hidden />\n                  <span>{point}</span>\n                </li>\n              ))}\n            </ul>\n            <a\n              href=\"#final-cta\"\n              className={[\n                'mt-5 inline-flex min-h-11 items-center justify-center rounded-xl px-4 py-2.5 text-sm font-semibold transition duration-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#2563EB] focus-visible:ring-offset-2 motion-reduce:transition-none dark:focus-visible:ring-[#60A5FA] dark:focus-visible:ring-offset-zinc-900',\n                plan.highlight\n                  ? 'bg-gradient-to-r from-[#2563EB] to-[#1D4ED8] text-white shadow-[0_14px_26px_-18px_rgba(37,99,235,0.95)] hover:-translate-y-0.5 hover:shadow-[0_20px_32px_-18px_rgba(37,99,235,0.9)]'\n                  : 'border border-slate-300/80 bg-white/80 text-slate-800 hover:-translate-y-0.5 hover:bg-white dark:border-zinc-700 dark:bg-zinc-900/80 dark:text-zinc-200 dark:hover:bg-zinc-900',\n              ].join(' ')}\n            >\n              {plan.cta}\n            </a>\n          </li>\n        ))}\n      </ul>\n    </>\n  )\n}\n"
  },
  {
    "path": "src/components/CustomFooter/index.tsx",
    "content": "import type { ReactNode } from 'react'\nimport Link from 'next/link'\nimport { Separator } from '@/components/ui/separator'\nimport { cn } from '@/lib/utils'\nimport LocaleToggle from '@/widgets/locale-toggle'\nimport ThemeToggle from '@/widgets/theme-toggle'\n\nconst UnderlineLink = ({\n  link,\n  label,\n  underlineByDefault = false,\n}: {\n  label: ReactNode | string\n  link: string\n  underlineByDefault?: boolean\n}) => {\n  return (\n    <Link\n      href={link}\n      target=\"_blank\"\n      className={cn(\n        'flex items-center rounded-none border border-transparent',\n        'dark:text-zinc-300',\n        'duration-200',\n        'hover:border-b-zinc-600',\n        'dark:hover:border-b-zinc-300',\n        underlineByDefault\n          ? `border-b border-b-zinc-400/[0.3] dark:border-b-zinc-500`\n          : 'hover:border-b',\n      )}\n    >\n      { label }\n    </Link>\n  )\n}\n\nexport function CustomFooter() {\n  return (\n    <div className=\"w-full flex justify-center items-center\">\n      <div className={cn(\n        'flex justify-center items-center gap-[2px]',\n        'max-sm:flex-col max-sm:gap-5 max-sm:pb-10',\n        'tracking-wide text-[15px] text-center group',\n        'text-gray-500/[0.8] dark:text-zinc-300/[0.8]',\n      )}\n      >\n        <UnderlineLink\n          link=\"https://creativecommons.org/licenses/by-nc-sa/4.0/\"\n          label=\"CC BY-NC-SA 4.0\"\n          underlineByDefault\n        />\n\n        <div className=\"flex items-center gap-[2px]\">\n          <span className=\"pl-[4px]\">\n            Copyright ©\n            {' '}\n            { new Date().getFullYear() }\n          </span>\n          <UnderlineLink\n            link=\"https://github.com/pdsuwwz\"\n            label={(\n              <>\n                <span className=\"animate-[heartbeat_1.5s_infinite] mr-[3px]\">❤️</span>\n                {' '}\n                Wisdom\n              </>\n            )}\n          />\n        </div>\n\n        <Separator\n          orientation=\"vertical\"\n          className=\"max-sm:hidden h-5 mx-2\"\n        />\n        <div className=\"flex justify-center h-5 items-center space-x-2 text-sm\">\n          <ThemeToggle />\n          <Separator orientation=\"vertical\" />\n          <LocaleToggle />\n        </div>\n\n      </div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "src/components/HomepageHero/Section.tsx",
    "content": "import type { ReactNode } from 'react'\nimport { MotionWrapperFadeIn, MotionWrapperFlash } from '@/components/MotionWrapper'\nimport { cn } from '@/lib/utils'\n\ninterface Props {\n  title?: string\n  titleProps?: Partial<React.ComponentProps<typeof MotionWrapperFlash>>\n  description?: string\n  children?: ReactNode\n  className?: string\n  tallPaddingY?: boolean\n}\n\nexport const Section = (props: Props) => {\n  const {\n    className,\n    titleProps,\n    title,\n    description,\n    children,\n    tallPaddingY = false,\n  } = props\n  return (\n    <section className={cn(\n      'flex flex-col items-center justify-center px-6',\n      className,\n    )}\n    >\n      <MotionWrapperFlash\n        {\n          ...titleProps\n        }\n      >\n        <h2 className={cn(\n          'relative',\n          'text-center font-semibold',\n          'bg-clip-text text-transparent bg-linear-to-b',\n          'text-3xl md:text-5xl md:leading-tight pt-5',\n          'from-slate-700 to-slate-900',\n          'dark:from-slate-200 dark:to-white',\n          `${tallPaddingY ? 'pt-20 pb-10' : ''}`,\n        )}\n        >\n          <span>{ title }</span>\n        </h2>\n      </MotionWrapperFlash>\n      <MotionWrapperFadeIn>\n        {\n          description\n          && (\n            <h2 className=\"text-sm md:text-base max-w-4xl my-4 mx-auto text-center font-normal text-zinc-600 dark:text-zinc-400\">\n              { description }\n            </h2>\n          )\n        }\n      </MotionWrapperFadeIn>\n      {children}\n    </section>\n  )\n}\n"
  },
  {
    "path": "src/components/HomepageHero/Setup.tsx",
    "content": "'use client'\n\nimport clsx from 'clsx'\nimport Link from 'next/link'\nimport styles from '@/components/HomepageHero/SetupHero.module.css'\nimport { MotionWrapperFlash } from '@/components/MotionWrapper/Flash'\nimport { Button } from '@/components/ui/button'\nimport { FlipWords } from '@/components/ui/flip-words'\nimport { LinkPreview } from '@/components/ui/link-preview'\nimport { useLocale } from '@/hooks'\n\ninterface Props {\n}\nexport function SetupHero(props: Props) {\n  const { t, currentLocale } = useLocale()\n\n  return (\n    <div className={styles.container}>\n      <div className={styles.glowA} aria-hidden />\n      <div className={styles.glowB} aria-hidden />\n      <div className={styles.content}>\n        <div className={styles.badgeContainer}>\n          <a\n            className={styles.badge}\n            href=\"https://github.com/pdsuwwz/nextjs-nextra-starter\"\n            target=\"_blank\"\n            rel=\"noopener noreferrer\"\n          >\n            {t('badgeTitle')}\n          </a>\n        </div>\n        <h1 className={styles.headline}>\n          <MotionWrapperFlash\n            disabledAnimation={false}\n            className=\"flex items-center\"\n          >\n            <span className=\"icon-[emojione-v1--lightning-mood]\"></span>\n          </MotionWrapperFlash>\n          {' '}\n          Nextra\n          {' '}\n          <br className=\"sm:hidden\"></br>\n          {' '}\n          Starter\n          <br className=\"sm:hidden\"></br>\n          {' '}\n          Template\n        </h1>\n\n        <Link\n          href={`/${currentLocale}/upgrade`}\n          className={clsx([\n            'text-sm mt-3 inline-flex items-center rounded-xl px-3.5 py-1.5',\n            'border border-blue-200/80 bg-blue-50/80 text-blue-700 shadow-[0_12px_22px_-18px_rgba(37,99,235,0.8)] backdrop-blur-sm',\n            'dark:border-cyan-500/25 dark:bg-cyan-500/10 dark:text-cyan-300 dark:shadow-[0_14px_24px_-20px_rgba(34,211,238,0.65)]',\n            '[&>span]:font-semibold',\n            'transition duration-300 hover:-translate-y-0.5',\n          ])}\n          dangerouslySetInnerHTML={{\n            __html: t('featureSupport', {\n              feature: `<span>Tailwind CSS v4, Nextra v4</span>`,\n            }),\n          }}\n        />\n\n\n        <div className={clsx([\n          styles.subtitle,\n          'text-neutral-500 dark:text-neutral-300',\n        ])}\n        >\n          Template made\n          {' '}\n          <FlipWords\n            words={[\n              'Fast',\n              'Simple',\n              'Modern',\n              'Flexible',\n              'Easy',\n              'Functional',\n              'Efficient',\n              'Scalable',\n              'Reusable',\n            ]}\n          />\n          <br />\n          With\n          {' '}\n          <LinkPreview\n            url=\"https://nextjs.org\"\n          >\n            Next.js\n          </LinkPreview>\n          ,\n          {' '}\n          <LinkPreview\n            url=\"https://tailwindcss.com\"\n          >\n            Tailwind CSS\n          </LinkPreview>\n          , and\n          {' '}\n          <LinkPreview\n            url=\"https://ui.shadcn.com\"\n          >\n            Shadcn UI\n          </LinkPreview>\n          {', '}\n          <LinkPreview\n            url=\"https://ui.aceternity.com\"\n          >\n            Aceternity UI\n          </LinkPreview>\n        </div>\n        <div className=\"flex justify-center pt-10\">\n          <div className=\"max-w-[500px] flex flex-wrap gap-[20px] max-sm:justify-center\">\n            <Button\n              asChild\n              size=\"lg\"\n              className=\"font-semibold group rounded-xl bg-linear-to-r from-blue-600 to-indigo-600 text-white shadow-[0_16px_30px_-20px_rgba(37,99,235,0.9)] transition duration-300 hover:-translate-y-0.5 hover:from-blue-700 hover:to-indigo-700 hover:text-white dark:from-blue-500 dark:to-cyan-500 dark:hover:from-blue-400 dark:hover:to-cyan-400 dark:text-white dark:hover:text-white max-sm:w-[100%]\"\n            >\n              <Link\n                href={`/${currentLocale}/introduction`}\n              >\n                {t('getStarted')}\n                <span className=\"w-[20px] translate-x-[6px] transition-all group-hover:translate-x-[10px] icon-[mingcute--arrow-right-fill]\"></span>\n              </Link>\n            </Button>\n            <Button\n              asChild\n              size=\"lg\"\n              variant=\"secondary\"\n              className=\"font-semibold group rounded-xl border border-slate-300/80 bg-white/85 shadow-[0_12px_22px_-18px_rgba(15,23,42,0.7)] transition duration-300 hover:-translate-y-0.5 hover:bg-white dark:border-zinc-700 dark:bg-zinc-900/80 dark:hover:bg-zinc-900 max-sm:w-[100%]\"\n            >\n              <Link\n                href=\"https://github.com/pdsuwwz/nextjs-nextra-starter\"\n                target=\"_blank\"\n              >\n                Github\n                <span className=\"ml-[6px] icon-[mingcute--github-line]\"></span>\n              </Link>\n            </Button>\n          </div>\n        </div>\n      </div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "src/components/HomepageHero/SetupHero.module.css",
    "content": "@reference \"tailwindcss\";\n\n.container {\n  position: relative;\n}\n\n.glowA {\n  position: absolute;\n  top: 1.5rem;\n  left: 8%;\n  width: 18rem;\n  height: 18rem;\n  border-radius: 9999px;\n  background: radial-gradient(circle, rgba(37, 99, 235, 0.18) 0%, rgba(37, 99, 235, 0) 70%);\n  filter: blur(20px);\n  pointer-events: none;\n}\n\n.glowB {\n  position: absolute;\n  right: 5%;\n  top: 3rem;\n  width: 20rem;\n  height: 20rem;\n  border-radius: 9999px;\n  background: radial-gradient(circle, rgba(34, 197, 94, 0.14) 0%, rgba(34, 197, 94, 0) 72%);\n  filter: blur(24px);\n  pointer-events: none;\n\n  :global(.dark) & {\n    background: radial-gradient(circle, rgba(34, 211, 238, 0.16) 0%, rgba(34, 211, 238, 0) 72%);\n  }\n}\n\n.content {\n  margin: 0 auto;\n  position: relative;\n  z-index: 2;\n  padding-left: max(env(safe-area-inset-left), 1.5rem);\n  padding-right: max(env(safe-area-inset-right), 1.5rem);\n  max-width: 90rem;\n  text-align: center;\n  @apply pb-12 md:pb-[100px];\n}\n\n.badgeContainer {\n  @apply mt-8 md:mt-16;\n}\n\n.badge {\n  padding: 0.45rem 0.95rem;\n  border-radius: 2em;\n  border: 1px solid hsl(214 32% 75%);\n  background: rgba(255, 255, 255, 0.72);\n  color: hsl(218 62% 31%);\n  font-size: 0.95rem;\n  font-weight: 500;\n  text-decoration: none;\n  white-space: nowrap;\n  user-select: none;\n  transition: all 0.2s ease;\n  backdrop-filter: blur(8px);\n\n  &:hover {\n    border-color: hsl(214 52% 55%);\n    box-shadow: 0 14px 24px -20px rgba(37, 99, 235, 0.85);\n    transform: translateY(-1px);\n  }\n\n  &:active {\n    transform: translateY(0);\n    border-color: hsl(214 32% 75%);\n  }\n\n  &:focus-visible {\n    outline: 2px solid\n      hsl(var(--nextra-primary-hue) var(--nextra-primary-saturation) 77%);\n    outline-offset: 2px;\n  }\n\n  :global(.dark) & {\n    background: rgba(20, 23, 34, 0.72);\n    color: hsl(210 50% 74%);\n    border: 1px solid hsl(220 25% 34%);\n    text-shadow: 0 1px 1px #000;\n\n    &:hover {\n      background: rgba(20, 23, 34, 0.9);\n      border-color: hsl(197 40% 46%);\n      box-shadow: 0 14px 24px -20px rgba(34, 211, 238, 0.8);\n    }\n\n    &:active {\n      border-color: hsl(220 25% 34%);\n    }\n  }\n}\n\n.headline {\n  margin-top: 1.5rem;\n  background-image: linear-gradient(138deg, #0f172a 0%, #1d4ed8 40%, #22c55e 95%);\n  -webkit-background-clip: text;\n  -webkit-text-fill-color: transparent;\n  background-clip: text;\n  font-size: 3.125rem;\n  font-size: min(4rem, max(8vw, 2.8rem));\n  font-weight: 700;\n  font-feature-settings: initial;\n  line-height: 1.05;\n  letter-spacing: -0.12rem;\n\n  :global(.dark) & {\n    background-image: linear-gradient(136deg, #dbeafe 0%, #7dd3fc 42%, #86efac 100%);\n  }\n\n  @apply flex max-lg:flex max-lg:flex-col items-center justify-center;\n}\n\n.subtitle {\n  margin-top: 1.25em;\n  font-size: 1.2rem;\n  font-size: min(1.2rem, max(3.2vw, 1.05rem));\n  font-feature-settings: initial;\n  font-weight: 450;\n  line-height: 1.6;\n}\n\n.actions {\n  margin-top: 1.6em;\n  margin-bottom: 1.4em;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  font-size: 1.3rem;\n  font-size: min(1.3rem, max(3.5vw, 1.1rem));\n  font-weight: 500;\n}\n"
  },
  {
    "path": "src/components/HomepageHero/index.tsx",
    "content": "'use client'\n\nimport { useMemo } from 'react'\nimport Marquee from 'react-fast-marquee'\nimport EntryCard from '@/components/AIDemoLanding/EntryCard'\nimport { PanelParticles } from '@/components/PanelParticles'\nimport ScrollProgressBar from '@/components/ScrollProgressBar'\nimport { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion'\nimport { HoverEffect } from '@/components/ui/card-hover-effect'\nimport { useLocale } from '@/hooks'\nimport { cn } from '@/lib/utils'\nimport { Section } from './Section'\n\nimport { SetupHero } from './Setup'\n\nexport const StackItem = ({\n  className,\n}: {\n  className: string\n},\n) => {\n  return (\n    <div className={cn(\n      'mx-6 size-[50px]',\n      'text-neutral-800 dark:text-neutral-100',\n      'transition-all duration-300 transform opacity-75',\n      'hover:scale-125 hover:opacity-100',\n      className,\n    )}\n    >\n    </div>\n  )\n}\n\nexport default function HomepageHero() {\n  const { t, currentLocale } = useLocale()\n\n  const featureList = t('featureList')\n  const faqs = t('faqs')\n  const homeEnhance = t('homeEnhance') as {\n    quickStatsTitle: string\n    quickStatsDesc: string\n    quickStats: Array<{ value: string, label: string }>\n    useCasesTitle: string\n    useCases: Array<{ title: string, description: string, tag: string }>\n    flowTitle: string\n    flow: Array<{ title: string, description: string }>\n    ctaTitle: string\n    ctaDescription: string\n    ctaPrimary: string\n    ctaSecondary: string\n  }\n  const processedFeatureList = useMemo(() => {\n    const icons = [\n      'icon-[material-symbols--rocket-launch-outline]',\n      'icon-[icon-park-outline--international]',\n      'icon-[nonicons--typescript-16]',\n      'icon-[carbon--face-satisfied] hover:icon-[carbon--face-wink]',\n      'icon-[teenyicons--tailwind-outline]',\n      'icon-[tabler--calendar-code]',\n      'icon-[carbon--color-palette]',\n      'icon-[carbon--ibm-cloud-transit-gateway]',\n      'icon-[carbon--flash]',\n    ]\n    return featureList.map((item, index) => {\n      return {\n        ...item,\n        icon: <span className={icons[index] || icons[0]}></span>,\n      }\n    })\n  }, [featureList])\n\n  return (\n    <>\n      <ScrollProgressBar />\n      <PanelParticles />\n      <SetupHero />\n      <EntryCard />\n      {/* <div className=\"relative top-[-18px] mb-[-10px] flex justify-center py-[0px] z-2\">\n        <a\n          href=\"https://nextjs.org\"\n          target=\"_blank\"\n          rel=\"noopener noreferrer\"\n          className=\"w-[150px] h-[40px] flex flex-col items-center gap-[20px]\"\n        >\n          <img\n            className=\"dark:invert\"\n            src=\"/next.svg\"\n            style={{ width: '100%', height: 'auto' }}\n          />\n        </a>\n      </div> */}\n      <div className=\"relative z-1 pb-10 md:pb-[100px]\">\n        <Section\n          title=\"Tech Stack\"\n          titleProps={{\n            disabledAnimation: false,\n          }}\n        >\n          <div className=\"flex justify-center w-full max-w-7xl h-[96px] my-[30px] rounded-2xl bg-transparent px-3\">\n            <Marquee\n              pauseOnHover\n              autoFill\n              gradient\n              direction=\"right\"\n              gradientColor=\"var(--background)\"\n              speed={60}\n            >\n              <StackItem className=\"icon-[akar-icons--nextjs-fill]\" />\n              <StackItem className=\"icon-[simple-icons--react]\" />\n              <StackItem className=\"icon-[simple-icons--tailwindcss]\" />\n              <StackItem className=\"icon-[teenyicons--framer-outline]\" />\n              <StackItem className=\"icon-[simple-icons--shadcnui]\" />\n              <StackItem className=\"icon-[simple-icons--typescript]\" />\n              <StackItem className=\"icon-[fa6-brands--sass]\" />\n              <StackItem className=\"icon-[teenyicons--eslint-outline]\" />\n              <StackItem className=\"icon-[simple-icons--postcss]\" />\n              <StackItem className=\"icon-[simple-icons--nextra]\" />\n              <StackItem className=\"icon-[line-md--iconify1]\" />\n            </Marquee>\n          </div>\n        </Section>\n        <Section\n          title=\"Features\"\n          description={t('featuresDesc')}\n        >\n          <div className=\"flex justify-center w-full max-w-7xl\">\n            <HoverEffect items={processedFeatureList} />\n          </div>\n        </Section>\n        <Section\n          title={homeEnhance.quickStatsTitle}\n          description={homeEnhance.quickStatsDesc}\n          className=\"pt-8 md:pt-14\"\n        >\n          <div className=\"w-full max-w-6xl\">\n            <ul className=\"flex flex-wrap justify-center gap-x-6 gap-y-4 border-b border-slate-200 pb-9 dark:border-zinc-700\">\n              {homeEnhance.quickStats.map(item => (\n                <li key={item.label} className=\"w-full max-w-[240px] text-center sm:w-[calc(50%-0.75rem)] lg:w-[calc(25%-1.125rem)]\">\n                  <p className=\"text-2xl font-semibold tracking-tight text-slate-900 dark:text-zinc-100\">{item.value}</p>\n                  <p className=\"mt-1 text-sm text-slate-600 dark:text-zinc-400\">{item.label}</p>\n                </li>\n              ))}\n            </ul>\n\n            <div className=\"mt-14 grid items-start gap-10 md:grid-cols-2\">\n              <article className=\"mx-auto w-full max-w-[28rem]\">\n                <p className=\"mb-4 text-center text-xs font-semibold uppercase tracking-[0.14em] text-slate-500 dark:text-zinc-400\">{homeEnhance.useCasesTitle}</p>\n                <ul className=\"mt-4 space-y-5\">\n                  {homeEnhance.useCases.map(item => (\n                    <li key={item.title}>\n                      <span className=\"inline-flex rounded-full bg-blue-50 px-2.5 py-1 text-xs font-medium text-blue-700 dark:bg-cyan-500/12 dark:text-cyan-300\">\n                        {item.tag}\n                      </span>\n                      <h3 className=\"mt-2 text-base font-semibold text-slate-900 dark:text-zinc-100\">{item.title}</h3>\n                      <p className=\"mt-1 text-sm leading-6 text-slate-700 dark:text-zinc-300\">{item.description}</p>\n                    </li>\n                  ))}\n                </ul>\n              </article>\n\n              <article className=\"mx-auto w-full max-w-[28rem]\">\n                <p className=\"mb-4 text-center text-xs font-semibold uppercase tracking-[0.14em] text-slate-500 dark:text-zinc-400\">{homeEnhance.flowTitle}</p>\n                <ol className=\"relative mx-auto mt-4 max-w-md space-y-7 before:absolute before:bottom-2 before:left-1/2 before:top-2 before:z-0 before:w-px before:-translate-x-1/2 before:bg-blue-200 before:content-[''] dark:before:bg-cyan-500/40\">\n                  {homeEnhance.flow.map((item, index) => (\n                    <li key={item.title} className=\"relative z-10 text-center\">\n                      <span\n                        className=\"absolute left-1/2 top-0 inline-flex h-7 w-7 -translate-x-1/2 items-center justify-center rounded-full bg-blue-100 text-xs font-semibold text-blue-700 dark:bg-cyan-500/20 dark:text-cyan-300\"\n                        aria-hidden\n                      >\n                        {index + 1}\n                      </span>\n                      <h3 className=\"inline-block bg-background px-3 pt-9 text-base font-semibold text-slate-900 dark:text-zinc-100\">{item.title.replace(/^\\d+\\.\\s*/, '')}</h3>\n                      <p className=\"mx-auto mt-1 max-w-xs bg-background px-2 text-sm leading-6 text-slate-700 dark:text-zinc-300\">{item.description}</p>\n                    </li>\n                  ))}\n                </ol>\n              </article>\n            </div>\n\n            <div className=\"mt-16 pt-2 text-center\">\n              <p className=\"text-base font-semibold text-slate-900 dark:text-zinc-100\">{homeEnhance.ctaDescription}</p>\n              <div className=\"mt-4 flex flex-wrap justify-center gap-2\">\n                <a\n                  href={`/${currentLocale}/ai-demo`}\n                  className=\"inline-flex min-h-10 items-center rounded-xl bg-linear-to-r from-[#2563EB] to-[#1D4ED8] px-4 py-2 text-sm font-semibold text-white\"\n                >\n                  {homeEnhance.ctaPrimary}\n                </a>\n                <a\n                  href={`/${currentLocale}/introduction`}\n                  className=\"inline-flex min-h-10 items-center rounded-xl border border-slate-300/80 bg-white px-4 py-2 text-sm font-semibold text-slate-700 dark:border-zinc-700 dark:bg-zinc-900 dark:text-zinc-200\"\n                >\n                  {homeEnhance.ctaSecondary}\n                </a>\n              </div>\n            </div>\n          </div>\n        </Section>\n        <Section\n          title=\"Frequently Asked Questions\"\n          tallPaddingY\n        >\n          <Accordion\n            type=\"single\"\n            collapsible\n            className=\"w-full max-w-5xl px-5\"\n          >\n            {\n              faqs.map((faqItem, index) => (\n                <AccordionItem\n                  value={faqItem.question}\n                  key={index}\n                >\n                  <AccordionTrigger>{faqItem.question}</AccordionTrigger>\n                  <AccordionContent>\n                    {faqItem.answer}\n                  </AccordionContent>\n                </AccordionItem>\n              ))\n            }\n          </Accordion>\n        </Section>\n      </div>\n    </>\n  )\n}\n"
  },
  {
    "path": "src/components/MotionWrapper/FadeIn.tsx",
    "content": "'use client'\n\nimport type { Variants } from 'framer-motion'\nimport { motion, useInView } from 'framer-motion'\nimport { memo, useRef } from 'react'\n\ninterface MotionWrapperFadeInProps {\n  children: React.ReactNode\n  className?: string\n  noVertical?: boolean\n  delay?: number\n  viewTriggerOffset?: boolean\n}\n\nconst fadeUpVariants: Variants = {\n  initial: (noVertical: boolean) => ({\n    opacity: 0,\n    y: noVertical ? 0 : 24,\n  }),\n  animate: {\n    opacity: 1,\n    y: 0,\n  },\n}\n\nexport const MotionWrapperFadeIn = memo(({\n  children,\n  className,\n  noVertical = false,\n  delay = 0,\n  viewTriggerOffset = false,\n}: MotionWrapperFadeInProps) => {\n  const ref = useRef(null)\n  const inView = useInView(ref, {\n    once: true,\n    margin: viewTriggerOffset ? '-100px' : '0px',\n  })\n\n  return (\n    <motion.div\n      animate={inView ? 'animate' : 'initial'}\n      className={className}\n      initial=\"initial\"\n      ref={ref}\n      transition={{\n        duration: 1,\n        delay,\n        ease: [0.25, 0.1, 0.25, 1],\n      }}\n      variants={fadeUpVariants}\n      custom={noVertical}\n    >\n      {children}\n    </motion.div>\n  )\n})\n"
  },
  {
    "path": "src/components/MotionWrapper/Flash.tsx",
    "content": "'use client'\n\nimport type { ReactNode } from 'react'\nimport { motion } from 'framer-motion'\nimport React from 'react'\n\ninterface Props {\n  className?: string\n  disabledAnimation?: boolean\n  disabledHover?: boolean\n  children: ReactNode\n}\n\nexport const MotionWrapperFlash: React.FC<Props> = (props) => {\n  const {\n    disabledAnimation = true,\n    disabledHover = false,\n    children,\n    className,\n  } = props\n\n  if (disabledAnimation) {\n    return children\n  }\n\n  return (\n    <motion.span\n      className={className}\n      initial={{ opacity: 0, scale: 0.8, rotate: -20 }}\n      animate={{ opacity: 1, scale: 1, rotate: 0 }}\n\n      whileHover={\n        !disabledHover\n          ? {\n              scale: 1.1,\n              rotate: 10,\n              transition: { duration: 0.3 },\n            }\n          : {}\n      }\n      transition={{\n        duration: 0.6,\n        ease: [0.2, 0.8, 0.6, 1],\n        scale: {\n          type: 'spring',\n          stiffness: 260,\n        },\n        rotate: {\n          type: 'spring',\n          stiffness: 150,\n        },\n        color: {\n          duration: 0.3,\n        },\n      }}\n    >\n      {children}\n    </motion.span>\n  )\n}\n"
  },
  {
    "path": "src/components/MotionWrapper/index.ts",
    "content": "export * from './FadeIn'\nexport * from './Flash'\n"
  },
  {
    "path": "src/components/PanelParticles/index.tsx",
    "content": "'use client'\n\nimport type { ISourceOptions } from '@tsparticles/engine'\nimport Particles, { initParticlesEngine } from '@tsparticles/react'\nimport { useTheme } from 'nextra-theme-docs'\nimport { useEffect, useMemo } from 'react'\nimport { loadFull } from 'tsparticles'\n\nconst PanelParticles = () => {\n  const { resolvedTheme } = useTheme()\n\n  useEffect(() => {\n    initParticlesEngine(async (engine) => {\n      await loadFull(engine)\n    })\n  }, [])\n\n\n  const options = useMemo<ISourceOptions>(\n    () => ({\n      fpsLimit: 120,\n      interactivity: {\n        events: {\n          onHover: {\n            enable: true,\n            mode: 'grab',\n          },\n        },\n        modes: {\n          push: {\n            quantity: 4,\n          },\n          repulse: {\n            distance: 200,\n            duration: 0.4,\n          },\n        },\n      },\n      particles: {\n        color: {\n          value: resolvedTheme === 'light' ? '#9f9cbf' : '#c1c7d1',\n        },\n        links: {\n          color: {\n            value: resolvedTheme === 'light' ? '#9f9cbf' : '#c1c7d1',\n          },\n          distance: 120,\n          enable: true,\n          opacity: resolvedTheme === 'light' ? 0.2 : 0.1,\n          width: 1,\n        },\n        move: {\n          direction: 'none',\n          enable: true,\n          outModes: {\n            default: 'bounce',\n          },\n          random: false,\n          speed: 1,\n          straight: false,\n        },\n        number: {\n          density: {\n            enable: true,\n          },\n          value: 60,\n        },\n        opacity: {\n          value: resolvedTheme === 'light' ? 0.2 : 0.15,\n        },\n        shape: {\n          type: 'circle',\n        },\n        size: {\n          value: { min: 1, max: 3 },\n        },\n      },\n      detectRetina: true,\n    }),\n    [resolvedTheme],\n  )\n\n  return (\n    <Particles\n      className=\"max-sm:hidden pointer-events-none\"\n      options={options}\n    />\n  )\n}\n\nexport {\n  PanelParticles,\n}\n"
  },
  {
    "path": "src/components/ScrollProgressBar/index.tsx",
    "content": "'use client'\n\nimport { usePathname } from 'next/navigation'\nimport { useCallback, useEffect, useRef, useState } from 'react'\n\ninterface ScrollProgressBarProps {\n  height?: number // 进度条高度，默认 3px\n  colors?: string[] // 渐变色数组，默认彩虹渐变\n  zIndex?: number // z-index 层级，默认 9999\n  smoothness?: number // 平滑度(0-1)，默认 0.15，越小越平滑但响应稍慢\n}\n\nconst defaultColors = [\n  '#00CED1',\n  '#4072ed',\n  '#9370DB',\n]\n\n\nexport default function ScrollProgressBar({\n  height = 4,\n  colors = defaultColors,\n  zIndex = 9999,\n  smoothness = 0.15,\n}: ScrollProgressBarProps) {\n  const [progress, setProgress] = useState(0)\n  const [isVisible, setIsVisible] = useState(false)\n  const pathname = usePathname()\n\n  // 使用 ref 存储动画相关状态，避免重复渲染\n  const rafIdRef = useRef<number | null>(null)\n  const currentProgressRef = useRef(0)\n  const targetProgressRef = useRef(0)\n  const lastScrollTimeRef = useRef(0)\n  const isAnimatingRef = useRef(false)\n\n  // 计算目标滚动进度\n  const calculateTargetProgress = useCallback(() => {\n    const windowHeight = window.innerHeight\n    const documentHeight = document.documentElement.scrollHeight\n    const scrollTop = window.scrollY || document.documentElement.scrollTop\n\n    const scrollableHeight = documentHeight - windowHeight\n\n    if (scrollableHeight <= 0) {\n      return { progress: 0, visible: false }\n    }\n\n    const scrollProgress = (scrollTop / scrollableHeight) * 100\n    const clampedProgress = Math.min(Math.max(scrollProgress, 0), 100)\n\n    return {\n      progress: clampedProgress,\n      visible: scrollTop > 0,\n    }\n  }, [])\n\n  // 平滑动画函数 - 使用 lerp (线性插值) 实现平滑过渡\n  const animateProgress = useCallback(() => {\n    const now = performance.now()\n    const timeSinceLastScroll = now - lastScrollTimeRef.current\n\n    // 计算当前进度到目标进度的差值\n    const diff = targetProgressRef.current - currentProgressRef.current\n\n    // 如果差值很小且已经 200ms 没有滚动，停止动画\n    if (Math.abs(diff) < 0.01 && timeSinceLastScroll > 200) {\n      currentProgressRef.current = targetProgressRef.current\n      setProgress(currentProgressRef.current)\n      isAnimatingRef.current = false\n      return\n    }\n\n    // 使用 lerp 平滑插值\n    currentProgressRef.current += diff * smoothness\n    setProgress(currentProgressRef.current)\n\n    // 继续动画\n    rafIdRef.current = requestAnimationFrame(animateProgress)\n  }, [smoothness])\n\n  // 启动平滑动画\n  const startAnimation = useCallback(() => {\n    if (!isAnimatingRef.current) {\n      isAnimatingRef.current = true\n      animateProgress()\n    }\n  }, [animateProgress])\n\n  // 处理滚动事件\n  const handleScroll = useCallback(() => {\n    lastScrollTimeRef.current = performance.now()\n\n    const { progress: newProgress, visible } = calculateTargetProgress()\n    targetProgressRef.current = newProgress\n    setIsVisible(visible)\n\n    // 启动或继续动画\n    startAnimation()\n  }, [calculateTargetProgress, startAnimation])\n\n  // 处理窗口大小变化\n  const handleResize = useCallback(() => {\n    const { progress: newProgress, visible } = calculateTargetProgress()\n    targetProgressRef.current = newProgress\n    currentProgressRef.current = newProgress\n    setProgress(newProgress)\n    setIsVisible(visible)\n  }, [calculateTargetProgress])\n\n  // 监听滚动和窗口变化\n  useEffect(() => {\n    // 初始化\n    const { progress: initialProgress, visible } = calculateTargetProgress()\n    targetProgressRef.current = initialProgress\n    currentProgressRef.current = initialProgress\n    setProgress(initialProgress)\n    setIsVisible(visible)\n\n    // 使用节流优化滚动事件\n    let scrollTimeout\n    const throttledScroll = () => {\n      clearTimeout(scrollTimeout)\n      handleScroll()\n    }\n\n    window.addEventListener('scroll', throttledScroll, { passive: true })\n    window.addEventListener('resize', handleResize, { passive: true })\n\n    return () => {\n      window.removeEventListener('scroll', throttledScroll)\n      window.removeEventListener('resize', handleResize)\n      if (rafIdRef.current !== null) {\n        cancelAnimationFrame(rafIdRef.current)\n      }\n    }\n  }, [calculateTargetProgress, handleScroll, handleResize])\n\n  // 路由切换时重置\n  useEffect(() => {\n    const timer = setTimeout(() => {\n      const { progress: newProgress, visible } = calculateTargetProgress()\n      targetProgressRef.current = newProgress\n      currentProgressRef.current = newProgress\n      setProgress(newProgress)\n      setIsVisible(visible)\n\n      // 取消正在进行的动画\n      if (rafIdRef.current !== null) {\n        cancelAnimationFrame(rafIdRef.current)\n        isAnimatingRef.current = false\n      }\n    }, 100)\n\n    return () => clearTimeout(timer)\n  }, [pathname, calculateTargetProgress])\n\n  // 生成渐变色字符串\n  const gradientColors = colors.join(', ')\n\n  return (\n    <div\n      className=\"fixed top-0 left-0 right-0 pointer-events-none\"\n      style={{ zIndex }}\n      aria-hidden=\"true\"\n    >\n      <div\n        className=\"origin-left\"\n        style={{\n          height: `${height}px`,\n          width: `${progress}%`,\n          background: `linear-gradient(to right, ${gradientColors})`,\n          opacity: isVisible ? 1 : 0,\n          transition: 'opacity 150ms ease-out',\n          willChange: 'width',\n          // 使用 transform 代替 width 动画以获得更好的性能\n          // 但这里我们保持 width 因为需要精确的进度显示\n        }}\n      />\n    </div>\n  )\n}\n"
  },
  {
    "path": "src/components/ThemeSwitcher/index.tsx",
    "content": "'use client'\n\nimport { Moon, Sun } from 'lucide-react'\nimport { useTheme } from 'nextra-theme-docs'\nimport { Button } from '@/components/ui/button'\nimport { useLocale } from '@/hooks'\n\nexport const ThemeSwitcher = () => {\n  const { setTheme } = useTheme()\n  const { t } = useLocale()\n\n  return (\n    <div className=\"flex justify-start max-sm:justify-center gap-6 py-6\">\n      <div className=\"flex flex-col items-center gap-2\">\n        <Button\n          variant=\"secondary\"\n          size=\"icon\"\n          onClick={() => setTheme('light')}\n          aria-label={t('themeSwitcher.lightAria')}\n        >\n          <Sun className=\"h-[1.5rem] w-[1.5rem]\" />\n        </Button>\n        <span className=\"text-sm text-muted-foreground\">{ t('themeSwitcher.light') }</span>\n      </div>\n\n      <div className=\"flex flex-col items-center gap-2\">\n        <Button\n          variant=\"secondary\"\n          size=\"icon\"\n          onClick={() => setTheme('dark')}\n          aria-label={t('themeSwitcher.darkAria')}\n        >\n          <Moon className=\"h-[1.5rem] w-[1.5rem]\" />\n        </Button>\n        <span className=\"text-sm text-muted-foreground\">{ t('themeSwitcher.dark') }</span>\n      </div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "src/components/TitleBadge/index.tsx",
    "content": "'use client'\nimport type { ReactNode } from 'react'\nimport clsx from 'clsx'\nimport { motion } from 'framer-motion'\n\ninterface Props {\n  className?: string\n  children?: ReactNode\n}\n\nexport const TitleBadge = ({\n  className,\n  children = 'NEW',\n}: Props) => {\n  return (\n    <motion.span\n      animate={{ backgroundPosition: ['0% 50%', '100% 50%', '0% 50%'] }}\n      transition={{ duration: 2, repeat: Infinity, ease: 'linear' }}\n      className={clsx(\n        'bg-gradient-to-r from-blue-500 via-purple-500 to-pink-500',\n        'bg-[length:200%_100%]',\n        'ml-[6px] py-[4px] px-[4.5px]',\n        'font-semibold text-[11px] rounded-[6px]',\n        'text-white',\n        'leading-[1]',\n        className,\n      )}\n    >\n      {children}\n    </motion.span>\n  )\n}\n"
  },
  {
    "path": "src/components/auth/login-form.client.tsx",
    "content": "'use client'\n\nimport dynamic from 'next/dynamic'\n\nconst LoginForm = dynamic(() => import('@/components/auth/login-form'), {\n  ssr: false,\n})\n\nexport default function LoginFormClient() {\n  return <LoginForm />\n}\n"
  },
  {
    "path": "src/components/auth/login-form.tsx",
    "content": "'use client'\n\nimport { useEffect, useMemo, useState } from 'react'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { LoaderOne } from '@/components/ui/loader'\nimport { Label } from '@/components/ui/label'\nimport { useLocale } from '@/hooks'\nimport { useRouter } from 'next/navigation'\nimport { toast } from 'sonner'\n\nconst STORAGE_KEY = 'auth:userEmail'\n\ntype ErrorType = 'invalidEmail' | 'passwordRequired' | 'storage' | null\n\nexport default function LoginForm() {\n  const { currentLocale, t } = useLocale()\n  const router = useRouter()\n  const [email, setEmail] = useState('')\n  const [password, setPassword] = useState('')\n  const [error, setError] = useState<ErrorType>(null)\n  const [googleLoading, setGoogleLoading] = useState(false)\n  const [submitLoading, setSubmitLoading] = useState(false)\n  const [pageLoading, setPageLoading] = useState(true)\n\n  useEffect(() => {\n    const timer = window.setTimeout(() => {\n      setPageLoading(false)\n    }, 700)\n\n    return () => window.clearTimeout(timer)\n  }, [])\n\n  const onSubmit = (event: React.FormEvent<HTMLFormElement>) => {\n    event.preventDefault()\n    setError(null)\n    if (submitLoading || googleLoading) {\n      return\n    }\n\n    if (!email || !/\\S+@\\S+\\.\\S+/.test(email)) {\n      setError('invalidEmail')\n      return\n    }\n\n    if (!password) {\n      setError('passwordRequired')\n      return\n    }\n\n    try {\n      setSubmitLoading(true)\n      window.localStorage.setItem(STORAGE_KEY, email)\n      toast.success(t('auth.success'))\n      window.dispatchEvent(new Event('auth:changed'))\n      window.setTimeout(() => {\n        router.replace(`/${currentLocale}`)\n        setSubmitLoading(false)\n      }, 1200)\n    } catch {\n      setSubmitLoading(false)\n      setError('storage')\n    }\n  }\n\n  const onGoogleLogin = () => {\n    if (googleLoading || submitLoading) {\n      return\n    }\n    setError(null)\n    setGoogleLoading(true)\n\n    // TODO: replace with real Google OAuth when backend is available.\n    window.setTimeout(() => {\n      try {\n        const googleEmail = 'jane.doe@gmail.com'\n        window.localStorage.setItem(STORAGE_KEY, googleEmail)\n        toast.success(t('auth.success'))\n        window.dispatchEvent(new Event('auth:changed'))\n        window.setTimeout(() => {\n          router.replace(`/${currentLocale}`)\n        }, 600)\n      } catch {\n        setError('storage')\n      } finally {\n        setGoogleLoading(false)\n      }\n    }, 900)\n  }\n\n  const errorMessage = useMemo(() => {\n    if (!error) {\n      return null\n    }\n\n    if (error === 'invalidEmail') {\n      return t('auth.invalidEmail')\n    }\n\n    if (error === 'passwordRequired') {\n      return t('auth.passwordRequired')\n    }\n\n    return t('auth.storageError')\n  }, [error, t])\n\n  if (pageLoading) {\n    return (\n      <div className=\"flex min-h-[60vh] w-full items-center justify-center\">\n        <div className=\"flex flex-col items-center gap-3 text-sm text-muted-foreground\">\n          <LoaderOne />\n          <span>{t('auth.loading')}</span>\n        </div>\n      </div>\n    )\n  }\n\n  return (\n    <div className=\"mx-auto flex w-full flex-col gap-5 px-4 py-6 sm:max-w-md sm:py-10\">\n      <div className=\"space-y-2 text-center\">\n        <p className=\"text-base font-medium text-foreground/70\">\n          {t('auth.brand')}\n        </p>\n        <h1 className=\"text-xl font-semibold leading-tight text-foreground sm:text-2xl\">\n          {t('auth.welcome')}\n        </h1>\n      </div>\n      <form className=\"flex flex-col gap-4\" onSubmit={onSubmit}>\n        <div className=\"flex flex-col gap-2\">\n          <Label htmlFor=\"email\">{t('auth.email')}</Label>\n          <Input\n            id=\"email\"\n            type=\"email\"\n            value={email}\n            placeholder={t('auth.emailPlaceholder')}\n            className=\"h-11 rounded-full bg-muted/70\"\n            onChange={(event) => {\n              setEmail(event.target.value)\n              if (error) {\n                setError(null)\n              }\n            }}\n            required\n          />\n        </div>\n        <div className=\"flex flex-col gap-2\">\n          <Label htmlFor=\"password\">{t('auth.password')}</Label>\n          <Input\n            id=\"password\"\n            type=\"password\"\n            value={password}\n            placeholder={t('auth.passwordPlaceholder')}\n            className=\"h-11 rounded-full bg-muted/70\"\n            onChange={(event) => {\n              setPassword(event.target.value)\n              if (error) {\n                setError(null)\n              }\n            }}\n            required\n          />\n        </div>\n        {errorMessage && (\n          <p className=\"text-sm text-destructive\">{errorMessage}</p>\n        )}\n        <Button\n          type=\"submit\"\n          className=\"h-10 w-full rounded-md bg-primary text-primary-foreground hover:bg-primary/90\"\n          disabled={submitLoading || googleLoading}\n          aria-busy={submitLoading}\n        >\n          {submitLoading ? t('auth.googleLoading') : t('auth.submit')}\n        </Button>\n      </form>\n      <div className=\"flex items-center gap-3 text-xs text-muted-foreground\">\n        <span className=\"h-px flex-1 bg-border\" />\n        <span className=\"text-center\">{t('auth.or')}</span>\n        <span className=\"h-px flex-1 bg-border\" />\n      </div>\n      <Button\n        type=\"button\"\n        variant=\"outline\"\n        className=\"h-10 w-full rounded-md\"\n        onClick={onGoogleLogin}\n        disabled={googleLoading || submitLoading}\n        aria-busy={googleLoading}\n      >\n        {googleLoading ? t('auth.googleLoading') : t('auth.google')}\n      </Button>\n      <Button\n        type=\"button\"\n        variant=\"ghost\"\n        className=\"h-9 w-full rounded-md text-muted-foreground\"\n        onClick={() => {\n          router.push(`/${currentLocale}`)\n        }}\n      >\n        {t('auth.backHome')}\n      </Button>\n    </div>\n  )\n}\n"
  },
  {
    "path": "src/components/ui/accordion.tsx",
    "content": "'use client'\n\nimport * as AccordionPrimitive from '@radix-ui/react-accordion'\n\nimport { ChevronDown } from 'lucide-react'\nimport * as React from 'react'\nimport { cn } from '@/lib/utils'\n\n\nconst Accordion = AccordionPrimitive.Root\n\nconst AccordionItem = ({\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>) => {\n  const itemRef = React.useRef<React.ComponentRef<typeof AccordionPrimitive.Item>>(null)\n\n  return (\n    <AccordionPrimitive.Item\n      ref={itemRef}\n      className={cn(\n        'border-b',\n        className,\n      )}\n      {...props}\n    />\n  )\n}\nAccordionItem.displayName = 'AccordionItem'\n\nconst AccordionTrigger = ({\n  className,\n  children,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>) => {\n  const itemRef = React.useRef<React.ComponentRef<typeof AccordionPrimitive.Trigger>>(null)\n  return (\n    <AccordionPrimitive.Header className=\"flex\">\n      <AccordionPrimitive.Trigger\n        ref={itemRef}\n        className={cn(\n          'group flex flex-1 items-center justify-between py-7 font-medium transition-all hover:underline',\n          'text-[18px] font-bold',\n          className,\n        )}\n        {...props}\n      >\n        {children}\n        <ChevronDown className=\"h-4 w-4 shrink-0 transition-transform duration-200 group-data-[state=open]:rotate-180\" />\n      </AccordionPrimitive.Trigger>\n    </AccordionPrimitive.Header>\n  )\n}\nAccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName\n\nconst AccordionContent = ({\n  className,\n  children,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>) => {\n  const itemRef = React.useRef<React.ComponentRef<typeof AccordionPrimitive.Content>>(null)\n\n  return (\n    <AccordionPrimitive.Content\n      ref={itemRef}\n      className={cn(\n        'overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down',\n        'text-[16px]',\n      )}\n      {...props}\n    >\n      <div className={cn('pb-6 pt-0', className)}>{children}</div>\n    </AccordionPrimitive.Content>\n  )\n}\n\nAccordionContent.displayName = AccordionPrimitive.Content.displayName\n\nexport { Accordion, AccordionContent, AccordionItem, AccordionTrigger }\n"
  },
  {
    "path": "src/components/ui/alert.tsx",
    "content": "import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst alertVariants = cva(\n  \"relative grid w-full grid-cols-[0_1fr] items-start gap-y-0.5 rounded-lg border px-4 py-3 text-sm has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] has-[>svg]:gap-x-3 [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current\",\n  {\n    variants: {\n      variant: {\n        default: \"bg-card text-card-foreground\",\n        destructive:\n          \"bg-card text-destructive *:data-[slot=alert-description]:text-destructive/90 [&>svg]:text-current\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n    },\n  }\n)\n\nfunction Alert({\n  className,\n  variant,\n  ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof alertVariants>) {\n  return (\n    <div\n      data-slot=\"alert\"\n      role=\"alert\"\n      className={cn(alertVariants({ variant }), className)}\n      {...props}\n    />\n  )\n}\n\nfunction AlertTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"alert-title\"\n      className={cn(\n        \"col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AlertDescription({\n  className,\n  ...props\n}: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"alert-description\"\n      className={cn(\n        \"col-start-2 grid justify-items-start gap-1 text-sm text-muted-foreground [&_p]:leading-relaxed\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nexport { Alert, AlertTitle, AlertDescription }\n"
  },
  {
    "path": "src/components/ui/button.tsx",
    "content": "import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { Slot } from \"radix-ui\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst buttonVariants = cva(\n  \"inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n  {\n    variants: {\n      variant: {\n        default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n        destructive:\n          \"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40\",\n        outline:\n          \"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50\",\n        secondary:\n          \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n        ghost:\n          \"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50\",\n        link: \"text-primary underline-offset-4 hover:underline\",\n      },\n      size: {\n        default: \"h-9 px-4 py-2 has-[>svg]:px-3\",\n        xs: \"h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3\",\n        sm: \"h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5\",\n        lg: \"h-10 rounded-md px-6 has-[>svg]:px-4\",\n        icon: \"size-9\",\n        \"icon-xs\": \"size-6 rounded-md [&_svg:not([class*='size-'])]:size-3\",\n        \"icon-sm\": \"size-8\",\n        \"icon-lg\": \"size-10\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n      size: \"default\",\n    },\n  }\n)\n\nfunction Button({\n  className,\n  variant = \"default\",\n  size = \"default\",\n  asChild = false,\n  ...props\n}: React.ComponentProps<\"button\"> &\n  VariantProps<typeof buttonVariants> & {\n    asChild?: boolean\n  }) {\n  const Comp = asChild ? Slot.Root : \"button\"\n\n  return (\n    <Comp\n      data-slot=\"button\"\n      data-variant={variant}\n      data-size={size}\n      className={cn(buttonVariants({ variant, size, className }))}\n      {...props}\n    />\n  )\n}\n\nexport { Button, buttonVariants }\n"
  },
  {
    "path": "src/components/ui/card-hover-effect.tsx",
    "content": "'use client'\n\nimport type { ReactNode } from 'react'\nimport { AnimatePresence, motion } from 'framer-motion'\nimport { useState } from 'react'\nimport { cn } from '@/lib/utils'\n\n\nexport const Card = ({\n  className,\n  children,\n}: {\n  className?: string\n  children: React.ReactNode\n}) => {\n  return (\n    <div\n      className={cn(\n        'relative rounded-2xl h-full w-full p-4 overflow-hidden',\n        'border duration-200',\n        'bg-neutral-50 dark:bg-neutral-800',\n        'border-neutral-200/[0.5] dark:border-white/[0.1]',\n        'group-hover:border-neutral-300/[0.6] dark:group-hover:border-primary/[0.8]',\n        className,\n      )}\n    >\n      <div className=\"relative\">\n        <div className=\"p-4\">{children}</div>\n      </div>\n    </div>\n  )\n}\n\nexport const CardIcon = ({\n  className,\n  children,\n}: {\n  className?: string\n  children?: React.ReactNode\n}) => {\n  return (\n    <div className={cn(\n      'flex justify-center items-center',\n      'rounded-[6px]',\n      'text-zinc-600 dark:text-zinc-200',\n      'size-[48px] mb-[20px] bg-red-200',\n      'text-[24px]',\n      'bg-[#e3e3e5] dark:bg-[#1e1e20]',\n      'transition-all duration-300 dark:group-hover:text-primary',\n      className,\n    )}\n    >\n      {children}\n    </div>\n  )\n}\nexport const CardTitle = ({\n  className,\n  children,\n}: {\n  className?: string\n  children: React.ReactNode\n}) => {\n  return (\n    <h4 className={cn(\n      'text-zinc-600 dark:text-zinc-200',\n      'font-bold tracking-wide mt-4',\n      className,\n    )}\n    >\n      {children}\n    </h4>\n  )\n}\n\nexport const CardDescription = ({\n  className,\n  children,\n}: {\n  className?: string\n  children: React.ReactNode\n}) => {\n  return (\n    <p\n      className={cn(\n        'mt-8 tracking-wide leading-relaxed text-sm',\n        'text-zinc-500 dark:text-zinc-300/[0.8]',\n        className,\n      )}\n    >\n      {children}\n    </p>\n  )\n}\n\nexport const HoverEffect = ({\n  items,\n  className,\n}: {\n  items: {\n    title: string\n    description: string\n    link?: string\n    icon: ReactNode\n  }[]\n  className?: string\n}) => {\n  const [hoveredIndex, setHoveredIndex] = useState<number | null>(null)\n\n  return (\n    <div\n      className={cn(\n        'grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 py-[10px]',\n        className,\n      )}\n    >\n      {items.map((item, idx) => (\n        <div\n          key={idx}\n          className=\"relative group block p-2 h-full w-full\"\n          onMouseEnter={() => setHoveredIndex(idx)}\n          onMouseLeave={() => setHoveredIndex(null)}\n        >\n          <AnimatePresence>\n            {hoveredIndex === idx && (\n              <motion.span\n                className=\"z-[-1] absolute inset-0 h-full w-full bg-neutral-200/[0.3] dark:bg-neutral-500/[0.5] block rounded-3xl\"\n                layoutId=\"hoverBackground\"\n                initial={{ opacity: 0 }}\n                animate={{\n                  opacity: 1,\n                  transition: { duration: 0.5 },\n                }}\n                exit={{\n                  opacity: 0,\n                  transition: { duration: 0.3, delay: 0.2 },\n                }}\n              />\n            )}\n          </AnimatePresence>\n          <Card>\n            <CardIcon>{item.icon}</CardIcon>\n            <CardTitle>{item.title}</CardTitle>\n            <CardDescription>{item.description}</CardDescription>\n          </Card>\n        </div>\n      ))}\n    </div>\n  )\n}\n"
  },
  {
    "path": "src/components/ui/card.tsx",
    "content": "import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Card({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card\"\n      className={cn(\n        \"flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground shadow-sm\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction CardHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-header\"\n      className={cn(\n        \"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction CardTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-title\"\n      className={cn(\"leading-none font-semibold\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction CardDescription({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-description\"\n      className={cn(\"text-sm text-muted-foreground\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction CardAction({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-action\"\n      className={cn(\n        \"col-start-2 row-span-2 row-start-1 self-start justify-self-end\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction CardContent({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-content\"\n      className={cn(\"px-6\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction CardFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-footer\"\n      className={cn(\"flex items-center px-6 [.border-t]:pt-6\", className)}\n      {...props}\n    />\n  )\n}\n\nexport {\n  Card,\n  CardHeader,\n  CardFooter,\n  CardTitle,\n  CardAction,\n  CardDescription,\n  CardContent,\n}\n"
  },
  {
    "path": "src/components/ui/flip-words.tsx",
    "content": "'use client'\n\nimport type { TargetAndTransition } from 'framer-motion'\nimport { AnimatePresence, motion } from 'framer-motion'\nimport React, { useCallback, useEffect, useMemo, useState } from 'react'\nimport { useBreakpoint } from '@/hooks'\nimport { cn } from '@/lib/utils'\n\nexport const FlipWords = ({\n  words,\n  duration = 3000,\n  className,\n}: {\n  words: string[]\n  duration?: number\n  className?: string\n}) => {\n  const [currentWord, setCurrentWord] = useState(words[0])\n  const [isAnimating, setIsAnimating] = useState<boolean>(false)\n\n  // thanks for the fix Julian - https://github.com/Julian-AT\n  const startAnimation = useCallback(() => {\n    const word = words[words.indexOf(currentWord) + 1] || words[0]\n    setCurrentWord(word)\n    setIsAnimating(true)\n  }, [currentWord, words])\n\n  useEffect(() => {\n    if (!isAnimating) {\n      setTimeout(() => {\n        startAnimation()\n      }, duration)\n    }\n  }, [isAnimating, duration, startAnimation])\n\n  const { isMd } = useBreakpoint()\n\n  const motionExit = useMemo<TargetAndTransition>(() => {\n    if (isMd) {\n      return {\n        opacity: 0,\n        filter: 'blur(0px)',\n        position: 'absolute',\n      }\n    }\n    return {\n      opacity: 0,\n      y: -40,\n      x: 40,\n      filter: 'blur(8px)',\n      scale: 2,\n      position: 'absolute',\n    }\n  }, [isMd])\n\n  return (\n    <AnimatePresence\n      onExitComplete={() => {\n        setIsAnimating(false)\n      }}\n    >\n      <motion.div\n        initial={{\n          opacity: 0,\n          y: 10,\n        }}\n        animate={{\n          opacity: 1,\n          y: 0,\n        }}\n        transition={{\n          type: 'spring',\n          stiffness: 100,\n          damping: 10,\n        }}\n        exit={motionExit}\n        className={cn(\n          'inline-block relative font-bold text-neutral-700 dark:text-neutral-200',\n          className,\n        )}\n        key={currentWord}\n      >\n        {currentWord.split('').map((letter, index) => (\n          <motion.span\n            key={currentWord + index}\n            initial={{ opacity: 0, y: 10, filter: 'blur(8px)' }}\n            animate={{ opacity: 1, y: 0, filter: 'blur(0px)' }}\n            transition={{\n              delay: index * 0.08,\n              duration: 0.4,\n            }}\n            className=\"inline-block\"\n          >\n            {letter}\n          </motion.span>\n        ))}\n      </motion.div>\n    </AnimatePresence>\n  )\n}\n"
  },
  {
    "path": "src/components/ui/hover-card.tsx",
    "content": "'use client'\n\nimport * as HoverCardPrimitive from '@radix-ui/react-hover-card'\nimport * as React from 'react'\n\nimport { cn } from '@/lib/utils'\n\nconst HoverCard = HoverCardPrimitive.Root\n\nconst HoverCardTrigger = HoverCardPrimitive.Trigger\n\n\nconst HoverCardContent = ({ className, align = 'center', sideOffset = 4, ...props }: React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Content>) => {\n  const itemRef = React.useRef<React.ComponentRef<typeof HoverCardPrimitive.Content>>(null)\n  return (\n    <HoverCardPrimitive.Content\n      ref={itemRef}\n      align={align}\n      sideOffset={sideOffset}\n      className={cn(\n        'z-50 w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-hidden data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',\n        className,\n      )}\n      {...props}\n    />\n  )\n}\nHoverCardContent.displayName = HoverCardPrimitive.Content.displayName\n\nexport { HoverCard, HoverCardContent, HoverCardTrigger }\n"
  },
  {
    "path": "src/components/ui/input.tsx",
    "content": "import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Input({ className, type, ...props }: React.ComponentProps<\"input\">) {\n  return (\n    <input\n      type={type}\n      data-slot=\"input\"\n      className={cn(\n        \"h-9 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm dark:bg-input/30\",\n        \"focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50\",\n        \"aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nexport { Input }\n"
  },
  {
    "path": "src/components/ui/label.tsx",
    "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Label as LabelPrimitive } from \"radix-ui\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Label({\n  className,\n  ...props\n}: React.ComponentProps<typeof LabelPrimitive.Root>) {\n  return (\n    <LabelPrimitive.Root\n      data-slot=\"label\"\n      className={cn(\n        \"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nexport { Label }\n"
  },
  {
    "path": "src/components/ui/link-preview.tsx",
    "content": "'use client'\nimport * as HoverCardPrimitive from '@radix-ui/react-hover-card'\nimport {\n  AnimatePresence,\n  motion,\n  useMotionValue,\n  useSpring,\n} from 'framer-motion'\nimport Image from 'next/image'\nimport Link from 'next/link'\nimport { encode } from 'qss'\nimport React from 'react'\nimport { cn } from '@/lib/utils'\n\ntype LinkPreviewProps = {\n  children: React.ReactNode\n  url: string\n  className?: string\n  width?: number\n  height?: number\n  quality?: number\n} & (\n  | { isStatic: true, imageSrc: string }\n  | { isStatic?: false, imageSrc?: never }\n)\n\nexport const LinkPreview = ({\n  children,\n  url,\n  className,\n  width = 200,\n  height = 125,\n  quality = 50,\n  isStatic = false,\n  imageSrc = '',\n}: LinkPreviewProps) => {\n  let src\n  if (!isStatic) {\n    const params = encode({\n      url,\n      screenshot: true,\n      meta: false,\n      embed: 'screenshot.url',\n      colorScheme: 'dark',\n      'viewport.isMobile': true,\n      'viewport.deviceScaleFactor': 1,\n      'viewport.width': width * 3,\n      'viewport.height': height * 3,\n    })\n    src = `https://api.microlink.io/?${params}`\n  }\n  else {\n    src = imageSrc\n  }\n\n  const [isOpen, setOpen] = React.useState(false)\n\n  const [isMounted, setIsMounted] = React.useState(false)\n\n  React.useEffect(() => {\n    setIsMounted(true)\n  }, [])\n\n  const springConfig = { stiffness: 100, damping: 15 }\n  const x = useMotionValue(0)\n\n  const translateX = useSpring(x, springConfig)\n\n  const handleMouseMove = (event: any) => {\n    const targetRect = event.target.getBoundingClientRect()\n    const eventOffsetX = event.clientX - targetRect.left\n    const offsetFromCenter = (eventOffsetX - targetRect.width / 2) / 2 // Reduce the effect to make it subtle\n    x.set(offsetFromCenter)\n  }\n\n  return (\n    <>\n      {isMounted\n        ? (\n            <div className=\"hidden\">\n              <Image\n                src={src}\n                width={width}\n                height={height}\n                quality={quality}\n                priority\n                alt=\"hidden image\"\n              />\n            </div>\n          )\n        : null}\n\n      <HoverCardPrimitive.Root\n        openDelay={50}\n        closeDelay={100}\n        onOpenChange={(open) => {\n          setOpen(open)\n        }}\n      >\n        <HoverCardPrimitive.Trigger\n          onMouseMove={handleMouseMove}\n          className={cn('font-bold bg-clip-text bg-linear-to-br', className)}\n          href={url}\n          target=\"_blank\"\n        >\n          {children}\n        </HoverCardPrimitive.Trigger>\n\n        <HoverCardPrimitive.Content\n          className=\"aa [transform-origin:var(--radix-hover-card-content-transform-origin)]\"\n          side=\"top\"\n          align=\"center\"\n          sideOffset={10}\n        >\n          <AnimatePresence>\n            {isOpen && (\n              <motion.div\n                initial={{ opacity: 0, y: 20, scale: 0.6 }}\n                animate={{\n                  opacity: 1,\n                  y: 0,\n                  scale: 1,\n                  transition: {\n                    type: 'spring',\n                    stiffness: 260,\n                    damping: 20,\n                  },\n                }}\n                exit={{ opacity: 0, y: 20, scale: 0.6 }}\n                className=\"shadow-xl rounded-xl\"\n                style={{\n                  x: translateX,\n                }}\n              >\n                <Link\n                  href={url}\n                  target=\"_blank\"\n                  className=\"block p-1 bg-white border-2 border-transparent shadow-sm rounded-xl hover:border-neutral-200 dark:hover:border-neutral-800\"\n                  style={{ fontSize: 0 }}\n                >\n                  <Image\n                    src={isStatic ? imageSrc : src}\n                    width={width}\n                    height={height}\n                    quality={quality}\n                    priority\n                    className=\"rounded-lg\"\n                    alt=\"preview image\"\n                  />\n                </Link>\n              </motion.div>\n            )}\n          </AnimatePresence>\n        </HoverCardPrimitive.Content>\n      </HoverCardPrimitive.Root>\n    </>\n  )\n}\n"
  },
  {
    "path": "src/components/ui/loader.tsx",
    "content": "\"use client\";\nimport { motion } from \"motion/react\";\nimport React from \"react\";\n\nexport const LoaderOne = () => {\n  const transition = (x: number) => {\n    return {\n      duration: 1,\n      repeat: Infinity,\n      repeatType: \"loop\" as const,\n      delay: x * 0.2,\n      ease: \"easeInOut\" as const,\n    };\n  };\n  return (\n    <div className=\"flex items-center gap-2\">\n      <motion.div\n        initial={{\n          y: 0,\n        }}\n        animate={{\n          y: [0, 10, 0],\n        }}\n        transition={transition(0)}\n        className=\"h-4 w-4 rounded-full border border-neutral-300 bg-gradient-to-b from-neutral-400 to-neutral-300\"\n      />\n      <motion.div\n        initial={{\n          y: 0,\n        }}\n        animate={{\n          y: [0, 10, 0],\n        }}\n        transition={transition(1)}\n        className=\"h-4 w-4 rounded-full border border-neutral-300 bg-gradient-to-b from-neutral-400 to-neutral-300\"\n      />\n      <motion.div\n        initial={{\n          y: 0,\n        }}\n        animate={{\n          y: [0, 10, 0],\n        }}\n        transition={transition(2)}\n        className=\"h-4 w-4 rounded-full border border-neutral-300 bg-gradient-to-b from-neutral-400 to-neutral-300\"\n      />\n    </div>\n  );\n};\n\nexport const LoaderTwo = () => {\n  const transition = (x: number) => {\n    return {\n      duration: 2,\n      repeat: Infinity,\n      repeatType: \"loop\" as const,\n      delay: x * 0.2,\n      ease: \"easeInOut\" as const,\n    };\n  };\n  return (\n    <div className=\"flex items-center\">\n      <motion.div\n        transition={transition(0)}\n        initial={{\n          x: 0,\n        }}\n        animate={{\n          x: [0, 20, 0],\n        }}\n        className=\"h-4 w-4 rounded-full bg-neutral-200 shadow-md dark:bg-neutral-500\"\n      />\n      <motion.div\n        initial={{\n          x: 0,\n        }}\n        animate={{\n          x: [0, 20, 0],\n        }}\n        transition={transition(0.4)}\n        className=\"h-4 w-4 -translate-x-2 rounded-full bg-neutral-200 shadow-md dark:bg-neutral-500\"\n      />\n      <motion.div\n        initial={{\n          x: 0,\n        }}\n        animate={{\n          x: [0, 20, 0],\n        }}\n        transition={transition(0.8)}\n        className=\"h-4 w-4 -translate-x-4 rounded-full bg-neutral-200 shadow-md dark:bg-neutral-500\"\n      />\n    </div>\n  );\n};\n\nexport const LoaderThree = () => {\n  return (\n    <motion.svg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      width=\"24\"\n      height=\"24\"\n      viewBox=\"0 0 24 24\"\n      fill=\"none\"\n      stroke=\"currentColor\"\n      strokeWidth=\"1\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      className=\"h-20 w-20 stroke-neutral-500 [--fill-final:var(--color-yellow-300)] [--fill-initial:var(--color-neutral-50)] dark:stroke-neutral-100 dark:[--fill-final:var(--color-yellow-500)] dark:[--fill-initial:var(--color-neutral-800)]\"\n    >\n      <motion.path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\" />\n      <motion.path\n        initial={{ pathLength: 0, fill: \"var(--fill-initial)\" }}\n        animate={{ pathLength: 1, fill: \"var(--fill-final)\" }}\n        transition={{\n          duration: 2,\n          ease: \"easeInOut\" as const,\n          repeat: Infinity,\n          repeatType: \"reverse\",\n        }}\n        d=\"M13 3l0 7l6 0l-8 11l0 -7l-6 0l8 -11\"\n      />\n    </motion.svg>\n  );\n};\n\nexport const LoaderFour = ({ text = \"Loading...\" }: { text?: string }) => {\n  return (\n    <div className=\"relative font-bold text-black [perspective:1000px] dark:text-white\">\n      <motion.span\n        animate={{\n          skewX: [0, -40, 0],\n          scaleX: [1, 2, 1],\n        }}\n        transition={{\n          duration: 0.05,\n          repeat: Infinity,\n          repeatType: \"reverse\",\n          repeatDelay: 2,\n          ease: \"linear\" as const,\n          times: [0, 0.2, 0.5, 0.8, 1],\n        }}\n        className=\"relative z-20 inline-block\"\n      >\n        {text}\n      </motion.span>\n      <motion.span\n        className=\"absolute inset-0 text-[#00e571]/50 blur-[0.5px] dark:text-[#00e571]\"\n        animate={{\n          x: [-2, 4, -3, 1.5, -2],\n          y: [-2, 4, -3, 1.5, -2],\n          opacity: [0.3, 0.9, 0.4, 0.8, 0.3],\n        }}\n        transition={{\n          duration: 0.5,\n          repeat: Infinity,\n          repeatType: \"reverse\",\n          ease: \"linear\" as const,\n          times: [0, 0.2, 0.5, 0.8, 1],\n        }}\n      >\n        {text}\n      </motion.span>\n      <motion.span\n        className=\"absolute inset-0 text-[#8b00ff]/50 dark:text-[#8b00ff]\"\n        animate={{\n          x: [0, 1, -1.5, 1.5, -1, 0],\n          y: [0, -1, 1.5, -0.5, 0],\n          opacity: [0.4, 0.8, 0.3, 0.9, 0.4],\n        }}\n        transition={{\n          duration: 0.8,\n          repeat: Infinity,\n          repeatType: \"reverse\",\n          ease: \"linear\" as const,\n          times: [0, 0.3, 0.6, 0.8, 1],\n        }}\n      >\n        {text}\n      </motion.span>\n    </div>\n  );\n};\n\nexport const LoaderFive = ({ text }: { text: string }) => {\n  return (\n    <div className=\"font-sans font-bold [--shadow-color:var(--color-neutral-500)] dark:[--shadow-color:var(--color-neutral-100)]\">\n      {text.split(\"\").map((char, i) => (\n        <motion.span\n          key={i}\n          className=\"inline-block\"\n          initial={{ scale: 1, opacity: 0.5 }}\n          animate={{\n            scale: [1, 1.1, 1],\n            textShadow: [\n              \"0 0 0 var(--shadow-color)\",\n              \"0 0 1px var(--shadow-color)\",\n              \"0 0 0 var(--shadow-color)\",\n            ],\n            opacity: [0.5, 1, 0.5],\n          }}\n          transition={{\n            duration: 0.5,\n            repeat: Infinity,\n            repeatType: \"loop\",\n            delay: i * 0.05,\n            ease: \"easeInOut\" as const,\n            repeatDelay: 2,\n          }}\n        >\n          {char === \" \" ? \"\\u00A0\" : char}\n        </motion.span>\n      ))}\n    </div>\n  );\n};\n"
  },
  {
    "path": "src/components/ui/separator.tsx",
    "content": "'use client'\n\n\nimport * as SeparatorPrimitive from '@radix-ui/react-separator'\nimport * as React from 'react'\n\nimport { cn } from '@/lib/utils'\n\nconst Separator = (\n  {\n    className,\n    orientation = 'horizontal',\n    decorative = true,\n    ...props\n  }: React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>,\n) => {\n  const itemRef = React.useRef<React.ComponentRef<typeof SeparatorPrimitive.Root>>(null)\n\n  return (\n    <SeparatorPrimitive.Root\n      ref={itemRef}\n      decorative={decorative}\n      orientation={orientation}\n      className={cn(\n        'shrink-0 bg-border',\n        orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',\n        className,\n      )}\n      {...props}\n    />\n  )\n}\nSeparator.displayName = SeparatorPrimitive.Root.displayName\n\nexport { Separator }\n"
  },
  {
    "path": "src/components/ui/sonner.tsx",
    "content": "\"use client\"\n\nimport type React from \"react\"\nimport {\n  CircleCheckIcon,\n  InfoIcon,\n  Loader2Icon,\n  OctagonXIcon,\n  TriangleAlertIcon,\n} from \"lucide-react\"\nimport { useTheme } from \"next-themes\"\nimport { Toaster as Sonner, type ToasterProps } from \"sonner\"\n\nconst Toaster = ({ ...props }: ToasterProps) => {\n  const { theme = \"system\" } = useTheme()\n\n  return (\n    <Sonner\n      theme={theme as ToasterProps[\"theme\"]}\n      className=\"toaster group\"\n      icons={{\n        success: <CircleCheckIcon className=\"size-4\" />,\n        info: <InfoIcon className=\"size-4\" />,\n        warning: <TriangleAlertIcon className=\"size-4\" />,\n        error: <OctagonXIcon className=\"size-4\" />,\n        loading: <Loader2Icon className=\"size-4 animate-spin\" />,\n      }}\n      style={\n        {\n          \"--normal-bg\": \"var(--popover)\",\n          \"--normal-text\": \"var(--popover-foreground)\",\n          \"--normal-border\": \"var(--border)\",\n          \"--border-radius\": \"var(--radius)\",\n        } as React.CSSProperties\n      }\n      {...props}\n    />\n  )\n}\n\nexport { Toaster }\n"
  },
  {
    "path": "src/components/ui/toggle.tsx",
    "content": "'use client'\n\nimport type { VariantProps } from 'class-variance-authority'\nimport * as TogglePrimitive from '@radix-ui/react-toggle'\nimport { cva } from 'class-variance-authority'\nimport * as React from 'react'\n\nimport { cn } from '@/lib/utils'\n\nconst toggleVariants = cva(\n  'inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground',\n  {\n    variants: {\n      variant: {\n        default: 'bg-transparent',\n        outline:\n          'border border-input bg-transparent hover:bg-accent hover:text-accent-foreground',\n      },\n      size: {\n        default: 'h-10 px-3',\n        sm: 'h-9 px-2.5',\n        lg: 'h-11 px-5',\n      },\n    },\n    defaultVariants: {\n      variant: 'default',\n      size: 'default',\n    },\n  },\n)\n\nconst Toggle = ({\n  className,\n  variant,\n  size,\n  ...props\n}: React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root> & VariantProps<typeof toggleVariants>) => {\n  const itemRef = React.useRef<React.ComponentRef<typeof TogglePrimitive.Root>>(null)\n\n  return (\n    <TogglePrimitive.Root\n      ref={itemRef}\n      className={cn(toggleVariants({ variant, size, className }))}\n      {...props}\n    />\n  )\n}\n\nToggle.displayName = TogglePrimitive.Root.displayName\n\nexport { Toggle, toggleVariants }\n"
  },
  {
    "path": "src/content/en/_meta.tsx",
    "content": "import type { MetaRecord } from 'nextra'\nimport { TitleBadge } from '@/components/TitleBadge'\n\nexport default {\n  index: {\n    type: 'page',\n    display: 'hidden',\n    theme: {\n      copyPage: false,\n      timestamp: false,\n      layout: 'full',\n      toc: false,\n    },\n  },\n  introduction: {\n    type: 'page',\n    title: 'This is Introduction',\n    theme: {\n      copyPage: false,\n      navbar: true,\n      toc: false,\n    },\n  },\n  login: {\n    type: 'page',\n    title: 'Login',\n    display: 'hidden',\n    theme: {\n      navbar: false,\n      footer: false,\n      toc: false,\n      layout: 'full',\n      timestamp: false,\n    },\n  },\n  'ai-demo': {\n    type: 'page',\n    display: 'hidden',\n    theme: {\n      copyPage: false,\n      toc: false,\n      timestamp: false,\n      layout: 'full',\n    },\n  },\n  docs: {\n    title: '📦 Some Examples',\n    type: 'page',\n  },\n  upgrade: {\n    title: (\n      <span className=\"flex items-center leading-[1]\">\n        What's New\n        <TitleBadge />\n      </span>\n    ),\n    type: 'page',\n  },\n} satisfies MetaRecord\n"
  },
  {
    "path": "src/content/en/ai-demo.mdx",
    "content": "---\ntitle: \"PulseOps AI Workflow Assistant | Landing Page Demo\"\ndescription: \"PulseOps landing page demo for an AI workflow assistant, showcasing positioning, features, and conversion structure for lean teams.\"\n---\n\nimport AIDemoLanding from '@/components/AIDemoLanding'\n\n<AIDemoLanding />\n"
  },
  {
    "path": "src/content/en/docs/_meta.tsx",
    "content": "import type { MetaRecord } from 'nextra'\n\nexport default {\n  // ...\n} satisfies MetaRecord\n"
  },
  {
    "path": "src/content/en/docs/examples/test-tailwind.mdx",
    "content": "# Tailwind CSS Example\n\n## Card Component\n\nHere's an example of a classic card component. It uses Tailwind CSS's utility classes to quickly build responsive layouts, including shadows, rounded corners, and some padding, making it look more elegant and modern.\n\n<div className=\"my-5 max-w-md mx-auto bg-foreground dark:bg-neutral-600 rounded-xl shadow-md border p-6\">\n  <h3 className=\"text-lg font-semibold text-zinc-200 mb-2\">Classic Card</h3>\n  <div className=\"text-zinc-200 mb-4\">\n    Using Tailwind CSS, you can quickly build responsive card components with great default styles and extensibility.\n  </div>\n  <button className=\"bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600 transition\">\n    Action Button\n  </button>\n</div>\n\n## Button State Demo\n\nHere are some examples of different button states, including default, disabled, and success/warning buttons. All buttons use Tailwind CSS's interaction state classes, such as `hover` and `disabled`, to achieve different visual effects.\n\n<div className=\"my-5 flex gap-4 flex-wrap\">\n  <button className=\"bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600 transition\">Default</button>\n  <button className=\"bg-gray-300 text-gray-700 px-4 py-2 rounded cursor-not-allowed\" disabled>Disabled</button>\n  <button className=\"bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600 transition\">Success</button>\n  <button className=\"bg-red-500 text-white px-4 py-2 rounded hover:bg-red-600 transition\">Warning</button>\n</div>\n\n## Alert (Prompt) \n\nAlert boxes are used to notify users of important information or warnings. By using Tailwind CSS's background colors and border styles, you can easily create different types of alert boxes.\n\n<div className=\"my-5 max-w-md mx-auto\">\n  <div className=\"bg-blue-100 border-l-4 border-blue-500 text-blue-700 p-4\">\n    <p className=\"font-bold\">Information Prompt:</p>\n    <p>This is an information prompt box, suitable for showing normal notification information.</p>\n  </div>\n  <div className=\"bg-yellow-100 border-l-4 border-yellow-500 text-yellow-700 p-4 mt-4\">\n    <p className=\"font-bold\">Warning Prompt:</p>\n    <p>This is a warning prompt box, suitable for showing important warning information.</p>\n  </div>\n  <div className=\"bg-red-100 border-l-4 border-red-500 text-red-700 p-4 mt-4\">\n    <p className=\"font-bold\">Error Prompt:</p>\n    <p>This is an error prompt box, suitable for showing error information or requiring correction.</p>\n  </div>\n</div>\n\n## Tags (Labels)\n\nTag components can be used to display the classification or tags of content, helping users quickly understand the type or theme of the content.\n\n<div className=\"my-5 mx-auto\">\n  <div className=\"space-x-2\">\n    <span className=\"inline-block bg-blue-100 text-blue-800 text-xs font-semibold px-2 py-1 rounded-full\">Tag 1</span>\n    <span className=\"inline-block bg-green-100 text-green-800 text-xs font-semibold px-2 py-1 rounded-full\">Tag 2</span>\n    <span className=\"inline-block bg-yellow-100 text-yellow-800 text-xs font-semibold px-2 py-1 rounded-full\">Tag 3</span>\n  </div>\n</div>\n\n## Responsive Layout Grid\n\nResponsive layout grids can automatically adjust the display based on different screen sizes. By using Tailwind CSS's `grid` class, you can easily create flexible layouts that adapt to desktop, tablet, and mobile devices.\n\n<div className=\"my-5 mx-auto grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\n  <div className=\"bg-accent p-4 rounded shadow text-center\">Block 1</div>\n  <div className=\"bg-accent p-4 rounded shadow text-center\">Block 2</div>\n  <div className=\"bg-accent p-4 rounded shadow text-center\">Block 3</div>\n  <div className=\"bg-accent p-4 rounded shadow text-center\">Block 4</div>\n  <div className=\"bg-accent p-4 rounded shadow text-center\">Block 5</div>\n  <div className=\"bg-accent p-4 rounded shadow text-center\">Block 6</div>\n  <div className=\"bg-accent p-4 rounded shadow text-center\">Block 7</div>\n</div>\n\n## Typography (Prose)\n\nTailwind CSS's Typography plugin (`@tailwindcss/typography`) provides excellent typographic styles, especially for Markdown content. Using the `prose` class, you can make text, lists, quotes, and code blocks look beautiful and elegant.\n\n<div className=\"my-5 mx-auto prose dark:prose-invert max-w-3xl\">\n  <h3>Supported Typography Content</h3>\n  <div>\n    Using Tailwind's Typography plugin, you can make originally unstyled Markdown content look great with default typography.\n  </div>\n  <ol>\n    <li>List item example 1</li>\n    <li>List item example 2</li>\n    <li>List item example 3</li>\n  </ol>\n  <blockquote>\n    Do what you should do, and let time take care of the rest.\n  </blockquote>\n  <div>\n    You can insert an inline code snippet:\n    <br />\n    e.g. <code>npm install tailwindcss</code>\n  </div>\n\n  <div>👉 More content can be found at the <a href=\"https://tailwindcss.com/docs\" target=\"_blank\">Tailwind official documentation</a>.</div>\n</div>\n"
  },
  {
    "path": "src/content/en/docs/examples/theme-update.mdx",
    "content": "# Dark Mode\n\nimport { ThemeSwitcher } from '@/components/ThemeSwitcher'\n\n<ThemeSwitcher />\n"
  },
  {
    "path": "src/content/en/docs/i18n.mdx",
    "content": "import { FileTree } from 'nextra/components'\n\n# i18n Support\n\nThis project provides two approaches for internationalization:\n1. Nextra's built-in folder structure internationalization\n2. Custom i18n implementation for components and client-side content\n\n## Nextra's Built-in Internationalization Support\n\nNextra supports multilingual content through folder structure. In the project root directory, you can create folders for different languages, such as:\n\n<FileTree>\n  <FileTree.Folder name=\"src\" defaultOpen>\n    <FileTree.Folder name=\"content\" defaultOpen>\n      <FileTree.Folder name=\"en\" defaultOpen>\n        <FileTree.File name=\"_meta.tsx\" active />\n        <FileTree.File name=\"index.mdx\" />\n        <FileTree.File name=\"introduction.mdx\" />\n      </FileTree.Folder>\n      <FileTree.Folder name=\"zh\" defaultOpen>\n        <FileTree.File name=\"_meta.tsx\" active />\n        <FileTree.File name=\"index.mdx\" />\n        <FileTree.File name=\"introduction.mdx\" />\n      </FileTree.Folder>\n    </FileTree.Folder>\n  </FileTree.Folder>\n</FileTree>\n\nYou can configure the language switcher via the `_meta.tsx` file:\n\n```tsx\nimport type { MetaRecord } from 'nextra'\n\nexport default {\n  index: {\n    type: 'page',\n    display: 'hidden',\n    theme: {\n      timestamp: false,\n      layout: 'full',\n      toc: false,\n    },\n  },\n  introduction: {\n    type: 'page',\n    theme: {\n      navbar: true,\n      toc: false,\n    },\n  },\n} satisfies MetaRecord\n```\n\n## Custom i18n Implementation\n\nFor components and client-side content, we've implemented a type-safe internationalization solution.\n\n### Directory Structure\n\n<FileTree>\n  <FileTree.Folder name=\"src\" defaultOpen>\n    <FileTree.Folder name=\"i18n\" defaultOpen>\n      <FileTree.File name=\"index.ts\" comment=\"Core functionality and type definitions\" />\n      <FileTree.File name=\"en.ts\" comment=\"English JSON language pack\" />\n      <FileTree.File name=\"zh.ts\" comment=\"Chinese JSON language pack\" />\n    </FileTree.Folder>\n    <FileTree.Folder name=\"hooks\" defaultOpen>\n      <FileTree.File name=\"useLocale.ts\" comment=\"Pre-packaged common hooks\" />\n    </FileTree.Folder>\n  </FileTree.Folder>\n</FileTree>\n\n### Language File Example\n\nThe language file structure is as follows (using [`en.ts`](https://github.com/pdsuwwz/nextjs-nextra-starter/blob/main/src/i18n/en.ts) as an example):\n\n```typescript\nexport default {\n  systemTitle: '🚀 My Nextra Starter',\n  banner: {\n    title: '👋 Hey there! Welcome to the Next.js Starter.',\n    more: 'Check it out',\n  },\n\n  badgeTitle: 'Lightweight & Easy 🎉',\n  featureSupport: `🔥 Now with {{feature}} support!`,\n  lastUpdated: 'Last updated on:',\n\n  getStarted: 'Get Started',\n  // ...\n}\n```\n\n### Usage\n\n#### 1. In Components\n\n```tsx\nimport { useLocale } from '@/hooks'\n\nfunction MyComponent() {\n  const { t, currentLocale } = useLocale()\n  \n  return (\n    <div>\n      <h1>{t('home.systemTitle')}</h1>\n      \n      {/* Using variable interpolation */}\n      <div dangerouslySetInnerHTML={{\n        __html: t('home.featureSupport', {\n          feature: '<span>Tailwind CSS v4, Nextra v4</span>',\n        }),\n      }} />\n    </div>\n  )\n}\n```\n\n#### 2. Dynamic Language Switching\n\nSwitch languages via URL paths (e.g., [`/en/introduction`](/en/introduction) and [`/zh/introduction`](/zh/introduction)). The current language is automatically obtained from the URL parameter.\n\n## Type Safety\n\nOur i18n implementation provides complete type safety support:\n\n1. **Auto-completion:** The editor automatically suggests all available translation keys\n2. **Type checking:** Using incorrect keys triggers TypeScript errors\n3. **Nested key support:** Supports dot notation access like `home.title`\n4. **Variable interpolation:** Can use `{{variable}}` syntax in translations\n\n## Advanced Features\n\n### Nested Value Retrieval\n\nThe `getNestedValue` function can retrieve nested values from an object based on dot notation paths:\n\n```typescript\nconst value = getNestedValue(i18nConfig[currentLocale], 'home.title')\n```\n\n### String Interpolation\n\nThe `interpolateString` function supports inserting variables into translation strings:\n\n```typescript\nconst result = interpolateString(\n  'Supports {{feature}}', \n  { feature: 'Tailwind CSS v4' }\n) // \"Supports Tailwind CSS v4\"\n```\n\n### Custom Hooks\n\nThe `useLocale` hook encapsulates language detection and translation functionality, providing:\n\n- `currentLocale`: Current language code\n- `t`: Translation function, supports variable interpolation\n\n## Best Practices\n\n1. **Organize translation files:** Use nested objects to group related translations\n2. **Avoid hardcoded strings:** Always use the `t()` function instead of hardcoded text\n3. **Set default language:** Ensure there's a fallback mechanism for the default language\n4. **Maintain key consistency:** All language files should contain the same keys\n5. **Use TypeScript:** Leverage the type system to ensure translation completeness and correctness\n\n## Practical Example\n\nHere's an example of using i18n in the `SetupHero` component:\n\n```tsx\n'use client'\n\nimport { useLocale } from '@/hooks'\n\nexport function SetupHero() {\n  const { t, currentLocale } = useLocale()\n\n  return (\n    <div>\n      <a href=\"https://github.com/pdsuwwz/nextjs-nextra-starter\">\n        {t('badgeTitle')}\n      </a>\n      \n      <Link href={`/${currentLocale}/upgrade`}>\n        <span dangerouslySetInnerHTML={{\n          __html: t('featureSupport', {\n            feature: `<span>Tailwind CSS v4, Nextra v4</span>`,\n          }),\n        }} />\n      </Link>\n      \n      <Button asChild>\n        <Link href={`/${currentLocale}/introduction`}>\n          {t('getStarted')}\n        </Link>\n      </Button>\n    </div>\n  )\n}\n```\n\n## Further Extensions\n\n- **Language detection:** Add automatic language detection based on browser or user preferences\n- **Number and date formatting:** Integrate the `Intl` API for localized formatting\n- **Pluralization:** Add support for different language pluralization rules\n- **Translation management interface:** Create translation management tools for content editors"
  },
  {
    "path": "src/content/en/docs/index.mdx",
    "content": "---\ntitle: \"Test Overview\"\n---\n\n<h1>This is the overview content</h1>\n"
  },
  {
    "path": "src/content/en/index.mdx",
    "content": "---\ntitle: \"Home Page\"\n---\n\n\nimport HomepageHero from \"@/components/HomepageHero\";\n\n<HomepageHero />\n"
  },
  {
    "path": "src/content/en/introduction.mdx",
    "content": "---\ntitle: \"Introduction\"\n---\n\nimport { Button } from \"@/components/ui/button\"\nimport { Alert, AlertDescription, AlertTitle } from \"@/components/ui/alert\"\n\nimport {\n  HoverCard,\n  HoverCardContent,\n  HoverCardTrigger,\n} from \"@/components/ui/hover-card\"\n\n\n\n# Introduction\n\nA free, open-source, and powerful Template with Next.js + Nextra + TypeScript + Tailwind CSS.\n\n```js\nconsole.log('hello, world')\n```\n\n## Installation & Running\n\n* Install dependencies\n\n```bash\npnpm install\n```\n\n* Local development\n\n```bash\npnpm run dev\n```\n\n\n<Alert>\n  <AlertTitle>Heads up!</AlertTitle>\n  <AlertDescription>\n    You can add components and dependencies to your app using the cli.\n  </AlertDescription>\n</Alert>\n\n---\n\n<HoverCard>\n  <HoverCardTrigger>\n    <Button>\n      😄 Hover Me\n    </Button>\n  </HoverCardTrigger>\n  <HoverCardContent>\n    The React Framework – created and maintained by @vercel.\n  </HoverCardContent>\n</HoverCard>\n\n"
  },
  {
    "path": "src/content/en/login.mdx",
    "content": "---\ntitle: Login\n---\n\nimport LoginForm from '@/components/auth/login-form.client'\n\n<div data-pagefind-ignore=\"all\">\n  <LoginForm />\n</div>\n"
  },
  {
    "path": "src/content/en/upgrade.mdx",
    "content": "---\ntitle: \"What's New\"\n---\n\nimport { Callout } from 'nextra/components'\n\n# 🔥 Major Framework Updates\n\nWe've completed significant core framework upgrades to bring you a better development experience!\n\n<Callout emoji={<span className='icon-[ri--alarm-warning-fill]'></span>} type=\"info\">\nNote\n\nThis is the latest release, and while it has been tested, there may still be some issues that have not been discovered. If you encounter any anomalies or instability, please provide [Feedback](https://github.com/pdsuwwz/nextjs-nextra-starter/issues), and I will fix them as soon as possible.\n</Callout>\n\n### Nextra v4 Updates\n\nNextra v4 is now released with major improvements and new features:\n\n- 🚀 **App Router Support**: Fully transitioned to Next.js App Router, discontinuing Pages Router, and supporting the latest Metadata API.  \n- ⚡ **Faster Page Loading**: Optimized bundle size and performance for a more responsive website.  \n- 🔍 **New Search Engine**: Rust-powered Pagefind delivers faster and more accurate search results.  \n- 🏎️ **Turbopack Support**: Improved development experience, addressing long-standing community requests.  \n- 🌍 **RSC + i18n**: Enhanced internationalization, making multilingual website development easier.  \n- 🎨 **Optimized Theme Styles**: Improved UI design for better visual consistency.  \n- 📱 **Better Mobile Adaptation**: Optimized display and interaction for smaller screens.  \n- 📚 **More Powerful Page Collection**: The new \"Page Map\" now collects `md/mdx` pages and `jsx/tsx` pages from the `app/` directory.  \n- 🛠️ **Remote MDX Rendering**: Supports rendering MDX content from any source while generating proper sidebar navigation.  \n- ✨ **Enhanced Table of Contents (TOC)**: Displays Markdown headings accurately, supporting JSX, code blocks, math formulas, and more.  \n\n\nFor more details, check out the [Nextra v4 Official Migration Guide](https://the-guild.dev/blog/nextra-4)\n\n\n### Tailwind CSS v4 Updates\n\nTailwind CSS v4 has been officially released, introducing several significant improvements and new features:\n\n- 🚀 **New High-Performance Engine**: Full builds are up to 5x faster, and incremental builds are over 100x faster, measured in microseconds.\n- 💎 **Designed for the Modern Web**: Built on cutting-edge CSS features like cascade layers, registered custom properties with `@property`, and `color-mix()`.\n- 🎯 **Simplified Installation**: Fewer dependencies, zero configuration, and just a single line of code in your CSS file.\n- 📦 **First-Party Vite Plugin**: Tight integration for maximum performance and minimum configuration.\n- 🔍 **Automatic Content Detection**: All of your template files are discovered automatically, with no configuration required.\n- 📂 **Built-In Import Support**: No additional tooling necessary to bundle multiple CSS files.\n- 🛠️ **CSS-First Configuration**: A reimagined developer experience where you customize and extend the framework directly in CSS instead of a JavaScript configuration file.\n\nFor more details, please refer to the [Tailwind CSS v4 Upgrade Guide](https://tailwindcss.com/docs/upgrade-guide) and [Tailwind CSS Blog](https://tailwindcss.com/blog/tailwindcss-v4)\n\n\n### Migration Tips\n\nFor a smooth upgrade process, we recommend:\n\n1. Test the upgrade in a development environment first\n2. Check custom component compatibility\n3. Monitor console for any warnings\n4. Follow the official migration guides step by step\n\n### Documentation & Support\n\n- 📘 [Nextra Documentation](https://nextra.site)\n- 🎨 [Tailwind CSS Documentation](https://tailwindcss.com)\n- 🐞 Found an issue? Open an [Issue](https://github.com/pdsuwwz/nextjs-nextra-starter/issues)\n\n### Roadmap\n\nWe'll continue optimizing framework performance and plan to add more useful features. Stay tuned!\n\nIf you find this project useful or like the work I’ve done, please consider clicking the [⭐️ Star](https://github.com/pdsuwwz/nextjs-nextra-starter) button to show your support! Each star motivates me to keep improving. Thank you! 😊\n"
  },
  {
    "path": "src/content/zh/_meta.tsx",
    "content": "import type { MetaRecord } from 'nextra'\nimport { TitleBadge } from '@/components/TitleBadge'\n\nexport default {\n  index: {\n    type: 'page',\n    display: 'hidden',\n    theme: {\n      copyPage: false,\n      timestamp: false,\n      layout: 'full',\n      toc: false,\n    },\n  },\n  introduction: {\n    type: 'page',\n    theme: {\n      copyPage: false,\n      navbar: true,\n      toc: false,\n    },\n  },\n  docs: {\n    title: '📦 示例代码',\n    type: 'page',\n  },\n  'ai-demo': {\n    type: 'page',\n    display: 'hidden',\n    theme: {\n      copyPage: false,\n      toc: false,\n      timestamp: false,\n      layout: 'full',\n    },\n  },\n  login: {\n    type: 'page',\n    title: '登录',\n    display: 'hidden',\n    theme: {\n      navbar: false,\n      footer: false,\n      toc: false,\n      layout: 'full',\n      timestamp: false,\n    },\n  },\n  upgrade: {\n    title: (\n      <span className=\"flex items-center leading-[1]\">\n        新变化\n        <TitleBadge />\n      </span>\n    ),\n    type: 'page',\n  },\n} satisfies MetaRecord\n"
  },
  {
    "path": "src/content/zh/ai-demo.mdx",
    "content": "---\ntitle: \"PulseOps AI 自动化工作流助手｜落地页示例\"\ndescription: \"PulseOps 落地页示例，展示 AI 自动化工作流助手在中小团队中的产品定位、功能与转化结构。\"\n---\n\nimport AIDemoLanding from '@/components/AIDemoLanding'\n\n<AIDemoLanding />\n"
  },
  {
    "path": "src/content/zh/docs/_meta.tsx",
    "content": "import type { MetaRecord } from 'nextra'\n\nexport default {\n  // ...\n} satisfies MetaRecord\n"
  },
  {
    "path": "src/content/zh/docs/examples/test-tailwind.mdx",
    "content": "# Tailwind CSS 示例\n\n## 卡片组件\n\n在这里，我们展示了一个经典的卡片组件。它使用了 Tailwind CSS 的工具类来快速构建响应式布局，包含了阴影、圆角和一些内边距等样式，使其看起来更具层次感和现代感。\n\n<div className=\"my-5 max-w-md mx-auto bg-foreground dark:bg-neutral-600 rounded-xl shadow-md border p-6\">\n  <h3 className=\"text-lg font-semibold text-zinc-200 mb-2\">经典卡片</h3>\n  <div className=\"text-zinc-200 mb-4\">\n    使用 Tailwind CSS 可以快速构建响应式卡片组件，具备良好的默认样式和扩展性。\n  </div>\n  <button className=\"bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600 transition\">\n    操作按钮\n  </button>\n</div>\n\n## 按钮状态演示\n\n这里展示了几个不同状态的按钮，包括默认状态、禁用状态和成功/警告按钮。所有按钮都使用了 Tailwind CSS 的交互状态类，例如 `hover` 和 `disabled`，以实现不同的视觉效果。\n\n<div className=\"my-5 flex gap-4 flex-wrap\">\n  <button className=\"bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600 transition\">默认</button>\n  <button className=\"bg-gray-300 text-gray-700 px-4 py-2 rounded cursor-not-allowed\" disabled>禁用</button>\n  <button className=\"bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600 transition\">成功</button>\n  <button className=\"bg-red-500 text-white px-4 py-2 rounded hover:bg-red-600 transition\">警告</button>\n</div>\n\n## 提示框（Alert）\n\n提示框是通知用户的重要信息或警告的组件。通过 Tailwind CSS 的背景色和边框样式，可以轻松制作不同类型的提示框。\n\n<div className=\"my-5 max-w-md mx-auto\">\n  <div className=\"bg-blue-100 border-l-4 border-blue-500 text-blue-700 p-4\">\n    <p className=\"font-bold\">信息提示：</p>\n    <p>这是一个信息提示框，适用于展示普通的通知信息。</p>\n  </div>\n\n  <div className=\"bg-yellow-100 border-l-4 border-yellow-500 text-yellow-700 p-4 mt-4\">\n    <p className=\"font-bold\">警告提示：</p>\n    <p>这是一个警告提示框，适用于展示重要警告信息。</p>\n  </div>\n\n  <div className=\"bg-red-100 border-l-4 border-red-500 text-red-700 p-4 mt-4\">\n    <p className=\"font-bold\">错误提示：</p>\n    <p>这是一个错误提示框，适用于展示错误信息或需要修正的操作。</p>\n  </div>\n</div>\n\n## 标签组件（Tags）\n\n标签组件可以用来展示内容的分类或标签，帮助用户快速了解内容的类型或主题。\n\n<div className=\"my-5 mx-auto\">\n  <div className=\"space-x-2\">\n    <span className=\"inline-block bg-blue-100 text-blue-800 text-xs font-semibold px-2 py-1 rounded-full\">标签 1</span>\n    <span className=\"inline-block bg-green-100 text-green-800 text-xs font-semibold px-2 py-1 rounded-full\">标签 2</span>\n    <span className=\"inline-block bg-yellow-100 text-yellow-800 text-xs font-semibold px-2 py-1 rounded-full\">标签 3</span>\n  </div>\n</div>\n\n## 响应式布局网格\n\n响应式布局网格可以根据不同屏幕尺寸自动调整显示方式。通过使用 Tailwind CSS 的 `grid` 类，你可以方便地创建灵活的布局，适应桌面、平板和手机等不同设备。\n\n<div className=\"my-5 mx-auto grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\n  <div className=\"bg-accent p-4 rounded shadow text-center\">区块 1</div>\n  <div className=\"bg-accent p-4 rounded shadow text-center\">区块 2</div>\n  <div className=\"bg-accent p-4 rounded shadow text-center\">区块 3</div>\n  <div className=\"bg-accent p-4 rounded shadow text-center\">区块 4</div>\n  <div className=\"bg-accent p-4 rounded shadow text-center\">区块 5</div>\n  <div className=\"bg-accent p-4 rounded shadow text-center\">区块 6</div>\n  <div className=\"bg-accent p-4 rounded shadow text-center\">区块 7</div>\n</div>\n\n## 排版样式（Prose）\n\nTailwind CSS 的 Typography 插件（`@tailwindcss/typography`）为你提供了精美的排版样式，特别适用于 Markdown 内容。使用 `prose` 类，你可以让文本、列表、引用和代码块等内容呈现出优雅的样式。\n\n<div className=\"my-5 mx-auto prose dark:prose-invert max-w-3xl\">\n  <h3>支持的排版内容</h3>\n  <div>\n    使用 Tailwind 的 Typography 插件，可以让原本没有样式的 Markdown 内容拥有很棒的默认排版。\n  </div>\n\n  <ol>\n    <li>列表项示例一</li>\n    <li>列表项示例二</li>\n    <li>列表项示例三</li>\n  </ol>\n\n  <blockquote>\n    做你该做的事，其他的交给时间 ~\n  </blockquote>\n\n  <div>\n    你可以插入一段内联代码：\n    \n    比如 <code>npm install tailwindcss</code>\n  </div>\n\n  <div>👉 更多内容请访问 <a href=\"https://tailwindcss.com/docs\" target=\"_blank\">Tailwind 官方文档</a>。</div>\n</div>\n"
  },
  {
    "path": "src/content/zh/docs/examples/theme-update.mdx",
    "content": "# 暗黑模式\n\nimport { ThemeSwitcher } from '@/components/ThemeSwitcher'\n\n<ThemeSwitcher />\n"
  },
  {
    "path": "src/content/zh/docs/i18n.mdx",
    "content": "import { FileTree } from 'nextra/components'\n\n# 国际化支持 (i18n)\n\n本项目提供了两种国际化实现方式：\n1. Nextra 内置的文件夹结构国际化\n2. 自定义 i18n 实现，用于组件和客户端内容\n\n## Nextra 内置的国际化支持\n\nNextra 通过文件夹结构来支持多语言内容。在项目根目录下，您可以创建不同语言的文件夹，如：\n\n<FileTree>\n  <FileTree.Folder name=\"src\" defaultOpen>\n    <FileTree.Folder name=\"content\" defaultOpen>\n      <FileTree.Folder name=\"en\" defaultOpen>\n        <FileTree.File name=\"_meta.tsx\" active />\n        <FileTree.File name=\"index.mdx\" />\n        <FileTree.File name=\"introduction.mdx\" />\n      </FileTree.Folder>\n      <FileTree.Folder name=\"zh\" defaultOpen>\n        <FileTree.File name=\"_meta.tsx\" active />\n        <FileTree.File name=\"index.mdx\" />\n        <FileTree.File name=\"introduction.mdx\" />\n      </FileTree.Folder>\n    </FileTree.Folder>\n  </FileTree.Folder>\n</FileTree>\n\n可以通过 `_meta.tsx` 文件配置语言切换器:\n\n```tsx\nimport type { MetaRecord } from 'nextra'\n\nexport default {\n  index: {\n    type: 'page',\n    display: 'hidden',\n    theme: {\n      timestamp: false,\n      layout: 'full',\n      toc: false,\n    },\n  },\n  introduction: {\n    type: 'page',\n    theme: {\n      navbar: true,\n      toc: false,\n    },\n  },\n} satisfies MetaRecord\n```\n\n## 自定义 i18n 实现\n\n对于组件和客户端内容，我们实现了类型安全的国际化解决方案。\n\n### 目录结构\n\n<FileTree>\n  <FileTree.Folder name=\"src\" defaultOpen>\n    <FileTree.Folder name=\"i18n\" defaultOpen>\n      <FileTree.File name=\"index.ts\" comment=\"核心功能和类型定义\" />\n      <FileTree.File name=\"en.ts\" comment=\"英文 json 语言包\" />\n      <FileTree.File name=\"zh.ts\" comment=\"中文 json 语言包\" />\n    </FileTree.Folder>\n    <FileTree.Folder name=\"hooks\" defaultOpen>\n      <FileTree.File name=\"useLocale.ts\" comment=\"封装好的通用 Hooks\" />\n    </FileTree.Folder>\n  </FileTree.Folder>\n</FileTree>\n\n### 语言文件示例\n\n语言文件结构如下（以 [`zh.ts`](https://github.com/pdsuwwz/nextjs-nextra-starter/blob/main/src/i18n/zh.ts) 为例）：\n\n```typescript\nexport default {\n  systemTitle: '🚀 Nextra 启动模板',\n  banner: {\n    title: '👋 嘿，欢迎来到 Next.js 起步模板!',\n    more: '了解详情',\n  },\n\n  badgeTitle: '轻量级、开箱即用 🎉',\n  featureSupport: `🔥 现在支持 {{feature}}！`,\n  lastUpdated: '最后更新于:',\n\n  getStarted: '开始使用',\n  // ...\n}\n```\n\n### 使用方法\n\n#### 1. 在组件中使用\n\n```tsx\nimport { useLocale } from '@/hooks'\n\nfunction MyComponent() {\n  const { t, currentLocale } = useLocale()\n  \n  return (\n    <div>\n      <h1>{t('home.systemTitle')}</h1>\n      \n      {/* 使用变量插值 */}\n      <div dangerouslySetInnerHTML={{\n        __html: t('home.featureSupport', {\n          feature: '<span>Tailwind CSS v4, Nextra v4</span>',\n        }),\n      }} />\n    </div>\n  )\n}\n```\n\n#### 2. 动态切换语言\n\n通过 URL 路径切换语言（例如 [`/en/introduction`](/en/introduction) 和 [`/zh/introduction`](/zh/introduction)）。当前语言会从 URL 参数中自动获取。\n\n## 类型安全\n\n我们的 i18n 实现提供了完整的类型安全支持：\n\n1. **自动补全：** 编辑器中会自动提示所有可用的翻译键\n2. **类型检查：** 使用错误的键会触发 TypeScript 错误\n3. **嵌套键支持：** 支持如 `home.title` 的点表示法访问\n4. **变量插值：** 可以在翻译中使用 `{{variable}}` 语法\n\n## 高级功能\n\n### 嵌套值获取\n\n`getNestedValue` 函数可以根据点表示法路径获取对象中的嵌套值：\n\n```typescript\nconst value = getNestedValue(i18nConfig[currentLocale], 'home.title')\n```\n\n### 字符串插值\n\n`interpolateString` 函数支持在翻译字符串中插入变量：\n\n```typescript\nconst result = interpolateString(\n  '支持 {{feature}}', \n  { feature: 'Tailwind CSS v4' }\n) // \"支持 Tailwind CSS v4\"\n```\n\n### 自定义 Hooks\n\n`useLocale` Hooks 封装了语言检测和翻译功能，提供：\n\n- `currentLocale`: 当前语言代码\n- `t`: 翻译函数，支持变量插值\n\n## 最佳实践\n\n1. **组织翻译文件：** 使用嵌套对象将相关翻译分组\n2. **避免硬编码字符串：** 总是使用 `t()` 函数而不是硬编码文本\n3. **设置默认语言：** 确保有默认语言回退机制\n4. **保持键的一致性：** 所有语言文件中应包含相同的键\n5. **使用 TypeScript：** 利用类型系统确保翻译的完整性和正确性\n\n## 实战示例\n\n以下是 `SetupHero` 组件中使用 i18n 的示例：\n\n```tsx\n'use client'\n\nimport { useLocale } from '@/hooks'\n\nexport function SetupHero() {\n  const { t, currentLocale } = useLocale()\n\n  return (\n    <div>\n      <a href=\"https://github.com/pdsuwwz/nextjs-nextra-starter\">\n        {t('badgeTitle')}\n      </a>\n      \n      <Link href={`/${currentLocale}/upgrade`}>\n        <span dangerouslySetInnerHTML={{\n          __html: t('featureSupport', {\n            feature: `<span>Tailwind CSS v4, Nextra v4</span>`,\n          }),\n        }} />\n      </Link>\n      \n      <Button asChild>\n        <Link href={`/${currentLocale}/introduction`}>\n          {t('getStarted')}\n        </Link>\n      </Button>\n    </div>\n  )\n}\n```\n\n## 进一步扩展\n\n- **语言检测：** 添加基于浏览器或用户偏好的自动语言检测\n- **数字和日期格式化：** 集成 `Intl` API 进行本地化格式化\n- **多元复数：** 添加对不同语言复数规则的支持\n- **翻译管理界面：** 为内容编辑者创建翻译管理工具\n"
  },
  {
    "path": "src/content/zh/docs/index.mdx",
    "content": "---\ntitle: \"测试概览\"\n---\n\n<h1>这是概览内容</h1>\n"
  },
  {
    "path": "src/content/zh/index.mdx",
    "content": "---\ntitle: \"首页\"\n---\n\n\nimport HomepageHero from \"@/components/HomepageHero\";\n\n<HomepageHero />\n"
  },
  {
    "path": "src/content/zh/introduction.mdx",
    "content": "---\ntitle: \"介绍\"\n---\n\nimport { Button } from \"@/components/ui/button\"\nimport { Alert, AlertDescription, AlertTitle } from \"@/components/ui/alert\"\n\nimport {\n  HoverCard,\n  HoverCardContent,\n  HoverCardTrigger,\n} from \"@/components/ui/hover-card\"\n\n\n\n# 简单介绍\n\n一个免费、开源且功能强大的模板，采用 Next.js + Nextra + TypeScript + Tailwind CSS\n\n```js\nconsole.log('hello, world')\n```\n\n## 安装和运行\n\n* 安装依赖\n\n```bash\npnpm install\n```\n\n* 本地开发\n\n```bash\npnpm run dev\n```\n\n\n<Alert>\n  <AlertTitle>Heads up!</AlertTitle>\n  <AlertDescription>\n    You can add components and dependencies to your app using the cli.\n  </AlertDescription>\n</Alert>\n\n---\n\n<HoverCard>\n  <HoverCardTrigger>\n    <Button>\n      😄 Hover Me\n    </Button>\n  </HoverCardTrigger>\n  <HoverCardContent>\n    The React Framework – created and maintained by @vercel.\n  </HoverCardContent>\n</HoverCard>\n\n"
  },
  {
    "path": "src/content/zh/login.mdx",
    "content": "---\ntitle: 登录\n---\n\nimport LoginForm from '@/components/auth/login-form.client'\n\n<div data-pagefind-ignore=\"all\">\n  <LoginForm />\n</div>\n"
  },
  {
    "path": "src/content/zh/upgrade.mdx",
    "content": "---\ntitle: \"新变化\"\n---\n\nimport { Callout } from 'nextra/components'\n\n# 🔥 重大框架升级\n\n本次完成了核心框架的重大升级，为您带来更好的开发体验！\n\n<Callout emoji={<span className='icon-[ri--alarm-warning-fill]'></span>} type=\"info\">\n注意\n\n本版本为最新发布版本，虽然已进行过测试，但仍可能存在一些未被发现的问题。如遇到任何异常或不稳定的情况，请及时[反馈](https://github.com/pdsuwwz/nextjs-nextra-starter/issues)，我会尽快修复。\n</Callout>\n\n### Nextra v4 更新要点\n\nNextra v4 现已发布，带来了诸多重要改进和新特性：\n\n- 🚀 **App Router 支持**：全面切换至 Next.js App Router，淘汰 Pages Router，支持最新的 Metadata API。\n- ⚡ **更快的页面加载**：优化后的打包体积与性能，使网站响应更迅速。\n- 🔍 **全新搜索引擎**：基于 Rust 的 Pagefind 提供更精准、更高效的搜索体验。\n- 🏎️ **Turbopack 支持**：改进开发体验，解决长期的社区需求。\n- 🌍 **RSC + i18n**：增强国际化支持，使多语言网站开发更加便捷。\n- 🎨 **优化主题样式**：改进 UI 设计，增强视觉一致性。\n- 📱 **更好的移动端适配**：针对小屏幕设备优化显示效果和交互体验。\n- 📚 **更强大的目录结构**：新的 “Page Map” 支持收集 md/mdx 与 app/ 目录下的 jsx/tsx 页面。\n- 🛠️ **远程 MDX 渲染**：支持从任意内容源加载 MDX，并正确生成侧边栏导航。\n- ✨ **增强的目录 (TOC)**：精确呈现 Markdown 标题，支持 JSX、代码块、数学公式等内容。\n\n详细信息请参考 [Nextra v4 官方升级指南](https://the-guild.dev/blog/nextra-4)\n\n### Tailwind CSS v4 更新要点\n\nTailwind CSS v4 已正式发布，带来了多个重要的改进和新特性：\n\n- 🚀 **全新高性能引擎**：完整构建速度提升最多 5 倍，增量构建速度提升超过 100 倍，单位为微秒。 \n- 💎 **为现代 Web 设计**：基于前沿的 CSS 特性构建，如层叠层（cascade layers）、带有 `@property` 的自定义属性和 `color-mix()`。 \n- 🎯 **简化安装过程**：更少的依赖，零配置，只需在你的 CSS 文件中添加一行代码。 \n- 📦 **官方 Vite 插件**：紧密集成，最大化性能并最小化配置。 \n- 🔍 **自动内容检测**：自动发现所有模板文件，无需配置。 \n- 📂 **内置导入支持**：无需额外工具即可捆绑多个 CSS 文件。\n- 🛠️ **CSS 优先配置**：重新构思的开发者体验，直接在 CSS 中自定义和扩展框架，无需 tailwind.config 配置文件。\n\n更多详情，请参考 [Tailwind CSS v4 升级指南](https://tailwindcss.com/docs/upgrade-guide) 和 [官方博客](https://tailwindcss.com/blog/tailwindcss-v4)。\n\n\n### 迁移说明\n\n为确保顺利升级，建议：\n\n1. 先在测试环境进行升级验证\n2. 检查自定义组件的兼容性\n3. 查看控制台是否有警告信息\n4. 按照官方迁移指南逐步操作\n\n### 文档与支持\n\n- 📘 [Nextra 官方文档](https://nextra.site)\n- 🎨 [Tailwind CSS 官方文档](https://tailwindcss.com)\n- 🐞 遇到问题？欢迎提交 [Issue](https://github.com/pdsuwwz/nextjs-nextra-starter/issues)\n\n### 后续计划\n\n将持续优化框架性能，并计划添加更多实用功能。敬请期待！\n\n如果你觉得这个项目有帮助，或喜欢我做的工作，欢迎点击项目右上角的 [⭐️ Star](https://github.com/pdsuwwz/nextjs-nextra-starter) 按钮进行支持！每一个星标都是对我最大的鼓励，帮助我不断改进和前进。非常感激你的支持！😊\n"
  },
  {
    "path": "src/hooks/index.ts",
    "content": "export * from './useBreakpoint'\nexport * from './useLocale'\nexport * from './useServerLocale'\n"
  },
  {
    "path": "src/hooks/useBreakpoint.ts",
    "content": "'use client'\n\nimport { useMediaQuery } from 'react-responsive'\n\nexport const useBreakpoint = () => {\n  // sm 640px @media (max-width: 639px) { ... }\n  const isSm = useMediaQuery({ query: '(max-width: 639px)' })\n\n  // md 768px @media (max-width: 767px) { ... }\n  const isMd = useMediaQuery({ query: '(max-width: 767px)' })\n\n  // lg 1024px @media (max-width: 1023px) { ... }\n  const isLg = useMediaQuery({ query: '(max-width: 1023px)' })\n\n  // xl 1280px @media (max-width: 1279px) { ... }\n  const isXl = useMediaQuery({ query: '(max-width: 1279px)' })\n\n  // 2xl 1536px @media (max-width: 1535px) { ... }\n  const is2Xl = useMediaQuery({ query: '(max-width: 1535px)' })\n\n  return { isSm, isMd, isLg, isXl, is2Xl }\n}\n"
  },
  {
    "path": "src/hooks/useLocale.ts",
    "content": "'use client'\n\nimport type { AllLocales, I18nLangKeys, LocaleKeys, PathValue } from '@/i18n'\nimport { useParams } from 'next/navigation' // 改用 next/navigation\nimport { useCallback } from 'react'\nimport { getNestedValue, i18nConfig, interpolateString } from '@/i18n'\n\n// 类型获取给定键的本地化值的类型\ntype LocalizedValue<T, K extends LocaleKeys> = PathValue<T, K> extends string\n  ? string\n  : PathValue<T, K>\n\nexport const useLocale = () => {\n  const params = useParams()\n\n  // 从 URL 参数中获取当前语言\n  const currentLocale = (\n    (params?.lang as I18nLangKeys)\n    || 'en'\n  ) as I18nLangKeys\n\n  const t = useCallback(\n    <K extends LocaleKeys>(\n      key: K,\n      withData: Record<string, any> = {},\n    ): LocalizedValue<AllLocales, K> => {\n      const template = getNestedValue(i18nConfig[currentLocale], key)\n\n      if (typeof template === 'string') {\n        return interpolateString(template, withData) as LocalizedValue<AllLocales, K>\n      }\n\n      return template as LocalizedValue<AllLocales, K>\n    },\n    [currentLocale],\n  )\n\n  return {\n    currentLocale,\n    t,\n  }\n}\n"
  },
  {
    "path": "src/hooks/useServerLocale.ts",
    "content": "import type { AllLocales, I18nLangKeys, LocaleKeys, PathValue } from '@/i18n'\nimport { getNestedValue, i18nConfig, interpolateString } from '@/i18n'\n\n// 类型获取给定键的本地化值的类型\ntype LocalizedValue<T, K extends LocaleKeys> = PathValue<T, K> extends string\n  ? string\n  : PathValue<T, K>\n\ninterface ServerLocaleParams {\n  params: {\n    lang?: string\n  }\n}\n\nexport async function useServerLocale(lang: I18nLangKeys) {\n  // 从参数中获取当前语言\n  const currentLocale = lang\n\n  function t<K extends LocaleKeys>(\n    key: K,\n    withData: Record<string, any> = {},\n  ): LocalizedValue<AllLocales, K> {\n    const template = getNestedValue(i18nConfig[currentLocale], key)\n\n    if (typeof template === 'string') {\n      return interpolateString(template, withData) as LocalizedValue<AllLocales, K>\n    }\n\n    return template as LocalizedValue<AllLocales, K>\n  }\n\n  return {\n    currentLocale,\n    t,\n  }\n}\n"
  },
  {
    "path": "src/i18n/ai-demo.ts",
    "content": "import type { I18nLangKeys } from './index'\nimport { i18nConfig } from './index'\n\ntype HeroCopy = {\n  title: string\n  subtitle: string\n  tryDemo: string\n  bookCall: string\n  startTrial: string\n  trust: string\n}\n\ntype SocialProof = {\n  logos: string[]\n  stats: Array<{ label: string, value: string }>\n}\n\ntype Feature = {\n  title: string\n  description: string\n}\n\ntype Step = {\n  title: string\n  description: string\n}\n\ntype UseCase = {\n  title: string\n  description: string\n}\n\ntype Testimonial = {\n  quote: string\n  name: string\n  role: string\n}\n\nexport type Plan = {\n  name: string\n  price: string\n  description: string\n  points: string[]\n  cta: string\n  highlight?: boolean\n}\n\ntype FAQ = {\n  question: string\n  answer: string\n}\n\ntype FinalCta = {\n  title: string\n  description: string\n  primary: string\n  secondary: string\n}\n\ntype Footer = {\n  productName: string\n  copyright: string\n  contactTitle: string\n  contactEmail: string\n  contactPhone: string\n}\n\nexport type LandingCopy = {\n  nav: {\n    product: string\n    tryDemo: string\n    bookCall: string\n    startTrial: string\n  }\n  hero: HeroCopy\n  socialProofTitle: string\n  socialProof: SocialProof\n  featureTitle: string\n  features: Feature[]\n  howItWorksTitle: string\n  steps: Step[]\n  useCasesTitle: string\n  useCases: UseCase[]\n  demoTitle: string\n  demoDescription: string\n  testimonialsTitle: string\n  testimonials: Testimonial[]\n  pricingTitle: string\n  pricingSubtitle: string\n  plans: Plan[]\n  faqTitle: string\n  faqs: FAQ[]\n  finalCta: FinalCta\n  footer: Footer\n}\n\nexport function getLandingCopy(lang: string): LandingCopy {\n  const safeLang: I18nLangKeys = lang === 'zh' ? 'zh' : 'en'\n  return i18nConfig[safeLang].aiDemo as LandingCopy\n}\n"
  },
  {
    "path": "src/i18n/en.ts",
    "content": "export default {\n  systemTitle: '🚀 My Nextra Starter',\n  banner: {\n    title: '👋 Hey there! Welcome to the Next.js Starter.',\n    more: 'Check it out',\n  },\n  pageTitle: 'On This Page',\n  backToTop: 'Back to top',\n\n  search: {\n    placeholder: 'Search...',\n    noResults: 'No results found',\n    errorText: 'Search error',\n    loading: 'Loading...',\n  },\n\n  badgeTitle: 'Lightweight & Easy 🎉',\n  featureSupport: `🔥 Now with {{feature}} support!`,\n  lastUpdated: 'Last updated on:',\n\n  getStarted: 'Get Started',\n\n  themeSwitcher: {\n    light: 'Light Mode',\n    dark: 'Dark Mode',\n    lightAria: 'Switch to light mode',\n    darkAria: 'Switch to dark mode',\n  },\n\n  auth: {\n    login: 'Login',\n    logout: 'Logout',\n    brand: 'Nextra Starter',\n    welcome: 'Welcome back',\n    email: 'Email',\n    emailPlaceholder: 'you@example.com',\n    password: 'Password',\n    passwordPlaceholder: '••••••••',\n    submit: 'Sign in',\n    or: 'or',\n    google: 'Continue with Google',\n    googleLoading: 'Signing in...',\n    loading: 'Loading...',\n    backHome: 'Back to home',\n    success: 'Login successful',\n    invalidEmail: 'Please enter a valid email address.',\n    passwordRequired: 'Please enter your password.',\n    storageError: 'Unable to save login state. Please try again.',\n  },\n\n  featureList: [\n    {\n      title: 'Advanced Tech Stack',\n      description: 'Leveraging efficient React (v19) and support with Next.js, Nextra(v4) and Shadcn UI to build modern applications.',\n    },\n    {\n      title: 'internationalization (i18n)',\n      description: 'Built-in multi-language support for easy i18n of your application, expanding your user base.',\n    },\n    {\n      title: 'TypeScript Safety',\n      description: 'Fully integrated with TypeScript, offering static type checking to reduce runtime errors and enhance code reliability and maintainability.',\n    },\n    {\n      title: 'Iconify Icons',\n      description: 'Integrated with the Iconify icon set, offering a wide range of icons to enhance UI visual presentation.',\n    },\n    {\n      title: 'Tailwind CSS (v4)',\n      description: 'Atomic CSS integrated with Tailwind CSS, enabling efficient design and responsive UI.',\n    },\n    {\n      title: 'Code Standards',\n      description: 'Adheres to best practices with code standards and uses ESLint for quality checks and consistency.',\n    },\n    {\n      title: 'Dark Mode',\n      description: 'Supports dark mode for an enhanced nighttime experience.',\n    },\n    {\n      title: 'Rich Components & Extensible Support',\n      description: 'Offers a range of built-in components and supports flexible custom extensions.',\n    },\n    {\n      title: 'Lightweight Design',\n      description: 'Employs a lightweight design approach, streamlining project setup to focus on content creation.',\n    },\n  ],\n  featuresDesc: 'Easily build modern applications and kickstart your development process.',\n  homeEnhance: {\n    quickStatsTitle: 'Build once, ship repeatedly',\n    quickStatsDesc: 'A practical base for docs, landing pages, and product frontends that need to look and feel ready.',\n    quickStats: [\n      { value: '15 min', label: 'From clone to first page' },\n      { value: 'v16 + v19', label: 'Next.js and React modern stack' },\n      { value: 'i18n Ready', label: 'English and Chinese routing out of the box' },\n      { value: 'Dark Mode', label: 'Theme system already wired' },\n    ],\n    useCasesTitle: 'Signals that matter',\n    useCases: [\n      {\n        title: 'AI SaaS Landing',\n        description: 'Ship a conversion-focused marketing page with reusable sections and clear CTA rhythm.',\n        tag: 'Growth',\n      },\n      {\n        title: 'Dev Docs Hub',\n        description: 'Publish multilingual docs with Nextra structure, search, and clean content organization.',\n        tag: 'Documentation',\n      },\n      {\n        title: 'Blog + Auth Demo',\n        description: 'Start from a practical baseline that includes login flow and frontend auth examples.',\n        tag: 'Product',\n      },\n    ],\n    flowTitle: 'From setup to shipping',\n    flow: [\n      {\n        title: '1. Initialize',\n        description: 'Install dependencies and run the dev server.',\n      },\n      {\n        title: '2. Customize',\n        description: 'Edit sections, i18n copy, and design tokens.',\n      },\n      {\n        title: '3. Launch',\n        description: 'Deploy to Netlify or Vercel with one command.',\n      },\n    ],\n    ctaTitle: 'Starter-ready scenarios',\n    ctaDescription: 'Use the AI demo page as your reference and turn it into your own product narrative in a few focused iterations.',\n    ctaPrimary: 'View AI Demo',\n    ctaSecondary: 'Read Introduction',\n  },\n  faqs: [\n    {\n      question: 'What frameworks and tech stack does this starter template support?',\n      answer: 'This starter template supports Next.js and Nextra, with integrated modern development technologies like Tailwind CSS, Framer Motion, and Shadcn UI components.',\n    },\n    {\n      question: 'How do I start developing with this template?',\n      answer: 'Simply clone our GitHub repository and follow the steps in the documentation to run the installation commands to get started.',\n    },\n    {\n      question: 'What types of projects is this template suitable for?',\n      answer: 'This template is ideal for building fast and efficient modern web applications, including corporate sites, personal blogs, and e-commerce platforms.',\n    },\n    {\n      question: 'How do I add or modify components in the project?',\n      answer: 'You can use the provided component library and follow the instructions in the documentation to customize and extend them to suit your specific needs.',\n    },\n    {\n      question: 'Does the template support multiple languages?',\n      answer: 'Yes, the template includes built-in internationalization (i18n) support, allowing you to easily add and manage multilingual content to expand your app\\'s international user base.',\n    },\n    {\n      question: 'How can I get technical support or help?',\n      answer: 'If you encounter any issues while using the template, please contact us via GitHub @pdsuwwz.',\n    },\n    {\n      question: '🐒 What does the author need most right now?',\n      answer: 'Stars! ⭐️ Coding till bald, just need Stars to heal my soul... 🥺',\n    },\n  ],\n  aiDemo: {\n    nav: {\n      product: 'PulseOps',\n      tryDemo: 'Try Demo',\n      bookCall: 'Book a Call',\n      startTrial: 'Start Free Trial',\n    },\n    hero: {\n      title: 'Automate repetitive ops and ship more every week',\n      subtitle: 'PulseOps helps indie builders and small teams turn SOPs into AI workflows in hours, not weeks.',\n      tryDemo: 'Try Demo',\n      bookCall: 'Book a Call',\n      startTrial: 'Start Free Trial',\n      trust: 'No credit card required · Setup in 10 minutes',\n    },\n    socialProofTitle: 'Social proof',\n    socialProof: {\n      logos: ['Marlow Ke', 'Nina Zhou', 'Evan Lin', 'Luca Ren', 'Iris Qiao'],\n      stats: [\n        { value: '41%', label: 'Average time saved on ops tasks' },\n        { value: '3.6x', label: 'Faster handoff from idea to execution' },\n        { value: '12 hrs', label: 'Recovered weekly focus time per team' },\n      ],\n    },\n    featureTitle: 'Core capabilities built for lean teams',\n    features: [\n      {\n        title: 'Workflow Builder',\n        description: 'Design multi-step automations with plain language prompts and reusable blocks.',\n      },\n      {\n        title: 'AI Task Routing',\n        description: 'Automatically assign tasks to the right person, tool, or bot based on context.',\n      },\n      {\n        title: 'Knowledge Sync',\n        description: 'Connect docs, tickets, and chat history to give your automations live context.',\n      },\n      {\n        title: 'Approval Guardrails',\n        description: 'Set review checkpoints before high-impact actions are executed.',\n      },\n      {\n        title: 'Execution Analytics',\n        description: 'Track success rates, cycle time, and ROI with clear operational dashboards.',\n      },\n      {\n        title: 'Template Library',\n        description: 'Launch proven workflow templates for support, growth, and product ops.',\n      },\n    ],\n    howItWorksTitle: 'How it works',\n    steps: [\n      {\n        title: '1. Map your process',\n        description: 'Upload SOPs or describe a process in plain English.',\n      },\n      {\n        title: '2. Generate and customize',\n        description: 'PulseOps creates a draft automation that your team can refine in minutes.',\n      },\n      {\n        title: '3. Run with control',\n        description: 'Launch workflows with approvals, alerts, and measurable outcomes.',\n      },\n    ],\n    useCasesTitle: 'Common use cases',\n    useCases: [\n      {\n        title: 'Customer support triage',\n        description: 'Classify, summarize, and route tickets before an agent opens them.',\n      },\n      {\n        title: 'Weekly growth reporting',\n        description: 'Collect data, generate summaries, and post actionable updates automatically.',\n      },\n      {\n        title: 'Product launch ops',\n        description: 'Coordinate assets, checklists, and approvals across tools without manual follow-up.',\n      },\n    ],\n    demoTitle: 'Product demo preview',\n    demoDescription: 'A single command center to monitor runs, detect bottlenecks, and trigger next actions.',\n    testimonialsTitle: 'What customers say',\n    testimonials: [\n      {\n        quote: 'We replaced scattered Zap workflows with one clear system. Operations finally feel predictable.',\n        name: 'Maya Chen',\n        role: 'Founder, Marlow Ke Team',\n      },\n      {\n        quote: 'Our four-person team now runs onboarding and support flows with enterprise-level discipline.',\n        name: 'Daniel Ross',\n        role: 'Head of Ops, Evan Lin Studio',\n      },\n    ],\n    pricingTitle: 'Simple pricing that scales with your team',\n    pricingSubtitle: 'Version A emphasizes ROI, cost clarity, and predictable automation throughput.',\n    plans: [\n      {\n        name: 'Starter',\n        price: '$29/mo',\n        description: 'For solo builders validating repeatable workflows.',\n        points: ['Up to 5 active workflows', 'Basic analytics', 'Email support'],\n        cta: 'Try Demo',\n      },\n      {\n        name: 'Growth',\n        price: '$99/mo',\n        description: 'For small teams running cross-functional automations.',\n        points: ['Up to 25 active workflows', 'Approval guardrails', 'Priority support'],\n        cta: 'Start Free Trial',\n        highlight: true,\n      },\n      {\n        name: 'Scale',\n        price: 'Custom',\n        description: 'For teams with advanced security and volume needs.',\n        points: ['Unlimited workflows', 'SSO + audit logs', 'Dedicated success manager'],\n        cta: 'Book a Call',\n      },\n    ],\n    faqTitle: 'FAQ',\n    faqs: [\n      {\n        question: 'How fast can we launch our first workflow?',\n        answer: 'Most teams launch one production workflow in less than a day.',\n      },\n      {\n        question: 'Do we need engineering support to use PulseOps?',\n        answer: 'No. Non-technical operators can build and maintain most workflows.',\n      },\n      {\n        question: 'Can we keep approvals for sensitive actions?',\n        answer: 'Yes. You can require manual approvals at any step in a workflow.',\n      },\n      {\n        question: 'What integrations are available?',\n        answer: 'PulseOps supports popular tools for docs, tickets, chat, and data storage.',\n      },\n      {\n        question: 'Is there a free trial?',\n        answer: 'Yes. You can start a free trial without entering a credit card.',\n      },\n    ],\n    finalCta: {\n      title: 'Cut busywork, increase shipping velocity',\n      description: 'See how much repetitive work your team can automate in the first week.',\n      primary: 'Start Free Trial',\n      secondary: 'Book a Call',\n    },\n    footer: {\n      productName: 'PulseOps',\n      copyright: '© 2026 PulseOps. All rights reserved.',\n      contactTitle: 'Contact',\n      contactEmail: 'hello@pulseops.ai',\n      contactPhone: '+1 (415) 555-0138',\n    },\n  },\n\n}\n"
  },
  {
    "path": "src/i18n/index.ts",
    "content": "import en from './en'\nimport zh from './zh'\n\nexport const i18nConfig = Object.freeze({\n  en,\n  zh,\n})\n\nexport type I18nLangKeys = keyof typeof i18nConfig\nexport interface I18nLangAsyncProps {\n  lang: I18nLangKeys\n}\n\n// 获取所有语言对象的联合类型\nexport type AllLocales = typeof i18nConfig[I18nLangKeys]\n\n\ntype DeepKeys<T> = {\n  [K in keyof T & (string | number)]: T[K] extends object\n    ? `${K & string | number}.${DeepKeys<T[K]>}`\n    : `${K & string | number}`\n}[keyof T & (string | number)]\n\n\nexport type NestedKeyOf<ObjectType extends object> = {\n  [Key in keyof ObjectType & (string | number)]: ObjectType[Key] extends object\n    ? `${Key}` | `${Key}.${NestedKeyOf<ObjectType[Key]>}`\n    : `${Key}`\n}[keyof ObjectType & (string | number)]\n\n// 获取所有可能的键\nexport type LocaleKeys = NestedKeyOf<AllLocales>\n\n\ntype DeepObject = Record<string, any>\n\n// 类型提取给定路径上值的类型\nexport type PathValue<T, P extends string>\n  = P extends `${infer Key}.${infer Rest}`\n    ? Key extends keyof T\n      ? PathValue<T[Key], Rest>\n      : never\n    : P extends keyof T\n      ? T[P]\n      : never\n\n// 获取嵌套值\nexport function getNestedValue<T extends DeepObject, K extends string>(obj: T, path: K): PathValue<T, K> {\n  return path.split('.').reduce((acc, key) => acc && acc[key], obj) as PathValue<T, K>\n}\n\n\n// 插入值表达式\nexport function interpolateString(template: string, context: Record<string, any>): string {\n  return template.replace(/\\{\\{\\s*(\\w+(\\.\\w+)*)\\s*\\}\\}/g, (_, path) => {\n    const value = getNestedValue(context, path.trim())\n    return value !== undefined ? value : `{{${path.trim()}}}`\n  })\n}\n"
  },
  {
    "path": "src/i18n/zh.ts",
    "content": "export default {\n  systemTitle: '🚀 Nextra 启动模板',\n  banner: {\n    title: '👋 嘿，欢迎来到 Next.js 起步模板!',\n    more: '了解详情',\n  },\n  pageTitle: '当前页面',\n  backToTop: '返回顶部',\n\n  search: {\n    placeholder: '搜索...',\n    noResults: '没有搜索结果',\n    errorText: '搜索出错',\n    loading: '加载中...',\n  },\n\n  badgeTitle: '轻量级、开箱即用 🎉',\n  featureSupport: `🔥 现在支持 {{feature}}！`,\n  lastUpdated: '最后更新于:',\n\n  getStarted: '开始使用',\n\n  themeSwitcher: {\n    light: '浅色模式',\n    dark: '深色模式',\n    lightAria: '切换到浅色模式',\n    darkAria: '切换到深色模式',\n  },\n\n  auth: {\n    login: '登录',\n    logout: '退出',\n    brand: 'Nextra 启动模板',\n    welcome: '欢迎回来',\n    email: '邮箱',\n    emailPlaceholder: 'name@example.com',\n    password: '密码',\n    passwordPlaceholder: '请输入密码',\n    submit: '登录',\n    or: '或',\n    google: '使用 Google 登录',\n    googleLoading: '登录中...',\n    loading: '加载中...',\n    backHome: '返回首页',\n    success: '登录成功',\n    invalidEmail: '请输入有效的邮箱地址。',\n    passwordRequired: '请输入密码。',\n    storageError: '无法保存登录状态，请重试。',\n  },\n\n  featureList: [\n    {\n      title: '先进的技术栈',\n      description: '高效的 React (v19) 框架，使用 Next.js、Nextra(v4) 和 Shadcn UI 打造现代化应用',\n    },\n    {\n      title: '国际化支持 (i18n)',\n      description: '内置多语言支持，轻松实现应用的国际化，扩大用户群体',\n    },\n    {\n      title: 'TypeScript 类型安全',\n      description: '全面集成 TypeScript，提供静态类型检查，减少运行时错误，提高代码可靠性和可维护性',\n    },\n    {\n      title: 'Iconify 图标集',\n      description: '纯 CSS 图标, 集成 Iconify 图标集，提供丰富的图标选择，增强 UI 视觉表现',\n    },\n    {\n      title: 'Tailwind CSS (v4)',\n      description: '使用原子化 CSS 框架 Tailwind CSS，快速构建高效设计、响应式界面 UI',\n    },\n    {\n      title: '代码规范',\n      description: '遵循最佳实践的代码规范，结合 ESLint 进行代码质量检查与一致性维护',\n    },\n    {\n      title: '暗黑模式',\n      description: '支持暗黑模式，提供更好的夜间使用体验',\n    },\n    {\n      title: '丰富组件 & 支持自由扩展',\n      description: '提供丰富的预置组件，并支持灵活的自定义扩展',\n    },\n    {\n      title: '轻量化设计',\n      description: '采用轻量化设计，精简项目设置，专注于内容编写',\n    },\n  ],\n  featuresDesc: '轻松构建现代应用，快速启动您的开发流程',\n  homeEnhance: {\n    quickStatsTitle: '一次搭好，持续交付',\n    quickStatsDesc: '适合文档、落地页与产品前台场景的实用基础模板，开箱就能进入可用状态。',\n    quickStats: [\n      { value: '15 分钟', label: '从克隆到首个页面' },\n      { value: 'v16 + v19', label: 'Next.js 与 React 新版本栈' },\n      { value: 'i18n 就绪', label: '内置中英文路由能力' },\n      { value: '暗黑模式', label: '主题系统已打通' },\n    ],\n    useCasesTitle: '关键指标',\n    useCases: [\n      {\n        title: 'AI SaaS 落地页',\n        description: '快速搭建转化导向的营销页面，模块可复用，CTA 节奏清晰。',\n        tag: '增长',\n      },\n      {\n        title: '开发文档中心',\n        description: '基于 Nextra 结构发布多语言文档，搜索与内容组织开箱即用。',\n        tag: '文档',\n      },\n      {\n        title: '博客 + 登录示例',\n        description: '从可落地的基础骨架开始，内含登录流程与前端鉴权示例。',\n        tag: '产品',\n      },\n    ],\n    flowTitle: '从初始化到上线',\n    flow: [\n      {\n        title: '1. 初始化',\n        description: '安装依赖并启动本地开发环境。',\n      },\n      {\n        title: '2. 定制化',\n        description: '调整模块、国际化文案与设计变量。',\n      },\n      {\n        title: '3. 发布上线',\n        description: '一键部署到 Netlify 或 Vercel。',\n      },\n    ],\n    ctaTitle: '适用场景',\n    ctaDescription: '可直接参考 AI Demo 的信息架构与视觉节奏，快速打磨成你自己的产品叙事页面。',\n    ctaPrimary: '查看 AI Demo',\n    ctaSecondary: '阅读介绍',\n  },\n  faqs: [\n    {\n      question: '这个启动模板支持哪些框架和技术栈？',\n      answer: '本启动模板支持 Next.js 和 Nextra，并集成了 Tailwind CSS、Framer Motion、Shadcn UI 组件等现代开发技术栈。',\n    },\n    {\n      question: '我如何开始使用这个模板进行开发？',\n      answer: '只需克隆我们的 GitHub 仓库并按照文档中的步骤运行安装命令，即可开始使用本模板进行开发。',\n    },\n    {\n      question: '这个模板适合哪些类型的项目？',\n      answer: '该模板适合用于创建快速、高效的现代 Web 应用程序，包括企业站点、个人博客、电子商务平台等。',\n    },\n    {\n      question: '如何添加或修改项目中的组件？',\n      answer: '可以使用提供的组件库，按照文档中的说明进行自定义和扩展，以适应您的具体需求。',\n    },\n    {\n      question: '模板是否提供多语言支持？',\n      answer: '是的，模板内置国际化 (i18n) 功能，可以轻松添加和管理多语言内容，扩大应用的国际用户群。',\n    },\n    {\n      question: '如何获得技术支持或帮助？',\n      answer: '如果在使用过程中遇到问题，请通过 GitHub @pdsuwwz 与我们联系。',\n    },\n    {\n      question: '🐒 作者现在最缺什么？',\n      answer: '缺 Star！⭐️ 每天写代码写到秃头，就指望这点 Star 安慰我受伤的心灵... 社畜的快乐就这么简单！',\n    },\n  ],\n  aiDemo: {\n    nav: {\n      product: 'PulseOps',\n      tryDemo: '试用 Demo',\n      bookCall: '预约咨询',\n      startTrial: '立即免费试用',\n    },\n    hero: {\n      title: '把重复流程交给 AI，让团队每周多产出一倍',\n      subtitle: 'PulseOps 面向独立开发者和小团队，将客服、运营、协作流程快速自动化，缩短交付周期。',\n      tryDemo: '试用 Demo',\n      bookCall: '预约咨询',\n      startTrial: '立即免费试用',\n      trust: '无需信用卡 · 10 分钟可完成首个流程配置',\n    },\n    socialProofTitle: '社会背书',\n    socialProof: {\n      logos: ['马洛可', '周宁禾', '林屿川', '任之远', '乔以南'],\n      stats: [\n        { value: '41%', label: '平均流程处理时间下降' },\n        { value: '3.6x', label: '从需求到执行速度提升' },\n        { value: '12 小时', label: '每周为团队节省可专注时间' },\n      ],\n    },\n    featureTitle: '核心卖点',\n    features: [\n      {\n        title: '可视化流程编排',\n        description: '用自然语言搭建多步骤自动化，非技术成员也能独立维护。',\n      },\n      {\n        title: '智能任务分发',\n        description: '基于上下文自动将任务分配给成员、系统或 AI 代理。',\n      },\n      {\n        title: '知识库联动',\n        description: '打通文档、工单和聊天记录，保证 AI 决策始终有依据。',\n      },\n      {\n        title: '审批与风控',\n        description: '关键动作前可配置人工审批，降低误触发风险。',\n      },\n      {\n        title: '效果追踪看板',\n        description: '实时查看成功率、处理时长、节省成本，结果可量化。',\n      },\n      {\n        title: '行业模板库',\n        description: '内置常见流程模板，开箱即用，减少试错成本。',\n      },\n    ],\n    howItWorksTitle: '三步上手',\n    steps: [\n      {\n        title: '1. 描述你的流程',\n        description: '上传 SOP 或直接输入流程说明。',\n      },\n      {\n        title: '2. 自动生成并微调',\n        description: '系统自动生成可执行流程，你只需做轻量调整。',\n      },\n      {\n        title: '3. 上线并持续优化',\n        description: '配置审批与提醒，按数据持续迭代流程效果。',\n      },\n    ],\n    useCasesTitle: '应用场景',\n    useCases: [\n      {\n        title: '客服工单分诊',\n        description: '自动分类、摘要并分配工单，减少人工预处理时间。',\n      },\n      {\n        title: '周报自动生成',\n        description: '自动汇总关键数据，输出可执行周报结论。',\n      },\n      {\n        title: '产品上线协同',\n        description: '串联素材、检查清单、审批节点，避免上线遗漏。',\n      },\n    ],\n    demoTitle: '产品演示区域',\n    demoDescription: '统一查看流程运行状态、瓶颈环节和下一步建议动作。',\n    testimonialsTitle: '客户评价',\n    testimonials: [\n      {\n        quote: '以前我们靠多个工具拼流程，现在一套系统就能稳定跑起来，运营效率明显提升。',\n        name: '陈明',\n        role: '创始人，马洛可团队',\n      },\n      {\n        quote: '4 人团队也能把客服和增长流程标准化，节省了大量重复沟通。',\n        name: '王琳',\n        role: '运营负责人，林屿川工作室',\n      },\n    ],\n    pricingTitle: '价格方案',\n    pricingSubtitle: '按团队阶段选择，先跑通流程，再逐步扩展。',\n    plans: [\n      {\n        name: 'Starter',\n        price: '¥199/月',\n        description: '适合个人开发者验证自动化流程。',\n        points: ['最多 5 条活跃流程', '基础数据看板', '邮件支持'],\n        cta: '试用 Demo',\n      },\n      {\n        name: 'Growth',\n        price: '¥699/月',\n        description: '适合小团队稳定运行跨部门流程。',\n        points: ['最多 25 条活跃流程', '审批与风控', '优先支持'],\n        cta: '立即免费试用',\n        highlight: true,\n      },\n      {\n        name: 'Scale',\n        price: '定制',\n        description: '适合对安全、规模有更高要求的团队。',\n        points: ['不限流程数', 'SSO 与审计日志', '专属客户成功'],\n        cta: '预约咨询',\n      },\n    ],\n    faqTitle: '常见问题',\n    faqs: [\n      {\n        question: '多快可以上线第一个流程？',\n        answer: '大多数团队可在 1 天内上线首个可运行流程。',\n      },\n      {\n        question: '是否必须有工程师参与？',\n        answer: '不必须。大部分流程可由运营或产品角色独立完成。',\n      },\n      {\n        question: '关键动作是否支持人工审核？',\n        answer: '支持。你可在任意节点加入人工审批。',\n      },\n      {\n        question: '支持哪些常见系统？',\n        answer: '支持文档、工单、聊天协作与数据系统等主流工具。',\n      },\n      {\n        question: '是否有免费试用？',\n        answer: '有，注册即可开始免费试用。',\n      },\n    ],\n    finalCta: {\n      title: '先跑通一条流程，再复制到全团队',\n      description: '现在开始免费试用，快速验证 AI 自动化带来的实际收益。',\n      primary: '立即免费试用',\n      secondary: '预约咨询',\n    },\n    footer: {\n      productName: 'PulseOps',\n      copyright: '© 2026 PulseOps. 保留所有权利。',\n      contactTitle: '联系方式',\n      contactEmail: 'hello@pulseops.ai',\n      contactPhone: '+86 400-888-1024',\n    },\n  },\n\n}\n"
  },
  {
    "path": "src/lib/utils.ts",
    "content": "import type { ClassValue } from 'clsx'\nimport { clsx } from 'clsx'\nimport { twMerge } from 'tailwind-merge'\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs))\n}\n"
  },
  {
    "path": "src/mdx-components.ts",
    "content": "import { useMDXComponents as getDocsMDXComponents } from 'nextra-theme-docs'\nimport { Pre, withIcons } from 'nextra/components'\nimport { GitHubIcon } from 'nextra/icons'\n\nexport const useMDXComponents: typeof getDocsMDXComponents = () => ({\n  ...getDocsMDXComponents({\n    pre: withIcons(Pre, { js: GitHubIcon }),\n  }),\n})\n"
  },
  {
    "path": "src/proxy.ts",
    "content": "export { proxy } from 'nextra/locales'\n\nexport const config = {\n  matcher: [\n    /*\n     * Match all request paths except for the ones starting with:\n     * - api (API routes)\n     * - _next/static (static files)\n     * - _next/image (image optimization files)\n     * - favicon.ico (favicon file)\n     * - img (image files)\n     * - *.xml (XML files like sitemap.xml, RSS feeds, etc.)\n     * - robots.txt (robots file)\n     */\n    '/((?!api|_next/static|_next/image|favicon.ico|img|_pagefind|.*\\\\.xml|robots.txt).*)',\n  ],\n}\n"
  },
  {
    "path": "src/widgets/auth-button.tsx",
    "content": "'use client'\n\nimport Link from 'next/link'\nimport { useEffect, useState } from 'react'\nimport { Button } from '@/components/ui/button'\nimport { useLocale } from '@/hooks'\nimport { cn } from '@/lib/utils'\n\nconst STORAGE_KEY = 'auth:userEmail'\n\ntype AuthButtonProps = {\n  className?: string\n  showOnMobile?: boolean\n}\n\nexport default function AuthButton({ className, showOnMobile }: AuthButtonProps) {\n  const { currentLocale, t } = useLocale()\n  const [email, setEmail] = useState<string | null>(null)\n  const [mounted, setMounted] = useState(false)\n  const visibilityClass = showOnMobile ? '' : 'max-md:hidden'\n\n  useEffect(() => {\n    setMounted(true)\n  }, [])\n\n  useEffect(() => {\n    const syncFromStorage = () => {\n      try {\n        const stored = window.localStorage.getItem(STORAGE_KEY)\n        setEmail(stored)\n      } catch {\n        setEmail(null)\n      }\n    }\n\n    window.addEventListener('storage', syncFromStorage)\n    window.addEventListener('auth:changed', syncFromStorage as EventListener)\n\n    return () => {\n      window.removeEventListener('storage', syncFromStorage)\n      window.removeEventListener('auth:changed', syncFromStorage as EventListener)\n    }\n  }, [])\n\n  useEffect(() => {\n    if (!mounted) {\n      return\n    }\n    try {\n      const stored = window.localStorage.getItem(STORAGE_KEY)\n      setEmail(stored)\n    } catch {\n      setEmail(null)\n    }\n  }, [mounted])\n\n  const onLogout = () => {\n    try {\n      window.localStorage.removeItem(STORAGE_KEY)\n    } finally {\n      window.dispatchEvent(new Event('auth:changed'))\n      setEmail(null)\n    }\n  }\n\n  if (!mounted) {\n    return (\n      <div\n        className={cn(\n          visibilityClass,\n          'flex items-center gap-2',\n          className\n        )}\n      >\n        <span className=\"h-3 w-10 rounded-sm bg-foreground/20 dark:bg-foreground/30 animate-pulse\" aria-hidden=\"true\" />\n        <span className=\"h-3 w-6 rounded-sm bg-foreground/15 dark:bg-foreground/25 animate-pulse\" aria-hidden=\"true\" />\n      </div>\n    )\n  }\n\n  if (!email) {\n    return (\n      <Button\n        asChild\n        variant=\"outline\"\n        size=\"sm\"\n        className={cn(\n          visibilityClass,\n          showOnMobile && 'w-full justify-center',\n          className\n        )}\n      >\n        <Link href={`/${currentLocale}/login`}>\n          {t('auth.login')}\n        </Link>\n      </Button>\n    )\n  }\n\n  return (\n    <div\n      className={cn(\n        visibilityClass,\n        showOnMobile\n          ? 'flex w-full flex-col items-start gap-2'\n          : 'inline-flex items-center gap-2',\n        className\n      )}\n    >\n      <span className=\"text-sm text-foreground/80\">{email}</span>\n      <Button\n        variant=\"outline\"\n        size=\"sm\"\n        className={cn(showOnMobile && 'w-full justify-center')}\n        onClick={onLogout}\n      >\n        {t('auth.logout')}\n      </Button>\n    </div>\n  )\n}\n"
  },
  {
    "path": "src/widgets/locale-toggle.tsx",
    "content": "'use client'\n\nimport clsx from 'clsx'\nimport { addBasePath } from 'next/dist/client/add-base-path'\nimport { usePathname, useRouter } from 'next/navigation'\nimport { useCallback, useEffect } from 'react'\nimport { Toggle } from '@/components/ui/toggle'\nimport { useLocale } from '@/hooks'\n\nconst ONE_YEAR = 365 * 24 * 60 * 60 * 1000\n\n/**\n * 快速切换语言组件，用于覆盖 nextra 原生切换下拉框\n */\nexport default function LocaleToggle({\n  className,\n}: {\n  className?: string\n}) {\n  const { currentLocale } = useLocale()\n  const router = useRouter()\n  const pathname = usePathname()\n\n  const forceHideBanner = useCallback(() => {\n    const banner = document.querySelector('.nextra-banner')\n    if (!banner) {\n      return\n    }\n\n    const isBannerDismissed = localStorage.getItem('starter-banner')\n    if (isBannerDismissed) {\n      banner.classList.add('x:hidden')\n    }\n  }, [])\n\n  useEffect(() => {\n    const observer = new MutationObserver((mutations) => {\n      mutations.forEach(() => {\n        forceHideBanner()\n      })\n    })\n\n    observer.observe(document.body, {\n      childList: true,\n      subtree: true,\n    })\n    forceHideBanner()\n    return () => observer.disconnect()\n  }, [forceHideBanner])\n\n  const changeLocale = useCallback(() => {\n    // 滚动条位置记录\n    const currentPosition = window.scrollY\n    // 检查是否滚动到底部\n    const isAtBottom = (window.innerHeight + window.scrollY) >= document.body.offsetHeight\n\n    const nextHref = {\n      value: '',\n    }\n    if (currentLocale === 'zh') {\n      nextHref.value = addBasePath(pathname.replace(`/zh`, `/en`))\n    }\n    else {\n      nextHref.value = addBasePath(pathname.replace(`/en`, `/zh`))\n    }\n\n    const date = new Date(Date.now() + ONE_YEAR)\n    document.cookie = `NEXT_LOCALE=${currentLocale}; expires=${date.toUTCString()}; path=/`\n\n    router.replace(nextHref.value)\n\n    // 在路由变化后恢复滚动位置\n    requestAnimationFrame(() => {\n      if (isAtBottom) {\n        window.scrollTo(0, document.body.scrollHeight)\n      }\n      else {\n        window.scrollTo(0, currentPosition)\n      }\n    })\n  }, [currentLocale, pathname, router])\n\n  return (\n    <Toggle\n      size=\"sm\"\n      className={clsx([\n        'cursor-pointer',\n        className,\n      ])}\n      onClick={changeLocale}\n    >\n      {\n        currentLocale === 'zh'\n          ? <span className=\"icon-[uil--letter-chinese-a]\" />\n          : <span className=\"icon-[ri--english-input]\" />\n      }\n    </Toggle>\n  )\n}\n"
  },
  {
    "path": "src/widgets/mobile-menu-auth.tsx",
    "content": "'use client'\n\nimport { useEffect, useState } from 'react'\nimport { createPortal } from 'react-dom'\nimport AuthButton from '@/widgets/auth-button'\n\nconst CONTAINER_ATTR = 'data-mobile-auth'\n\nexport default function MobileMenuAuth() {\n  const [container, setContainer] = useState<HTMLElement | null>(null)\n\n  useEffect(() => {\n    const ensureContainer = () => {\n      const mobileNav = document.querySelector('.nextra-mobile-nav')\n      if (!mobileNav) {\n        return\n      }\n\n      const footer = mobileNav.querySelector('.nextra-sidebar-footer')\n      if (!footer || !(footer instanceof HTMLElement)) {\n        return\n      }\n\n      let target = mobileNav.querySelector<HTMLElement>(`[${CONTAINER_ATTR}]`)\n      if (!target) {\n        target = document.createElement('div')\n        target.setAttribute(CONTAINER_ATTR, 'true')\n        target.className = 'px-4 pt-4 pb-2'\n        footer.parentElement?.insertBefore(target, footer)\n      }\n\n      if (target !== container) {\n        setContainer(target)\n      }\n    }\n\n    ensureContainer()\n    const observer = new MutationObserver(ensureContainer)\n    observer.observe(document.body, { childList: true, subtree: true })\n\n    return () => {\n      observer.disconnect()\n    }\n  }, [container])\n\n  if (!container) {\n    return null\n  }\n\n  return createPortal(\n    <AuthButton showOnMobile className=\"w-full\" />,\n    container\n  )\n}\n"
  },
  {
    "path": "src/widgets/navbar-extras.tsx",
    "content": "'use client'\n\nimport AuthButton from '@/widgets/auth-button'\nimport LocaleToggle from '@/widgets/locale-toggle'\nimport MobileMenuAuth from '@/widgets/mobile-menu-auth'\nimport ThemeToggle from '@/widgets/theme-toggle'\n\nexport default function NavbarExtras() {\n  return (\n    <>\n      <LocaleToggle className=\"max-md:hidden\" />\n      <ThemeToggle className=\"max-md:hidden\" />\n      <AuthButton />\n      <MobileMenuAuth />\n    </>\n  )\n}\n"
  },
  {
    "path": "src/widgets/theme-toggle.tsx",
    "content": "'use client'\n\nimport clsx from 'clsx'\nimport { useTheme } from 'nextra-theme-docs'\nimport { useCallback } from 'react'\nimport { Toggle } from '@/components/ui/toggle'\n\n/**\n * 快速切换暗黑模式组件，用于覆盖 nextra 原生切换下拉框\n */\nexport default function ThemeToggle({\n  className,\n}: {\n  className?: string\n}) {\n  const { setTheme, theme } = useTheme()\n\n  const changeTheme = useCallback(() => {\n    if (theme === 'dark') {\n      setTheme('light')\n    }\n    else {\n      setTheme('dark')\n    }\n  }, [setTheme, theme])\n\n  return (\n    <Toggle\n      size=\"sm\"\n      className={clsx([\n        'cursor-pointer',\n        className,\n      ])}\n      onClick={changeTheme}\n    >\n      <span className=\"icon-[ri--sun-fill] dark:icon-[ri--moon-clear-fill]\"></span>\n    </Toggle>\n  )\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"incremental\": true,\n    \"target\": \"ES2017\",\n    \"jsx\": \"react-jsx\",\n    \"lib\": [\n      \"dom\",\n      \"dom.iterable\",\n      \"esnext\"\n    ],\n    \"baseUrl\": \".\",\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"bundler\",\n    \"paths\": {\n      \"@/*\": [\n        \"./src/*\"\n      ]\n    },\n    \"ignoreDeprecations\": \"5.0\",\n    \"resolveJsonModule\": true,\n    \"allowJs\": true,\n    \"strict\": true,\n    \"noEmit\": true,\n    \"esModuleInterop\": true,\n    \"isolatedModules\": true,\n    \"skipLibCheck\": true,\n    \"plugins\": [\n      {\n        \"name\": \"next\"\n      }\n    ]\n  },\n  \"include\": [\n    \"**/*.ts\",\n    \"**/*.tsx\",\n    \".next/types/**/*.ts\",\n    \"next-env.d.ts\",\n    \"./.next/types/**/*.ts\",\n    \".next/dev/types/**/*.ts\"\n  ],\n  \"exclude\": [\n    \"node_modules\"\n  ]\n}\n"
  }
]