feat(ai-protocols): add MCP and A2A protocol demos and documentation
docs(ai-protocols): update AI protocols page with visual demos and detailed explanations style(git-demos): improve responsive design and layout for git visualization components refactor(ai-history): simplify and clean up demo components chore: update config to register new AI protocol components
This commit is contained in:
@@ -2,69 +2,75 @@
|
||||
<div class="adder-demo">
|
||||
<div class="demo-header">
|
||||
<span class="title">加法器:用逻辑门做二进制加法</span>
|
||||
<span class="subtitle">点击蓝色位按钮切换 0/1,观察进位如何逐位传递</span>
|
||||
<span class="subtitle">就像手算竖式:从个位往高位算,逢二进一,进位往左传</span>
|
||||
</div>
|
||||
|
||||
<!-- 名词解释 -->
|
||||
<div class="legend">
|
||||
<span class="legend-item"><span class="dot a" />A = 被加数</span>
|
||||
<span class="legend-item"><span class="dot b" />B = 加数</span>
|
||||
<span class="legend-item"><span class="dot s" />S = 和(Sum,本位结果)</span>
|
||||
<span class="legend-item"><span class="dot c" />C = 进位(Carry,传给下一位)</span>
|
||||
</div>
|
||||
|
||||
<!-- 输入控制 -->
|
||||
<div class="control-panel">
|
||||
<div class="input-group">
|
||||
<span class="group-label">A(被加数)</span>
|
||||
<div class="bits">
|
||||
<button
|
||||
v-for="(bit, i) in bitsA"
|
||||
:key="'a' + i"
|
||||
class="bit-btn"
|
||||
:class="{ on: bit }"
|
||||
@click="toggleBit('A', i)"
|
||||
>
|
||||
{{ bit }}
|
||||
</button>
|
||||
</div>
|
||||
<span class="decimal">= {{ decimalA }}</span>
|
||||
<label>
|
||||
<span class="control-label">A(被加数)</span>
|
||||
<input v-model.number="inputA" type="number" min="0" max="15" class="num-input" />
|
||||
</label>
|
||||
<span class="op">+</span>
|
||||
<label>
|
||||
<span class="control-label">B(加数)</span>
|
||||
<input v-model.number="inputB" type="number" min="0" max="15" class="num-input" />
|
||||
</label>
|
||||
<span class="eq">=</span>
|
||||
<span class="result-dec">{{ resultDec }}</span>
|
||||
</div>
|
||||
|
||||
<div class="why-what-box">
|
||||
<p class="why-p">
|
||||
<strong>为啥要看这些?</strong>CPU 只会处理 0 和 1,所以加法要「一位一位」算;每一列(第 0 位、第 1 位…)都需要一个小电路来算「这一位写几、要不要往左进位」。
|
||||
</p>
|
||||
<p class="what-p">
|
||||
<strong>这些词是啥?</strong>
|
||||
<span class="term">半加器</span>:只算这一位的 A+B(最右边没有进位进来)。
|
||||
<span class="term">全加器</span>:算 A+B+上一位的进位。
|
||||
<span class="term">S</span>:这一位写下的数字(0 或 1)。
|
||||
<span class="term">Cout</span>:要不要往左边一位进 1(进就是 1,不进就是 0)。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="example-block">
|
||||
<div class="example-row">
|
||||
<span class="example-label">A(被加数)</span>
|
||||
<span class="example-bits">
|
||||
<span v-for="(b, i) in bitsA" :key="'a'+i" class="bit" :class="{ active: highlightedBit === (3 - i) }">{{ b }}</span>
|
||||
</span>
|
||||
<span class="example-dec">= {{ inputA }}</span>
|
||||
</div>
|
||||
<div class="op-sign">+</div>
|
||||
<div class="input-group">
|
||||
<span class="group-label">B(加数)</span>
|
||||
<div class="bits">
|
||||
<button
|
||||
v-for="(bit, i) in bitsB"
|
||||
:key="'b' + i"
|
||||
class="bit-btn"
|
||||
:class="{ on: bit }"
|
||||
@click="toggleBit('B', i)"
|
||||
>
|
||||
{{ bit }}
|
||||
</button>
|
||||
</div>
|
||||
<span class="decimal">= {{ decimalB }}</span>
|
||||
<div class="example-row">
|
||||
<span class="example-label">B(加数)</span>
|
||||
<span class="example-bits">
|
||||
<span v-for="(b, i) in bitsB" :key="'b'+i" class="bit" :class="{ active: highlightedBit === (3 - i) }">{{ b }}</span>
|
||||
</span>
|
||||
<span class="example-dec">= {{ inputB }}</span>
|
||||
</div>
|
||||
<div class="op-sign">=</div>
|
||||
<div class="result-inline">
|
||||
<span class="result-bin">{{ resultBinary }}</span>
|
||||
<span class="result-dec">(十进制 {{ resultDecimal }})</span>
|
||||
<div class="example-row result-row">
|
||||
<span class="example-label">结果</span>
|
||||
<span class="example-bits">
|
||||
<span v-for="(b, i) in bitsSum" :key="'s'+i" class="bit" :class="{ active: highlightedBit === (3 - i) }">{{ b }}</span>
|
||||
</span>
|
||||
<span class="example-dec">= {{ resultDec }}</span>
|
||||
</div>
|
||||
<div class="bit-legend">
|
||||
<span v-for="i in 4" :key="i" class="bit-legend-item">第{{ 4 - i }}位</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 每位加法器展示 -->
|
||||
<div class="stages-label">逐位计算过程(从最低位开始)</div>
|
||||
<div class="stages-label">逐位计算(从右往左:第 0 位 → 第 3 位,对应上面每一列)</div>
|
||||
<div class="adder-stages">
|
||||
<div
|
||||
v-for="(stage, idx) in stageData"
|
||||
v-for="(stage, idx) in stages"
|
||||
:key="idx"
|
||||
class="stage"
|
||||
:class="{ 'stage-highlight': highlightedBit === stage.bitPos }"
|
||||
@mouseenter="highlightedBit = stage.bitPos"
|
||||
@mouseleave="highlightedBit = null"
|
||||
>
|
||||
<div class="stage-title">第 {{ stage.bitPos }} 位({{ stage.posName }})</div>
|
||||
|
||||
<div class="stage-content">
|
||||
<!-- 输入列 -->
|
||||
<div class="io-col inputs-col">
|
||||
<div class="io-row">
|
||||
<span class="io-badge a-badge">A</span>
|
||||
@@ -74,55 +80,34 @@
|
||||
<span class="io-badge b-badge">B</span>
|
||||
<span class="io-val">{{ stage.b }}</span>
|
||||
</div>
|
||||
<div v-if="stage.carryIn !== null" class="io-row carry-in-row">
|
||||
<div v-if="stage.carryIn !== null" class="io-row">
|
||||
<span class="io-badge cin-badge">Cin</span>
|
||||
<span class="io-val">{{ stage.carryIn }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 全加器框 -->
|
||||
<div class="fa-box">
|
||||
<div class="fa-label">{{ stage.carryIn !== null ? '全加器' : '半加器' }}</div>
|
||||
<div class="fa-hint">{{ stage.carryIn !== null ? 'Full Adder' : 'Half Adder' }}</div>
|
||||
<div class="fa-hint">{{ stage.carryIn !== null ? 'A+B+进位' : '只算 A+B' }}</div>
|
||||
</div>
|
||||
|
||||
<!-- 输出列 -->
|
||||
<div class="io-col outputs-col">
|
||||
<div class="io-row">
|
||||
<span class="io-badge s-badge">S</span>
|
||||
<span class="io-badge s-badge" :title="'S = 这一位写下的数'">S</span>
|
||||
<span class="io-val sum-val">{{ stage.sum }}</span>
|
||||
</div>
|
||||
<div class="io-row">
|
||||
<span class="io-badge cout-badge">Cout</span>
|
||||
<span class="io-badge cout-badge" :title="'Cout = 往左进 0 还是 1'">Cout</span>
|
||||
<span class="io-val carry-val">{{ stage.carryOut }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 进位传递提示 -->
|
||||
<div v-if="idx < stageData.length - 1 && stage.carryOut" class="carry-hint">
|
||||
进位 {{ stage.carryOut }} 传给第 {{ stage.bitPos + 1 }} 位 →
|
||||
<div v-if="idx < stages.length - 1" class="carry-hint" :class="{ 'no-carry': !stage.carryOut }">
|
||||
{{ stage.carryOut ? `进位 ${stage.carryOut} 传给第 ${stage.bitPos + 1} 位 →` : '无进位' }}
|
||||
</div>
|
||||
<div v-else-if="idx < stageData.length - 1" class="carry-hint no-carry">
|
||||
无进位
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 结果 -->
|
||||
<div class="result-bar">
|
||||
<div class="result-row">
|
||||
<span class="result-label">二进制结果</span>
|
||||
<span class="result-bits">{{ resultBinary }}</span>
|
||||
</div>
|
||||
<div class="result-row">
|
||||
<span class="result-label">十进制验证</span>
|
||||
<span class="result-eq">{{ decimalA }} + {{ decimalB }} = {{ resultDecimal }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<strong>核心思想:</strong>每位全加器接收 A、B 和上一位的进位(Cin),输出本位的和(S)与向上传递的进位(Cout)——和我们手算竖式加法"逢二进一"完全一致。
|
||||
<strong>核心思想:</strong>每位全加器接收 A、B 和上一位的进位(Cin),输出本位的和(S)与传给下一位的进位(Cout),和手算竖式「逢二进一」一致。
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -130,57 +115,66 @@
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
|
||||
const bitsA = ref([0, 0, 1, 1])
|
||||
const bitsB = ref([0, 0, 1, 0])
|
||||
const POS_NAMES = ['最低位', '次低位', '次高位', '最高位']
|
||||
|
||||
const toggleBit = (arr, i) => {
|
||||
if (arr === 'A') {
|
||||
bitsA.value[i] = bitsA.value[i] ? 0 : 1
|
||||
} else {
|
||||
bitsB.value[i] = bitsB.value[i] ? 0 : 1
|
||||
}
|
||||
function clamp(n) {
|
||||
const v = Number(n)
|
||||
if (Number.isNaN(v)) return 0
|
||||
return Math.max(0, Math.min(15, Math.floor(v)))
|
||||
}
|
||||
|
||||
const decimalA = computed(() =>
|
||||
bitsA.value.reduce((acc, bit, i) => acc + bit * Math.pow(2, 3 - i), 0)
|
||||
)
|
||||
const inputA = ref(3)
|
||||
const inputB = ref(2)
|
||||
const highlightedBit = ref(null)
|
||||
|
||||
const decimalB = computed(() =>
|
||||
bitsB.value.reduce((acc, bit, i) => acc + bit * Math.pow(2, 3 - i), 0)
|
||||
)
|
||||
const clampedA = computed(() => clamp(inputA.value))
|
||||
const clampedB = computed(() => clamp(inputB.value))
|
||||
|
||||
const stageData = computed(() => {
|
||||
const stages = []
|
||||
let carry = 0
|
||||
const posNames = ['最低位', '次低位', '次高位', '最高位']
|
||||
for (let i = 3; i >= 0; i--) {
|
||||
const a = bitsA.value[i]
|
||||
const b = bitsB.value[i]
|
||||
const total = a + b + carry
|
||||
const sum = total % 2
|
||||
const carryOut = total >= 2 ? 1 : 0
|
||||
stages.push({
|
||||
bitPos: 3 - i,
|
||||
posName: posNames[3 - i],
|
||||
const bitsA = computed(() => (clampedA.value >>> 0).toString(2).padStart(4, '0').split(''))
|
||||
const bitsB = computed(() => (clampedB.value >>> 0).toString(2).padStart(4, '0').split(''))
|
||||
|
||||
const stages = computed(() => {
|
||||
const A = clampedA.value
|
||||
const B = clampedB.value
|
||||
const result = []
|
||||
let carryIn = null
|
||||
for (let i = 0; i < 4; i++) {
|
||||
const a = (A >> i) & 1
|
||||
const b = (B >> i) & 1
|
||||
let sum, carryOut
|
||||
if (carryIn === null) {
|
||||
sum = a ^ b
|
||||
carryOut = a & b
|
||||
} else {
|
||||
sum = (a ^ b) ^ carryIn
|
||||
carryOut = (a & b) | (carryIn & (a ^ b))
|
||||
}
|
||||
result.push({
|
||||
bitPos: i,
|
||||
posName: POS_NAMES[i],
|
||||
a,
|
||||
b,
|
||||
carryIn: stages.length > 0 ? carry : null,
|
||||
carryIn: carryIn === null ? null : carryIn,
|
||||
sum,
|
||||
carryOut
|
||||
})
|
||||
carry = carryOut
|
||||
carryIn = carryOut
|
||||
}
|
||||
return stages
|
||||
return result
|
||||
})
|
||||
|
||||
const sumBits = computed(() => stageData.value.map((s) => s.sum).reverse())
|
||||
|
||||
const resultBinary = computed(() => {
|
||||
const lastCarry = stageData.value[stageData.value.length - 1]?.carryOut || 0
|
||||
return (lastCarry ? lastCarry.toString() : '') + sumBits.value.join('')
|
||||
const bitsSum = computed(() => {
|
||||
const S = stages.value.reduce((acc, s, i) => acc + (s.sum << i), 0)
|
||||
return (S >>> 0).toString(2).padStart(4, '0').split('')
|
||||
})
|
||||
|
||||
const resultDecimal = computed(() => decimalA.value + decimalB.value)
|
||||
const fourBitResult = computed(() =>
|
||||
stages.value.reduce((acc, s, i) => acc + (s.sum << i), 0)
|
||||
)
|
||||
const overflow = computed(() => clampedA.value + clampedB.value > 15)
|
||||
const resultDec = computed(() =>
|
||||
overflow.value ? `${fourBitResult.value}(4 位溢出)` : String(fourBitResult.value)
|
||||
)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -193,147 +187,167 @@ const resultDecimal = computed(() => decimalA.value + decimalB.value)
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.65rem;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 0.35rem;
|
||||
}
|
||||
|
||||
.demo-header .title {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.demo-header .subtitle {
|
||||
color: var(--vp-c-text-2);
|
||||
display: block;
|
||||
font-size: 0.82rem;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
/* 名词解释 */
|
||||
.legend {
|
||||
display: flex;
|
||||
gap: 0.8rem;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 0.7rem;
|
||||
font-size: 0.78rem;
|
||||
color: var(--vp-c-text-2);
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
padding: 0.5rem 0.7rem;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
}
|
||||
|
||||
.dot {
|
||||
display: inline-block;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.dot.a { background: var(--vp-c-brand); }
|
||||
.dot.b { background: #8b5cf6; }
|
||||
.dot.s { background: var(--vp-c-success, #16a34a); }
|
||||
.dot.c { background: #d97706; }
|
||||
|
||||
/* 控制面板 */
|
||||
.control-panel {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
padding: 0.55rem 0.75rem;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
background: var(--vp-c-bg);
|
||||
margin-bottom: 0.75rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.input-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
|
||||
.group-label {
|
||||
font-size: 0.8rem;
|
||||
.control-panel label {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
}
|
||||
|
||||
.control-label {
|
||||
font-size: 0.85rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.num-input {
|
||||
width: 3rem;
|
||||
padding: 0.25rem 0.35rem;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 4px;
|
||||
font-size: 0.9rem;
|
||||
background: var(--vp-c-bg);
|
||||
}
|
||||
|
||||
.control-panel .op,
|
||||
.control-panel .eq {
|
||||
font-weight: bold;
|
||||
color: var(--vp-c-text-2);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.bits {
|
||||
display: flex;
|
||||
gap: 0.2rem;
|
||||
}
|
||||
|
||||
.bit-btn {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-alt);
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 0.85rem;
|
||||
.control-panel .result-dec {
|
||||
font-weight: bold;
|
||||
transition: all 0.2s;
|
||||
color: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
.bit-btn.on {
|
||||
background: var(--vp-c-brand);
|
||||
color: white;
|
||||
border-color: var(--vp-c-brand);
|
||||
.why-what-box {
|
||||
background: var(--vp-c-bg-alt);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
padding: 0.65rem 0.85rem;
|
||||
margin-bottom: 0.75rem;
|
||||
font-size: 0.85rem;
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.decimal {
|
||||
font-size: 0.82rem;
|
||||
.why-what-box .why-p {
|
||||
margin: 0 0 0.4rem;
|
||||
}
|
||||
|
||||
.why-what-box .what-p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.why-what-box .term {
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.example-block {
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.bit-legend {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
margin-left: 6rem;
|
||||
margin-top: 0.2rem;
|
||||
font-size: 0.7rem;
|
||||
color: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
.bit-legend-item {
|
||||
min-width: 1.2em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.example-row .example-bits {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.bit {
|
||||
display: inline-block;
|
||||
min-width: 1.2em;
|
||||
text-align: center;
|
||||
padding: 0.1rem 0;
|
||||
border-radius: 3px;
|
||||
transition: background 0.15s ease;
|
||||
}
|
||||
|
||||
.bit.active {
|
||||
background: var(--vp-c-brand-2);
|
||||
color: var(--vp-c-bg);
|
||||
}
|
||||
|
||||
.stage.stage-highlight {
|
||||
outline: 2px solid var(--vp-c-brand-1);
|
||||
outline-offset: 1px;
|
||||
}
|
||||
|
||||
.example-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.25rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.example-label {
|
||||
color: var(--vp-c-text-2);
|
||||
min-width: 6rem;
|
||||
}
|
||||
|
||||
.example-bits {
|
||||
font-family: monospace;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.example-dec {
|
||||
color: var(--vp-c-text-2);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.op-sign {
|
||||
font-size: 1.1rem;
|
||||
.result-row .example-bits {
|
||||
font-weight: bold;
|
||||
color: var(--vp-c-brand);
|
||||
flex-shrink: 0;
|
||||
color: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
.result-inline {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
}
|
||||
|
||||
.result-bin {
|
||||
font-family: monospace;
|
||||
font-weight: bold;
|
||||
color: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.result-dec {
|
||||
font-size: 0.8rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
/* 阶段 */
|
||||
.stages-label {
|
||||
font-size: 0.82rem;
|
||||
font-size: 0.85rem;
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.4rem;
|
||||
margin: 0.75rem 0 0.4rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.adder-stages {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 0.45rem;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
@@ -344,7 +358,7 @@ const resultDecimal = computed(() => decimalA.value + decimalB.value)
|
||||
padding: 0.55rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.4rem;
|
||||
gap: 0.35rem;
|
||||
}
|
||||
|
||||
.stage-title {
|
||||
@@ -401,16 +415,11 @@ const resultDecimal = computed(() => decimalA.value + decimalB.value)
|
||||
.sum-val { color: var(--vp-c-success, #16a34a); }
|
||||
.carry-val { color: #d97706; }
|
||||
|
||||
/* 全加器盒子 */
|
||||
.fa-box {
|
||||
background: var(--vp-c-bg-alt);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
padding: 0.3rem 0.35rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.1rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@@ -422,9 +431,9 @@ const resultDecimal = computed(() => decimalA.value + decimalB.value)
|
||||
.fa-hint {
|
||||
font-size: 0.6rem;
|
||||
color: var(--vp-c-text-3);
|
||||
margin-top: 0.1rem;
|
||||
}
|
||||
|
||||
/* 进位提示 */
|
||||
.carry-hint {
|
||||
font-size: 0.65rem;
|
||||
color: #d97706;
|
||||
@@ -436,48 +445,14 @@ const resultDecimal = computed(() => decimalA.value + decimalB.value)
|
||||
color: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
/* 结果栏 */
|
||||
.result-bar {
|
||||
background: var(--vp-c-bg-alt);
|
||||
border-radius: 6px;
|
||||
padding: 0.55rem 0.75rem;
|
||||
display: flex;
|
||||
gap: 1.5rem;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.result-row {
|
||||
display: flex;
|
||||
gap: 0.4rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.result-label {
|
||||
font-size: 0.82rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.result-bits {
|
||||
font-family: monospace;
|
||||
font-weight: bold;
|
||||
color: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.result-eq {
|
||||
font-weight: bold;
|
||||
color: var(--vp-c-success, #16a34a);
|
||||
}
|
||||
|
||||
/* info box */
|
||||
.info-box {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
background: var(--vp-c-bg-alt);
|
||||
padding: 0.75rem;
|
||||
border-radius: 6px;
|
||||
font-size: 0.85rem;
|
||||
color: var(--vp-c-text-2);
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.info-box strong {
|
||||
|
||||
+44
-244
@@ -2,48 +2,13 @@
|
||||
<div class="logic-gate-demo">
|
||||
<div class="demo-header">
|
||||
<span class="title">逻辑门:用开关做运算</span>
|
||||
<span class="subtitle">切换输入 A / B,同屏观察四种门的输出</span>
|
||||
</div>
|
||||
|
||||
<div class="control-panel">
|
||||
<span class="panel-hint">点按钮切换 0 / 1,右侧四个门同步更新:</span>
|
||||
<div class="input-item">
|
||||
<span class="input-label">输入 A</span>
|
||||
<button class="input-btn" :class="{ on: inputA }" @click="inputA = !inputA">
|
||||
{{ inputA ? '1' : '0' }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="input-item">
|
||||
<span class="input-label">输入 B</span>
|
||||
<button class="input-btn" :class="{ on: inputB }" @click="inputB = !inputB">
|
||||
{{ inputB ? '1' : '0' }}
|
||||
</button>
|
||||
</div>
|
||||
<span class="current-state">当前:A={{ inputA ? 1 : 0 }},B={{ inputB ? 1 : 0 }}</span>
|
||||
</div>
|
||||
|
||||
<div class="gate-grid">
|
||||
<div v-for="gate in gates" :key="gate.name" class="gate-card">
|
||||
<div class="gate-top">
|
||||
<span class="gate-name">{{ gate.name }}</span>
|
||||
<span class="gate-formula">{{ gate.formula }}</span>
|
||||
</div>
|
||||
<div class="gate-analogy">{{ gate.analogy }}</div>
|
||||
<div class="gate-output-row">
|
||||
<span class="output-label">输出</span>
|
||||
<span
|
||||
class="output-value"
|
||||
:class="{ on: gateOutput(gate.name, inputA, inputB) }"
|
||||
>
|
||||
{{ gateOutput(gate.name, inputA, inputB) }}
|
||||
</span>
|
||||
<span class="output-hint">{{ gateOutput(gate.name, inputA, inputB) ? '(真 / 导通)' : '(假 / 断开)' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="intro">
|
||||
输入 A、B 只能是 0 或 1;四种门按不同规则输出一个 0 或 1。下面表格列出所有 4 种输入组合的结果。
|
||||
</p>
|
||||
|
||||
<div class="truth-section">
|
||||
<div class="table-title">四种门真值表对照(高亮行 = 当前输入)</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -56,65 +21,37 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="row in truthRows"
|
||||
:key="`${row.a}-${row.b}`"
|
||||
:class="{
|
||||
highlight:
|
||||
row.a === (inputA ? 1 : 0) && row.b === (inputB ? 1 : 0)
|
||||
}"
|
||||
>
|
||||
<tr v-for="row in truthRows" :key="`${row.a}-${row.b}`">
|
||||
<td>{{ row.a }}</td>
|
||||
<td>{{ row.b }}</td>
|
||||
<td>{{ gateOutput('AND', !!row.a, !!row.b) }}</td>
|
||||
<td>{{ gateOutput('OR', !!row.a, !!row.b) }}</td>
|
||||
<td>{{ gateOutput('NOT', !!row.a, !!row.b) }}</td>
|
||||
<td>{{ gateOutput('XOR', !!row.a, !!row.b) }}</td>
|
||||
<td>{{ row.and }}</td>
|
||||
<td>{{ row.or }}</td>
|
||||
<td>{{ row.not }}</td>
|
||||
<td>{{ row.xor }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<ul class="col-meaning">
|
||||
<li><strong>AND</strong>:两个都是 1 才输出 1(像串联:都通才通)</li>
|
||||
<li><strong>OR</strong>:有一个 1 就输出 1(像并联:一通就通)</li>
|
||||
<li><strong>NOT(A)</strong>:对 A 取反,0→1、1→0</li>
|
||||
<li><strong>XOR</strong>:两个不同输出 1,相同输出 0</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<strong>核心思想:</strong>逻辑门用晶体管的"开关"组合实现基本运算——AND 像串联、OR 像并联、NOT 取反、XOR 判异。所有复杂计算都由这四种基础操作构建而来。
|
||||
<strong>核心思想:</strong>逻辑门用晶体管的“开关”组合实现这四种运算,复杂计算都由它们组合而成。
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const inputA = ref(false)
|
||||
const inputB = ref(false)
|
||||
|
||||
const gates = [
|
||||
{ name: 'AND', formula: 'A && B', analogy: '串联:都为 1 才输出 1' },
|
||||
{ name: 'OR', formula: 'A || B', analogy: '并联:任一为 1 就输出 1' },
|
||||
{ name: 'NOT', formula: '!A', analogy: '取反:0→1,1→0' },
|
||||
{ name: 'XOR', formula: 'A ⊕ B', analogy: '判异:不同为 1,相同为 0' }
|
||||
]
|
||||
|
||||
const truthRows = [
|
||||
{ a: 0, b: 0 },
|
||||
{ a: 0, b: 1 },
|
||||
{ a: 1, b: 0 },
|
||||
{ a: 1, b: 1 }
|
||||
{ a: 0, b: 0, and: 0, or: 0, not: 1, xor: 0 },
|
||||
{ a: 0, b: 1, and: 0, or: 1, not: 1, xor: 1 },
|
||||
{ a: 1, b: 0, and: 0, or: 1, not: 0, xor: 1 },
|
||||
{ a: 1, b: 1, and: 1, or: 1, not: 0, xor: 0 }
|
||||
]
|
||||
|
||||
const gateOutput = (name, a, b) => {
|
||||
switch (name) {
|
||||
case 'AND':
|
||||
return a && b ? 1 : 0
|
||||
case 'OR':
|
||||
return a || b ? 1 : 0
|
||||
case 'NOT':
|
||||
return a ? 0 : 1
|
||||
case 'XOR':
|
||||
return a !== b ? 1 : 0
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -127,11 +64,7 @@ const gateOutput = (name, a, b) => {
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.demo-header .title {
|
||||
@@ -139,169 +72,29 @@ const gateOutput = (name, a, b) => {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.demo-header .subtitle {
|
||||
.intro {
|
||||
font-size: 0.9rem;
|
||||
color: var(--vp-c-text-2);
|
||||
font-size: 0.82rem;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.control-panel {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
margin-bottom: 0.75rem;
|
||||
flex-wrap: wrap;
|
||||
padding: 0.5rem 0.65rem;
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.panel-hint {
|
||||
font-size: 0.8rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.current-state {
|
||||
font-size: 0.8rem;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-left: auto;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.input-item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
background: var(--vp-c-bg-alt);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 999px;
|
||||
padding: 0.2rem 0.5rem;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.input-label {
|
||||
font-size: 0.82rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.input-btn {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-alt);
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.input-btn.on {
|
||||
background: var(--vp-c-brand);
|
||||
color: white;
|
||||
border-color: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.gate-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.gate-card {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 0.55rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.35rem;
|
||||
}
|
||||
|
||||
.gate-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.gate-name {
|
||||
font-weight: bold;
|
||||
font-size: 0.85rem;
|
||||
color: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
.gate-formula {
|
||||
font-family: monospace;
|
||||
font-size: 0.72rem;
|
||||
color: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
.gate-analogy {
|
||||
font-size: 0.72rem;
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.gate-output-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
margin-top: 0.1rem;
|
||||
}
|
||||
|
||||
.output-label {
|
||||
font-size: 0.7rem;
|
||||
color: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
.output-hint {
|
||||
font-size: 0.68rem;
|
||||
color: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
.output-value {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 4px;
|
||||
background: var(--vp-c-bg-alt);
|
||||
font-weight: bold;
|
||||
font-size: 0.85rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.output-value.on {
|
||||
background: var(--vp-c-success);
|
||||
color: white;
|
||||
border-color: var(--vp-c-success);
|
||||
margin: 0 0 0.75rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.truth-section {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.table-title {
|
||||
font-weight: bold;
|
||||
font-size: 0.82rem;
|
||||
margin-bottom: 0.4rem;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
table-layout: fixed;
|
||||
font-size: 0.8rem;
|
||||
font-size: 0.88rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
padding: 0;
|
||||
height: 2rem;
|
||||
padding: 0.4rem 0.5rem;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
font-variant-numeric: tabular-nums;
|
||||
@@ -312,29 +105,36 @@ th {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
tr.highlight {
|
||||
background: var(--vp-c-brand-soft);
|
||||
.col-meaning {
|
||||
margin: 0;
|
||||
padding-left: 1.25rem;
|
||||
font-size: 0.85rem;
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.col-meaning li {
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.col-meaning strong {
|
||||
color: var(--vp-c-text-1);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.info-box {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
background: var(--vp-c-bg-alt);
|
||||
padding: 0.75rem;
|
||||
border-radius: 6px;
|
||||
font-size: 0.85rem;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-top: 0.75rem;
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.info-box strong {
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.gate-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
+119
-296
@@ -1,13 +1,26 @@
|
||||
<template>
|
||||
<div class="register-demo">
|
||||
<div class="demo-header">
|
||||
<span class="title">寄存器:存储状态的功能单元</span>
|
||||
<span class="subtitle">改变输入不会改变存储值——必须主动"写入"</span>
|
||||
<span class="title">寄存器:能「记住」一个 0 或 1 的小单元</span>
|
||||
<span class="subtitle">只有点「写入」时才会把当前输入记下来,平时改输入不会影响已存的值</span>
|
||||
</div>
|
||||
|
||||
<div class="why-what-box">
|
||||
<p class="why-p">
|
||||
<strong>为啥要看这个?</strong>CPU 算到一半要暂时「记住」中间结果,寄存器就是干这个的。它和「直接连线」不同:改输入不会立刻改变里面存的东西,必须主动点一次「写入」才会更新。
|
||||
</p>
|
||||
<p class="what-p">
|
||||
<strong>这些词是啥?</strong>
|
||||
<span class="term">输入</span>:你想写进去的 0 或 1。
|
||||
<span class="term">写入</span>:点一下,把当前输入「锁进」寄存器。
|
||||
<span class="term">存储值</span>:寄存器里现在记着的数(只有写入时才会变)。
|
||||
<span class="term">输出</span>:从寄存器读出来的数,和存储值一样。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="control-panel">
|
||||
<div class="control-left">
|
||||
<span class="ctrl-label">输入值</span>
|
||||
<label class="ctrl-group">
|
||||
<span class="ctrl-label">输入</span>
|
||||
<button
|
||||
class="input-toggle"
|
||||
:class="{ on: inputData === 1 }"
|
||||
@@ -15,87 +28,33 @@
|
||||
>
|
||||
{{ inputData }}
|
||||
</button>
|
||||
</div>
|
||||
</label>
|
||||
<button class="write-btn" :class="{ flash: isWriting }" @click="writeOnce">
|
||||
写入寄存器 →
|
||||
写入
|
||||
</button>
|
||||
<div class="control-right">
|
||||
<span class="chip">存储值:{{ storedData }}</span>
|
||||
<span class="chip" :class="{ chip_on: storedData === 1 }">输出:{{ storedData === 1 ? '1 ✓' : '0' }}</span>
|
||||
</div>
|
||||
<label class="ctrl-group">
|
||||
<span class="ctrl-label">存储</span>
|
||||
<span class="stored-val" :class="{ on: storedData === 1 }">{{ storedData }}</span>
|
||||
</label>
|
||||
<span class="ctrl-group">
|
||||
<span class="ctrl-label">输出</span>
|
||||
<span class="output-val" :class="{ on: storedData === 1 }">{{ storedData }}</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="demo-content">
|
||||
<div class="flow-diagram">
|
||||
<div class="flow-node input-node">
|
||||
<div class="node-label">输入(Data)</div>
|
||||
<div class="node-value" :class="{ on: inputData === 1 }">{{ inputData }}</div>
|
||||
<div class="node-hint">点左侧按钮切换</div>
|
||||
</div>
|
||||
|
||||
<div class="flow-arrow" :class="{ active: isWriting }">
|
||||
<div class="arrow-line" />
|
||||
<div class="arrow-tag">{{ isWriting ? '写入中...' : '写入触发' }}</div>
|
||||
<div class="arrow-head">→</div>
|
||||
</div>
|
||||
|
||||
<div class="flow-node register-node" :class="{ flashing: isWriting }">
|
||||
<div class="node-label">D 触发器(寄存器核心)</div>
|
||||
<div class="node-value" :class="{ on: storedData === 1 }">{{ storedData }}</div>
|
||||
<div class="node-hint">{{ isWriting ? '正在锁存...' : '保持 (Hold)' }}</div>
|
||||
</div>
|
||||
|
||||
<div class="flow-arrow" :class="{ active: storedData === 1 }">
|
||||
<div class="arrow-line" />
|
||||
<div class="arrow-tag">输出</div>
|
||||
<div class="arrow-head">→</div>
|
||||
</div>
|
||||
|
||||
<div class="flow-node output-node" :class="{ on: storedData === 1 }">
|
||||
<div class="node-label">输出(Output)</div>
|
||||
<div class="bulb">{{ storedData === 1 ? '💡' : '🌑' }}</div>
|
||||
<div class="node-hint">{{ storedData === 1 ? '亮(1)' : '灭(0)' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="state-table">
|
||||
<div class="table-title">操作步骤说明</div>
|
||||
<div class="state-rows">
|
||||
<div class="state-row">
|
||||
<span class="step-num">①</span>
|
||||
<span>点"输入值"按钮切换输入(0/1)</span>
|
||||
</div>
|
||||
<div class="state-row">
|
||||
<span class="step-num">②</span>
|
||||
<span>此时存储值<strong>不变</strong>——这就是寄存器的意义</span>
|
||||
</div>
|
||||
<div class="state-row">
|
||||
<span class="step-num">③</span>
|
||||
<span>点"写入寄存器",输入值才被锁入</span>
|
||||
</div>
|
||||
<div class="state-row">
|
||||
<span class="step-num">④</span>
|
||||
<span>写入后再改输入,存储值依然<strong>保持</strong>不变</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="diff-display">
|
||||
<div class="diff-item">
|
||||
<div class="diff-label">当前输入</div>
|
||||
<div class="diff-value" :class="{ on: inputData === 1 }">{{ inputData }}</div>
|
||||
</div>
|
||||
<div class="diff-sep">≠</div>
|
||||
<div class="diff-item">
|
||||
<div class="diff-label">存储值</div>
|
||||
<div class="diff-value" :class="{ on: storedData === 1 }">{{ storedData }}</div>
|
||||
</div>
|
||||
<div v-if="inputData === storedData" class="diff-same">(当前相同)</div>
|
||||
</div>
|
||||
<div class="visualization-area">
|
||||
<div class="flow-strip">
|
||||
<span class="flow-item">输入 {{ inputData }}</span>
|
||||
<span class="flow-arrow" :class="{ active: isWriting }">{{ isWriting ? '写入中 →' : '— 点「写入」才更新 →' }}</span>
|
||||
<span class="flow-item flow-store" :class="{ flash: isWriting }">存 {{ storedData }}</span>
|
||||
</div>
|
||||
<p class="flow-hint">
|
||||
{{ inputData !== storedData ? '输入和存储不一样:点「写入」会把当前输入记进去。' : '输入和存储已一致。' }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<strong>核心思想:</strong>寄存器只在"写入"信号触发时更新,其余时刻持续锁定当前值。这就是 CPU 能在计算过程中稳定保存中间结果的原因。
|
||||
<strong>核心思想:</strong>寄存器只在「写入」那一刻更新,其余时间一直保持原来的值,所以 CPU 能稳定保存中间结果。
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -126,41 +85,62 @@ const writeOnce = () => {
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.8rem;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.demo-header .title {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.demo-header .subtitle {
|
||||
color: var(--vp-c-text-2);
|
||||
display: block;
|
||||
font-size: 0.82rem;
|
||||
margin-left: 0.5rem;
|
||||
color: var(--vp-c-text-2);
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.why-what-box {
|
||||
background: var(--vp-c-bg-alt);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
padding: 0.65rem 0.85rem;
|
||||
margin-bottom: 0.75rem;
|
||||
font-size: 0.85rem;
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.why-what-box .why-p {
|
||||
margin: 0 0 0.4rem;
|
||||
}
|
||||
|
||||
.why-what-box .what-p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.why-what-box .term {
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
/* ---- control panel ---- */
|
||||
.control-panel {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 0.7rem;
|
||||
padding: 0.6rem 0.75rem;
|
||||
gap: 0.6rem;
|
||||
padding: 0.5rem 0.7rem;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
background: var(--vp-c-bg);
|
||||
margin-bottom: 0.8rem;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.control-left {
|
||||
display: flex;
|
||||
.ctrl-group {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.45rem;
|
||||
gap: 0.35rem;
|
||||
}
|
||||
|
||||
.ctrl-label {
|
||||
@@ -169,9 +149,9 @@ const writeOnce = () => {
|
||||
}
|
||||
|
||||
.input-toggle {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
border-radius: 50%;
|
||||
width: 2.2rem;
|
||||
height: 2.2rem;
|
||||
border-radius: 6px;
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-alt);
|
||||
font-weight: bold;
|
||||
@@ -187,260 +167,102 @@ const writeOnce = () => {
|
||||
}
|
||||
|
||||
.write-btn {
|
||||
padding: 0.3rem 0.75rem;
|
||||
border-radius: 999px;
|
||||
border: 2px solid var(--vp-c-warning);
|
||||
padding: 0.35rem 0.8rem;
|
||||
border-radius: 6px;
|
||||
border: 2px solid var(--vp-c-warning-1, #d97706);
|
||||
background: var(--vp-c-bg);
|
||||
color: var(--vp-c-warning-1, #d97706);
|
||||
font-size: 0.82rem;
|
||||
font-size: 0.85rem;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.write-btn:hover {
|
||||
background: var(--vp-c-warning-soft);
|
||||
background: var(--vp-c-warning-soft, rgba(217, 119, 6, 0.1));
|
||||
}
|
||||
|
||||
.write-btn.flash {
|
||||
background: var(--vp-c-warning);
|
||||
background: var(--vp-c-warning-1, #d97706);
|
||||
color: white;
|
||||
transform: scale(0.96);
|
||||
}
|
||||
|
||||
.control-right {
|
||||
display: flex;
|
||||
gap: 0.4rem;
|
||||
flex-wrap: wrap;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.chip {
|
||||
font-size: 0.78rem;
|
||||
padding: 0.2rem 0.45rem;
|
||||
border-radius: 999px;
|
||||
background: var(--vp-c-bg-alt);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.chip_on {
|
||||
border-color: var(--vp-c-brand);
|
||||
color: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
/* ---- main content ---- */
|
||||
.demo-content {
|
||||
display: grid;
|
||||
grid-template-columns: 1.5fr 1fr;
|
||||
gap: 0.8rem;
|
||||
}
|
||||
|
||||
/* ---- flow diagram ---- */
|
||||
.flow-diagram {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
background: var(--vp-c-bg);
|
||||
padding: 0.8rem;
|
||||
display: flex;
|
||||
.stored-val,
|
||||
.output-val {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.flow-node {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.node-label {
|
||||
font-size: 0.72rem;
|
||||
color: var(--vp-c-text-2);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.node-value {
|
||||
width: 2.4rem;
|
||||
height: 2.4rem;
|
||||
border-radius: 8px;
|
||||
justify-content: center;
|
||||
min-width: 2rem;
|
||||
height: 2rem;
|
||||
padding: 0 0.4rem;
|
||||
border-radius: 6px;
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-alt);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.2rem;
|
||||
font-weight: bold;
|
||||
font-family: monospace;
|
||||
transition: all 0.3s;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.node-value.on {
|
||||
.stored-val.on,
|
||||
.output-val.on {
|
||||
border-color: var(--vp-c-brand);
|
||||
color: var(--vp-c-brand);
|
||||
background: var(--vp-c-brand-soft);
|
||||
}
|
||||
|
||||
.node-hint {
|
||||
font-size: 0.7rem;
|
||||
color: var(--vp-c-text-3);
|
||||
.visualization-area {
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.register-node .node-value {
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
font-size: 1.5rem;
|
||||
border: 3px solid var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.register-node.flashing .node-value {
|
||||
border-color: var(--vp-c-warning);
|
||||
box-shadow: 0 0 10px var(--vp-c-warning-soft);
|
||||
}
|
||||
|
||||
.bulb {
|
||||
font-size: 1.8rem;
|
||||
filter: grayscale(100%);
|
||||
opacity: 0.4;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.output-node.on .bulb {
|
||||
filter: grayscale(0%);
|
||||
opacity: 1;
|
||||
text-shadow: 0 0 12px #facc15;
|
||||
}
|
||||
|
||||
/* ---- arrows ---- */
|
||||
.flow-arrow {
|
||||
.flow-strip {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 0.2rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.arrow-line {
|
||||
width: 28px;
|
||||
height: 2px;
|
||||
background: var(--vp-c-divider);
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.flow-arrow.active .arrow-line {
|
||||
background: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.arrow-tag {
|
||||
font-size: 0.65rem;
|
||||
color: var(--vp-c-text-3);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.arrow-head {
|
||||
font-size: 0.8rem;
|
||||
color: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
/* ---- state table ---- */
|
||||
.state-table {
|
||||
gap: 0.4rem;
|
||||
padding: 0.6rem 0.8rem;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
background: var(--vp-c-bg);
|
||||
padding: 0.8rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.table-title {
|
||||
.flow-item {
|
||||
font-weight: bold;
|
||||
font-size: 0.85rem;
|
||||
margin-bottom: 0.6rem;
|
||||
}
|
||||
|
||||
.state-rows {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.state-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 0.4rem;
|
||||
font-size: 0.78rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.step-num {
|
||||
flex-shrink: 0;
|
||||
font-weight: bold;
|
||||
.flow-store {
|
||||
color: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.diff-display {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-top: 0.75rem;
|
||||
padding: 0.5rem;
|
||||
background: var(--vp-c-bg-alt);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.diff-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.2rem;
|
||||
}
|
||||
|
||||
.diff-label {
|
||||
font-size: 0.7rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.diff-value {
|
||||
width: 1.6rem;
|
||||
height: 1.6rem;
|
||||
.flow-store.flash {
|
||||
box-shadow: 0 0 0 2px var(--vp-c-warning-1);
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: bold;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.diff-value.on {
|
||||
border-color: var(--vp-c-brand);
|
||||
color: var(--vp-c-brand);
|
||||
background: var(--vp-c-brand-soft);
|
||||
}
|
||||
|
||||
.diff-sep {
|
||||
font-size: 1.1rem;
|
||||
.flow-arrow {
|
||||
color: var(--vp-c-text-3);
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
|
||||
.flow-arrow.active {
|
||||
color: var(--vp-c-warning-1);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.diff-same {
|
||||
font-size: 0.72rem;
|
||||
color: var(--vp-c-text-3);
|
||||
.flow-hint {
|
||||
margin: 0.4rem 0 0;
|
||||
font-size: 0.82rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
/* ---- info box ---- */
|
||||
.info-box {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
background: var(--vp-c-bg-alt);
|
||||
padding: 0.75rem;
|
||||
border-radius: 6px;
|
||||
font-size: 0.85rem;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-top: 0.8rem;
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.info-box strong {
|
||||
@@ -448,9 +270,10 @@ const writeOnce = () => {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 760px) {
|
||||
.demo-content {
|
||||
grid-template-columns: 1fr;
|
||||
@media (max-width: 520px) {
|
||||
.control-panel {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
+72
-276
@@ -5,97 +5,43 @@
|
||||
<span class="subtitle">Gate 电压决定电流能否通过</span>
|
||||
</div>
|
||||
|
||||
<div class="control-panel">
|
||||
<div class="control-left">
|
||||
<span class="control-label">栅极输入(Gate)</span>
|
||||
<button class="gate-toggle" :class="{ on: isOn }" @click="toggleSwitch">
|
||||
{{ isOn ? '1(高电压)' : '0(低电压)' }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="control-right">
|
||||
<span class="chip">通道:{{ isOn ? '导通' : '断开' }}</span>
|
||||
<span class="chip">输出:{{ isOn ? '1' : '0' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo-content">
|
||||
<div class="transistor-diagram">
|
||||
<div class="gate-column">
|
||||
<div class="gate-title">控制端 Gate</div>
|
||||
<div class="gate-value" :class="{ on: isOn }">
|
||||
{{ isOn ? '1' : '0' }}
|
||||
<div class="states">
|
||||
<div class="state-card">
|
||||
<div class="state-label">Gate = 0(低电压)</div>
|
||||
<div class="channel-row">
|
||||
<span class="terminal">源极</span>
|
||||
<div class="channel-track off">
|
||||
<span class="block-icon">✕ 断开</span>
|
||||
</div>
|
||||
<div class="gate-arrow">↓ 控制</div>
|
||||
<span class="terminal">漏极</span>
|
||||
</div>
|
||||
<div class="output-line">输出:<strong>0</strong></div>
|
||||
</div>
|
||||
|
||||
<div class="main-channel">
|
||||
<div class="terminal-box">源极 Source</div>
|
||||
<div class="channel-track" :class="{ on: isOn }">
|
||||
<span v-if="!isOn" class="block-icon">✕</span>
|
||||
<template v-else>
|
||||
<span class="flow-dot d1" />
|
||||
<span class="flow-dot d2" />
|
||||
<span class="flow-dot d3" />
|
||||
</template>
|
||||
<div class="state-card">
|
||||
<div class="state-label">Gate = 1(高电压)</div>
|
||||
<div class="channel-row">
|
||||
<span class="terminal">源极</span>
|
||||
<div class="channel-track on">
|
||||
<span class="flow-dot d1" />
|
||||
<span class="flow-dot d2" />
|
||||
<span class="flow-dot d3" />
|
||||
<span class="flow-label">导通</span>
|
||||
</div>
|
||||
<div class="terminal-box">漏极 Drain</div>
|
||||
</div>
|
||||
|
||||
<div class="result-line" :class="{ on: isOn }">
|
||||
{{ isOn ? '电流通过:Source → Drain' : '电流被阻断:无法通过通道' }}
|
||||
<span class="terminal">漏极</span>
|
||||
</div>
|
||||
<div class="output-line">输出:<strong>1</strong></div>
|
||||
</div>
|
||||
|
||||
<div class="truth-table">
|
||||
<div class="table-title">晶体管状态表</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Gate 输入</th>
|
||||
<th>通道状态</th>
|
||||
<th>输出</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr :class="{ highlight: !isOn }">
|
||||
<td>0(低电压)</td>
|
||||
<td>断开</td>
|
||||
<td>0</td>
|
||||
</tr>
|
||||
<tr :class="{ highlight: isOn }">
|
||||
<td>1(高电压)</td>
|
||||
<td>导通</td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="table-hint">
|
||||
点上方按钮切换 Gate,观察“通道状态”和“电流流动”如何同步变化。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="step-guide">
|
||||
<div class="step-item">① 改变 Gate 电压(0/1)</div>
|
||||
<div class="step-item">② 通道变为断开/导通</div>
|
||||
<div class="step-item">③ 输出随之变成 0/1</div>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<strong>核心思想:</strong>晶体管本质是“电控开关”:Gate=1 时导通,Gate=0
|
||||
时断开。所有数字计算都建立在这种 0/1 开关之上。
|
||||
<strong>核心思想:</strong>晶体管是“电控开关”:Gate=1 导通、Gate=0 断开,所有数字计算都建立在这种 0/1 开关之上。
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const isOn = ref(false)
|
||||
|
||||
const toggleSwitch = () => {
|
||||
isOn.value = !isOn.value
|
||||
}
|
||||
// 纯静态展示,无需交互
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -111,7 +57,7 @@ const toggleSwitch = () => {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.8rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.demo-header .title {
|
||||
@@ -125,166 +71,72 @@ const toggleSwitch = () => {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.control-panel {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.65rem 0.75rem;
|
||||
.states {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.state-card {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
background: var(--vp-c-bg);
|
||||
margin-bottom: 0.8rem;
|
||||
flex-wrap: wrap;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.control-left {
|
||||
.state-label {
|
||||
font-size: 0.85rem;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.channel-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.55rem;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.control-label {
|
||||
.terminal {
|
||||
font-size: 0.82rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.gate-toggle {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-alt);
|
||||
border-radius: 999px;
|
||||
padding: 0.3rem 0.65rem;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.gate-toggle.on {
|
||||
background: var(--vp-c-success-soft);
|
||||
color: var(--vp-c-success-1);
|
||||
border-color: var(--vp-c-success);
|
||||
color: var(--vp-c-success-1);
|
||||
background: var(--vp-c-success-soft);
|
||||
}
|
||||
|
||||
.control-right {
|
||||
display: flex;
|
||||
gap: 0.4rem;
|
||||
flex-wrap: wrap;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.chip {
|
||||
font-size: 0.78rem;
|
||||
padding: 0.2rem 0.45rem;
|
||||
border-radius: 999px;
|
||||
background: var(--vp-c-bg-alt);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
.chip.active {
|
||||
border-color: var(--vp-c-success);
|
||||
}
|
||||
|
||||
.legend-chip {
|
||||
font-size: 0.72rem;
|
||||
padding: 0.16rem 0.42rem;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg);
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.demo-content {
|
||||
display: grid;
|
||||
grid-template-columns: 1.2fr 1fr;
|
||||
gap: 0.9rem;
|
||||
}
|
||||
|
||||
.transistor-diagram {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
background: var(--vp-c-bg);
|
||||
padding: 0.8rem;
|
||||
}
|
||||
|
||||
.gate-column {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.45rem;
|
||||
margin-bottom: 0.7rem;
|
||||
}
|
||||
|
||||
.gate-title {
|
||||
font-size: 0.8rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.gate-value {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
border-radius: 50%;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.gate-value.on {
|
||||
border-color: var(--vp-c-success);
|
||||
color: var(--vp-c-success-1);
|
||||
background: var(--vp-c-success-soft);
|
||||
}
|
||||
|
||||
.gate-arrow {
|
||||
font-size: 0.78rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.main-channel {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1.6fr 1fr;
|
||||
align-items: center;
|
||||
gap: 0.55rem;
|
||||
}
|
||||
|
||||
.terminal-box {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg-alt);
|
||||
padding: 0.45rem;
|
||||
text-align: center;
|
||||
font-size: 0.78rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.channel-track {
|
||||
height: 2.4rem;
|
||||
flex: 1;
|
||||
min-height: 2.5rem;
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
border-radius: 999px;
|
||||
background: #e5e7eb;
|
||||
position: relative;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.channel-track.off {
|
||||
background: var(--vp-c-bg-alt);
|
||||
}
|
||||
|
||||
.channel-track.on {
|
||||
background: var(--vp-c-success-soft);
|
||||
border-color: var(--vp-c-success);
|
||||
}
|
||||
|
||||
.block-icon {
|
||||
font-size: 1.1rem;
|
||||
font-size: 0.9rem;
|
||||
font-weight: bold;
|
||||
color: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
.flow-dot {
|
||||
width: 0.42rem;
|
||||
height: 0.42rem;
|
||||
width: 0.4rem;
|
||||
height: 0.4rem;
|
||||
border-radius: 50%;
|
||||
background: var(--vp-c-success);
|
||||
position: absolute;
|
||||
left: -8%;
|
||||
left: -10%;
|
||||
animation: flow 1.5s linear infinite;
|
||||
}
|
||||
|
||||
@@ -296,92 +148,40 @@ const toggleSwitch = () => {
|
||||
animation-delay: 0.9s;
|
||||
}
|
||||
|
||||
.flow-label {
|
||||
margin-left: 0.4rem;
|
||||
font-size: 0.85rem;
|
||||
color: var(--vp-c-success-1);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@keyframes flow {
|
||||
from {
|
||||
left: -8%;
|
||||
left: -10%;
|
||||
}
|
||||
to {
|
||||
left: 105%;
|
||||
}
|
||||
}
|
||||
|
||||
.result-line {
|
||||
margin-top: 0.7rem;
|
||||
font-size: 0.82rem;
|
||||
color: var(--vp-c-text-2);
|
||||
padding: 0.45rem 0.55rem;
|
||||
background: var(--vp-c-bg-alt);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.result-line.on {
|
||||
color: var(--vp-c-success-1);
|
||||
}
|
||||
|
||||
.truth-table {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
background: var(--vp-c-bg);
|
||||
padding: 0.8rem;
|
||||
}
|
||||
|
||||
.table-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.55rem;
|
||||
.output-line {
|
||||
margin-top: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 0.84rem;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
padding: 0.45rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
th {
|
||||
background: var(--vp-c-bg-alt);
|
||||
}
|
||||
|
||||
tr.highlight {
|
||||
background: var(--vp-c-brand-soft);
|
||||
}
|
||||
|
||||
.table-hint {
|
||||
margin-top: 0.55rem;
|
||||
font-size: 0.8rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.step-guide {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 0.45rem;
|
||||
margin-top: 0.8rem;
|
||||
}
|
||||
|
||||
.step-item {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 6px;
|
||||
padding: 0.45rem 0.5rem;
|
||||
font-size: 0.78rem;
|
||||
.output-line strong {
|
||||
color: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
.info-box {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
background: var(--vp-c-bg-alt);
|
||||
padding: 0.75rem;
|
||||
border-radius: 6px;
|
||||
font-size: 0.85rem;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-top: 0.75rem;
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.info-box strong {
|
||||
@@ -389,12 +189,8 @@ tr.highlight {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 860px) {
|
||||
.demo-content {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.step-guide {
|
||||
@media (max-width: 640px) {
|
||||
.states {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user