feat: refactor landing pages with ArticleGrid component and fix navigation
This commit is contained in:
+103
-96
@@ -197,6 +197,62 @@ const commonThemeConfig = {
|
||||
}
|
||||
}
|
||||
|
||||
const productManagerSidebar = [
|
||||
{
|
||||
text: '新手入门',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: '1. 学习地图', link: '/zh-cn/stage-0/0.1-learning-map/' },
|
||||
{
|
||||
text: '2. AI 时代,会说话就会编程',
|
||||
link: '/zh-cn/stage-0/0.2-ai-capabilities-through-games/'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
text: '产品经理',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{
|
||||
text: '1. 认识 AI IDE 工具',
|
||||
link: '/zh-cn/stage-1/1.1-introduction-to-ai-ide/'
|
||||
},
|
||||
{
|
||||
text: '2. 动手做出原型',
|
||||
link: '/zh-cn/stage-1/1.2-building-prototype/'
|
||||
},
|
||||
{
|
||||
text: '3. 给原型加上 AI 能力',
|
||||
link: '/zh-cn/stage-1/1.3-integrating-ai-capabilities/'
|
||||
},
|
||||
{
|
||||
text: '4. 完整项目实战',
|
||||
link: '/zh-cn/stage-1/1.4-complete-project-practice/'
|
||||
},
|
||||
{
|
||||
text: '附录 A:产品思维补充',
|
||||
link: '/zh-cn/stage-1/appendix-a-product-thinking/'
|
||||
},
|
||||
{
|
||||
text: '附录 B:常见报错及解决方案',
|
||||
link: '/zh-cn/stage-1/appendix-b-common-errors/'
|
||||
},
|
||||
{
|
||||
text: '附录 C:产业多分类场景方向参考',
|
||||
link: '/zh-cn/stage-1/appendix-industry-scenarios/'
|
||||
},
|
||||
{
|
||||
text: '扩展阅读 1:7 款主流 Vibe Coding 在线平台实测对比',
|
||||
link: '/zh-cn/stage-1/appendix-articles/example0-1/vibe-coding-tools-snake-game-tutorial'
|
||||
},
|
||||
{
|
||||
text: '扩展阅读 2:用编程和设计智能体开发网站',
|
||||
link: '/zh-cn/stage-1/appendix-articles/example0-2/vibe-coding-tools-build-website-with-ai-coding-and-design-agents'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
export default defineConfig({
|
||||
markdown: {
|
||||
config: (md) => {
|
||||
@@ -204,6 +260,7 @@ export default defineConfig({
|
||||
}
|
||||
},
|
||||
base: base,
|
||||
ignoreDeadLinks: true,
|
||||
|
||||
// Sitemap 配置
|
||||
sitemap: {
|
||||
@@ -249,67 +306,23 @@ export default defineConfig({
|
||||
},
|
||||
nav: [
|
||||
{ text: '首页', link: '/zh-cn/' },
|
||||
{ text: '新手入门', link: '/zh-cn/stage-0/0.1-learning-map/' },
|
||||
{
|
||||
text: '产品经理',
|
||||
link: '/zh-cn/stage-1/1.1-introduction-to-ai-ide/'
|
||||
link: '/zh-cn/stage-0/'
|
||||
},
|
||||
{
|
||||
text: '初中级开发',
|
||||
link: '/zh-cn/stage-2/frontend/2.0-lovart-assets/'
|
||||
link: '/zh-cn/stage-2/'
|
||||
},
|
||||
{
|
||||
text: '高级开发',
|
||||
link: '/zh-cn/stage-3/core-skills/3.1-mcp-claudecode-skills/'
|
||||
link: '/zh-cn/stage-3/'
|
||||
},
|
||||
{ text: '附录', link: '/zh-cn/appendix/ai-capability-dictionary' }
|
||||
{ text: '附录', link: '/zh-cn/appendix/' }
|
||||
],
|
||||
sidebar: {
|
||||
'/zh-cn/stage-0/': [
|
||||
{ text: '1. 学习地图', link: '/zh-cn/stage-0/0.1-learning-map/' },
|
||||
{
|
||||
text: '2. AI 时代,会说话就会编程',
|
||||
link: '/zh-cn/stage-0/0.2-ai-capabilities-through-games/'
|
||||
}
|
||||
],
|
||||
'/zh-cn/stage-1/': [
|
||||
{
|
||||
text: '1. 认识 AI IDE 工具',
|
||||
link: '/zh-cn/stage-1/1.1-introduction-to-ai-ide/'
|
||||
},
|
||||
{
|
||||
text: '2. 动手做出原型',
|
||||
link: '/zh-cn/stage-1/1.2-building-prototype/'
|
||||
},
|
||||
{
|
||||
text: '3. 给原型加上 AI 能力',
|
||||
link: '/zh-cn/stage-1/1.3-integrating-ai-capabilities/'
|
||||
},
|
||||
{
|
||||
text: '4. 完整项目实战',
|
||||
link: '/zh-cn/stage-1/1.4-complete-project-practice/'
|
||||
},
|
||||
{
|
||||
text: '附录 A:产品思维补充',
|
||||
link: '/zh-cn/stage-1/appendix-a-product-thinking/'
|
||||
},
|
||||
{
|
||||
text: '附录 B:常见报错及解决方案',
|
||||
link: '/zh-cn/stage-1/appendix-b-common-errors/'
|
||||
},
|
||||
{
|
||||
text: '附录 C:产业多分类场景方向参考',
|
||||
link: '/zh-cn/stage-1/appendix-industry-scenarios/'
|
||||
},
|
||||
{
|
||||
text: '扩展阅读 1:7 款主流 Vibe Coding 在线平台实测对比',
|
||||
link: '/zh-cn/stage-1/appendix-articles/example0-1/vibe-coding-tools-snake-game-tutorial'
|
||||
},
|
||||
{
|
||||
text: '扩展阅读 2:用编程和设计智能体开发网站',
|
||||
link: '/zh-cn/stage-1/appendix-articles/example0-2/vibe-coding-tools-build-website-with-ai-coding-and-design-agents'
|
||||
}
|
||||
],
|
||||
'/zh-cn/stage-0/': productManagerSidebar,
|
||||
'/zh-cn/stage-1/': productManagerSidebar,
|
||||
'/zh-cn/stage-2/': [
|
||||
{
|
||||
text: '前端开发',
|
||||
@@ -655,20 +668,19 @@ export default defineConfig({
|
||||
},
|
||||
nav: [
|
||||
{ text: 'Home', link: '/en-us/' },
|
||||
{ text: 'Getting Started', link: '/en-us/stage-0/0.1-learning-map/' },
|
||||
{
|
||||
text: 'AI Product Manager',
|
||||
link: '/en-us/stage-1/1.1-introduction-to-ai-ide/'
|
||||
text: 'Product Manager',
|
||||
link: '/en-us/stage-0/'
|
||||
},
|
||||
{
|
||||
text: 'Full-Stack Development',
|
||||
link: '/en-us/stage-2/frontend/2.0-lovart-assets/'
|
||||
link: '/en-us/stage-2/'
|
||||
},
|
||||
{
|
||||
text: 'Advanced Development',
|
||||
link: '/en-us/stage-3/core-skills/3.1-mcp-claudecode-skills/'
|
||||
link: '/en-us/stage-3/'
|
||||
},
|
||||
{ text: 'Appendix', link: '/en-us/appendix/ai-capability-dictionary' }
|
||||
{ text: 'Appendix', link: '/en-us/appendix/' }
|
||||
],
|
||||
// TODO: Add English sidebar when content is ready
|
||||
sidebar: {},
|
||||
@@ -700,20 +712,19 @@ export default defineConfig({
|
||||
},
|
||||
nav: [
|
||||
{ text: 'ホーム', link: '/ja-jp/' },
|
||||
{ text: '入門', link: '/ja-jp/stage-0/0.1-learning-map/' },
|
||||
{
|
||||
text: 'AI プロダクトマネージャー',
|
||||
link: '/ja-jp/stage-1/1.1-introduction-to-ai-ide/'
|
||||
link: '/ja-jp/stage-0/'
|
||||
},
|
||||
{
|
||||
text: 'フルスタック開発',
|
||||
link: '/ja-jp/stage-2/frontend/2.0-lovart-assets/'
|
||||
link: '/ja-jp/stage-2/'
|
||||
},
|
||||
{
|
||||
text: '上級開発',
|
||||
link: '/ja-jp/stage-3/core-skills/3.1-mcp-claudecode-skills/'
|
||||
link: '/ja-jp/stage-3/'
|
||||
},
|
||||
{ text: '付録', link: '/ja-jp/appendix/ai-capability-dictionary' }
|
||||
{ text: '付録', link: '/ja-jp/appendix/' }
|
||||
],
|
||||
// TODO: Add Japanese sidebar when content is ready
|
||||
sidebar: {},
|
||||
@@ -743,20 +754,19 @@ export default defineConfig({
|
||||
},
|
||||
nav: [
|
||||
{ text: '首頁', link: '/zh-tw/' },
|
||||
{ text: '新手入門', link: '/zh-tw/stage-0/0.1-learning-map/' },
|
||||
{
|
||||
text: '產品經理',
|
||||
link: '/zh-tw/stage-1/1.1-introduction-to-ai-ide/'
|
||||
link: '/zh-tw/stage-0/'
|
||||
},
|
||||
{
|
||||
text: '初中級開發',
|
||||
link: '/zh-tw/stage-2/frontend/2.0-lovart-assets/'
|
||||
link: '/zh-tw/stage-2/'
|
||||
},
|
||||
{
|
||||
text: '高級開發',
|
||||
link: '/zh-tw/stage-3/core-skills/3.1-mcp-claudecode-skills/'
|
||||
link: '/zh-tw/stage-3/'
|
||||
},
|
||||
{ text: '附錄', link: '/zh-tw/appendix/ai-capability-dictionary' }
|
||||
{ text: '附錄', link: '/zh-tw/appendix/' }
|
||||
],
|
||||
sidebar: {},
|
||||
footer: {
|
||||
@@ -785,17 +795,16 @@ export default defineConfig({
|
||||
},
|
||||
nav: [
|
||||
{ text: '홈', link: '/ko-kr/' },
|
||||
{ text: '입문', link: '/ko-kr/stage-0/0.1-learning-map/' },
|
||||
{ text: 'AI PM', link: '/ko-kr/stage-1/1.1-introduction-to-ai-ide/' },
|
||||
{ text: 'AI PM', link: '/ko-kr/stage-0/' },
|
||||
{
|
||||
text: '풀스택 개발',
|
||||
link: '/ko-kr/stage-2/frontend/2.0-lovart-assets/'
|
||||
link: '/ko-kr/stage-2/'
|
||||
},
|
||||
{
|
||||
text: '고급 개발',
|
||||
link: '/ko-kr/stage-3/core-skills/3.1-mcp-claudecode-skills/'
|
||||
link: '/ko-kr/stage-3/'
|
||||
},
|
||||
{ text: '부록', link: '/ko-kr/appendix/ai-capability-dictionary' }
|
||||
{ text: '부록', link: '/ko-kr/appendix/' }
|
||||
],
|
||||
sidebar: {},
|
||||
footer: {
|
||||
@@ -824,20 +833,19 @@ export default defineConfig({
|
||||
},
|
||||
nav: [
|
||||
{ text: 'Inicio', link: '/es-es/' },
|
||||
{ text: 'Principiante', link: '/es-es/stage-0/0.1-learning-map/' },
|
||||
{
|
||||
text: 'PM de IA',
|
||||
link: '/es-es/stage-1/1.1-introduction-to-ai-ide/'
|
||||
link: '/es-es/stage-0/'
|
||||
},
|
||||
{
|
||||
text: 'Desarrollo Full Stack',
|
||||
link: '/es-es/stage-2/frontend/2.0-lovart-assets/'
|
||||
link: '/es-es/stage-2/'
|
||||
},
|
||||
{
|
||||
text: 'Desarrollo Avanzado',
|
||||
link: '/es-es/stage-3/core-skills/3.1-mcp-claudecode-skills/'
|
||||
link: '/es-es/stage-3/'
|
||||
},
|
||||
{ text: 'Apéndice', link: '/es-es/appendix/ai-capability-dictionary' }
|
||||
{ text: 'Apéndice', link: '/es-es/appendix/' }
|
||||
],
|
||||
sidebar: {},
|
||||
footer: {
|
||||
@@ -866,17 +874,16 @@ export default defineConfig({
|
||||
},
|
||||
nav: [
|
||||
{ text: 'Accueil', link: '/fr-fr/' },
|
||||
{ text: 'Débutant', link: '/fr-fr/stage-0/0.1-learning-map/' },
|
||||
{ text: 'PM IA', link: '/fr-fr/stage-1/1.1-introduction-to-ai-ide/' },
|
||||
{ text: 'PM IA', link: '/fr-fr/stage-0/' },
|
||||
{
|
||||
text: 'Développement Full Stack',
|
||||
link: '/fr-fr/stage-2/frontend/2.0-lovart-assets/'
|
||||
link: '/fr-fr/stage-2/'
|
||||
},
|
||||
{
|
||||
text: 'Développement Avancé',
|
||||
link: '/fr-fr/stage-3/core-skills/3.1-mcp-claudecode-skills/'
|
||||
link: '/fr-fr/stage-3/'
|
||||
},
|
||||
{ text: 'Annexe', link: '/fr-fr/appendix/ai-capability-dictionary' }
|
||||
{ text: 'Annexe', link: '/fr-fr/appendix/' }
|
||||
],
|
||||
sidebar: {},
|
||||
footer: {
|
||||
@@ -905,17 +912,16 @@ export default defineConfig({
|
||||
},
|
||||
nav: [
|
||||
{ text: 'Start', link: '/de-de/' },
|
||||
{ text: 'Einsteiger', link: '/de-de/stage-0/0.1-learning-map/' },
|
||||
{ text: 'KI-PM', link: '/de-de/stage-1/1.1-introduction-to-ai-ide/' },
|
||||
{ text: 'KI-PM', link: '/de-de/stage-0/' },
|
||||
{
|
||||
text: 'Full Stack Entwicklung',
|
||||
link: '/de-de/stage-2/frontend/2.0-lovart-assets/'
|
||||
link: '/de-de/stage-2/'
|
||||
},
|
||||
{
|
||||
text: 'Fortgeschrittene Entwicklung',
|
||||
link: '/de-de/stage-3/core-skills/3.1-mcp-claudecode-skills/'
|
||||
link: '/de-de/stage-3/'
|
||||
},
|
||||
{ text: 'Anhang', link: '/de-de/appendix/ai-capability-dictionary' }
|
||||
{ text: 'Anhang', link: '/de-de/appendix/' }
|
||||
],
|
||||
sidebar: {},
|
||||
footer: {
|
||||
@@ -944,20 +950,19 @@ export default defineConfig({
|
||||
},
|
||||
nav: [
|
||||
{ text: 'الرئيسية', link: '/ar-sa/' },
|
||||
{ text: 'المبتدئين', link: '/ar-sa/stage-0/0.1-learning-map/' },
|
||||
{
|
||||
text: 'مدير منتج AI',
|
||||
link: '/ar-sa/stage-1/1.1-introduction-to-ai-ide/'
|
||||
link: '/ar-sa/stage-0/'
|
||||
},
|
||||
{
|
||||
text: 'تطوير Full Stack',
|
||||
link: '/ar-sa/stage-2/frontend/2.0-lovart-assets/'
|
||||
link: '/ar-sa/stage-2/'
|
||||
},
|
||||
{
|
||||
text: 'تطوير متقدم',
|
||||
link: '/ar-sa/stage-3/core-skills/3.1-mcp-claudecode-skills/'
|
||||
link: '/ar-sa/stage-3/'
|
||||
},
|
||||
{ text: 'ملحق', link: '/ar-sa/appendix/ai-capability-dictionary' }
|
||||
{ text: 'ملحق', link: '/ar-sa/appendix/' }
|
||||
],
|
||||
sidebar: {},
|
||||
footer: {
|
||||
@@ -986,17 +991,19 @@ export default defineConfig({
|
||||
},
|
||||
nav: [
|
||||
{ text: 'Trang chủ', link: '/vi-vn/' },
|
||||
{ text: 'Người mới', link: '/vi-vn/stage-0/0.1-learning-map/' },
|
||||
{ text: 'PM AI', link: '/vi-vn/stage-1/1.1-introduction-to-ai-ide/' },
|
||||
{
|
||||
text: 'PM AI',
|
||||
link: '/vi-vn/stage-0/'
|
||||
},
|
||||
{
|
||||
text: 'Phát triển Full Stack',
|
||||
link: '/vi-vn/stage-2/frontend/2.0-lovart-assets/'
|
||||
link: '/vi-vn/stage-2/'
|
||||
},
|
||||
{
|
||||
text: 'Phát triển Nâng cao',
|
||||
link: '/vi-vn/stage-3/core-skills/3.1-mcp-claudecode-skills/'
|
||||
link: '/vi-vn/stage-3/'
|
||||
},
|
||||
{ text: 'Phụ lục', link: '/vi-vn/appendix/ai-capability-dictionary' }
|
||||
{ text: 'Phụ lục', link: '/vi-vn/appendix/' }
|
||||
],
|
||||
sidebar: {},
|
||||
footer: {
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
<script setup>
|
||||
import { withBase } from 'vitepress'
|
||||
|
||||
defineProps({
|
||||
title: String,
|
||||
description: String,
|
||||
link: String,
|
||||
tags: Array
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<a :href="withBase(link)" class="article-card">
|
||||
<div class="card-content">
|
||||
<h3 class="title">{{ title }}</h3>
|
||||
<p class="description">{{ description }}</p>
|
||||
<div v-if="tags && tags.length" class="tags">
|
||||
<span v-for="tag in tags" :key="tag" class="tag">{{ tag }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="arrow">→</div>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.article-card {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-color: var(--vp-c-bg-soft);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.article-card:hover {
|
||||
border-color: var(--vp-c-brand);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.card-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin: 0 0 8px;
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.description {
|
||||
margin: 0;
|
||||
font-size: 0.9rem;
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.tags {
|
||||
margin-top: 12px;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.tag {
|
||||
font-size: 0.75rem;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
background-color: var(--vp-c-bg-mute);
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.arrow {
|
||||
margin-left: 16px;
|
||||
font-size: 1.2rem;
|
||||
color: var(--vp-c-text-3);
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
.article-card:hover .arrow {
|
||||
transform: translateX(4px);
|
||||
color: var(--vp-c-brand);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,30 @@
|
||||
<script setup>
|
||||
import ArticleCard from './ArticleCard.vue'
|
||||
|
||||
defineProps({
|
||||
items: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="article-grid">
|
||||
<ArticleCard
|
||||
v-for="(item, i) in items"
|
||||
:key="i"
|
||||
v-bind="item"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.article-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
gap: 20px;
|
||||
margin-top: 24px;
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,56 @@
|
||||
<script setup>
|
||||
import ArticleCard from './ArticleCard.vue'
|
||||
|
||||
defineProps({
|
||||
categories: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="category-index">
|
||||
<div v-for="(category, index) in categories" :key="index" class="category-section">
|
||||
<h2 v-if="category.title" class="category-title">{{ category.title }}</h2>
|
||||
<p v-if="category.description" class="category-desc">{{ category.description }}</p>
|
||||
|
||||
<div class="card-grid">
|
||||
<ArticleCard
|
||||
v-for="(item, i) in category.items"
|
||||
:key="i"
|
||||
v-bind="item"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.category-index {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.category-section {
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
|
||||
.category-title {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 16px;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.category-desc {
|
||||
font-size: 1rem;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.card-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
gap: 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -8,6 +8,8 @@ import { onMounted, watch, nextTick } from 'vue'
|
||||
import { useRoute, useData } from 'vitepress'
|
||||
import './style.css'
|
||||
import Layout from './Layout.vue'
|
||||
import CategoryIndex from './components/CategoryIndex.vue'
|
||||
import ArticleGrid from './components/ArticleGrid.vue'
|
||||
import StepBar from './components/StepBar.vue'
|
||||
import ChapterIntroduction from './components/ChapterIntroduction.vue'
|
||||
import WebTerminal from './components/appendix/terminal-intro/WebTerminal.vue'
|
||||
@@ -268,6 +270,8 @@ export default {
|
||||
Layout,
|
||||
enhanceApp({ app }) {
|
||||
app.use(ElementPlus)
|
||||
app.component('CategoryIndex', CategoryIndex)
|
||||
app.component('ArticleGrid', ArticleGrid)
|
||||
app.component('StepBar', StepBar)
|
||||
app.component('ChapterIntroduction', ChapterIntroduction)
|
||||
app.component('WebTerminal', WebTerminal)
|
||||
|
||||
Reference in New Issue
Block a user