Skip to content

Commit 5a98617

Browse files
committed
feat(examples): style both hubs with the shared @internal/design system
Replace the examples' hand-rolled UnoCSS with @internal/design's presetDevframe + theme.css — the same preset, token theme, df-* component vocabulary, and Phosphor preset-icons the built-in plugins use. The Vite hub loads it via unocss/vite; the Next hub via @unocss/postcss (mirroring the git plugin). Dock glyphs resolve to i-ph-* classes inlined offline, no SVG map.
1 parent e83ac99 commit 5a98617

13 files changed

Lines changed: 218 additions & 505 deletions

File tree

examples/minimal-next-devframe-hub/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,20 @@
1717
"@devframes/plugin-git": "workspace:*",
1818
"@devframes/plugin-inspect": "workspace:*",
1919
"@devframes/plugin-terminals": "workspace:*",
20+
"@internal/design": "workspace:*",
2021
"devframe": "workspace:*",
2122
"next": "catalog:frontend",
2223
"react": "catalog:frontend",
2324
"react-dom": "catalog:frontend"
2425
},
2526
"devDependencies": {
27+
"@iconify-json/ph": "catalog:frontend",
2628
"@types/react": "catalog:types",
2729
"@types/react-dom": "catalog:types",
30+
"@unocss/postcss": "catalog:frontend",
2831
"get-port-please": "catalog:deps",
2932
"pathe": "catalog:deps",
33+
"unocss": "catalog:frontend",
3034
"vitest": "catalog:testing",
3135
"ws": "catalog:deps"
3236
}
Lines changed: 6 additions & 302 deletions
Original file line numberDiff line numberDiff line change
@@ -1,303 +1,7 @@
1-
/*
2-
* A deliberately small "minimal vite-devtools" skin (Next.js edition): an icon
3-
* dock on the left, the selected tool's iframe filling the stage, and a drawer
4-
* of hub subsystems (commands / messages / terminals) along the bottom. Mirrors
5-
* the Vite example so the same protocol reads identically across hosts.
6-
*/
7-
:root {
8-
color-scheme: light dark;
9-
font-family: Inter, system-ui, -apple-system, sans-serif;
10-
line-height: 1.5;
1+
/* The hub UI's design tokens, base layer, and component vocabulary come from the
2+
shared devframe design system. `@unocss` is replaced by UnoCSS (via
3+
`@unocss/postcss`, see ../postcss.config.mjs) with the generated preflights +
4+
utilities; `@internal/design/theme.css` (imported after this file in
5+
layout.tsx) supplies the `--df-*` token values + base element styling. */
116

12-
--accent: #845eee;
13-
--bg: #ffffff;
14-
--bg-sunken: #f6f6f8;
15-
--bg-raised: #ffffff;
16-
--fg: #1c1c22;
17-
--fg-muted: #6b6b78;
18-
--border: #e6e6ec;
19-
--border-strong: #d6d6e0;
20-
--ok: #16a34a;
21-
--err: #e1326a;
22-
}
23-
24-
@media (prefers-color-scheme: dark) {
25-
:root {
26-
--bg: #0e0e12;
27-
--bg-sunken: #131318;
28-
--bg-raised: #1a1a22;
29-
--fg: #e9e9f0;
30-
--fg-muted: #9b9bac;
31-
--border: #26262f;
32-
--border-strong: #34343f;
33-
--ok: #4ade80;
34-
--err: #ff6b9d;
35-
}
36-
}
37-
38-
* {
39-
box-sizing: border-box;
40-
}
41-
42-
body {
43-
margin: 0;
44-
height: 100vh;
45-
overflow: hidden;
46-
background: var(--bg);
47-
color: var(--fg);
48-
}
49-
50-
.app-shell {
51-
display: grid;
52-
grid-template-columns: 248px 1fr;
53-
grid-template-rows: auto 1fr auto;
54-
grid-template-areas:
55-
"header header"
56-
"sidebar main"
57-
"footer footer";
58-
height: 100vh;
59-
}
60-
61-
/* ── Header ───────────────────────────────────────────────── */
62-
.app-header {
63-
grid-area: header;
64-
display: flex;
65-
align-items: baseline;
66-
gap: 0.75rem;
67-
padding: 0.7rem 1.1rem;
68-
border-bottom: 1px solid var(--border);
69-
background: var(--bg-raised);
70-
}
71-
72-
.app-header h1 {
73-
margin: 0;
74-
font-size: 0.92rem;
75-
font-weight: 650;
76-
letter-spacing: 0.02em;
77-
}
78-
79-
.app-header p {
80-
margin: 0;
81-
font-family: ui-monospace, monospace;
82-
font-size: 0.74rem;
83-
color: var(--fg-muted);
84-
}
85-
86-
.app-tagline {
87-
margin-left: auto !important;
88-
font-style: italic;
89-
opacity: 0.8;
90-
}
91-
92-
#status span::before {
93-
content: "";
94-
display: inline-block;
95-
width: 7px;
96-
height: 7px;
97-
margin-right: 0.4em;
98-
border-radius: 50%;
99-
background: var(--fg-muted);
100-
vertical-align: middle;
101-
}
102-
103-
#status.ready span { color: var(--ok); }
104-
#status.ready span::before { background: var(--ok); }
105-
#status.error span { color: var(--err); }
106-
#status.error span::before { background: var(--err); }
107-
108-
/* ── Dock (sidebar) ───────────────────────────────────────── */
109-
.app-sidebar {
110-
grid-area: sidebar;
111-
border-right: 1px solid var(--border);
112-
padding: 0.6rem;
113-
overflow: auto;
114-
background: var(--bg-sunken);
115-
}
116-
117-
.app-sidebar h2 {
118-
padding: 0 0.5rem;
119-
}
120-
121-
.app-sidebar ul {
122-
gap: 0.15rem;
123-
}
124-
125-
.app-sidebar li {
126-
padding: 0;
127-
border: 0;
128-
background: transparent;
129-
}
130-
131-
.dock-btn {
132-
display: flex;
133-
align-items: center;
134-
gap: 0.6rem;
135-
width: 100%;
136-
text-align: left;
137-
padding: 0.5rem 0.6rem;
138-
font: inherit;
139-
font-size: 0.85rem;
140-
color: var(--fg);
141-
background: transparent;
142-
border: 0;
143-
border-radius: 0.5rem;
144-
cursor: pointer;
145-
position: relative;
146-
transition: background 0.12s ease, color 0.12s ease;
147-
}
148-
149-
.dock-btn:hover {
150-
background: color-mix(in srgb, var(--accent) 9%, transparent);
151-
}
152-
153-
.dock-btn.active {
154-
background: color-mix(in srgb, var(--accent) 14%, transparent);
155-
color: color-mix(in srgb, var(--accent) 65%, var(--fg));
156-
font-weight: 550;
157-
}
158-
159-
.dock-btn.active::before {
160-
content: "";
161-
position: absolute;
162-
left: -0.6rem;
163-
top: 50%;
164-
transform: translateY(-50%);
165-
width: 3px;
166-
height: 1.1rem;
167-
border-radius: 0 3px 3px 0;
168-
background: var(--accent);
169-
}
170-
171-
.dock-ico {
172-
display: inline-flex;
173-
align-items: center;
174-
justify-content: center;
175-
width: 22px;
176-
height: 22px;
177-
flex: none;
178-
color: var(--fg-muted);
179-
}
180-
181-
.dock-btn.active .dock-ico {
182-
color: var(--accent);
183-
}
184-
185-
.dock-ico svg {
186-
width: 20px;
187-
height: 20px;
188-
}
189-
190-
.dock-initial {
191-
display: inline-grid;
192-
place-items: center;
193-
width: 20px;
194-
height: 20px;
195-
border-radius: 0.35rem;
196-
background: color-mix(in srgb, var(--accent) 20%, transparent);
197-
font-size: 0.7rem;
198-
font-weight: 700;
199-
}
200-
201-
.dock-label {
202-
overflow: hidden;
203-
text-overflow: ellipsis;
204-
white-space: nowrap;
205-
}
206-
207-
/* ── Stage ────────────────────────────────────────────────── */
208-
.app-main {
209-
grid-area: main;
210-
overflow: hidden;
211-
background: var(--bg-sunken);
212-
}
213-
214-
.app-main iframe {
215-
width: 100%;
216-
height: 100%;
217-
border: 0;
218-
display: block;
219-
background: var(--bg);
220-
}
221-
222-
/* ── Drawer (footer) ──────────────────────────────────────── */
223-
.app-footer {
224-
grid-area: footer;
225-
display: flex;
226-
gap: 1.25rem;
227-
padding: 0.8rem 1.1rem;
228-
border-top: 1px solid var(--border);
229-
background: var(--bg-raised);
230-
max-height: 30vh;
231-
overflow: auto;
232-
}
233-
234-
.app-footer section {
235-
flex: 1;
236-
min-width: 0;
237-
}
238-
239-
h2 {
240-
font-size: 0.68rem;
241-
text-transform: uppercase;
242-
letter-spacing: 0.07em;
243-
color: var(--fg-muted);
244-
margin: 0 0 0.55rem;
245-
}
246-
247-
ul {
248-
list-style: none;
249-
padding-left: 0;
250-
margin: 0;
251-
display: flex;
252-
flex-direction: column;
253-
gap: 0.3rem;
254-
}
255-
256-
.app-footer li {
257-
padding: 0.4rem 0.6rem;
258-
border: 1px solid var(--border);
259-
border-radius: 0.45rem;
260-
background: var(--bg-sunken);
261-
font-family: ui-monospace, monospace;
262-
font-size: 0.78rem;
263-
}
264-
265-
li.muted {
266-
opacity: 0.55;
267-
font-style: italic;
268-
border-style: dashed;
269-
}
270-
271-
code {
272-
font-family: ui-monospace, monospace;
273-
font-size: 0.92em;
274-
background: color-mix(in srgb, var(--fg) 8%, transparent);
275-
padding: 0.1em 0.35em;
276-
border-radius: 0.25em;
277-
color: var(--fg-muted);
278-
}
279-
280-
.actions {
281-
display: flex;
282-
flex-wrap: wrap;
283-
gap: 0.75rem;
284-
align-items: flex-start;
285-
margin-top: 0.6rem;
286-
}
287-
288-
button {
289-
font: inherit;
290-
font-size: 0.82rem;
291-
padding: 0.4rem 0.8rem;
292-
border-radius: 0.45rem;
293-
border: 1px solid var(--border-strong);
294-
background: var(--bg-raised);
295-
cursor: pointer;
296-
color: var(--fg);
297-
transition: background 0.12s ease, border-color 0.12s ease;
298-
}
299-
300-
button:hover {
301-
border-color: var(--accent);
302-
background: color-mix(in srgb, var(--accent) 8%, transparent);
303-
}
7+
@unocss;
Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,27 @@
1-
// Offline dock icons. SVG bodies are inlined from `@iconify-json/ph` — the
2-
// same Phosphor set vite-devtools uses — so the dock renders crisp glyphs with
3-
// no runtime network and no multi-megabyte icon-set dependency in the bundle.
4-
// To add an icon, copy its `body` from the `ph` set under a `ph:<name>` key.
5-
const ICONS: Record<string, string> = {
6-
'ph:git-branch-duotone': '<g fill="currentColor"><path d="M224 64a24 24 0 1 1-24-24a24 24 0 0 1 24 24" opacity=".2"/><path d="M232 64a32 32 0 1 0-40 31v17a8 8 0 0 1-8 8H96a23.8 23.8 0 0 0-8 1.38V95a32 32 0 1 0-16 0v66a32 32 0 1 0 16 0v-17a8 8 0 0 1 8-8h88a24 24 0 0 0 24-24V95a32.06 32.06 0 0 0 24-31M64 64a16 16 0 1 1 16 16a16 16 0 0 1-16-16m32 128a16 16 0 1 1-16-16a16 16 0 0 1 16 16M200 80a16 16 0 1 1 16-16a16 16 0 0 1-16 16"/></g>',
7-
'ph:terminal-window-duotone': '<g fill="currentColor"><path d="M224 56v144a8 8 0 0 1-8 8H40a8 8 0 0 1-8-8V56a8 8 0 0 1 8-8h176a8 8 0 0 1 8 8" opacity=".2"/><path d="M128 128a8 8 0 0 1-3 6.25l-40 32a8 8 0 1 1-10-12.5L107.19 128L75 102.25a8 8 0 1 1 10-12.5l40 32a8 8 0 0 1 3 6.25m48 24h-40a8 8 0 0 0 0 16h40a8 8 0 0 0 0-16m56-96v144a16 16 0 0 1-16 16H40a16 16 0 0 1-16-16V56a16 16 0 0 1 16-16h176a16 16 0 0 1 16 16m-16 144V56H40v144z"/></g>',
8-
'ph:code-duotone': '<g fill="currentColor"><path d="m240 128l-48 40H64l-48-40l48-40h128Z" opacity=".2"/><path d="M69.12 94.15L28.5 128l40.62 33.85a8 8 0 1 1-10.24 12.29l-48-40a8 8 0 0 1 0-12.29l48-40a8 8 0 0 1 10.24 12.3m176 27.7l-48-40a8 8 0 1 0-10.24 12.3L227.5 128l-40.62 33.85a8 8 0 1 0 10.24 12.29l48-40a8 8 0 0 0 0-12.29m-82.39-89.37a8 8 0 0 0-10.25 4.79l-64 176a8 8 0 0 0 4.79 10.26A8.1 8.1 0 0 0 96 224a8 8 0 0 0 7.52-5.27l64-176a8 8 0 0 0-4.79-10.25"/></g>',
9-
'ph:stethoscope-duotone': '<g fill="currentColor"><path d="M240 160a32 32 0 1 1-32-32a32 32 0 0 1 32 32" opacity=".2"/><path d="M220 160a12 12 0 1 1-12-12a12 12 0 0 1 12 12m-4.55 39.29A48.08 48.08 0 0 1 168 240h-24a48.05 48.05 0 0 1-48-48v-40.51A64 64 0 0 1 40 88V40a8 8 0 0 1 8-8h24a8 8 0 0 1 0 16H56v40a48 48 0 0 0 48.64 48c26.11-.34 47.36-22.25 47.36-48.83V48h-16a8 8 0 0 1 0-16h24a8 8 0 0 1 8 8v47.17c0 32.84-24.53 60.29-56 64.31V192a32 32 0 0 0 32 32h24a32.06 32.06 0 0 0 31.22-25a40 40 0 1 1 16.23.27ZM232 160a24 24 0 1 0-24 24a24 24 0 0 0 24-24"/></g>',
10-
'ph:wheelchair-duotone': '<g fill="currentColor"><path d="M128 48a24 24 0 1 1-24-24a24 24 0 0 1 24 24" opacity=".2"/><path d="M255.59 189.47a8 8 0 0 0-10.12-5.06l-17.42 5.81l-28.9-57.8A8 8 0 0 0 192 128h-80v-24h56a8 8 0 0 0 0-16h-56v-9a32 32 0 1 0-16 0v10.81A72 72 0 0 0 112 232c33.52 0 63.69-22.71 71.75-54a8 8 0 1 0-15.5-4c-6.16 24-30.34 42-56.25 42a56 56 0 0 1-16-109.66V136a8 8 0 0 0 8 8h83.05l29.79 59.58a8 8 0 0 0 9.69 4l24-8a8 8 0 0 0 5.06-10.11M88 48a16 16 0 1 1 16 16a16 16 0 0 1-16-16"/></g>',
11-
'ph:rocket-duotone': '<g fill="currentColor"><path d="m94.81 192l-29.45 22.24a8 8 0 0 1-12.81-4.51L40.19 154.1a8 8 0 0 1 1.66-6.86l30.31-36.33C71 134.25 76.7 161.43 94.81 192m119.34-44.76l-30.31-36.33c1.21 23.34-4.54 50.52-22.65 81.09l29.45 22.24a8 8 0 0 0 12.81-4.51l12.36-55.63a8 8 0 0 0-1.66-6.86" opacity=".2"/><path d="M152 224a8 8 0 0 1-8 8h-32a8 8 0 0 1 0-16h32a8 8 0 0 1 8 8m-24-112a12 12 0 1 0-12-12a12 12 0 0 0 12 12m95.62 43.83l-12.36 55.63a16 16 0 0 1-25.51 9.11L158.51 200h-61l-27.26 20.57a16 16 0 0 1-25.51-9.11l-12.36-55.63a16.09 16.09 0 0 1 3.32-13.71l28.56-34.26a123 123 0 0 1 8.57-36.67c12.9-32.34 36-52.63 45.37-59.85a16 16 0 0 1 19.6 0c9.34 7.22 32.47 27.51 45.37 59.85a123 123 0 0 1 8.57 36.67l28.56 34.26a16.09 16.09 0 0 1 3.32 13.71M99.43 184h57.14c21.12-37.54 25.07-73.48 11.74-106.88C156.55 47.64 134.49 29 128 24c-6.51 5-28.57 23.64-40.33 53.12c-13.31 33.4-9.36 69.34 11.76 106.88m-15 5.85q-16.15-29.35-19.6-57.69L48 152.36L60.36 208l.18-.13ZM208 152.36l-16.83-20.2q-3.42 28.28-19.56 57.69l23.85 18l.18.13Z"/></g>',
12-
'ph:wrench-duotone': '<g fill="currentColor"><path d="M224 96a64 64 0 0 1-94.94 56L73 217a24 24 0 0 1-34-34l65-56.06a64 64 0 0 1 80-90.29L144 80l5.66 26.34L176 112l43.35-40A63.8 63.8 0 0 1 224 96" opacity=".2"/><path d="M226.76 69a8 8 0 0 0-12.84-2.88l-40.3 37.19l-17.23-3.7l-3.7-17.23l37.19-40.3A8 8 0 0 0 187 29.24A72 72 0 0 0 88 96a72.3 72.3 0 0 0 6 28.94L33.79 177c-.15.12-.29.26-.43.39a32 32 0 0 0 45.26 45.26c.13-.13.27-.28.39-.42L131.06 162A72 72 0 0 0 232 96a71.6 71.6 0 0 0-5.24-27M160 152a56.14 56.14 0 0 1-27.07-7a8 8 0 0 0-9.92 1.77l-55.9 64.74a16 16 0 0 1-22.62-22.62L109.18 133a8 8 0 0 0 1.77-9.93a56 56 0 0 1 58.36-82.31l-31.2 33.81a8 8 0 0 0-1.94 7.1l5.66 26.33a8 8 0 0 0 6.14 6.14l26.35 5.66a8 8 0 0 0 7.1-1.94l33.81-31.2A56.06 56.06 0 0 1 160 152"/></g>',
13-
'ph:plug-duotone': '<g fill="currentColor"><path d="m212 132l-58.63 58.63a32 32 0 0 1-45.25 0l-42.75-42.75a32 32 0 0 1 0-45.25L124 44Z" opacity=".2"/><path d="M237.66 66.34a8 8 0 0 0-11.32 0L192 100.69L155.31 64l34.35-34.34a8 8 0 1 0-11.32-11.32L144 52.69l-26.34-26.35a8 8 0 0 0-11.32 11.32l6.35 6.34l-53 53a40 40 0 0 0 0 56.57l15.71 15.71l-49.06 49.06a8 8 0 0 0 11.32 11.32l49.09-49.09l15.71 15.71a40 40 0 0 0 56.57 0l53-53l6.34 6.35a8 8 0 0 0 11.32-11.32L203.31 112l34.35-34.34a8 8 0 0 0 0-11.32M147.72 185a24 24 0 0 1-33.95 0L71 142.23a24 24 0 0 1 0-33.95l53-53L200.69 132Z"/></g>',
14-
'ph:gear-duotone': '<g fill="currentColor"><path d="m207.86 123.18l16.78-21a99 99 0 0 0-10.07-24.29l-26.7-3a81 81 0 0 0-6.81-6.81l-3-26.71a99.4 99.4 0 0 0-24.3-10l-21 16.77a82 82 0 0 0-9.64 0l-21-16.78a99 99 0 0 0-24.21 10.07l-3 26.7a81 81 0 0 0-6.81 6.81l-26.71 3a99.4 99.4 0 0 0-10 24.3l16.77 21a82 82 0 0 0 0 9.64l-16.78 21a99 99 0 0 0 10.07 24.29l26.7 3a81 81 0 0 0 6.81 6.81l3 26.71a99.4 99.4 0 0 0 24.3 10l21-16.77a82 82 0 0 0 9.64 0l21 16.78a99 99 0 0 0 24.29-10.07l3-26.7a81 81 0 0 0 6.81-6.81l26.71-3a99.4 99.4 0 0 0 10-24.3l-16.77-21a82 82 0 0 0-.08-9.64M128 168a40 40 0 1 1 40-40a40 40 0 0 1-40 40" opacity=".2"/><path d="M128 80a48 48 0 1 0 48 48a48.05 48.05 0 0 0-48-48m0 80a32 32 0 1 1 32-32a32 32 0 0 1-32 32m88-29.84q.06-2.16 0-4.32l14.92-18.64a8 8 0 0 0 1.48-7.06a107.6 107.6 0 0 0-10.88-26.25a8 8 0 0 0-6-3.93l-23.72-2.64q-1.48-1.56-3-3L186 40.54a8 8 0 0 0-3.94-6a107.3 107.3 0 0 0-26.25-10.86a8 8 0 0 0-7.06 1.48L130.16 40h-4.32L107.2 25.11a8 8 0 0 0-7.06-1.48a107.6 107.6 0 0 0-26.25 10.88a8 8 0 0 0-3.93 6l-2.64 23.76q-1.56 1.49-3 3L40.54 70a8 8 0 0 0-6 3.94a107.7 107.7 0 0 0-10.87 26.25a8 8 0 0 0 1.49 7.06L40 125.84v4.32L25.11 148.8a8 8 0 0 0-1.48 7.06a107.6 107.6 0 0 0 10.88 26.25a8 8 0 0 0 6 3.93l23.72 2.64q1.49 1.56 3 3L70 215.46a8 8 0 0 0 3.94 6a107.7 107.7 0 0 0 26.25 10.87a8 8 0 0 0 7.06-1.49L125.84 216q2.16.06 4.32 0l18.64 14.92a8 8 0 0 0 7.06 1.48a107.2 107.2 0 0 0 26.25-10.88a8 8 0 0 0 3.93-6l2.64-23.72q1.56-1.48 3-3l23.78-2.8a8 8 0 0 0 6-3.94a107.7 107.7 0 0 0 10.87-26.25a8 8 0 0 0-1.49-7.06Zm-16.1-6.5a74 74 0 0 1 0 8.68a8 8 0 0 0 1.74 5.48l14.19 17.73a91.6 91.6 0 0 1-6.23 15l-22.6 2.56a8 8 0 0 0-5.1 2.64a74 74 0 0 1-6.14 6.14a8 8 0 0 0-2.64 5.1l-2.51 22.58a91.3 91.3 0 0 1-15 6.23l-17.74-14.19a8 8 0 0 0-5-1.75h-.48a74 74 0 0 1-8.68 0a8.06 8.06 0 0 0-5.48 1.74l-17.78 14.2a91.6 91.6 0 0 1-15-6.23L82.89 187a8 8 0 0 0-2.64-5.1a74 74 0 0 1-6.14-6.14a8 8 0 0 0-5.1-2.64l-22.58-2.52a91.3 91.3 0 0 1-6.23-15l14.19-17.74a8 8 0 0 0 1.74-5.48a74 74 0 0 1 0-8.68a8 8 0 0 0-1.74-5.48L40.2 100.45a91.6 91.6 0 0 1 6.23-15L69 82.89a8 8 0 0 0 5.1-2.64a74 74 0 0 1 6.14-6.14A8 8 0 0 0 82.89 69l2.51-22.57a91.3 91.3 0 0 1 15-6.23l17.74 14.19a8 8 0 0 0 5.48 1.74a74 74 0 0 1 8.68 0a8.06 8.06 0 0 0 5.48-1.74l17.77-14.19a91.6 91.6 0 0 1 15 6.23L173.11 69a8 8 0 0 0 2.64 5.1a74 74 0 0 1 6.14 6.14a8 8 0 0 0 5.1 2.64l22.58 2.51a91.3 91.3 0 0 1 6.23 15l-14.19 17.74a8 8 0 0 0-1.74 5.53Z"/></g>',
15-
'ph:gauge-duotone': '<g fill="currentColor"><path d="M232 152v24a8 8 0 0 1-8 8H32a8 8 0 0 1-8-8v-22.87C24 95.65 70.15 48.2 127.63 48A104 104 0 0 1 232 152" opacity=".2"/><path d="M207.06 72.67A111.24 111.24 0 0 0 128 40h-.4C66.07 40.21 16 91 16 153.13V176a16 16 0 0 0 16 16h192a16 16 0 0 0 16-16v-24a111.25 111.25 0 0 0-32.94-79.33M224 176H119.71l54.76-75.3a8 8 0 0 0-12.94-9.42L99.92 176H32v-22.87c0-3.08.15-6.12.43-9.13H56a8 8 0 0 0 0-16H35.27c10.32-38.86 44-68.24 84.73-71.66V80a8 8 0 0 0 16 0V56.33A96.14 96.14 0 0 1 221 128h-21a8 8 0 0 0 0 16h23.67c.21 2.65.33 5.31.33 8Z"/></g>',
1+
// @unocss-include
2+
// Map a devframe dock `icon` (e.g. `ph:git-branch-duotone`) to a UnoCSS
3+
// `preset-icons` class. Keeping the class strings literal lets UnoCSS
4+
// statically extract them and inline only these glyphs from `@iconify-json/ph`
5+
// at build time — the same icon strategy vite-devtools uses. Add a row here to
6+
// support another dock icon.
7+
const ICON_CLASS: Record<string, string> = {
8+
'ph:git-branch-duotone': 'i-ph-git-branch-duotone',
9+
'ph:terminal-window-duotone': 'i-ph-terminal-window-duotone',
10+
'ph:code-duotone': 'i-ph-code-duotone',
11+
'ph:stethoscope-duotone': 'i-ph-stethoscope-duotone',
12+
'ph:wheelchair-duotone': 'i-ph-wheelchair-duotone',
13+
'ph:rocket-duotone': 'i-ph-rocket-duotone',
14+
'ph:wrench-duotone': 'i-ph-wrench-duotone',
15+
'ph:plug-duotone': 'i-ph-plug-duotone',
1616
}
1717

1818
/**
19-
* Render a devframe dock `icon` (e.g. `ph:git-branch-duotone`) as an inline
20-
* SVG string. Returns an empty string for icons absent from {@link ICONS} so
21-
* the caller can fall back to a text glyph.
19+
* Resolve a dock icon to its UnoCSS class, or an empty string when the icon
20+
* isn't mapped (the caller falls back to a text initial).
2221
*/
23-
export function iconSvg(name: string | { light: string, dark: string } | undefined, size = 18): string {
22+
export function iconClass(name: string | { light: string, dark: string } | undefined): string {
2423
if (!name)
2524
return ''
2625
const id = typeof name === 'string' ? name : name.light
27-
const body = ICONS[id]
28-
if (!body)
29-
return ''
30-
return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 256 256" aria-hidden="true">${body}</svg>`
26+
return ICON_CLASS[id] ?? ''
3127
}

0 commit comments

Comments
 (0)