Skip to content

Commit 84ec703

Browse files
committed
feat: body content for all 106 features, rich tooltips, full-width tables
- Add body descriptions to every feature in features.json (1-3 paragraphs each covering escape sequence syntax, usage, and cross-terminal differences) - Feature detail pages render body content with tags as links - Rich tooltips on feature names show spec URL and tags - Terminal header tooltips show version on category/tag pages - Feature tables use full page width with fixed column proportions (Backend 20%, Version 10%, Support 10%, Notes 60%)
1 parent 50293c0 commit 84ec703

13 files changed

Lines changed: 280 additions & 117 deletions

docs/.vitepress/config.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,19 @@ function buildSidebar() {
109109
device: "Device Status",
110110
}
111111

112-
const categoryOrder = ["sgr", "cursor", "text", "erase", "editing", "modes", "scrollback", "reset", "extensions", "charsets", "device"]
112+
const categoryOrder = [
113+
"sgr",
114+
"cursor",
115+
"text",
116+
"erase",
117+
"editing",
118+
"modes",
119+
"scrollback",
120+
"reset",
121+
"extensions",
122+
"charsets",
123+
"device",
124+
]
113125

114126
// Determine categories and features from features.json
115127
const categories = new Map<string, Array<{ id: string; name: string; slug: string }>>()

docs/[category]/[id].md

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const { params } = useData()
1010
const p = params.value
1111

1212
const backendResults = JSON.parse(p.backendResults)
13+
const featureTags = JSON.parse(p.featureTags || '[]')
1314

