Files
test-repo/docs/.vitepress/theme/components/HomeFeatures.vue
T
sanbuphy 80609bf277 refactor(docs): consolidate stage-0 into stage-1 and update routing
- Update homepage links in zh-cn and zh-tw to point to stage-1
- Update internal navigation links within stage-1 index files
- Remove obsolete github-pages-deployment document
- Update sitemap generation script to reflect stage-0 removal
2026-04-02 13:48:55 +08:00

3814 lines
114 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup>
import { ref, onMounted, onUnmounted, computed } from 'vue'
import { useRouter, withBase, useData } from 'vitepress'
import GitHubStars from './GitHubStars.vue'
import VibeStories from './VibeStories.vue'
import { provide } from 'vue'
import stage2LovartCover from '../../../zh-cn/stage-2/frontend/lovart-assets/images/image1.png'
import stage2FigmaCover from '../../../zh-cn/stage-2/frontend/figma-mastergo/images/image8.png'
import stage2DesignToCodeCover from '../../../zh-cn/stage-2/frontend/design-to-code/images/image42.png'
import stage2SupabaseCover from '../../../zh-cn/stage-2/backend/database-supabase/images/image1.png'
import stage2ZeaburCover from '../../../zh-cn/stage-2/backend/zeabur-deployment/images/image1.png'
import stage2DifyCover from '../../../zh-cn/stage-2/ai-capabilities/dify-knowledge-base/images/image1.png'
import stage3ElectronCover from '../../../zh-cn/stage-3/cross-platform/electron-voice-to-text/images/image3.png'
import stage3AgentTeamsCover from '../../../zh-cn/stage-3/core-skills/agent-teams/images/home-cover.svg'
import stage3LongRunningCover from '../../../zh-cn/stage-3/core-skills/long-running-tasks/images/home-cover.svg'
import stage3PersonalBrandCover from '../../../zh-cn/stage-3/personal-brand/personal-website-blog/images/image1.png'
const router = useRouter()
const { site, page, lang } = useData()
const activeTab = ref('home')
const showLangMenu = ref(false)
const topPromoProgress = ref(1)
const topPromoDismissed = ref(false)
const topPromoIntroProgress = ref(0)
const topPromoColorProgress = ref(0)
let topPromoIntroRaf = 0
let topPromoColorRaf = 0
let topPromoColorTimer = 0
const WELCOME_SEEN_KEY = 'easy-vibe-welcome-seen'
// Appendix Scroll Logic
const appendixWrapper = ref(null)
const vibeStoriesSection = ref(null)
const totalPages = ref(1)
const currentPage = ref(0)
const updatePagination = () => {
if (appendixWrapper.value) {
const { scrollLeft, clientWidth, scrollWidth } = appendixWrapper.value
// If scrollWidth is close to clientWidth, only 1 page
if (scrollWidth <= clientWidth + 5) {
totalPages.value = 1
currentPage.value = 0
} else {
totalPages.value = Math.ceil(scrollWidth / clientWidth)
currentPage.value = Math.round(scrollLeft / clientWidth)
}
}
}
const onAppendixScroll = () => {
if (!appendixWrapper.value) return
const { scrollLeft, clientWidth } = appendixWrapper.value
const newPage = Math.round(scrollLeft / clientWidth)
if (currentPage.value !== newPage) {
currentPage.value = newPage
}
}
const scrollToPage = (pageIndex) => {
if (appendixWrapper.value) {
const width = appendixWrapper.value.clientWidth
appendixWrapper.value.scrollTo({
left: pageIndex * width,
behavior: 'smooth'
})
}
}
const scrollAppendixByPage = (direction) => {
const nextPage = Math.min(
totalPages.value - 1,
Math.max(0, currentPage.value + direction)
)
scrollToPage(nextPage)
}
const autoScroll = () => {
if (appendixWrapper.value) {
const { scrollLeft, clientWidth, scrollWidth } = appendixWrapper.value
const maxScroll = scrollWidth - clientWidth
if (scrollLeft >= maxScroll - 20) {
appendixWrapper.value.scrollTo({ left: 0, behavior: 'smooth' })
} else {
appendixWrapper.value.scrollBy({ left: clientWidth, behavior: 'smooth' })
}
}
}
const i18n = {
'zh-cn': {
nav: {
title: 'Easy-Vibe 教程',
home: '首页',
stories: '用户故事',
pm: '零基础入门',
junior: '初中级开发',
senior: '高级开发',
appendix: '附录',
start: '开始学习'
},
stories: {
cat: '用户故事',
title: '看见每一个<br><span class="highlight">闪亮的你</span>',
sub: '加入他们,分享你的 vibe coding 故事',
s1: { title: '放弃月入过万,他在农村小学带孩子们“用AI赶苍蝇”', author: '小学老师小浩' },
s2: { title: '期末考试周,我偷偷用AI造了个“校园闲鱼”', author: '一位大二学生' },
s3: { title: '我给每个学生,做了一个不会累的“学霸同桌”', author: '高中信息技术老师' },
s4: { title: '48岁货车司机,熬了几个通宵,硬是用AI磕出一个出海工具站', author: '货车司机老黄' },
authorPrefix: '讲述者:',
ui: {
prevLabel: '上一则故事',
nextLabel: '下一则故事',
selectLabel: '查看这个故事',
imageAlt: '用户故事封面'
}
},
stage1: {
cat: 'Stage 1 · 零基础入门',
title:
'没有技术背景?<br><span class="highlight">正好。</span>',
sub: '不看专业、不看出身——会说话,你就能做产品。',
cards: [
{
title: '学习地图',
desc: '了解从零基础到全栈开发的完整学习路径,明确每个阶段的目标和收获。',
sub: '全年龄友好',
link: '/zh-cn/stage-1/learning-map/'
},
{
title: '游戏化入门',
desc: '通过制作贪吃蛇等 AI 原生小游戏,体验 AI 编程的魅力,打破对代码的恐惧。',
sub: '边玩边学',
link: '/zh-cn/stage-1/ai-capabilities-through-games/'
},
{
title: '产品原型实战',
desc: '掌握 Vibe Coding 工作流,从想法到可交互原型,独立完成高保真 Web 应用。',
sub: '核心心法',
link: '/zh-cn/stage-1/finding-great-idea/'
}
]
},
stage2: {
cat: 'Stage 2 · 初中级开发',
title: '一个人,<br><span class="highlight">就是一支团队。</span>',
sub: '从前端到后端,从数据库到上线。',
cards: [
{
title: '素材生成 Agent',
headline: '先把素材生产提速。',
desc: '从 Lovart 和 Nanobanana 出发,搭建自己的素材生产工作流和绘图 Agent。',
link: '/zh-cn/stage-2/frontend/lovart-assets/'
},
{
title: 'Figma 与 MasterGo',
headline: '先把设计工具用顺。',
desc: '掌握专业 UI 设计工具的基础操作,理解从设计稿到开发协作的关键链路。',
link: '/zh-cn/stage-2/frontend/figma-mastergo/'
},
{
title: '设计稿转代码',
headline: '把原型真正变成页面。',
desc: '学习如何将设计原型转成可以在浏览器里运行的前端代码,减少手工重搭。',
link: '/zh-cn/stage-2/frontend/design-to-code/'
},
{
title: '真实数据项目',
headline: '连上真正的数据库。',
desc: '在 Supabase 上设计数据表和权限,用真实读写操作支撑你的产品数据层。',
link: '/zh-cn/stage-2/backend/database-supabase/'
},
{
title: '部署上线',
headline: '让世界看到你的作品。',
desc: '使用 CloudBase、Vercel、Zeabur 等平台,一口气打通从代码到公网访问的完整流程。',
link: '/zh-cn/stage-2/backend/zeabur-deployment/'
},
{
title: 'AI 知识库集成',
headline: '让应用接上智能问答。',
desc: '学习用 Dify 构建 AI 应用和知识库,把检索增强能力接进你的真实产品。',
link: '/zh-cn/stage-2/ai-capabilities/dify-knowledge-base/'
}
]
},
stage3: {
cat: 'Stage 3 · 高级开发',
title: '产品和结果,<br><span class="highlight">我全都要。</span>',
sub: '突破时间与设备限制,让 AI 产品随处可见。',
cards: [
{
title: '跨平台桌面应用',
desc: '用 Electron 做语音转文字桌面程序,一次开发同时跑在 Windows、macOS、Linux。',
link: '/zh-cn/stage-3/cross-platform/electron-voice-to-text/'
},
{
title: 'AI 智能体团队',
desc: '用 Claude Agent Teams 组建 AI 开发小队,多代理协作完成大型任务。',
link: '/zh-cn/stage-3/core-skills/agent-teams/'
},
{
title: '长效稳定执行',
desc: '用循环脚本和 Ralph 插件管理长时间任务,让 Claude Code 过夜稳定跑完工作。',
link: '/zh-cn/stage-3/core-skills/long-running-tasks/'
},
{
title: '个人品牌与输出',
desc: '搭建个人网站与技术博客,让你的项目和经验长期沉淀并被更多人看到。',
link: '/zh-cn/stage-3/personal-brand/personal-website-blog/'
}
]
},
appendix: {
cat: 'Appendix · 附录',
title: '让代码,<br><span class="highlight">活灵活现。</span>',
sub: '告别晦涩的文字堆砌。用动态演示和实时交互,重新定义技术文档。',
cards: [
{
title: 'AI 进化史',
desc: '回顾人工智能发展历程中的关键里程碑。',
link: '/zh-cn/appendix/8-artificial-intelligence/ai-history'
},
{
title: '提示词工程',
desc: '掌握与 AI 高效对话的技巧,解锁潜力。',
link: '/zh-cn/appendix/8-artificial-intelligence/prompt-engineering'
},
{
title: '大语言模型',
desc: '深入浅出解析 LLM 的工作原理与应用。',
link: '/zh-cn/appendix/8-artificial-intelligence/llm-principles'
},
{
title: 'Agent 智能体',
desc: '探索具备自主决策与执行能力的 AI 架构。',
link: '/zh-cn/appendix/8-artificial-intelligence/ai-agents'
},
{
title: '前端基础',
desc: 'HTML/CSS/JS 三大基石,入门必修课。',
link: '/zh-cn/appendix/3-browser-and-frontend/javascript-deep-dive'
},
{
title: '前端进化史',
desc: '了解前端技术栈演变,把握发展趋势。',
link: '/zh-cn/appendix/3-browser-and-frontend/frontend-frameworks'
},
{
title: '后端架构',
desc: '从单体到微服务,探索架构演进之路。',
link: '/zh-cn/appendix/4-server-and-backend/backend-layered-architecture'
},
{
title: '后端语言',
desc: '对比主流后端语言特性,选择最佳技术栈。',
link: '/zh-cn/appendix/4-server-and-backend/backend-languages'
},
{
title: '数据库原理',
desc: '理解数据库核心原理,掌握数据存储艺术。',
link: '/zh-cn/appendix/5-data/database-fundamentals'
},
{
title: 'API 设计',
desc: 'API 接口设计与开发的基础知识。',
link: '/zh-cn/appendix/4-server-and-backend/api-intro'
},
{
title: 'Git 版本控制',
desc: '深入理解 Git 原理与高级用法。',
link: '/zh-cn/appendix/2-development-tools/git-version-control'
},
{
title: '计算机网络',
desc: '网络协议与通信原理的基础知识。',
link: '/zh-cn/appendix/1-computer-fundamentals/computer-networks'
}
]
},
footer: {
title: '你的想法,<br>此刻上线。',
desc: '灵感到现实,何不从现在开始。',
btn: '>_ Start'
}
},
'en': {
nav: {
title: 'Easy-Vibe Tutorial',
home: 'Home',
stories: 'Vibe Stories',
pm: 'Product Manager',
junior: 'Junior Dev',
senior: 'Senior Dev',
appendix: 'Appendix',
start: 'Start Learning'
},
stories: {
cat: 'Vibe Stories',
title: 'Meet every <br><span class="highlight">shining builder.</span>',
sub: 'See how people from different backgrounds use AI to solve real problems.',
s1: { title: 'He gave up a high salary to help rural kids "fight flies" with AI', author: 'Xiaohao, primary school teacher' },
s2: { title: 'During finals week, I secretly built a campus marketplace with AI', author: 'A sophomore student' },
s3: { title: 'I built every student a tireless AI study buddy', author: 'A high school IT teacher' },
s4: { title: 'A 48-year-old truck driver stayed up for nights to build an overseas AI tool site', author: 'Lao Huang, truck driver' },
authorPrefix: 'By',
ui: {
prevLabel: 'Previous story',
nextLabel: 'Next story',
selectLabel: 'View this story',
imageAlt: 'Vibe story cover'
}
},
stage1: {
cat: 'Stage 1 · Getting Started',
title: 'Zero to Hero, <br><span class="highlight">Be Your Own PM.</span>',
sub: 'No CS background needed. Just speak your ideas—AI will turn them into high-fidelity web prototypes.',
cards: [
{
title: 'Learning Map',
desc: 'Understand the complete learning path from zero to full-stack development.',
sub: 'All Ages Friendly',
link: '/en/stage-1/learning-map/'
},
{
title: 'Gamified Intro',
desc: 'Experience the magic of AI programming by building games like Snake.',
sub: 'Learn by Playing',
link: '/en/stage-1/ai-capabilities-through-games/'
},
{
title: 'Vibe Coding',
desc: 'Master the core of AI coding: From product ideas to interactive prototypes.',
sub: 'Core Mindset',
link: '/en/stage-1/'
}
]
},
stage2: {
cat: 'Stage 2 · Junior/Mid Dev',
title:
'Go Full Stack, <br><span class="highlight">Build Real Apps.</span>',
sub: 'Understand the full journey from frontend to backend, database and deployment.',
cards: [
{
title: 'Asset Agent',
headline: 'Speed up content production.',
desc: 'Build your own design-asset workflow and drawing agent with Lovart and Nanobanana.',
link: '/zh-cn/stage-2/frontend/lovart-assets/'
},
{
title: 'Figma & MasterGo',
headline: 'Get fluent with design tools.',
desc: 'Learn the basics of modern UI design tools and how design files flow into development.',
link: '/zh-cn/stage-2/frontend/figma-mastergo/'
},
{
title: 'Design to Code',
headline: 'Turn mockups into pages.',
desc: 'Convert prototypes into real frontend code that runs in the browser instead of staying as static designs.',
link: '/zh-cn/stage-2/frontend/design-to-code/'
},
{
title: 'Real Data Project',
headline: 'Backed by a real DB.',
desc: 'Design tables and permissions on Supabase and wire them into real read/write flows.',
link: '/zh-cn/stage-2/backend/database-supabase/'
},
{
title: 'Deployment',
headline: 'Ship it to the world.',
desc: 'Use CloudBase, Vercel and Zeabur to turn local projects into publicly reachable sites.',
link: '/zh-cn/stage-2/backend/zeabur-deployment/'
},
{
title: 'AI Knowledge Base',
headline: 'Plug AI into the app.',
desc: 'Use Dify to build AI workflows and knowledge-base powered product experiences.',
link: '/zh-cn/stage-2/ai-capabilities/dify-knowledge-base/'
}
]
},
stage3: {
cat: 'Stage 3 · Senior Dev',
title:
'Advanced Practice, <br><span class="highlight">Infinite Possibilities.</span>',
sub: 'Cross-platform apps and AI-native workflows, powered by Claude Code.',
cards: [
{
title: 'Electron Desktop App',
desc: 'Build a speech-to-text desktop app that runs on Windows, macOS and Linux from one codebase.',
link: '/zh-cn/stage-3/cross-platform/electron-voice-to-text/'
},
{
title: 'Agent Teams',
desc: 'Use Claude Agent Teams to orchestrate multiple agents like a real dev team.',
link: '/zh-cn/stage-3/core-skills/agent-teams/'
},
{
title: 'Long-running Tasks',
desc: 'Design loops and task queues so Claude Code can safely run overnight until work is truly done.',
link: '/zh-cn/stage-3/core-skills/long-running-tasks/'
},
{
title: 'Personal Brand',
desc: 'Build your own website and tech blog to showcase projects and writing.',
link: '/zh-cn/stage-3/personal-brand/personal-website-blog/'
}
]
},
appendix: {
cat: 'Appendix',
title:
'Encyclopedia, <br><span class="highlight">Solid Foundation.</span>',
sub: 'From Computer Networks to AI Principles, complete your tech puzzle.',
cards: [
{
title: 'AI History',
desc: 'Milestones in AI evolution.',
link: '/zh-cn/appendix/8-artificial-intelligence/ai-history'
},
{
title: 'Prompt Eng',
desc: 'Master AI communication skills.',
link: '/zh-cn/appendix/8-artificial-intelligence/prompt-engineering'
},
{
title: 'LLM Intro',
desc: 'Understanding Large Language Models.',
link: '/zh-cn/appendix/8-artificial-intelligence/llm-principles'
},
{
title: 'AI Agents',
desc: 'Autonomous decision-making AI.',
link: '/zh-cn/appendix/8-artificial-intelligence/ai-agents'
},
{
title: 'Web Basics',
desc: 'HTML/CSS/JS fundamentals.',
link: '/zh-cn/appendix/3-browser-and-frontend/javascript-deep-dive'
},
{
title: 'Frontend Evo',
desc: 'Evolution of frontend tech stack.',
link: '/zh-cn/appendix/3-browser-and-frontend/frontend-frameworks'
},
{
title: 'Backend Arch',
desc: 'From monolith to microservices.',
link: '/zh-cn/appendix/4-server-and-backend/backend-layered-architecture'
},
{
title: 'Backend Lang',
desc: 'Choosing the right tech stack.',
link: '/zh-cn/appendix/4-server-and-backend/backend-languages'
},
{
title: 'Database',
desc: 'Core principles of data storage.',
link: '/zh-cn/appendix/5-data/database-fundamentals'
},
{
title: 'API Design',
desc: 'Designing robust interfaces.',
link: '/zh-cn/appendix/4-server-and-backend/api-intro'
},
{
title: 'Git',
desc: 'Version control mastery.',
link: '/zh-cn/appendix/2-development-tools/git-version-control'
},
{
title: 'Networks',
desc: 'Protocols and communication.',
link: '/zh-cn/appendix/1-computer-fundamentals/computer-networks'
}
]
},
footer: {
title: 'Ready to start?',
desc: 'Easy-Vibe, make coding as natural as breathing.',
btn: 'Start Now'
}
},
'ja-jp': {
nav: {
title: 'Easy-Vibe チュートリアル',
home: 'ホーム',
stories: 'ユーザーストーリー',
pm: 'プロダクトマネージャー',
junior: '初中級開発者',
senior: '上級開発者',
appendix: '付録',
start: '学習を開始'
},
stories: {
cat: 'ユーザーストーリー',
title: 'それぞれの<br><span class="highlight">輝く物語を見よう。</span>',
sub: 'さまざまな背景の人たちが、AIで現実の課題をどう解決したかを紹介します。',
s1: { title: '高収入の仕事を辞め、農村の子どもたちとAIで「ハエ対策」アプリを作った先生', author: '小学校教師 小浩' },
s2: { title: '期末試験の週に、AIでこっそり「学内版フリマ」を作った', author: '大学2年生' },
s3: { title: '生徒一人ひとりに、疲れない「AI優等生の隣の席」を作った', author: '高校の情報技術教師' },
s4: { title: '48歳のトラック運転手が、徹夜で海外向けAIツールサイトを作り上げた', author: 'トラック運転手 老黄' },
authorPrefix: '語り手:',
ui: {
prevLabel: '前のストーリー',
nextLabel: '次のストーリー',
selectLabel: 'このストーリーを見る',
imageAlt: 'ユーザーストーリーのカバー'
}
},
stage1: {
cat: 'Stage 1 · 初心者とPM',
title:
'ゼロからの入門、<br><span class="highlight">自分だけのPMになる。</span>',
sub: 'CSの背景は不要。アイデアを話すだけで、AIが高精度のWebプロトタイプに変換します。',
cards: [
{
title: 'AI PM',
desc: 'アイデアからプロトタイプまで、話すだけ。',
sub: '非技術者向け',
link: '/ja-jp/stage-1/'
},
{
title: 'ゲーム化入門',
desc: 'スネークゲームやテトリスを作って、コードへの恐怖を克服。',
sub: '遊びながら学ぶ',
link: '/ja-jp/stage-1/'
},
{
title: 'Vibe Coding',
desc: 'AI時代のコーディングの核心:プロンプトエンジニアリングとコンテキスト管理。',
sub: '核心的な考え方',
link: '/ja-jp/stage-1/'
}
]
},
stage2: {
cat: 'Stage 2 · 初中級開発者',
title:
'フルスタックへ、<br><span class="highlight">リアルなアプリを構築。</span>',
sub: 'フロントエンドとバックエンドの分離をマスター。DB、API、複雑なインタラクションを含む商用レベルのプロジェクトを構築。',
cards: [
{
title: 'フルスタック',
headline: 'フロント&バックエンド。',
desc: 'DB設計からAPI、コンポーネントまで、現代的なWebアプリを完全に構築。',
link: '/ja-jp/stage-2/'
},
{
title: 'リアルプロジェクト',
headline: 'おもちゃのコードは卒業。',
desc: '認証、ストレージ、ファイルアップロード、コアビジネスロジックを深く掘り下げる。',
link: '/ja-jp/stage-2/'
},
{
title: 'デプロイ',
headline: '世界に公開。',
desc: 'サーバー設定、DNS、CI/CD。製品リリースのラストワンマイル。',
link: '/ja-jp/stage-2/'
}
]
},
stage3: {
cat: 'Stage 3 · 上級開発者',
title: '高度な実践、<br><span class="highlight">無限の可能性。</span>',
sub: 'モバイルミニプログラムとAIネイティブアプリ。LLM時代の可能性を探求。',
cards: [
{
title: 'WeChatミニアプリ',
desc: 'クロスプラットフォーム開発、数億人のユーザーに到達。',
link: '/ja-jp/stage-3/'
},
{
title: 'AIネイティブアプリ',
desc: 'RAG、Agent。LLMの限界を探る。',
link: '/ja-jp/stage-3/'
},
{
title: '複雑なアーキテクチャ',
desc: '高並行性、高可用性のアーキテクチャ設計。',
link: '/ja-jp/stage-3/'
},
{
title: 'パーソナルブランド',
desc: '自分のウェブサイトと学術ブログを構築。',
link: '/ja-jp/stage-3/'
}
]
},
appendix: {
cat: 'Appendix · 付録',
title:
'Encyclopedia, <br><span class="highlight">Solid Foundation.</span>',
sub: 'From Computer Networks to AI Principles, complete your tech puzzle.',
cards: [
{
title: 'AI Fundamentals',
desc: 'LLM, Agent, RAG. Dive into AI internals.',
link: '/ja-jp/appendix/ai-evolution'
},
{
title: 'Frontend',
desc: 'Browser internals, Performance, Canvas.',
link: '/ja-jp/appendix/web-basics'
},
{
title: 'Backend',
desc: 'High concurrency, Distributed systems, Microservices.',
link: '/ja-jp/appendix/backend-evolution'
},
{
title: 'General Skills',
desc: 'Git, Networks, IDE internals.',
link: '/ja-jp/appendix/git-intro'
}
]
},
footer: {
title: '準備はいいですか?',
desc: 'Easy-Vibe、呼吸するように自然にコーディング。',
btn: '今すぐ開始'
}
},
'zh-tw': {
nav: {
title: 'Easy-Vibe 教學',
home: '首頁',
stories: '使用者故事',
pm: '產品經理',
junior: '初中級開發',
senior: '高級開發',
appendix: '附錄',
start: '開始學習'
},
stories: {
cat: '使用者故事',
title: '看見每一個<br><span class="highlight">閃光的你。</span>',
sub: '看看不同背景的人,如何用 AI 解決真實問題、做出真實產品。',
s1: { title: '放棄月入過萬,他在鄉村小學帶孩子們「用 AI 趕蒼蠅」', author: '小學老師小浩' },
s2: { title: '期末考週,我偷偷用 AI 做了個「校園閒魚」', author: '一位大二學生' },
s3: { title: '我給每個學生,做了一個不會累的「學霸同桌」', author: '高中資訊科技老師' },
s4: { title: '48 歲貨車司機熬了幾個通宵,硬是用 AI 做出一個出海工具站', author: '貨車司機老黃' },
authorPrefix: '講述者:',
ui: {
prevLabel: '上一則故事',
nextLabel: '下一則故事',
selectLabel: '查看這個故事',
imageAlt: '使用者故事封面'
}
},
stage1: {
cat: 'Stage 1 · 新手與產品原型',
title:
'零基礎入門,<br><span class="highlight">做自己的產品經理。</span>',
sub: '不需要計算機專業背景,只要會說話,就能通過 AI 將你的創意轉化為高保真的 Web 原型。',
cards: [
{
title: 'AI 產品經理',
desc: '從想法到高保真原型,你只需要會說話。',
sub: '適合非技術背景',
link: '/zh-tw/stage-1/'
},
{
title: '遊戲化入門',
desc: '通過製作貪吃蛇、俄羅斯方塊,打破對代碼的恐懼。',
sub: '邊玩邊學',
link: '/zh-tw/stage-1/'
},
{
title: 'Vibe Coding',
desc: '掌握 AI 時代的編程核心:提示詞工程與上下文管理。',
sub: '核心心法',
link: '/zh-tw/stage-1/'
}
]
},
stage2: {
cat: 'Stage 2 · 初中級開發',
title: '深入全棧,<br><span class="highlight">構建真實應用。</span>',
sub: '掌握前後端分離架構,親手打造包含數據庫、API 和複雜交互的完整商業級項目。',
cards: [
{
title: '全棧開發',
headline: '獨立完成前後端。',
desc: '從數據庫設計到 API 開發,再到前端組件化,完整構建一個現代化 Web 應用。',
link: '/zh-tw/stage-2/'
},
{
title: '真實項目',
headline: '拒絕玩具代碼。',
desc: '深入理解用戶鑑權、數據存儲、文件上傳等核心業務邏輯。',
link: '/zh-tw/stage-2/'
},
{
title: '部署上線',
headline: '讓世界看到你的作品。',
desc: '學習服務器配置、域名解析和自動化部署,打通產品落地的最後一公里。',
link: '/zh-tw/stage-2/'
}
]
},
stage3: {
cat: 'Stage 3 · 高級開發',
title: '高階實戰,<br><span class="highlight">挑戰無限可能。</span>',
sub: '進軍移動端小程序與 AI 原生應用開發,探索大模型時代的無限機遇。',
cards: [
{
title: '微信小程序',
desc: '跨平台開發,觸達億級用戶。',
link: '/zh-tw/stage-3/'
},
{
title: 'AI 原生應用',
desc: 'RAG、Agent,探索 LLM 的無限可能。',
link: '/zh-tw/stage-3/'
},
{
title: '複雜業務架構',
desc: '應對高並發、高可用場景的架構設計。',
link: '/zh-tw/stage-3/'
},
{
title: '個人品牌',
desc: '構建屬於自己的個人網頁與學術博客。',
link: '/zh-tw/stage-3/'
}
]
},
appendix: {
cat: 'Appendix · 附錄',
title: '百科全書,<br><span class="highlight">夯實基礎。</span>',
sub: '從計算機網絡到 AI 原理,補齊你的技術拼圖。',
cards: [
{
title: '人工智能',
desc: 'LLM、Agent、RAG,深入 AI 底層原理。',
link: '/zh-tw/appendix/ai-evolution'
},
{
title: '前端開發',
desc: '瀏覽器原理、性能優化、Canvas 圖形學。',
link: '/zh-tw/appendix/web-basics'
},
{
title: '後端架構',
desc: '高並發、分佈式、微服務架構設計。',
link: '/zh-tw/appendix/backend-evolution'
},
{
title: '通用技能',
desc: 'Git、網絡、IDE 原理,開發者必備素養。',
link: '/zh-tw/appendix/git-intro'
}
]
},
footer: {
title: '準備好開始了嗎?',
desc: 'Easy-Vibe,讓編程像呼吸一樣自然。',
btn: '立即開啟'
}
},
'ko-kr': {
nav: {
title: 'Easy-Vibe 튜토리얼',
home: '홈',
stories: '사용자 이야기',
pm: '제품 관리자',
junior: '초/중급 개발자',
senior: '고급 개발자',
appendix: '부록',
start: '학습 시작'
},
stories: {
cat: '사용자 이야기',
title: '빛나는 모두의<br><span class="highlight">이야기를 만나보세요.</span>',
sub: '서로 다른 배경의 사람들이 AI로 현실의 문제를 어떻게 해결했는지 살펴보세요.',
s1: { title: '높은 월급을 포기하고 시골 초등학교 아이들과 AI로 "파리 막기"를 만든 선생님', author: '초등학교 교사 샤오하오' },
s2: { title: '기말고사 주간에 몰래 AI로 "캠퍼스 중고장터"를 만든 이야기', author: '대학교 2학년 학생' },
s3: { title: '모든 학생에게 지치지 않는 "AI 우등생 짝꿍"을 만들어 준 선생님', author: '고등학교 정보기술 교사' },
s4: { title: '48세 트럭 운전사가 며칠 밤을 새워 해외용 AI 툴 사이트를 만든 이야기', author: '트럭 운전사 라오황' },
authorPrefix: '화자:',
ui: {
prevLabel: '이전 이야기',
nextLabel: '다음 이야기',
selectLabel: '이 이야기 보기',
imageAlt: '사용자 이야기 표지'
}
},
stage1: {
cat: 'Stage 1 · 초보자 & PM',
title:
'제로 베이스 입문,<br><span class="highlight">나만의 PM이 되다.</span>',
sub: 'CS 배경지식이 없어도 괜찮습니다. 아이디어를 말하기만 하면 AI가 고품질 웹 프로토타입으로 변환해줍니다.',
cards: [
{
title: 'AI 제품 관리자',
desc: '아이디어에서 프로토타입까지, 말 한마디로.',
sub: '비전공자 추천',
link: '/ko-kr/stage-1/'
},
{
title: '게임으로 입문',
desc: '스네이크 게임, 테트리스를 만들며 코딩 공포증 극복.',
sub: '놀면서 배우기',
link: '/ko-kr/stage-1/'
},
{
title: 'Vibe Coding',
desc: 'AI 시대 코딩의 핵심: 프롬프트 엔지니어링과 컨텍스트 관리.',
sub: '핵심 마인드셋',
link: '/ko-kr/stage-1/'
}
]
},
stage2: {
cat: 'Stage 2 · 초/중급 개발자',
title: '풀스택 심화,<br><span class="highlight">실제 앱 구축.</span>',
sub: '프론트엔드-백엔드 분리 아키텍처 마스터. DB, API, 복잡한 상호작용이 포함된 상용급 프로젝트 구축.',
cards: [
{
title: '풀스택 개발',
headline: '프론트 & 백엔드 독립 완성.',
desc: 'DB 설계부터 API 개발, 프론트엔드 컴포넌트화까지 현대적인 웹 앱을 완벽하게 구축.',
link: '/ko-kr/stage-2/'
},
{
title: '실전 프로젝트',
headline: '장난감 코드는 그만.',
desc: '사용자 인증, 데이터 저장, 파일 업로드 등 핵심 비즈니스 로직 심층 이해.',
link: '/ko-kr/stage-2/'
},
{
title: '배포 및 출시',
headline: '세상에 보여주세요.',
desc: '서버 설정, 도메인 연결, CI/CD. 제품 출시의 마지막 관문.',
link: '/ko-kr/stage-2/'
}
]
},
stage3: {
cat: 'Stage 3 · 고급 개발자',
title:
'고급 실전,<br><span class="highlight">무한한 가능성에 도전.</span>',
sub: '모바일 미니 프로그램 및 AI 네이티브 앱 개발. LLM 시대의 무한한 기회 탐색.',
cards: [
{
title: '위챗 미니프로그램',
desc: '크로스 플랫폼 개발, 수억 명의 사용자 도달.',
link: '/ko-kr/stage-3/'
},
{
title: 'AI 네이티브 앱',
desc: 'RAG, Agent. LLM의 한계 탐색.',
link: '/ko-kr/stage-3/'
},
{
title: '복잡한 아키텍처',
desc: '고동시성, 고가용성 아키텍처 설계.',
link: '/ko-kr/stage-3/'
},
{
title: '퍼스널 브랜딩',
desc: '나만의 웹사이트와 학술 블로그 구축.',
link: '/ko-kr/stage-3/'
}
]
},
appendix: {
cat: 'Appendix · 부록',
title:
'Encyclopedia, <br><span class="highlight">Solid Foundation.</span>',
sub: 'From Computer Networks to AI Principles, complete your tech puzzle.',
cards: [
{
title: 'AI Fundamentals',
desc: 'LLM, Agent, RAG. Dive into AI internals.',
link: '/ko-kr/appendix/ai-evolution'
},
{
title: 'Frontend',
desc: 'Browser internals, Performance, Canvas.',
link: '/ko-kr/appendix/web-basics'
},
{
title: 'Backend',
desc: 'High concurrency, Distributed systems, Microservices.',
link: '/ko-kr/appendix/backend-evolution'
},
{
title: 'General Skills',
desc: 'Git, Networks, IDE internals.',
link: '/ko-kr/appendix/git-intro'
}
]
},
footer: {
title: '시작할 준비 되셨나요?',
desc: 'Easy-Vibe, 숨 쉬듯 자연스러운 코딩.',
btn: '지금 시작하기'
}
},
'es-es': {
nav: {
title: 'Tutorial Easy-Vibe',
home: 'Inicio',
stories: 'Historias de usuarios',
pm: 'Gerente de Producto',
junior: 'Desarrollador Junior',
senior: 'Desarrollador Senior',
appendix: 'Apéndice',
start: 'Empezar'
},
stories: {
cat: 'Historias de usuarios',
title: 'Conoce cada <br><span class="highlight">historia que brilla.</span>',
sub: 'Descubre cómo personas de distintos contextos usan la IA para resolver problemas reales.',
s1: { title: 'Dejó un salario de cinco cifras para ayudar a niños rurales a "ahuyentar moscas" con IA', author: 'Xiaohao, maestro de primaria rural' },
s2: { title: 'Durante la semana de finales, construí en secreto un mercado universitario con IA', author: 'Una estudiante de segundo año' },
s3: { title: 'Le construí a cada alumno un compañero de estudio con IA que nunca se cansa', author: 'Un profesor de informática de secundaria' },
s4: { title: 'Un camionero de 48 años pasó varias noches despierto para crear una web de herramientas de IA para el extranjero', author: 'Lao Huang, camionero' },
authorPrefix: 'Por',
ui: {
prevLabel: 'Historia anterior',
nextLabel: 'Siguiente historia',
selectLabel: 'Ver esta historia',
imageAlt: 'Portada de la historia'
}
},
stage1: {
cat: 'Stage 1 · Principiante y PM',
title:
'De Cero a Héroe,<br><span class="highlight">Sé tu propio PM.</span>',
sub: 'No necesitas experiencia en CS. Solo di tu idea y la IA la convertirá en prototipos web de alta fidelidad.',
cards: [
{
title: 'PM de IA',
desc: 'De la idea al prototipo, solo hablando.',
sub: 'Amigable para no técnicos',
link: '/es-es/stage-1/'
},
{
title: 'Intro Gamificada',
desc: 'Crea Snake, Tetris y rompe el miedo al código.',
sub: 'Aprende jugando',
link: '/es-es/stage-1/'
},
{
title: 'Vibe Coding',
desc: 'Domina el núcleo de la programación con IA: Ingeniería de Prompts y Contexto.',
sub: 'Mentalidad Clave',
link: '/es-es/stage-1/'
}
]
},
stage2: {
cat: 'Stage 2 · Desarrollador Junior/Mid',
title: 'Full Stack,<br><span class="highlight">Crea Apps Reales.</span>',
sub: 'De la base de datos al despliegue: conecta frontend, backend y operaciones en un solo recorrido.',
cards: [
{
title: 'Mapa de la Etapa',
headline: 'Primero entiende el recorrido completo.',
desc: 'Revisa la vista general de Stage 2 para ver cómo encajan frontend, backend, DB y despliegue.',
link: '/zh-cn/stage-2/'
},
{
title: 'Proyecto con DB real',
headline: 'Supabase como base de datos de verdad.',
desc: 'Diseña tablas y permisos en Supabase y conéctalos a flujos reales de lectura/escritura.',
link: '/zh-cn/stage-2/backend/database-supabase/'
},
{
title: 'Despliegue en producción',
headline: 'Lleva tu app al mundo real.',
desc: 'Usa CloudBase, Vercel y Zeabur para convertir tu código local en un sitio público.',
link: '/zh-cn/stage-2/backend/zeabur-deployment/'
}
]
},
stage3: {
cat: 'Stage 3 · Desarrollador Senior',
title:
'Práctica Avanzada,<br><span class="highlight">Posibilidades Infinitas.</span>',
sub: 'Apps multiplataforma y flujos de trabajo AI-native impulsados por Claude Code.',
cards: [
{
title: 'App de escritorio multiplataforma',
desc: 'Crea con Electron una app de voz a texto que funciona en Windows, macOS y Linux con una sola base de código.',
link: '/zh-cn/stage-3/cross-platform/electron-voice-to-text/'
},
{
title: 'Equipos de agentes IA',
desc: 'Usa Claude Agent Teams para orquestar varios agentes como si fueran un equipo de desarrollo real.',
link: '/zh-cn/stage-3/core-skills/agent-teams/'
},
{
title: 'Tareas de larga duración',
desc: 'Diseña bucles y colas de tareas para que Claude Code pueda trabajar durante horas de forma estable.',
link: '/zh-cn/stage-3/core-skills/long-running-tasks/'
},
{
title: 'Marca personal',
desc: 'Construye tu sitio web y blog técnico para dar visibilidad a tus proyectos.',
link: '/zh-cn/stage-3/personal-brand/personal-website-blog/'
}
]
},
appendix: {
cat: 'Appendix · Apéndice',
title:
'Encyclopedia, <br><span class="highlight">Solid Foundation.</span>',
sub: 'From Computer Networks to AI Principles, complete your tech puzzle.',
cards: [
{
title: 'AI Fundamentals',
desc: 'LLM, Agent, RAG. Dive into AI internals.',
link: '/es-es/appendix/ai-evolution'
},
{
title: 'Frontend',
desc: 'Browser internals, Performance, Canvas.',
link: '/es-es/appendix/web-basics'
},
{
title: 'Backend',
desc: 'High concurrency, Distributed systems, Microservices.',
link: '/es-es/appendix/backend-evolution'
},
{
title: 'General Skills',
desc: 'Git, Networks, IDE internals.',
link: '/es-es/appendix/git-intro'
}
]
},
footer: {
title: '¿Listo para empezar?',
desc: 'Easy-Vibe, haz que programar sea tan natural como respirar.',
btn: 'Empezar Ahora'
}
},
'fr-fr': {
nav: {
title: 'Tutoriel Easy-Vibe',
home: 'Accueil',
stories: 'Histoires dutilisateurs',
pm: 'Chef de Produit',
junior: 'Dév Junior',
senior: 'Dév Senior',
appendix: 'Annexe',
start: 'Commencer'
},
stories: {
cat: 'Histoires dutilisateurs',
title: 'Découvrez chaque <br><span class="highlight">parcours inspirant.</span>',
sub: 'Voyez comment des personnes de tous horizons utilisent lIA pour résoudre de vrais problèmes.',
s1: { title: 'Il a quitté un salaire confortable pour aider des enfants dune école rurale à "chasser les mouches" avec lIA', author: 'Xiaohao, instituteur' },
s2: { title: 'Pendant la semaine des examens, jai secrètement créé une marketplace de campus avec lIA', author: 'Une étudiante de deuxième année' },
s3: { title: 'Jai créé pour chaque élève un binôme d’étude IA qui ne se fatigue jamais', author: 'Un professeur dinformatique au lycée' },
s4: { title: 'Un chauffeur routier de 48 ans a veillé plusieurs nuits pour lancer un site doutils IA à linternational', author: 'Lao Huang, chauffeur routier' },
authorPrefix: 'Par',
ui: {
prevLabel: 'Histoire précédente',
nextLabel: 'Histoire suivante',
selectLabel: 'Voir cette histoire',
imageAlt: 'Couverture de lhistoire'
}
},
stage1: {
cat: 'Stage 1 · Débutant & PM',
title:
'De Zéro à Héros,<br><span class="highlight">Soyez votre propre PM.</span>',
sub: "Pas besoin de background CS. Parlez juste de votre idée, et l'IA la transformera en prototypes web haute fidélité.",
cards: [
{
title: 'PM IA',
desc: "De l'idée au prototype, juste en parlant.",
sub: 'Accessible aux non-tech',
link: '/fr-fr/stage-1/'
},
{
title: 'Intro Gamifiée',
desc: 'Créez Snake, Tetris et brisez la peur du code.',
sub: 'Apprendre en jouant',
link: '/fr-fr/stage-1/'
},
{
title: 'Vibe Coding',
desc: 'Maîtrisez le cœur du codage IA : Prompt Engineering & Contexte.',
sub: 'Esprit Clé',
link: '/fr-fr/stage-1/'
}
]
},
stage2: {
cat: 'Stage 2 · Dév Junior/Mid',
title:
'Full Stack,<br><span class="highlight">Créez de Vraies Apps.</span>',
sub: 'Maîtrisez la séparation frontend-backend. Créez des projets commerciaux avec DB, API et interactions complexes.',
cards: [
{
title: 'Full Stack',
headline: 'Frontend & Backend.',
desc: 'Du design DB aux API et composants, construisez une web app moderne complète.',
link: '/fr-fr/stage-2/'
},
{
title: 'Projets Réels',
headline: 'Pas de code jouet.',
desc: "Plongez dans l'Auth, le Stockage, l'Upload de fichiers et la logique métier.",
link: '/fr-fr/stage-2/'
},
{
title: 'Déploiement',
headline: 'Montrez au monde.',
desc: 'Config serveur, DNS, CI/CD. Le dernier kilomètre de la livraison produit.',
link: '/fr-fr/stage-2/'
}
]
},
stage3: {
cat: 'Stage 3 · Dév Senior',
title:
'Pratique Avancée,<br><span class="highlight">Possibilités Infinies.</span>',
sub: "Mini-programmes mobiles et Apps Natives IA. Explorez l'ère des LLM.",
cards: [
{
title: 'WeChat Mini-app',
desc: "Dév multiplateforme, touchant des millions d'utilisateurs.",
link: '/fr-fr/stage-3/'
},
{
title: 'Apps Natives IA',
desc: 'RAG, Agent. Explorez les limites des LLM.',
link: '/fr-fr/stage-3/'
},
{
title: 'Arch. Complexe',
desc: "Conception d'architecture haute concurrence et haute disponibilité.",
link: '/fr-fr/stage-3/'
},
{
title: 'Marque Perso',
desc: 'Construisez votre propre site web et blog académique.',
link: '/fr-fr/stage-3/'
}
]
},
appendix: {
cat: 'Appendix · Annexe',
title:
'Encyclopedia, <br><span class="highlight">Solid Foundation.</span>',
sub: 'From Computer Networks to AI Principles, complete your tech puzzle.',
cards: [
{
title: 'AI Fundamentals',
desc: 'LLM, Agent, RAG. Dive into AI internals.',
link: '/fr-fr/appendix/ai-evolution'
},
{
title: 'Frontend',
desc: 'Browser internals, Performance, Canvas.',
link: '/fr-fr/appendix/web-basics'
},
{
title: 'Backend',
desc: 'High concurrency, Distributed systems, Microservices.',
link: '/fr-fr/appendix/backend-evolution'
},
{
title: 'General Skills',
desc: 'Git, Networks, IDE internals.',
link: '/fr-fr/appendix/git-intro'
}
]
},
footer: {
title: 'Prêt à commencer ?',
desc: 'Easy-Vibe, rendez le codage aussi naturel que la respiration.',
btn: 'Commencer'
}
},
'de-de': {
nav: {
title: 'Easy-Vibe Tutorial',
home: 'Startseite',
stories: 'Nutzergeschichten',
pm: 'Produktmanager',
junior: 'Junior Dev',
senior: 'Senior Dev',
appendix: 'Anhang',
start: 'Starten'
},
stories: {
cat: 'Nutzergeschichten',
title: 'Entdecke jede <br><span class="highlight">inspirierende Geschichte.</span>',
sub: 'Sieh, wie Menschen mit ganz unterschiedlichen Hintergründen mit KI echte Probleme lösen.',
s1: { title: 'Er gab ein hohes Gehalt auf, um Kindern auf dem Land mit KI beim "Fliegenvertreiben" zu helfen', author: 'Xiaohao, Grundschullehrer' },
s2: { title: 'In der Prüfungswoche habe ich heimlich mit KI einen Campus-Marktplatz gebaut', author: 'Eine Studentin im zweiten Jahr' },
s3: { title: 'Ich habe jedem Schüler einen unermüdlichen KI-Lernpartner gebaut', author: 'Ein Informatiklehrer an einer Oberschule' },
s4: { title: 'Ein 48-jähriger Lkw-Fahrer blieb mehrere Nächte wach, um eine internationale KI-Toolseite zu bauen', author: 'Lao Huang, Lkw-Fahrer' },
authorPrefix: 'Von',
ui: {
prevLabel: 'Vorherige Geschichte',
nextLabel: 'Nächste Geschichte',
selectLabel: 'Diese Geschichte ansehen',
imageAlt: 'Titelbild der Geschichte'
}
},
stage1: {
cat: 'Stage 1 · Anfänger & PM',
title:
'Von Null auf Hundert,<br><span class="highlight">Sei dein eigener PM.</span>',
sub: 'Kein CS-Hintergrund nötig. Sprich einfach deine Idee aus, und KI verwandelt sie in High-Fidelity-Web-Prototypen.',
cards: [
{
title: 'KI PM',
desc: 'Von der Idee zum Prototyp, einfach durch Sprechen.',
sub: 'Nicht-Tech-freundlich',
link: '/de-de/stage-1/'
},
{
title: 'Gamifizierte Intro',
desc: 'Baue Snake, Tetris und überwinde die Angst vor Code.',
sub: 'Spielend lernen',
link: '/de-de/stage-1/'
},
{
title: 'Vibe Coding',
desc: 'Meistere den Kern des KI-Codings: Prompt Engineering & Kontext.',
sub: 'Kern-Mindset',
link: '/de-de/stage-1/'
}
]
},
stage2: {
cat: 'Stage 2 · Junior/Mid Dev',
title: 'Full Stack,<br><span class="highlight">Baue echte Apps.</span>',
sub: 'Meistere die Frontend-Backend-Trennung. Baue kommerzielle Projekte mit DB, API und komplexen Interaktionen.',
cards: [
{
title: 'Full Stack',
headline: 'Frontend & Backend.',
desc: 'Vom DB-Design bis zu APIs und Komponenten, baue eine moderne Web-App komplett.',
link: '/de-de/stage-2/'
},
{
title: 'Echte Projekte',
headline: 'Kein Spielzeug-Code.',
desc: 'Tauche ein in Auth, Speicher, Datei-Uploads und Kern-Geschäftslogik.',
link: '/de-de/stage-2/'
},
{
title: 'Deployment',
headline: 'Zeig es der Welt.',
desc: 'Server-Konfig, DNS, CI/CD. Die letzte Meile der Produktlieferung.',
link: '/de-de/stage-2/'
}
]
},
stage3: {
cat: 'Stage 3 · Senior Dev',
title:
'Fortgeschrittene Praxis,<br><span class="highlight">Unendliche Möglichkeiten.</span>',
sub: 'Mobile Mini-Programme & KI-Native Apps. Erkunde die Ära der LLMs.',
cards: [
{
title: 'WeChat Mini-App',
desc: 'Plattformübergreifende Entwicklung, Millionen von Nutzern erreichen.',
link: '/de-de/stage-3/'
},
{
title: 'KI-Native Apps',
desc: 'RAG, Agent. Erkunde die Grenzen von LLMs.',
link: '/de-de/stage-3/'
},
{
title: 'Komplexe Arch',
desc: 'Architekturdesign für hohe Gleichzeitigkeit und hohe Verfügbarkeit.',
link: '/de-de/stage-3/'
},
{
title: 'Persönliche Marke',
desc: 'Baue deine eigene Website und deinen akademischen Blog.',
link: '/de-de/stage-3/'
}
]
},
appendix: {
cat: 'Appendix · Anhang',
title:
'Encyclopedia, <br><span class="highlight">Solid Foundation.</span>',
sub: 'From Computer Networks to AI Principles, complete your tech puzzle.',
cards: [
{
title: 'AI Fundamentals',
desc: 'LLM, Agent, RAG. Dive into AI internals.',
link: '/de-de/appendix/ai-evolution'
},
{
title: 'Frontend',
desc: 'Browser internals, Performance, Canvas.',
link: '/de-de/appendix/web-basics'
},
{
title: 'Backend',
desc: 'High concurrency, Distributed systems, Microservices.',
link: '/de-de/appendix/backend-evolution'
},
{
title: 'General Skills',
desc: 'Git, Networks, IDE internals.',
link: '/de-de/appendix/git-intro'
}
]
},
footer: {
title: 'Bereit zu starten?',
desc: 'Easy-Vibe, mache Coden so natürlich wie Atmen.',
btn: 'Jetzt starten'
}
},
'ar-sa': {
nav: {
title: 'دليل Easy-Vibe',
home: 'الرئيسية',
stories: 'قصص المستخدمين',
pm: 'مدير المنتج',
junior: 'مطور مبتدئ',
senior: 'مطور خبير',
appendix: 'ملحق',
start: 'ابدأ التعلم'
},
stories: {
cat: 'قصص المستخدمين',
title: 'تعرّف على كل <br><span class="highlight">قصة ملهمة.</span>',
sub: 'اكتشف كيف يستخدم أشخاص من خلفيات مختلفة الذكاء الاصطناعي لحل مشكلات حقيقية.',
s1: { title: 'تخلّى عن راتب مرتفع ليساعد أطفال مدرسة ريفية على "طرد الذباب" باستخدام الذكاء الاصطناعي', author: 'شياوهاو، معلم مدرسة ابتدائية' },
s2: { title: 'خلال أسبوع الامتحانات النهائية، بنيت سرًا سوقًا جامعيًا باستخدام الذكاء الاصطناعي', author: 'طالبة في السنة الثانية' },
s3: { title: 'صنعت لكل طالب زميل دراسة بالذكاء الاصطناعي لا يتعب أبدًا', author: 'معلم تقنية معلومات في الثانوية' },
s4: { title: 'سائق شاحنة يبلغ 48 عامًا سهر عدة ليالٍ ليبني موقع أدوات ذكاء اصطناعي للأسواق الخارجية', author: 'لاو هوانغ، سائق شاحنة' },
authorPrefix: 'الراوي:',
ui: {
prevLabel: 'القصة السابقة',
nextLabel: 'القصة التالية',
selectLabel: 'عرض هذه القصة',
imageAlt: 'غلاف القصة'
}
},
stage1: {
cat: 'Stage 1 · مدير المنتج',
title:
'من الصفر إلى الاحتراف،<br><span class="highlight">كن مدير منتجك الخاص.</span>',
sub: 'لا حاجة لخلفية في علوم الحاسوب. فقط تحدث بفكرتك، وسيُحولها الذكاء الاصطناعي إلى نماذج ويب عالية الدقة.',
cards: [
{
title: 'مدير منتج AI',
desc: 'من الفكرة إلى النموذج الأولي، بمجرد التحدث.',
sub: 'صديق لغير التقنيين',
link: '/ar-sa/stage-1/'
},
{
title: 'مقدمة بالألعاب',
desc: 'ابنِ Snake و Tetris واكسر حاجز الخوف من الكود.',
sub: 'تعلم باللعب',
link: '/ar-sa/stage-1/'
},
{
title: 'Vibe Coding',
desc: 'أتقن جوهر برمجة الذكاء الاصطناعي: هندسة الأوامر والسياق.',
sub: 'العقلية الأساسية',
link: '/ar-sa/stage-1/'
}
]
},
stage2: {
cat: 'Stage 2 · مطور مبتدئ/متوسط',
title:
'Full Stack،<br><span class="highlight">ابنِ تطبيقات حقيقية.</span>',
sub: 'أتقن فصل الواجهة الأمامية عن الخلفية. ابنِ مشاريع تجارية مع قواعد بيانات و API وتفاعلات معقدة.',
cards: [
{
title: 'Full Stack',
headline: 'واجهة أمامية وخلفية.',
desc: 'من تصميم DB إلى API والمكونات، ابنِ تطبيق ويب حديث بالكامل.',
link: '/ar-sa/stage-2/'
},
{
title: 'مشاريع حقيقية',
headline: 'ليس كود ألعاب.',
desc: 'تعمق في المصادقة، التخزين، رفع الملفات ومنطق العمل الأساسي.',
link: '/ar-sa/stage-2/'
},
{
title: 'النشر',
headline: 'أظهر للعالم.',
desc: 'إعداد الخادم، DNS، CI/CD. الميل الأخير لتسليم المنتج.',
link: '/ar-sa/stage-2/'
}
]
},
stage3: {
cat: 'Stage 3 · مطور خبير',
title:
'ممارسة متقدمة،<br><span class="highlight">إمكانيات لا نهائية.</span>',
sub: 'برامج WeChat الصغيرة وتطبيقات AI الأصلية. استكشف عصر LLMs.',
cards: [
{
title: 'برنامج WeChat المصغر',
desc: 'تطوير متعدد المنصات، الوصول لملايين المستخدمين.',
link: '/ar-sa/stage-3/'
},
{
title: 'تطبيقات AI الأصلية',
desc: 'RAG، Agent. استكشف حدود LLMs.',
link: '/ar-sa/stage-3/'
},
{
title: 'هندسة معقدة',
desc: 'تصميم هندسة التزامن العالي والتوافر العالي.',
link: '/ar-sa/stage-3/'
},
{
title: 'العلامة التجارية الشخصية',
desc: 'ابنِ موقعك الخاص ومدونتك الأكاديمية.',
link: '/ar-sa/stage-3/'
}
]
},
appendix: {
cat: 'Appendix · ملحق',
title:
'Encyclopedia, <br><span class="highlight">Solid Foundation.</span>',
sub: 'From Computer Networks to AI Principles, complete your tech puzzle.',
cards: [
{
title: 'AI Fundamentals',
desc: 'LLM, Agent, RAG. Dive into AI internals.',
link: '/ar-sa/appendix/ai-evolution'
},
{
title: 'Frontend',
desc: 'Browser internals, Performance, Canvas.',
link: '/ar-sa/appendix/web-basics'
},
{
title: 'Backend',
desc: 'High concurrency, Distributed systems, Microservices.',
link: '/ar-sa/appendix/backend-evolution'
},
{
title: 'General Skills',
desc: 'Git, Networks, IDE internals.',
link: '/ar-sa/appendix/git-intro'
}
]
},
footer: {
title: 'جاهز للبدء؟',
desc: 'Easy-Vibe، اجعل البرمجة طبيعية كالتنفس.',
btn: 'ابدأ الآن'
}
},
'vi-vn': {
nav: {
title: 'Hướng dẫn Easy-Vibe',
home: 'Trang chủ',
stories: 'Câu chuyện người dùng',
pm: 'Quản lý sản phẩm',
junior: 'Dev Sơ/Trung cấp',
senior: 'Dev Cao cấp',
appendix: 'Phụ lục',
start: 'Bắt đầu học'
},
stories: {
cat: 'Câu chuyện người dùng',
title: 'Gặp gỡ từng <br><span class="highlight">câu chuyện tỏa sáng.</span>',
sub: 'Khám phá cách những người từ nhiều xuất phát điểm khác nhau dùng AI để giải quyết vấn đề thật.',
s1: { title: 'Anh bỏ mức lương cao để giúp trẻ em vùng quê "đuổi ruồi" bằng AI', author: 'Xiaohao, giáo viên tiểu học' },
s2: { title: 'Trong tuần thi cuối kỳ, tôi lặng lẽ làm một chợ đồ cũ trong trường bằng AI', author: 'Một sinh viên năm hai' },
s3: { title: 'Tôi tạo cho mỗi học sinh một bạn học giỏi AI không biết mệt', author: 'Một giáo viên CNTT trung học' },
s4: { title: 'Một tài xế xe tải 48 tuổi thức trắng nhiều đêm để làm một website công cụ AI cho thị trường quốc tế', author: 'Lao Huang, tài xế xe tải' },
authorPrefix: 'Người kể:',
ui: {
prevLabel: 'Câu chuyện trước',
nextLabel: 'Câu chuyện tiếp theo',
selectLabel: 'Xem câu chuyện này',
imageAlt: 'Ảnh bìa câu chuyện'
}
},
stage1: {
cat: 'Stage 1 · Người mới & PM',
title:
'Từ số 0 đến Hero,<br><span class="highlight">Tự làm PM cho chính mình.</span>',
sub: 'Không cần nền tảng CS. Chỉ cần nói ra ý tưởng, AI sẽ biến nó thành nguyên mẫu web độ trung thực cao.',
cards: [
{
title: 'AI PM',
desc: 'Từ ý tưởng đến nguyên mẫu, chỉ bằng lời nói.',
sub: 'Thân thiện với non-tech',
link: '/vi-vn/stage-1/'
},
{
title: 'Nhập môn qua Game',
desc: 'Xây dựng Snake, Tetris và phá bỏ nỗi sợ code.',
sub: 'Học mà chơi',
link: '/vi-vn/stage-1/'
},
{
title: 'Vibe Coding',
desc: 'Nắm vững cốt lõi lập trình AI: Prompt Engineering & Context.',
sub: 'Tư duy cốt lõi',
link: '/vi-vn/stage-1/'
}
]
},
stage2: {
cat: 'Stage 2 · Dev Sơ/Trung cấp',
title:
'Full Stack,<br><span class="highlight">Xây dựng App thực tế.</span>',
sub: 'Nắm vững tách biệt frontend-backend. Xây dựng dự án thương mại với DB, API và tương tác phức tạp.',
cards: [
{
title: 'Full Stack',
headline: 'Frontend & Backend.',
desc: 'Từ thiết kế DB đến API và component, xây dựng trọn vẹn web app hiện đại.',
link: '/vi-vn/stage-2/'
},
{
title: 'Dự án thực tế',
headline: 'Không phải code đồ chơi.',
desc: 'Đi sâu vào Auth, Lưu trữ, Upload file và logic nghiệp vụ cốt lõi.',
link: '/vi-vn/stage-2/'
},
{
title: 'Triển khai',
headline: 'Show cho thế giới.',
desc: 'Cấu hình server, DNS, CI/CD. Chặng cuối của việc giao sản phẩm.',
link: '/vi-vn/stage-2/'
}
]
},
stage3: {
cat: 'Stage 3 · Dev Cao cấp',
title:
'Thực hành nâng cao,<br><span class="highlight">Khả năng vô hạn.</span>',
sub: 'Mini-app di động & Ứng dụng AI Native. Khám phá kỷ nguyên LLM.',
cards: [
{
title: 'WeChat Mini-app',
desc: 'Phát triển đa nền tảng, tiếp cận hàng triệu người dùng.',
link: '/vi-vn/stage-3/'
},
{
title: 'App AI Native',
desc: 'RAG, Agent. Khám phá giới hạn của LLM.',
link: '/vi-vn/stage-3/'
},
{
title: 'Kiến trúc phức tạp',
desc: 'Thiết kế kiến trúc chịu tải cao và sẵn sàng cao.',
link: '/vi-vn/stage-3/'
},
{
title: 'Thương hiệu cá nhân',
desc: 'Xây dựng website và blog học thuật của riêng bạn.',
link: '/vi-vn/stage-3/'
}
]
},
appendix: {
cat: 'Appendix · Phụ lục',
title:
'Encyclopedia, <br><span class="highlight">Solid Foundation.</span>',
sub: 'From Computer Networks to AI Principles, complete your tech puzzle.',
cards: [
{
title: 'AI Fundamentals',
desc: 'LLM, Agent, RAG. Dive into AI internals.',
link: '/vi-vn/appendix/ai-evolution'
},
{
title: 'Frontend',
desc: 'Browser internals, Performance, Canvas.',
link: '/vi-vn/appendix/web-basics'
},
{
title: 'Backend',
desc: 'High concurrency, Distributed systems, Microservices.',
link: '/vi-vn/appendix/backend-evolution'
},
{
title: 'General Skills',
desc: 'Git, Networks, IDE internals.',
link: '/vi-vn/appendix/git-intro'
}
]
},
footer: {
title: 'Sẵn sàng chưa?',
desc: 'Easy-Vibe, biến lập trình trở nên tự nhiên như hơi thở.',
btn: 'Bắt đầu ngay'
}
}
}
const t = computed(() => {
const code = lang.value ? lang.value.toLowerCase() : 'zh-cn'
return i18n[code] || i18n['en']
})
provide('t', t)
const isCjkLocale = computed(() => {
const code = lang.value ? lang.value.toLowerCase() : ''
if (['zh-cn', 'zh-tw', 'ja-jp', 'ko-kr'].includes(code)) {
return true
}
const path = router.route.path.toLowerCase()
return /^\/(zh-cn|zh-tw|ja-jp|ko-kr)\//.test(path)
})
const topPromo = computed(() => {
const code = lang.value ? lang.value.toLowerCase() : 'en'
if (code === 'zh-cn' || code === 'zh-tw') {
return {
text: '用 Easy-Vibe 构建你的第一个 AI 应用,最快当天可上线原型。',
cta: '开始学习 ',
link: '/zh-cn/stage-1/learning-map/'
}
}
return {
text: 'Build your first AI app with Easy-Vibe and ship a working prototype fast.',
cta: 'Start learning ',
link: '/en/stage-1/learning-map/'
}
})
const appleFooterInfo = computed(() => {
const locale = lang.value ? lang.value.toLowerCase() : 'zh-cn'
const content = {
'zh-cn': {
notes: [
'1. 学习路径与章节内容会持续更新,显示内容以当前页面为准。',
'2. 示例项目与截图用于教学演示,可能与后续版本界面存在差异。',
'3. 部分章节链接会随着课程迭代调整,建议优先从首页导航进入最新路径。'
],
breadcrumbPrefix: 'Easy-Vibe',
breadcrumbCurrent: '学习导航',
columns: [
{
title: '学习与导航',
links: ['零基础入门', '初中级开发', '高级开发', '附录', '学习地图', '课程总览']
},
{
title: '学习支持',
links: ['常见问题', '学习建议', '章节勘误', '版本更新']
},
{
title: '项目资源',
links: ['GitHub 仓库', '开源协议', '提交 Issue', '贡献指南']
},
{
title: '社区',
links: ['学习社群', '讨论区', '课程反馈']
},
{
title: '关于 Easy-Vibe',
links: ['项目介绍', '更新日志', '联系我们']
}
],
more: '更多学习方式:访问',
moreLink: 'GitHub 仓库',
moreTail: ',获取更新与交流信息。',
copyright: 'Copyright © 2026 Easy-Vibe. 保留所有权利。',
policies: ['隐私政策', '使用条款', '网站地图']
},
en: {
notes: [
'1. Learning paths and chapters are continuously updated.',
'2. Screenshots and demo projects are for educational illustration.',
'3. Some chapter links may change as the course evolves.',
'4. The page is optimized for modern desktop browsers and responsive layouts.'
],
breadcrumbPrefix: 'Easy-Vibe',
breadcrumbCurrent: 'Learning Navigation',
columns: [
{
title: 'Explore',
links: ['Foundations', 'Junior/Mid Dev', 'Senior Dev', 'Appendix', 'Learning Map', 'Course Outline']
},
{
title: 'Support',
links: ['FAQ', 'Learning Tips', 'Errata', 'Release Notes']
},
{
title: 'Resources',
links: ['GitHub Repository', 'License', 'Report Issue', 'Contribution Guide']
},
{
title: 'Community',
links: ['Community', 'Discussions', 'Feedback']
},
{
title: 'About Easy-Vibe',
links: ['Overview', 'Changelog', 'Contact']
}
],
more: 'More ways to learn: visit',
moreLink: 'GitHub Repository',
moreTail: ' for updates and community discussions.',
copyright: 'Copyright © 2026 Easy-Vibe. All rights reserved.',
policies: ['Privacy Policy', 'Terms of Use', 'Sitemap']
}
}
return content[locale] || content.en
})
const footerRepositoryLink = computed(() => {
const locale = lang.value ? lang.value.toLowerCase() : 'zh-cn'
if (locale === 'zh-cn') {
return 'https://github.com/datawhalechina/easy-vibe'
}
return 'https://github.com/datawhalechina/easy-vibe'
})
const footerPolicyLinkMap = {
'隐私政策': '#',
'使用条款': '#',
'网站地图': '#',
'Privacy Policy': '#',
'Terms of Use': '#',
'Sitemap': '#'
}
const footerColumnLinkMap = {
'零基础入门': '/zh-cn/stage-1/',
'初中级开发': '/zh-cn/stage-2/',
'高级开发': '/zh-cn/stage-3/',
'附录': '/zh-cn/appendix/',
'学习地图': '/zh-cn/stage-1/learning-map/',
'课程总览': '/zh-cn/stage-1/',
'GitHub 仓库': 'https://github.com/datawhalechina/easy-vibe',
'Foundations': '/en/stage-1/',
'Junior/Mid Dev': '/en/stage-2/',
'Senior Dev': '/en/stage-3/',
'Appendix': '/en/appendix/',
'Learning Map': '/en/stage-1/learning-map/',
'Course Outline': '/en/stage-1/',
'GitHub Repository': 'https://github.com/datawhalechina/easy-vibe',
'Overview': '/en/guide/introduction',
'Changelog': 'https://github.com/datawhalechina/easy-vibe/releases'
}
const getFooterLink = (label) => {
return footerColumnLinkMap[label] || '#'
}
const getPolicyLink = (label) => {
return footerPolicyLinkMap[label] || '#'
}
const resolveFooterHref = (link) => {
if (link.startsWith('http://') || link.startsWith('https://')) {
return link
}
return withBase(link)
}
const locales = [
{ code: 'zh-cn', text: '简体中文' },
{ code: 'en', text: 'English' },
{ code: 'ja-jp', text: '日本語' },
{ code: 'zh-tw', text: '繁體中文' },
{ code: 'ko-kr', text: '한국어' },
{ code: 'es-es', text: 'Español' },
{ code: 'fr-fr', text: 'Français' },
{ code: 'de-de', text: 'Deutsch' },
{ code: 'ar-sa', text: 'العربية' },
{ code: 'vi-vn', text: 'Tiếng Việt' }
]
const toggleLangMenu = () => {
showLangMenu.value = !showLangMenu.value
}
const updateHash = (id) => {
const targetHash = id === 'home' ? '#home' : `#${id}`
const currentUrl = `${window.location.pathname}${window.location.search}${window.location.hash}`
const nextUrl = `${window.location.pathname}${window.location.search}${targetHash}`
if (currentUrl !== nextUrl) {
window.history.replaceState(null, '', nextUrl)
}
}
const syncTopPromoWithHash = () => {
const rawHash = window.location.hash.replace(/^#/, '')
const targetId = rawHash || 'home'
if (targetId === 'home') {
topPromoDismissed.value = false
topPromoProgress.value = 1
return
}
topPromoDismissed.value = true
topPromoProgress.value = 0
}
const changeLang = (targetLocale) => {
const currentPath = router.route.path
// Find current locale based on path prefix
const currentLocale = locales.find((l) =>
currentPath.startsWith(`/${l.code}/`)
)
let newPath
if (currentLocale) {
newPath = currentPath.replace(
`/${currentLocale.code}/`,
`/${targetLocale}/`
)
} else {
// Fallback for root path or missing locale prefix
newPath = `/${targetLocale}/`
}
const hash = window.location.hash || ''
router.go(withBase(`${newPath}${hash}`))
showLangMenu.value = false
}
const scrollTo = (id) => {
if (id === 'home') {
window.scrollTo({ top: 0, behavior: 'smooth' })
activeTab.value = 'home'
updateHash('home')
syncTopPromoWithHash()
updateTopPromoVisibility()
return
}
const el = document.getElementById(id)
if (el) {
const navHeight = 48
const elementPosition = el.getBoundingClientRect().top + window.pageYOffset
const extraOffset = id === 'vibe-stories' ? 20 : 40
const offset = elementPosition - navHeight - extraOffset
window.scrollTo({ top: offset, behavior: 'smooth' })
activeTab.value = id
updateHash(id)
syncTopPromoWithHash()
}
}
const scrollToHashTarget = (behavior = 'auto') => {
const rawHash = window.location.hash.replace(/^#/, '')
const targetId = rawHash || 'home'
if (targetId === 'home') {
window.scrollTo({ top: 0, behavior })
activeTab.value = 'home'
syncTopPromoWithHash()
updateTopPromoVisibility()
return
}
const el = document.getElementById(targetId)
if (el) {
const navHeight = 48
const elementPosition = el.getBoundingClientRect().top + window.pageYOffset
const extraOffset = targetId === 'vibe-stories' ? 20 : 40
const offset = elementPosition - navHeight - extraOffset
window.scrollTo({ top: offset, behavior })
activeTab.value = targetId
syncTopPromoWithHash()
}
}
// Close lang menu on click outside
const closeLangMenu = (e) => {
if (!e.target.closest('.lang-switch-wrapper')) {
showLangMenu.value = false
}
}
const updateTopPromoVisibility = () => {
if (topPromoDismissed.value) {
topPromoProgress.value = 0
return
}
if (!vibeStoriesSection.value) {
topPromoProgress.value = 1
return
}
const navHeight = 44
const sectionTop =
vibeStoriesSection.value.getBoundingClientRect().top + window.pageYOffset
const endY = sectionTop - navHeight
const startY = endY - 96
const scrollY = window.pageYOffset
if (scrollY <= startY) {
topPromoProgress.value = 1
return
}
if (scrollY >= endY) {
topPromoProgress.value = 0
topPromoDismissed.value = true
return
}
topPromoProgress.value = (endY - scrollY) / (endY - startY)
}
const topPromoStyle = computed(() => {
const scrollProgress = topPromoProgress.value
const introProgress = topPromoIntroProgress.value
const colorProgress = topPromoColorProgress.value
const progress = scrollProgress * introProgress
const scrollOffset = -100 * (1 - scrollProgress)
const startTextColor = { r: 255, g: 255, b: 255 }
const endTextColor = { r: 29, g: 29, b: 31 }
const startBgColor = { r: 0, g: 113, b: 227 }
const endBgColor = { r: 245, g: 245, b: 247 }
const startLinkColor = { r: 255, g: 255, b: 255 }
const endLinkColor = { r: 0, g: 102, b: 204 }
const textColor = `rgb(${Math.round(startTextColor.r + (endTextColor.r - startTextColor.r) * colorProgress)}, ${Math.round(startTextColor.g + (endTextColor.g - startTextColor.g) * colorProgress)}, ${Math.round(startTextColor.b + (endTextColor.b - startTextColor.b) * colorProgress)})`
const bgColor = `rgb(${Math.round(startBgColor.r + (endBgColor.r - startBgColor.r) * colorProgress)}, ${Math.round(startBgColor.g + (endBgColor.g - startBgColor.g) * colorProgress)}, ${Math.round(startBgColor.b + (endBgColor.b - startBgColor.b) * colorProgress)})`
const linkColor = `rgb(${Math.round(startLinkColor.r + (endLinkColor.r - startLinkColor.r) * colorProgress)}, ${Math.round(startLinkColor.g + (endLinkColor.g - startLinkColor.g) * colorProgress)}, ${Math.round(startLinkColor.b + (endLinkColor.b - startLinkColor.b) * colorProgress)})`
return {
opacity: progress,
transform: `translateY(${scrollOffset}%)`,
maxHeight: `${30 * progress}px`,
backgroundColor: bgColor,
color: textColor,
'--top-promo-link-color': linkColor,
pointerEvents: progress < 0.02 ? 'none' : 'auto'
}
})
onMounted(() => {
const introDuration = 1800
const colorDelay = 500
const colorDuration = 1800
const introStart = performance.now()
const stepTopPromoIntro = (now) => {
const raw = Math.min(1, (now - introStart) / introDuration)
const eased = 1 - Math.pow(1 - raw, 3)
topPromoIntroProgress.value = eased
if (raw < 1) {
topPromoIntroRaf = window.requestAnimationFrame(stepTopPromoIntro)
return
}
topPromoColorTimer = window.setTimeout(() => {
const colorStart = performance.now()
const stepTopPromoColor = (time) => {
const colorRaw = Math.min(1, (time - colorStart) / colorDuration)
const colorEased = 1 - Math.pow(1 - colorRaw, 3)
topPromoColorProgress.value = colorEased
if (colorRaw < 1) {
topPromoColorRaf = window.requestAnimationFrame(stepTopPromoColor)
}
}
topPromoColorRaf = window.requestAnimationFrame(stepTopPromoColor)
}, colorDelay)
}
topPromoIntroRaf = window.requestAnimationFrame(stepTopPromoIntro)
const currentPath = window.location.pathname
const basePath = site.value.base || '/'
const normalizedBase = basePath.endsWith('/') ? basePath : `${basePath}/`
const normalizedPath = currentPath.endsWith('/')
? currentPath
: `${currentPath}/`
const localeHomeSuffixes = [
'/zh-cn/',
'/en/',
'/zh-tw/',
'/ja-jp/',
'/ko-kr/',
'/es-es/',
'/fr-fr/',
'/de-de/',
'/ar-sa/',
'/vi-vn/'
]
const isLocaleHome = localeHomeSuffixes.some(
(suffix) =>
currentPath.endsWith(suffix) ||
currentPath.endsWith(`${suffix}index.html`)
)
const isRootHome =
normalizedPath === normalizedBase ||
currentPath === `${normalizedBase}index.html`
if (isRootHome && !isLocaleHome) {
const hasSeenWelcome = window.localStorage.getItem(WELCOME_SEEN_KEY) === '1'
if (!hasSeenWelcome) {
router.go(withBase(`/welcome/?next=${encodeURIComponent(currentPath)}`))
return
}
}
document.addEventListener('click', closeLangMenu)
if (appendixWrapper.value) {
appendixWrapper.value.addEventListener('scroll', onAppendixScroll)
updatePagination()
window.addEventListener('resize', updatePagination)
}
syncTopPromoWithHash()
window.setTimeout(() => {
scrollToHashTarget('auto')
}, 0)
updateTopPromoVisibility()
window.addEventListener('scroll', updateTopPromoVisibility, { passive: true })
window.addEventListener('resize', updateTopPromoVisibility)
window.addEventListener('hashchange', scrollToHashTarget)
})
onUnmounted(() => {
if (topPromoIntroRaf) {
window.cancelAnimationFrame(topPromoIntroRaf)
topPromoIntroRaf = 0
}
if (topPromoColorRaf) {
window.cancelAnimationFrame(topPromoColorRaf)
topPromoColorRaf = 0
}
if (topPromoColorTimer) {
window.clearTimeout(topPromoColorTimer)
topPromoColorTimer = 0
}
document.removeEventListener('click', closeLangMenu)
if (appendixWrapper.value) {
appendixWrapper.value.removeEventListener('scroll', onAppendixScroll)
}
window.removeEventListener('resize', updatePagination)
window.removeEventListener('scroll', updateTopPromoVisibility)
window.removeEventListener('resize', updateTopPromoVisibility)
window.removeEventListener('hashchange', scrollToHashTarget)
})
// Stage 1: 产品经理 (Web 原型)
const stage1Cards = [
{
title: 'AI 产品经理',
desc: '从想法到高保真原型,你只需要会说话。',
sub: '适合非技术背景',
color: 'linear-gradient(135deg, #FF9A9E 0%, #FECFEF 99%, #FECFEF 100%)',
icon: '🎨',
link: '/zh-cn/stage-1/learning-map/'
},
{
title: '游戏化入门',
desc: '通过制作贪吃蛇、俄罗斯方块,打破对代码的恐惧。',
sub: '边玩边学',
color: 'linear-gradient(120deg, #a1c4fd 0%, #c2e9fb 100%)',
icon: '🎮',
link: '/zh-cn/stage-1/ai-capabilities-through-games/'
},
{
title: 'Vibe Coding',
desc: '掌握 AI 时代的编程核心:提示词工程与上下文管理。',
sub: '核心心法',
color: 'linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%)',
icon: '💡',
link: '/zh-cn/stage-1/introduction-to-ai-ide/'
}
]
// Stage 2: 初中级开发 (全栈)
const stage2Cards = [
{
imageColor: '#E0C3FC',
image: stage2LovartCover,
imageAlt: 'Lovart 素材生产 Agent 界面截图',
link: '/zh-cn/stage-2/frontend/lovart-assets/'
},
{
imageColor: '#D8C4F8',
image: stage2FigmaCover,
imageAlt: 'Figma 与 MasterGo 设计工具截图',
link: '/zh-cn/stage-2/frontend/figma-mastergo/'
},
{
imageColor: '#C7DDFB',
image: stage2DesignToCodeCover,
imageAlt: '设计稿转代码示意截图',
link: '/zh-cn/stage-2/frontend/design-to-code/'
},
{
imageColor: '#8EC5FC',
image: stage2SupabaseCover,
imageAlt: 'Supabase 数据库控制台截图',
link: '/zh-cn/stage-2/backend/database-supabase/'
},
{
imageColor: '#96E6A1',
image: stage2ZeaburCover,
imageAlt: 'Zeabur 部署流程截图',
link: '/zh-cn/stage-2/backend/zeabur-deployment/'
},
{
imageColor: '#A7F3D0',
image: stage2DifyCover,
imageAlt: 'Dify 知识库工作台截图',
link: '/zh-cn/stage-2/ai-capabilities/dify-knowledge-base/'
}
]
const localizedStage2Cards = computed(() => {
return t.value.stage2.cards.map((card, index) => {
const visual = stage2Cards.find((item) => item.link === card.link) || stage2Cards[index]
return {
...card,
...visual
}
})
})
// Stage 3: 高级开发 (小程序 & AI)
const stage3Cards = [
{
title: '跨平台桌面应用',
desc: '用 Electron 做语音转文字桌面程序,一次开发同时跑在 Windows、macOS、Linux。',
tag: 'Stage 3',
visualType: 'phone',
image: stage3ElectronCover,
imageAlt: 'Electron 语音转文字桌面应用预览图',
link: '/zh-cn/stage-3/cross-platform/electron-voice-to-text/'
},
{
title: 'AI 智能体团队',
desc: '用 Claude Agent Teams 组建 AI 开发小队,多代理协作完成大型任务。',
tag: 'Advanced',
visualType: 'ai',
image: stage3AgentTeamsCover,
imageAlt: 'Claude Agent Teams 协作流程封面图',
link: '/zh-cn/stage-3/core-skills/agent-teams/'
},
{
title: '长效稳定执行',
desc: '用循环脚本和 Ralph 插件管理长时间任务,让 Claude Code 过夜稳定跑完工作。',
tag: 'Architecture',
visualType: 'arch',
image: stage3LongRunningCover,
imageAlt: 'Claude Code 长时间执行与循环任务封面图',
link: '/zh-cn/stage-3/core-skills/long-running-tasks/'
},
{
title: '个人品牌与输出',
desc: '搭建个人网站与技术博客,让你的项目和经验长期沉淀并被更多人看到。',
tag: 'Brand',
visualType: 'brand',
image: stage3PersonalBrandCover,
imageAlt: '个人网站与学术博客示例截图',
imageClass: 'prod-image--personal-brand',
link: '/zh-cn/stage-3/personal-brand/personal-website-blog/'
}
]
// Appendix: 附录
const appendixCards = [
{
title: '人工智能',
desc: 'LLM、Agent、RAG,深入 AI 底层原理。',
tag: 'AI',
link: '/zh-cn/appendix/8-artificial-intelligence/ai-history'
},
{
title: '提示词工程',
desc: '掌握与 AI 高效对话的技巧,解锁潜力。',
tag: 'AI',
link: '/zh-cn/appendix/8-artificial-intelligence/prompt-engineering'
},
{
title: '大语言模型',
desc: '深入浅出解析 LLM 的工作原理与应用。',
tag: 'AI',
link: '/zh-cn/appendix/8-artificial-intelligence/llm-principles'
},
{
title: 'Agent 智能体',
desc: '探索具备自主决策与执行能力的 AI 架构。',
tag: 'AI',
link: '/zh-cn/appendix/8-artificial-intelligence/ai-agents'
},
{
title: '前端基础',
desc: 'HTML/CSS/JS 三大基石,入门必修课。',
tag: 'Frontend',
link: '/zh-cn/appendix/3-browser-and-frontend/javascript-deep-dive'
},
{
title: '前端进化史',
desc: '了解前端技术栈演变,把握发展趋势。',
tag: 'Frontend',
link: '/zh-cn/appendix/3-browser-and-frontend/frontend-frameworks'
},
{
title: '后端架构',
desc: '从单体到微服务,探索架构演进之路。',
tag: 'Backend',
link: '/zh-cn/appendix/4-server-and-backend/backend-layered-architecture'
},
{
title: '后端语言',
desc: '对比主流后端语言特性,选择最佳技术栈。',
tag: 'Backend',
link: '/zh-cn/appendix/4-server-and-backend/backend-languages'
},
{
title: '数据库原理',
desc: '理解数据库核心原理,掌握数据存储艺术。',
tag: 'Database',
link: '/zh-cn/appendix/5-data/database-fundamentals'
},
{
title: 'API 设计',
desc: 'API 接口设计与开发的基础知识。',
tag: 'API',
link: '/zh-cn/appendix/4-server-and-backend/api-intro'
},
{
title: 'Git 版本控制',
desc: '深入理解 Git 原理与高级用法。',
tag: 'General',
link: '/zh-cn/appendix/2-development-tools/git-version-control'
},
{
title: '计算机网络',
desc: '网络协议与通信原理的基础知识。',
tag: 'General',
link: '/zh-cn/appendix/1-computer-fundamentals/computer-networks'
}
]
</script>
<template>
<div class="apple-container">
<!-- Sticky Navigation -->
<nav class="sticky-nav glass">
<div class="nav-content">
<div class="nav-cluster">
<div
class="nav-title"
:aria-label="t.nav.title"
>
<img
class="nav-title-logo no-viewer"
:src="withBase('/assets/easy-vibe-logo-hd.svg')"
:alt="t.nav.title"
width="64"
height="30"
draggable="false"
>
</div>
<div class="nav-links">
<button
:class="{ active: activeTab === 'home' }"
class="nav-link-item"
@click="scrollTo('home')"
>
{{ t.nav.home }}
</button>
<button
:class="{ active: activeTab === 'vibe-stories' }"
class="nav-link-item"
@click="scrollTo('vibe-stories')"
>
{{ t.nav.stories || 'Vibe 故事' }}
</button>
<button
:class="{ active: activeTab === 'pm' }"
class="nav-link-item"
@click="scrollTo('pm')"
>
{{ t.nav.pm }}
</button>
<button
:class="{ active: activeTab === 'junior' }"
class="nav-link-item"
@click="scrollTo('junior')"
>
{{ t.nav.junior }}
</button>
<button
:class="{ active: activeTab === 'senior' }"
class="nav-link-item"
@click="scrollTo('senior')"
>
{{ t.nav.senior }}
</button>
<button
:class="{ active: activeTab === 'appendix' }"
class="nav-link-item"
@click="scrollTo('appendix')"
>
{{ t.nav.appendix }}
</button>
</div>
<div class="nav-action">
<div class="nav-icons">
<div class="lang-switch-wrapper">
<button
type="button"
class="button"
aria-haspopup="true"
:aria-expanded="showLangMenu"
aria-label="Change language"
@click.stop="toggleLangMenu"
>
<span class="text">
<span class="vpi-languages option-icon" />
<span class="vpi-chevron-down text-icon" />
</span>
</button>
<div
v-if="showLangMenu"
class="lang-dropdown glass"
>
<button
v-for="locale in locales"
:key="locale.code"
class="lang-item"
@click="changeLang(locale.code)"
>
{{ locale.text }}
</button>
</div>
</div>
<GitHubStars class="nav-github-stars" />
</div>
<a
class="buy-btn"
:href="withBase(t.stage1.cards[0].link)"
>{{ t.footer.btn }}</a>
</div>
</div>
</div>
<div
class="nav-promo"
:style="topPromoStyle"
>
<span>{{ topPromo.text }}</span>
<a :href="resolveFooterHref(topPromo.link)">{{ topPromo.cta }}</a>
</div>
</nav>
<!-- Home Anchor -->
<div
id="home"
style="height: 0"
/>
<!-- Vibe Stories -->
<section
id="vibe-stories"
ref="vibeStoriesSection"
class="section-container"
>
<VibeStories />
</section>
<div class="section-band section-band-learning">
<!-- Stage 1: Product Manager -->
<section id="pm" class="section-container section-pm">
<div class="section-header">
<h2 class="section-category">
{{ t.stage1.cat }}
</h2>
<h3
class="section-headline"
v-html="t.stage1.title"
/>
<p class="section-sub">
{{ t.stage1.sub }}
</p>
</div>
<div class="feature-grid">
<a
v-for="(card, i) in stage1Cards"
:key="i"
:href="withBase(t.stage1.cards[i].link)"
class="feature-card glass"
>
<div
class="feature-icon"
:style="{ background: card.color }"
>
{{ card.icon }}
</div>
<div class="feature-content">
<h4>{{ t.stage1.cards[i].title }}</h4>
<p>{{ t.stage1.cards[i].desc }}</p>
</div>
</a>
</div>
</section>
<!-- Stage 2: Junior/Mid Dev -->
<section
id="junior"
class="section-container section-junior"
>
<div class="section-header">
<h2 class="section-category">
{{ t.stage2.cat }}
</h2>
<h3
class="section-headline"
v-html="t.stage2.title"
/>
<p class="section-sub">
{{ t.stage2.sub }}
</p>
</div>
<div class="comm-grid">
<a
v-for="(card, index) in localizedStage2Cards"
:key="index"
:href="withBase(card.link)"
class="comm-card glass"
>
<div
class="comm-visual"
:style="{ backgroundColor: card.imageColor }"
>
<img
:src="card.image"
:alt="card.imageAlt || card.title"
loading="lazy"
>
</div>
<div class="comm-text">
<h4 class="comm-title">{{ card.title }}</h4>
<p class="comm-desc">{{ card.desc }}</p>
<span class="comm-note">进一步了解 </span>
</div>
</a>
</div>
</section>
</div>
<!-- Stage 3: Senior Dev -->
<section
id="senior"
class="section-container section-senior"
>
<div class="section-header">
<h2 class="section-category">
{{ t.stage3.cat }}
</h2>
<h3
class="section-headline"
v-html="t.stage3.title"
/>
<p class="section-sub">
{{ t.stage3.sub }}
</p>
</div>
<div class="scroll-container">
<div class="scroll-track">
<a
v-for="(card, index) in stage3Cards"
:key="index"
:href="withBase(t.stage3.cards[index].link)"
class="prod-card glass"
>
<div class="prod-tag">{{ card.tag }}</div>
<h4>{{ t.stage3.cards[index].title }}</h4>
<p>{{ t.stage3.cards[index].desc }}</p>
<div class="prod-visual">
<img
:src="card.image"
:alt="card.imageAlt"
:class="card.imageClass"
loading="lazy"
>
</div>
</a>
</div>
</div>
</section>
<!-- Appendix -->
<section
id="appendix"
class="section-container section-appendix"
>
<div class="section-header">
<h2 class="section-category">
{{ t.appendix.cat }}
</h2>
<h3
class="section-headline"
v-html="t.appendix.title"
/>
<p class="section-sub">
{{ t.appendix.sub }}
</p>
</div>
<div
ref="appendixWrapper"
class="appendix-scroll-wrapper"
>
<div class="appendix-track">
<a
v-for="(card, index) in t.appendix.cards"
:key="index"
:href="withBase(card.link)"
class="appendix-card"
>
<span class="appendix-emoji">{{
['🤖', '🧠', '🎨', '🚀', '⚙️', '💾', '🛠️', '🌐'][index] || '📚'
}}</span>
<span class="appendix-title">{{ card.title }}</span>
</a>
</div>
</div>
<div
v-if="totalPages > 1"
class="appendix-scroll-hint"
>
<div class="appendix-progress-track">
<div
class="appendix-progress-thumb"
:style="{
width: `${100 / totalPages}%`,
transform: `translateX(${currentPage * 100}%)`
}"
/>
</div>
<div class="appendix-scroll-actions">
<button
class="appendix-arrow-btn"
:class="{ disabled: currentPage === 0 }"
:disabled="currentPage === 0"
aria-label="向左滑动"
@click="scrollAppendixByPage(-1)"
>
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
>
<path
d="M11.5 5.5L7 10L11.5 14.5"
stroke="currentColor"
stroke-width="2.4"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</button>
<button
class="appendix-arrow-btn"
:class="{ disabled: currentPage >= totalPages - 1 }"
:disabled="currentPage >= totalPages - 1"
aria-label="向右滑动"
@click="scrollAppendixByPage(1)"
>
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
>
<path
d="M8.5 5.5L13 10L8.5 14.5"
stroke="currentColor"
stroke-width="2.4"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</button>
</div>
</div>
</section>
<!-- Footer Callout -->
<div class="footer-callout">
<h2 v-html="t.footer.title" />
<p>{{ t.footer.desc }}</p>
<a
class="buy-btn large"
:href="withBase('/zh-cn/stage-1/learning-map/')"
>{{ t.footer.btn }}</a>
</div>
<div
class="apple-site-footer"
:class="{ 'is-cjk-locale': isCjkLocale }"
>
<div class="apple-site-footer-inner">
<div class="apple-footer-breadcrumb">
<span></span>
<span></span>
<span>{{ appleFooterInfo.breadcrumbPrefix }}</span>
<span></span>
<span>{{ appleFooterInfo.breadcrumbCurrent }}</span>
</div>
<div class="apple-footer-notes">
<p
v-for="(item, idx) in appleFooterInfo.notes"
:key="idx"
>
{{ item }}
</p>
</div>
<div class="apple-footer-grid">
<div
v-for="(column, index) in appleFooterInfo.columns"
:key="index"
class="apple-footer-column"
>
<h4>{{ column.title }}</h4>
<a
v-for="(link, linkIndex) in column.links"
:key="linkIndex"
:href="resolveFooterHref(getFooterLink(link))"
>
{{ link }}
</a>
</div>
</div>
<div class="apple-footer-more">
{{ appleFooterInfo.more }}
<a :href="footerRepositoryLink">{{ appleFooterInfo.moreLink }}</a>
{{ appleFooterInfo.moreTail }}
</div>
<div class="apple-footer-bottom">
<p>{{ appleFooterInfo.copyright }}</p>
<div class="apple-footer-policy">
<a
v-for="(policy, policyIndex) in appleFooterInfo.policies"
:key="policyIndex"
:href="resolveFooterHref(getPolicyLink(policy))"
>
{{ policy }}
</a>
</div>
</div>
</div>
</div>
</div>
</template>
<style scoped>
/* Reset & Base */
.apple-container {
font-family:
-apple-system, BlinkMacSystemFont, 'SF Pro Text', 'PingFang SC',
'Helvetica Neue', sans-serif;
color: var(--vp-c-text-1);
background: transparent;
}
#vibe-stories,
#vibe-stories:focus,
#vibe-stories:focus-visible,
#vibe-stories:target {
outline: none !important;
box-shadow: none !important;
}
a {
text-decoration: none;
color: inherit;
}
:is(.feature-card, .comm-card, .prod-card, .appendix-card, .buy-btn) {
border-bottom: none !important;
outline: none !important;
-webkit-tap-highlight-color: transparent;
}
:is(
.feature-card,
.comm-card,
.prod-card,
.appendix-card,
.buy-btn
):is(:hover, :focus, :focus-visible, :active) {
border-bottom-color: transparent !important;
text-decoration: none !important;
outline: none !important;
}
.highlight {
color: var(--vp-c-text-2);
}
/* Sticky Nav */
.sticky-nav {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 100;
border-bottom: 1px solid #d2d2d7;
transition: all 0.3s ease;
background: rgba(245, 245, 247, 0.82);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
}
/* Dark mode adjustment for glass effect */
:root.dark .sticky-nav {
background: rgba(18, 18, 20, 0.8);
border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}
.nav-content {
max-width: 1280px;
margin: 0 auto;
padding: 0 28px;
height: 44px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
z-index: 2;
}
.nav-cluster {
display: flex;
align-items: center;
gap: 20px;
max-width: 100%;
}
.nav-title {
flex-shrink: 0;
background: none;
border: none;
padding: 0;
margin: 0;
cursor: default;
display: inline-flex;
align-items: center;
}
.nav-title-logo {
display: block;
max-width: 64px !important;
max-height: 30px !important;
height: 30px !important;
width: 64px !important;
min-width: 64px;
min-height: 30px;
object-fit: contain;
flex: 0 0 auto;
filter: grayscale(1) brightness(0.28) contrast(1.05);
}
.nav-links {
display: flex;
gap: 20px;
align-items: center;
margin: 0;
white-space: nowrap;
}
.nav-links button,
.nav-link-item {
background: none;
border: none;
font-size: 12px;
color: var(--vp-c-text-1) !important;
cursor: pointer;
transition: opacity 0.2s;
padding: 0;
margin: 0;
line-height: 1;
font-weight: 400;
opacity: 0.76;
text-decoration: none;
}
.nav-links button:hover,
.nav-links button.active,
.nav-link-item:hover {
color: var(--vp-c-text-1) !important;
opacity: 1;
}
.nav-action {
display: flex;
align-items: center;
gap: 10px;
flex-shrink: 0;
}
.nav-icons {
display: flex;
gap: 10px;
align-items: center;
}
:deep(.nav-github-stars) {
display: flex;
align-items: center;
}
:deep(.nav-github-stars .github-stars-link) {
color: var(--vp-c-text-1) !important;
display: flex;
align-items: center;
gap: 4px;
text-decoration: none;
}
:deep(.nav-github-stars .github-stars-link:hover) {
opacity: 0.7;
}
:deep(.nav-github-stars .github-stars-wrapper) {
padding-left: 0 !important;
}
.nav-promo {
height: 30px;
max-height: 30px;
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
font-size: 13px;
color: #1d1d1f;
padding: 0 16px;
overflow: hidden;
transform-origin: top center;
position: relative;
z-index: 1;
will-change: transform, opacity, max-height, background-color, color;
transition:
transform 0.16s ease-out,
opacity 0.16s ease-out,
max-height 0.16s ease-out,
background-color 0.22s ease-out,
color 0.22s ease-out;
}
.nav-promo a {
color: var(--top-promo-link-color, #0066cc);
text-decoration: none;
transition: color 0.25s ease-out;
}
.button {
background: none;
border: none;
padding: 0;
color: var(--vp-c-text-1) !important;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
opacity: 1;
transition: opacity 0.2s;
}
.button:hover {
opacity: 0.7;
}
.button .text {
display: flex;
align-items: center;
gap: 2px;
}
.button .option-icon {
width: 20px;
height: 20px;
color: var(--vp-c-text-1) !important;
}
.button .text-icon {
width: 14px;
height: 14px;
color: var(--vp-c-text-1) !important;
}
/* Lang Switcher */
.lang-switch-wrapper {
position: relative;
display: flex;
align-items: center;
}
.lang-dropdown {
position: absolute;
top: 100%;
right: -10px; /* Align slightly to right */
margin-top: 12px;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 16px;
padding: 6px;
min-width: 140px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.14);
display: flex;
flex-direction: column;
gap: 2px;
max-height: 300px;
overflow-y: auto;
z-index: 20;
}
.lang-item {
text-align: left;
padding: 8px 12px;
border-radius: 6px;
font-size: 13px;
color: var(--vp-c-text-1);
transition: background 0.2s;
background: transparent;
border: none;
cursor: pointer;
white-space: nowrap;
}
.lang-item:hover {
background: var(--vp-c-bg-soft);
}
.buy-btn {
background: #0071e3;
color: #fff !important;
padding: 7px 16px;
border-radius: 980px;
font-size: 13px;
font-weight: 500;
line-height: 1;
transition: all 0.2s ease;
}
.buy-btn:hover {
background: #0077ed;
transform: scale(1.02);
}
.buy-btn.large {
padding: 12px 24px;
font-size: 15px;
margin-top: 20px;
display: inline-block;
}
/* Sections General */
.section-container {
max-width: 1280px;
margin: 0 auto 96px;
padding: 0 40px;
}
.section-band-learning {
width: 100vw;
max-width: none;
margin: 0 calc(50% - 50vw) 96px;
background: #f5f5f7;
border-radius: 0;
padding-top: 64px;
padding-bottom: 64px;
padding-left: max(40px, calc((100vw - 1280px) / 2 + 40px));
padding-right: max(40px, calc((100vw - 1280px) / 2 + 40px));
}
.section-band-learning .section-container {
max-width: 1280px;
margin: 0 auto;
padding: 0;
}
.section-band-learning .section-junior {
margin-top: 72px;
}
.section-appendix {
background: transparent;
border-radius: 0;
padding-top: 64px;
padding-bottom: 64px;
}
.dark .section-band-learning {
background: rgba(255, 255, 255, 0.03);
}
.dark .section-appendix {
background: transparent;
}
.section-header {
margin-bottom: 44px;
}
.section-category {
font-size: 24px;
font-weight: 700;
margin-bottom: 14px;
border: none;
padding: 0;
color: #1d1d1f;
letter-spacing: -0.024em;
font-family:
-apple-system, BlinkMacSystemFont, 'SF Pro Display', 'PingFang SC',
sans-serif;
}
.section-headline {
font-size: 64px;
line-height: 1.08;
font-weight: 700;
letter-spacing: -0.034em;
margin-bottom: 12px;
color: #1d1d1f;
font-family:
-apple-system, BlinkMacSystemFont, 'SF Pro Display', 'PingFang SC',
sans-serif;
}
.section-sub {
font-size: 21px;
line-height: 1.4;
font-weight: 400;
letter-spacing: -0.01em;
color: #6e6e73;
max-width: 760px;
font-family:
-apple-system, BlinkMacSystemFont, 'SF Pro Text', 'PingFang SC',
sans-serif;
}
/* Bento Grid */
.bento-grid {
display: grid;
grid-template-columns: 2fr 1fr;
gap: 24px;
height: 500px;
}
.bento-item {
border-radius: 30px;
padding: 40px;
position: relative;
overflow: hidden;
transition: transform 0.3s cubic-bezier(0.25, 0.1, 0.25, 1);
color: #1d1d1f; /* Force dark text on colorful backgrounds */
display: block;
}
.bento-item:hover {
transform: scale(1.02);
}
.bento-column {
display: flex;
flex-direction: column;
gap: 24px;
}
.bento-item.small {
flex: 1;
padding: 30px;
}
.card-icon {
font-size: 48px;
margin-bottom: 20px;
display: block;
}
.bento-item h4 {
font-size: 28px;
font-weight: 600;
margin-bottom: 10px;
line-height: 1.2;
}
.bento-item p {
font-size: 17px;
font-weight: 600;
line-height: 1.4;
opacity: 0.8;
}
.card-sub {
position: absolute;
bottom: 40px;
font-size: 14px;
opacity: 0.6;
}
/* Communication Grid (Now used for Stage 2) */
.comm-grid {
display: flex;
gap: 24px;
overflow-x: auto;
width: calc(100% + 40px);
margin: 0 -20px;
padding: 12px 20px 16px;
scroll-snap-type: x mandatory;
-webkit-overflow-scrolling: touch;
overscroll-behavior-x: contain;
scrollbar-width: none;
-ms-overflow-style: none;
}
.comm-grid::-webkit-scrollbar {
display: none;
}
.comm-card {
flex: 0 0 380px;
border-radius: 32px;
overflow: hidden;
background: #fff;
box-shadow: none;
border: 1px solid rgba(0, 0, 0, 0.025);
transition: transform 0.3s;
transform-origin: center top;
display: block;
scroll-snap-align: start;
}
.comm-card:hover {
transform: scale(1.015);
}
.comm-visual {
height: 220px;
width: 100%;
position: relative;
overflow: hidden;
}
.comm-visual img {
width: 100%;
height: 100%;
display: block;
object-fit: cover;
object-position: top center;
}
.comm-text {
padding: 26px 26px 30px;
}
.comm-title {
font-size: 28px;
font-weight: 700;
margin-bottom: 8px;
color: #1d1d1f;
letter-spacing: -0.02em;
font-family:
-apple-system, BlinkMacSystemFont, 'SF Pro Display', 'PingFang SC',
sans-serif;
}
.comm-desc {
font-size: 16px;
color: #6e6e73;
margin-bottom: 20px;
line-height: 1.5;
}
.comm-note {
font-size: 17px;
color: #0066cc;
letter-spacing: -0.01em;
}
/* Productivity Scroll (Now used for Stage 3) */
.scroll-container {
overflow-x: auto;
padding-bottom: 40px;
margin: 0 -20px;
padding: 12px 20px 40px;
-webkit-overflow-scrolling: touch;
scroll-snap-type: x mandatory;
overscroll-behavior-x: contain;
scrollbar-width: none;
-ms-overflow-style: none;
}
.scroll-container::-webkit-scrollbar {
display: none;
}
.scroll-track {
display: flex;
gap: 24px;
width: max-content;
}
.prod-card {
width: 300px;
height: 400px;
border-radius: 32px;
background: #f7f7f9;
padding: 30px;
scroll-snap-align: center;
text-decoration: none !important;
color: inherit !important;
display: flex;
flex-direction: column;
transition: transform 0.3s;
transform-origin: center top;
border: 1px solid rgba(0, 0, 0, 0.025);
box-shadow: none;
}
.prod-card:hover {
transform: scale(1.015);
}
.prod-tag {
font-size: 12px;
font-weight: 600;
color: #6e6e73;
margin-bottom: 10px;
text-transform: uppercase;
}
.prod-card h4 {
font-size: 34px;
font-weight: 700;
margin-bottom: 10px;
color: #1d1d1f;
letter-spacing: -0.025em;
font-family:
-apple-system, BlinkMacSystemFont, 'SF Pro Display', 'PingFang SC',
sans-serif;
}
.prod-card p {
color: #6e6e73;
font-size: 16px;
line-height: 1.5;
}
.prod-visual {
margin-top: auto;
height: 150px;
border-radius: 20px;
overflow: hidden;
background: linear-gradient(135deg, #dbeafe 0%, #e5e7eb 100%);
}
.prod-visual img {
width: 100%;
height: 100%;
display: block;
object-fit: cover;
object-position: center;
}
.prod-visual img.prod-image--personal-brand {
transform: scale(1.18) translateY(-10px);
transform-origin: center top;
}
/* Appendix Horizontal Scroll */
.appendix-scroll-wrapper {
overflow-x: auto;
scroll-snap-type: x mandatory;
margin: 0 -20px;
padding: 0 20px 12px;
scrollbar-width: none;
-ms-overflow-style: none;
overscroll-behavior-x: contain;
}
.appendix-scroll-wrapper::-webkit-scrollbar {
display: none;
}
.appendix-track {
display: flex;
align-items: flex-start;
gap: 40px;
width: max-content;
}
.appendix-card {
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
gap: 12px;
text-decoration: none !important;
color: inherit !important;
background: transparent;
padding: 0;
border: 0;
box-shadow: none;
scroll-snap-align: start;
width: 120px;
min-height: 120px;
transition: transform 0.25s ease;
text-align: center;
}
.appendix-card:hover {
transform: scale(1.03);
}
.appendix-emoji {
font-size: 52px;
line-height: 1;
display: block;
}
.appendix-title {
font-weight: 600;
color: #3c3c43;
margin: 0;
font-size: 14px;
line-height: 1.35;
letter-spacing: -0.01em;
white-space: normal;
}
.appendix-scroll-hint {
position: relative;
display: flex;
align-items: center;
justify-content: flex-end;
gap: 18px;
margin-top: 20px;
min-height: 40px;
}
.appendix-progress-track {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 160px;
height: 4px;
border-radius: 999px;
background: rgba(60, 60, 67, 0.08);
overflow: hidden;
}
.appendix-progress-thumb {
height: 100%;
border-radius: inherit;
background: rgba(60, 60, 67, 0.28);
transition: transform 0.25s ease;
}
.appendix-scroll-actions {
display: flex;
align-items: center;
gap: 10px;
margin-left: auto;
margin-right: 56px;
}
.appendix-arrow-btn {
width: 38px;
height: 38px;
border-radius: 999px;
border: 1px solid rgba(60, 60, 67, 0.05);
background: rgba(60, 60, 67, 0.05);
color: rgba(60, 60, 67, 0.62);
display: inline-flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition:
background-color 0.2s ease,
color 0.2s ease,
transform 0.2s ease;
}
.appendix-arrow-btn:hover {
background: rgba(255, 255, 255, 0.78);
border-color: rgba(60, 60, 67, 0.08);
color: rgba(60, 60, 67, 0.74);
transform: scale(1.04);
}
.appendix-arrow-btn.disabled,
.appendix-arrow-btn:disabled {
opacity: 0.42;
cursor: default;
transform: none;
}
.appendix-arrow-btn.disabled:hover,
.appendix-arrow-btn:disabled:hover {
background: rgba(60, 60, 67, 0.05);
color: rgba(60, 60, 67, 0.62);
}
/* Footer */
.footer-callout {
text-align: center;
padding: 92px 20px;
background: #fff;
margin: 0 40px 64px;
border-radius: 40px;
}
.footer-callout h2 {
font-size: 62px;
font-weight: 700;
margin-bottom: 20px;
line-height: 1.08;
letter-spacing: -0.03em;
color: #1d1d1f;
font-family:
-apple-system, BlinkMacSystemFont, 'SF Pro Display', 'PingFang SC',
sans-serif;
}
.footer-callout p {
color: #6e6e73;
font-size: 20px;
margin-bottom: 18px;
}
.apple-site-footer {
max-width: 1060px;
margin: 0 auto 56px;
padding: 0 40px;
}
.apple-site-footer-inner {
border-top: 1px solid #d2d2d7;
color: #6e6e73;
font-size: 12px;
}
.apple-footer-breadcrumb {
display: flex;
align-items: center;
gap: 8px;
color: #6e6e73;
font-size: 12px;
padding-top: 12px;
}
.apple-site-footer.is-cjk-locale .apple-footer-breadcrumb {
font-family:
'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Noto Sans CJK SC',
sans-serif;
font-size: 13px;
letter-spacing: 0.02em;
}
.apple-footer-notes {
padding-top: 18px;
}
.apple-footer-notes p {
margin: 0 0 8px;
line-height: 1.45;
color: #86868b;
}
.apple-site-footer.is-cjk-locale .apple-footer-notes p {
font-family:
'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Noto Sans CJK SC',
sans-serif;
font-size: 13px;
line-height: 1.88;
letter-spacing: 0.03em;
font-weight: 400;
color: #7d7d83;
}
.apple-footer-grid {
margin-top: 18px;
display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr));
gap: 22px;
}
.apple-footer-column h4 {
margin: 0 0 10px;
color: #1d1d1f;
font-size: 12px;
font-weight: 600;
}
.apple-site-footer.is-cjk-locale .apple-footer-column h4 {
font-family:
'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Noto Sans CJK SC',
sans-serif;
font-size: 13px;
line-height: 1.45;
letter-spacing: 0.025em;
}
.apple-footer-column a {
display: block;
color: #424245;
margin-bottom: 8px;
font-size: 12px;
line-height: 1.25;
}
.apple-site-footer.is-cjk-locale .apple-footer-column a {
font-family:
'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Noto Sans CJK SC',
sans-serif;
font-size: 13px;
line-height: 1.72;
letter-spacing: 0.02em;
margin-bottom: 9px;
}
.apple-footer-column a:hover {
color: #0066cc;
}
.apple-footer-more {
margin-top: 18px;
border-top: 1px solid #d2d2d7;
padding-top: 14px;
color: #6e6e73;
}
.apple-site-footer.is-cjk-locale .apple-footer-more {
font-family:
'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Noto Sans CJK SC',
sans-serif;
font-size: 13px;
line-height: 1.72;
letter-spacing: 0.02em;
}
.apple-footer-more a {
color: #0066cc;
}
.apple-footer-bottom {
margin-top: 14px;
padding-top: 14px;
border-top: 1px solid #d2d2d7;
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
}
.apple-footer-bottom p {
margin: 0;
color: #86868b;
}
.apple-site-footer.is-cjk-locale .apple-footer-bottom p {
font-family:
'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Noto Sans CJK SC',
sans-serif;
font-size: 13px;
line-height: 1.55;
letter-spacing: 0.02em;
}
.apple-footer-policy {
display: flex;
gap: 16px;
flex-wrap: wrap;
}
.apple-footer-policy a {
color: #424245;
}
.apple-footer-policy a:hover {
color: #0066cc;
}
.apple-site-footer.is-cjk-locale .apple-footer-policy a {
font-family:
'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Noto Sans CJK SC',
sans-serif;
font-size: 13px;
line-height: 1.55;
letter-spacing: 0.02em;
}
@media (min-width: 1024px) {
.apple-site-footer {
max-width: 996px;
padding: 0 24px;
}
.apple-site-footer-inner {
font-size: 11px;
}
.apple-footer-notes p {
font-size: 11px;
line-height: 1.38;
margin-bottom: 6px;
}
.apple-footer-grid {
grid-template-columns: 1.2fr repeat(4, minmax(0, 1fr));
gap: 24px;
}
.apple-footer-column h4 {
font-size: 11px;
margin-bottom: 8px;
}
.apple-footer-column a {
font-size: 11px;
margin-bottom: 7px;
}
.apple-site-footer.is-cjk-locale .apple-site-footer-inner {
font-size: 13px;
}
.apple-site-footer.is-cjk-locale .apple-footer-notes p {
font-size: 13px;
margin-bottom: 7px;
}
.apple-site-footer.is-cjk-locale .apple-footer-column h4 {
font-size: 13px;
}
.apple-site-footer.is-cjk-locale .apple-footer-column a {
font-size: 13px;
margin-bottom: 8px;
}
}
/* Responsive */
@media (max-width: 768px) {
.section-headline {
font-size: 42px;
}
.bento-grid {
grid-template-columns: 1fr;
height: auto;
}
.nav-links {
display: none;
}
.nav-promo {
font-size: 12px;
height: 28px;
justify-content: flex-start;
overflow-x: auto;
white-space: nowrap;
}
.section-appendix {
padding-top: 42px;
padding-bottom: 42px;
}
.section-band-learning {
margin-bottom: 96px;
padding-top: 42px;
padding-bottom: 42px;
padding-left: 24px;
padding-right: 24px;
}
.section-band-learning .section-junior {
margin-top: 56px;
}
.footer-callout {
margin: 0 16px 40px;
border-radius: 28px;
}
.footer-callout h2 {
font-size: 38px;
}
.footer-callout p {
font-size: 17px;
}
.apple-site-footer {
padding: 0 16px;
}
.apple-footer-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 20px 14px;
}
.apple-footer-bottom {
flex-direction: column;
align-items: flex-start;
}
}
</style>
<style>
/* Global layout fix for fixed nav */
.VPHome {
padding-top: 84px !important;
}
</style>
<style scoped>
/* Feature Grid (Apple Store Style) */
.feature-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
}
.feature-card {
background: #fff;
border-radius: 32px;
padding: 32px;
display: flex;
flex-direction: column;
transition: all 0.3s cubic-bezier(0.25, 0.1, 0.25, 1);
box-shadow: none;
height: 100%;
position: relative;
overflow: hidden;
text-decoration: none !important;
border: 1px solid rgba(0, 0, 0, 0.025);
}
.dark .feature-card {
border: 1px solid rgba(255, 255, 255, 0.06);
background: var(--vp-c-bg-mute);
}
.feature-card:hover {
transform: scale(1.015);
box-shadow: none;
}
.feature-icon {
width: 64px;
height: 64px;
border-radius: 18px;
display: flex;
align-items: center;
justify-content: center;
font-size: 30px;
margin-bottom: 24px;
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.45);
}
.feature-content {
display: flex;
flex-direction: column;
}
.feature-content h4 {
font-size: 34px;
font-weight: 700;
margin-bottom: 10px;
color: #1d1d1f;
line-height: 1.3;
letter-spacing: -0.024em;
font-family:
-apple-system, BlinkMacSystemFont, 'SF Pro Display', 'PingFang SC',
sans-serif;
}
.feature-content p {
font-size: 17px;
color: #6e6e73;
line-height: 1.6;
margin-top: 4px;
margin-bottom: 0;
}
@media (max-width: 960px) {
.feature-grid {
grid-template-columns: repeat(2, 1fr);
}
.comm-card {
flex-basis: 340px;
}
}
@media (max-width: 640px) {
.feature-grid {
grid-template-columns: 1fr;
}
.feature-card {
padding: 24px;
}
.comm-card {
flex-basis: min(86vw, 340px);
}
}
</style>