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
This commit is contained in:
@@ -1,6 +1,3 @@
|
|||||||
#!/bin/sh
|
|
||||||
. "$(dirname "$0")/_/husky.sh"
|
|
||||||
|
|
||||||
echo "🔍 Pre-commit checks started..."
|
echo "🔍 Pre-commit checks started..."
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import DefaultTheme from 'vitepress/theme'
|
|||||||
import { useData, useRoute, withBase } from 'vitepress'
|
import { useData, useRoute, withBase } from 'vitepress'
|
||||||
import TextType from './components/TextType.vue'
|
import TextType from './components/TextType.vue'
|
||||||
import GitHubStars from './components/GitHubStars.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 ReadingProgress from './components/ReadingProgress.vue'
|
||||||
import { Setting } from '@element-plus/icons-vue'
|
import { Setting } from '@element-plus/icons-vue'
|
||||||
import easyVibePaths from './data/easyVibePaths.json'
|
import easyVibePaths from './data/easyVibePaths.json'
|
||||||
@@ -88,12 +88,99 @@ const resetLineHeight = () => {
|
|||||||
// 目录栏(左侧 VPSidebar)收起/展开功能
|
// 目录栏(左侧 VPSidebar)收起/展开功能
|
||||||
// ============================================
|
// ============================================
|
||||||
const SIDEBAR_COLLAPSED_KEY = 'ev-sidebar-collapsed'
|
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 sidebarCollapsed = ref(false)
|
||||||
|
const sidebarWidth = ref(DEFAULT_SIDEBAR_WIDTH)
|
||||||
|
const sidebarResizing = ref(false)
|
||||||
|
let sidebarResizeLeft = 0
|
||||||
|
|
||||||
const toggleSidebar = () => {
|
const toggleSidebar = () => {
|
||||||
sidebarCollapsed.value = !sidebarCollapsed.value
|
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 isHomePage = computed(() => frontmatter.value.layout === 'home')
|
||||||
const isWelcomePage = computed(() =>
|
const isWelcomePage = computed(() =>
|
||||||
route.path === '/welcome/' ||
|
route.path === '/welcome/' ||
|
||||||
@@ -119,9 +206,23 @@ onMounted(() => {
|
|||||||
document.body.classList.add('ev-sidebar-collapsed')
|
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()
|
initOutlineAutoScroll()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
window.removeEventListener('resize', handleViewportResize)
|
||||||
|
stopSidebarResize()
|
||||||
|
})
|
||||||
|
|
||||||
// ============================================
|
// ============================================
|
||||||
// Outline 侧边栏自动滚动跟随功能
|
// Outline 侧边栏自动滚动跟随功能
|
||||||
// 当页面滚动时,自动滚动 outline 让当前激活项保持在可视区域
|
// 当页面滚动时,自动滚动 outline 让当前激活项保持在可视区域
|
||||||
@@ -484,8 +585,15 @@ watch(sidebarCollapsed, (collapsed) => {
|
|||||||
<div
|
<div
|
||||||
v-if="!isHomePage && !isWelcomePage"
|
v-if="!isHomePage && !isWelcomePage"
|
||||||
class="ev-sidebar-hover-area"
|
class="ev-sidebar-hover-area"
|
||||||
:class="{ collapsed: sidebarCollapsed }"
|
:class="{ collapsed: sidebarCollapsed, resizing: sidebarResizing }"
|
||||||
>
|
>
|
||||||
|
<div
|
||||||
|
v-if="!sidebarCollapsed"
|
||||||
|
class="ev-sidebar-resizer"
|
||||||
|
role="separator"
|
||||||
|
aria-orientation="vertical"
|
||||||
|
@pointerdown="startSidebarResize"
|
||||||
|
/>
|
||||||
<button
|
<button
|
||||||
class="ev-sidebar-toggle-btn"
|
class="ev-sidebar-toggle-btn"
|
||||||
:class="{ collapsed: sidebarCollapsed }"
|
:class="{ collapsed: sidebarCollapsed }"
|
||||||
@@ -695,7 +803,8 @@ watch(sidebarCollapsed, (collapsed) => {
|
|||||||
display: none;
|
display: none;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: calc(var(--vp-sidebar-width, 272px) - 16px);
|
--ev-sidebar-divider-offset: 16px;
|
||||||
|
left: calc(var(--vp-sidebar-width, 272px) - var(--ev-sidebar-divider-offset));
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
z-index: 30;
|
z-index: 30;
|
||||||
@@ -703,6 +812,22 @@ watch(sidebarCollapsed, (collapsed) => {
|
|||||||
.ev-sidebar-hover-area.collapsed {
|
.ev-sidebar-hover-area.collapsed {
|
||||||
left: 0;
|
left: 0;
|
||||||
}
|
}
|
||||||
|
.ev-sidebar-resizer {
|
||||||
|
position: absolute;
|
||||||
|
left: var(--ev-sidebar-divider-offset);
|
||||||
|
top: 0;
|
||||||
|
width: 2px;
|
||||||
|
height: 100%;
|
||||||
|
background: var(--vp-c-divider);
|
||||||
|
opacity: 0;
|
||||||
|
cursor: col-resize;
|
||||||
|
transition: opacity 0.2s ease, background-color 0.2s ease;
|
||||||
|
}
|
||||||
|
.ev-sidebar-hover-area:hover .ev-sidebar-resizer,
|
||||||
|
.ev-sidebar-hover-area.resizing .ev-sidebar-resizer {
|
||||||
|
opacity: 1;
|
||||||
|
background: var(--vp-c-brand-1);
|
||||||
|
}
|
||||||
|
|
||||||
/* 分界线上的收起按钮 */
|
/* 分界线上的收起按钮 */
|
||||||
.ev-sidebar-toggle-btn {
|
.ev-sidebar-toggle-btn {
|
||||||
@@ -710,7 +835,7 @@ watch(sidebarCollapsed, (collapsed) => {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
left: 6px;
|
left: calc(var(--ev-sidebar-divider-offset) - 4px);
|
||||||
width: 18px;
|
width: 18px;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
border: 1px solid var(--vp-c-divider);
|
border: 1px solid var(--vp-c-divider);
|
||||||
@@ -740,6 +865,9 @@ watch(sidebarCollapsed, (collapsed) => {
|
|||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
animation: none;
|
animation: none;
|
||||||
}
|
}
|
||||||
|
.ev-sidebar-hover-area.resizing .ev-sidebar-toggle-btn {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* 桌面端才显示按钮 */
|
/* 桌面端才显示按钮 */
|
||||||
@media (min-width: 960px) {
|
@media (min-width: 960px) {
|
||||||
@@ -754,7 +882,7 @@ watch(sidebarCollapsed, (collapsed) => {
|
|||||||
/* @1440px 时分界线按钮跟随侧边栏实际宽度 */
|
/* @1440px 时分界线按钮跟随侧边栏实际宽度 */
|
||||||
@media (min-width: 1440px) {
|
@media (min-width: 1440px) {
|
||||||
.ev-sidebar-hover-area:not(.collapsed) {
|
.ev-sidebar-hover-area:not(.collapsed) {
|
||||||
left: calc((100% - (var(--vp-layout-max-width, 1440px) - 64px)) / 2 + var(--vp-sidebar-width, 272px) - 32px - 16px);
|
left: calc((100% - (var(--vp-layout-max-width, 1440px) - 64px)) / 2 + var(--vp-sidebar-width, 272px) - var(--ev-sidebar-divider-offset));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -804,4 +932,17 @@ watch(sidebarCollapsed, (collapsed) => {
|
|||||||
.VPNavBar.has-sidebar .divider {
|
.VPNavBar.has-sidebar .divider {
|
||||||
transition: padding-left 0.3s ease, transform 0.3s ease;
|
transition: padding-left 0.3s ease, transform 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ev-sidebar-resizing,
|
||||||
|
.ev-sidebar-resizing * {
|
||||||
|
cursor: col-resize !important;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ev-sidebar-resizing .VPSidebar,
|
||||||
|
.ev-sidebar-resizing .VPContent.has-sidebar,
|
||||||
|
.ev-sidebar-resizing .VPNavBar.has-sidebar .content,
|
||||||
|
.ev-sidebar-resizing .VPNavBar.has-sidebar .divider {
|
||||||
|
transition: none !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -49,7 +49,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup>
|
||||||
import { onMounted, onUnmounted, ref } from 'vue'
|
import { onMounted, onUnmounted, ref } from 'vue'
|
||||||
|
|
||||||
import iconChatGPT from './icons/chatgpt.svg?raw'
|
import iconChatGPT from './icons/chatgpt.svg?raw'
|
||||||
@@ -71,9 +71,9 @@ const aiProviders = [
|
|||||||
const isOpen = ref(false)
|
const isOpen = ref(false)
|
||||||
const copied = ref(false)
|
const copied = ref(false)
|
||||||
const downloaded = ref(false)
|
const downloaded = ref(false)
|
||||||
const dropdownContainer = ref<HTMLElement | null>(null)
|
const dropdownContainer = ref(null)
|
||||||
const isRendered = ref(false)
|
const isRendered = ref(false)
|
||||||
const dropdownMenu = ref<HTMLElement | null>(null)
|
const dropdownMenu = ref(null)
|
||||||
|
|
||||||
function toggleDropdown() {
|
function toggleDropdown() {
|
||||||
if (isOpen.value) {
|
if (isOpen.value) {
|
||||||
@@ -120,7 +120,7 @@ function viewAsMarkdown() {
|
|||||||
isOpen.value = false
|
isOpen.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
function openInAI(provider: (typeof aiProviders)[0]) {
|
function openInAI(provider) {
|
||||||
const markdownUrl = resolveMarkdownPageURL(currentURL)
|
const markdownUrl = resolveMarkdownPageURL(currentURL)
|
||||||
const prompt = `Read from ${markdownUrl} so I can ask questions about it.`
|
const prompt = `Read from ${markdownUrl} so I can ask questions about it.`
|
||||||
window.open(provider.url + encodeURIComponent(prompt), '_blank')
|
window.open(provider.url + encodeURIComponent(prompt), '_blank')
|
||||||
@@ -141,8 +141,8 @@ function downloadMarkdown() {
|
|||||||
.catch((e) => console.error('❌ Error:', e))
|
.catch((e) => console.error('❌ Error:', e))
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleClickOutside(event: MouseEvent) {
|
function handleClickOutside(event) {
|
||||||
if (dropdownContainer.value && !dropdownContainer.value.contains(event.target as Node)) {
|
if (dropdownContainer.value && !dropdownContainer.value.contains(event.target)) {
|
||||||
isOpen.value = false
|
isOpen.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -594,7 +594,7 @@
|
|||||||
</url>
|
</url>
|
||||||
<url>
|
<url>
|
||||||
<loc>https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/8-artificial-intelligence/ai-capability-dictionary/</loc>
|
<loc>https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/8-artificial-intelligence/ai-capability-dictionary/</loc>
|
||||||
<lastmod>2026-03-12T13:45:38+08:00</lastmod>
|
<lastmod>2026-03-18T07:57:16-05:00</lastmod>
|
||||||
<changefreq>weekly</changefreq>
|
<changefreq>weekly</changefreq>
|
||||||
<priority>0.7</priority>
|
<priority>0.7</priority>
|
||||||
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/8-artificial-intelligence/ai-capability-dictionary/"/>
|
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/8-artificial-intelligence/ai-capability-dictionary/"/>
|
||||||
@@ -812,7 +812,7 @@
|
|||||||
</url>
|
</url>
|
||||||
<url>
|
<url>
|
||||||
<loc>https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/1.1-introduction-to-ai-ide/</loc>
|
<loc>https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/1.1-introduction-to-ai-ide/</loc>
|
||||||
<lastmod>2026-03-16T12:42:29+08:00</lastmod>
|
<lastmod>2026-03-18T07:57:16-05:00</lastmod>
|
||||||
<changefreq>weekly</changefreq>
|
<changefreq>weekly</changefreq>
|
||||||
<priority>0.9</priority>
|
<priority>0.9</priority>
|
||||||
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/1.1-introduction-to-ai-ide/"/>
|
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/1.1-introduction-to-ai-ide/"/>
|
||||||
@@ -828,7 +828,7 @@
|
|||||||
</url>
|
</url>
|
||||||
<url>
|
<url>
|
||||||
<loc>https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/1.3-integrating-ai-capabilities/</loc>
|
<loc>https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/1.3-integrating-ai-capabilities/</loc>
|
||||||
<lastmod>2026-03-16T12:42:29+08:00</lastmod>
|
<lastmod>2026-03-18T07:57:16-05:00</lastmod>
|
||||||
<changefreq>weekly</changefreq>
|
<changefreq>weekly</changefreq>
|
||||||
<priority>0.9</priority>
|
<priority>0.9</priority>
|
||||||
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/1.3-integrating-ai-capabilities/"/>
|
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/1.3-integrating-ai-capabilities/"/>
|
||||||
@@ -949,7 +949,7 @@
|
|||||||
</url>
|
</url>
|
||||||
<url>
|
<url>
|
||||||
<loc>https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/backend/2.6-modern-cli/</loc>
|
<loc>https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/backend/2.6-modern-cli/</loc>
|
||||||
<lastmod>2026-02-27T18:26:49+08:00</lastmod>
|
<lastmod>2026-03-18T07:59:13-05:00</lastmod>
|
||||||
<changefreq>weekly</changefreq>
|
<changefreq>weekly</changefreq>
|
||||||
<priority>0.8</priority>
|
<priority>0.8</priority>
|
||||||
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/backend/2.6-modern-cli/"/>
|
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/backend/2.6-modern-cli/"/>
|
||||||
@@ -1070,7 +1070,7 @@
|
|||||||
</url>
|
</url>
|
||||||
<url>
|
<url>
|
||||||
<loc>https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/core-skills/long-running-tasks/</loc>
|
<loc>https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/core-skills/long-running-tasks/</loc>
|
||||||
<lastmod>2026-03-03T13:14:17+08:00</lastmod>
|
<lastmod>2026-03-18T17:22:35+08:00</lastmod>
|
||||||
<changefreq>weekly</changefreq>
|
<changefreq>weekly</changefreq>
|
||||||
<priority>0.8</priority>
|
<priority>0.8</priority>
|
||||||
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/core-skills/long-running-tasks/"/>
|
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/core-skills/long-running-tasks/"/>
|
||||||
|
|||||||
@@ -366,7 +366,7 @@ https://docs.claude.com/en/docs/claude-code/slash-commands
|
|||||||
| claude -c | 继续最近的一次会话 | `claude -c` |
|
| claude -c | 继续最近的一次会话 | `claude -c` |
|
||||||
| claude -r | 恢复上一段会话 | `claude -r` |
|
| claude -r | 恢复上一段会话 | `claude -r` |
|
||||||
| /resume | 在当前聊天中切换回上一段会话 | `claude -c`、`/resume` |
|
| /resume | 在当前聊天中切换回上一段会话 | `claude -c`、`/resume` |
|
||||||
| claude commit | 协助创建 Git 提交信息并提交代码 | `claude commit` |
|
| /plugin | 管理插件,可安装提交与审查类扩展能力 | `/plugin` |
|
||||||
| /init | 用 CLAUDE.md 初始化项目说明 | `/init` |
|
| /init | 用 CLAUDE.md 初始化项目说明 | `/init` |
|
||||||
| /clear | 清空当前会话上下文,防止信息过载 | `/clear` |
|
| /clear | 清空当前会话上下文,防止信息过载 | `/clear` |
|
||||||
| /compact | 压缩会话历史,减少上下文 token 占用 | `/compact` |
|
| /compact | 压缩会话历史,减少上下文 token 占用 | `/compact` |
|
||||||
|
|||||||
@@ -451,47 +451,61 @@ Claude Code 的上下文窗口是有限的(通常 200K Token)。长对话会
|
|||||||
现在我们已经完成了用户模块,接下来做订单模块
|
现在我们已经完成了用户模块,接下来做订单模块
|
||||||
```
|
```
|
||||||
|
|
||||||
### 技巧 7:/commit 自动提交 —— Git 工作流自动化
|
### 技巧 7:用 Claude Code 辅助 Git 提交
|
||||||
|
|
||||||
`/commit` 让 Git 提交变得 effortless。Claude 会自动查看变更,生成符合规范的提交信息。
|
在 Claude Code 里,推荐的提交流程是:先让 Claude 帮你查看 diff、整理提交信息,再由你执行标准的 Git 命令完成提交。这样既清晰,也方便你在提交前再次确认改动内容。
|
||||||
|
|
||||||
**使用方式:**
|
官方文档参考:
|
||||||
|
|
||||||
|
- [Built-in commands](https://code.claude.com/docs/en/commands)
|
||||||
|
- [Discover plugins](https://code.claude.com/docs/en/discover-plugins)
|
||||||
|
|
||||||
|
**推荐工作流:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
/commit
|
# 1. 查看当前改动
|
||||||
|
/diff
|
||||||
|
!git status
|
||||||
|
|
||||||
|
# 2. 让 Claude 总结变更并生成提交信息
|
||||||
|
请基于当前 git diff,按照 Conventional Commits 规范生成一个 commit message,
|
||||||
|
并用中文解释为什么这样分类
|
||||||
|
|
||||||
|
# 3. 你确认后,再执行标准 Git 提交
|
||||||
|
!git add -A
|
||||||
|
!git commit -m "feat(docs): update Claude Code workflow guidance"
|
||||||
```
|
```
|
||||||
|
|
||||||
**Claude 会做什么:**
|
**这种方式的好处:**
|
||||||
|
|
||||||
1. **查看变更**:运行 `git diff` 和 `git status`
|
1. **更贴近当前官方能力**:不依赖已经移除的内置命令
|
||||||
2. **分析变更内容**:理解修改的目的和影响
|
2. **更透明**:你能先检查 diff 和 commit message,再决定是否提交
|
||||||
3. **生成提交信息**:按照 Conventional Commits 规范
|
3. **更通用**:换到别的 AI IDE 或纯 Git 环境时,工作流依然成立
|
||||||
4. **执行提交**:运行 `git commit`
|
|
||||||
|
|
||||||
**示例输出:**
|
**如果你想保留"一条命令提交"的体验:**
|
||||||
|
|
||||||
```
|
Claude Code 现在推荐通过插件补回这类能力。例如官方插件市场示例里的 `commit-commands` 插件,会提供 `/commit-commands:commit` 这类命令。
|
||||||
检测到以下变更:
|
|
||||||
- src/components/UserCard.tsx - 新增用户卡片组件
|
|
||||||
- src/types/user.ts - 添加 User 类型定义
|
|
||||||
- tests/UserCard.test.tsx - 添加单元测试
|
|
||||||
|
|
||||||
建议的提交信息:
|
|
||||||
feat(components): add UserCard component with type definitions and tests
|
|
||||||
|
|
||||||
是否执行提交?(y/n/e - 编辑信息)
|
|
||||||
```
|
|
||||||
|
|
||||||
**进阶用法:**
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 自动提交,不询问
|
# 1. 添加示例插件市场
|
||||||
/commit --yes
|
/plugin marketplace add anthropics/claude-code
|
||||||
|
|
||||||
# 生成提交信息但不执行
|
# 2. 安装提交工作流插件
|
||||||
/commit --dry-run
|
/plugin install commit-commands@anthropics-claude-code
|
||||||
|
|
||||||
|
# 3. 重新加载插件
|
||||||
|
/reload-plugins
|
||||||
|
|
||||||
|
# 4. 使用插件命令提交
|
||||||
|
/commit-commands:commit
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**补充说明:**
|
||||||
|
|
||||||
|
- `/commit-commands:commit` 是插件提供的命令,不是 Claude Code 当前默认内置命令
|
||||||
|
- 如果你只是想在提交前检查改动,优先使用 `/diff`,或直接让 Claude 解读 `git diff`
|
||||||
|
- 官方也已将 `/review` 标记为 deprecated;如果你需要类似能力,建议改用插件或自然语言审查工作流
|
||||||
|
|
||||||
### 技巧 8:Shift+Tab 自动接受 —— 提高流畅度
|
### 技巧 8:Shift+Tab 自动接受 —— 提高流畅度
|
||||||
|
|
||||||
默认情况下,Claude 修改代码前会询问你的确认。这在学习阶段很有帮助,但熟悉后可能会觉得繁琐。`Shift+Tab` 开启自动接受模式,让工作流更流畅。
|
默认情况下,Claude 修改代码前会询问你的确认。这在学习阶段很有帮助,但熟悉后可能会觉得繁琐。`Shift+Tab` 开启自动接受模式,让工作流更流畅。
|
||||||
@@ -1101,8 +1115,8 @@ Slash 命令是 Claude Code 的内置功能,以 `/` 开头。它们提供标
|
|||||||
| `/plan` | 进入规划模式 | 复杂任务前先制定计划 |
|
| `/plan` | 进入规划模式 | 复杂任务前先制定计划 |
|
||||||
| `/clear` | 清除对话历史 | 上下文混乱时重新开始 |
|
| `/clear` | 清除对话历史 | 上下文混乱时重新开始 |
|
||||||
| `/compact` | 压缩上下文 | 长对话后节省 Token |
|
| `/compact` | 压缩上下文 | 长对话后节省 Token |
|
||||||
| `/commit` | 创建 Git 提交 | 快速提交变更 |
|
| `/diff` | 打开交互式 diff 视图 | 查看当前未提交改动 |
|
||||||
| `/review` | 审查未提交的变更 | 提交前检查代码 |
|
| `/plugin` | 管理插件 | 安装提交、审查等扩展能力 |
|
||||||
| `/context` | 查看上下文使用 | 优化 Token 消耗 |
|
| `/context` | 查看上下文使用 | 优化 Token 消耗 |
|
||||||
| `/cost` | 查看本次会话费用 | 关注使用成本 |
|
| `/cost` | 查看本次会话费用 | 关注使用成本 |
|
||||||
| `/config` | 打开配置面板 | 修改设置 |
|
| `/config` | 打开配置面板 | 修改设置 |
|
||||||
@@ -1115,9 +1129,11 @@ Slash 命令是 Claude Code 的内置功能,以 `/` 开头。它们提供标
|
|||||||
# 完整开发工作流
|
# 完整开发工作流
|
||||||
/plan # 1. 制定计划
|
/plan # 1. 制定计划
|
||||||
# ... 执行开发 ...
|
# ... 执行开发 ...
|
||||||
/review # 2. 审查变更
|
/diff # 2. 查看变更
|
||||||
/commit # 3. 提交代码
|
请基于当前 diff 生成 commit message
|
||||||
/cost # 4. 查看成本
|
!git add -A # 3. 暂存改动
|
||||||
|
!git commit -m "..." # 4. 提交代码
|
||||||
|
/cost # 5. 查看成本
|
||||||
```
|
```
|
||||||
|
|
||||||
### 符号系统
|
### 符号系统
|
||||||
@@ -1219,12 +1235,15 @@ Claude Code 深度集成了 Git,让你可以在不离开终端的情况下完
|
|||||||
**创建提交:**
|
**创建提交:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 自动提交
|
# 查看变更
|
||||||
/commit
|
/diff
|
||||||
|
|
||||||
# 提交前审查
|
# 让 Claude 生成提交信息
|
||||||
/review
|
请基于当前 git diff 生成一个 Conventional Commit message
|
||||||
/commit
|
|
||||||
|
# 手动提交
|
||||||
|
!git add -A
|
||||||
|
!git commit -m "..."
|
||||||
```
|
```
|
||||||
|
|
||||||
**分支操作:**
|
**分支操作:**
|
||||||
@@ -1234,7 +1253,9 @@ Claude Code 深度集成了 Git,让你可以在不离开终端的情况下完
|
|||||||
!git checkout -b feature/user-authentication
|
!git checkout -b feature/user-authentication
|
||||||
|
|
||||||
# 完成开发后
|
# 完成开发后
|
||||||
/commit
|
请根据当前改动生成提交信息
|
||||||
|
!git add -A
|
||||||
|
!git commit -m "..."
|
||||||
!git push -u origin feature/user-authentication
|
!git push -u origin feature/user-authentication
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -1250,11 +1271,13 @@ Claude Code 深度集成了 Git,让你可以在不离开终端的情况下完
|
|||||||
# 3. 运行测试
|
# 3. 运行测试
|
||||||
!npm test
|
!npm test
|
||||||
|
|
||||||
# 4. 审查变更
|
# 4. 查看变更
|
||||||
/review
|
/diff
|
||||||
|
|
||||||
# 5. 提交代码
|
# 5. 生成并确认提交信息
|
||||||
/commit
|
请基于当前 git diff 生成一个 Conventional Commit message
|
||||||
|
!git add -A
|
||||||
|
!git commit -m "..."
|
||||||
|
|
||||||
# 6. 推送到远程
|
# 6. 推送到远程
|
||||||
!git push -u origin feature/payment-integration
|
!git push -u origin feature/payment-integration
|
||||||
@@ -1391,7 +1414,9 @@ Claude Code 深度集成了 Git,让你可以在不离开终端的情况下完
|
|||||||
!npm test
|
!npm test
|
||||||
|
|
||||||
# 5. 提交修复
|
# 5. 提交修复
|
||||||
/commit
|
请根据当前 diff 生成修复类提交信息
|
||||||
|
!git add -A
|
||||||
|
!git commit -m "fix: ..."
|
||||||
```
|
```
|
||||||
|
|
||||||
**场景 2:代码审查工作流**
|
**场景 2:代码审查工作流**
|
||||||
@@ -1411,7 +1436,8 @@ Claude Code 深度集成了 Git,让你可以在不离开终端的情况下完
|
|||||||
优化 UserList 组件的性能
|
优化 UserList 组件的性能
|
||||||
|
|
||||||
# 5. 最终审查
|
# 5. 最终审查
|
||||||
/review
|
/diff
|
||||||
|
请审查当前改动,指出潜在风险和可改进点
|
||||||
```
|
```
|
||||||
|
|
||||||
**场景 3:新功能开发工作流**
|
**场景 3:新功能开发工作流**
|
||||||
@@ -1434,10 +1460,13 @@ Claude Code 深度集成了 Git,让你可以在不离开终端的情况下完
|
|||||||
!npm test
|
!npm test
|
||||||
|
|
||||||
# 6. 代码审查
|
# 6. 代码审查
|
||||||
/review
|
/diff
|
||||||
|
请基于当前 diff 做一次代码审查
|
||||||
|
|
||||||
# 7. 提交代码
|
# 7. 提交代码
|
||||||
/commit
|
请生成本次功能开发的 commit message
|
||||||
|
!git add -A
|
||||||
|
!git commit -m "feat: ..."
|
||||||
!git push
|
!git push
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user