docs(api-intro): rewrite API introduction with interactive examples and clearer explanations
- Restructure content with more engaging metaphors and practical examples - Add simplified interactive components to demonstrate key concepts - Improve readability with better organization and visual aids - Update terminology to be more beginner-friendly - Include real-world API usage scenarios
This commit is contained in:
@@ -1,755 +1,132 @@
|
||||
<!--
|
||||
ApiQuickStartDemo.vue
|
||||
参考 ide-intro 的“虚拟 UI + 先玩再讲”风格。
|
||||
目标:0 基础读者能立刻理解 API = 按钮/入口:
|
||||
选择按钮 -> 填一点 -> 点一下 -> 看结果(成功/失败)。
|
||||
ApiQuickStartDemo.vue - 简化版
|
||||
目标:用最简单的交互展示 API 调用流程
|
||||
-->
|
||||
<template>
|
||||
<div class="machine">
|
||||
<div class="top">
|
||||
<div>
|
||||
<div class="title">先玩一下:把 API 当成一个“按钮机”</div>
|
||||
<div class="sub">你只管:选按钮、填信息、点一下。别背术语。</div>
|
||||
</div>
|
||||
<div class="legend">
|
||||
<span class="dot in" /> 你填的信息
|
||||
<span class="dot mid" /> “按钮”(API) <span class="dot out" /> 返回结果
|
||||
<div class="demo">
|
||||
<div class="title">🎮 试试看:调用一次 API</div>
|
||||
<p class="subtitle">点一下按钮,看看会发生什么</p>
|
||||
|
||||
<div class="box">
|
||||
<button class="call-btn" :disabled="calling" @click="callApi">
|
||||
{{ calling ? '调用中...' : '🔘 点我调用 API' }}
|
||||
</button>
|
||||
|
||||
<div class="result" v-if="result">
|
||||
<div class="success" v-if="result.success">
|
||||
✅ 成功!API 返回了:{{ result.data }}
|
||||
</div>
|
||||
<div class="error" v-else>
|
||||
❌ 失败了:{{ result.error }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="screen">
|
||||
<div class="left">
|
||||
<div class="panelTitle">① 选一个按钮</div>
|
||||
<div class="buttons">
|
||||
<button
|
||||
v-for="b in buttons"
|
||||
:key="b.id"
|
||||
:class="['bigBtn', { active: currentId === b.id }]"
|
||||
@click="select(b.id)"
|
||||
>
|
||||
<div class="icon">{{ b.icon }}</div>
|
||||
<div class="label">{{ b.label }}</div>
|
||||
<div class="hint">{{ b.hint }}</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="middle">
|
||||
<div class="panelTitle">② 填一点信息</div>
|
||||
|
||||
<div class="form" v-if="currentId === 'date'">
|
||||
<label class="row">
|
||||
<span class="k">日期</span>
|
||||
<input
|
||||
v-model="form.dateText"
|
||||
class="input"
|
||||
placeholder="2026-01-19"
|
||||
/>
|
||||
</label>
|
||||
<div class="row">
|
||||
<span class="k">格式</span>
|
||||
<div class="chips">
|
||||
<button
|
||||
v-for="f in formats"
|
||||
:key="f"
|
||||
:class="['chip', { active: form.dateFormat === f }]"
|
||||
@click="form.dateFormat = f"
|
||||
>
|
||||
{{ f }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tip">玩法:把日期写错试试(比如 2026-99-99)。</div>
|
||||
</div>
|
||||
|
||||
<div class="form" v-else-if="currentId === 'ai'">
|
||||
<label class="row">
|
||||
<span class="k">问题</span>
|
||||
<textarea
|
||||
v-model="form.question"
|
||||
class="textarea"
|
||||
placeholder="例如:用一句话解释什么是 API"
|
||||
/>
|
||||
</label>
|
||||
<div class="tip">玩法:清空问题再点一下,看看会发生什么。</div>
|
||||
</div>
|
||||
|
||||
<div class="form" v-else>
|
||||
<div class="row">
|
||||
<span class="k">选择</span>
|
||||
<div class="chips">
|
||||
<button
|
||||
:class="['chip', { active: form.loginOk }]"
|
||||
@click="form.loginOk = true"
|
||||
>
|
||||
同意
|
||||
</button>
|
||||
<button
|
||||
:class="['chip', { active: !form.loginOk }]"
|
||||
@click="form.loginOk = false"
|
||||
>
|
||||
取消
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tip">玩法:选“取消”,再点一下。</div>
|
||||
</div>
|
||||
|
||||
<div class="callBar">
|
||||
<button class="callBtn" :disabled="busy" @click="call">
|
||||
{{ busy ? '执行中…' : '③ 点一下(调用)' }}
|
||||
</button>
|
||||
<button class="ghost" :disabled="busy" @click="resetScore">
|
||||
清零计分
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="score">
|
||||
<div class="scoreItem">
|
||||
<div class="scoreK">成功</div>
|
||||
<div class="scoreV">{{ score.ok }}</div>
|
||||
</div>
|
||||
<div class="scoreItem">
|
||||
<div class="scoreK">失败</div>
|
||||
<div class="scoreV">{{ score.bad }}</div>
|
||||
</div>
|
||||
<div class="scoreItem">
|
||||
<div class="scoreK">连续成功</div>
|
||||
<div class="scoreV">{{ score.streak }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="right">
|
||||
<div class="panelTitle">④ 看结果</div>
|
||||
|
||||
<div class="flow">
|
||||
<div class="node">
|
||||
<div class="nodeTop">
|
||||
<span class="dot in" />
|
||||
<span class="nodeTitle">你填的信息</span>
|
||||
</div>
|
||||
<div class="nodeBody">{{ requestPreview }}</div>
|
||||
</div>
|
||||
<div class="arrow" :class="{ go: animating }">→</div>
|
||||
<div class="node">
|
||||
<div class="nodeTop">
|
||||
<span class="dot mid" />
|
||||
<span class="nodeTitle">按钮(API)</span>
|
||||
</div>
|
||||
<div class="nodeBody">{{ currentHow }}</div>
|
||||
</div>
|
||||
<div class="arrow" :class="{ go: animating }">→</div>
|
||||
<div class="node">
|
||||
<div class="nodeTop">
|
||||
<span class="dot out" />
|
||||
<span class="nodeTitle">返回结果</span>
|
||||
</div>
|
||||
<div class="nodeBody">
|
||||
<div v-if="!result" class="muted">
|
||||
还没有结果。点一下“调用”试试。
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="resultBox"
|
||||
:class="{ ok: result.ok, bad: !result.ok }"
|
||||
>
|
||||
<div class="badge">{{ result.ok ? '成功' : '失败' }}</div>
|
||||
<div class="resultText">{{ result.text }}</div>
|
||||
<pre
|
||||
v-if="result.debug"
|
||||
class="code"
|
||||
><code>{{ result.debug }}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<details class="details">
|
||||
<summary>(选看)你不用管的细节</summary>
|
||||
<ul class="list">
|
||||
<li v-for="x in currentDetails" :key="x">{{ x }}</li>
|
||||
</ul>
|
||||
</details>
|
||||
</div>
|
||||
<div class="explain">
|
||||
<p><strong>你看:</strong>你只需要点一下按钮(调用 API),就会得到结果。</p>
|
||||
<p>这就是 API 的本质:<strong>按约定把请求交给对方,对方按约定把结果给你</strong>。</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const buttons = [
|
||||
{
|
||||
id: 'date',
|
||||
icon: '🗓️',
|
||||
label: '日期格式化',
|
||||
hint: '最简单:填日期 -> 得到结果',
|
||||
how: '调用一个日期格式化函数(本地)',
|
||||
details: ['内部怎么处理时区', '怎么优化性能', '怎么兼容不同语言环境']
|
||||
},
|
||||
{
|
||||
id: 'ai',
|
||||
icon: '🤖',
|
||||
label: '问 AI(模拟)',
|
||||
hint: '写一句话 -> 得到回答',
|
||||
how: '调用一个“问答入口”(可能是 SDK 或 HTTP)',
|
||||
details: ['模型怎么训练', '服务端怎么排队', '怎么限流/重试']
|
||||
},
|
||||
{
|
||||
id: 'login',
|
||||
icon: '🔑',
|
||||
label: '一键登录(模拟)',
|
||||
hint: '点同意/取消 -> 得到结果',
|
||||
how: '按登录流程走一遍(这里用模拟)',
|
||||
details: ['它怎么做安全校验', '登录凭证怎么生成', '怎么风控']
|
||||
}
|
||||
]
|
||||
|
||||
const formats = ['YYYY-MM-DD', 'YYYY/MM/DD', 'MM-DD']
|
||||
|
||||
const currentId = ref('date')
|
||||
const busy = ref(false)
|
||||
const animating = ref(false)
|
||||
|
||||
const form = reactive({
|
||||
dateText: '2026-01-19',
|
||||
dateFormat: 'YYYY-MM-DD',
|
||||
question: '用一句话解释什么是 API',
|
||||
loginOk: true
|
||||
})
|
||||
|
||||
const score = reactive({ ok: 0, bad: 0, streak: 0 })
|
||||
const calling = ref(false)
|
||||
const result = ref(null)
|
||||
|
||||
const callTimes = ref([]) // for "too frequent"
|
||||
|
||||
const current = computed(
|
||||
() => buttons.find((b) => b.id === currentId.value) || buttons[0]
|
||||
)
|
||||
|
||||
const currentHow = computed(() => current.value.how)
|
||||
const currentDetails = computed(() => current.value.details || [])
|
||||
|
||||
const requestPreview = computed(() => {
|
||||
if (currentId.value === 'date') {
|
||||
return `日期=${form.dateText || '(空)'};格式=${form.dateFormat}`
|
||||
}
|
||||
if (currentId.value === 'ai') {
|
||||
return `问题=${(form.question || '').trim() || '(空)'}`
|
||||
}
|
||||
return `选择=${form.loginOk ? '同意' : '取消'}`
|
||||
})
|
||||
|
||||
function select(id) {
|
||||
currentId.value = id
|
||||
function callApi() {
|
||||
calling.value = true
|
||||
result.value = null
|
||||
}
|
||||
|
||||
function resetScore() {
|
||||
score.ok = 0
|
||||
score.bad = 0
|
||||
score.streak = 0
|
||||
}
|
||||
|
||||
function pad2(n) {
|
||||
return String(n).padStart(2, '0')
|
||||
}
|
||||
|
||||
function fmtDate(d, fmt) {
|
||||
const y = d.getFullYear()
|
||||
const m = pad2(d.getMonth() + 1)
|
||||
const day = pad2(d.getDate())
|
||||
if (fmt === 'YYYY/MM/DD') return `${y}/${m}/${day}`
|
||||
if (fmt === 'MM-DD') return `${m}-${day}`
|
||||
return `${y}-${m}-${day}`
|
||||
}
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise((r) => setTimeout(r, ms))
|
||||
}
|
||||
|
||||
function record(ok) {
|
||||
if (ok) {
|
||||
score.ok += 1
|
||||
score.streak += 1
|
||||
} else {
|
||||
score.bad += 1
|
||||
score.streak = 0
|
||||
}
|
||||
}
|
||||
|
||||
async function call() {
|
||||
if (busy.value) return
|
||||
busy.value = true
|
||||
animating.value = true
|
||||
|
||||
// simulate "too frequent"
|
||||
const now = Date.now()
|
||||
callTimes.value = callTimes.value.filter((t) => now - t < 1200)
|
||||
callTimes.value.push(now)
|
||||
if (callTimes.value.length >= 4) {
|
||||
await sleep(220)
|
||||
// 模拟 API 调用
|
||||
setTimeout(() => {
|
||||
result.value = {
|
||||
ok: false,
|
||||
text: '太频繁了,请慢一点再试(模拟)',
|
||||
debug: '现实里:有些 API 会限制你“点太快”。'
|
||||
success: true,
|
||||
data: 'Hello from API!'
|
||||
}
|
||||
record(false)
|
||||
animating.value = false
|
||||
busy.value = false
|
||||
return
|
||||
}
|
||||
|
||||
await sleep(380)
|
||||
|
||||
if (currentId.value === 'date') {
|
||||
const raw = String(form.dateText || '').trim()
|
||||
const d = new Date(raw)
|
||||
if (Number.isNaN(d.getTime())) {
|
||||
result.value = {
|
||||
ok: false,
|
||||
text: '日期写错了(我看不懂)',
|
||||
debug: `输入:${raw}`
|
||||
}
|
||||
record(false)
|
||||
animating.value = false
|
||||
busy.value = false
|
||||
return
|
||||
}
|
||||
const out = fmtDate(d, form.dateFormat)
|
||||
result.value = {
|
||||
ok: true,
|
||||
text: `结果:${out}`,
|
||||
debug: `你填的:${raw}\n你选的格式:${form.dateFormat}\n它给你的:${out}`
|
||||
}
|
||||
record(true)
|
||||
animating.value = false
|
||||
busy.value = false
|
||||
return
|
||||
}
|
||||
|
||||
if (currentId.value === 'ai') {
|
||||
const q = String(form.question || '').trim()
|
||||
if (!q) {
|
||||
result.value = { ok: false, text: '你还没写问题', debug: '' }
|
||||
record(false)
|
||||
animating.value = false
|
||||
busy.value = false
|
||||
return
|
||||
}
|
||||
result.value = {
|
||||
ok: true,
|
||||
text: '回答:API 就是“别的软件给你用的按钮/入口”。',
|
||||
debug: `你的问题:${q}\n回答:API 就是“别的软件给你用的按钮/入口”。`
|
||||
}
|
||||
record(true)
|
||||
animating.value = false
|
||||
busy.value = false
|
||||
return
|
||||
}
|
||||
|
||||
// login
|
||||
if (!form.loginOk) {
|
||||
result.value = { ok: false, text: '用户取消了登录(模拟)', debug: '' }
|
||||
record(false)
|
||||
animating.value = false
|
||||
busy.value = false
|
||||
return
|
||||
}
|
||||
result.value = {
|
||||
ok: true,
|
||||
text: '登录成功:拿到用户信息(模拟)',
|
||||
debug: '用户:Alice\n状态:成功'
|
||||
}
|
||||
record(true)
|
||||
animating.value = false
|
||||
busy.value = false
|
||||
calling.value = false
|
||||
}, 800)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.machine {
|
||||
.demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 14px;
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.top {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
align-items: flex-start;
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-weight: 900;
|
||||
font-size: 16px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.sub {
|
||||
margin-top: 6px;
|
||||
font-size: 13px;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.legend {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
font-size: 12px;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 999px;
|
||||
display: inline-block;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.dot.in {
|
||||
background: color-mix(in srgb, #60a5fa 40%, var(--vp-c-bg));
|
||||
}
|
||||
|
||||
.dot.mid {
|
||||
background: color-mix(in srgb, var(--vp-c-brand-1) 35%, var(--vp-c-bg));
|
||||
}
|
||||
|
||||
.dot.out {
|
||||
background: color-mix(in srgb, #22c55e 30%, var(--vp-c-bg));
|
||||
}
|
||||
|
||||
.screen {
|
||||
margin-top: 12px;
|
||||
display: grid;
|
||||
grid-template-columns: 1.05fr 1fr 1.2fr;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.panelTitle {
|
||||
font-weight: 800;
|
||||
font-size: 13px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.left,
|
||||
.middle,
|
||||
.right {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 12px;
|
||||
background: var(--vp-c-bg);
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
margin-top: 10px;
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.bigBtn {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-soft);
|
||||
color: var(--vp-c-text-1);
|
||||
border-radius: 12px;
|
||||
padding: 12px;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.bigBtn:hover {
|
||||
border-color: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
.bigBtn.active {
|
||||
border-color: var(--vp-c-brand-1);
|
||||
box-shadow: 0 0 0 3px color-mix(in srgb, var(--vp-c-brand-1) 18%, transparent);
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.label {
|
||||
margin-top: 6px;
|
||||
font-weight: 900;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.hint {
|
||||
margin-top: 6px;
|
||||
font-size: 12px;
|
||||
.subtitle {
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.5;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.form {
|
||||
margin-top: 10px;
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: grid;
|
||||
grid-template-columns: 56px 1fr;
|
||||
gap: 10px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.k {
|
||||
font-size: 12px;
|
||||
color: var(--vp-c-text-3);
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
.input {
|
||||
width: 100%;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 10px;
|
||||
padding: 8px 10px;
|
||||
color: var(--vp-c-text-1);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.textarea {
|
||||
width: 100%;
|
||||
min-height: 78px;
|
||||
resize: vertical;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 10px;
|
||||
padding: 8px 10px;
|
||||
color: var(--vp-c-text-1);
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.chips {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.chip {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
.box {
|
||||
background: var(--vp-c-bg);
|
||||
color: var(--vp-c-text-1);
|
||||
padding: 6px 10px;
|
||||
border-radius: 999px;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.chip.active {
|
||||
border-color: var(--vp-c-brand-1);
|
||||
box-shadow: 0 0 0 3px color-mix(in srgb, var(--vp-c-brand-1) 18%, transparent);
|
||||
}
|
||||
|
||||
.tip {
|
||||
margin-top: 4px;
|
||||
font-size: 12px;
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.callBar {
|
||||
margin-top: 12px;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.callBtn {
|
||||
flex: 1;
|
||||
min-width: 200px;
|
||||
border: 1px solid var(--vp-c-brand-1);
|
||||
.call-btn {
|
||||
background: var(--vp-c-brand-1);
|
||||
color: #fff;
|
||||
border-radius: 12px;
|
||||
padding: 10px 12px;
|
||||
font-weight: 900;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 12px 24px;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.ghost {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg);
|
||||
color: var(--vp-c-text-1);
|
||||
border-radius: 12px;
|
||||
padding: 10px 12px;
|
||||
font-weight: 900;
|
||||
cursor: pointer;
|
||||
.call-btn:hover:not(:disabled) {
|
||||
opacity: 0.9;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.callBtn:disabled,
|
||||
.ghost:disabled {
|
||||
.call-btn:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.score {
|
||||
margin-top: 12px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 10px;
|
||||
.result {
|
||||
margin-top: 16px;
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.scoreItem {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 12px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 10px 12px;
|
||||
.success {
|
||||
background: #dcfce7;
|
||||
color: #166534;
|
||||
border: 1px solid #86efac;
|
||||
}
|
||||
|
||||
.scoreK {
|
||||
font-size: 12px;
|
||||
color: var(--vp-c-text-2);
|
||||
.error {
|
||||
background: #fee2e2;
|
||||
color: #991b1b;
|
||||
border: 1px solid #fca5a5;
|
||||
}
|
||||
|
||||
.scoreV {
|
||||
margin-top: 4px;
|
||||
font-size: 18px;
|
||||
font-weight: 900;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.flow {
|
||||
margin-top: 10px;
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.node {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 12px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.nodeTop {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
padding: 10px 12px;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.nodeTitle {
|
||||
font-weight: 900;
|
||||
font-size: 12px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.nodeBody {
|
||||
padding: 10px 12px;
|
||||
font-size: 12px;
|
||||
color: var(--vp-c-text-1);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
text-align: center;
|
||||
color: var(--vp-c-text-3);
|
||||
font-weight: 900;
|
||||
font-size: 16px;
|
||||
transition: transform 180ms ease;
|
||||
}
|
||||
|
||||
.arrow.go {
|
||||
transform: translateX(6px);
|
||||
color: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
.muted {
|
||||
font-size: 12px;
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.resultBox {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 12px;
|
||||
.explain {
|
||||
margin-top: 16px;
|
||||
padding: 12px;
|
||||
background: var(--vp-c-bg);
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.resultBox.ok {
|
||||
border-color: color-mix(in srgb, #22c55e 45%, var(--vp-c-divider));
|
||||
}
|
||||
|
||||
.resultBox.bad {
|
||||
border-color: color-mix(in srgb, #ef4444 45%, var(--vp-c-divider));
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
padding: 2px 10px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-soft);
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.resultText {
|
||||
margin-top: 8px;
|
||||
font-size: 13px;
|
||||
font-weight: 900;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.code {
|
||||
margin: 8px 0 0;
|
||||
padding: 10px 12px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-soft);
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.details {
|
||||
margin-top: 12px;
|
||||
border: 1px dashed var(--vp-c-divider);
|
||||
border-radius: 12px;
|
||||
background: var(--vp-c-bg);
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.details summary {
|
||||
cursor: pointer;
|
||||
color: var(--vp-c-text-1);
|
||||
font-weight: 900;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.list {
|
||||
margin: 10px 0 0;
|
||||
padding-left: 16px;
|
||||
color: var(--vp-c-text-1);
|
||||
font-size: 12px;
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.top {
|
||||
flex-direction: column;
|
||||
}
|
||||
.screen {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.score {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user