Skip to content

Commit c59c805

Browse files
committed
update docs: change online editor
1 parent 2bf1596 commit c59c805

File tree

58 files changed

+4953
-4689
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+4953
-4689
lines changed

docs/package.json

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,16 @@
1111
"serve": "vite preview --port 4173"
1212
},
1313
"dependencies": {
14+
"@codesandbox/sandpack-themes": "^2.0.0",
1415
"@iconify/vue": "^5.0.0",
15-
"@stackblitz/sdk": "^1.11.0",
16-
"@webcontainer/api": "^1.6.1",
1716
"highlight.js": "^11.11.1",
1817
"jszip": "^3.10.1",
1918
"lodash-es": "^4.17.21",
20-
"react": "^18.2.0",
21-
"react-dom": "^18.2.0",
19+
"sandpack-vue3": "^3.1.12",
2220
"vue": "^3.4.0",
2321
"vue-router": "^4.2.0"
2422
},
2523
"devDependencies": {
26-
"@types/react": "^18.2.0",
27-
"@types/react-dom": "^18.2.0",
28-
"@vitejs/plugin-react": "^4.2.0",
2924
"@vitejs/plugin-vue": "^5.0.0",
3025
"sass": "^1.77.0",
3126
"typescript": "^5.2.0",

docs/src/App.vue

Lines changed: 321 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
<img src="/logo.png" alt="XGantt" class="logo-img" />
88
<span class="logo-text">XGantt</span>
99
</RouterLink>
10-
<div class="nav-menu">
10+
11+
<!-- 桌面端菜单 -->
12+
<div class="nav-menu desktop-menu">
1113
<RouterLink to="/" class="nav-link">首页</RouterLink>
1214
<RouterLink to="/demos" class="nav-link">演示</RouterLink>
1315
<RouterLink to="/tutorials" class="nav-link">教程</RouterLink>
@@ -49,6 +51,89 @@
4951
</a>
5052
<a href="https://docs.xiaopangying.com/gantt/docs/" target="_blank" class="nav-link docs-link">去看旧版(vue3)</a>
5153
</div>
54+
55+
<!-- 移动端菜单按钮 -->
56+
<button
57+
class="mobile-menu-btn"
58+
@click="toggleMobileMenu"
59+
:class="{ 'is-active': isMobileMenuOpen }"
60+
aria-label="菜单"
61+
>
62+
<span class="hamburger-box">
63+
<span class="hamburger-inner"></span>
64+
</span>
65+
</button>
66+
67+
<!-- 移动端下拉菜单 -->
68+
<Transition name="dropdown">
69+
<div v-if="isMobileMenuOpen" class="mobile-menu" @click.self="closeMobileMenu">
70+
<div class="mobile-menu-content">
71+
<!-- 导航分类 -->
72+
<div class="mobile-menu-section">
73+
<div class="mobile-menu-label">导航</div>
74+
<RouterLink to="/" class="mobile-menu-item" @click="closeMobileMenu">
75+
<Icon icon="solar:home-2-bold-duotone" width="20" height="20" />
76+
<span>首页</span>
77+
</RouterLink>
78+
<RouterLink to="/demos" class="mobile-menu-item" @click="closeMobileMenu">
79+
<Icon icon="solar:gallery-bold-duotone" width="20" height="20" />
80+
<span>演示</span>
81+
</RouterLink>
82+
<RouterLink to="/tutorials" class="mobile-menu-item" @click="closeMobileMenu">
83+
<Icon icon="solar:book-bold-duotone" width="20" height="20" />
84+
<span>教程</span>
85+
</RouterLink>
86+
<RouterLink to="/api" class="mobile-menu-item" @click="closeMobileMenu">
87+
<Icon icon="solar:code-bold-duotone" width="20" height="20" />
88+
<span>API</span>
89+
</RouterLink>
90+
</div>
91+
92+
<div class="mobile-menu-divider"></div>
93+
94+
<!-- 外部链接分类 -->
95+
<div class="mobile-menu-section">
96+
<div class="mobile-menu-label">链接</div>
97+
<a
98+
href="https://github.com/xpyjs/gantt"
99+
target="_blank"
100+
class="mobile-menu-item"
101+
@click="closeMobileMenu"
102+
>
103+
<Icon icon="mdi:github" width="20" height="20" />
104+
<span>GitHub</span>
105+
<Icon icon="solar:arrow-right-up-linear" width="14" height="14" class="external-icon" />
106+
</a>
107+
<a
108+
href="https://docs.xiaopangying.com/gantt/docs/"
109+
target="_blank"
110+
class="mobile-menu-item"
111+
@click="closeMobileMenu"
112+
>
113+
<Icon icon="solar:document-bold-duotone" width="20" height="20" />
114+
<span>旧版文档(vue3)</span>
115+
<Icon icon="solar:arrow-right-up-linear" width="14" height="14" class="external-icon" />
116+
</a>
117+
</div>
118+
119+
<div class="mobile-menu-divider"></div>
120+
121+
<!-- 主题切换 -->
122+
<div class="mobile-menu-section">
123+
<div class="mobile-menu-label">外观</div>
124+
<button class="mobile-menu-item theme-switch" @click="handleThemeToggle">
125+
<Icon
126+
:icon="isDark ? 'solar:sun-bold-duotone' : 'solar:moon-bold-duotone'"
127+
width="20"
128+
height="20"
129+
:class="isDark ? 'sun-icon' : 'moon-icon'"
130+
/>
131+
<span>{{ isDark ? '切换到亮色模式' : '切换到暗色模式' }}</span>
132+
</button>
133+
</div>
134+
</div>
135+
</div>
136+
</Transition>
52137
</div>
53138
</nav>
54139

@@ -78,12 +163,60 @@
78163
</template>
79164

80165
<script setup lang="ts">
166+
import { ref, onMounted, onUnmounted } from "vue";
81167
import { RouterLink, RouterView } from "vue-router";
82168
import { Icon } from "@iconify/vue";
83169
import { useTheme } from "@/composables/useTheme";
84170
import ToastContainer from "@/components/ToastContainer.vue";
85171
86172
const { isDark, toggleTheme } = useTheme();
173+
174+
// 移动端菜单状态
175+
const isMobileMenuOpen = ref(false);
176+
177+
const toggleMobileMenu = () => {
178+
isMobileMenuOpen.value = !isMobileMenuOpen.value;
179+
// 打开菜单时禁止滚动
180+
if (isMobileMenuOpen.value) {
181+
document.body.style.overflow = 'hidden';
182+
} else {
183+
document.body.style.overflow = '';
184+
}
185+
};
186+
187+
const closeMobileMenu = () => {
188+
isMobileMenuOpen.value = false;
189+
document.body.style.overflow = '';
190+
};
191+
192+
const handleThemeToggle = () => {
193+
toggleTheme();
194+
};
195+
196+
// 监听窗口大小变化,超过 700px 时自动关闭移动端菜单
197+
const handleResize = () => {
198+
if (window.innerWidth > 700 && isMobileMenuOpen.value) {
199+
closeMobileMenu();
200+
}
201+
};
202+
203+
// 监听 ESC 键关闭菜单
204+
const handleKeydown = (e: KeyboardEvent) => {
205+
if (e.key === 'Escape' && isMobileMenuOpen.value) {
206+
closeMobileMenu();
207+
}
208+
};
209+
210+
onMounted(() => {
211+
window.addEventListener('resize', handleResize);
212+
window.addEventListener('keydown', handleKeydown);
213+
});
214+
215+
onUnmounted(() => {
216+
window.removeEventListener('resize', handleResize);
217+
window.removeEventListener('keydown', handleKeydown);
218+
document.body.style.overflow = '';
219+
});
87220
</script>
88221

89222
<style scoped>
@@ -208,6 +341,182 @@ const { isDark, toggleTheme } = useTheme();
208341
transform: rotate(15deg) scale(1.1);
209342
}
210343
344+
/* 移动端菜单按钮 - 汉堡菜单 */
345+
.mobile-menu-btn {
346+
display: none;
347+
background: transparent;
348+
border: none;
349+
padding: 0.5rem;
350+
cursor: pointer;
351+
z-index: 101;
352+
}
353+
354+
.hamburger-box {
355+
width: 24px;
356+
height: 18px;
357+
display: inline-block;
358+
position: relative;
359+
}
360+
361+
.hamburger-inner {
362+
display: block;
363+
top: 50%;
364+
margin-top: -1.5px;
365+
}
366+
367+
.hamburger-inner,
368+
.hamburger-inner::before,
369+
.hamburger-inner::after {
370+
width: 24px;
371+
height: 3px;
372+
background-color: var(--text-primary);
373+
border-radius: 3px;
374+
position: absolute;
375+
transition: transform 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55),
376+
opacity 0.15s ease;
377+
}
378+
379+
.hamburger-inner::before,
380+
.hamburger-inner::after {
381+
content: "";
382+
display: block;
383+
}
384+
385+
.hamburger-inner::before {
386+
top: -8px;
387+
}
388+
389+
.hamburger-inner::after {
390+
bottom: -8px;
391+
}
392+
393+
/* 汉堡菜单激活状态 - 变成 X */
394+
.mobile-menu-btn.is-active .hamburger-inner {
395+
transform: rotate(45deg);
396+
}
397+
398+
.mobile-menu-btn.is-active .hamburger-inner::before {
399+
top: 0;
400+
opacity: 0;
401+
transform: rotate(0deg);
402+
}
403+
404+
.mobile-menu-btn.is-active .hamburger-inner::after {
405+
bottom: 0;
406+
transform: rotate(-90deg);
407+
}
408+
409+
/* 移动端下拉菜单 */
410+
.mobile-menu {
411+
position: fixed;
412+
top: 64px;
413+
left: 0;
414+
right: 0;
415+
bottom: 0;
416+
background: rgba(0, 0, 0, 0.4);
417+
backdrop-filter: blur(4px);
418+
z-index: 99;
419+
}
420+
421+
.mobile-menu-content {
422+
background: var(--bg-primary);
423+
border-bottom: 1px solid var(--border-color);
424+
box-shadow: 0 8px 32px var(--shadow-color);
425+
max-height: calc(100vh - 64px);
426+
overflow-y: auto;
427+
padding: 0.5rem 0;
428+
}
429+
430+
.mobile-menu-section {
431+
padding: 0.25rem 0;
432+
}
433+
434+
.mobile-menu-label {
435+
font-size: 0.75rem;
436+
font-weight: 600;
437+
color: var(--text-tertiary);
438+
text-transform: uppercase;
439+
letter-spacing: 0.05em;
440+
padding: 0.5rem 1.5rem;
441+
margin-bottom: 0.25rem;
442+
}
443+
444+
.mobile-menu-item {
445+
display: flex;
446+
align-items: center;
447+
gap: 0.75rem;
448+
padding: 0.875rem 1.5rem;
449+
color: var(--text-primary);
450+
text-decoration: none;
451+
transition: all 0.2s ease;
452+
border: none;
453+
background: transparent;
454+
width: 100%;
455+
font-size: 1rem;
456+
cursor: pointer;
457+
text-align: left;
458+
}
459+
460+
.mobile-menu-item:hover,
461+
.mobile-menu-item:focus {
462+
background: var(--bg-secondary);
463+
color: var(--accent-color);
464+
}
465+
466+
.mobile-menu-item.router-link-active {
467+
color: var(--accent-color);
468+
background: var(--bg-secondary);
469+
font-weight: 500;
470+
}
471+
472+
.mobile-menu-item .external-icon {
473+
margin-left: auto;
474+
opacity: 0.5;
475+
}
476+
477+
.mobile-menu-divider {
478+
height: 1px;
479+
background: var(--border-color);
480+
margin: 0.5rem 1rem;
481+
}
482+
483+
.mobile-menu-item.theme-switch .sun-icon {
484+
color: #f59e0b;
485+
}
486+
487+
.mobile-menu-item.theme-switch .moon-icon {
488+
color: #6366f1;
489+
}
490+
491+
/* 下拉菜单动画 */
492+
.dropdown-enter-active,
493+
.dropdown-leave-active {
494+
transition: opacity 0.25s ease;
495+
}
496+
497+
.dropdown-enter-active .mobile-menu-content,
498+
.dropdown-leave-active .mobile-menu-content {
499+
transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1),
500+
opacity 0.25s ease;
501+
}
502+
503+
.dropdown-enter-from,
504+
.dropdown-leave-to {
505+
opacity: 0;
506+
}
507+
508+
.dropdown-enter-from .mobile-menu-content,
509+
.dropdown-leave-to .mobile-menu-content {
510+
transform: translateY(-10px);
511+
opacity: 0;
512+
}
513+
514+
.dropdown-enter-to .mobile-menu-content,
515+
.dropdown-leave-from .mobile-menu-content {
516+
transform: translateY(0);
517+
opacity: 1;
518+
}
519+
211520
.main-content {
212521
min-height: calc(100vh - 64px - 80px);
213522
}
@@ -249,14 +558,21 @@ const { isDark, toggleTheme } = useTheme();
249558
padding: 0 1rem;
250559
}
251560
252-
.nav-menu {
253-
gap: 1rem;
254-
}
255-
256561
.footer-container {
257562
flex-direction: column;
258563
gap: 1rem;
259564
text-align: center;
260565
}
261566
}
567+
568+
/* 移动端响应式 - 700px 以下显示移动菜单 */
569+
@media (max-width: 700px) {
570+
.desktop-menu {
571+
display: none;
572+
}
573+
574+
.mobile-menu-btn {
575+
display: block;
576+
}
577+
}
262578
</style>

0 commit comments

Comments
 (0)