From e2796ea75dcc423aca7e83e2ef49bedded945b7c Mon Sep 17 00:00:00 2001 From: sanbuphy Date: Mon, 23 Mar 2026 17:36:13 +0800 Subject: [PATCH] feat(docs): add sidebar resizing and update Claude Code workflow - Add sidebar width resizing functionality with persistence and bounds checking - Update Claude Code documentation to reflect current command changes (remove deprecated /commit and /review, add /diff and plugin workflow) - Remove Husky pre-commit hook boilerplate to simplify setup - Update Vue component type annotations from TypeScript to plain JavaScript for consistency - Regenerate sitemap with updated timestamps --- .husky/pre-commit | 3 - docs/.vitepress/theme/Layout.vue | 151 +++++++++++++++++- .../CopyOrDownloadAsMarkdownButtons/index.vue | 12 +- docs/public/sitemap.xml | 10 +- .../stage-2/backend/2.6-modern-cli/index.md | 2 +- .../zh-cn/stage-3/core-skills/basics/index.md | 121 ++++++++------ 6 files changed, 233 insertions(+), 66 deletions(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index da97d44..c6a46de 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,6 +1,3 @@ -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - echo "🔍 Pre-commit checks started..." echo "" diff --git a/docs/.vitepress/theme/Layout.vue b/docs/.vitepress/theme/Layout.vue index 4e7354a..58f36c4 100644 --- a/docs/.vitepress/theme/Layout.vue +++ b/docs/.vitepress/theme/Layout.vue @@ -3,7 +3,7 @@ import DefaultTheme from 'vitepress/theme' import { useData, useRoute, withBase } from 'vitepress' import TextType from './components/TextType.vue' import GitHubStars from './components/GitHubStars.vue' -import { onMounted, ref, watch, computed } from 'vue' +import { onMounted, onBeforeUnmount, ref, watch, computed } from 'vue' import ReadingProgress from './components/ReadingProgress.vue' import { Setting } from '@element-plus/icons-vue' import easyVibePaths from './data/easyVibePaths.json' @@ -88,12 +88,99 @@ const resetLineHeight = () => { // 目录栏(左侧 VPSidebar)收起/展开功能 // ============================================ const SIDEBAR_COLLAPSED_KEY = 'ev-sidebar-collapsed' +const SIDEBAR_WIDTH_KEY = 'ev-sidebar-width' +const DEFAULT_SIDEBAR_WIDTH = 272 +const MIN_SIDEBAR_WIDTH = 160 +const MAX_SIDEBAR_WIDTH = 560 const sidebarCollapsed = ref(false) +const sidebarWidth = ref(DEFAULT_SIDEBAR_WIDTH) +const sidebarResizing = ref(false) +let sidebarResizeLeft = 0 const toggleSidebar = () => { sidebarCollapsed.value = !sidebarCollapsed.value } +const getSidebarWidthBounds = () => { + if (typeof window === 'undefined') { + return { + min: MIN_SIDEBAR_WIDTH, + max: MAX_SIDEBAR_WIDTH + } + } + const viewportMax = window.innerWidth - 240 + return { + min: MIN_SIDEBAR_WIDTH, + max: Math.min(MAX_SIDEBAR_WIDTH, Math.max(MIN_SIDEBAR_WIDTH, viewportMax)) + } +} + +const clampSidebarWidth = (value) => { + const numeric = Number(value) + if (!Number.isFinite(numeric)) return DEFAULT_SIDEBAR_WIDTH + const bounds = getSidebarWidthBounds() + return Math.min(bounds.max, Math.max(bounds.min, numeric)) +} + +const applySidebarWidth = (width) => { + if (typeof document === 'undefined') return + document.documentElement.style.setProperty('--vp-sidebar-width', `${width}px`) +} + +const setSidebarWidth = (value, shouldPersist = true) => { + const normalized = clampSidebarWidth(value) + sidebarWidth.value = normalized + applySidebarWidth(normalized) + if (shouldPersist) { + localStorage.setItem(SIDEBAR_WIDTH_KEY, String(normalized)) + } +} + +const getSidebarLeftBoundary = () => { + const sidebar = document.querySelector('.VPSidebar') + if (sidebar) { + return sidebar.getBoundingClientRect().left + } + return 0 +} + +const updateSidebarWidthFromPointer = (clientX) => { + const nextWidth = clientX - sidebarResizeLeft + setSidebarWidth(nextWidth, false) +} + +const handleSidebarResizeMove = (event) => { + if (!sidebarResizing.value) return + updateSidebarWidthFromPointer(event.clientX) +} + +const stopSidebarResize = () => { + if (!sidebarResizing.value) return + sidebarResizing.value = false + document.body.classList.remove('ev-sidebar-resizing') + localStorage.setItem(SIDEBAR_WIDTH_KEY, String(sidebarWidth.value)) + window.removeEventListener('pointermove', handleSidebarResizeMove) + window.removeEventListener('pointerup', stopSidebarResize) + window.removeEventListener('pointercancel', stopSidebarResize) +} + +const startSidebarResize = (event) => { + if (typeof window === 'undefined') return + if (window.innerWidth < 960 || sidebarCollapsed.value) return + event.preventDefault() + sidebarResizeLeft = getSidebarLeftBoundary() + sidebarResizing.value = true + document.body.classList.add('ev-sidebar-resizing') + updateSidebarWidthFromPointer(event.clientX) + window.addEventListener('pointermove', handleSidebarResizeMove) + window.addEventListener('pointerup', stopSidebarResize) + window.addEventListener('pointercancel', stopSidebarResize) +} + +const handleViewportResize = () => { + setSidebarWidth(sidebarWidth.value, false) +} + const isHomePage = computed(() => frontmatter.value.layout === 'home') const isWelcomePage = computed(() => route.path === '/welcome/' || @@ -119,9 +206,23 @@ onMounted(() => { document.body.classList.add('ev-sidebar-collapsed') } + const savedSidebarWidth = localStorage.getItem(SIDEBAR_WIDTH_KEY) + if (savedSidebarWidth) { + setSidebarWidth(savedSidebarWidth, false) + } else { + setSidebarWidth(DEFAULT_SIDEBAR_WIDTH, false) + } + + window.addEventListener('resize', handleViewportResize) + initOutlineAutoScroll() }) +onBeforeUnmount(() => { + window.removeEventListener('resize', handleViewportResize) + stopSidebarResize() +}) + // ============================================ // Outline 侧边栏自动滚动跟随功能 // 当页面滚动时,自动滚动 outline 让当前激活项保持在可视区域 @@ -484,8 +585,15 @@ watch(sidebarCollapsed, (collapsed) => {
+ -