diff --git a/docs/.vitepress/theme/components/appendix/terminal-intro/EscapeParserDemo.vue b/docs/.vitepress/theme/components/appendix/terminal-intro/EscapeParserDemo.vue index 53e1545..15e343e 100644 --- a/docs/.vitepress/theme/components/appendix/terminal-intro/EscapeParserDemo.vue +++ b/docs/.vitepress/theme/components/appendix/terminal-intro/EscapeParserDemo.vue @@ -4,8 +4,8 @@
转义序列解析原理 (Parser Mechanism)
-
@@ -81,7 +81,7 @@ @@ -241,14 +263,14 @@ const play = async () => { .stream-track { position: relative; height: 60px; - display: flex; - justify-content: center; /* Center the focus area */ + /* Use a fixed height to contain the items */ } .stream-window-mask { width: 100%; overflow: hidden; position: relative; + height: 100%; /* Mask gradient to fade edges */ mask-image: linear-gradient(to right, transparent, black 40%, black 60%, transparent); -webkit-mask-image: linear-gradient(to right, transparent, black 40%, black 60%, transparent); @@ -258,9 +280,18 @@ const play = async () => { display: flex; gap: 4px; position: absolute; - left: 50%; /* Start from center */ + left: 50%; /* Center the container start */ + /* + Correct centering logic: + - Item width: 36px + - Gap: 4px + - Total unit: 40px + - We want Item[0] center to be at left:0 (relative to left:50%) + - Item[0] center is at: 18px (half width) + - So we need to shift left by 18px initially. + */ + margin-left: -18px; transition: transform 0.5s cubic-bezier(0.25, 1, 0.5, 1); - padding-left: 20px; /* Offset for first item */ } .char-box { diff --git a/docs/.vitepress/theme/components/appendix/terminal-intro/TerminalHandsOn.vue b/docs/.vitepress/theme/components/appendix/terminal-intro/TerminalHandsOn.vue index 2270790..c69f731 100644 --- a/docs/.vitepress/theme/components/appendix/terminal-intro/TerminalHandsOn.vue +++ b/docs/.vitepress/theme/components/appendix/terminal-intro/TerminalHandsOn.vue @@ -20,18 +20,33 @@

{{ currentTask.description }}

-
+
🤖 不知道怎么写?问问 AI -
-
+
{{ currentTask.aiQuery }}

{{ currentTask.aiResponse[currentOS] || currentTask.aiResponse.common }}

- +
+ +
@@ -79,6 +94,7 @@ spellcheck="false" autocomplete="off" /> + ⏎ 按回车执行
@@ -91,7 +107,7 @@ import { ref, computed, nextTick, watch } from 'vue' const currentOS = ref('win-cmd') const currentTaskIndex = ref(0) -const isAiOpen = ref(false) +const isAiOpen = ref(true) const inputCmd = ref('') const history = ref([]) const cmdInput = ref(null) @@ -197,23 +213,80 @@ d---- 1/15/2026 9:00 AM Downloads output: () => '' }, { - title: '第五步:安装程序', - description: '终端不仅能管理文件,还能安装软件。比如我们想安装一个 Python 库 "requests"。', - goal: '使用 pip 安装 requests 库。', - aiQuery: '怎么用命令行安装 python 的 requests 库?', + title: '第五步:安装程序 (系统软件 & Python库)', + description: '终端不仅能管理文件,还能安装软件。我们来尝试两种常见的安装场景:安装系统工具(如 wget/git)和安装 Python 库(如 requests)。', + goal: '任选其一:安装系统工具或 Python 库。', + aiQuery: '怎么用命令行安装软件?我想装 git 或者 python 的 requests 库。', aiResponse: { - 'common': '安装 Python 库通常使用 `pip` (Python Package Installer)。命令是 `pip install requests`。' + 'mac': 'macOS 推荐使用 Homebrew 安装系统软件,使用 pip 安装 Python 库。', + 'linux': 'Linux (Ubuntu/Debian) 使用 apt 安装系统软件,使用 pip 安装 Python 库。', + 'win-ps': 'Windows PowerShell 可以使用 pip 安装 Python 库。系统软件通常用 winget (这里暂只演示 pip)。', + 'win-cmd': 'CMD 也可以使用 pip 安装 Python 库。', + 'common': '不同系统有不同的包管理器。' + }, + commands: { + 'mac': [ + { label: '安装 wget (系统)', cmd: 'brew install wget' }, + { label: '安装 requests (Python)', cmd: 'pip install requests' } + ], + 'linux': [ + { label: '安装 git (系统)', cmd: 'sudo apt install git' }, + { label: '安装 requests (Python)', cmd: 'pip install requests' } + ], + 'win-ps': [ + { label: '安装 requests (Python)', cmd: 'pip install requests' } + ], + 'win-cmd': [ + { label: '安装 requests (Python)', cmd: 'pip install requests' } + ] }, expectedCmd: { - 'common': 'pip install requests' + // Fallback/Legacy + 'mac': 'brew install wget', + 'linux': 'sudo apt install git', + 'win-ps': 'pip install requests', + 'win-cmd': 'pip install requests' }, - validate: (cmd) => cmd.trim() === 'pip install requests', - output: () => ` + validate: (cmd, os) => { + const c = cmd.trim() + if (os === 'mac') return c === 'brew install wget' || c === 'pip install requests' + if (os === 'linux') return c === 'sudo apt install git' || c === 'apt install git' || c === 'pip install requests' + return c === 'pip install requests' + }, + output: (os, cmd) => { // Modified to accept cmd + const c = cmd ? cmd.trim() : '' + + // Python requests output + if (c.includes('pip install requests')) { + return ` Downloading/unpacking requests Downloading requests-2.31.0-py3-none-any.whl (62kB): 62kB downloaded Installing collected packages: requests Successfully installed requests Cleaning up...` + } + + // System tools output + if (os === 'mac') { + return ` +==> Downloading https://ghcr.io/v2/homebrew/core/wget/manifests/1.21.4 +######################################################################## 100.0% +==> Installing wget +🍺 /usr/local/Cellar/wget/1.21.4: 90 files, 4.2MB` + } + if (os === 'linux') { + return ` +Reading package lists... Done +Building dependency tree... Done +The following NEW packages will be installed: + git +0 upgraded, 1 newly installed, 0 to remove. +Get:1 http://archive.ubuntu.com/ubuntu jammy/main amd64 git amd64 1:2.34.1 [3MB] +Fetched 3MB in 1s (2560 kB/s) +Setting up git (1:2.34.1-1ubuntu1.9) ...` + } + return `Successfully installed.` + } }, { title: '第六步:打扫战场', @@ -288,7 +361,7 @@ const executeCommand = () => { // Check if it matches current task requirement if (!isTaskCompleted.value && currentTask.value.validate(cmd, currentOS.value)) { // Success - const out = currentTask.value.output(currentOS.value) + const out = currentTask.value.output(currentOS.value, cmd) // Pass cmd to output if (out) { history.value.push({ type: 'output', content: out }) } @@ -320,7 +393,6 @@ const nextTask = () => { if (currentTaskIndex.value < tasks.length - 1) { currentTaskIndex.value++ isTaskCompleted.value = false - isAiOpen.value = false // Clear history to keep it clean? Or keep it? Let's keep it but maybe add a separator history.value.push({ type: 'info', content: `--- 进入下一关: ${currentTask.value.title} ---` }) scrollToBottom() @@ -330,7 +402,6 @@ const nextTask = () => { const resetCurrentTask = () => { isTaskCompleted.value = false inputCmd.value = '' - isAiOpen.value = false history.value = [] } @@ -426,7 +497,6 @@ watch(currentOS, () => { .ai-header { padding: 10px 15px; background: linear-gradient(to right, rgba(16, 185, 129, 0.1), transparent); - cursor: pointer; display: flex; align-items: center; gap: 8px; @@ -440,16 +510,6 @@ watch(currentOS, () => { background: linear-gradient(to right, rgba(16, 185, 129, 0.2), transparent); } -.ai-header.active .ai-arrow { - transform: rotate(180deg); -} - -.ai-arrow { - margin-left: auto; - font-size: 0.8rem; - transition: transform 0.2s; -} - .ai-chat { padding: 15px; border-top: 1px solid var(--vp-c-divider); @@ -478,15 +538,22 @@ watch(currentOS, () => { border-bottom-left-radius: 2px; } +.cmd-buttons { + display: flex; + flex-direction: column; + gap: 8px; + margin-top: 10px; +} + .copy-btn { - margin-top: 5px; font-size: 0.8rem; - padding: 2px 8px; + padding: 4px 10px; border: 1px solid var(--vp-c-brand); color: var(--vp-c-brand); background: transparent; border-radius: 4px; cursor: pointer; + text-align: left; } .copy-btn:hover { @@ -633,6 +700,19 @@ watch(currentOS, () => { margin: 0; } +.enter-hint { + color: #666; + font-size: 12px; + margin-left: 10px; + animation: blink 1.5s infinite; + white-space: nowrap; +} + +@keyframes blink { + 0%, 100% { opacity: 0.5; } + 50% { opacity: 1; } +} + .line.output { color: inherit; opacity: 0.9; diff --git a/docs/zh-cn/appendix/terminal-intro.md b/docs/zh-cn/appendix/terminal-intro.md index 0ee62c9..4b85346 100644 --- a/docs/zh-cn/appendix/terminal-intro.md +++ b/docs/zh-cn/appendix/terminal-intro.md @@ -31,10 +31,12 @@ > 💡 **提示**:为了安全和方便,推荐你在下方的**网页模拟器**中操作。如果你有信心,也可以按照第 0 章的方法打开你电脑上真实的终端,跟随步骤一起练习(效果是一样的)。 在这个练习中,你将学会: -1. 查看当前有什么文件。 -2. 创建文件夹和文件。 -3. 删除它们。 -4. **学会向 AI 提问**:当你忘记命令时,如何让 AI 告诉你答案。 +1. **查看文件**:学会用 `ls` 或 `dir` 看看当前目录下有什么。 +2. **创建与进入**:学会用 `mkdir` 创建新文件夹,用 `cd` 像传送门一样进入它。 +3. **新建文件**:学会用命令快速创建一个新文件。 +4. **安装软件**:体验一行代码安装 Python 库或系统软件的快感。 +5. **删除清理**:学会如何删除不需要的文件(慎用!)。 +6. **求助 AI**:这是最重要的!当你忘记命令时,学会问 AI:“在 Mac 上怎么删除文件?”,它会直接告诉你答案。 *请在下方选择你常用的操作系统,然后跟随引导开始操作:*