fix(eslint): reduce warnings in GitHub Actions deployment

- Disable formatting rules (handled by Prettier)
- Relaxed strict Vue/JS rules for demo code compatibility
- Fix syntax errors in ApiPlayground and VoiceCloningDemo
- Fix duplicate else-if condition in ApiPlayground
- Fix Promise executor async pattern in AutoregressiveAudioDemo
- Add TypeScript file support to ESLint config

Warnings reduced from 295 to 251 problems.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
sanbuphy
2026-02-18 17:38:10 +08:00
parent 8b01686e68
commit 0eba9e87e9
456 changed files with 28450 additions and 9677 deletions
@@ -15,14 +15,23 @@
<div class="tui-window">
<div class="tui-header">
<div class="tabs">
<div class="tab active">Continuous</div>
<div class="tab">Integration</div>
<div class="tab">Logging</div>
<div class="tab active">
Continuous
</div>
<div class="tab">
Integration
</div>
<div class="tab">
Logging
</div>
</div>
</div>
<div class="tui-body">
<div class="sidebar" :style="{ width: sidebarWidth + '%' }">
<div
class="sidebar"
:style="{ width: sidebarWidth + '%' }"
>
<div class="list-item success">
<span class="icon"></span> ci-fe-be-rules
</div>
@@ -48,7 +57,9 @@
<div class="status-row">
Status: <span class="text-success">success</span>
</div>
<div class="info-row">Updated: 2024-01-15 14:32:00 UTC</div>
<div class="info-row">
Updated: 2024-01-15 14:32:00 UTC
</div>
</div>
</div>
</div>
@@ -56,12 +67,17 @@
<div class="tui-controls">
<div class="control-group">
<button @click="toggleCoordinates" :class="{ active: showCoordinates }">
<button
:class="{ active: showCoordinates }"
@click="toggleCoordinates"
>
Show Coordinates
</button>
</div>
<div class="control-group">
<button @click="simulateResize">Simulate Resize</button>
<button @click="simulateResize">
Simulate Resize
</button>
<span class="size-label">Size: {{ sizeDisplay }}</span>
</div>
</div>
@@ -15,35 +15,56 @@
<div class="arch-demo">
<div class="analogy-header">
<div class="analogy-item">
<div class="icon">🖥</div>
<div class="icon">
🖥
</div>
<div class="text">
<div class="role">Terminal (终端)</div>
<div class="desc">传声筒 / 窗口</div>
<div class="role">
Terminal (终端)
</div>
<div class="desc">
传声筒 / 窗口
</div>
</div>
</div>
<div class="analogy-item">
<div class="icon">🗣</div>
<div class="icon">
🗣
</div>
<div class="text">
<div class="role">Shell ()</div>
<div class="desc">翻译官 / 助手</div>
<div class="role">
Shell ()
</div>
<div class="desc">
翻译官 / 助手
</div>
</div>
</div>
<div class="analogy-item">
<div class="icon"></div>
<div class="icon">
</div>
<div class="text">
<div class="role">Kernel (内核)</div>
<div class="desc">大管家 / 芯片</div>
<div class="role">
Kernel (内核)
</div>
<div class="desc">
大管家 / 芯片
</div>
</div>
</div>
</div>
<div
class="diagram-container"
@click="nextStep"
:class="{ clickable: currentStep < totalSteps }"
@click="nextStep"
>
<!-- Click Overlay Hint -->
<div class="click-overlay" v-if="currentStep === 0">
<div
v-if="currentStep === 0"
class="click-overlay"
>
<div class="click-hint">
<span class="icon">👆</span>
<span class="text">不断点击屏幕演示 / Keep Clicking</span>
@@ -51,8 +72,14 @@
</div>
<!-- Completed Overlay -->
<div class="completed-overlay" v-if="currentStep >= totalSteps">
<div class="completed-hint" @click.stop="reset">
<div
v-if="currentStep >= totalSteps"
class="completed-overlay"
>
<div
class="completed-hint"
@click.stop="reset"
>
<span class="icon"></span>
<span class="text">演示结束点击重置 / Finished (Reset)</span>
</div>
@@ -61,30 +88,48 @@
<!-- Spaces Background -->
<div class="spaces-bg">
<div class="space user-space">
<div class="space-header">User Space (用户空间)</div>
<div class="space-header">
User Space (用户空间)
</div>
</div>
<div class="barrier">
<div class="barrier-line"></div>
<div class="barrier-line" />
</div>
<div class="space kernel-space">
<div class="space-header">Kernel Space (内核空间)</div>
<div class="space-header">
Kernel Space (内核空间)
</div>
</div>
</div>
<!-- Terminal Node -->
<div class="node terminal" :class="{ active: activeNode === 'terminal' }">
<div class="node-title">TERMINAL (终端)</div>
<div
class="node terminal"
:class="{ active: activeNode === 'terminal' }"
>
<div class="node-title">
TERMINAL (终端)
</div>
<div class="screen">
<div v-for="(line, i) in terminalLines" :key="i" class="line">
<div
v-for="(line, i) in terminalLines"
:key="i"
class="line"
>
{{ line }}
</div>
<div class="line input-line">
<span class="prompt">$</span>
<span class="typing">{{ currentInput }}</span>
<span class="cursor" v-if="activeNode === 'terminal'"></span>
<span
v-if="activeNode === 'terminal'"
class="cursor"
/>
</div>
</div>
<div class="node-label">/dev/tty</div>
<div class="node-label">
/dev/tty
</div>
</div>
<!-- Connections -->
@@ -94,24 +139,43 @@
active: packetState === 't-to-s' || packetState === 's-to-t'
}"
>
<div class="line-path"></div>
<div class="data-label" v-if="packetState === 't-to-s'">
<div class="line-path" />
<div
v-if="packetState === 't-to-s'"
class="data-label"
>
<span class="icon"></span> Bytes
</div>
<div class="data-label" v-if="packetState === 's-to-t'">
<div
v-if="packetState === 's-to-t'"
class="data-label"
>
<span class="icon"></span> Text
</div>
<div class="conn-label">stdin / stdout</div>
<div class="conn-label">
stdin / stdout
</div>
</div>
<!-- Shell Node -->
<div class="node shell" :class="{ active: activeNode === 'shell' }">
<div class="node-title">SHELL ()</div>
<div class="process-box">
<div class="status-icon">{{ shellIcon }}</div>
<div class="status">{{ shellStatus }}</div>
<div
class="node shell"
:class="{ active: activeNode === 'shell' }"
>
<div class="node-title">
SHELL ()
</div>
<div class="process-box">
<div class="status-icon">
{{ shellIcon }}
</div>
<div class="status">
{{ shellStatus }}
</div>
</div>
<div class="node-label">
/bin/zsh
</div>
<div class="node-label">/bin/zsh</div>
</div>
<!-- Connections -->
@@ -121,24 +185,43 @@
active: packetState === 's-to-k' || packetState === 'k-to-s'
}"
>
<div class="line-path"></div>
<div class="data-label" v-if="packetState === 's-to-k'">
<div class="line-path" />
<div
v-if="packetState === 's-to-k'"
class="data-label"
>
<span class="icon"></span> Syscall
</div>
<div class="data-label" v-if="packetState === 'k-to-s'">
<div
v-if="packetState === 'k-to-s'"
class="data-label"
>
<span class="icon"></span> Raw Data
</div>
<div class="conn-label">System Calls</div>
<div class="conn-label">
System Calls
</div>
</div>
<!-- Kernel Node -->
<div class="node kernel" :class="{ active: activeNode === 'kernel' }">
<div class="node-title">KERNEL (内核)</div>
<div class="process-box">
<div class="status-icon">{{ kernelIcon }}</div>
<div class="status">{{ kernelStatus }}</div>
<div
class="node kernel"
:class="{ active: activeNode === 'kernel' }"
>
<div class="node-title">
KERNEL (内核)
</div>
<div class="process-box">
<div class="status-icon">
{{ kernelIcon }}
</div>
<div class="status">
{{ kernelStatus }}
</div>
</div>
<div class="node-label">
macOS / Linux
</div>
<div class="node-label">macOS / Linux</div>
</div>
</div>
@@ -146,45 +229,63 @@
<div class="btn-group">
<button
class="btn primary"
@click="nextStep"
:disabled="currentStep >= totalSteps"
@click="nextStep"
>
<span v-if="currentStep === 0"> Start Simulation / 开始演示</span>
<span v-else-if="currentStep < totalSteps"
>Next Step / 下一步 ({{ currentStep }}/{{ totalSteps }}) </span
>
<span v-else-if="currentStep < totalSteps">Next Step / 下一步 ({{ currentStep }}/{{ totalSteps }}) </span>
<span v-else> Done / 完成 (Reset)</span>
</button>
<button class="btn secondary" @click="reset" v-if="currentStep > 0">
<button
v-if="currentStep > 0"
class="btn secondary"
@click="reset"
>
Reset / 重置
</button>
</div>
<div class="step-info" v-if="currentStep > 0">
<div
v-if="currentStep > 0"
class="step-info"
>
<div class="step-title">
{{ steps[currentStep - 1].titleEn }}
<span class="divider">|</span>
{{ steps[currentStep - 1].titleZh }}
</div>
<div class="step-desc">
<div class="en">{{ steps[currentStep - 1].descEn }}</div>
<div class="zh">{{ steps[currentStep - 1].descZh }}</div>
<div class="en">
{{ steps[currentStep - 1].descEn }}
</div>
<div class="zh">
{{ steps[currentStep - 1].descZh }}
</div>
</div>
<div class="step-tech">
<span class="tech-label">Technical / 技术原理:</span>
<div class="tech-content">
<div class="en">{{ steps[currentStep - 1].techEn }}</div>
<div class="zh">{{ steps[currentStep - 1].techZh }}</div>
<div class="en">
{{ steps[currentStep - 1].techEn }}
</div>
<div class="zh">
{{ steps[currentStep - 1].techZh }}
</div>
</div>
</div>
</div>
<div class="step-info placeholder" v-else>
<div
v-else
class="step-info placeholder"
>
<div class="step-desc">
<div class="en">
Click "Start Simulation" to see how the command 'ls' travels through
the system.
</div>
<div class="zh">点击开始演示查看 'ls' 命令如何在系统中流转</div>
<div class="zh">
点击开始演示查看 'ls' 命令如何在系统中流转
</div>
</div>
</div>
</div>
@@ -2,9 +2,9 @@
<div class="buffer-demo">
<div class="terminal-frame">
<div class="window-bar">
<span class="dot red"></span>
<span class="dot yellow"></span>
<span class="dot green"></span>
<span class="dot red" />
<span class="dot yellow" />
<span class="dot green" />
<span class="title">Terminal - Buffer Switching Demo</span>
</div>
@@ -14,7 +14,9 @@
<div class="line">
<span class="prompt"></span> <span class="cmd">ls -la</span>
</div>
<div class="line output">total 16</div>
<div class="line output">
total 16
</div>
<div class="line output">
drwxr-xr-x 2 user staff 64 Jan 15 10:00 .
</div>
@@ -28,7 +30,9 @@
<span class="prompt"></span>
<span class="cmd">echo "Hello World"</span>
</div>
<div class="line output">Hello World</div>
<div class="line output">
Hello World
</div>
<div class="line">
<span class="prompt"></span> <span class="cmd">vim notes.txt</span>
</div>
@@ -37,29 +41,54 @@
<!-- Alternate Buffer (Layer 1) -->
<transition name="slide-up">
<div v-if="isAltBufferActive" class="buffer alt-buffer">
<div
v-if="isAltBufferActive"
class="buffer alt-buffer"
>
<div class="vim-header">
<span class="filename">notes.txt</span>
<span class="modified">[+]</span>
</div>
<div class="vim-body">
<div class="line-num">1</div>
<div class="code">This is a text file opened in Vim.</div>
<div class="line-num">2</div>
<div class="code"></div>
<div class="line-num">3</div>
<div class="code">Notice how this interface takes up</div>
<div class="line-num">4</div>
<div class="code">the entire screen?</div>
<div class="line-num">5</div>
<div class="code"></div>
<div class="line-num">6</div>
<div class="line-num">
1
</div>
<div class="code">
This is a text file opened in Vim.
</div>
<div class="line-num">
2
</div>
<div class="code" />
<div class="line-num">
3
</div>
<div class="code">
Notice how this interface takes up
</div>
<div class="line-num">
4
</div>
<div class="code">
the entire screen?
</div>
<div class="line-num">
5
</div>
<div class="code" />
<div class="line-num">
6
</div>
<div class="code">
It is running in the
<span class="highlight">Alternate Buffer</span>.
</div>
<div class="line-num">~</div>
<div class="line-num">~</div>
<div class="line-num">
~
</div>
<div class="line-num">
~
</div>
</div>
<div class="vim-status-bar">
<span class="mode">NORMAL</span>
@@ -81,7 +110,10 @@
This is the standard scrolling log. Commands are executed line by
line.
</p>
<button class="action-btn" @click="openVim">
<button
class="action-btn"
@click="openVim"
>
Execute `vim notes.txt`
</button>
</div>
@@ -91,7 +123,10 @@
A separate "canvas" for full-screen apps. It hides the history but
doesn't delete it.
</p>
<button class="action-btn red" @click="quitVim">
<button
class="action-btn red"
@click="quitVim"
>
Execute `:q` (Quit)
</button>
</div>
@@ -13,7 +13,10 @@
<template>
<div class="cell-inspector">
<div class="preview-area">
<div class="large-cell" :style="cellStyle">
<div
class="large-cell"
:style="cellStyle"
>
{{ char }}
</div>
</div>
@@ -43,7 +46,7 @@
:style="{ backgroundColor: color }"
:class="{ active: fgColor === color }"
@click="fgColor = color"
></div>
/>
</div>
</div>
@@ -63,7 +66,7 @@
background-color: #111;
"
@click="bgColor = 'transparent'"
></div>
/>
<div
v-for="color in bgColors"
:key="color"
@@ -71,7 +74,7 @@
:style="{ backgroundColor: color }"
:class="{ active: bgColor === color }"
@click="bgColor = color"
></div>
/>
</div>
</div>
@@ -79,11 +82,17 @@
<label>ATTRIBUTES</label>
<div class="toggles">
<label class="toggle">
<input type="checkbox" v-model="isBold" />
<input
v-model="isBold"
type="checkbox"
>
<span>Bold</span>
</label>
<label class="toggle">
<input type="checkbox" v-model="isUnderline" />
<input
v-model="isUnderline"
type="checkbox"
>
<span>Underline</span>
</label>
</div>
@@ -1,15 +1,24 @@
<template>
<div class="cooked-raw-demo">
<div class="mode-switch">
<button :class="{ active: mode === 'cooked' }" @click="setMode('cooked')">
<button
:class="{ active: mode === 'cooked' }"
@click="setMode('cooked')"
>
🥘 Cooked Mode (Standard)
</button>
<button :class="{ active: mode === 'raw' }" @click="setMode('raw')">
<button
:class="{ active: mode === 'raw' }"
@click="setMode('raw')"
>
🥩 Raw Mode (Vim/Games)
</button>
</div>
<div class="demo-container" @click="focusInput">
<div
class="demo-container"
@click="focusInput"
>
<!-- Hidden Input for capturing keystrokes -->
<input
ref="inputRef"
@@ -18,23 +27,41 @@
@keydown="handleKey"
@blur="isFocused = false"
@focus="isFocused = true"
/>
>
<!-- Visualization -->
<div class="flow-diagram">
<!-- 1. User Input -->
<div class="stage user-input" :class="{ focused: isFocused }">
<div class="stage-title">1. Keyboard Input</div>
<div
class="stage user-input"
:class="{ focused: isFocused }"
>
<div class="stage-title">
1. Keyboard Input
</div>
<div class="key-visual">
<span v-if="lastPressedKey" class="key-cap">{{
<span
v-if="lastPressedKey"
class="key-cap"
>{{
lastPressedKey
}}</span>
<span v-else class="placeholder">Type here...</span>
<span
v-else
class="placeholder"
>Type here...</span>
</div>
<div
v-if="!isFocused"
class="status-text"
>
Click to focus
</div>
<div class="status-text" v-if="!isFocused">Click to focus</div>
</div>
<div class="arrow"></div>
<div class="arrow">
</div>
<!-- 2. OS Buffer (Only for Cooked) -->
<div
@@ -43,12 +70,22 @@
>
<div class="stage-title">
2. Line Buffer (Kernel)
<span class="badge" v-if="mode === 'cooked'">Active</span>
<span class="badge disabled" v-else>Bypassed</span>
<span
v-if="mode === 'cooked'"
class="badge"
>Active</span>
<span
v-else
class="badge disabled"
>Bypassed</span>
</div>
<div class="buffer-content">
<template v-if="mode === 'cooked'">
<span v-for="(char, i) in buffer" :key="i" class="char">{{
<span
v-for="(char, i) in buffer"
:key="i"
class="char"
>{{
char
}}</span>
<span class="cursor">_</span>
@@ -58,20 +95,26 @@
</template>
</div>
<div class="explanation">
<span v-if="mode === 'cooked'"
>Waiting for Enter... (Backspace works)</span
>
<span v-if="mode === 'cooked'">Waiting for Enter... (Backspace works)</span>
<span v-else>No buffering. Every key is sent immediately.</span>
</div>
</div>
<div class="arrow"></div>
<div class="arrow">
</div>
<!-- 3. Application -->
<div class="stage app-input">
<div class="stage-title">3. Application Receives</div>
<div class="stage-title">
3. Application Receives
</div>
<div class="app-content">
<div v-for="(line, i) in appLines" :key="i" class="app-line">
<div
v-for="(line, i) in appLines"
:key="i"
class="app-line"
>
{{ line }}
</div>
<div class="app-line current">
@@ -1,10 +1,20 @@
<template>
<div class="parser-demo">
<div class="demo-header">
<div class="title">转义序列解析原理 (Parser Mechanism)</div>
<div class="title">
转义序列解析原理 (Parser Mechanism)
</div>
<div class="controls">
<button @click="reset" :disabled="isPlaying">Reset</button>
<button @click="togglePlay" class="play-btn">
<button
:disabled="isPlaying"
@click="reset"
>
Reset
</button>
<button
class="play-btn"
@click="togglePlay"
>
{{
isPlaying ? '⏸ Pause' : isFinished ? '↺ Replay' : '▶ Play Animation'
}}
@@ -14,7 +24,9 @@
<!-- 1. 字节流传送带 -->
<div class="stream-container">
<div class="label">Input Byte Stream / 输入字节流</div>
<div class="label">
Input Byte Stream / 输入字节流
</div>
<div class="stream-track">
<div class="stream-window-mask">
<div
@@ -39,29 +51,49 @@
</div>
<!-- 指针 -->
<div class="pointer">
<div class="arrow"></div>
<div class="pointer-label">Current Byte</div>
<div class="arrow">
</div>
<div class="pointer-label">
Current Byte
</div>
</div>
</div>
</div>
<!-- 2. 解析器状态机 -->
<div class="parser-state-machine">
<div class="state-box" :class="{ active: parserState === 'NORMAL' }">
<div class="state-name">NORMAL</div>
<div class="state-desc">Print Characters</div>
<div
class="state-box"
:class="{ active: parserState === 'NORMAL' }"
>
<div class="state-name">
NORMAL
</div>
<div class="state-desc">
Print Characters
</div>
</div>
<div class="arrow-right">
</div>
<div class="arrow-right"></div>
<div
class="state-box warning"
:class="{ active: parserState === 'ESCAPE' }"
>
<div class="state-name">ESCAPE MODE</div>
<div class="state-desc">Buffer Command...</div>
<div class="state-name">
ESCAPE MODE
</div>
<div class="state-desc">
Buffer Command...
</div>
</div>
<!-- 指令说明框 -->
<div class="action-log" v-if="lastAction">
<div
v-if="lastAction"
class="action-log"
>
<span class="action-icon"></span>
{{ lastAction }}
</div>
@@ -69,14 +101,15 @@
<!-- 3. 终端屏幕 -->
<div class="terminal-screen">
<div class="label">Terminal Screen / 屏幕显示</div>
<div class="label">
Terminal Screen / 屏幕显示
</div>
<div class="screen-content">
<span
v-for="(char, index) in outputBuffer"
:key="index"
:style="char.style"
>{{ char.val }}</span
><span class="cursor">_</span>
>{{ char.val }}</span><span class="cursor">_</span>
</div>
</div>
@@ -26,11 +26,14 @@
:key="index"
class="swatch"
:style="{ backgroundColor: color }"
@click="applyColor(index)"
:title="`^[[38;5;${index}m`"
></div>
@click="applyColor(index)"
/>
</div>
<div class="hint-text" v-if="activeColor">
<div
v-if="activeColor"
class="hint-text"
>
Sequence:
<span class="code">^[[38;5;{{ palette.indexOf(activeColor) }}m</span>
</div>
@@ -43,17 +46,29 @@
<span class="zh">样式序列</span>
</div>
<div class="btn-group">
<button @click="applyStyle('1')" :class="{ active: isBold }">
<button
:class="{ active: isBold }"
@click="applyStyle('1')"
>
<span class="btn-code">^[[1m</span>
<span class="btn-label">Bold / 加粗</span>
</button>
<button @click="applyStyle('4')" :class="{ active: isUnderline }">
<button
:class="{ active: isUnderline }"
@click="applyStyle('4')"
>
<span class="btn-code">^[[4m</span>
<span class="btn-label">Underline / 下划线</span>
</button>
</div>
<div class="btn-group" style="margin-top: 8px">
<button @click="resetStyle" class="reset-btn">
<div
class="btn-group"
style="margin-top: 8px"
>
<button
class="reset-btn"
@click="resetStyle"
>
<span class="btn-code">^[[0m</span>
<span class="btn-label">Reset / 重置所有样式</span>
</button>
@@ -86,22 +101,32 @@
<div class="preview">
<div class="terminal-window">
<div class="window-header">
<div class="dots"><span></span><span></span><span></span></div>
<div class="window-title">Terminal Preview</div>
<div class="dots">
<span /><span /><span />
</div>
<div class="window-title">
Terminal Preview
</div>
</div>
<div class="window-content">
<div class="sequence-display-area">
<span class="label">Last Sequence:</span>
<span v-if="lastSequence" class="sequence-code">{{
<span
v-if="lastSequence"
class="sequence-code"
>{{
lastSequence
}}</span>
<span v-else class="placeholder">Waiting for input...</span>
<span
v-else
class="placeholder"
>Waiting for input...</span>
</div>
<div
v-if="isContentVisible"
class="main-display"
:style="currentStyle"
v-if="isContentVisible"
>
Hello World
</div>
@@ -109,10 +134,13 @@
<div class="cursor-line">
<span class="prompt">$</span>
<span
class="cursor-placeholder"
v-if="cursorMode === 'absolute'"
></span>
<span class="cursor-block" :style="cursorStyle"></span>
class="cursor-placeholder"
/>
<span
class="cursor-block"
:style="cursorStyle"
/>
</div>
</div>
</div>
@@ -13,69 +13,111 @@
<template>
<div class="flow-diagram">
<div class="stack-col">
<div class="stack-label">TERMINAL STACK</div>
<div class="stack-label">
TERMINAL STACK
</div>
<div class="stack-box kbd" :class="{ active: activeStage === 'kbd' }">
<div
class="stack-box kbd"
:class="{ active: activeStage === 'kbd' }"
>
<div class="box-header">
<span class="box-icon">[kbd]</span>
<span class="box-title">You (Keyboard)</span>
</div>
<div class="box-desc">Physical keystrokes</div>
<div class="box-desc">
Physical keystrokes
</div>
</div>
<div class="arrow"> / </div>
<div class="arrow">
/
</div>
<div class="stack-box tty" :class="{ active: activeStage === 'tty' }">
<div
class="stack-box tty"
:class="{ active: activeStage === 'tty' }"
>
<div class="box-header">
<span class="box-icon">[tty]</span>
<span class="box-title">Terminal Emulator</span>
</div>
<div class="box-desc">Encodes input, renders output</div>
<div class="box-desc">
Encodes input, renders output
</div>
</div>
<div class="arrow"> / </div>
<div class="arrow">
/
</div>
<div class="stack-box pty" :class="{ active: activeStage === 'pty' }">
<div
class="stack-box pty"
:class="{ active: activeStage === 'pty' }"
>
<div class="box-header">
<span class="box-icon">[pty]</span>
<span class="box-title">PTY (Pseudo-Terminal)</span>
</div>
<div class="box-desc">Bidirectional pipe</div>
<div class="box-desc">
Bidirectional pipe
</div>
</div>
<div class="arrow"> / </div>
<div class="arrow">
/
</div>
<div class="stack-box sh" :class="{ active: activeStage === 'sh' }">
<div
class="stack-box sh"
:class="{ active: activeStage === 'sh' }"
>
<div class="box-header">
<span class="box-icon">[sh]</span>
<span class="box-title">Shell / Program</span>
</div>
<div class="box-desc">bash, zsh, or any CLI program</div>
<div class="box-desc">
bash, zsh, or any CLI program
</div>
</div>
</div>
<div class="output-col">
<div class="output-label">OUTPUT</div>
<div class="output-label">
OUTPUT
</div>
<div class="terminal-preview">
<div class="term-header"><span></span><span></span><span></span></div>
<div class="term-header">
<span /><span /><span />
</div>
<div class="term-body">
<span class="prompt">$ </span>
<span class="typed-text">{{ displayText }}</span>
<span class="cursor" :class="{ blinking: !isAnimating }"></span>
<span
class="cursor"
:class="{ blinking: !isAnimating }"
/>
</div>
</div>
<div class="status-box">
<div class="status-title" :class="statusColor">{{ statusTitle }}</div>
<div class="status-desc">{{ statusDesc }}</div>
<div
class="status-title"
:class="statusColor"
>
{{ statusTitle }}
</div>
<div class="status-desc">
{{ statusDesc }}
</div>
</div>
<div class="controls">
<button
class="play-btn"
@click="startAnimation"
:disabled="isAnimating"
@click="startAnimation"
>
{{ isAnimating ? 'Simulating...' : 'Simulate Keystroke' }}
</button>
@@ -18,24 +18,41 @@
@keydown="handleKeydown"
@blur="handleBlur"
>
<div class="focus-overlay" v-if="!isFocused" @click="focus">
<div
v-if="!isFocused"
class="focus-overlay"
@click="focus"
>
<div class="focus-btn">
<span class="icon"></span>
<span>Click to Type</span>
</div>
</div>
<div class="main-display" :class="{ 'blur-content': !isFocused }">
<div class="key-name">{{ currentKey.name || 'Press any key' }}</div>
<div
class="main-display"
:class="{ 'blur-content': !isFocused }"
>
<div class="key-name">
{{ currentKey.name || 'Press any key' }}
</div>
<div class="info-grid">
<div class="info-box">
<div class="label">BYTES (HEX)</div>
<div class="value highlight">{{ currentKey.bytes || '-' }}</div>
<div class="label">
BYTES (HEX)
</div>
<div class="value highlight">
{{ currentKey.bytes || '-' }}
</div>
</div>
<div class="info-box">
<div class="label">SEQUENCE</div>
<div class="value code">{{ currentKey.sequence || '-' }}</div>
<div class="label">
SEQUENCE
</div>
<div class="value code">
{{ currentKey.sequence || '-' }}
</div>
</div>
</div>
@@ -46,7 +63,11 @@
</div>
<div class="history-strip">
<div v-for="(item, i) in history" :key="i" class="history-item">
<div
v-for="(item, i) in history"
:key="i"
class="history-item"
>
<span class="h-name">{{ item.name }}</span>
<span class="arrow"></span>
<span class="h-bytes">{{ item.bytes }}</span>
@@ -24,7 +24,9 @@
<span class="key">Ctrl</span>+<span class="key">C</span>
<span class="action">Interrupt</span>
</div>
<div class="signal-name">SIGINT</div>
<div class="signal-name">
SIGINT
</div>
</div>
<div
@@ -36,7 +38,9 @@
<span class="key">Ctrl</span>+<span class="key">Z</span>
<span class="action">Suspend</span>
</div>
<div class="signal-name">SIGTSTP</div>
<div class="signal-name">
SIGTSTP
</div>
</div>
</div>
@@ -46,7 +50,9 @@
<span class="highlight">Ctrl+C</span>
<span class="signal-green">SIGINT</span>
</div>
<div class="info-desc">Stop the running program</div>
<div class="info-desc">
Stop the running program
</div>
<p>
Sends SIGINT (signal interrupt) to the foreground process. Most
programs respond by stopping immediately. It's how you cancel a
@@ -62,7 +68,9 @@
<span class="highlight">Ctrl+Z</span>
<span class="signal-blue">SIGTSTP</span>
</div>
<div class="info-desc">Suspend the running program</div>
<div class="info-desc">
Suspend the running program
</div>
<p>
Sends SIGTSTP (signal terminal stop). The process is paused and put
in the background. You can resume it later with `fg` command.
@@ -73,7 +81,9 @@
</div>
</div>
<div v-else>
<div class="info-header">Select a signal</div>
<div class="info-header">
Select a signal
</div>
<p>Click on a signal type above to see how it works.</p>
</div>
</div>
@@ -82,7 +92,9 @@
<div class="right-panel">
<div class="terminal-window">
<div class="window-header">
<div class="dots"><span></span><span></span><span></span></div>
<div class="dots">
<span /><span /><span />
</div>
</div>
<div class="window-content">
<div
@@ -93,24 +105,54 @@
>
{{ line.text }}
</div>
<div v-if="isRunning" class="term-line output">sleeping...</div>
<div v-if="inputBuffer" class="term-line input">
<span class="prompt">$</span> {{ inputBuffer
}}<span class="cursor"></span>
<div
v-if="isRunning"
class="term-line output"
>
sleeping...
</div>
<div v-else class="term-line input">
<span class="prompt">$</span> <span class="cursor"></span>
<div
v-if="inputBuffer"
class="term-line input"
>
<span class="prompt">$</span> {{ inputBuffer
}}<span class="cursor" />
</div>
<div
v-else
class="term-line input"
>
<span class="prompt">$</span> <span class="cursor" />
</div>
</div>
</div>
<div class="controls">
<button class="btn" @click="runCommand" :disabled="isRunning">
<button
class="btn"
:disabled="isRunning"
@click="runCommand"
>
Run Command
</button>
<button class="btn" @click="sendSignal('SIGINT')">Ctrl+C</button>
<button class="btn" @click="sendSignal('SIGTSTP')">Ctrl+Z</button>
<button class="btn secondary" @click="reset">Reset</button>
<button
class="btn"
@click="sendSignal('SIGINT')"
>
Ctrl+C
</button>
<button
class="btn"
@click="sendSignal('SIGTSTP')"
>
Ctrl+Z
</button>
<button
class="btn secondary"
@click="reset"
>
Reset
</button>
</div>
<div class="state-display">
@@ -1,16 +1,25 @@
<template>
<div class="terminal-definition">
<div class="mode-switch">
<button :class="{ active: mode === 'cli' }" @click="mode = 'cli'">
<button
:class="{ active: mode === 'cli' }"
@click="mode = 'cli'"
>
🖥 CLI (命令行界面)
</button>
<button :class="{ active: mode === 'gui' }" @click="mode = 'gui'">
<button
:class="{ active: mode === 'gui' }"
@click="mode = 'gui'"
>
🖱 GUI (图形用户界面)
</button>
</div>
<!-- CLI Visualization -->
<div v-if="mode === 'cli'" class="visualization-container">
<div
v-if="mode === 'cli'"
class="visualization-container"
>
<div class="flow-container">
<!-- Input Side -->
<div class="stage input-stage">
@@ -26,26 +35,39 @@
stroke-linecap="round"
stroke-linejoin="round"
>
<rect x="2" y="4" width="20" height="16" rx="2" ry="2"></rect>
<path d="M6 8h.001"></path>
<path d="M10 8h.001"></path>
<path d="M14 8h.001"></path>
<path d="M18 8h.001"></path>
<path d="M6 12h.001"></path>
<path d="M10 12h.001"></path>
<path d="M14 12h.001"></path>
<path d="M18 12h.001"></path>
<path d="M7 16h10"></path>
<rect
x="2"
y="4"
width="20"
height="16"
rx="2"
ry="2"
/>
<path d="M6 8h.001" />
<path d="M10 8h.001" />
<path d="M14 8h.001" />
<path d="M18 8h.001" />
<path d="M6 12h.001" />
<path d="M10 12h.001" />
<path d="M14 12h.001" />
<path d="M18 12h.001" />
<path d="M7 16h10" />
</svg>
</div>
<div class="label">Input (Keyboard)</div>
<div class="sub-label">发送指令 (字符信号)</div>
<div class="label">
Input (Keyboard)
</div>
<div class="sub-label">
发送指令 (字符信号)
</div>
</div>
<!-- Stream Animation -->
<div class="stream-path">
<div class="stream-line"></div>
<div class="stream-label">Character Stream / 字符流</div>
<div class="stream-line" />
<div class="stream-label">
Character Stream / 字符流
</div>
<div
v-for="char in activeChars"
:key="char.id"
@@ -64,8 +86,12 @@
}}<span class="cursor">_</span>
</div>
</div>
<div class="label">Output (Text Grid)</div>
<div class="sub-label">文本网格反馈</div>
<div class="label">
Output (Text Grid)
</div>
<div class="sub-label">
文本网格反馈
</div>
</div>
</div>
@@ -77,7 +103,10 @@
</div>
<div class="control-bar">
<button @click="startSimulation" :disabled="isAnimating">
<button
:disabled="isAnimating"
@click="startSimulation"
>
<span v-if="!isAnimating"> Play Simulation / 演示输入流</span>
<span v-else>Simulating... / 演示中...</span>
</button>
@@ -85,11 +114,17 @@
</div>
<!-- GUI Visualization -->
<div v-else class="visualization-container">
<div
v-else
class="visualization-container"
>
<div class="flow-container">
<!-- Input Side -->
<div class="stage input-stage">
<div class="icon-box gui-input" :class="{ clicking: isGuiClicking }">
<div
class="icon-box gui-input"
:class="{ clicking: isGuiClicking }"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="32"
@@ -101,18 +136,24 @@
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M3 3l7.07 16.97 2.51-7.39 7.39-2.51L3 3z"></path>
<path d="M13 13l6 6"></path>
<path d="M3 3l7.07 16.97 2.51-7.39 7.39-2.51L3 3z" />
<path d="M13 13l6 6" />
</svg>
</div>
<div class="label">Input (Mouse)</div>
<div class="sub-label">发送事件 (坐标/点击)</div>
<div class="label">
Input (Mouse)
</div>
<div class="sub-label">
发送事件 (坐标/点击)
</div>
</div>
<!-- Event Animation -->
<div class="stream-path">
<div class="stream-line dashed"></div>
<div class="stream-label">Event Loop / 事件循环</div>
<div class="stream-line dashed" />
<div class="stream-label">
Event Loop / 事件循环
</div>
<div
v-for="ev in guiEvents"
:key="ev.id"
@@ -127,15 +168,23 @@
<div class="stage output-stage">
<div class="gui-screen">
<div class="window-frame">
<div class="win-header"></div>
<div class="win-header" />
<div class="win-body">
<div class="icon-grid">
<div class="desktop-icon" :class="{ selected: iconSelected }">
<div
class="desktop-icon"
:class="{ selected: iconSelected }"
>
📁
</div>
<div class="desktop-icon">📄</div>
<div class="desktop-icon">
📄
</div>
</div>
<div class="gui-cursor" :style="cursorStyle">
<div
class="gui-cursor"
:style="cursorStyle"
>
<svg
width="12"
height="12"
@@ -144,14 +193,18 @@
stroke="black"
stroke-width="2"
>
<path d="M3 3l7.07 16.97 2.51-7.39 7.39-2.51L3 3z"></path>
<path d="M3 3l7.07 16.97 2.51-7.39 7.39-2.51L3 3z" />
</svg>
</div>
</div>
</div>
</div>
<div class="label">Output (Graphics)</div>
<div class="sub-label">像素图形渲染</div>
<div class="label">
Output (Graphics)
</div>
<div class="sub-label">
像素图形渲染
</div>
</div>
</div>
@@ -164,7 +217,10 @@
</div>
<div class="control-bar">
<button @click="startGuiSimulation" :disabled="isGuiAnimating">
<button
:disabled="isGuiAnimating"
@click="startGuiSimulation"
>
<span v-if="!isGuiAnimating"> Play Interaction / 演示交互</span>
<span v-else>Simulating... / 演示中...</span>
</button>
@@ -14,11 +14,15 @@
<template>
<div class="grid-demo">
<div class="terminal-screen">
<div class="grid-row" v-for="(row, rIndex) in rows" :key="rIndex">
<div
v-for="(row, rIndex) in rows"
:key="rIndex"
class="grid-row"
>
<div
class="grid-cell"
v-for="(cell, cIndex) in row"
:key="cIndex"
class="grid-cell"
:class="{
'active-cursor': cursor.r === rIndex && cursor.c === cIndex,
drawn: cell.drawn
@@ -34,13 +38,18 @@
<div class="controls">
<input
ref="inputRef"
type="text"
v-model="inputText"
type="text"
placeholder="Type here..."
class="text-input"
@keydown="handleKeydown"
/>
<button class="btn" @click="clearGrid">Clear</button>
>
<button
class="btn"
@click="clearGrid"
>
Clear
</button>
<span class="hint">Click/Drag cells to draw, Type to insert text</span>
</div>
</div>
@@ -4,29 +4,43 @@
<!-- Left Panel: Task Guide -->
<div class="task-panel">
<div class="panel-header">
<span class="panel-title"
>🎯 实操任务 ({{ currentTaskIndex + 1 }}/{{ tasks.length }})</span
>
<span class="panel-title">🎯 实操任务 ({{ currentTaskIndex + 1 }}/{{ tasks.length }})</span>
<div class="os-selector">
<select v-model="currentOS" @change="resetCurrentTask">
<option value="mac">macOS</option>
<option value="win-ps">Windows PowerShell</option>
<option value="win-cmd">Windows CMD</option>
<option value="linux">Linux</option>
<select
v-model="currentOS"
@change="resetCurrentTask"
>
<option value="mac">
macOS
</option>
<option value="win-ps">
Windows PowerShell
</option>
<option value="win-cmd">
Windows CMD
</option>
<option value="linux">
Linux
</option>
</select>
</div>
</div>
<div class="task-content">
<h3>{{ currentTask.title }}</h3>
<p class="task-desc">{{ currentTask.description }}</p>
<p class="task-desc">
{{ currentTask.description }}
</p>
<div class="ai-helper">
<div class="ai-header">
<span class="ai-icon">🤖</span>
<span class="ai-title">不知道怎么写问问 AI</span>
</div>
<div class="ai-chat" v-show="isAiOpen">
<div
v-show="isAiOpen"
class="ai-chat"
>
<div class="chat-bubble user">
{{ currentTask.aiQuery }}
</div>
@@ -34,7 +48,7 @@
<p>
{{
currentTask.aiResponse[currentOS] ||
currentTask.aiResponse.common
currentTask.aiResponse.common
}}
</p>
<!-- Multiple Commands Support -->
@@ -68,61 +82,90 @@
</div>
</div>
<div class="expected-result" v-if="!isTaskCompleted">
<div
v-if="!isTaskCompleted"
class="expected-result"
>
<span class="label">预期目标</span>
<span class="value">{{ currentTask.goal }}</span>
</div>
<div class="success-message" v-if="isTaskCompleted">
<div
v-if="isTaskCompleted"
class="success-message"
>
<span class="icon">🎉</span>
<span>太棒了任务完成</span>
<button
v-if="currentTaskIndex < tasks.length - 1"
class="next-btn"
@click="nextTask"
v-if="currentTaskIndex < tasks.length - 1"
>
下一关
</button>
<button class="reset-btn" @click="resetAll" v-else>重新开始</button>
<button
v-else
class="reset-btn"
@click="resetAll"
>
重新开始
</button>
</div>
</div>
</div>
<!-- Right Panel: Terminal Emulator -->
<div class="terminal-panel" :class="currentOS">
<div
class="terminal-panel"
:class="currentOS"
>
<div class="terminal-header">
<div class="dots">
<span class="dot red"></span>
<span class="dot yellow"></span>
<span class="dot green"></span>
<span class="dot red" />
<span class="dot yellow" />
<span class="dot green" />
</div>
<div class="title">
{{ terminalTitle }}
</div>
<div class="title">{{ terminalTitle }}</div>
</div>
<div class="terminal-body" ref="terminalBody" @click="focusInput">
<div v-for="(line, index) in history" :key="index" class="line">
<span v-if="line.type === 'input'" class="prompt">{{
<div
ref="terminalBody"
class="terminal-body"
@click="focusInput"
>
<div
v-for="(line, index) in history"
:key="index"
class="line"
>
<span
v-if="line.type === 'input'"
class="prompt"
>{{
line.prompt
}}</span>
<span :class="line.type">{{ line.content }}</span>
</div>
<div
class="line input-line"
v-if="!isTaskCompleted || currentTaskIndex < tasks.length - 1"
class="line input-line"
>
<span class="prompt">{{ prompt }}</span>
<input
ref="cmdInput"
v-model="inputCmd"
@keydown.enter="executeCommand"
@keydown.tab.prevent
type="text"
spellcheck="false"
autocomplete="off"
/>
<span v-if="inputCmd.length > 0" class="enter-hint"
> 按回车执行</span
@keydown.enter="executeCommand"
@keydown.tab.prevent
>
<span
v-if="inputCmd.length > 0"
class="enter-hint"
> 按回车执行</span>
</div>
</div>
</div>
@@ -12,34 +12,43 @@
</button>
</div>
<div class="terminal-window" :class="currentOS">
<div
class="terminal-window"
:class="currentOS"
>
<div class="window-bar">
<div class="window-buttons">
<span class="btn close"></span>
<span class="btn minimize"></span>
<span class="btn maximize"></span>
<span class="btn close" />
<span class="btn minimize" />
<span class="btn maximize" />
</div>
<div class="window-title">
{{ currentOSConfig.title }}
</div>
<div class="window-title">{{ currentOSConfig.title }}</div>
<div class="window-controls">
<button class="control-btn" @click="resetDemo" title="Reset">
<button
class="control-btn"
title="Reset"
@click="resetDemo"
>
</button>
</div>
</div>
<div
class="terminal-content"
@click="nextStep"
:class="{ clickable: !isTyping && !isFinished }"
@click="nextStep"
>
<!-- Start Overlay -->
<div
class="start-overlay"
v-if="
lines.length === 0 ||
(lines.length === 1 &&
lines[0].content === '' &&
currentStepIndex === -1)
(lines.length === 1 &&
lines[0].content === '' &&
currentStepIndex === -1)
"
class="start-overlay"
>
<div class="start-hint">
<span class="icon">👆</span>
@@ -48,17 +57,26 @@
</div>
<!-- Completed Overlay -->
<div class="completed-overlay" v-if="isFinished">
<div class="completed-hint" @click.stop="resetDemo">
<div
v-if="isFinished"
class="completed-overlay"
>
<div
class="completed-hint"
@click.stop="resetDemo"
>
<span class="icon">✅</span>
<span class="text">演示结束,点击重置 / Finished (Reset)</span>
</div>
</div>
<div v-for="(line, index) in lines" :key="index" class="line">
<div
v-for="(line, index) in lines"
:key="index"
class="line"
>
<template v-if="line.type === 'input'">
<span class="prompt">{{ line.prompt }}</span
><span class="cmd-text">{{ line.content }}</span>
<span class="prompt">{{ line.prompt }}</span><span class="cmd-text">{{ line.content }}</span>
</template>
<template v-else>
<span class="output-text">{{ line.content }}</span>
@@ -67,25 +85,33 @@
<!-- Active Input Line (when not animating or just waiting) -->
<div
class="line input-line"
v-if="
lines.length === 0 ||
(!isTyping &&
lines[lines.length - 1].type !== 'input' &&
!isFinished)
(!isTyping &&
lines[lines.length - 1].type !== 'input' &&
!isFinished)
"
class="line input-line"
>
<span class="prompt">{{ currentOSConfig.prompt }}</span>
<span class="cursor">_</span>
<span v-if="lines.length === 0" class="hint">
(点击屏幕继续 / Click screen to continue)</span
<span
v-if="lines.length === 0"
class="hint"
>
<span v-else class="hint blink-hint"> ⏎ </span>
(点击屏幕继续 / Click screen to continue)</span>
<span
v-else
class="hint blink-hint"
> ⏎ </span>
</div>
</div>
<!-- Explanation Bar -->
<div class="explanation-bar" :class="{ visible: currentExplanation }">
<div
class="explanation-bar"
:class="{ visible: currentExplanation }"
>
<span class="icon">💡</span>
<span class="text">{{ currentExplanation }}</span>
</div>
@@ -16,19 +16,28 @@
<div class="terminal-container">
<div class="terminal-header">
<div class="terminal-buttons">
<span class="btn red"></span>
<span class="btn yellow"></span>
<span class="btn green"></span>
<span class="btn red" />
<span class="btn yellow" />
<span class="btn green" />
</div>
<div class="terminal-title">
Terminal - zsh
</div>
<div class="terminal-title">Terminal - zsh</div>
</div>
<div class="terminal-body" ref="terminalBody" @click="focusInput">
<div
ref="terminalBody"
class="terminal-body"
@click="focusInput"
>
<div
v-for="(line, index) in history"
:key="index"
class="terminal-line"
>
<span class="prompt" v-if="line.type === 'input'">
<span
v-if="line.type === 'input'"
class="prompt"
>
<span class="path">{{ currentPath }}</span>
<span class="arrow">$ </span>
</span>
@@ -40,16 +49,16 @@
<span class="arrow">$ </span>
</span>
<input
type="text"
ref="inputField"
v-model="currentInput"
type="text"
autocomplete="off"
spellcheck="false"
@keyup.enter="executeCommand"
@keydown.up.prevent="navigateHistory(-1)"
@keydown.down.prevent="navigateHistory(1)"
@keydown.tab.prevent="handleTabCompletion"
ref="inputField"
autocomplete="off"
spellcheck="false"
/>
>
</div>
</div>
</div>
@@ -63,22 +72,31 @@
</div>
<div class="sheet-content">
<div
class="cmd-group"
v-for="(group, gIndex) in cheatSheet"
:key="gIndex"
class="cmd-group"
>
<div class="group-title">{{ group.category }}</div>
<div class="group-title">
{{ group.category }}
</div>
<div
class="cmd-item"
v-for="(cmd, cIndex) in group.commands"
:key="cIndex"
class="cmd-item"
>
<div class="cmd-name" @click="fillCommand(cmd.name)">
<div
class="cmd-name"
@click="fillCommand(cmd.name)"
>
{{ cmd.name }}
</div>
<div class="cmd-desc">
<div class="en">{{ cmd.descEn }}</div>
<div class="zh">{{ cmd.descZh }}</div>
<div class="en">
{{ cmd.descEn }}
</div>
<div class="zh">
{{ cmd.descZh }}
</div>
</div>
</div>
</div>