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:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user