u
This commit is contained in:
1 parent
ae3ca3cfa1
commit
7bd5f1dde9
45 files changed
+3414
-229
No files matched your search
@@ -184,7 +184,11 @@ export default defineConfig({
|
||||
text: '接口文档',
|
||||
icon: 'cable',
|
||||
collapsed: false,
|
||||
items: [{ text: '快速开始', link: '/api/getting-started' }],
|
||||
items: [
|
||||
{ text: '快速开始', link: '/api/getting-started' },
|
||||
{ text: '数据查询', link: '/api/data' },
|
||||
{ text: '数据写入', link: '/api/save' },
|
||||
],
|
||||
},
|
||||
] satisfies G3SidebarItem[],
|
||||
},
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* API 参数面板 —— 给 markdown 表格套一层「带标题的框」。
|
||||
*
|
||||
* 为什么收 slot 而不是数组 prop:
|
||||
* 仓库约定 API 表格**直接写在 md 里**(见 CODEBUDDY.md「组件文档写作约定」)。
|
||||
* 若改成 `:rows="[{ name: 'view_name', ... }]"`,表格会退化成一长行 JS 字面量,
|
||||
* md 源码既不好读也不好 diff。所以这里只负责外壳与版式,表格本体仍由
|
||||
* markdown 渲染后塞进 slot。
|
||||
*
|
||||
* 配套样式见 theme/api.css(.g3-api-panel)。
|
||||
*
|
||||
* variant:
|
||||
* params(默认)参数表 —— 列序约定「参数 / 类型 / 必填 / 说明」,第 2、3 列的样式
|
||||
* 按位置写,改列序要同步改 api.css。
|
||||
* bare 只给框和标题,不套列样式。用于形状不同的表(如错误码表:
|
||||
* code / 含义 / 典型原因 / 定位)—— 若套上参数表的列样式,散文列
|
||||
* 会被当成「类型」套等宽、被当成「必填」染成品牌色。
|
||||
*
|
||||
* ⚠ 刻意不叫 plain:G3ApiPayload 表示「无语气」的类名就是 .g3-api-panel--plain,
|
||||
* 两者含义不同,同名迟早埋坑。
|
||||
*/
|
||||
withDefaults(defineProps<{ title?: string | null; variant?: 'params' | 'bare' }>(), {
|
||||
title: '请求参数',
|
||||
variant: 'params',
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="g3-api-panel" :class="`g3-api-panel--${variant}`">
|
||||
<!-- title 传 null 时不渲染标题栏:表格已经在自己那节标题下面时,
|
||||
重复一遍标题只是噪音,只保留边框与行分隔线。 -->
|
||||
<div v-if="title !== null" class="g3-api-panel__head">{{ title }}</div>
|
||||
<div class="g3-api-panel__body">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,57 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* API 报文面板 —— 请求体 / 响应体,按 **body.code** 着色。
|
||||
*
|
||||
* 存在理由:原来请求体和响应体都是裸 ```json 代码块,视觉上完全一样,
|
||||
* 读者分不清哪块是入参哪块是出参;而 `code: 0` 与 `code: 1000` 也同样是
|
||||
* 一片灰底,全站最想强调的「HTTP 200 也可能是失败」在版式上零体现。
|
||||
*
|
||||
* ⚠ 着色依据是 body.code,**不是 HTTP 状态码**。这正是通用 OpenAPI 渲染器
|
||||
* 做不到的地方:它们的颜色模型绑死了 HTTP 状态码,会把这里的失败响应
|
||||
* 渲染成绿色成功块。
|
||||
*
|
||||
* tone 的推断规则:给了 code 就是「0 成功、其余失败」;语义特殊的码
|
||||
* (如部分成功)显式传 tone="warn" 覆盖。
|
||||
*/
|
||||
import { computed } from 'vue'
|
||||
|
||||
type Tone = 'plain' | 'ok' | 'warn' | 'error'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
/** 面板标题,如「请求体」「响应」 */
|
||||
title?: string
|
||||
/** 响应体里的 code;给出时参与 tone 推断,并在标题栏显示 code 徽章 */
|
||||
code?: number | string
|
||||
/** 显式指定语气,覆盖由 code 推断的结果 */
|
||||
tone?: Tone
|
||||
}>(),
|
||||
{ title: '响应' },
|
||||
)
|
||||
|
||||
const resolvedTone = computed<Tone>(() => {
|
||||
if (props.tone) return props.tone
|
||||
if (props.code === undefined) return 'plain'
|
||||
return props.code === 0 ? 'ok' : 'error'
|
||||
})
|
||||
|
||||
/** 颜色之外再给一个文字标签:色觉障碍下也能读出成功/失败 */
|
||||
const toneLabel = computed(() => {
|
||||
const map: Record<Tone, string> = { plain: '', ok: '成功', warn: '警告', error: '失败' }
|
||||
return map[resolvedTone.value]
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="g3-api-panel g3-api-panel--payload" :class="`g3-api-panel--${resolvedTone}`">
|
||||
<div class="g3-api-panel__head">
|
||||
<span class="g3-api-panel__dot" />
|
||||
<span>{{ title }}</span>
|
||||
<code v-if="code !== undefined" class="g3-api-panel__code">code {{ code }}</code>
|
||||
<span v-if="toneLabel" class="g3-api-panel__tone">{{ toneLabel }}</span>
|
||||
</div>
|
||||
<div class="g3-api-panel__body">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,240 @@
|
||||
/* ==========================================================================
|
||||
API 文档版式(docs/content/api/**)
|
||||
--------------------------------------------------------------------------
|
||||
三处视觉缺口,对应下面三段:
|
||||
|
||||
1. 端点标题 `## `POST` `/data/page`` 与 `## 基础约定` 长得一样 → 方法徽章
|
||||
2. 参数表是裸 markdown 表格(必填列原来是 emoji)→ G3ApiParams 面板
|
||||
3. 请求体 / 响应体是两块一模一样的灰底 JSON → G3ApiPayload 面板(按 code 着色)
|
||||
|
||||
两条自我约束:
|
||||
- 只用 --vp-c-* 变量,不引第三方样式表。站点其余部分是逐像素对齐 Docus 的
|
||||
(见 custom.css),API 页必须留在同一套设计语言里。
|
||||
- 一律逻辑属性(inline-* / block-*),站内已有 RTL 支持(见 content/ui/usage/rtl)。
|
||||
========================================================================== */
|
||||
|
||||
/* ==========================================================================
|
||||
1. 端点标题
|
||||
--------------------------------------------------------------------------
|
||||
写法:## `POST` `/data/page`
|
||||
|
||||
用 :has(> code:first-child) 把端点标题与普通 H2 区分开 —— 这既是样式的需要,
|
||||
也是「为什么不用组件渲染标题」的答案:标题一旦交给 Vue 组件渲染,就不再进
|
||||
markdown 的 heading token 流,右侧目录(G3DocAside)会丢掉全部条目、锚点
|
||||
一并消失。所以标题仍是 markdown H2,只在 CSS 上做文章。
|
||||
|
||||
代价:方法徽章的颜色没法按 GET/POST 区分(CSS 不能按文本匹配)。当前
|
||||
/api/** 下全部是 POST,所以是准确的;将来出现混合方法时,在 config.mts 的
|
||||
markdown.config 里加一个「把首词换成 <span class="g3-api-method--get">」的
|
||||
小插件即可,slug 由文本 token 决定,不受影响。
|
||||
|
||||
作用域:三张 API 页都带 frontmatter `pageClass: g3-api`(VitePress 把该 class
|
||||
落到根 <div class="Layout"> 上,见主题 Layout.vue:34),下面全部规则都由
|
||||
.g3-api 兜住,不会漏到组件页去。
|
||||
========================================================================== */
|
||||
.g3-api .vp-doc h2:has(> code:first-child) {
|
||||
/* 覆盖 VitePress 的 .vp-doc h2(上边框 + padding-top):端点标题改为
|
||||
「下方一条分隔线」,与紧随其后的参数面板构成一组,读起来是一个接口一节。 */
|
||||
margin-block: 56px 20px;
|
||||
padding-block: 0 14px;
|
||||
border-block-start: 0;
|
||||
border-block-end: 1px solid var(--vp-c-divider);
|
||||
font-size: 20px;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
/* 方法徽章:第一个 code */
|
||||
.g3-api .vp-doc h2:has(> code:first-child) > code:first-child {
|
||||
padding: 2px 8px;
|
||||
border-radius: 6px;
|
||||
background-color: var(--vp-c-brand-soft);
|
||||
color: var(--vp-c-brand-1);
|
||||
font-family: var(--vp-font-family-mono);
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
line-height: 18px;
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
|
||||
/* 路径:第二个 code(nth-of-type 只数 code,不受中间的空格文本与
|
||||
末尾 header-anchor 的 <a> 影响) */
|
||||
.g3-api .vp-doc h2:has(> code:first-child) > code:nth-of-type(2) {
|
||||
padding: 0;
|
||||
background-color: transparent;
|
||||
color: var(--vp-c-text-1);
|
||||
font-family: var(--vp-font-family-mono);
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
2 & 3. 面板(G3ApiParams / G3ApiPayload)
|
||||
--------------------------------------------------------------------------
|
||||
结构:标题栏 + 内容两段式。三个语气走同一组自定义变量,默认中性、
|
||||
ok / warn / error 分别取 success / warning / danger。
|
||||
|
||||
⚠ 语气语义是 **body.code**,不是 HTTP 状态码 —— 这正是通用 OpenAPI
|
||||
渲染器做不到的地方(它们的颜色模型绑死 HTTP 状态码,会把这里的
|
||||
失败响应渲染成绿色成功块)。
|
||||
========================================================================== */
|
||||
.g3-api-panel {
|
||||
--g3-api-accent: var(--vp-c-text-3);
|
||||
--g3-api-accent-soft: var(--vp-c-bg-alt);
|
||||
|
||||
margin: 16px 0;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
/* 圆角要裁掉子元素底色(标题栏、代码块),但横向滚动不能裁 ——
|
||||
滚动交给 __body,见下。 */
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.g3-api-panel--ok {
|
||||
--g3-api-accent: var(--vp-c-success-1, var(--vp-c-green-1));
|
||||
--g3-api-accent-soft: var(--vp-c-success-soft, var(--vp-c-green-soft));
|
||||
}
|
||||
|
||||
.g3-api-panel--warn {
|
||||
--g3-api-accent: var(--vp-c-warning-1, var(--vp-c-yellow-1));
|
||||
--g3-api-accent-soft: var(--vp-c-warning-soft, var(--vp-c-yellow-soft));
|
||||
}
|
||||
|
||||
.g3-api-panel--error {
|
||||
--g3-api-accent: var(--vp-c-danger-1, var(--vp-c-red-1));
|
||||
--g3-api-accent-soft: var(--vp-c-danger-soft, var(--vp-c-red-soft));
|
||||
}
|
||||
|
||||
.g3-api-panel__head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 14px;
|
||||
background-color: var(--vp-c-bg-soft);
|
||||
border-block-end: 1px solid var(--vp-c-divider);
|
||||
color: var(--vp-c-text-2);
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
/* 语气点:与语气同色。文字标签(成功/失败)与它并存,
|
||||
不让颜色成为唯一的区分手段。 */
|
||||
.g3-api-panel__dot {
|
||||
flex: 0 0 auto;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background-color: var(--g3-api-accent);
|
||||
}
|
||||
|
||||
.g3-api-panel--ok .g3-api-panel__head,
|
||||
.g3-api-panel--warn .g3-api-panel__head,
|
||||
.g3-api-panel--error .g3-api-panel__head {
|
||||
color: var(--g3-api-accent);
|
||||
}
|
||||
|
||||
.g3-api-panel__tone {
|
||||
font-weight: 500;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
/* code 徽章:仅 G3ApiPayload 传了 code 时出现 */
|
||||
.g3-api-panel__code {
|
||||
padding: 1px 7px;
|
||||
border-radius: 9999px;
|
||||
background-color: var(--g3-api-accent-soft);
|
||||
color: inherit;
|
||||
font-family: var(--vp-font-family-mono);
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.g3-api-panel__body {
|
||||
/* 宽表横向滚动由这一层承担:VitePress 给 .vp-doc table 设了
|
||||
display:block + overflow-x:auto,那会让 table 自己成为滚动容器
|
||||
(custom.css 里已记录过它导致 sticky 表头失效的问题)。 */
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
/* --- 参数表:去掉 .vp-doc 给 markdown 表格画的四边框与上下留白 ------ */
|
||||
.g3-api-panel__body table {
|
||||
display: table;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.g3-api-panel__body table th,
|
||||
.g3-api-panel__body table td {
|
||||
border: 0;
|
||||
border-block-end: 1px solid var(--vp-c-divider);
|
||||
padding: 8px 14px;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.g3-api-panel__body table tr:nth-child(2n) {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.g3-api-panel__body table tr:last-child td {
|
||||
border-block-end: 0;
|
||||
}
|
||||
|
||||
.g3-api-panel__body table th {
|
||||
color: var(--vp-c-text-3);
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
text-align: start;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* 列序约定:参数 / 类型 / 必填 / 说明。这两条按位置定样式,所以要两重限定:
|
||||
1) variant="params" —— 参数表才有这个形状。bare 的表(错误码:code / 含义 /
|
||||
典型原因 / 定位)若套上,散文列会被当成「类型」套等宽、被当成「必填」染成品牌色。
|
||||
2) :has(td:nth-child(4)) —— 同一个 params 变体下,「字段 / 说明」两列表(如
|
||||
/data/page 的 data 字段)第 2 列是散文,也不该套等宽小字。
|
||||
第 1 列两种表都是标识符(参数名 / 字段名 / code),所以不加限定。 */
|
||||
.g3-api-panel__body table td:first-child {
|
||||
color: var(--vp-c-text-1);
|
||||
font-family: var(--vp-font-family-mono);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.g3-api-panel--params .g3-api-panel__body:has(td:nth-child(4)) table td:nth-child(2) {
|
||||
color: var(--vp-c-text-3);
|
||||
font-family: var(--vp-font-family-mono);
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.g3-api-panel--params .g3-api-panel__body:has(td:nth-child(4)) table td:nth-child(3) {
|
||||
color: var(--vp-c-brand-1);
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* --- 报文里的代码块:贴边(VitePress 默认 margin:20px 0 + 圆角 8px)- */
|
||||
.g3-api-panel__body div[class*='language-'] {
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
4. 表格列宽:短中文列不被压扁
|
||||
--------------------------------------------------------------------------
|
||||
现象:/api/getting-started 的「接口一览」里「板块」列被压成一列一个字
|
||||
(「数据查询」折成两行)。
|
||||
|
||||
原因不是这列太长,而是**太短**:CJK 没有「词」的边界,可以逐字换行,于是
|
||||
该列的 min-content 宽度只有 1 个字。table-layout: auto 按 min-content 分配
|
||||
空间时,浏览器会把这列压到最小、把余量让给旁边的长路径与长文案 —— 越短的列
|
||||
越容易被牺牲,与直觉相反。
|
||||
|
||||
nowrap 把该列的 min-content 抬到「整格文字的宽度」,即不可再压。
|
||||
API 页各表的首列都是短键(板块 / 项 / code / 字段 / 参数名),nowrap 安全;
|
||||
长文案列(说明、触发场景)不带这条规则,照常换行。
|
||||
========================================================================== */
|
||||
.g3-api .vp-doc table th:first-child,
|
||||
.g3-api .vp-doc table td:first-child {
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -694,3 +694,80 @@
|
||||
.vitepress-demo-plugin__container > .vitepress-demo-plugin-preview {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
⚠ 必须还原 <table> 自身:`.vp-doc table { display:block; overflow-x:auto;
|
||||
margin:20px 0; border-collapse:collapse }`
|
||||
--------------------------------------------------------------------------
|
||||
这一整条是 VitePress 给 markdown 表格做「宽表横向滚动 + 上下留白」用的,
|
||||
但它命中了 G3Table 内部的 `<table class="stk-table-main">`,四个属性逐个都有害:
|
||||
|
||||
display:block + overflow-x:auto
|
||||
→ table 自身成为**滚动容器**
|
||||
→ th { position: sticky; top: 0 } 的定位基准变成这张 15 万 px 高、
|
||||
永不滚动的 table,而不是真正在滚的 .stk-table
|
||||
→ 纵向滚动时**表头跟着一起滚走**
|
||||
margin:20px 0
|
||||
→ 表格在容器内整体下移 20px,表头起始位置就偏了 20px
|
||||
border-collapse:collapse
|
||||
→ 库要求 separate(它用 border-spacing:0 + 逐格 background-image 画线),
|
||||
collapse 会改变边框模型
|
||||
|
||||
实测对比(同一组件、同一库版本、同样 5000 行虚拟滚动):
|
||||
playground(无 .vp-doc):滚动 600px 后表头位移 delta=0 ← 正常
|
||||
文档站(有 .vp-doc) :delta=-600,且 table 计算值 overflow:auto
|
||||
|
||||
还原成 table 的默认呈现,让 sticky 的作用域回到 .stk-table 这一层。
|
||||
⚠ 不要用 `all: revert` 之类的粗暴重置:那会连带清掉库需要的
|
||||
border-spacing / border-collapse:separate(库显式依赖二者)。 */
|
||||
.vp-doc .vitepress-demo-plugin-preview table {
|
||||
display: table;
|
||||
overflow: visible;
|
||||
margin: 0;
|
||||
border-collapse: separate;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
组件 Demo:隔断 VitePress 的正文排版样式
|
||||
--------------------------------------------------------------------------
|
||||
`.vp-doc` 是 VitePress 给正文(markdown 渲染结果)套的排版容器,它带一条
|
||||
`.vp-doc th, .vp-doc td { border: 1px solid var(--vp-c-divider) }` —— 给
|
||||
markdown 表格画的**四边**框线。而 demo 预览区(.vitepress-demo-plugin-preview)
|
||||
也在 .vp-doc 里面,于是 G3Table 的每个单元格都被额外套上四边框:
|
||||
|
||||
实测(/ui/data/table,docs 站):
|
||||
单元格计算值 borderTop/Bottom/Left/Right 全是 1px
|
||||
逐像素量内部横线 2px、竖线 2–3px ← 用户看到的「内部边框很厚」
|
||||
同一组件在 playground(无 .vp-doc)量到的是干净 1px。
|
||||
|
||||
也就是说「很厚」= VitePress 的四边框 + 组件自己的行分隔线叠出来的,
|
||||
组件本身没问题。修在文档站这一层,别去动组件样式。
|
||||
|
||||
注意选择器写在 .vp-doc **之内**限定 demo 预览区,不要写全局
|
||||
`.g3-table th` —— 那会把组件库样式泄漏到宿主页,反过来污染文档站正文里的
|
||||
普通 markdown 表格。
|
||||
========================================================================== */
|
||||
.vp-doc .vitepress-demo-plugin-preview table th,
|
||||
.vp-doc .vitepress-demo-plugin-preview table td {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* 内边距交回组件自己:上面 padding:0 是为了清掉 .vp-doc 给 markdown 单元格
|
||||
设的 padding,但我们的组件用的是 --cell-padding-x,被清掉后文字会贴边,
|
||||
所以这里还原回库的变量。
|
||||
|
||||
⚠ 这里**不要**再写 border-bottom:组件已改为把边框完全交给库
|
||||
(传 bordered: true),库的 .stk-table.bordered th,td 会用
|
||||
--bg-border-bottom 渐变自己画底部线。
|
||||
早先组件用 bordered-v(库不画底部线)时这里补过一条 border-bottom,
|
||||
现在两者会在同一像素位置叠成 2px —— 正是「内部边框很厚」的来源。 */
|
||||
.vp-doc .vitepress-demo-plugin-preview .g3-table__inner.stk-table th,
|
||||
.vp-doc .vitepress-demo-plugin-preview .g3-table__inner.stk-table td {
|
||||
padding: var(--cell-padding-y) var(--cell-padding-x);
|
||||
}
|
||||
|
||||
/* 展示态/编辑器内容自己带内边距,别被再套一层 */
|
||||
.vp-doc .vitepress-demo-plugin-preview .g3-table__inner.stk-table td:has(> .g3-table__cell-editor-root) {
|
||||
padding: 3px;
|
||||
}
|
||||
@@ -2,6 +2,10 @@ import type { Theme } from 'vitepress'
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
import Layout from './Layout.vue'
|
||||
import './custom.css'
|
||||
// API 文档版式(content/api/**):端点标题、参数面板、报文面板
|
||||
import './api.css'
|
||||
import G3ApiParams from './G3ApiParams.vue'
|
||||
import G3ApiPayload from './G3ApiPayload.vue'
|
||||
// 设计令牌的编译产物(经 vite alias 落到 packages/tokens/dist/index.css)。
|
||||
// 组件样式全部依赖 --g3-* 变量,必须先引入。改 tokens 后需重新 build @g3soft/tokens。
|
||||
import '@g3soft/tokens'
|
||||
@@ -9,4 +13,10 @@ import '@g3soft/tokens'
|
||||
export default {
|
||||
extends: DefaultTheme,
|
||||
Layout,
|
||||
enhanceApp({ app }) {
|
||||
// API 文档版式组件:全局注册,md 里直接写 <G3ApiParams> / <G3ApiPayload>,
|
||||
// 与 <demo> 一样是「不 import 就能用」的形态。
|
||||
app.component('G3ApiParams', G3ApiParams)
|
||||
app.component('G3ApiPayload', G3ApiPayload)
|
||||
},
|
||||
} satisfies Theme
|
||||
Reference in new issue
Block a user