1415
function icon(result) {
1516
if (result === 'yes') return ''
@@ -32,9 +33,12 @@ function cls(result) {
3233

3334
<p class="feature-meta">
3435
Category: <a :href="'/' + p.featureCategory">{{ p.featureCategory }}</a>
36+
<span v-if="featureTags.length"> · Tags: <template v-for="(tag, i) in featureTags" :key="tag.id"><a :href="'/' + tag.id">{{ tag.label }}</a><template v-if="i < featureTags.length - 1">, </template></template></span>
3537
<span v-if="p.specUrl"> · <a :href="p.specUrl" target="_blank" rel="noopener">Specification ↗</a></span>
3638
</p>
3739

40+
<div v-if="p.featureBody" class="feature-body" v-html="p.featureBody"></div>
41+
3842
<p class="feature-score">
3943
Supported by <strong>{{ p.yesCount }}</strong> of <strong>{{ p.totalCount }}</strong> backends ({{ Math.round(p.yesCount / p.totalCount * 100) }}%)
4044
</p>
@@ -71,7 +75,7 @@ function cls(result) {
7175

7276
<style>
7377
.feature-page {
74-
max-width: 800px;
78+
max-width: 100%;
7579
}
7680

7781
.feature-meta {
@@ -84,18 +88,45 @@ function cls(result) {
8488
color: var(--vp-c-brand-1);
8589
}
8690

91+
.feature-body {
92+
color: var(--vp-c-text-2);
93+
font-size: 0.95em;
94+
line-height: 1.7;
95+
margin: 1em 0 1.5em;
96+
}
97+
98+
.feature-body code {
99+
font-family: var(--vp-font-family-mono);
100+
font-size: 0.9em;
101+
padding: 2px 6px;
102+
border-radius: 4px;
103+
background: var(--vp-c-bg-soft);
104+
color: var(--vp-c-text-1);
105+
}
106+
87107
.feature-score {
88108
font-size: 1.1em;
89109
margin: 1em 0;
90110
}
91111

92112
.support-table {
93113
width: 100%;
114+
table-layout: fixed;
94115
border-collapse: collapse;
95116
font-size: 0.9em;
96117
margin: 1em 0;
97118
}
98119

120+
/* Column proportions: Backend 20%, Version 10%, Support 10%, Notes 60% */
121+
.support-table th:nth-child(1),
122+
.support-table td:nth-child(1) { width: 20%; }
123+
.support-table th:nth-child(2),
124+
.support-table td:nth-child(2) { width: 10%; }
125+
.support-table th:nth-child(3),
126+
.support-table td:nth-child(3) { width: 10%; }
127+
.support-table th:nth-child(4),
128+
.support-table td:nth-child(4) { width: 60%; }
129+
99130
.support-table th,
100131
.support-table td {
101132
padding: 8px 12px;
@@ -131,6 +162,8 @@ function cls(result) {
131162
.note-cell {
132163
color: var(--vp-c-text-2);
133164
font-size: 0.95em;
165+
word-wrap: break-word;
166+
overflow-wrap: break-word;
134167
}
135168

136169
.cell-yes { color: #10b981; }

docs/[category]/[id].paths.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
import { loadCensus, featureSlug, terminalSlug } from "../data/load-census"
1+
import { loadCensus, featureSlug, terminalSlug, loadFeaturesMeta, tagLabel as getTagLabel } from "../data/load-census"
22

33
export default {
44
paths() {
55
const data = loadCensus()
6+
const featuresMeta = loadFeaturesMeta()
67

78
return data.features.map((f) => {
89
const slug = featureSlug(f.id)
910
const desc = data.featureDescriptions[f.id]
11+
const meta = featuresMeta[f.id]
1012

1113
// Build per-backend results for this feature
1214
const backendResults: Array<{
@@ -44,6 +46,12 @@ export default {
4446
const yesCount = backendResults.filter((r) => r.result === "yes").length
4547
const totalCount = backendResults.length
4648

49+
// Build tags with labels for display
50+
const tags = (meta?.tags ?? []).map((t: string) => ({
51+
id: t,
52+
label: getTagLabel(t),
53+
}))
54+
4755
return {
4856
params: {
4957
category: f.category,
@@ -52,6 +60,8 @@ export default {
5260
featureName: desc?.name ?? f.name,
5361
featureCategory: f.category,
5462
specUrl: desc?.url ?? f.spec ?? "",
63+
featureBody: meta?.body ?? "",
64+
featureTags: JSON.stringify(tags),
5565
backendResults: JSON.stringify(backendResults),
5666
yesCount: String(yesCount),
5767
totalCount: String(totalCount),

docs/data/census.data.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ interface FeatureMeta {
6363
url?: string
6464
tags?: string[]
6565
group?: string
66+
body?: string
6667
}
6768

6869
function loadFeatureDescriptions(): Record<string, FeatureMeta> {
@@ -79,7 +80,7 @@ function loadFeatureDescriptions(): Record<string, FeatureMeta> {
7980
if (typeof val === "string") result[id] = { name: val }
8081
else {
8182
const v = val as any
82-
result[id] = { name: v.name, slug: v.slug, url: v.url, tags: v.tags, group: v.group }
83+
result[id] = { name: v.name, slug: v.slug, url: v.url, tags: v.tags, group: v.group, body: v.body }
8384
}
8485
}
8586
return result

docs/data/load-census.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export interface FeatureMeta {
2727
url?: string
2828
tags?: string[]
2929
group?: string
30+
body?: string
3031
}
3132

3233
let _featuresMeta: Record<string, FeatureMeta> | null = null

docs/data/results/alacritty-0.26.0.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,4 +127,4 @@
127127
"sgr.underline.color": "got null not, expected null",
128128
"sgr.fg.standard": "got null not, expected null"
129129
}
130-
}
130+
}

docs/data/results/ghostty-native-1.3.1.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,4 @@
123123
"sgr.hidden": "not supported",
124124
"sgr.underline.color": "got null not, expected null"
125125
}
126-
}
126+
}

docs/data/results/kitty-0.40.0.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,4 @@
126126
"sgr.hidden": "not supported",
127127
"sgr.underline.color": "got null not, expected null"
128128
}
129-
}
129+
}

docs/data/results/vt100-0.1.0.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,4 +130,4 @@
130130
"sgr.hidden": "not supported",
131131
"sgr.underline.color": "got false, expected truthy"
132132
}
133-
}
133+
}

docs/data/results/wezterm-0.1.0-fork.5.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,4 +128,4 @@
128128
"sgr.fg.bright": "got 9, expected greater than 150",
129129
"sgr.bg.bright": "got 0, expected greater than 150"
130130
}
131-
}
131+
}

0 commit comments

Comments
 (0)