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:
@@ -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.")),
|
||||
),
|
||||
|
||||
@@ -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")}
|
||||
|
||||
@@ -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)),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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"><ToastProvider></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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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} />
|
||||
|
||||
@@ -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 ?? "")}>
|
||||
|
||||
@@ -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
|
||||
? (
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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) => (
|
||||
|
||||
@@ -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)...)
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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...),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -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...))
|
||||
|
||||
@@ -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...))
|
||||
}
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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))),
|
||||
|
||||
Reference in New Issue
Block a user