@filipgutica/ui 1.8.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -14
- package/dist/index.js +1 -1
- package/dist/site.js +5 -5
- package/dist/{use-active-section-CiflgGBI.js → use-active-section-qEJQS1S9.js} +62 -50
- package/package.json +1 -1
- package/src/components/tabs.css +7 -2
- package/src/components.css +56 -51
- package/src/site.css +190 -12
- package/src/theme.css +2 -0
- package/src/themes/graphite-indigo.css +2 -2
package/README.md
CHANGED
|
@@ -18,6 +18,7 @@ Import the styles from your application stylesheet:
|
|
|
18
18
|
```css
|
|
19
19
|
@import "tailwindcss";
|
|
20
20
|
@import "@filipgutica/ui/theme.css";
|
|
21
|
+
@import "@filipgutica/ui/themes/graphite-indigo.css";
|
|
21
22
|
@import "@filipgutica/ui/components.css";
|
|
22
23
|
```
|
|
23
24
|
|
|
@@ -93,13 +94,10 @@ The gallery's search-and-install dialog is docs-only, not an exported component.
|
|
|
93
94
|
Applications can build their own picker with the exported components and theme
|
|
94
95
|
helpers. `UiSiteHeader` includes the built-in System, Light, and Dark control.
|
|
95
96
|
|
|
96
|
-
The
|
|
97
|
-
`theme.css
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
@import "@filipgutica/ui/theme.css";
|
|
101
|
-
@import "@filipgutica/ui/themes/graphite-indigo.css";
|
|
102
|
-
```
|
|
97
|
+
The install steps above import Graphite Indigo, the palette of the project
|
|
98
|
+
sites, after `theme.css`. To keep the base theme instead, with blue actions and
|
|
99
|
+
warm greys, leave out the `themes/graphite-indigo.css` import. Graphite Indigo
|
|
100
|
+
stays opt-in: `theme.css` alone still gives the base theme.
|
|
103
101
|
|
|
104
102
|
## Project sites
|
|
105
103
|
|
|
@@ -124,8 +122,9 @@ import { UiSiteHeader } from '@filipgutica/ui/site'
|
|
|
124
122
|
|
|
125
123
|
`project` is `wtree`, `annoterm`, `devps`, `workbench`, `filip-stack`, or `ui`. The project
|
|
126
124
|
menu is a native disclosure that works without JavaScript; Escape closes it and
|
|
127
|
-
returns focus to its button.
|
|
128
|
-
|
|
125
|
+
returns focus to its button. Inside `.fg-site-docs`, at 640px and below, the
|
|
126
|
+
header hides `links` so it fits one row, so repeat those destinations in the footer. Without a
|
|
127
|
+
default slot the header renders a System, Light, and Dark picker. A page with its own appearance control passes it
|
|
129
128
|
in the default slot and uses `useSiteAppearance({ applyToRoot: false })` when it
|
|
130
129
|
owns the root element.
|
|
131
130
|
|
|
@@ -169,8 +168,9 @@ import read from './captures/read.html?raw'
|
|
|
169
168
|
`aria-current="location"`, a text-only marker. An item with `current: true` gets
|
|
170
169
|
`aria-current="page"`, the selected fill and accent bar; `code: true` shows the
|
|
171
170
|
label in the monospace font. The page grid places the rail, which stays in view
|
|
172
|
-
on desktop. At 800px and below it is a native
|
|
173
|
-
interactive, then a drawer. The
|
|
171
|
+
on desktop. At 800px and below it is a native disclosure until the page is
|
|
172
|
+
interactive, then a drawer. The disclosure, the drawer button, and the drawer
|
|
173
|
+
title all show `label`. The drawer closes on navigation and focuses the
|
|
174
174
|
destination section, and focus follows the visible control across the
|
|
175
175
|
breakpoint.
|
|
176
176
|
|
|
@@ -182,9 +182,11 @@ focus returns to the button on close. Phones show the button as an icon. `v-mode
|
|
|
182
182
|
holds the active ID and defaults to the first item. Each capture has the ID
|
|
183
183
|
`idPrefix` + `id` (`frame-` by default), so a deep link such as `#frame-read`
|
|
184
184
|
selects its tab on load and on hash change. Without JavaScript every capture is
|
|
185
|
-
listed under its own heading and scrolls at full size.
|
|
186
|
-
|
|
187
|
-
the
|
|
185
|
+
listed under its own heading and scrolls at full size. Captures use a dark
|
|
186
|
+
terminal palette for the `.term` root and the converter's ANSI classes (`.tf0`
|
|
187
|
+
to `.tf15`, `.tb0` to `.tb15`, `.tf-dim`, `.tbold`, and the others). To change
|
|
188
|
+
it, set `--site-capture-bg`, `--t-bg`, `--t-fg`, `--t-dim`, or `--t0` to `--t15`
|
|
189
|
+
on `:root`, because the dialog renders outside the panel.
|
|
188
190
|
|
|
189
191
|
`UiCommandList` renders a table of monospace commands and descriptions. Use the
|
|
190
192
|
`command` slot to show a key as `<kbd>`, the `description` slot for `<kbd>` or
|
|
@@ -200,6 +202,53 @@ pairs, `.fg-site-definitions` for a two-column `dl` of `dt` and `dd` that stacks
|
|
|
200
202
|
on phones, `.fg-site-sr-only` for visually hidden text, and `.fg-site-skip` for
|
|
201
203
|
a skip link that appears on focus.
|
|
202
204
|
|
|
205
|
+
### Docs shell
|
|
206
|
+
|
|
207
|
+
Add `fg-site-docs` to the element that wraps a project page's header, rail,
|
|
208
|
+
main content, and footer. The shell then supplies:
|
|
209
|
+
|
|
210
|
+
- the frame: the header across the top, the `--sidebar` rail beside `main`, and
|
|
211
|
+
the footer on the frame edges. At 800px and below the rail stacks above `main`.
|
|
212
|
+
- element defaults inside the shell, plus the page background and font on
|
|
213
|
+
`body`: box sizing, heading sizes and margins, paragraph measure, links,
|
|
214
|
+
`kbd`, and a 2px focus outline.
|
|
215
|
+
- `.fg-site-footer` for the footer and `.fg-site-legend` for a `dl` that explains
|
|
216
|
+
what a capture shows.
|
|
217
|
+
|
|
218
|
+
```vue
|
|
219
|
+
<template>
|
|
220
|
+
<div class="fg-site-docs">
|
|
221
|
+
<UiSiteHeader project="devps" />
|
|
222
|
+
<UiSiteNav label="On this page" :groups="navigation" />
|
|
223
|
+
<main id="main">
|
|
224
|
+
<section aria-labelledby="title">…</section>
|
|
225
|
+
<dl class="fg-site-legend">
|
|
226
|
+
<div><dt>PORTS</dt><dd>The ports the server listens on.</dd></div>
|
|
227
|
+
</dl>
|
|
228
|
+
</main>
|
|
229
|
+
<footer class="fg-site-footer">
|
|
230
|
+
<a href="https://github.com/filipgutica">Built by Filip Gutica</a>
|
|
231
|
+
<nav aria-label="Project links">
|
|
232
|
+
<a href="https://github.com/filipgutica/devps/releases">Releases</a>
|
|
233
|
+
</nav>
|
|
234
|
+
</footer>
|
|
235
|
+
</div>
|
|
236
|
+
</template>
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
The header, rail, `main`, and footer must be direct children of the shell. The
|
|
240
|
+
element defaults sit in the `base` cascade layer, so library components and the
|
|
241
|
+
site's own rules win. That holds only when the site declares the layer order
|
|
242
|
+
before importing `site.css`: `@import "tailwindcss"` does this, or start the
|
|
243
|
+
stylesheet with `@layer base, components, utilities;`. To adopt the shell, delete
|
|
244
|
+
the site's own frame, element base, `kbd`, footer, legend, and ANSI palette
|
|
245
|
+
rules. Without `fg-site-docs`, the frame, element defaults, and phone header
|
|
246
|
+
rules do not apply. These apply on every page: the `fg-site-footer` and
|
|
247
|
+
`fg-site-legend` classes wherever a page uses them; the capture terminal palette
|
|
248
|
+
for every `UiCapture`, in the `components` layer, so a site's own unlayered
|
|
249
|
+
`.term` and ANSI rules and its `--t*` values still win; and `UiSiteNav`, whose
|
|
250
|
+
phone toggle and drawer title now show its `label`.
|
|
251
|
+
|
|
203
252
|
## Development
|
|
204
253
|
|
|
205
254
|
```sh
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as e, i as t, n, o as r, r as i, t as a } from "./use-active-section-
|
|
1
|
+
import { a as e, i as t, n, o as r, r as i, t as a } from "./use-active-section-qEJQS1S9.js";
|
|
2
2
|
import { Fragment as o, computed as s, createBlock as c, createCommentVNode as l, createElementBlock as u, createElementVNode as d, createTextVNode as f, createVNode as p, defineComponent as m, inject as h, mergeModels as g, mergeProps as _, normalizeStyle as v, openBlock as y, provide as b, ref as ee, renderList as x, renderSlot as S, resolveDynamicComponent as C, shallowRef as te, toDisplayString as w, unref as T, useId as E, useModel as ne, useSlots as D, watch as re, withCtx as O } from "vue";
|
|
3
3
|
import { CheckboxIndicator as k, CheckboxRoot as A, Primitive as j, ProgressIndicator as M, ProgressRoot as N, RadioGroupItem as P, RadioGroupRoot as F, SliderRange as I, SliderRoot as L, SliderThumb as R, SliderTrack as z, Toggle as B } from "reka-ui";
|
|
4
4
|
//#region src/components/UiCard.vue?vue&type=script&setup=true&lang.ts
|
package/dist/site.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as e, i as t, n, o as r, r as i, t as a } from "./use-active-section-
|
|
1
|
+
import { a as e, i as t, n, o as r, r as i, t as a } from "./use-active-section-qEJQS1S9.js";
|
|
2
2
|
import { Fragment as o, computed as s, createBlock as c, createCommentVNode as l, createElementBlock as u, createElementVNode as d, createTextVNode as f, createVNode as p, defineComponent as m, mergeModels as h, nextTick as g, normalizeClass as _, normalizeStyle as v, onBeforeUnmount as y, onMounted as b, onUnmounted as x, openBlock as S, ref as C, renderList as w, renderSlot as T, shallowRef as E, toDisplayString as D, unref as O, useId as k, useModel as ee, useSlots as A, useTemplateRef as te, watch as j, withCtx as M } from "vue";
|
|
3
3
|
import { tryOnMounted as N, usePreferredDark as P, useStorage as F } from "@vueuse/core";
|
|
4
4
|
//#region src/site/appearance.ts
|
|
@@ -250,7 +250,7 @@ var I = "tool-site-theme", L = (e) => e === "system" || e === "light" || e === "
|
|
|
250
250
|
}, [d("summary", {
|
|
251
251
|
class: "fg-site-rail__summary",
|
|
252
252
|
"aria-controls": O(t)
|
|
253
|
-
},
|
|
253
|
+
}, D(e.label), 9, pe), p(Z, {
|
|
254
254
|
"content-id": O(t),
|
|
255
255
|
label: e.label,
|
|
256
256
|
groups: e.groups,
|
|
@@ -264,7 +264,7 @@ var I = "tool-site-theme", L = (e) => e === "system" || e === "light" || e === "
|
|
|
264
264
|
key: 1,
|
|
265
265
|
open: l.value,
|
|
266
266
|
"onUpdate:open": h[0] ||= (e) => l.value = e,
|
|
267
|
-
title:
|
|
267
|
+
title: e.label,
|
|
268
268
|
onCloseAutoFocus: E
|
|
269
269
|
}, {
|
|
270
270
|
trigger: M(() => [p(r, {
|
|
@@ -272,7 +272,7 @@ var I = "tool-site-theme", L = (e) => e === "system" || e === "light" || e === "
|
|
|
272
272
|
size: "lg",
|
|
273
273
|
class: "fg-site-rail__toggle"
|
|
274
274
|
}, {
|
|
275
|
-
default: M(() => [
|
|
275
|
+
default: M(() => [f(D(e.label), 1)]),
|
|
276
276
|
_: 1
|
|
277
277
|
})]),
|
|
278
278
|
default: M(() => [p(Z, {
|
|
@@ -288,7 +288,7 @@ var I = "tool-site-theme", L = (e) => e === "system" || e === "light" || e === "
|
|
|
288
288
|
"active-id"
|
|
289
289
|
])]),
|
|
290
290
|
_: 1
|
|
291
|
-
}, 8, ["open"]))], 8, de));
|
|
291
|
+
}, 8, ["open", "title"]))], 8, de));
|
|
292
292
|
}
|
|
293
293
|
}), ge = [
|
|
294
294
|
"aria-label",
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { Fragment as e, computed as t, createBlock as n, createCommentVNode as r, createElementBlock as i, createElementVNode as a, createTextVNode as o, createVNode as s, defineComponent as c, mergeProps as l, onMounted as u, onUnmounted as d, openBlock as f, readonly as p, ref as m, renderList as h, renderSlot as g, toDisplayString as _, unref as v, useId as y,
|
|
2
|
-
import { DialogClose as
|
|
3
|
-
import { useTimeoutFn as
|
|
1
|
+
import { Fragment as e, computed as t, createBlock as n, createCommentVNode as r, createElementBlock as i, createElementVNode as a, createTextVNode as o, createVNode as s, defineComponent as c, mergeProps as l, onMounted as u, onUnmounted as d, openBlock as f, readonly as p, ref as m, renderList as h, renderSlot as g, toDisplayString as _, unref as v, useId as y, useTemplateRef as b, watch as x, withCtx as S } from "vue";
|
|
2
|
+
import { DialogClose as C, DialogContent as w, DialogDescription as T, DialogOverlay as E, DialogPortal as D, DialogRoot as O, DialogTitle as k, DialogTrigger as A, Primitive as j } from "reka-ui";
|
|
3
|
+
import { useTimeoutFn as M } from "@vueuse/core";
|
|
4
4
|
//#endregion
|
|
5
5
|
//#region src/components/UiButton.vue
|
|
6
|
-
var
|
|
6
|
+
var N = /* @__PURE__ */ c({
|
|
7
7
|
__name: "UiButton",
|
|
8
8
|
props: {
|
|
9
9
|
disabled: {
|
|
@@ -19,7 +19,7 @@ var j = /* @__PURE__ */ c({
|
|
|
19
19
|
variant: { default: "primary" }
|
|
20
20
|
},
|
|
21
21
|
setup(e) {
|
|
22
|
-
return (t, r) => (f(), n(v(
|
|
22
|
+
return (t, r) => (f(), n(v(j), {
|
|
23
23
|
as: "button",
|
|
24
24
|
class: "fg-button",
|
|
25
25
|
"data-size": e.size,
|
|
@@ -28,7 +28,7 @@ var j = /* @__PURE__ */ c({
|
|
|
28
28
|
disabled: e.disabled || e.loading,
|
|
29
29
|
type: e.type
|
|
30
30
|
}, {
|
|
31
|
-
default:
|
|
31
|
+
default: S(() => [g(t.$slots, "default")]),
|
|
32
32
|
_: 3
|
|
33
33
|
}, 8, [
|
|
34
34
|
"data-size",
|
|
@@ -38,8 +38,8 @@ var j = /* @__PURE__ */ c({
|
|
|
38
38
|
"type"
|
|
39
39
|
]));
|
|
40
40
|
}
|
|
41
|
-
}),
|
|
42
|
-
let n = m(!1), r = m(!1), i = m(""), { start: a } =
|
|
41
|
+
}), P = ({ unavailableMessage: e, failureMessage: t }) => {
|
|
42
|
+
let n = m(!1), r = m(!1), i = m(""), { start: a } = M(() => {
|
|
43
43
|
n.value = !1;
|
|
44
44
|
}, 1500, { immediate: !1 });
|
|
45
45
|
return {
|
|
@@ -61,10 +61,10 @@ var j = /* @__PURE__ */ c({
|
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
};
|
|
64
|
-
},
|
|
64
|
+
}, F = { class: "fg-dialog__header" }, I = { class: "fg-dialog__body" }, L = {
|
|
65
65
|
key: 0,
|
|
66
66
|
class: "fg-dialog__footer"
|
|
67
|
-
},
|
|
67
|
+
}, R = /* @__PURE__ */ c({
|
|
68
68
|
inheritAttrs: !1,
|
|
69
69
|
__name: "UiDialog",
|
|
70
70
|
props: {
|
|
@@ -75,34 +75,34 @@ var j = /* @__PURE__ */ c({
|
|
|
75
75
|
emits: ["update:open"],
|
|
76
76
|
setup(e, { emit: t }) {
|
|
77
77
|
let c = t;
|
|
78
|
-
return (t, u) => (f(), n(v(
|
|
78
|
+
return (t, u) => (f(), n(v(O), {
|
|
79
79
|
open: e.open,
|
|
80
80
|
"onUpdate:open": u[0] ||= (e) => c("update:open", e)
|
|
81
81
|
}, {
|
|
82
|
-
default:
|
|
83
|
-
default:
|
|
82
|
+
default: S(() => [s(v(D), null, {
|
|
83
|
+
default: S(() => [s(v(E), { class: "fg-dialog__overlay" }), s(v(w), l({
|
|
84
84
|
class: "fg-dialog__content",
|
|
85
85
|
"aria-modal": "true"
|
|
86
86
|
}, t.$attrs), {
|
|
87
|
-
default:
|
|
88
|
-
a("div",
|
|
89
|
-
default:
|
|
87
|
+
default: S(() => [
|
|
88
|
+
a("div", F, [a("div", null, [s(v(k), { class: "fg-dialog__title" }, {
|
|
89
|
+
default: S(() => [o(_(e.title), 1)]),
|
|
90
90
|
_: 1
|
|
91
|
-
}), e.description ? (f(), n(v(
|
|
91
|
+
}), e.description ? (f(), n(v(T), {
|
|
92
92
|
key: 0,
|
|
93
93
|
class: "fg-dialog__description"
|
|
94
94
|
}, {
|
|
95
|
-
default:
|
|
95
|
+
default: S(() => [o(_(e.description), 1)]),
|
|
96
96
|
_: 1
|
|
97
|
-
})) : r("", !0)]), s(v(
|
|
97
|
+
})) : r("", !0)]), s(v(C), {
|
|
98
98
|
class: "fg-dialog__close",
|
|
99
99
|
"aria-label": "Close dialog"
|
|
100
100
|
}, {
|
|
101
|
-
default:
|
|
101
|
+
default: S(() => [...u[1] ||= [o(" × ", -1)]]),
|
|
102
102
|
_: 1
|
|
103
103
|
})]),
|
|
104
|
-
a("div",
|
|
105
|
-
t.$slots.footer ? (f(), i("div",
|
|
104
|
+
a("div", I, [g(t.$slots, "default")]),
|
|
105
|
+
t.$slots.footer ? (f(), i("div", L, [g(t.$slots, "footer")])) : r("", !0)
|
|
106
106
|
]),
|
|
107
107
|
_: 3
|
|
108
108
|
}, 16)]),
|
|
@@ -111,7 +111,7 @@ var j = /* @__PURE__ */ c({
|
|
|
111
111
|
_: 3
|
|
112
112
|
}, 8, ["open"]));
|
|
113
113
|
}
|
|
114
|
-
}),
|
|
114
|
+
}), z = { class: "fg-drawer__header" }, B = { class: "fg-drawer__body" }, V = /* @__PURE__ */ c({
|
|
115
115
|
inheritAttrs: !1,
|
|
116
116
|
__name: "UiDrawer",
|
|
117
117
|
props: {
|
|
@@ -121,32 +121,32 @@ var j = /* @__PURE__ */ c({
|
|
|
121
121
|
emits: ["update:open", "closeAutoFocus"],
|
|
122
122
|
setup(e, { emit: t }) {
|
|
123
123
|
let i = t;
|
|
124
|
-
return (t, c) => (f(), n(v(
|
|
124
|
+
return (t, c) => (f(), n(v(O), {
|
|
125
125
|
open: e.open,
|
|
126
126
|
"onUpdate:open": c[1] ||= (e) => i("update:open", e)
|
|
127
127
|
}, {
|
|
128
|
-
default:
|
|
128
|
+
default: S(() => [t.$slots.trigger ? (f(), n(v(A), {
|
|
129
129
|
key: 0,
|
|
130
130
|
"as-child": ""
|
|
131
131
|
}, {
|
|
132
|
-
default:
|
|
132
|
+
default: S(() => [g(t.$slots, "trigger")]),
|
|
133
133
|
_: 3
|
|
134
|
-
})) : r("", !0), s(v(
|
|
135
|
-
default:
|
|
134
|
+
})) : r("", !0), s(v(D), null, {
|
|
135
|
+
default: S(() => [s(v(E), { class: "fg-drawer__overlay" }), s(v(w), l({
|
|
136
136
|
class: "fg-drawer__content",
|
|
137
137
|
"aria-modal": "true",
|
|
138
138
|
"aria-describedby": void 0
|
|
139
139
|
}, t.$attrs, { onCloseAutoFocus: c[0] ||= (e) => i("closeAutoFocus", e) }), {
|
|
140
|
-
default:
|
|
141
|
-
default:
|
|
140
|
+
default: S(() => [a("div", z, [s(v(k), { class: "fg-drawer__title" }, {
|
|
141
|
+
default: S(() => [o(_(e.title), 1)]),
|
|
142
142
|
_: 1
|
|
143
|
-
}), s(v(
|
|
143
|
+
}), s(v(C), {
|
|
144
144
|
class: "fg-drawer__close",
|
|
145
145
|
"aria-label": "Close drawer"
|
|
146
146
|
}, {
|
|
147
|
-
default:
|
|
147
|
+
default: S(() => [...c[2] ||= [o(" × ", -1)]]),
|
|
148
148
|
_: 1
|
|
149
|
-
})]), a("div",
|
|
149
|
+
})]), a("div", B, [g(t.$slots, "default")])]),
|
|
150
150
|
_: 3
|
|
151
151
|
}, 16)]),
|
|
152
152
|
_: 3
|
|
@@ -154,20 +154,20 @@ var j = /* @__PURE__ */ c({
|
|
|
154
154
|
_: 3
|
|
155
155
|
}, 8, ["open"]));
|
|
156
156
|
}
|
|
157
|
-
}),
|
|
157
|
+
}), H = { class: "fg-tabs" }, U = ["aria-label"], W = [
|
|
158
158
|
"id",
|
|
159
159
|
"aria-controls",
|
|
160
160
|
"aria-selected",
|
|
161
161
|
"tabindex",
|
|
162
162
|
"onClick",
|
|
163
163
|
"onFocus"
|
|
164
|
-
],
|
|
164
|
+
], G = [
|
|
165
165
|
"id",
|
|
166
166
|
"role",
|
|
167
167
|
"aria-labelledby",
|
|
168
168
|
"hidden",
|
|
169
169
|
"tabindex"
|
|
170
|
-
],
|
|
170
|
+
], K = ["id", "hidden"], q = /* @__PURE__ */ c({
|
|
171
171
|
__name: "UiTabs",
|
|
172
172
|
props: {
|
|
173
173
|
items: {},
|
|
@@ -176,13 +176,20 @@ var j = /* @__PURE__ */ c({
|
|
|
176
176
|
},
|
|
177
177
|
emits: ["update:modelValue"],
|
|
178
178
|
setup(n, { emit: o }) {
|
|
179
|
-
let s = o, c = y(), l = m(!1), d = t(() => n.items.some((e) => e.value === n.modelValue) ? n.modelValue : n.items[0]?.value), p = (e) => `${c}-tab-${encodeURIComponent(e)}`, v = (e) => `${c}-panel-${encodeURIComponent(e)}`,
|
|
179
|
+
let s = o, c = y(), l = m(!1), d = t(() => n.items.some((e) => e.value === n.modelValue) ? n.modelValue : n.items[0]?.value), p = (e) => `${c}-tab-${encodeURIComponent(e)}`, v = (e) => `${c}-panel-${encodeURIComponent(e)}`, S = (e) => `${c}-heading-${encodeURIComponent(e)}`;
|
|
180
180
|
u(() => {
|
|
181
181
|
l.value = !0;
|
|
182
182
|
});
|
|
183
|
-
let
|
|
183
|
+
let C = b("list");
|
|
184
|
+
x([l, d], () => {
|
|
185
|
+
let e = C.value, t = e?.querySelector("[aria-selected=\"true\"]");
|
|
186
|
+
if (!e || !t) return;
|
|
187
|
+
let n = e.getBoundingClientRect(), { left: r, right: i } = t.getBoundingClientRect();
|
|
188
|
+
r < n.left ? e.scrollLeft -= n.left - r : i > n.right && (e.scrollLeft += i - n.right);
|
|
189
|
+
}, { flush: "post" });
|
|
190
|
+
let w = (e) => {
|
|
184
191
|
e !== d.value && s("update:modelValue", e);
|
|
185
|
-
},
|
|
192
|
+
}, T = (e) => {
|
|
186
193
|
if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey || ![
|
|
187
194
|
"ArrowLeft",
|
|
188
195
|
"ArrowRight",
|
|
@@ -194,14 +201,19 @@ var j = /* @__PURE__ */ c({
|
|
|
194
201
|
let r = [...t.querySelectorAll("[role=\"tab\"]")], i = r.indexOf(n);
|
|
195
202
|
if (i < 0 || r.length === 0) return;
|
|
196
203
|
let a = getComputedStyle(t).direction === "rtl", o = e.key === (a ? "ArrowRight" : "ArrowLeft"), s = r[e.key === "Home" ? 0 : e.key === "End" ? r.length - 1 : (i + (o ? -1 : 1) + r.length) % r.length];
|
|
197
|
-
s && (e.preventDefault(), s.focus()
|
|
204
|
+
s && (e.preventDefault(), s.focus(), s.scrollIntoView({
|
|
205
|
+
block: "nearest",
|
|
206
|
+
inline: "nearest"
|
|
207
|
+
}));
|
|
198
208
|
};
|
|
199
|
-
return (t, o) => (f(), i("div",
|
|
209
|
+
return (t, o) => (f(), i("div", H, [l.value ? (f(), i("div", {
|
|
200
210
|
key: 0,
|
|
211
|
+
ref_key: "list",
|
|
212
|
+
ref: C,
|
|
201
213
|
class: "fg-tabs__list",
|
|
202
214
|
role: "tablist",
|
|
203
215
|
"aria-label": n.label,
|
|
204
|
-
onKeydown:
|
|
216
|
+
onKeydown: T
|
|
205
217
|
}, [(f(!0), i(e, null, h(n.items, (e) => (f(), i("button", {
|
|
206
218
|
id: p(e.value),
|
|
207
219
|
key: e.value,
|
|
@@ -211,23 +223,23 @@ var j = /* @__PURE__ */ c({
|
|
|
211
223
|
"aria-controls": v(e.value),
|
|
212
224
|
"aria-selected": e.value === d.value,
|
|
213
225
|
tabindex: e.value === d.value ? 0 : -1,
|
|
214
|
-
onClick: (t) =>
|
|
215
|
-
onFocus: (t) =>
|
|
216
|
-
}, _(e.label), 41,
|
|
226
|
+
onClick: (t) => w(e.value),
|
|
227
|
+
onFocus: (t) => w(e.value)
|
|
228
|
+
}, _(e.label), 41, W))), 128))], 40, U)) : r("", !0), (f(!0), i(e, null, h(n.items, (e) => (f(), i("section", {
|
|
217
229
|
id: v(e.value),
|
|
218
230
|
key: e.value,
|
|
219
231
|
class: "fg-tabs__panel",
|
|
220
232
|
role: l.value ? "tabpanel" : void 0,
|
|
221
|
-
"aria-labelledby": l.value ? p(e.value) :
|
|
233
|
+
"aria-labelledby": l.value ? p(e.value) : S(e.value),
|
|
222
234
|
hidden: l.value && e.value !== d.value,
|
|
223
235
|
tabindex: l.value ? 0 : void 0
|
|
224
236
|
}, [a("h3", {
|
|
225
|
-
id:
|
|
237
|
+
id: S(e.value),
|
|
226
238
|
class: "fg-tabs__heading",
|
|
227
239
|
hidden: l.value
|
|
228
|
-
}, _(e.label), 9,
|
|
240
|
+
}, _(e.label), 9, K), g(t.$slots, "panel", { value: e.value })], 8, G))), 128))]));
|
|
229
241
|
}
|
|
230
|
-
}),
|
|
242
|
+
}), J = ({ targetIds: e }) => {
|
|
231
243
|
let t = m(e[0]), n, r, i;
|
|
232
244
|
return u(() => {
|
|
233
245
|
let a = e.flatMap((e) => {
|
|
@@ -252,4 +264,4 @@ var j = /* @__PURE__ */ c({
|
|
|
252
264
|
}), p(t);
|
|
253
265
|
};
|
|
254
266
|
//#endregion
|
|
255
|
-
export {
|
|
267
|
+
export { P as a, R as i, q as n, N as o, V as r, J as t };
|
package/package.json
CHANGED
package/src/components/tabs.css
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
|
|
33
33
|
.fg-tabs__tab:hover { color: var(--color-text); }
|
|
34
34
|
.fg-tabs__tab[aria-selected="true"] {
|
|
35
|
-
border-bottom-color: var(--color-
|
|
35
|
+
border-bottom-color: var(--color-accent);
|
|
36
36
|
color: var(--color-text);
|
|
37
37
|
}
|
|
38
38
|
|
|
@@ -44,10 +44,15 @@
|
|
|
44
44
|
font-weight: var(--weight-medium);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
/* Inset: the tab list scrolls sideways, which would clip an outer ring. */
|
|
48
|
+
.fg-tabs__tab:focus-visible {
|
|
48
49
|
outline: 2px solid var(--color-focus);
|
|
49
50
|
outline-offset: -2px;
|
|
50
51
|
}
|
|
52
|
+
.fg-tabs__panel:focus-visible {
|
|
53
|
+
outline: 2px solid var(--color-focus);
|
|
54
|
+
outline-offset: 2px;
|
|
55
|
+
}
|
|
51
56
|
|
|
52
57
|
@media (max-width: 640px) {
|
|
53
58
|
.fg-tabs__tab { min-height: var(--control-lg); }
|
package/src/components.css
CHANGED
|
@@ -24,16 +24,16 @@
|
|
|
24
24
|
.fg-code-block__header {
|
|
25
25
|
display: flex;
|
|
26
26
|
align-items: center;
|
|
27
|
-
gap:
|
|
27
|
+
gap: var(--space-3);
|
|
28
28
|
min-height: 2.5rem;
|
|
29
|
-
padding: 0.35rem
|
|
29
|
+
padding: 0.35rem var(--space-3);
|
|
30
30
|
border-bottom: 1px solid color-mix(in srgb, var(--color-code-text) 16%, transparent);
|
|
31
31
|
background: color-mix(in srgb, var(--color-code-text) 5%, var(--color-code));
|
|
32
|
-
font-size:
|
|
32
|
+
font-size: var(--text-xs);
|
|
33
33
|
}
|
|
34
34
|
.fg-code-block__title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
|
|
35
35
|
.fg-code-block__language { opacity: 0.7; }
|
|
36
|
-
.fg-code-block__actions { display: flex; align-items: center; gap:
|
|
36
|
+
.fg-code-block__actions { display: flex; align-items: center; gap: var(--space-2); margin-left: auto; flex-shrink: 0; }
|
|
37
37
|
.fg-code-block__copy {
|
|
38
38
|
display: inline-flex;
|
|
39
39
|
align-items: center;
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
gap: 0.4rem;
|
|
42
42
|
min-width: var(--control-lg);
|
|
43
43
|
min-height: var(--control-lg);
|
|
44
|
-
padding:
|
|
44
|
+
padding: var(--space-1) 0.4rem;
|
|
45
45
|
border: 0;
|
|
46
|
-
border-radius:
|
|
46
|
+
border-radius: var(--radius-inline);
|
|
47
47
|
background: transparent;
|
|
48
48
|
color: inherit;
|
|
49
49
|
font: inherit;
|
|
@@ -51,16 +51,18 @@
|
|
|
51
51
|
}
|
|
52
52
|
.fg-code-block__copy:hover { background: color-mix(in srgb, currentColor 12%, transparent); }
|
|
53
53
|
.fg-code-block__copy svg { width: 1rem; height: 1rem; }
|
|
54
|
-
|
|
55
|
-
.fg-code-block__pre {
|
|
56
|
-
.fg-
|
|
54
|
+
/* Inset: the code block clips its content. */
|
|
55
|
+
.fg-code-block__copy:focus-visible, .fg-code-block__pre:focus-visible { outline: 2px solid var(--color-focus); outline-offset: -2px; }
|
|
56
|
+
.fg-figure__plate:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
|
|
57
|
+
.fg-code-block__pre { margin: 0; padding: var(--space-4); overflow: auto; max-height: 32rem; tab-size: 2; }
|
|
58
|
+
.fg-code-block__pre, .fg-code-block__pre code { font-family: var(--font-mono); font-size: var(--text-sm); line-height: 1.65; }
|
|
57
59
|
.fg-code-block__pre code { display: block; color: inherit; }
|
|
58
60
|
.fg-code-block__line { display: flex; min-height: 1.65em; }
|
|
59
61
|
.fg-code-block__text { white-space: pre; }
|
|
60
62
|
.fg-code-block__number { min-width: 2.5em; padding-right: 1em; flex-shrink: 0; text-align: right; opacity: 0.5; user-select: none; }
|
|
61
63
|
.fg-code-block[data-wrap="true"] .fg-code-block__text { min-width: 0; white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
62
64
|
.fg-code-block__status:empty { display: none; }
|
|
63
|
-
.fg-code-block__status:not(:empty) { display: block; padding:
|
|
65
|
+
.fg-code-block__status:not(:empty) { display: block; padding: var(--space-2) var(--space-3); font-size: var(--text-xs); }
|
|
64
66
|
.fg-code-block[data-variant="compact"] {
|
|
65
67
|
position: relative;
|
|
66
68
|
display: grid;
|
|
@@ -120,7 +122,7 @@
|
|
|
120
122
|
display: inline-flex;
|
|
121
123
|
align-items: center;
|
|
122
124
|
justify-content: center;
|
|
123
|
-
gap:
|
|
125
|
+
gap: var(--space-2);
|
|
124
126
|
color: var(--color-button-text);
|
|
125
127
|
background: var(--color-button-bg);
|
|
126
128
|
box-shadow: none;
|
|
@@ -165,19 +167,19 @@
|
|
|
165
167
|
.fg-button[data-size="sm"],
|
|
166
168
|
.fg-input[data-size="sm"],
|
|
167
169
|
.fg-select[data-size="sm"] {
|
|
168
|
-
font-size:
|
|
170
|
+
font-size: var(--text-sm);
|
|
169
171
|
}
|
|
170
172
|
|
|
171
173
|
.fg-button[data-size="md"],
|
|
172
174
|
.fg-input[data-size="md"],
|
|
173
175
|
.fg-select[data-size="md"] {
|
|
174
|
-
font-size:
|
|
176
|
+
font-size: var(--text-md);
|
|
175
177
|
}
|
|
176
178
|
|
|
177
179
|
.fg-button[data-size="lg"],
|
|
178
180
|
.fg-input[data-size="lg"],
|
|
179
181
|
.fg-select[data-size="lg"] {
|
|
180
|
-
font-size:
|
|
182
|
+
font-size: var(--text-lg);
|
|
181
183
|
}
|
|
182
184
|
|
|
183
185
|
.fg-button[data-size="sm"] { min-height: var(--control-sm); }
|
|
@@ -191,20 +193,20 @@
|
|
|
191
193
|
.fg-select[data-size="lg"] { height: var(--control-lg); }
|
|
192
194
|
|
|
193
195
|
.fg-button[data-size="sm"] { padding: 0 0.6rem; }
|
|
194
|
-
.fg-button[data-size="md"] { padding: 0
|
|
195
|
-
.fg-button[data-size="lg"] { padding: 0
|
|
196
|
+
.fg-button[data-size="md"] { padding: 0 var(--space-3); }
|
|
197
|
+
.fg-button[data-size="lg"] { padding: 0 var(--space-4); }
|
|
196
198
|
|
|
197
199
|
/* Deprecated UiButton aliases retained for existing consumers. */
|
|
198
200
|
.fg-button[data-size="compact"] {
|
|
199
201
|
min-height: var(--control-md);
|
|
200
202
|
padding: 0 0.7rem;
|
|
201
|
-
font-size:
|
|
203
|
+
font-size: var(--text-sm);
|
|
202
204
|
}
|
|
203
205
|
|
|
204
206
|
.fg-button[data-size="default"] {
|
|
205
207
|
min-height: var(--control-lg);
|
|
206
|
-
padding: 0
|
|
207
|
-
font-size:
|
|
208
|
+
padding: 0 var(--space-4);
|
|
209
|
+
font-size: var(--text-lg);
|
|
208
210
|
}
|
|
209
211
|
|
|
210
212
|
.fg-button[data-variant="secondary"] {
|
|
@@ -241,7 +243,7 @@
|
|
|
241
243
|
.fg-button[data-variant="text"] {
|
|
242
244
|
height: auto;
|
|
243
245
|
min-height: auto;
|
|
244
|
-
padding:
|
|
246
|
+
padding: var(--space-1);
|
|
245
247
|
color: var(--color-link);
|
|
246
248
|
background: transparent;
|
|
247
249
|
text-decoration: underline;
|
|
@@ -323,9 +325,11 @@
|
|
|
323
325
|
cursor: pointer;
|
|
324
326
|
}
|
|
325
327
|
.fg-select:not([multiple]):not([size]) option:checked { color: var(--color-row-selected-text); background: var(--color-row-selected); }
|
|
326
|
-
|
|
328
|
+
/* Pointer hover only fills the row; the focus ring marks the keyboard position. Inset: the picker scrolls. */
|
|
329
|
+
.fg-select:not([multiple]):not([size]) option:hover:not(:disabled) { background: var(--color-row-hover); }
|
|
330
|
+
.fg-select:not([multiple]):not([size]) option:focus-visible { background: var(--color-row-hover); outline: 2px solid var(--color-focus); outline-offset: -2px; }
|
|
327
331
|
.fg-select:not([multiple]):not([size]) option:disabled { color: var(--color-muted); opacity: 0.58; cursor: not-allowed; }
|
|
328
|
-
.fg-select:not([multiple]):not([size]) option::checkmark { order: 1; margin-left: auto; color: var(--color-
|
|
332
|
+
.fg-select:not([multiple]):not([size]) option::checkmark { order: 1; margin-left: auto; color: var(--color-accent); }
|
|
329
333
|
@media (pointer: coarse) {
|
|
330
334
|
.fg-select:not([multiple]):not([size]) option { min-height: var(--control-lg); }
|
|
331
335
|
}
|
|
@@ -335,7 +339,7 @@
|
|
|
335
339
|
.fg-input[data-size="md"] { padding: 0 0.65rem; }
|
|
336
340
|
.fg-input[data-size="lg"] { padding: 0 0.7rem; }
|
|
337
341
|
|
|
338
|
-
.fg-select[data-size="sm"] { padding: 0 1.6rem 0
|
|
342
|
+
.fg-select[data-size="sm"] { padding: 0 1.6rem 0 var(--space-2); }
|
|
339
343
|
.fg-select[data-size="md"] { padding: 0 1.7rem 0 0.6rem; }
|
|
340
344
|
.fg-select[data-size="lg"] { padding: 0 1.8rem 0 0.7rem; }
|
|
341
345
|
|
|
@@ -357,14 +361,14 @@
|
|
|
357
361
|
|
|
358
362
|
.fg-field__label {
|
|
359
363
|
color: var(--color-text);
|
|
360
|
-
font-size:
|
|
364
|
+
font-size: var(--text-sm);
|
|
361
365
|
font-weight: 600;
|
|
362
366
|
}
|
|
363
367
|
|
|
364
368
|
.fg-field__description,
|
|
365
369
|
.fg-field__error {
|
|
366
370
|
margin: 0;
|
|
367
|
-
font-size:
|
|
371
|
+
font-size: var(--text-sm);
|
|
368
372
|
}
|
|
369
373
|
|
|
370
374
|
.fg-field__description { color: var(--color-muted); }
|
|
@@ -409,21 +413,21 @@
|
|
|
409
413
|
min-height: var(--control-sm);
|
|
410
414
|
align-items: center;
|
|
411
415
|
gap: 0.45rem;
|
|
412
|
-
font-size:
|
|
416
|
+
font-size: var(--text-sm);
|
|
413
417
|
}
|
|
414
418
|
|
|
415
419
|
.fg-checkbox[data-size="md"] {
|
|
416
420
|
min-height: var(--control-md);
|
|
417
421
|
align-items: center;
|
|
418
422
|
gap: 0.55rem;
|
|
419
|
-
font-size:
|
|
423
|
+
font-size: var(--text-md);
|
|
420
424
|
}
|
|
421
425
|
|
|
422
426
|
.fg-checkbox[data-size="lg"] {
|
|
423
427
|
min-height: var(--control-lg);
|
|
424
428
|
align-items: center;
|
|
425
429
|
gap: 0.65rem;
|
|
426
|
-
font-size:
|
|
430
|
+
font-size: var(--text-lg);
|
|
427
431
|
}
|
|
428
432
|
|
|
429
433
|
.fg-checkbox[data-size] .fg-checkbox__control { margin-top: 0; }
|
|
@@ -431,7 +435,7 @@
|
|
|
431
435
|
.fg-checkbox[data-size="sm"] .fg-checkbox__control {
|
|
432
436
|
width: 1rem;
|
|
433
437
|
height: 1rem;
|
|
434
|
-
border-radius:
|
|
438
|
+
border-radius: var(--radius-inline);
|
|
435
439
|
}
|
|
436
440
|
|
|
437
441
|
.fg-checkbox[data-size="md"] .fg-checkbox__control {
|
|
@@ -451,14 +455,14 @@
|
|
|
451
455
|
.fg-radio-card-group {
|
|
452
456
|
display: grid;
|
|
453
457
|
grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
|
|
454
|
-
gap:
|
|
458
|
+
gap: var(--space-3);
|
|
455
459
|
}
|
|
456
460
|
|
|
457
461
|
.fg-radio-card {
|
|
458
462
|
position: relative;
|
|
459
463
|
display: block;
|
|
460
464
|
min-width: 0;
|
|
461
|
-
padding:
|
|
465
|
+
padding: var(--space-3);
|
|
462
466
|
overflow: hidden;
|
|
463
467
|
border: 1px solid var(--color-border-subtle);
|
|
464
468
|
border-radius: var(--radius-panel);
|
|
@@ -474,9 +478,10 @@
|
|
|
474
478
|
border-color: var(--color-border);
|
|
475
479
|
}
|
|
476
480
|
|
|
481
|
+
/* Checked choices use the accent, as the checkbox does; blue stays for links and focus. */
|
|
477
482
|
.fg-radio-card[data-state="checked"] {
|
|
478
|
-
border-color: var(--color-
|
|
479
|
-
outline: 1px solid var(--color-
|
|
483
|
+
border-color: var(--color-accent);
|
|
484
|
+
outline: 1px solid var(--color-accent);
|
|
480
485
|
outline-offset: -2px;
|
|
481
486
|
}
|
|
482
487
|
|
|
@@ -488,15 +493,15 @@
|
|
|
488
493
|
.fg-radio-card__content {
|
|
489
494
|
display: grid;
|
|
490
495
|
min-width: 0;
|
|
491
|
-
gap:
|
|
496
|
+
gap: var(--space-1);
|
|
492
497
|
padding-right: 1.75rem;
|
|
493
498
|
}
|
|
494
499
|
|
|
495
500
|
.fg-radio-card__indicator {
|
|
496
501
|
position: absolute;
|
|
497
502
|
z-index: 1;
|
|
498
|
-
top:
|
|
499
|
-
right:
|
|
503
|
+
top: var(--space-3);
|
|
504
|
+
right: var(--space-3);
|
|
500
505
|
display: block;
|
|
501
506
|
width: 1rem;
|
|
502
507
|
height: 1rem;
|
|
@@ -506,7 +511,7 @@
|
|
|
506
511
|
}
|
|
507
512
|
|
|
508
513
|
.fg-radio-card[data-state="checked"] .fg-radio-card__indicator {
|
|
509
|
-
border: 0.3rem solid var(--color-
|
|
514
|
+
border: 0.3rem solid var(--color-accent);
|
|
510
515
|
}
|
|
511
516
|
|
|
512
517
|
.fg-badge {
|
|
@@ -518,7 +523,7 @@
|
|
|
518
523
|
padding: 0.18rem 0.48rem;
|
|
519
524
|
color: var(--color-muted);
|
|
520
525
|
background: var(--color-surface-muted);
|
|
521
|
-
font-size:
|
|
526
|
+
font-size: var(--text-xs);
|
|
522
527
|
font-weight: 500;
|
|
523
528
|
line-height: 1.25;
|
|
524
529
|
}
|
|
@@ -532,8 +537,8 @@
|
|
|
532
537
|
.fg-alert {
|
|
533
538
|
display: flex;
|
|
534
539
|
align-items: flex-start;
|
|
535
|
-
gap:
|
|
536
|
-
padding:
|
|
540
|
+
gap: var(--space-3);
|
|
541
|
+
padding: var(--space-3) var(--space-4);
|
|
537
542
|
border: 1px solid var(--color-border-subtle);
|
|
538
543
|
border-radius: var(--radius-control);
|
|
539
544
|
color: var(--color-text);
|
|
@@ -557,8 +562,8 @@
|
|
|
557
562
|
box-shadow: none;
|
|
558
563
|
}
|
|
559
564
|
|
|
560
|
-
.fg-surface[data-padding="compact"] { padding:
|
|
561
|
-
.fg-surface[data-padding="default"] { padding:
|
|
565
|
+
.fg-surface[data-padding="compact"] { padding: var(--space-3); }
|
|
566
|
+
.fg-surface[data-padding="default"] { padding: var(--space-4); }
|
|
562
567
|
|
|
563
568
|
.fg-card {
|
|
564
569
|
min-width: 0;
|
|
@@ -800,8 +805,8 @@
|
|
|
800
805
|
top: 50%;
|
|
801
806
|
left: 50%;
|
|
802
807
|
display: grid;
|
|
803
|
-
width: min(32rem, calc(100vw -
|
|
804
|
-
max-height: min(42rem, calc(100vh -
|
|
808
|
+
width: min(32rem, calc(100vw - var(--space-8)));
|
|
809
|
+
max-height: min(42rem, calc(100vh - var(--space-8)));
|
|
805
810
|
overflow: hidden;
|
|
806
811
|
transform: translate(-50%, -50%);
|
|
807
812
|
border: 1px solid var(--color-border-subtle);
|
|
@@ -816,8 +821,8 @@
|
|
|
816
821
|
display: flex;
|
|
817
822
|
align-items: flex-start;
|
|
818
823
|
justify-content: space-between;
|
|
819
|
-
gap:
|
|
820
|
-
padding:
|
|
824
|
+
gap: var(--space-4);
|
|
825
|
+
padding: var(--space-4);
|
|
821
826
|
}
|
|
822
827
|
|
|
823
828
|
.fg-dialog__header { border-bottom: 1px solid var(--color-border-subtle); }
|
|
@@ -831,21 +836,21 @@
|
|
|
831
836
|
}
|
|
832
837
|
|
|
833
838
|
.fg-dialog__description {
|
|
834
|
-
margin:
|
|
839
|
+
margin: var(--space-1) 0 0;
|
|
835
840
|
color: var(--color-muted);
|
|
836
|
-
font-size:
|
|
841
|
+
font-size: var(--text-md);
|
|
837
842
|
}
|
|
838
843
|
|
|
839
844
|
.fg-dialog__body {
|
|
840
845
|
min-height: 0;
|
|
841
846
|
overflow: auto;
|
|
842
|
-
padding:
|
|
847
|
+
padding: var(--space-4);
|
|
843
848
|
}
|
|
844
849
|
|
|
845
850
|
.fg-dialog__close {
|
|
846
851
|
display: inline-grid;
|
|
847
852
|
flex: none;
|
|
848
|
-
width:
|
|
853
|
+
width: var(--control-lg);
|
|
849
854
|
min-height: var(--control-lg);
|
|
850
855
|
padding: 0;
|
|
851
856
|
place-items: center;
|
|
@@ -895,7 +900,7 @@
|
|
|
895
900
|
bottom: 0;
|
|
896
901
|
left: 0;
|
|
897
902
|
width: 100%;
|
|
898
|
-
max-height: calc(100vh -
|
|
903
|
+
max-height: calc(100vh - var(--space-4));
|
|
899
904
|
transform: none;
|
|
900
905
|
border-radius: var(--radius-panel) var(--radius-panel) 0 0;
|
|
901
906
|
}
|
package/src/site.css
CHANGED
|
@@ -1,7 +1,113 @@
|
|
|
1
1
|
/* Shared chrome and page helpers for the project sites. Use with
|
|
2
2
|
* @filipgutica/ui/themes/graphite-indigo.css, which supplies the type, space, and
|
|
3
3
|
* page-measure roles this file reads. Nothing here targets site-specific markup. */
|
|
4
|
+
/* Element defaults for a docs page inside .fg-site-docs. They sit in the base layer, so
|
|
5
|
+
* library components and the site's own rules win, as long as the site declares the layer
|
|
6
|
+
* order first (Tailwind's import does, or write @layer base, components, utilities;).
|
|
7
|
+
* Pages without .fg-site-docs get none of them. */
|
|
8
|
+
@layer base {
|
|
9
|
+
html:has(.fg-site-docs) { scroll-padding-top: var(--space-6); }
|
|
10
|
+
body:has(.fg-site-docs) {
|
|
11
|
+
margin: 0;
|
|
12
|
+
background: var(--color-bg);
|
|
13
|
+
color: var(--color-text);
|
|
14
|
+
font: var(--text-md) / var(--leading) var(--font-ui);
|
|
15
|
+
-webkit-font-smoothing: antialiased;
|
|
16
|
+
}
|
|
17
|
+
.fg-site-docs,
|
|
18
|
+
.fg-site-docs *,
|
|
19
|
+
.fg-site-docs *::before,
|
|
20
|
+
.fg-site-docs *::after { box-sizing: border-box; }
|
|
21
|
+
.fg-site-docs :where(h1, h2, h3, p, dl, dd, figure) { margin: 0; }
|
|
22
|
+
.fg-site-docs :where(h1, h2, h3) {
|
|
23
|
+
font-weight: var(--weight-semibold);
|
|
24
|
+
line-height: var(--leading-tight);
|
|
25
|
+
text-wrap: balance;
|
|
26
|
+
}
|
|
27
|
+
.fg-site-docs :where(h1) { max-width: 22ch; font-size: var(--text-3xl); letter-spacing: var(--tracking-tight); }
|
|
28
|
+
.fg-site-docs :where(h2) { font-size: var(--text-xl); }
|
|
29
|
+
.fg-site-docs :where(p) { max-width: var(--measure); }
|
|
30
|
+
.fg-site-docs :where(code, kbd, pre) { font-family: var(--font-mono); }
|
|
31
|
+
.fg-site-docs :where(a) { color: var(--color-link); text-underline-offset: 0.18em; }
|
|
32
|
+
.fg-site-docs :where(kbd) {
|
|
33
|
+
display: inline-block;
|
|
34
|
+
padding: 0 var(--space-1);
|
|
35
|
+
border: 1px solid var(--color-border);
|
|
36
|
+
border-bottom-width: 2px;
|
|
37
|
+
border-radius: var(--radius-inline);
|
|
38
|
+
background: var(--color-surface);
|
|
39
|
+
font-size: var(--text-xs);
|
|
40
|
+
white-space: nowrap;
|
|
41
|
+
}
|
|
42
|
+
.fg-site-docs :where(:focus-visible) { outline: 2px solid var(--color-focus); outline-offset: 2px; }
|
|
43
|
+
}
|
|
44
|
+
|
|
4
45
|
@layer components {
|
|
46
|
+
/* Docs shell: header across the top, the --sidebar rail beside main, and the footer
|
|
47
|
+
* on the frame edges. Header, rail, main, and footer are direct children. */
|
|
48
|
+
.fg-site-docs {
|
|
49
|
+
display: grid;
|
|
50
|
+
grid-template-columns: var(--sidebar) minmax(0, 1fr);
|
|
51
|
+
column-gap: var(--space-8);
|
|
52
|
+
max-width: calc(var(--page-max) + var(--sidebar) + var(--space-8) + var(--space-12));
|
|
53
|
+
margin-inline: auto;
|
|
54
|
+
padding-inline: var(--space-6);
|
|
55
|
+
}
|
|
56
|
+
.fg-site-docs > .fg-site-header {
|
|
57
|
+
--site-frame: 100%;
|
|
58
|
+
--site-gutter: 0px;
|
|
59
|
+
grid-column: 1 / -1;
|
|
60
|
+
min-width: 0;
|
|
61
|
+
}
|
|
62
|
+
.fg-site-docs > main {
|
|
63
|
+
display: grid;
|
|
64
|
+
grid-template-columns: minmax(0, 1fr);
|
|
65
|
+
gap: var(--space-12);
|
|
66
|
+
min-width: 0;
|
|
67
|
+
padding-block: var(--space-8) var(--space-16);
|
|
68
|
+
}
|
|
69
|
+
.fg-site-docs > .fg-site-footer { grid-column: 1 / -1; }
|
|
70
|
+
|
|
71
|
+
/* Footer: an attribution link at the start, project links in a nav at the end. */
|
|
72
|
+
.fg-site-footer {
|
|
73
|
+
display: flex;
|
|
74
|
+
flex-wrap: wrap;
|
|
75
|
+
align-items: center;
|
|
76
|
+
justify-content: space-between;
|
|
77
|
+
gap: 0 var(--space-5);
|
|
78
|
+
padding-block: var(--space-6) var(--space-8);
|
|
79
|
+
border-top: 1px solid var(--color-border-subtle);
|
|
80
|
+
color: var(--color-muted);
|
|
81
|
+
font-size: var(--text-sm);
|
|
82
|
+
}
|
|
83
|
+
.fg-site-footer nav { display: flex; flex-wrap: wrap; gap: 0 var(--space-5); }
|
|
84
|
+
.fg-site-footer a {
|
|
85
|
+
display: inline-flex;
|
|
86
|
+
min-height: var(--control-lg);
|
|
87
|
+
align-items: center;
|
|
88
|
+
color: var(--color-muted);
|
|
89
|
+
text-decoration: none;
|
|
90
|
+
}
|
|
91
|
+
.fg-site-footer a:hover { color: var(--color-text); text-decoration: underline; }
|
|
92
|
+
|
|
93
|
+
/* Legend: a dl of what a capture shows, with one div per dt and dd pair. */
|
|
94
|
+
.fg-site-legend {
|
|
95
|
+
display: grid;
|
|
96
|
+
grid-template-columns: repeat(auto-fit, minmax(min(var(--sidebar), 100%), 1fr));
|
|
97
|
+
gap: 0 var(--space-6);
|
|
98
|
+
margin: 0;
|
|
99
|
+
font-size: var(--text-sm);
|
|
100
|
+
}
|
|
101
|
+
.fg-site-legend > div {
|
|
102
|
+
display: grid;
|
|
103
|
+
align-content: start;
|
|
104
|
+
gap: var(--space-1);
|
|
105
|
+
padding-block: var(--space-3);
|
|
106
|
+
border-top: 1px solid var(--color-border-subtle);
|
|
107
|
+
}
|
|
108
|
+
.fg-site-legend dt { font-family: var(--font-mono); font-weight: var(--weight-medium); }
|
|
109
|
+
.fg-site-legend dd { margin: 0; color: var(--color-muted); }
|
|
110
|
+
|
|
5
111
|
/* A centered frame. The header uses the same edges as the page below it.
|
|
6
112
|
* Set --site-frame on the header or a frame to change its width. */
|
|
7
113
|
.fg-site-frame,
|
|
@@ -129,15 +235,17 @@
|
|
|
129
235
|
.fg-site-appearance__choice:hover { color: var(--color-text); background: var(--color-row-hover); }
|
|
130
236
|
.fg-site-appearance__choice[aria-pressed="true"] { color: var(--color-text); background: var(--color-row-selected); }
|
|
131
237
|
|
|
238
|
+
/* Focus is a 2px outline outside the control, which forced-colors mode keeps. An
|
|
239
|
+
* inset ring is used only where a scrolling ancestor would clip an outer one. */
|
|
132
240
|
.fg-site-header a:focus-visible,
|
|
133
241
|
.fg-site-projects__trigger:focus-visible,
|
|
134
242
|
.fg-site-appearance__choice:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
|
|
135
|
-
|
|
243
|
+
/* Inset: the desktop rail and the phone drawer scroll. */
|
|
136
244
|
.fg-site-nav a:focus-visible { outline: 2px solid var(--color-focus); outline-offset: -2px; }
|
|
137
245
|
|
|
138
246
|
/* Section rail (UiSiteNav). The page grid places it; on desktop it stays in view
|
|
139
|
-
* beside the article. At 800px and below it becomes a
|
|
140
|
-
* by a drawer once the page is interactive. */
|
|
247
|
+
* beside the article. At 800px and below it becomes a disclosure named by the
|
|
248
|
+
* label prop, replaced by a drawer once the page is interactive. */
|
|
141
249
|
.fg-site-rail {
|
|
142
250
|
position: sticky;
|
|
143
251
|
top: var(--space-6);
|
|
@@ -166,9 +274,9 @@
|
|
|
166
274
|
.fg-site-rail__group-label { margin-block-end: var(--space-1); }
|
|
167
275
|
|
|
168
276
|
/* Capture panel (UiCapture): tabs in the header, the capture as the body, and the
|
|
169
|
-
* command and caption as the footer. The
|
|
170
|
-
*
|
|
171
|
-
* full-size viewer. Nothing clips the panel, so focus rings inside it stay whole. */
|
|
277
|
+
* command and caption as the footer. The screen uses a dark terminal palette by
|
|
278
|
+
* default. A site can set --site-capture-bg and --t* values on :root, which also
|
|
279
|
+
* reach the full-size viewer. Nothing clips the panel, so focus rings inside it stay whole. */
|
|
172
280
|
.fg-capture {
|
|
173
281
|
position: relative;
|
|
174
282
|
min-width: 0;
|
|
@@ -178,8 +286,9 @@
|
|
|
178
286
|
}
|
|
179
287
|
.fg-capture .fg-tabs__list { width: 100%; margin-block-end: 0; padding-inline: var(--space-2); }
|
|
180
288
|
.fg-capture .fg-tabs__tab { min-height: var(--control-lg); }
|
|
181
|
-
/* The Full size control sits at the end of the tab row
|
|
182
|
-
|
|
289
|
+
/* The Full size control sits at the end of the tab row. The list's margin, not its
|
|
290
|
+
* padding, reserves the control's width, so the scroll area and divider end before it. */
|
|
291
|
+
.fg-capture[data-enhanced="true"] .fg-tabs__list { width: auto; margin-inline-end: calc(var(--space-2) + 6.5rem); }
|
|
183
292
|
.fg-capture__full {
|
|
184
293
|
position: absolute;
|
|
185
294
|
top: 0;
|
|
@@ -198,6 +307,7 @@
|
|
|
198
307
|
}
|
|
199
308
|
.fg-capture__full:hover { color: var(--color-text); }
|
|
200
309
|
.fg-capture__full svg { width: 14px; height: 14px; flex: none; }
|
|
310
|
+
/* Inset: the capture preview below would cover an outset ring. */
|
|
201
311
|
.fg-capture__full:focus-visible { outline: 2px solid var(--color-focus); outline-offset: -2px; }
|
|
202
312
|
/* Without JavaScript every capture is listed under its own heading. */
|
|
203
313
|
.fg-capture .fg-tabs__heading { margin: 0; padding: var(--space-3) var(--space-4); }
|
|
@@ -216,7 +326,59 @@
|
|
|
216
326
|
overflow-x: auto;
|
|
217
327
|
background: var(--site-capture-bg, var(--color-code));
|
|
218
328
|
}
|
|
329
|
+
/* Terminal markup gets the dark default; a plain <pre> keeps the code background its text expects. */
|
|
330
|
+
.fg-capture__screen:has(> .term) { background: var(--site-capture-bg, var(--t-bg, #131316)); }
|
|
219
331
|
.fg-capture__screen > * { width: max-content; margin: 0; }
|
|
332
|
+
/* Terminal colors for checked-in capture markup: .term and the ANSI classes the capture
|
|
333
|
+
* converter emits. Each color reads the site's --t* value first, so a site palette on
|
|
334
|
+
* :root still wins, and these defaults apply only where a site sets none. */
|
|
335
|
+
.fg-capture__screen .term {
|
|
336
|
+
padding: var(--space-4);
|
|
337
|
+
color: var(--t-fg, #e6e6ea);
|
|
338
|
+
font: var(--weight-regular) var(--text-sm) / 1 var(--font-mono);
|
|
339
|
+
font-variant-ligatures: none;
|
|
340
|
+
tab-size: 8;
|
|
341
|
+
}
|
|
342
|
+
.fg-capture__screen .term i { display: inline-block; width: 1ch; overflow: visible; font-style: normal; }
|
|
343
|
+
.fg-capture__screen .tf0 { color: var(--t0, #2b2b31); }
|
|
344
|
+
.fg-capture__screen .tf1 { color: var(--t1, #f0776c); }
|
|
345
|
+
.fg-capture__screen .tf2 { color: var(--t2, #4cc38a); }
|
|
346
|
+
.fg-capture__screen .tf3 { color: var(--t3, #e2a54b); }
|
|
347
|
+
.fg-capture__screen .tf4 { color: var(--t4, #7d97ff); }
|
|
348
|
+
.fg-capture__screen .tf5 { color: var(--t5, #c792ea); }
|
|
349
|
+
.fg-capture__screen .tf6 { color: var(--t6, #5fd3d9); }
|
|
350
|
+
.fg-capture__screen .tf7 { color: var(--t7, #c8c8d0); }
|
|
351
|
+
.fg-capture__screen .tf8 { color: var(--t8, #a0a0ab); }
|
|
352
|
+
.fg-capture__screen .tf9 { color: var(--t9, #ff8f85); }
|
|
353
|
+
.fg-capture__screen .tf10 { color: var(--t10, #6fd3a0); }
|
|
354
|
+
.fg-capture__screen .tf11 { color: var(--t11, #e8b56a); }
|
|
355
|
+
.fg-capture__screen .tf12 { color: var(--t12, #7d97ff); }
|
|
356
|
+
.fg-capture__screen .tf13 { color: var(--t13, #d9a8f0); }
|
|
357
|
+
.fg-capture__screen .tf14 { color: var(--t14, #8ee3e8); }
|
|
358
|
+
.fg-capture__screen .tf15 { color: var(--t15, #ffffff); }
|
|
359
|
+
.fg-capture__screen .tb0 { background: var(--t0, #2b2b31); }
|
|
360
|
+
.fg-capture__screen .tb1 { background: var(--t1, #f0776c); }
|
|
361
|
+
.fg-capture__screen .tb2 { background: var(--t2, #4cc38a); }
|
|
362
|
+
.fg-capture__screen .tb3 { background: var(--t3, #e2a54b); }
|
|
363
|
+
.fg-capture__screen .tb4 { background: var(--t4, #7d97ff); }
|
|
364
|
+
.fg-capture__screen .tb5 { background: var(--t5, #c792ea); }
|
|
365
|
+
.fg-capture__screen .tb6 { background: var(--t6, #5fd3d9); }
|
|
366
|
+
.fg-capture__screen .tb7 { background: var(--t7, #c8c8d0); }
|
|
367
|
+
.fg-capture__screen .tb8 { background: var(--t8, #a0a0ab); }
|
|
368
|
+
.fg-capture__screen .tb9 { background: var(--t9, #ff8f85); }
|
|
369
|
+
.fg-capture__screen .tb10 { background: var(--t10, #6fd3a0); }
|
|
370
|
+
.fg-capture__screen .tb11 { background: var(--t11, #e8b56a); }
|
|
371
|
+
.fg-capture__screen .tb12 { background: var(--t12, #7d97ff); }
|
|
372
|
+
.fg-capture__screen .tb13 { background: var(--t13, #d9a8f0); }
|
|
373
|
+
.fg-capture__screen .tb14 { background: var(--t14, #8ee3e8); }
|
|
374
|
+
.fg-capture__screen .tb15 { background: var(--t15, #ffffff); }
|
|
375
|
+
.fg-capture__screen .tf-dim { color: var(--t-dim, #a0a0ab); }
|
|
376
|
+
.fg-capture__screen .tf-bg { color: var(--t-bg, #131316); }
|
|
377
|
+
.fg-capture__screen .tb-fg { background: var(--t-fg, #e6e6ea); }
|
|
378
|
+
.fg-capture__screen .tbold { font-weight: var(--weight-semibold); }
|
|
379
|
+
.fg-capture__screen .tital { font-style: italic; }
|
|
380
|
+
.fg-capture__screen .tul { text-decoration: underline; text-underline-offset: 0.18em; }
|
|
381
|
+
|
|
220
382
|
.fg-capture__screen[data-fit] { overflow: hidden; }
|
|
221
383
|
.fg-capture__screen[data-fit] > * { transform: scale(var(--capture-scale, 1)); transform-origin: top left; }
|
|
222
384
|
.fg-capture__expand {
|
|
@@ -240,8 +402,9 @@
|
|
|
240
402
|
line-height: var(--leading);
|
|
241
403
|
}
|
|
242
404
|
.fg-capture__caption > code { color: var(--color-text); font-family: var(--font-mono); font-size: var(--text-sm); overflow-wrap: anywhere; }
|
|
243
|
-
|
|
244
|
-
.fg-
|
|
405
|
+
/* Inset: the enhanced panel clips its content. */
|
|
406
|
+
.fg-capture__screen:focus-visible,
|
|
407
|
+
.fg-capture__expand:focus-visible { outline: 2px solid var(--color-focus); outline-offset: -2px; }
|
|
245
408
|
.fg-dialog__content.fg-capture-viewer {
|
|
246
409
|
width: calc(100vw - var(--space-8));
|
|
247
410
|
max-width: var(--page-max);
|
|
@@ -299,6 +462,7 @@
|
|
|
299
462
|
}
|
|
300
463
|
.fg-command-list__copy:hover { color: var(--color-text); background: var(--color-row-hover); }
|
|
301
464
|
.fg-command-list__copy svg { width: 1rem; height: 1rem; }
|
|
465
|
+
/* Inset: the table scrolls sideways on larger screens. */
|
|
302
466
|
.fg-command-list__copy:focus-visible { outline: 2px solid var(--color-focus); outline-offset: -2px; }
|
|
303
467
|
.fg-command-list__status:not(:empty) { display: block; padding-top: var(--space-2); font-size: var(--text-sm); }
|
|
304
468
|
|
|
@@ -401,6 +565,8 @@
|
|
|
401
565
|
}
|
|
402
566
|
/* Keep in sync with MOBILE_QUERY in UiSiteNav.vue. */
|
|
403
567
|
@media (max-width: 800px) {
|
|
568
|
+
.fg-site-docs { grid-template-columns: minmax(0, 1fr); }
|
|
569
|
+
.fg-site-docs > main { gap: var(--space-8); padding-top: var(--space-6); }
|
|
404
570
|
.fg-site-rail {
|
|
405
571
|
position: static;
|
|
406
572
|
max-height: none;
|
|
@@ -421,16 +587,28 @@
|
|
|
421
587
|
}
|
|
422
588
|
.fg-site-rail__summary::-webkit-details-marker { display: none; }
|
|
423
589
|
.fg-site-rail__summary:hover { color: var(--color-text); background: var(--color-row-hover); }
|
|
424
|
-
.fg-site-rail__summary:focus-visible { outline: 2px solid var(--color-focus); outline-offset:
|
|
590
|
+
.fg-site-rail__summary:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
|
|
425
591
|
.fg-site-rail__menu > .fg-site-rail__content { padding-block: var(--space-4); }
|
|
426
592
|
.fg-site-rail__menu .fg-site-rail__group { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
427
593
|
.fg-site-rail__menu .fg-site-rail__group-label { grid-column: 1 / -1; }
|
|
428
594
|
.fg-site-rail__nav a { min-height: var(--control-lg); }
|
|
595
|
+
/* The drawer title already shows the label; the heading still names the nav. */
|
|
596
|
+
.fg-drawer__content .fg-site-rail__label {
|
|
597
|
+
position: absolute;
|
|
598
|
+
width: 1px;
|
|
599
|
+
height: 1px;
|
|
600
|
+
overflow: hidden;
|
|
601
|
+
clip-path: inset(50%);
|
|
602
|
+
white-space: nowrap;
|
|
603
|
+
}
|
|
429
604
|
}
|
|
430
605
|
@media (max-width: 640px) {
|
|
606
|
+
.fg-site-docs { padding-inline: var(--space-4); }
|
|
607
|
+
/* Docs-shell pages keep one header row on phones and repeat these links in their footer. */
|
|
608
|
+
.fg-site-docs .fg-site-header__links { display: none; }
|
|
431
609
|
.fg-dialog__content.fg-capture-viewer { width: 100%; max-width: none; }
|
|
432
610
|
/* Phones keep the icon; the accessible name still says Full size. */
|
|
433
|
-
.fg-capture[data-enhanced="true"] .fg-tabs__list {
|
|
611
|
+
.fg-capture[data-enhanced="true"] .fg-tabs__list { margin-inline-end: calc(var(--space-2) + var(--control-lg)); }
|
|
434
612
|
.fg-capture__full { min-width: var(--control-lg); justify-content: center; }
|
|
435
613
|
.fg-capture__full-label { display: none; }
|
|
436
614
|
.fg-command-list__table,
|
package/src/theme.css
CHANGED
|
@@ -75,6 +75,7 @@
|
|
|
75
75
|
--color-warning-surface: color-mix(in srgb, var(--color-warning) 13%, var(--color-surface));
|
|
76
76
|
--color-success-surface: color-mix(in srgb, var(--color-success) 12%, var(--color-surface));
|
|
77
77
|
--color-info-surface: color-mix(in srgb, var(--color-info) 12%, var(--color-surface));
|
|
78
|
+
--radius-inline: 0.25rem;
|
|
78
79
|
--radius-control: 0.375rem;
|
|
79
80
|
--radius-panel: 0.5rem;
|
|
80
81
|
--radius-pill: 999px;
|
|
@@ -147,6 +148,7 @@
|
|
|
147
148
|
--color-ui-warning: var(--color-warning);
|
|
148
149
|
--color-ui-success: var(--color-success);
|
|
149
150
|
--color-ui-info: var(--color-info);
|
|
151
|
+
--radius-ui-inline: var(--radius-inline);
|
|
150
152
|
--radius-ui-control: var(--radius-control);
|
|
151
153
|
--radius-ui-panel: var(--radius-panel);
|
|
152
154
|
}
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
--color-syntax-attribute: var(--color-syntax-number);
|
|
42
42
|
--color-error: #c7372d;
|
|
43
43
|
--color-warning: #86532e;
|
|
44
|
-
--color-success: #
|
|
44
|
+
--color-success: #157249;
|
|
45
45
|
--color-info: #175cd3;
|
|
46
46
|
--color-progress: var(--color-accent);
|
|
47
47
|
--color-error-surface: color-mix(in srgb, var(--color-error) 10%, var(--color-bg));
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
:root.dark {
|
|
65
65
|
color-scheme: dark;
|
|
66
66
|
--color-bg: #151619;
|
|
67
|
-
--color-surface: #
|
|
67
|
+
--color-surface: #0e0f12;
|
|
68
68
|
--color-surface-raised: #212226;
|
|
69
69
|
--color-surface-muted: #303238;
|
|
70
70
|
--color-text: #f4f5f8;
|