Reverted text-xs override. text-ss replaces the text-xs override while tailwind's existing text-xs replaces our text-2xs.

This commit is contained in:
2026-07-17 12:19:20 -04:00
parent dda0e738d4
commit 4f0418ea6e
43 changed files with 159 additions and 159 deletions

View File

@@ -232,7 +232,7 @@ func badgesSection() func() *VNode {
ui.EnvBadge("staging"),
// Production deliberately renders NOTHING — the badge exists to tell you that
// you are NOT in production, and a badge that is always there says nothing.
Span(Attr("class", "text-xs text-ink-muted"),
Span(Attr("class", "text-ss text-ink-muted"),
Text("(production renders nothing — that is the point of it)")),
),
),
@@ -473,7 +473,7 @@ func selectsSection() func() *VNode {
field("Timezone", ui.FormTimezoneSelector(ui.FormSelectProps{
Value: tz.Get(), OnChange: func(v string) { tz.Set(v) }})),
),
P(Attr("class", "mt-3 text-xs text-ink-muted"),
P(Attr("class", "mt-3 text-ss text-ink-muted"),
Text("one="+orElse(one.Get(), "—")+" several="+orElse(strings.Join(langs.Get(), ","), "—"))),
),
@@ -484,7 +484,7 @@ func selectsSection() func() *VNode {
OnSelect: func(o ui.FormSelectOption) { picked.Set(o.Label + " <" + o.Value + ">") },
}),
),
P(Attr("class", "mt-3 text-xs text-ink-muted"),
P(Attr("class", "mt-3 text-ss text-ink-muted"),
Text("Two characters before it asks; 200 ms after you stop typing. A response for a query "+
"you have already typed past is DISCARDED rather than shown — which is the whole bug "+
"with hand-rolled autocompletes.")),
@@ -500,7 +500,7 @@ func selectsSection() func() *VNode {
ShowSelectAll: true,
OnChange: func(v []string) { tags.Set(v) },
}),
P(Attr("class", "mt-3 text-xs text-ink-muted"),
P(Attr("class", "mt-3 text-ss text-ink-muted"),
Text("Same selection model as the field above; only the thing you click on differs.")),
),
)
@@ -535,7 +535,7 @@ func togglesSection() func() *VNode {
demo("Signature pad — "+itoa(len(signed.Get()))+" bytes of SVG",
pad.Render(ui.SignaturePadProps{}),
P(Attr("class", "mt-3 text-xs text-ink-muted"),
P(Attr("class", "mt-3 text-ss text-ink-muted"),
Text("Draw in it. Long strokes are smoothed; a single stray point is not a stroke and "+
"is dropped, so a click does not leave a dot behind.")),
),
@@ -584,7 +584,7 @@ func datesSection() func() *VNode {
OnNavigate: func(m time.Time) { month.Set(m) },
}),
),
P(Attr("class", "mt-3 text-xs text-ink-muted"),
P(Attr("class", "mt-3 text-ss text-ink-muted"),
Text("The same grid the picker drops down, usable directly when you want it inline.")),
),
)
@@ -676,7 +676,7 @@ func tablesSection() func() *VNode {
SortDesc: gridDesc.Get(),
SetSortDesc: func(b bool) { gridDesc.Set(b) },
}),
P(Attr("class", "mt-3 text-xs text-ink-muted"),
P(Attr("class", "mt-3 text-ss text-ink-muted"),
Text("Click a Qty or Price cell and type. The grid does not own the rows — it tells you "+
"which cell changed and hands the value back; what you do with it is yours.")),
),
@@ -801,7 +801,7 @@ func overlaysSection(push func(ui.ToastType, string)) func() *VNode {
tipFocus.Render(Span(Text("Shown on FOCUS, not hover — tab to the field")),
ui.FormInput(ui.FormInputProps{Placeholder: "Focus me"})),
),
P(Attr("class", "mt-3 text-xs text-ink-muted"),
P(Attr("class", "mt-3 text-ss text-ink-muted"),
Text("Narrow the window and hover \"Right\": it flips to the left, and its arrow follows "+
"it. A tooltip that only answers to a mouse is a tooltip a keyboard user cannot read.")),
),
@@ -862,7 +862,7 @@ func overlaysSection(push func(ui.ToastType, string)) func() *VNode {
hoverMenu.Item(ui.MenuItemProps{}, Text("Two")),
),
),
P(Attr("class", "mt-3 text-xs text-ink-muted"),
P(Attr("class", "mt-3 text-ss text-ink-muted"),
Text("Opening one closes the other — a single-open manager. Submenus are exempt, or a "+
"submenu would close the very menu it belongs to as it opened. The items raise toasts, "+
"which is how you can see that an item really does close its own menu.")),
@@ -889,7 +889,7 @@ func overlaysSection(push func(ui.ToastType, string)) func() *VNode {
}, ui.ModalOptions{Size: ui.ModalSmall})
}}),
),
P(Attr("class", "mt-3 text-xs text-ink-muted"),
P(Attr("class", "mt-3 text-ss text-ink-muted"),
Text("Open the modal, then the nested one inside it, and press Escape twice: modals unwind "+
"ONE LAYER per press rather than all at once.")),
@@ -994,7 +994,7 @@ func feedbackSection(toaster *ui.Toaster, tour *ui.Tutorial) func() *VNode {
demo("The guided tour",
row("flex flex-wrap items-center gap-3",
tour.StartButton(0, "", Text("Take the tour")),
Span(Attr("class", "text-xs text-ink-muted"),
Span(Attr("class", "text-ss text-ink-muted"),
Text("It dims the page, cuts a hole around each target, and animates the spotlight from "+
"one to the next. Targets are CSS SELECTORS — the same section ids the sidebar jumps to.")),
),
@@ -1006,7 +1006,7 @@ func feedbackSection(toaster *ui.Toaster, tour *ui.Tutorial) func() *VNode {
OnClick: flash.Fire}),
ui.RemoteUpdateFlash(flash.Visible()),
),
P(Attr("class", "mt-3 text-xs text-ink-muted"),
P(Attr("class", "mt-3 text-ss text-ink-muted"),
Text("A two-second acknowledgement that data you are looking at was changed by somebody "+
"else. It is not a toast: it belongs next to the thing that moved, not in the corner.")),
),
@@ -1071,7 +1071,7 @@ func navigationSection() func() *VNode {
demo("Accordion — one open at a time, or several",
row("grid gap-6 lg:grid-cols-2",
row("flex flex-col gap-2",
P(Attr("class", "text-xs font-semibold uppercase tracking-widest text-ink-faint"),
P(Attr("class", "text-ss font-semibold uppercase tracking-widest text-ink-faint"),
Text("SingleAccordion")),
ui.SingleAccordion([]ui.AccordionItemData{
{Title: "What is Kjøl Wasm Web?", Content: panel("kjol's Go→WebAssembly UI engine.")},
@@ -1080,7 +1080,7 @@ func navigationSection() func() *VNode {
}, acc.Get(), func(i int) { acc.Set(i) }),
),
row("flex flex-col gap-2",
P(Attr("class", "text-xs font-semibold uppercase tracking-widest text-ink-faint"),
P(Attr("class", "text-ss font-semibold uppercase tracking-widest text-ink-faint"),
Text("Accordion (several at once)")),
ui.Accordion([]ui.AccordionItemData{
{Title: "First", Content: panel("Open me.")},
@@ -1107,7 +1107,7 @@ func navigationSection() func() *VNode {
}},
}, func(id string) { side.Set(id) }, ""),
),
P(Attr("class", "mt-3 text-xs text-ink-muted"),
P(Attr("class", "mt-3 text-ss text-ink-muted"),
Text("It reports the id you clicked and nothing else. The sidebar on THIS page is the "+
"same idea, wired to scroll the section into view.")),
),
@@ -1230,7 +1230,7 @@ func chartsSection() func() *VNode {
row("mt-4 flex items-center gap-3",
ui.Button(ui.ButtonProps{Color: ui.ButtonPrimary, Small: true, Text: "New data", OnClick: func() { seed.Set(seed.Get() + 1) }}),
ui.Button(ui.ButtonProps{Color: ui.ButtonNeutral, Small: true, Text: threeDLabel, OnClick: func() { threeD.Set(!threeD.Get()) }}),
Span(Attr("class", "text-xs text-ink-muted"), Text("Each chart takes a Title; a multi-series chart also draws a legend. Click a legend key (Errors, or a donut slice) to hide it — the scale and marks recompute. 3D extrudes the bars and tilts the donut.")),
Span(Attr("class", "text-ss text-ink-muted"), Text("Each chart takes a Title; a multi-series chart also draws a legend. Click a legend key (Errors, or a donut slice) to hide it — the scale and marks recompute. 3D extrudes the bars and tilts the donut.")),
),
),
@@ -1247,7 +1247,7 @@ func chartsSection() func() *VNode {
demo("US heatmap — a value per state, with proportional lat/lng points on top",
heat.Render(ui.USHeatmapProps{Data: usSignups, Points: usCities, Proportional: true}),
Span(Attr("class", "mt-3 block text-xs text-ink-muted"),
Span(Attr("class", "mt-3 block text-ss text-ink-muted"),
Text("webui.USHeatmap shades each state on the choropleth ramp and projects lat/lng points "+
"with a Go albersUsa port — Anchorage and Honolulu land on the insets. Hover a state or a point.")),
),

View File

@@ -5,6 +5,7 @@ import (
"kjol/lexer" // syntax highlighting for the code blocks — a string in, HTML out
. "kjol/vdom"
// The host API is dual-build — real under js/wasm, no-ops natively — so neutral page
// code can measure the browser and still server-render. This page uses it for exactly
// one thing: reading the clock when hydration commits.
@@ -89,7 +90,7 @@ func docPage(eyebrow, title, lede string, sections ...*VNode) *VNode {
mods := []Mod{Attr("class", "pb-16")}
mods = append(mods,
Div(Attr("class", "border-b border-line pb-6"),
P(Attr("class", "text-xs font-semibold uppercase tracking-widest text-accent"), Text(eyebrow)),
P(Attr("class", "text-ss font-semibold uppercase tracking-widest text-accent"), Text(eyebrow)),
H1(Attr("class", "mt-2 text-3xl font-semibold tracking-tight text-text-heading"), Text(title)),
P(Attr("class", "mt-3 text-ink-muted leading-relaxed"), Text(lede)),
),
@@ -150,7 +151,7 @@ func codeLang(caption, lang, src string) *VNode {
return Div(Attr("class", "mt-4 overflow-hidden rounded-default border border-neutral-800 bg-neutral-900"),
Div(Attr("class", "flex items-center gap-2 border-b border-neutral-800 px-4 py-2"),
Span(Attr("class", "text-xs font-medium text-ink-faint font-mono"), Text(caption)),
Span(Attr("class", "text-ss font-medium text-ink-faint font-mono"), Text(caption)),
Span(Attr("class", "ml-auto rounded-full bg-white/5 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wider text-ink-faint"), Text(lang)),
),
Pre(Attr("class", "overflow-x-auto px-4 py-3 text-[13px] leading-relaxed text-neutral-100 font-mono"), body),
@@ -164,7 +165,7 @@ func demo(title string, body ...*VNode) *VNode {
mods := []Mod{Attr("class", "mt-4 rounded-default border border-line bg-surface shadow-xs")}
mods = append(mods,
Div(Attr("class", "border-b border-line px-4 py-2"),
Span(Attr("class", "text-xs text-ink-muted"), Text(title)),
Span(Attr("class", "text-ss text-ink-muted"), Text(title)),
),
)
inner := []Mod{Attr("class", "p-4")}

View File

@@ -247,7 +247,7 @@ func layerItem(d Deps, l Layer) *VNode {
Span(Attr("class", "rounded-full bg-surface-raised px-1.5 py-0.5 text-[10px] font-semibold uppercase tracking-wider text-ink-muted"),
Text("reference")),
),
Span(Attr("class", "text-xs text-ink-muted"), Text(l.Tagline)),
Span(Attr("class", "text-ss text-ink-muted"), Text(l.Tagline)),
)
}
@@ -257,6 +257,6 @@ func layerItem(d Deps, l Layer) *VNode {
}
return A(Attr("class", cls), Attr("href", l.Href),
Span(Attr("class", "text-sm font-medium text-ink"), Text(l.Name)),
Span(Attr("class", "text-xs text-ink-muted"), Text(l.Tagline)),
Span(Attr("class", "text-ss text-ink-muted"), Text(l.Tagline)),
)
}

View File

@@ -410,7 +410,7 @@ serving "./wwwroot" on http://localhost:8085`
func AboutPage(d Deps) func() *VNode {
return func() *VNode {
return Div(Attr("class", "mx-auto max-w-3xl py-4"),
P(Attr("class", "text-xs font-semibold uppercase tracking-widest text-accent"), Text("About")),
P(Attr("class", "text-ss font-semibold uppercase tracking-widest text-accent"), Text("About")),
H1(Attr("class", "mt-2 text-4xl font-semibold tracking-tight text-text-heading"), Text("Why this exists")),
P(Attr("class", "mt-6 text-lg leading-relaxed text-ink-soft"),

View File

@@ -98,7 +98,7 @@ function LayerItem(props: { layer: Layer; current?: Layer }) {
reference
</span>
</span>
<span class="text-xs text-ink-muted">{props.layer.tagline}</span>
<span class="text-ss text-ink-muted">{props.layer.tagline}</span>
</div>
}
>
@@ -113,7 +113,7 @@ function LayerItem(props: { layer: Layer; current?: Layer }) {
}
>
<span class="text-sm font-medium text-ink">{props.layer.name}</span>
<span class="text-xs text-ink-muted">{props.layer.tagline}</span>
<span class="text-ss text-ink-muted">{props.layer.tagline}</span>
</a>
</Show>
);

View File

@@ -112,7 +112,7 @@ function Panel(props: { title: string; children?: JSXElement }) {
return (
<div class="mt-4 rounded-default border border-line bg-surface shadow-xs">
<div class="border-b border-line px-4 py-2">
<span class="text-xs text-ink-muted">{props.title}</span>
<span class="text-ss text-ink-muted">{props.title}</span>
</div>
<div class="p-4">{props.children}</div>
</div>
@@ -153,7 +153,7 @@ function Body() {
return (
<div>
<div class="border-b border-line pb-6">
<p class="text-xs font-semibold uppercase tracking-widest text-primary">Kjøl JS Web</p>
<p class="text-ss font-semibold uppercase tracking-widest text-primary">Kjøl JS Web</p>
<h1 class="mt-2 text-3xl font-semibold tracking-tight text-ink">Components</h1>
<p class="mt-3 leading-relaxed text-ink-muted">
Every component in the Solid kit, running. Not a screenshot of one anywhere: each block
@@ -313,7 +313,7 @@ function Badges() {
<span class="text-sm font-semibold text-ink">kjol</span>
<EnvBadge />
</div>
<p class="mt-3 text-xs text-ink-muted">
<p class="mt-3 text-ss text-ink-muted">
Nothing beside the wordmark? Then this build is production which is what it is telling
you.
</p>
@@ -429,7 +429,7 @@ function Icons() {
<Icon icon="star" size={18} solid />
<Icon icon="star" size={18} solid={false} />
</div>
<p class="mt-3 text-xs text-ink-muted">
<p class="mt-3 text-ss text-ink-muted">
The last two are the same name in the solid and regular styles. Which one you get by
default is a CSS variable the app sets, read at runtime.
</p>
@@ -614,7 +614,7 @@ function Selects() {
<FormTimezoneSelector value={tz()} onchange={(e: any) => setTz(e?.currentTarget?.value ?? e)} />
</Field>
</div>
<p class="mt-3 text-xs text-ink-muted">
<p class="mt-3 text-ss text-ink-muted">
one: <span class="font-mono text-ink">{one() || "—"}</span> · several:{" "}
<span class="font-mono text-ink">{many().join(", ") || "—"}</span>
</p>
@@ -635,7 +635,7 @@ function Selects() {
onSelect={(value, option) => setPicked(option.label + " <" + value + ">")}
/>
</div>
<p class="mt-3 text-xs text-ink-muted">
<p class="mt-3 text-ss text-ink-muted">
Two characters before it asks; 200 ms after you stop typing. A response for a query you
have already typed past is DISCARDED rather than shown which is the whole bug with
hand-rolled autocompletes.
@@ -655,7 +655,7 @@ function Selects() {
searchable
showSelectAll
/>
<p class="mt-3 text-xs text-ink-muted">
<p class="mt-3 text-ss text-ink-muted">
Same selection model as the field above; only the thing you click on differs.
</p>
</Panel>
@@ -698,7 +698,7 @@ function Toggles() {
<Panel title={"Signature pad — " + signed().length + " bytes of SVG"}>
<FormSignaturePad onchange={setSigned} />
<p class="mt-3 text-xs text-ink-muted">
<p class="mt-3 text-ss text-ink-muted">
Draw in it. Clearing it emits an empty string, so "did they sign?" is just a length check.
</p>
</Panel>
@@ -735,7 +735,7 @@ function Dates() {
<div class="max-w-xs">
<Calendar selected={day()} onSelect={setDay} />
</div>
<p class="mt-3 text-xs text-ink-muted">
<p class="mt-3 text-ss text-ink-muted">
The same grid the picker drops down, usable directly when you want it inline. Pass{" "}
<code class="font-mono">variant="month"</code> for the big version.
</p>
@@ -859,7 +859,7 @@ function Tables() {
sortDesc={sortDesc()}
setSortDesc={setSortDesc}
/>
<p class="mt-3 text-xs text-ink-muted">
<p class="mt-3 text-ss text-ink-muted">
Click a Qty or Price cell and type; Tab and the arrow keys move between editable cells.
The grid does not own the rows it tells you which cell changed and hands the value back.
</p>
@@ -972,7 +972,7 @@ function Overlays() {
<FormInput placeholder="Focus me" />
</Tooltip>
</div>
<p class="mt-3 text-xs text-ink-muted">
<p class="mt-3 text-ss text-ink-muted">
A tooltip that only answers to a mouse is a tooltip a keyboard user cannot read.
</p>
</Panel>
@@ -1048,7 +1048,7 @@ function Overlays() {
</MenuContent>
</Menu>
</div>
<p class="mt-3 text-xs text-ink-muted">
<p class="mt-3 text-ss text-ink-muted">
The items raise toasts, which is how you can see that an item really does close its own
menu — and that the one marked closeOnClick={"{false}"} does not.
</p>
@@ -1064,7 +1064,7 @@ function Overlays() {
Open wizard
</ButtonUI>
</div>
<p class="mt-3 text-xs text-ink-muted">
<p class="mt-3 text-ss text-ink-muted">
Open the modal, then the nested one inside it, and press Escape twice: modals unwind ONE
LAYER per press rather than all at once.
</p>
@@ -1190,7 +1190,7 @@ function Feedback() {
Sticky (no timer)
</ButtonUI>
</div>
<p class="mt-3 text-xs text-ink-muted">
<p class="mt-3 text-ss text-ink-muted">
<code class="font-mono">useToast()</code> throws outside a{" "}
<code class="font-mono">&lt;ToastProvider&gt;</code> which is one of only two providers
this kit has.
@@ -1200,7 +1200,7 @@ function Feedback() {
<Panel title="The guided tour">
<div class="flex flex-wrap items-center gap-3">
<StartTutorialButton>Take the tour</StartTutorialButton>
<span class="text-xs text-ink-muted">
<span class="text-ss text-ink-muted">
It dims the page, cuts a hole around each target, and animates the spotlight from one
to the next. Targets are CSS SELECTORS the same section ids the sidebar jumps to.
</span>
@@ -1214,7 +1214,7 @@ function Feedback() {
</ButtonUI>
<RemoteUpdateFlash when={flash.visible()} />
</div>
<p class="mt-3 text-xs text-ink-muted">
<p class="mt-3 text-ss text-ink-muted">
A brief acknowledgement that data you are looking at was changed by somebody else. It is
not a toast: it belongs next to the thing that moved, not in the corner.
</p>
@@ -1269,7 +1269,7 @@ function Navigation() {
<Panel title="Accordion — one open at a time, or several">
<div class="grid gap-6 lg:grid-cols-2">
<div class="flex flex-col gap-2">
<p class="text-xs font-semibold uppercase tracking-widest text-ink-faint">
<p class="text-ss font-semibold uppercase tracking-widest text-ink-faint">
SingleAccordion
</p>
<SingleAccordion
@@ -1281,7 +1281,7 @@ function Navigation() {
/>
</div>
<div class="flex flex-col gap-2">
<p class="text-xs font-semibold uppercase tracking-widest text-ink-faint">
<p class="text-ss font-semibold uppercase tracking-widest text-ink-faint">
Accordion (several at once)
</p>
<Accordion
@@ -1314,7 +1314,7 @@ function Navigation() {
onItemClick={setSide}
/>
</div>
<p class="mt-3 text-xs text-ink-muted">
<p class="mt-3 text-ss text-ink-muted">
It scrolls the element whose <code class="font-mono">id</code> matches the item into view
so these really do jump, because those sections really do exist on this page.
</p>
@@ -1353,7 +1353,7 @@ function Search() {
onSelect={(value) => setHit(value)}
/>
</div>
<p class="mt-3 text-xs text-ink-muted">
<p class="mt-3 text-ss text-ink-muted">
The scorer is headless too: <code class="font-mono">rankFuzzyMatches</code> and{" "}
<code class="font-mono">fuzzySegments</code> give you the ranking and the highlight runs,
and you render them however you like.
@@ -1438,7 +1438,7 @@ function Charts() {
<ButtonUI color={BUTTON_COLOR_NEUTRAL} small onclick={() => setThreeD(!threeD())}>
{threeD() ? "Flat" : "3D"}
</ButtonUI>
<span class="text-xs text-ink-muted">
<span class="text-ss text-ink-muted">
Each chart carries a <code class="font-mono">title</code>; a multi-series chart also draws a
legend. Click a legend key say <em>Errors</em> or a donut slice to hide it, and the scale
and marks recompute from what's left. The <code class="font-mono">threeD</code> prop extrudes
@@ -1468,7 +1468,7 @@ function Charts() {
{ name: "Retries", data: shuffle([5, 7, 3, 9]) },
]} height={260} />
</div>
<p class="mt-3 text-xs text-ink-muted">
<p class="mt-3 text-ss text-ink-muted">
<code class="font-mono">horizontal</code> runs the categories down the y-axis;{" "}
<code class="font-mono">stacked</code> layers the series with a 2px surface gap between segments.
</p>
@@ -1476,7 +1476,7 @@ function Charts() {
<Panel title="US heatmap — a value per state, with proportional lat/lng points on top">
<USHeatmap data={US_SIGNUPS} points={US_CITIES} proportional valueFormat={(v) => v.toLocaleString("en-US")} />
<p class="mt-3 text-xs text-ink-muted">
<p class="mt-3 text-ss text-ink-muted">
<code class="font-mono">@ui/USHeatmap</code> shades each state on a themed sequential ramp and
projects <code class="font-mono">points</code> (latitude/longitude) with a dependency-free
albersUsa port — so Anchorage and Honolulu land on the Alaska and Hawaii insets. With{" "}
@@ -1557,7 +1557,7 @@ function Theming() {
)}
</For>
</div>
<p class="mt-3 text-xs text-ink-muted">
<p class="mt-3 text-ss text-ink-muted">
The swatch class is written out in full in the source, not built as{" "}
<code class="font-mono">"bg-" + name</code>. Tailwind finds the classes it must compile by
scanning the source for literal strings a concatenation is invisible to it, and every

View File

@@ -13,7 +13,7 @@ export function Overview() {
return (
<div>
<p class="text-xs font-semibold uppercase tracking-widest text-primary">Kjøl JS Web</p>
<p class="text-ss font-semibold uppercase tracking-widest text-primary">Kjøl JS Web</p>
<h1 class="mt-2 text-3xl font-semibold tracking-tight text-ink">
A Solid kit, built by a Go toolchain
</h1>
@@ -103,7 +103,7 @@ export function Overview() {
function Stage(props: { n: string; title: string; body: string }) {
return (
<div class="flex gap-4 border-l-2 border-line pl-4">
<span class="mt-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-surface-raised text-xs font-semibold text-ink-soft">
<span class="mt-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-surface-raised text-ss font-semibold text-ink-soft">
{props.n}
</span>
<div>

View File

@@ -29,7 +29,7 @@ export function Ssr() {
return (
<div class="page-ssr mx-auto max-w-2xl px-4 py-14">
<p class="text-xs font-semibold uppercase tracking-widest text-primary">Kjøl JS Web</p>
<p class="text-ss font-semibold uppercase tracking-widest text-primary">Kjøl JS Web</p>
<h1 class="mt-2 text-3xl font-semibold tracking-tight text-ink">
This page was rendered by Go
</h1>

View File

@@ -39,8 +39,7 @@
@theme {
/* Custom text sizes */
--text-2xs: 0.75rem; /* Same size as Tailwind's default text-xs */
--text-xs: 0.8rem; /* Override: Tailwind default is 0.75rem */
--text-ss: 0.8rem; /* Override: Tailwind default is 0.75rem */
/* Custom breakpoints (Tailwind defaults + xs + ultrawide) */
--breakpoint-xs: 375px;

View File

@@ -560,14 +560,14 @@ const HEADER_SORT_ICON_CLS: Record<AutoTableHeaderColor, string> = {
export const HEADER_PADDING_CLS: Record<AutoTableSize, string> = {
[AUTOTABLE_SIZE_DEFAULT]: "p-4 text-sm",
[AUTOTABLE_SIZE_COMPACT]: "py-1.5 px-2 text-sm",
[AUTOTABLE_SIZE_SUPERCOMPACT]: "py-1 px-2 text-xs",
[AUTOTABLE_SIZE_SUPERCOMPACT]: "py-1 px-2 text-ss",
};
// Body cell padding per table size — applied via [&_td]: on the tbody.
export const BODY_PADDING_CLS: Record<AutoTableSize, string> = {
[AUTOTABLE_SIZE_DEFAULT]: "text-sm [&_td]:p-4",
[AUTOTABLE_SIZE_COMPACT]: "text-sm [&_td]:py-1 [&_td]:px-2",
[AUTOTABLE_SIZE_SUPERCOMPACT]: "text-xs [&_td]:py-0.5 [&_td]:px-2",
[AUTOTABLE_SIZE_SUPERCOMPACT]: "text-ss [&_td]:py-0.5 [&_td]:px-2",
};
// Pagination padding per table size.
@@ -651,7 +651,7 @@ const FORMULA_PLACEHOLDER = `<span class="text-ink-faint">e.g. [Revenue] / SUM({
// Mobile: filters collapse behind a toggle; lg+ always shows the filter row inline.
const FILTERS_TOGGLE = "lg:hidden inline-flex w-full items-center justify-between gap-2 py-1 px-3 text-sm font-normal text-ink bg-surface-muted border border-line-strong rounded-default shadow-xs cursor-pointer hover:bg-surface-raised";
const FILTERS_BADGE = "inline-flex items-center justify-center min-w-5 h-5 px-1.5 text-xs font-semibold text-white bg-sky-700 rounded-full";
const FILTERS_BADGE = "inline-flex items-center justify-center min-w-5 h-5 px-1.5 text-ss font-semibold text-white bg-sky-700 rounded-full";
const FILTERS_BODY_BASE = "grow flex flex-col gap-3 min-w-0 max-w-full items-stretch overflow-visible lg:items-end max-lg:[&>*]:w-full max-lg:[&>*]:min-w-0 max-lg:[&_.search-fields]:w-full max-lg:[&_.search-fields]:flex-col [&>.quick-date-tags]:w-full";
const FILTERS_BODY_INLINE = FILTERS_BODY_BASE
+ " lg:flex lg:flex-row lg:flex-wrap lg:items-end lg:gap-x-3.5 lg:gap-y-2.5"
@@ -668,14 +668,14 @@ export const SEARCH_FIELDS = "search-fields flex flex-col items-stretch gap-3 w-
export const SEARCH_FIELDS_SPACER = "search-fields-spacer hidden lg:block flex-1 min-w-4 basis-full lg:basis-auto lg:min-w-[1rem]";
/** Combobox / custom filter control wrapper — pair with FormCombobox fieldWidth="grow". */
export const AUTOTABLE_FILTER_FIELD = "flex flex-col gap-1 min-w-0 w-full overflow-visible [&>label]:text-xs [&>label]:font-medium [&>label]:text-ink [&_.relative]:w-full [&_.relative]:min-w-0 [&_.relative]:flex-none";
export const AUTOTABLE_FILTER_FIELD = "flex flex-col gap-1 min-w-0 w-full overflow-visible [&>label]:text-ss [&>label]:font-medium [&>label]:text-ink [&_.relative]:w-full [&_.relative]:min-w-0 [&_.relative]:flex-none";
/** Sales report toolbar wrappers (presets row 1, filters + export row 2). */
export const SALES_REPORT_TOOLBAR = "sales-report-toolbar flex flex-col gap-2.5 w-full min-w-0 lg:contents";
export const SALES_REPORT_PRESETS = "sales-report-toolbar__presets min-w-0 w-full [&_.quick-date-tags]:gap-1.5";
export const SALES_REPORT_FILTERS = "search-fields sales-report-toolbar__filters flex flex-col items-stretch gap-3 w-full overflow-visible lg:flex-row lg:flex-wrap lg:items-end lg:gap-x-3.5 lg:gap-y-2.5 lg:w-auto lg:min-w-0 min-w-0 pt-0.5 border-t border-line [&>*]:min-w-0 [&>*]:max-lg:w-full lg:[&>*]:w-auto lg:[&>*:not(.sales-report-filter-date):not(.sales-report-filter-ref)]:flex-[1_1_8rem] lg:[&>*:not(.sales-report-filter-date):not(.sales-report-filter-ref)]:max-w-[12rem] [&_.relative]:w-full [&_.relative]:min-w-0 [&_.relative]:flex-none";
export const AUTOTABLE_SEARCH_FIELD = "flex flex-col gap-1 min-w-0 w-full [&>label]:text-xs [&>label]:font-medium [&>label]:text-ink [&_.relative]:w-full [&_.relative]:min-w-0";
export const AUTOTABLE_SEARCH_FIELD = "flex flex-col gap-1 min-w-0 w-full [&>label]:text-ss [&>label]:font-medium [&>label]:text-ink [&_.relative]:w-full [&_.relative]:min-w-0";
export const AUTOTABLE_SEARCH_FIELD_WIDE = AUTOTABLE_SEARCH_FIELD + " lg:flex-[2_1_12rem] lg:max-w-[20rem]";
export const AUTOTABLE_SEARCH_FIELD_NARROW = AUTOTABLE_SEARCH_FIELD + " lg:flex-[0_1_auto] lg:max-w-[11rem] lg:min-w-[7rem]";
export const AUTOTABLE_DATE_SEARCH_FIELD = AUTOTABLE_SEARCH_FIELD + " lg:flex-[1_1_10rem] lg:max-w-none";
@@ -1831,8 +1831,8 @@ function FormulaField(props: FormulaFieldProps) {
</div>;
// -- Insert menus (Advanced mode), shown in a row above the formula input ----
const MENU_TRIGGER = "inline-flex items-center gap-1 px-2 py-1 text-xs rounded-default border border-line-strong bg-surface-muted hover:bg-surface-raised text-ink cursor-pointer leading-none";
const MENU_SEARCH = "w-full text-xs p-1 border border-line-strong rounded-default focus:outline-2 focus:outline-sky-500 focus:outline-offset-1";
const MENU_TRIGGER = "inline-flex items-center gap-1 px-2 py-1 text-ss rounded-default border border-line-strong bg-surface-muted hover:bg-surface-raised text-ink cursor-pointer leading-none";
const MENU_SEARCH = "w-full text-ss p-1 border border-line-strong rounded-default focus:outline-2 focus:outline-sky-500 focus:outline-offset-1";
const columnMenu = () => <Show when={operandOptions.length}>
<Popover placement="bottom-start" standalone={true} open={colMenuOpen()} onOpenChange={setColMenuOpen}>
@@ -1850,17 +1850,17 @@ function FormulaField(props: FormulaFieldProps) {
class="flex items-center rounded-default hover:bg-surface-raised"
onMouseEnter={() => highlight([o.value])} onMouseLeave={() => highlight(null)}>
<button type="button"
class="flex-1 min-w-0 text-left truncate px-2 py-1 font-mono text-xs text-sky-600 dark:text-sky-400 bg-transparent border-0 cursor-pointer"
class="flex-1 min-w-0 text-left truncate px-2 py-1 font-mono text-ss text-sky-600 dark:text-sky-400 bg-transparent border-0 cursor-pointer"
title={"Insert [" + o.label + "] — this row's cell"}
onclick={(_e: MouseEvent) => { insertRef("[" + o.label + "]"); setColMenuOpen(false); }}>[{o.label}]</button>
<button type="button"
class="px-2 py-1 text-xs font-mono text-violet-600 hover:text-violet-800 bg-transparent border-0 cursor-pointer"
class="px-2 py-1 text-ss font-mono text-violet-600 hover:text-violet-800 bg-transparent border-0 cursor-pointer"
title={"Insert {" + o.label + "} — whole column"}
onclick={(_e: MouseEvent) => { insertRef("{" + o.label + "}"); setColMenuOpen(false); }}>{"{ }"}</button>
</div>}
</For>
<Show when={filteredColumns().length === 0}>
<div class="px-2 py-3 text-xs text-ink-muted text-center">No columns match.</div>
<div class="px-2 py-3 text-ss text-ink-muted text-center">No columns match.</div>
</Show>
</div>
</PopoverContent>
@@ -1884,14 +1884,14 @@ function FormulaField(props: FormulaFieldProps) {
{(f: { name: string; sig: string; desc: string }) => <button type="button"
class="w-full text-left px-2 py-1 rounded-default hover:bg-surface-raised cursor-pointer border-0 bg-transparent flex flex-col gap-0.5"
onclick={(_e: MouseEvent) => { insertFunction(f.name); setFuncMenuOpen(false); }}>
<span class="font-mono text-xs text-ink" innerHTML={highlightFormula(f.sig)}></span>
<span class="font-mono text-ss text-ink" innerHTML={highlightFormula(f.sig)}></span>
<span class="text-[11px] text-ink-muted">{f.desc}</span>
</button>}
</For>
</div>}
</For>
<Show when={filteredFunctionGroups().length === 0}>
<div class="px-2 py-3 text-xs text-ink-muted text-center">No functions match.</div>
<div class="px-2 py-3 text-ss text-ink-muted text-center">No functions match.</div>
</Show>
</div>
</PopoverContent>
@@ -1911,12 +1911,12 @@ function FormulaField(props: FormulaFieldProps) {
{(c: { name: string; desc: string }) => <button type="button"
class="w-full text-left px-2 py-1 rounded-default hover:bg-surface-raised cursor-pointer border-0 bg-transparent flex items-center justify-between gap-2"
onclick={(_e: MouseEvent) => { insertRef(c.name); setConstMenuOpen(false); }}>
<span class="font-mono text-xs text-amber-600 dark:text-amber-400">{c.name}</span>
<span class="font-mono text-ss text-amber-600 dark:text-amber-400">{c.name}</span>
<span class="text-[11px] text-ink-muted">{c.desc}</span>
</button>}
</For>
<Show when={filteredConstants().length === 0}>
<div class="px-2 py-3 text-xs text-ink-muted text-center">No constants match.</div>
<div class="px-2 py-3 text-ss text-ink-muted text-center">No constants match.</div>
</Show>
</div>
</PopoverContent>
@@ -1948,7 +1948,7 @@ function FormulaField(props: FormulaFieldProps) {
<HoverPopoverTrigger class="inline-flex items-center text-ink-faint hover:text-ink-soft cursor-help bg-transparent border-0 p-0 leading-none">
<Icon icon="circle-info" size={14} />
</HoverPopoverTrigger>
<HoverPopoverContent class="p-3 w-80 text-xs text-ink-soft leading-relaxed flex flex-col gap-2">
<HoverPopoverContent class="p-3 w-80 text-ss text-ink-soft leading-relaxed flex flex-col gap-2">
<div>
<div class="font-medium text-ink mb-1">References</div>
<div class="grid grid-cols-[max-content_1fr] gap-x-3 gap-y-1 items-center">
@@ -2098,7 +2098,7 @@ function CalculatedColumnForm(props: CalculatedColumnFormProps) {
onHighlight={highlight}
apiRef={(api: FormulaFieldApi) => { formulaApi = api; }} />
<Show when={formulaError()}>
<p class="text-xs text-red-600 dark:text-red-400 mt-1">{formulaError()}</p>
<p class="text-ss text-red-600 dark:text-red-400 mt-1">{formulaError()}</p>
</Show>
</div>
<div class="grid grid-cols-2 gap-2">
@@ -2130,11 +2130,11 @@ function CalculatedColumnForm(props: CalculatedColumnFormProps) {
</div>
</div>
<Show when={errorMsg()}>
<p class="text-xs text-red-600 dark:text-red-400">{errorMsg()}</p>
<p class="text-ss text-red-600 dark:text-red-400">{errorMsg()}</p>
</Show>
<div class="flex gap-2 items-center pt-1">
<Show when={!!column() && !!props.onRemove}>
<ButtonLinkRed onclick={(_e: MouseEvent) => handleRemove()}><span class="text-xs">Remove</span></ButtonLinkRed>
<ButtonLinkRed onclick={(_e: MouseEvent) => handleRemove()}><span class="text-ss">Remove</span></ButtonLinkRed>
</Show>
<div class="flex gap-2 items-center ml-auto">
<ButtonUI small={true} color={BUTTON_COLOR_LIGHT_NEUTRAL} onclick={(_e: MouseEvent) => close()}>Cancel</ButtonUI>
@@ -2235,7 +2235,7 @@ function SummaryRowForm(props: SummaryRowFormProps) {
onHighlight={highlight}
apiRef={(api: FormulaFieldApi) => { formulaApi = api; }} />
<Show when={formulaError()}>
<p class="text-xs text-red-600 dark:text-red-400 mt-1">{formulaError()}</p>
<p class="text-ss text-red-600 dark:text-red-400 mt-1">{formulaError()}</p>
</Show>
</div>
<div class="grid grid-cols-2 gap-2">
@@ -2257,11 +2257,11 @@ function SummaryRowForm(props: SummaryRowFormProps) {
</div>
</div>
<Show when={errorMsg()}>
<p class="text-xs text-red-600 dark:text-red-400">{errorMsg()}</p>
<p class="text-ss text-red-600 dark:text-red-400">{errorMsg()}</p>
</Show>
<div class="flex gap-2 items-center pt-1">
<Show when={!!row() && !!props.onRemove}>
<ButtonLinkRed onclick={(_e: MouseEvent) => handleRemove()}><span class="text-xs">Remove</span></ButtonLinkRed>
<ButtonLinkRed onclick={(_e: MouseEvent) => handleRemove()}><span class="text-ss">Remove</span></ButtonLinkRed>
</Show>
<div class="flex gap-2 items-center ml-auto">
<ButtonUI small={true} color={BUTTON_COLOR_LIGHT_NEUTRAL} onclick={(_e: MouseEvent) => close()}>Cancel</ButtonUI>
@@ -2303,7 +2303,7 @@ function AddCalcMenu(props: AddCalcMenuProps) {
<Icon icon="table-columns" size={16} class="mt-0.5 text-ink-muted" />
<span class="flex flex-col">
<span class="text-sm font-medium text-ink">Calculated column</span>
<span class="text-xs text-ink-muted">A new column computed for each row</span>
<span class="text-ss text-ink-muted">A new column computed for each row</span>
</span>
</button>
</Show>
@@ -2312,7 +2312,7 @@ function AddCalcMenu(props: AddCalcMenuProps) {
<Icon icon="list-ol" size={16} class="mt-0.5 text-ink-muted" />
<span class="flex flex-col">
<span class="text-sm font-medium text-ink">Summary row</span>
<span class="text-xs text-ink-muted">A total or aggregate shown in the footer</span>
<span class="text-ss text-ink-muted">A total or aggregate shown in the footer</span>
</span>
</button>
</Show>

View File

@@ -7,7 +7,7 @@ export const BADGE_AMBER = "amber";
export const BADGE_NEUTRAL = "neutral";
export const BADGE_MUTED = "muted";
const BASE = "inline-flex items-center gap-1 text-xs font-semibold py-0.5 px-2 rounded-default whitespace-nowrap";
const BASE = "inline-flex items-center gap-1 text-ss font-semibold py-0.5 px-2 rounded-default whitespace-nowrap";
const COLORS: Record<string, string> = {
"green": "text-white bg-green-700",

View File

@@ -144,7 +144,7 @@ export function SegmentedButtons(props: SegmentedButtonsProps) {
const innerRadius = "rounded-default"; // chips: 4px
const outerRadius = "rounded-md"; // track: 4px + 2px = 6px
const sizeCls = () => props.small ? "py-0.5 px-2 text-xs" : "py-1 px-3 text-sm";
const sizeCls = () => props.small ? "py-0.5 px-2 text-ss" : "py-1 px-3 text-sm";
const baseCls = "inline-flex items-center justify-center gap-1.5 flex-1 cursor-pointer font-medium transition-colors whitespace-nowrap disabled:opacity-50 disabled:cursor-not-allowed";
const activeCls = "bg-surface text-ink shadow-sm";
const inactiveCls = "text-ink-muted hover:text-ink";

View File

@@ -21,14 +21,14 @@ export const CAL_MY_MONTH = "text-lg font-heading mx-4 flex-1 text-center font-s
export const CAL_WEEKDAYS_PICKER = "grid grid-cols-7 gap-[2px] mb-1";
export const CAL_WEEKDAYS_MONTH = "grid grid-cols-7 border-b border-line";
export const CAL_WEEKDAY_PICKER = "text-center text-xs font-semibold text-ink-muted p-1";
export const CAL_WEEKDAY_MONTH = "text-center text-xs font-semibold text-ink-muted p-2 uppercase tracking-wider";
export const CAL_WEEKDAY_PICKER = "text-center text-ss font-semibold text-ink-muted p-1";
export const CAL_WEEKDAY_MONTH = "text-center text-ss font-semibold text-ink-muted p-2 uppercase tracking-wider";
export const CAL_DAYS_PICKER = "grid grid-cols-7 gap-[2px]";
export const CAL_DAYS_MONTH = "grid grid-cols-7";
export const CAL_DAY_PICKER_BASE = "aspect-square flex items-center justify-center text-sm bg-transparent border-0 rounded-sm cursor-pointer text-ink p-0";
export const CAL_DAY_MONTH_BASE = "min-h-[6.5rem] flex flex-col items-stretch justify-start p-1.5 border-r border-b border-line text-left gap-1 text-xs bg-transparent cursor-pointer";
export const CAL_DAY_MONTH_BASE = "min-h-[6.5rem] flex flex-col items-stretch justify-start p-1.5 border-r border-b border-line text-left gap-1 text-ss bg-transparent cursor-pointer";
export const CAL_SELECT = "flex-1 py-1 px-2 text-sm font-semibold border border-line rounded-sm bg-surface text-ink cursor-pointer focus:outline-hidden focus:border-primary";

View File

@@ -1,7 +1,7 @@
import { createSignal, createMemo, untrack, Show, For, JSXElement } from "solid-js";
import { Icon } from "./Icons.tsx";
export const GRID_HEADER_CLS = "border-b border-r border-line-strong bg-surface-muted px-1.5 py-1.5 text-left text-xs font-bold uppercase text-ink whitespace-nowrap last:border-r-0";
export const GRID_HEADER_CLS = "border-b border-r border-line-strong bg-surface-muted px-1.5 py-1.5 text-left text-ss font-bold uppercase text-ink whitespace-nowrap last:border-r-0";
interface SortableHeaderProps {
label: string;
@@ -411,7 +411,7 @@ export function CellGrid(props: CellGridProps) {
);
};
const tableCls = () => "min-w-full w-max border-collapse " + (dense() ? "text-xs" : "text-sm");
const tableCls = () => "min-w-full w-max border-collapse " + (dense() ? "text-ss" : "text-sm");
return (
<div class="relative max-w-full overflow-x-auto border border-line-strong rounded-default bg-surface tabular-nums">

View File

@@ -586,7 +586,7 @@ function CartesianTooltip(p: {
});
const rows = () => p.props.series.map((s, i) => ({ s, i })).filter(({ i }) => !p.hidden.has(i));
return (
<div class="pointer-events-none absolute z-10 min-w-32 max-w-64 rounded-default border border-line bg-surface px-3 py-2 text-xs shadow-lg"
<div class="pointer-events-none absolute z-10 min-w-32 max-w-64 rounded-default border border-line bg-surface px-3 py-2 text-ss shadow-lg"
style={style()}>
<div class="mb-1 font-medium text-ink">{p.label}</div>
<For each={rows()}>{(row) => (
@@ -704,7 +704,7 @@ function RadialChart(p: SubProps): JSXElement {
<svg width={p.width} height={p.height} viewBox={`0 0 ${p.width} ${p.height}`} class="block" role="img"
innerHTML={body()} onpointermove={onMove} onpointerleave={() => setHover(null)} />
<Show when={p.props.tooltip !== false && hover() !== null}>
<div class="pointer-events-none absolute z-10 min-w-28 max-w-64 rounded-default border border-line bg-surface px-3 py-2 text-xs shadow-lg"
<div class="pointer-events-none absolute z-10 min-w-28 max-w-64 rounded-default border border-line bg-surface px-3 py-2 text-ss shadow-lg"
style={{
left: `${clamp(pointer()[0], 8, p.width - 8)}px`,
top: `${clamp(pointer()[1], 8, p.height - 8)}px`,
@@ -752,7 +752,7 @@ function Legend(p: { props: ChartProps; colorOf: (i: number) => string; hidden:
}>
<span class="inline-block h-0.5 w-4 rounded-full" style={{ "background-color": p.colorOf(it.i), opacity: off() ? 0.35 : 1 }} />
</Show>
<span class={"text-xs " + (off() ? "text-ink-faint line-through" : "text-ink-soft")}>{it.name}</span>
<span class={"text-ss " + (off() ? "text-ink-faint line-through" : "text-ink-soft")}>{it.name}</span>
</button>
);
}}</For>

View File

@@ -102,7 +102,7 @@ const CRM_TAB_ROW = "flex w-full overflow-x-auto text-sm";
const CRM_TAB_BASE = "flex items-center gap-1.5 cursor-pointer p-4 font-medium border-line-strong transition-colors";
const CRM_TAB_INACTIVE = "border-b text-ink-muted hover:text-ink";
const CRM_TAB_ACTIVE = "border-x border-t-2 border-t-sky-700 text-primary";
const CRM_TAB_BADGE = "inline-flex items-center justify-center min-w-5 h-5 px-1 text-xs font-semibold bg-primary text-white rounded-full";
const CRM_TAB_BADGE = "inline-flex items-center justify-center min-w-5 h-5 px-1 text-ss font-semibold bg-primary text-white rounded-full";
export function CrmTabGroup(props: CrmTabGroupProps) {
// Memoize props.items: callers pass items={[{content: <Comp/>}]} where each
@@ -148,7 +148,7 @@ const CRM_SUBTAB_BASE = "flex items-center gap-1.5 py-1 px-3 cursor-pointer font
const CRM_SUBTAB_DIVIDER = "border-l border-line-strong";
const CRM_SUBTAB_ACTIVE = "bg-neutral-500 text-white";
const CRM_SUBTAB_INACTIVE = "bg-surface text-ink-soft hover:bg-surface-raised hover:text-ink";
const CRM_SUBTAB_BADGE = "inline-flex items-center justify-center min-w-5 h-5 px-1 text-xs font-semibold bg-black/10 text-current rounded-full";
const CRM_SUBTAB_BADGE = "inline-flex items-center justify-center min-w-5 h-5 px-1 text-ss font-semibold bg-black/10 text-current rounded-full";
export function CrmSubTabGroup(props: CrmTabGroupProps) {
// See CrmTabGroup: memoize eager `content` JSX so it's built once, in-owner.

View File

@@ -45,8 +45,8 @@ function _prefixCls(small?: boolean, error?: unknown, onDark?: boolean): string
+ (small ? " p-1 text-sm" : " p-2");
}
const FORM_ERROR = "block text-red-600 text-xs mt-1";
const FORM_SUCCESS = "block text-green-600 text-xs mt-1";
const FORM_ERROR = "block text-red-600 text-ss mt-1";
const FORM_SUCCESS = "block text-green-600 text-ss mt-1";
const INPUT_GROUP = "flex flex-row items-stretch w-full text-sm";
const TRIGGER_BASE = "bg-white border border-neutral-300 rounded-default shadow-xs text-sm w-full text-left flex items-center justify-between gap-2 cursor-pointer disabled:bg-neutral-100 disabled:cursor-not-allowed";
@@ -662,8 +662,8 @@ export function FormSignaturePad(props: { value?: () => string; onchange?: (svg:
onTouchEnd={stopDrawing}
/>
<div class="flex items-center justify-between px-2 py-1 border-t border-neutral-200 bg-neutral-50">
<span class="text-xs text-neutral-400 italic">{isEmpty() ? "Sign above" : ""}</span>
<button type="button" class="text-xs font-medium text-neutral-500 bg-transparent border-none cursor-pointer px-1 py-0.5 rounded-default hover:text-red-600 hover:bg-red-50 disabled:opacity-40 disabled:cursor-not-allowed" onclick={clearSignature} disabled={isEmpty()}>Clear</button>
<span class="text-ss text-neutral-400 italic">{isEmpty() ? "Sign above" : ""}</span>
<button type="button" class="text-ss font-medium text-neutral-500 bg-transparent border-none cursor-pointer px-1 py-0.5 rounded-default hover:text-red-600 hover:bg-red-50 disabled:opacity-40 disabled:cursor-not-allowed" onclick={clearSignature} disabled={isEmpty()}>Clear</button>
</div>
</div>
</div>;
@@ -1537,7 +1537,7 @@ export function FormMultiSelect(props: FormMultiSelectProps) {
}
return <div ref={(el) => tagsContainerRef = el} class="flex flex-nowrap gap-1 overflow-hidden items-center">
<For each={selectedOptions()}>
{(option) => <span class={"inline-flex items-center gap-0.5 bg-neutral-200 rounded-default whitespace-nowrap leading-none" + (props.small ? " py-0.5 px-1.5 text-xs" : " py-0.5 px-2 text-sm")}>
{(option) => <span class={"inline-flex items-center gap-0.5 bg-neutral-200 rounded-default whitespace-nowrap leading-none" + (props.small ? " py-0.5 px-1.5 text-ss" : " py-0.5 px-2 text-sm")}>
{option.label}
<button type="button" class="bg-transparent border-none p-0 cursor-pointer flex items-center hover:text-neutral-900" onclick={(e) => removeOption(option.value, e)}>
<IconInline icon="xmark" size={10} />

View File

@@ -258,7 +258,7 @@ export function FuzzyMatch(props: FuzzyMatchProps) {
const ScoreBadge = (p: { score: number }) =>
<Show when={props.showScores}>
<span class="ml-3 shrink-0 text-xs text-ink-faint">{p.score}</span>
<span class="ml-3 shrink-0 text-ss text-ink-faint">{p.score}</span>
</Show>;
return <div ref={containerRef} class={"relative " + (props.class ?? "")}>

View File

@@ -21,7 +21,7 @@ interface CodeBoxProps {
export function CodeBox(props: CodeBoxProps): JSXElement {
return (
<div class={"text-xs p-3 bg-neutral-800 text-neutral-100 border border-neutral-700 rounded-default " + (props.class || "")}>
<div class={"text-ss p-3 bg-neutral-800 text-neutral-100 border border-neutral-700 rounded-default " + (props.class || "")}>
<pre><code>{props.code}</code></pre>
</div>
);
@@ -79,7 +79,7 @@ interface BreadcrumbsProps {
export function Breadcrumbs(props: BreadcrumbsProps): JSXElement {
return (
<div class="flex flex-row items-center text-ink-faint text-xs">
<div class="flex flex-row items-center text-ink-faint text-ss">
<For each={props.items}>{(crumb, index) => (
index() !== props.items.length - 1
? (

View File

@@ -90,7 +90,7 @@ const MODAL_SIZES: Record<ModalSize, string> = {
"2xlarge":"max-w-5xl",
"3xlarge":"max-w-6xl",
"4xlarge":"max-w-7xl",
"5xlarge":"max-w-[90rem]",
"5xlarge":"max-w-8xl",
full: "max-w-none",
};
@@ -117,12 +117,12 @@ const CONFIRM_OK_VARIANTS = {
const WIZARD_HEADER = "flex flex-col items-center gap-2 flex-1";
const WIZARD_TITLE_ROW = "flex items-center justify-between w-full";
const WIZARD_TITLE = "text-xl";
const WIZARD_STEP_NAME = "text-xs font-semibold text-ink-soft uppercase tracking-wider";
const WIZARD_STEP_NAME = "text-ss font-semibold text-ink-soft uppercase tracking-wider";
const WIZARD_STEPS = "flex items-center justify-between relative w-full max-w-64";
const WIZARD_TRACK = "absolute top-1/2 left-0 right-0 h-0.5 bg-surface-strong -translate-y-1/2";
const WIZARD_TRACK_FILL = "h-full bg-primary transition-[width] duration-300 ease-in-out";
const WIZARD_STEP_WRAP = "relative z-[1]";
const STEP_INDICATOR_BASE = "w-7 h-7 rounded-full flex items-center justify-center text-xs font-semibold border-2 shrink-0 transition-all duration-300 ease-in-out";
const STEP_INDICATOR_BASE = "w-7 h-7 rounded-full flex items-center justify-center text-ss font-semibold border-2 shrink-0 transition-all duration-300 ease-in-out";
const STEP_INDICATOR_PENDING = "border-line-strong text-ink-faint bg-surface";
const STEP_INDICATOR_ACTIVE = "bg-primary text-white border-primary";
const STEP_INDICATOR_COMPLETED = "bg-primary text-white border-primary";

View File

@@ -3,7 +3,7 @@ import { For, createSignal, Show, JSXElement } from "solid-js";
const NAV_ROOT = "bg-surface rounded-default shadow-sm border border-line py-2";
const NAV_LIST = "list-none m-0 p-0";
const NAV_BTN = "w-full text-left py-2 pr-3 pl-4 text-sm cursor-pointer bg-transparent text-ink-soft border-0 hover:text-ink hover:bg-surface-muted";
const NAV_SUBBTN = "w-full text-left py-1.5 pr-3 pl-8 text-xs cursor-pointer bg-transparent text-ink-muted border-0 hover:text-ink hover:bg-surface-muted";
const NAV_SUBBTN = "w-full text-left py-1.5 pr-3 pl-8 text-ss cursor-pointer bg-transparent text-ink-muted border-0 hover:text-ink hover:bg-surface-muted";
const NAV_ICON = "mr-2";
const LAYOUT_ROOT = "grid grid-cols-1 gap-8 min-h-screen items-start lg:grid-cols-12";

View File

@@ -146,7 +146,7 @@ export function TabGroup(props: TabGroupProps) {
const b = resolveBadge(item.badge);
return b != null && b > 0;
})()}>
<span class="inline-flex items-center justify-center min-w-5 h-5 px-1 text-xs font-semibold bg-primary text-white rounded-full">{resolveBadge(item.badge)}</span>
<span class="inline-flex items-center justify-center min-w-5 h-5 px-1 text-ss font-semibold bg-primary text-white rounded-full">{resolveBadge(item.badge)}</span>
</Show>
</button>
)}</For>

View File

@@ -55,7 +55,7 @@ export function ToggleSwitch(props: ToggleSwitchProps) {
class={"text-sm select-none " + (isDisabled() ? "text-ink-faint" : "text-ink")}
onclick={(_e: MouseEvent) => toggle()}
>{resolve(props.label)}</span>}
{props.description !== undefined && <span class="text-xs text-ink-muted">{resolve(props.description)}</span>}
{props.description !== undefined && <span class="text-ss text-ink-muted">{resolve(props.description)}</span>}
</div>}
</div>;
}

View File

@@ -468,7 +468,7 @@ function TutorialPopover() {
<Show when={displayedStep()?.title}>
<span class="font-medium text-ink">{displayedStep()?.title}</span>
</Show>
<span class="text-xs text-ink-muted">
<span class="text-ss text-ink-muted">
{(displayedStepIndex() + 1) + " of " + ctx.totalSteps()}
</span>
</div>

View File

@@ -195,7 +195,7 @@ export function USHeatmap(props: USHeatmapProps): JSXElement {
<Show when={props.tooltip !== false && tip()}>
{(t) => (
<div class="pointer-events-none absolute z-10 min-w-28 max-w-64 rounded-default border border-line bg-surface px-3 py-2 text-xs shadow-lg"
<div class="pointer-events-none absolute z-10 min-w-28 max-w-64 rounded-default border border-line bg-surface px-3 py-2 text-ss shadow-lg"
style={{
left: `${clamp(pointer()[0], 8, 100000)}px`,
top: `${Math.max(8, pointer()[1])}px`,
@@ -222,7 +222,7 @@ export function USHeatmap(props: USHeatmapProps): JSXElement {
function ChoroplethLegend(p: { min: number; max: number; steps: number; fmt: (v: number) => string }): JSXElement {
const swatches = () => Array.from({ length: p.steps }, (_, i) => i + 1);
return (
<div class="mt-3 flex items-center gap-2 text-xs text-ink-muted">
<div class="mt-3 flex items-center gap-2 text-ss text-ink-muted">
<span style={{ "font-variant-numeric": "tabular-nums" }}>{p.fmt(p.min)}</span>
<div class="flex overflow-hidden rounded-xs">
<For each={swatches()}>{(k) => (

View File

@@ -118,14 +118,14 @@ var atHeaderSortIconCls = map[AutoTableHeaderColor]string{
var HEADER_PADDING_CLS = map[AutoTableSize]string{
AUTOTABLE_SIZE_DEFAULT: "p-4 text-sm",
AUTOTABLE_SIZE_COMPACT: "py-1.5 px-2 text-sm",
AUTOTABLE_SIZE_SUPERCOMPACT: "py-1 px-2 text-xs",
AUTOTABLE_SIZE_SUPERCOMPACT: "py-1 px-2 text-ss",
}
// BODY_PADDING_CLS is the body cell padding per table size (applied via [&_td]:).
var BODY_PADDING_CLS = map[AutoTableSize]string{
AUTOTABLE_SIZE_DEFAULT: "text-sm [&_td]:p-4",
AUTOTABLE_SIZE_COMPACT: "text-sm [&_td]:py-1 [&_td]:px-2",
AUTOTABLE_SIZE_SUPERCOMPACT: "text-xs [&_td]:py-0.5 [&_td]:px-2",
AUTOTABLE_SIZE_SUPERCOMPACT: "text-ss [&_td]:py-0.5 [&_td]:px-2",
}
// atPaginationPaddingCls is the pagination bar padding per table size.
@@ -2184,7 +2184,7 @@ const (
AUTOTABLE_SEARCH_FIELD = "flex flex-col gap-1 min-w-0 grow sm:grow-0 sm:w-48"
AUTOTABLE_SEARCH_SELECT = "w-full rounded-default border border-line-strong bg-surface px-3 py-2 text-sm"
AUTOTABLE_FILTERS_TOGGLE = "sm:hidden inline-flex items-center gap-2 rounded-default border border-line-strong px-3 py-2 text-sm"
AUTOTABLE_FILTERS_BADGE = "ml-1 inline-flex h-5 min-w-5 items-center justify-center rounded-full bg-sky-600 px-1.5 text-xs font-semibold text-white"
AUTOTABLE_FILTERS_BADGE = "ml-1 inline-flex h-5 min-w-5 items-center justify-center rounded-full bg-sky-600 px-1.5 text-ss font-semibold text-white"
AUTOTABLE_TOOLBAR = "flex flex-wrap items-end justify-between gap-3 pb-3"
AUTOTABLE_ASIDE = "w-full sm:w-64 shrink-0 rounded-default border border-line-strong bg-surface p-3"
AUTOTABLE_ACCORDION_CELL = "w-10 text-center"
@@ -3141,7 +3141,7 @@ const (
formulaPlaceholder = `<span class="text-ink-faint">e.g. [Revenue] / SUM({Revenue}) * 100</span>`
calcMenuTrigger = "inline-flex items-center gap-1 rounded-default border border-line-strong bg-surface-muted px-2 py-1 text-xs leading-none text-ink-soft cursor-pointer hover:bg-surface-raised"
calcMenuTrigger = "inline-flex items-center gap-1 rounded-default border border-line-strong bg-surface-muted px-2 py-1 text-ss leading-none text-ink-soft cursor-pointer hover:bg-surface-raised"
calcChooserItem = "w-full text-left px-2 py-2 rounded-default hover:bg-surface-raised cursor-pointer border-0 bg-transparent flex items-start gap-2.5"
)
@@ -3630,7 +3630,7 @@ func calcChooserButton(icon, title, subtitle string, onClick func()) *vdom.VNode
Icon(icon, 16, "mt-0.5 text-ink-muted"),
vdom.Span(vdom.Attr("class", "flex flex-col"),
vdom.Span(vdom.Attr("class", "text-sm font-medium text-ink"), vdom.Text(title)),
vdom.Span(vdom.Attr("class", "text-xs text-ink-muted"), vdom.Text(subtitle)),
vdom.Span(vdom.Attr("class", "text-ss text-ink-muted"), vdom.Text(subtitle)),
),
)
}
@@ -3639,7 +3639,7 @@ func calcListRow(title, subtitle string, onEdit, onDelete func()) *vdom.VNode {
return vdom.Div(vdom.Attr("class", "flex items-center gap-2 rounded-default px-2 py-1 hover:bg-surface-muted"),
vdom.Div(vdom.Attr("class", "min-w-0 grow"),
vdom.Div(vdom.Attr("class", "truncate text-sm font-medium text-ink"), vdom.Text(title)),
vdom.Div(vdom.Attr("class", "truncate font-mono text-xs text-ink-muted"), vdom.Text(subtitle)),
vdom.Div(vdom.Attr("class", "truncate font-mono text-ss text-ink-muted"), vdom.Text(subtitle)),
),
Button(ButtonProps{Color: ButtonLightNeutral, Small: true, Icon: "pencil", Title: "Edit", OnClick: onEdit}),
Button(ButtonProps{Color: ButtonLightNeutral, Small: true, Icon: "trash", Title: "Delete", OnClick: onDelete}),
@@ -3793,7 +3793,7 @@ func (s *AutoTableState) calcForm(e *calcEditor, summary bool) *vdom.VNode {
}
if msg := e.errorMsg.Get(); msg != "" {
fields = append(fields, vdom.P(vdom.Attr("class", "text-xs text-red-600 dark:text-red-400"), vdom.Text(msg)))
fields = append(fields, vdom.P(vdom.Attr("class", "text-ss text-red-600 dark:text-red-400"), vdom.Text(msg)))
}
saveLabel := "Add"
@@ -3897,7 +3897,7 @@ func (s *AutoTableState) calcBasicEditor(e *calcEditor, summary bool) *vdom.VNod
})))
}
children = append(children, vdom.P(vdom.Attr("class", "text-xs text-ink-muted"),
children = append(children, vdom.P(vdom.Attr("class", "text-ss text-ink-muted"),
vdom.Text(calcBasicHint(e, summary))))
return vdom.Div(kids([]vdom.Mod{vdom.Attr("class", "flex flex-col gap-2")}, children)...)
@@ -3929,11 +3929,11 @@ func (s *AutoTableState) calcAdvancedEditor(e *calcEditor, summary bool) *vdom.V
colItems = append(colItems,
e.colMenu.Item(MenuItemProps{OnClick: func() { e.insertAtCaret("[" + label + "]") }},
vdom.Span(vdom.Attr("class", "font-mono text-sky-600 dark:text-sky-400"), vdom.Text("["+label+"]")),
vdom.Span(vdom.Attr("class", "ml-2 text-xs text-ink-muted"), vdom.Text("this row")),
vdom.Span(vdom.Attr("class", "ml-2 text-ss text-ink-muted"), vdom.Text("this row")),
),
e.colMenu.Item(MenuItemProps{OnClick: func() { e.insertAtCaret("{" + label + "}") }},
vdom.Span(vdom.Attr("class", "font-mono text-violet-600 dark:text-violet-400"), vdom.Text("{"+label+"}")),
vdom.Span(vdom.Attr("class", "ml-2 text-xs text-ink-muted"), vdom.Text("whole column")),
vdom.Span(vdom.Attr("class", "ml-2 text-ss text-ink-muted"), vdom.Text("whole column")),
),
)
}
@@ -3945,7 +3945,7 @@ func (s *AutoTableState) calcAdvancedEditor(e *calcEditor, summary bool) *vdom.V
groups := filterFormulaGroups(e.fnSearch.Get())
if len(groups) == 0 {
fnItems = append(fnItems, vdom.Div(
vdom.Attr("class", "px-2 py-3 text-center text-xs text-ink-muted"),
vdom.Attr("class", "px-2 py-3 text-center text-ss text-ink-muted"),
vdom.Text("No functions match"),
))
}
@@ -3959,8 +3959,8 @@ func (s *AutoTableState) calcAdvancedEditor(e *calcEditor, summary bool) *vdom.V
vdom.Div(vdom.Attr("class", "flex flex-col items-start gap-0.5 min-w-0"),
// The signature is syntax-highlighted with the same highlighter the
// formula box uses, so the menu and the editor speak one language.
vdom.Span(vdom.Attr("class", "font-mono text-xs"), vdom.Raw(HighlightFormula(f.Sig))),
vdom.Span(vdom.Attr("class", "text-xs text-ink-muted"), vdom.Text(f.Desc)),
vdom.Span(vdom.Attr("class", "font-mono text-ss"), vdom.Raw(HighlightFormula(f.Sig))),
vdom.Span(vdom.Attr("class", "text-ss text-ink-muted"), vdom.Text(f.Desc)),
),
))
}
@@ -3973,8 +3973,8 @@ func (s *AutoTableState) calcAdvancedEditor(e *calcEditor, summary bool) *vdom.V
OnClick: func() { e.insertAtCaret(cc.Name) },
},
vdom.Div(vdom.Attr("class", "flex flex-col items-start gap-0.5"),
vdom.Span(vdom.Attr("class", "font-mono text-xs text-amber-600 dark:text-amber-400"), vdom.Text(cc.Name)),
vdom.Span(vdom.Attr("class", "text-xs text-ink-muted"), vdom.Text(cc.Desc)),
vdom.Span(vdom.Attr("class", "font-mono text-ss text-amber-600 dark:text-amber-400"), vdom.Text(cc.Name)),
vdom.Span(vdom.Attr("class", "text-ss text-ink-muted"), vdom.Text(cc.Desc)),
),
))
}
@@ -4028,7 +4028,7 @@ func (s *AutoTableState) calcAdvancedEditor(e *calcEditor, summary bool) *vdom.V
),
)
help := vdom.P(vdom.Attr("class", "text-xs text-ink-muted"),
help := vdom.P(vdom.Attr("class", "text-ss text-ink-muted"),
vdom.Text("[Column] is this row's cell · {Column} is the whole column · {Column:1:ROW()} is a running total."))
children := []*vdom.VNode{menus, editor, help}
@@ -4048,7 +4048,7 @@ func (e *calcEditor) fnSearchBox() *vdom.VNode {
vdom.Input(
vdom.WithRef(e.fnSearchRef),
vdom.Attr("type", "text"),
vdom.Attr("class", "w-full rounded-default border border-line-strong p-1 text-xs focus:outline-2 focus:outline-sky-500"),
vdom.Attr("class", "w-full rounded-default border border-line-strong p-1 text-ss focus:outline-2 focus:outline-sky-500"),
vdom.Attr("placeholder", "Search functions…"),
vdom.Attr("spellcheck", "false"),
vdom.Prop("value", e.fnSearch.Get()),
@@ -4089,12 +4089,12 @@ func (s *AutoTableState) calcPreview(e *calcEditor, src string, summary bool) *v
return nil
}
if _, err := CompileFormula(src); err != nil {
return vdom.P(vdom.Attr("class", "text-xs text-red-600 dark:text-red-400"), vdom.Text(err.Error()))
return vdom.P(vdom.Attr("class", "text-ss text-red-600 dark:text-red-400"), vdom.Text(err.Error()))
}
rows := s.FilteredRows()
if len(rows) == 0 {
return vdom.P(vdom.Attr("class", "text-xs text-ink-muted"), vdom.Text("Formula is valid."))
return vdom.P(vdom.Attr("class", "text-ss text-ink-muted"), vdom.Text("Formula is valid."))
}
ctx := NewCalcContext(rows, s.cols, s.Calculated(), s.read)
@@ -4107,10 +4107,10 @@ func (s *AutoTableState) calcPreview(e *calcEditor, src string, summary bool) *v
n, err := EvalFormula(src, target)
if err != nil {
return vdom.P(vdom.Attr("class", "text-xs text-red-600 dark:text-red-400"), vdom.Text(err.Error()))
return vdom.P(vdom.Attr("class", "text-ss text-red-600 dark:text-red-400"), vdom.Text(err.Error()))
}
out := FormatCalcResult(n, CalculatedDataType(e.dataType.Get()), calcPrecisionOf(e.precision.Get()), "", "", "")
return vdom.P(vdom.Attr("class", "text-xs text-ink-muted"), vdom.Text(prefix+out))
return vdom.P(vdom.Attr("class", "text-ss text-ink-muted"), vdom.Text(prefix+out))
}
// insertAtCaret drops text where the cursor is, rather than at the end — which is
@@ -4141,7 +4141,7 @@ func (e *calcEditor) insertAtCaretOffset(text string, back int) {
func calcField(label string, children ...*vdom.VNode) *vdom.VNode {
nodes := []*vdom.VNode{
vdom.Span(vdom.Attr("class", "text-xs font-medium text-ink-soft"), vdom.Text(label)),
vdom.Span(vdom.Attr("class", "text-ss font-medium text-ink-soft"), vdom.Text(label)),
}
nodes = append(nodes, children...)
return vdom.Div(kids([]vdom.Mod{vdom.Attr("class", "flex flex-col gap-1")}, nodes)...)

View File

@@ -13,7 +13,7 @@ const (
BadgeMuted = "muted"
)
const badgeBase = "inline-flex items-center gap-1 text-xs font-semibold py-0.5 px-2 rounded-default whitespace-nowrap"
const badgeBase = "inline-flex items-center gap-1 text-ss font-semibold py-0.5 px-2 rounded-default whitespace-nowrap"
var badgeColors = map[string]string{
"green": "text-white bg-green-700",

View File

@@ -171,7 +171,7 @@ type SegmentedButtonOption struct {
func SegmentedButtons(options []SegmentedButtonOption, value string, onChange func(string), small bool, class string) *vdom.VNode {
sizeCls := "py-1 px-3 text-sm"
if small {
sizeCls = "py-0.5 px-2 text-xs"
sizeCls = "py-0.5 px-2 text-ss"
}
const baseCls = "inline-flex items-center justify-center gap-1.5 flex-1 cursor-pointer font-medium transition-colors whitespace-nowrap disabled:opacity-50 disabled:cursor-not-allowed"
const activeCls = "bg-surface text-text-heading shadow-sm"

View File

@@ -38,14 +38,14 @@ const calMyMonth = "text-lg font-heading mx-4 flex-1 text-center font-semibold t
const calWeekdaysPicker = "grid grid-cols-7 gap-[2px] mb-1"
const calWeekdaysMonth = "grid grid-cols-7 border-b border-line"
const calWeekdayPicker = "text-center text-xs font-semibold text-text-muted p-1"
const calWeekdayMonth = "text-center text-xs font-semibold text-text-muted p-2 uppercase tracking-wider"
const calWeekdayPicker = "text-center text-ss font-semibold text-text-muted p-1"
const calWeekdayMonth = "text-center text-ss font-semibold text-text-muted p-2 uppercase tracking-wider"
const calDaysPicker = "grid grid-cols-7 gap-[2px]"
const calDaysMonth = "grid grid-cols-7"
const calDayPickerBase = "aspect-square flex items-center justify-center text-sm bg-transparent border-0 rounded-sm cursor-pointer text-text-body p-0"
const calDayMonthBase = "min-h-[6.5rem] flex flex-col items-stretch justify-start p-1.5 border-r border-b border-line text-left gap-1 text-xs bg-transparent cursor-pointer"
const calDayMonthBase = "min-h-[6.5rem] flex flex-col items-stretch justify-start p-1.5 border-r border-b border-line text-left gap-1 text-ss bg-transparent cursor-pointer"
const calSelect = "flex-1 py-1 px-2 text-sm font-semibold border border-line rounded-sm bg-surface text-text-heading cursor-pointer focus:outline-hidden focus:border-primary"

View File

@@ -35,7 +35,7 @@ import (
// GridHeaderCls is the base <th> class for CellGrid headers (exported, matching
// the TSX GRID_HEADER_CLS).
const GridHeaderCls = "border-b border-r border-line-strong bg-surface-muted px-1.5 py-1.5 text-left text-xs font-bold uppercase text-ink whitespace-nowrap last:border-r-0"
const GridHeaderCls = "border-b border-r border-line-strong bg-surface-muted px-1.5 py-1.5 text-left text-ss font-bold uppercase text-ink whitespace-nowrap last:border-r-0"
var cgLeadingDigits = regexp.MustCompile(`^\d+`)
var cgLeadingFloat = regexp.MustCompile(`^[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?`)
@@ -467,7 +467,7 @@ func CellGrid(p CellGridProps) *vdom.VNode {
tableCls := "min-w-full w-max border-collapse text-sm"
if p.Dense {
tableCls = "min-w-full w-max border-collapse text-xs"
tableCls = "min-w-full w-max border-collapse text-ss"
}
return vdom.Div(vdom.Attr("class", "relative max-w-full overflow-x-auto border border-line-strong rounded-default bg-surface tabular-nums"),
vdom.Table(vdom.Attr("class", tableCls), thead, tbody),

View File

@@ -308,7 +308,7 @@ func (c *Chart) positionTip(left, top float64, transform string) {
// pass so its ref stays valid; onMove positions it imperatively. When there is no hover it
// is present but hidden — the same slot each render keeps the reconciler's diff stable.
func (c *Chart) tooltipNode(p ChartProps, hv int) *vdom.VNode {
base := "pointer-events-none absolute z-10 max-w-64 rounded-default border border-line bg-surface px-3 py-2 text-xs shadow-lg"
base := "pointer-events-none absolute z-10 max-w-64 rounded-default border border-line bg-surface px-3 py-2 text-ss shadow-lg"
if p.NoTooltip || hv < 0 || hv >= chartN(p) {
return vdom.Div(vdom.WithRef(c.tipRef), vdom.Attr("class", cx(base, "hidden")))
}
@@ -1086,10 +1086,10 @@ func (c *Chart) legend(p ChartProps) *vdom.VNode {
it := it // capture per iteration for the click closure
off := !chartShown(p, it.i)
swatchStyle := "background-color:" + chartColor(p, it.i)
labelClass := "text-xs text-ink-soft"
labelClass := "text-ss text-ink-soft"
if off {
swatchStyle += ";opacity:0.35"
labelClass = "text-xs text-ink-faint line-through"
labelClass = "text-ss text-ink-faint line-through"
}
nodes = append(nodes, vdom.El("button",
vdom.Attr("type", "button"),

View File

@@ -52,7 +52,7 @@ const crmTabRow = "flex w-full overflow-x-auto text-sm"
const crmTabBase = "flex items-center gap-1.5 cursor-pointer p-4 font-medium border-line-strong transition-colors"
const crmTabInactive = "border-b text-ink-muted hover:text-ink"
const crmTabActive = "border-x border-t-2 border-t-sky-700 text-accent"
const crmTabBadge = "inline-flex items-center justify-center min-w-5 h-5 px-1 text-xs font-semibold bg-primary text-white rounded-full"
const crmTabBadge = "inline-flex items-center justify-center min-w-5 h-5 px-1 text-ss font-semibold bg-primary text-white rounded-full"
// CrmTabGroup renders boxed tabs with a sky-blue top accent; content sits flat
// beneath the row (no body panel), with a trailing filler extending the baseline.
@@ -95,7 +95,7 @@ const crmSubTabBase = "flex items-center gap-1.5 py-1 px-3 cursor-pointer font-m
const crmSubTabDivider = "border-l border-line-strong"
const crmSubTabActive = "bg-neutral-500 text-white"
const crmSubTabInactive = "bg-surface text-ink-soft hover:bg-surface-raised hover:text-ink"
const crmSubTabBadge = "inline-flex items-center justify-center min-w-5 h-5 px-1 text-xs font-semibold bg-black/10 text-current rounded-full"
const crmSubTabBadge = "inline-flex items-center justify-center min-w-5 h-5 px-1 text-ss font-semibold bg-black/10 text-current rounded-full"
// CrmSubTabGroup renders a left-aligned segmented control (interlocking
// segments) with a full-width baseline separating the bar from the content.

View File

@@ -26,8 +26,8 @@ import (
const formInputBase = "bg-surface block w-full border rounded-default shadow-xs text-sm focus:outline-2 focus:outline-offset-1 disabled:bg-surface-raised disabled:cursor-not-allowed"
const formInputBaseDark = "bg-dark text-text-on-dark placeholder:text-text-on-dark-faint block w-full border rounded-default shadow-xs text-sm focus:outline-2 focus:outline-offset-1 disabled:opacity-50 disabled:cursor-not-allowed"
const formErrorCls = "block text-red-600 dark:text-red-400 text-xs mt-1"
const formSuccessCls = "block text-green-600 text-xs mt-1"
const formErrorCls = "block text-red-600 dark:text-red-400 text-ss mt-1"
const formSuccessCls = "block text-green-600 text-ss mt-1"
const formInputGroupCls = "flex flex-row items-stretch w-full text-sm"
const formTriggerBase = "bg-surface border border-line-strong rounded-default shadow-xs text-sm w-full text-left flex items-center justify-between gap-2 cursor-pointer disabled:bg-surface-raised disabled:cursor-not-allowed"
@@ -1312,7 +1312,7 @@ func (m *MultiSelect) triggerFace(p FormMultiSelectProps, selected []FormSelectO
pillCls := formMultiSelectTag
if p.Small {
pillCls = cx(pillCls, "px-1.5 text-xs")
pillCls = cx(pillCls, "px-1.5 text-ss")
} else {
pillCls = cx(pillCls, "px-2 text-sm")
}

View File

@@ -275,7 +275,7 @@ func fuzzyScoreBadge(show bool, score int) *vdom.VNode {
if !show {
return nil
}
return vdom.Span(vdom.Attr("class", "ml-3 shrink-0 text-xs text-ink-faint"), vdom.Text(strconv.Itoa(score)))
return vdom.Span(vdom.Attr("class", "ml-3 shrink-0 text-ss text-ink-faint"), vdom.Text(strconv.Itoa(score)))
}
// fuzzyListView renders the inline "list" display. Before the user types, all

View File

@@ -15,7 +15,7 @@ func Divider() *vdom.VNode { return vdom.Hr(vdom.Attr("class", "text-line mt-1 m
// CodeBox renders a dark monospace code block.
func CodeBox(code, class string) *vdom.VNode {
return vdom.Div(vdom.Attr("class", cx("text-xs p-3 bg-neutral-800 text-neutral-100 border border-neutral-700 rounded-default", class)),
return vdom.Div(vdom.Attr("class", cx("text-ss p-3 bg-neutral-800 text-neutral-100 border border-neutral-700 rounded-default", class)),
vdom.Pre(vdom.Code(vdom.Text(code))),
)
}
@@ -58,7 +58,7 @@ type BreadcrumbItem struct {
// Breadcrumbs renders a chevron-separated crumb trail; the last item is bold and
// not linked.
func Breadcrumbs(items []BreadcrumbItem) *vdom.VNode {
mods := []vdom.Mod{vdom.Attr("class", "flex flex-row items-center text-ink-faint text-xs")}
mods := []vdom.Mod{vdom.Attr("class", "flex flex-row items-center text-ink-faint text-ss")}
for i, crumb := range items {
if i != len(items)-1 {
mods = append(mods, vdom.Span(vdom.Attr("class", "flex items-center"),

View File

@@ -109,7 +109,7 @@ var modalSizes = map[ModalSize]string{
Modal2XLarge: "max-w-5xl",
Modal3XLarge: "max-w-6xl",
Modal4XLarge: "max-w-7xl",
Modal5XLarge: "max-w-[90rem]",
Modal5XLarge: "max-w-8xl",
ModalFull: "max-w-none",
}
@@ -137,12 +137,12 @@ var modalConfirmOkVariants = map[string]string{
const modalWizardHeader = "flex flex-col items-center gap-2 flex-1"
const modalWizardTitleRow = "flex items-center justify-between w-full"
const modalWizardTitle = "text-xl"
const modalWizardStepName = "text-xs font-semibold text-ink-soft uppercase tracking-wider"
const modalWizardStepName = "text-ss font-semibold text-ink-soft uppercase tracking-wider"
const modalWizardSteps = "flex items-center justify-between relative w-full max-w-64"
const modalWizardTrack = "absolute top-1/2 left-0 right-0 h-0.5 bg-surface-strong -translate-y-1/2"
const modalWizardTrackFill = "h-full bg-primary transition-[width] duration-300 ease-in-out"
const modalWizardStepWrap = "relative z-[1]"
const modalStepIndicatorBase = "w-7 h-7 rounded-full flex items-center justify-center text-xs font-semibold border-2 shrink-0 transition-all duration-300 ease-in-out"
const modalStepIndicatorBase = "w-7 h-7 rounded-full flex items-center justify-center text-ss font-semibold border-2 shrink-0 transition-all duration-300 ease-in-out"
const modalStepIndicatorPending = "border-line-strong text-ink-faint bg-surface"
const modalStepIndicatorActive = "bg-primary text-white border-primary"
const modalStepIndicatorCompleted = "bg-primary text-white border-primary"

View File

@@ -80,13 +80,13 @@ var ptRowHoverCls = map[PrettyTableHeaderColor]string{
var ptHeaderPaddingCls = map[PrettyTableSize]string{
PrettyTableSizeDefault: "p-4 text-sm",
PrettyTableSizeCompact: "py-1.5 px-2 text-sm",
PrettyTableSizeSuperCompact: "py-1 px-2 text-xs",
PrettyTableSizeSuperCompact: "py-1 px-2 text-ss",
}
var ptBodyPaddingCls = map[PrettyTableSize]string{
PrettyTableSizeDefault: "text-sm [&_td]:p-4",
PrettyTableSizeCompact: "text-sm [&_td]:py-1 [&_td]:px-2",
PrettyTableSizeSuperCompact: "text-xs [&_td]:py-0.5 [&_td]:px-2",
PrettyTableSizeSuperCompact: "text-ss [&_td]:py-0.5 [&_td]:px-2",
}
var ptPosCls = map[PrettyTableColumnPosition]string{

View File

@@ -7,7 +7,7 @@ import "kjol/vdom"
const sidebarNavRoot = "bg-surface rounded-default shadow-sm border border-line py-2"
const sidebarNavList = "list-none m-0 p-0"
const sidebarNavBtn = "w-full text-left py-2 pr-3 pl-4 text-sm cursor-pointer bg-transparent text-ink-soft border-0 hover:text-ink hover:bg-surface-muted"
const sidebarNavSubBtn = "w-full text-left py-1.5 pr-3 pl-8 text-xs cursor-pointer bg-transparent text-ink-muted border-0 hover:text-ink hover:bg-surface-muted"
const sidebarNavSubBtn = "w-full text-left py-1.5 pr-3 pl-8 text-ss cursor-pointer bg-transparent text-ink-muted border-0 hover:text-ink hover:bg-surface-muted"
const sidebarNavIcon = "mr-2"
const sidebarLayoutRoot = "grid grid-cols-1 gap-8 min-h-screen items-start lg:grid-cols-12"

View File

@@ -135,7 +135,7 @@ func (s *SignaturePad) Render(p SignaturePadProps) *vdom.VNode {
}
clear := []vdom.Mod{
vdom.Attr("type", "button"),
vdom.Attr("class", "text-xs text-ink-muted hover:text-ink disabled:opacity-50"),
vdom.Attr("class", "text-ss text-ink-muted hover:text-ink disabled:opacity-50"),
vdom.Text(pick(p.ClearText, "Clear")),
}
if p.Disabled || s.IsEmpty() {
@@ -145,7 +145,7 @@ func (s *SignaturePad) Render(p SignaturePadProps) *vdom.VNode {
}
kids = append(kids, vdom.Div(
vdom.Attr("class", "flex items-center justify-between border-t border-line bg-surface-muted px-2 py-1"),
vdom.Span(vdom.Attr("class", "text-xs italic text-ink-faint"), vdom.Text(hint)),
vdom.Span(vdom.Attr("class", "text-ss italic text-ink-faint"), vdom.Text(hint)),
vdom.Button(clear...),
))
}

View File

@@ -113,7 +113,7 @@ func TabGroup(p TabGroupProps) *vdom.VNode {
vdom.Text(item.Title),
}
if item.Badge > 0 {
btn = append(btn, vdom.Span(vdom.Attr("class", "inline-flex items-center justify-center min-w-5 h-5 px-1 text-xs font-semibold bg-primary text-white rounded-full"),
btn = append(btn, vdom.Span(vdom.Attr("class", "inline-flex items-center justify-center min-w-5 h-5 px-1 text-ss font-semibold bg-primary text-white rounded-full"),
vdom.Text(strconv.Itoa(item.Badge))))
}
header = append(header, vdom.Button(btn...))

View File

@@ -56,7 +56,7 @@ func ToggleSwitch(checked bool, onChange func(bool), label, description string,
vdom.Text(label)))
}
if description != "" {
text = append(text, vdom.Span(vdom.Attr("class", "text-xs text-ink-muted"), vdom.Text(description)))
text = append(text, vdom.Span(vdom.Attr("class", "text-ss text-ink-muted"), vdom.Text(description)))
}
mods = append(mods, vdom.Div(text...))
}

View File

@@ -704,7 +704,7 @@ func (t *Tutorial) content(step *TutorialStep, idx, total int) *vdom.VNode {
headerLeft = append(headerLeft, vdom.Span(vdom.Attr("class", "font-medium text-ink"),
vdom.Text(step.Title)))
}
headerLeft = append(headerLeft, vdom.Span(vdom.Attr("class", "text-xs text-ink-muted"),
headerLeft = append(headerLeft, vdom.Span(vdom.Attr("class", "text-ss text-ink-muted"),
vdom.Text(strconv.Itoa(idx+1)+" of "+strconv.Itoa(total))))
header := vdom.Div(vdom.Attr("class", "flex items-center justify-between p-4 pb-2"),

View File

@@ -221,7 +221,7 @@ func (c *USHeatmap) onMove(e vdom.Event) {
// tooltipNode is the HTML tooltip (absolute, pointer-events-none), rendered every pass so
// its ref stays valid; onMove positions it imperatively. Hidden when nothing is hovered.
func (c *USHeatmap) tooltipNode(p USHeatmapProps, hv usHover, mn, mx float64, steps int) *vdom.VNode {
base := "pointer-events-none absolute z-10 min-w-28 max-w-64 rounded-default border border-line bg-surface px-3 py-2 text-xs shadow-lg"
base := "pointer-events-none absolute z-10 min-w-28 max-w-64 rounded-default border border-line bg-surface px-3 py-2 text-ss shadow-lg"
if p.NoTooltip || hv.kind == "" {
return vdom.Div(vdom.WithRef(c.tipRef), vdom.Attr("class", cx(base, "hidden")))
}
@@ -387,7 +387,7 @@ func choroplethLegend(mn, mx float64, steps int, fmt func(float64) string) *vdom
vdom.Attr("style", "background-color:var(--color-choropleth-"+strconv.Itoa(k)+")")))
}
ramp := vdom.Div(kids([]vdom.Mod{vdom.Attr("class", "flex overflow-hidden rounded-xs")}, swatches)...)
return vdom.Div(vdom.Attr("class", "mt-3 flex items-center gap-2 text-xs text-ink-muted"),
return vdom.Div(vdom.Attr("class", "mt-3 flex items-center gap-2 text-ss text-ink-muted"),
vdom.Span(vdom.Attr("style", "font-variant-numeric:tabular-nums"), vdom.Text(fmt(mn))),
ramp,
vdom.Span(vdom.Attr("style", "font-variant-numeric:tabular-nums"), vdom.Text(fmt(mx))),