@calliopelabs/ui 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +332 -2
- package/dist/appearance/AppearancePicker.d.ts +10 -0
- package/dist/appearance/AppearancePicker.js +75 -0
- package/dist/appearance/AppearanceProvider.d.ts +53 -0
- package/dist/appearance/AppearanceProvider.js +113 -0
- package/dist/appearance/AppearanceScript.d.ts +16 -0
- package/dist/appearance/AppearanceScript.js +14 -0
- package/dist/appearance/appearance.d.ts +90 -0
- package/dist/appearance/appearance.js +151 -0
- package/dist/appearance/boot.d.ts +30 -0
- package/dist/appearance/boot.js +91 -0
- package/dist/appearance/brands.d.ts +94 -0
- package/dist/appearance/brands.js +61 -0
- package/dist/appearance/product.d.ts +89 -0
- package/dist/appearance/product.js +96 -0
- package/dist/data/DataTable.d.ts +66 -0
- package/dist/data/DataTable.js +148 -0
- package/dist/data/List.d.ts +55 -0
- package/dist/data/List.js +41 -0
- package/dist/data/types.d.ts +92 -0
- package/dist/data/types.js +2 -0
- package/dist/data/use-row-selection.d.ts +17 -0
- package/dist/data/use-row-selection.js +51 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +61 -0
- package/dist/lib/cn.d.ts +3 -0
- package/dist/lib/cn.js +6 -0
- package/dist/lib/local-store.d.ts +12 -0
- package/dist/lib/local-store.js +54 -0
- package/dist/nav/Nav.d.ts +21 -0
- package/dist/nav/Nav.js +97 -0
- package/dist/nav/model.d.ts +77 -0
- package/dist/nav/model.js +72 -0
- package/dist/overlays/ConfirmDialog.d.ts +37 -0
- package/dist/overlays/ConfirmDialog.js +70 -0
- package/dist/overlays/Dialog.d.ts +18 -0
- package/dist/overlays/Dialog.js +39 -0
- package/dist/overlays/Drawer.d.ts +24 -0
- package/dist/overlays/Drawer.js +42 -0
- package/dist/page/Breadcrumbs.d.ts +20 -0
- package/dist/page/Breadcrumbs.js +25 -0
- package/dist/page/PageFrame.d.ts +17 -0
- package/dist/page/PageFrame.js +14 -0
- package/dist/page/PageHeader.d.ts +28 -0
- package/dist/page/PageHeader.js +13 -0
- package/dist/page/Section.d.ts +18 -0
- package/dist/page/Section.js +12 -0
- package/dist/page/TabNav.d.ts +19 -0
- package/dist/page/TabNav.js +16 -0
- package/dist/primitives/Button.d.ts +16 -0
- package/dist/primitives/Button.js +36 -0
- package/dist/primitives/Checkbox.d.ts +8 -0
- package/dist/primitives/Checkbox.js +13 -0
- package/dist/primitives/DropdownMenu.d.ts +11 -0
- package/dist/primitives/DropdownMenu.js +25 -0
- package/dist/primitives/Input.d.ts +2 -0
- package/dist/primitives/Input.js +5 -0
- package/dist/primitives/Popover.d.ts +5 -0
- package/dist/primitives/Popover.js +13 -0
- package/dist/primitives/Skeleton.d.ts +3 -0
- package/dist/primitives/Skeleton.js +6 -0
- package/dist/primitives/Tabs.d.ts +12 -0
- package/dist/primitives/Tabs.js +22 -0
- package/dist/provider/UIProvider.d.ts +29 -0
- package/dist/provider/UIProvider.js +21 -0
- package/dist/provider/messages.d.ts +106 -0
- package/dist/provider/messages.js +104 -0
- package/dist/shell/AppShell.d.ts +43 -0
- package/dist/shell/AppShell.js +62 -0
- package/dist/shell/BrandMark.d.ts +14 -0
- package/dist/shell/BrandMark.js +14 -0
- package/dist/shell/RailPanel.d.ts +39 -0
- package/dist/shell/RailPanel.js +62 -0
- package/dist/shell/RailTree.d.ts +35 -0
- package/dist/shell/RailTree.js +32 -0
- package/dist/shell/Sidebar.d.ts +26 -0
- package/dist/shell/Sidebar.js +21 -0
- package/dist/shell/UserMenu.d.ts +22 -0
- package/dist/shell/UserMenu.js +31 -0
- package/dist/shell/placement.d.ts +10 -0
- package/dist/shell/placement.js +6 -0
- package/dist/shell/rail-state.d.ts +13 -0
- package/dist/shell/rail-state.js +28 -0
- package/dist/states/EmptyState.d.ts +20 -0
- package/dist/states/EmptyState.js +15 -0
- package/dist/states/ErrorState.d.ts +23 -0
- package/dist/states/ErrorState.js +16 -0
- package/dist/states/LoadingState.d.ts +14 -0
- package/dist/states/LoadingState.js +14 -0
- package/dist/status/StatusBadge.d.ts +19 -0
- package/dist/status/StatusBadge.js +13 -0
- package/dist/status/StatusDot.d.ts +14 -0
- package/dist/status/StatusDot.js +7 -0
- package/dist/status/tones.d.ts +17 -0
- package/dist/status/tones.js +29 -0
- package/dist/styles/preset.css +175 -0
- package/dist/styles/theme.css +339 -0
- package/dist/theme/contrast.d.ts +8 -0
- package/dist/theme/contrast.js +18 -0
- package/dist/theme/css.d.ts +23 -0
- package/dist/theme/css.js +116 -0
- package/dist/theme/tokens.d.ts +195 -0
- package/dist/theme/tokens.js +294 -0
- package/package.json +112 -4
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface ErrorStateProps {
|
|
2
|
+
/** What failed ("Could not load runs"). Defaults to "Something went wrong". */
|
|
3
|
+
title?: string;
|
|
4
|
+
/** The error, or its message. Without one, a generic line. */
|
|
5
|
+
error?: string | {
|
|
6
|
+
message: string;
|
|
7
|
+
} | null;
|
|
8
|
+
onRetry?: () => void;
|
|
9
|
+
retryLabel?: string;
|
|
10
|
+
/**
|
|
11
|
+
* `inline` is a callout inside a page, for one query that failed. `page` is
|
|
12
|
+
* the whole surface, for an error boundary: centred, with the digest a
|
|
13
|
+
* report can be traced by, and a way out when retrying fails the same way.
|
|
14
|
+
*/
|
|
15
|
+
variant?: "inline" | "page";
|
|
16
|
+
/** The server's error digest, shown on the page variant. */
|
|
17
|
+
digest?: string;
|
|
18
|
+
/** A known-good page to escape to, on the page variant. */
|
|
19
|
+
homeHref?: string;
|
|
20
|
+
homeLabel?: string;
|
|
21
|
+
className?: string;
|
|
22
|
+
}
|
|
23
|
+
export declare function ErrorState({ title, error, onRetry, retryLabel, variant, digest, homeHref, homeLabel, className, }: ErrorStateProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { CircleAlertIcon, TriangleAlertIcon } from "lucide-react";
|
|
4
|
+
import { cn } from "../lib/cn.js";
|
|
5
|
+
import { Button } from "../primitives/Button.js";
|
|
6
|
+
import { useUI } from "../provider/UIProvider.js";
|
|
7
|
+
export function ErrorState({ title, error, onRetry, retryLabel, variant = "inline", digest, homeHref, homeLabel, className, }) {
|
|
8
|
+
const { Link, messages } = useUI();
|
|
9
|
+
const message = (typeof error === "string" ? error : error?.message) || messages.states.unexpected;
|
|
10
|
+
const heading = title ?? messages.states.errorTitle;
|
|
11
|
+
const retry = onRetry && (_jsx(Button, { type: "button", size: "sm", variant: "outline", onClick: onRetry, children: retryLabel ?? messages.states.retry }));
|
|
12
|
+
if (variant === "page") {
|
|
13
|
+
return (_jsxs("div", { role: "alert", "data-slot": "error-state", className: cn("flex flex-1 flex-col items-center justify-center gap-4 p-6 text-center", className), children: [_jsx("div", { "aria-hidden": true, className: "rounded-full bg-danger-bg p-4 text-danger", children: _jsx(CircleAlertIcon, { className: "size-8" }) }), _jsxs("div", { className: "min-w-0", children: [_jsx("h2", { className: "text-lg font-semibold", children: heading }), _jsx("p", { className: "mt-1 max-w-sm text-sm [overflow-wrap:anywhere] text-muted-foreground", children: message }), digest && (_jsx("p", { className: "mt-2 font-mono text-xs text-muted-foreground", children: messages.states.errorId(digest) }))] }), (retry || homeHref) && (_jsxs("div", { className: "flex items-center gap-2", children: [retry, homeHref && homeLabel && (_jsx(Button, { asChild: true, size: "sm", variant: "ghost", children: _jsx(Link, { href: homeHref, children: homeLabel }) }))] }))] }));
|
|
14
|
+
}
|
|
15
|
+
return (_jsxs("div", { role: "alert", "data-slot": "error-state", className: cn("flex min-w-0 flex-col gap-3 rounded-lg border border-danger-border bg-danger/5 p-4", className), children: [_jsxs("div", { className: "flex min-w-0 items-start gap-2", children: [_jsx(TriangleAlertIcon, { "aria-hidden": true, className: "mt-0.5 size-4 shrink-0 text-danger" }), _jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "text-sm font-medium text-danger-fg", children: heading }), _jsx("p", { className: "mt-1 text-xs [overflow-wrap:anywhere] text-muted-foreground", children: message })] })] }), retry && _jsx("div", { children: retry })] }));
|
|
16
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface LoadingStateProps {
|
|
2
|
+
/** Announced to screen readers ("Loading runs"). Defaults to "Loading". */
|
|
3
|
+
label?: string;
|
|
4
|
+
/**
|
|
5
|
+
* `rows` stands in for a list: hairline rows in one panel. `page` stands in
|
|
6
|
+
* for a whole route: a row of stat tiles over two panels. Tables draw their
|
|
7
|
+
* own skeleton rows inside the real table, sized from the columns.
|
|
8
|
+
*/
|
|
9
|
+
variant?: "rows" | "page";
|
|
10
|
+
rows?: number;
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
13
|
+
/** The loading placeholder: the geometry of what is coming, so nothing jumps when it lands. */
|
|
14
|
+
export declare function LoadingState({ label, variant, rows, className }: LoadingStateProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { cn } from "../lib/cn.js";
|
|
4
|
+
import { Skeleton } from "../primitives/Skeleton.js";
|
|
5
|
+
import { useUI } from "../provider/UIProvider.js";
|
|
6
|
+
/** The loading placeholder: the geometry of what is coming, so nothing jumps when it lands. */
|
|
7
|
+
export function LoadingState({ label, variant = "rows", rows = 5, className }) {
|
|
8
|
+
const { messages } = useUI();
|
|
9
|
+
const status = (_jsx("p", { role: "status", className: "sr-only", children: label ?? messages.states.loading }));
|
|
10
|
+
if (variant === "page") {
|
|
11
|
+
return (_jsxs("div", { "data-slot": "loading-state", "aria-busy": true, className: cn("flex min-w-0 flex-1 flex-col gap-6", className), children: [status, _jsx("div", { className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-4", children: Array.from({ length: 4 }, (_, i) => (_jsxs("div", { className: "flex flex-col gap-3 rounded-lg border bg-card p-4", children: [_jsx(Skeleton, { className: "h-4 w-24" }), _jsx(Skeleton, { className: "h-8 w-32" })] }, i))) }), _jsxs("div", { className: "grid gap-4 lg:grid-cols-3", children: [_jsxs("div", { className: "flex flex-col gap-3 rounded-lg border bg-card p-4 lg:col-span-2", children: [_jsx(Skeleton, { className: "h-5 w-32" }), _jsx(Skeleton, { className: "h-60 w-full" })] }), _jsxs("div", { className: "flex flex-col gap-3 rounded-lg border bg-card p-4", children: [_jsx(Skeleton, { className: "h-5 w-28" }), _jsx(Skeleton, { className: "h-60 w-full" })] })] })] }));
|
|
12
|
+
}
|
|
13
|
+
return (_jsxs("div", { "data-slot": "loading-state", "aria-busy": true, className: cn("min-w-0 overflow-hidden rounded-lg border", className), children: [status, Array.from({ length: rows }, (_, i) => (_jsxs("div", { className: "flex items-center gap-3 border-b px-(--row-pad-x) py-(--row-pad-y) last:border-b-0", children: [_jsx(Skeleton, { className: "size-4 shrink-0" }), _jsx(Skeleton, { className: "h-4 flex-1" }), _jsx(Skeleton, { className: "h-4 w-20 shrink-0" })] }, i)))] }));
|
|
14
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type * as React from "react";
|
|
2
|
+
import { type StatusTone } from "./tones.js";
|
|
3
|
+
export interface StatusBadgeProps extends Omit<React.ComponentProps<"span">, "children"> {
|
|
4
|
+
tone: StatusTone;
|
|
5
|
+
/** The status in words ("running", "failed"). Colour is never the only carrier. */
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
/** In flight (deploying, running): the dot pulses; the label holds still, so it stays readable. */
|
|
8
|
+
pulse?: boolean;
|
|
9
|
+
/** Strike the label through, for superseded states. */
|
|
10
|
+
struck?: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* A status pill: mono label, tinted fill, glowing dot (the admin badge
|
|
14
|
+
* recipe). Apps map their own states onto the five tones, once, in a table:
|
|
15
|
+
*
|
|
16
|
+
* const DEPLOYMENT_TONE = { running: "ok", failed: "error", deploying: "info", ... };
|
|
17
|
+
* <StatusBadge tone={DEPLOYMENT_TONE[d.status]} pulse={d.status === "deploying"}>{label}</StatusBadge>
|
|
18
|
+
*/
|
|
19
|
+
export declare function StatusBadge({ tone, children, pulse, struck, className, ...props }: StatusBadgeProps): React.JSX.Element;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { IN_FLIGHT, PILL_TONE } from "./tones.js";
|
|
4
|
+
/**
|
|
5
|
+
* A status pill: mono label, tinted fill, glowing dot (the admin badge
|
|
6
|
+
* recipe). Apps map their own states onto the five tones, once, in a table:
|
|
7
|
+
*
|
|
8
|
+
* const DEPLOYMENT_TONE = { running: "ok", failed: "error", deploying: "info", ... };
|
|
9
|
+
* <StatusBadge tone={DEPLOYMENT_TONE[d.status]} pulse={d.status === "deploying"}>{label}</StatusBadge>
|
|
10
|
+
*/
|
|
11
|
+
export function StatusBadge({ tone, children, pulse = false, struck = false, className, ...props }) {
|
|
12
|
+
return (_jsxs("span", { "data-slot": "status-badge", "data-tone": tone, className: cn("inline-flex h-5 w-fit shrink-0 items-center gap-1.5 overflow-hidden rounded-full border px-2 font-mono text-xs font-semibold whitespace-nowrap", PILL_TONE[tone], className), ...props, children: [_jsx("span", { "aria-hidden": true, className: cn("size-1.5 shrink-0 rounded-full bg-current shadow-[0_0_8px_currentColor]", pulse && IN_FLIGHT) }), _jsx("span", { className: cn("truncate", struck && "line-through"), children: children })] }));
|
|
13
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type StatusTone } from "./tones.js";
|
|
2
|
+
export interface StatusDotProps {
|
|
3
|
+
tone: StatusTone;
|
|
4
|
+
/** In flight (deploying, running): the dot pulses. */
|
|
5
|
+
pulse?: boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Read by screen readers when the dot stands alone (a tree row, a table
|
|
8
|
+
* cell with no text). Leave it out when a visible label sits beside it.
|
|
9
|
+
*/
|
|
10
|
+
label?: string;
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
13
|
+
/** A status mark. Its colour is a status token, so it means the same thing whatever the accent. */
|
|
14
|
+
export declare function StatusDot({ tone, pulse, label, className }: StatusDotProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { DOT_TONE, IN_FLIGHT } from "./tones.js";
|
|
4
|
+
/** A status mark. Its colour is a status token, so it means the same thing whatever the accent. */
|
|
5
|
+
export function StatusDot({ tone, pulse = false, label, className }) {
|
|
6
|
+
return (_jsxs("span", { className: cn("inline-flex shrink-0 items-center", className), "data-tone": tone, children: [_jsx("span", { "aria-hidden": true, className: cn("inline-block size-2 rounded-full shadow-[0_0_0_2px_var(--background)]", DOT_TONE[tone], pulse && IN_FLIGHT) }), label && _jsx("span", { className: "sr-only", children: label })] }));
|
|
7
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one status colour map (Astrolift #2126). Status is semantic and never
|
|
3
|
+
* follows the accent: with a copper or ice accent a healthy deployment is
|
|
4
|
+
* still lime, a failure still red. Every tone here is a status token.
|
|
5
|
+
*/
|
|
6
|
+
export type StatusTone = "ok" | "warn" | "error" | "info" | "muted";
|
|
7
|
+
export declare const STATUS_TONES: readonly StatusTone[];
|
|
8
|
+
/** The status token each tone paints. `muted` has none: it is the muted foreground. */
|
|
9
|
+
export declare const TONE_TOKEN: Record<StatusTone, "success" | "warning" | "danger" | "info" | null>;
|
|
10
|
+
/** A dot: solid status colour with a soft halo, the one glow the brand permits besides focus. */
|
|
11
|
+
export declare const DOT_TONE: Record<StatusTone, string>;
|
|
12
|
+
/** How much of the status colour tints a pill's fill (`bg-success/15`). */
|
|
13
|
+
export declare const PILL_TINT = 0.15;
|
|
14
|
+
/** A pill: tinted fill, readable text, tinted hairline. */
|
|
15
|
+
export declare const PILL_TONE: Record<StatusTone, string>;
|
|
16
|
+
/** In-flight states pulse; nothing else moves. Reduced motion holds it still. */
|
|
17
|
+
export declare const IN_FLIGHT = "animate-pulse motion-reduce:animate-none";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export const STATUS_TONES = ["ok", "warn", "error", "info", "muted"];
|
|
2
|
+
/** The status token each tone paints. `muted` has none: it is the muted foreground. */
|
|
3
|
+
export const TONE_TOKEN = {
|
|
4
|
+
ok: "success",
|
|
5
|
+
warn: "warning",
|
|
6
|
+
error: "danger",
|
|
7
|
+
info: "info",
|
|
8
|
+
muted: null,
|
|
9
|
+
};
|
|
10
|
+
/** A dot: solid status colour with a soft halo, the one glow the brand permits besides focus. */
|
|
11
|
+
export const DOT_TONE = {
|
|
12
|
+
ok: "bg-success shadow-success/50",
|
|
13
|
+
warn: "bg-warning shadow-warning/50",
|
|
14
|
+
error: "bg-danger shadow-danger/50",
|
|
15
|
+
info: "bg-info shadow-info/50",
|
|
16
|
+
muted: "bg-muted-foreground shadow-muted-foreground/40",
|
|
17
|
+
};
|
|
18
|
+
/** How much of the status colour tints a pill's fill (`bg-success/15`). */
|
|
19
|
+
export const PILL_TINT = 0.15;
|
|
20
|
+
/** A pill: tinted fill, readable text, tinted hairline. */
|
|
21
|
+
export const PILL_TONE = {
|
|
22
|
+
ok: "border-success-border bg-success/15 text-success-fg",
|
|
23
|
+
warn: "border-warning-border bg-warning/15 text-warning-fg",
|
|
24
|
+
error: "border-danger-border bg-danger/15 text-danger-fg",
|
|
25
|
+
info: "border-info-border bg-info/15 text-info-fg",
|
|
26
|
+
muted: "border-border bg-foreground/5 text-muted-foreground",
|
|
27
|
+
};
|
|
28
|
+
/** In-flight states pulse; nothing else moves. Reduced motion holds it still. */
|
|
29
|
+
export const IN_FLIGHT = "animate-pulse motion-reduce:animate-none";
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @calliopelabs/ui Tailwind 4 preset.
|
|
3
|
+
*
|
|
4
|
+
* @import "tailwindcss";
|
|
5
|
+
* @import "@calliopelabs/ui/preset.css";
|
|
6
|
+
*
|
|
7
|
+
* It brings the theme tokens, maps them onto Tailwind's colour, radius, font,
|
|
8
|
+
* type and motion scales, points Tailwind at this package's components so
|
|
9
|
+
* their classes are generated, and sets the family's base layer.
|
|
10
|
+
*/
|
|
11
|
+
@import "./theme.css";
|
|
12
|
+
|
|
13
|
+
/* The package's own components: their classes are generated with the app's. */
|
|
14
|
+
@source "../";
|
|
15
|
+
|
|
16
|
+
/* Dark follows the ground, not the OS: `data-mode` on <html> says which. */
|
|
17
|
+
@custom-variant dark (&:where([data-mode="dark"], [data-mode="dark"] *));
|
|
18
|
+
|
|
19
|
+
@theme inline {
|
|
20
|
+
--color-background: var(--background);
|
|
21
|
+
--color-foreground: var(--foreground);
|
|
22
|
+
--color-card: var(--card);
|
|
23
|
+
--color-card-foreground: var(--card-foreground);
|
|
24
|
+
--color-popover: var(--popover);
|
|
25
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
26
|
+
--color-primary: var(--primary);
|
|
27
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
28
|
+
--color-secondary: var(--secondary);
|
|
29
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
30
|
+
--color-muted: var(--muted);
|
|
31
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
32
|
+
--color-accent: var(--accent);
|
|
33
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
34
|
+
--color-destructive: var(--destructive);
|
|
35
|
+
--color-border: var(--border);
|
|
36
|
+
--color-input: var(--input);
|
|
37
|
+
--color-ring: var(--ring);
|
|
38
|
+
--color-chart-1: var(--chart-1);
|
|
39
|
+
--color-chart-2: var(--chart-2);
|
|
40
|
+
--color-chart-3: var(--chart-3);
|
|
41
|
+
--color-chart-4: var(--chart-4);
|
|
42
|
+
--color-chart-5: var(--chart-5);
|
|
43
|
+
--color-sidebar: var(--sidebar);
|
|
44
|
+
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
45
|
+
--color-sidebar-primary: var(--sidebar-primary);
|
|
46
|
+
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
47
|
+
--color-sidebar-accent: var(--sidebar-accent);
|
|
48
|
+
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
49
|
+
--color-sidebar-border: var(--sidebar-border);
|
|
50
|
+
--color-sidebar-ring: var(--sidebar-ring);
|
|
51
|
+
--color-surface-0: var(--surface-0);
|
|
52
|
+
--color-surface-1: var(--surface-1);
|
|
53
|
+
--color-surface-2: var(--surface-2);
|
|
54
|
+
|
|
55
|
+
/* Semantic status: solid base, -fg text on the tint, -bg fill, -border hairline. */
|
|
56
|
+
--color-success: var(--success);
|
|
57
|
+
--color-success-fg: var(--success-fg);
|
|
58
|
+
--color-success-bg: var(--success-bg);
|
|
59
|
+
--color-success-border: var(--success-border);
|
|
60
|
+
--color-warning: var(--warning);
|
|
61
|
+
--color-warning-fg: var(--warning-fg);
|
|
62
|
+
--color-warning-bg: var(--warning-bg);
|
|
63
|
+
--color-warning-border: var(--warning-border);
|
|
64
|
+
--color-info: var(--info);
|
|
65
|
+
--color-info-fg: var(--info-fg);
|
|
66
|
+
--color-info-bg: var(--info-bg);
|
|
67
|
+
--color-info-border: var(--info-border);
|
|
68
|
+
--color-danger: var(--danger);
|
|
69
|
+
--color-danger-fg: var(--danger-fg);
|
|
70
|
+
--color-danger-bg: var(--danger-bg);
|
|
71
|
+
--color-danger-border: var(--danger-border);
|
|
72
|
+
|
|
73
|
+
/* IBM Plex Sans for UI, IBM Plex Mono for anything technical, DM Sans for headings. */
|
|
74
|
+
--font-sans: var(--font-plex-sans, "IBM Plex Sans"), system-ui, sans-serif;
|
|
75
|
+
--font-mono:
|
|
76
|
+
var(--font-plex-mono, "IBM Plex Mono"), ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
77
|
+
--font-head: var(--font-dm-sans, "DM Sans"), system-ui, sans-serif;
|
|
78
|
+
|
|
79
|
+
/* `rounded-lg` is the corners setting itself; clamped so 0px never goes negative. */
|
|
80
|
+
--radius-sm: max(0px, calc(var(--radius) - 4px));
|
|
81
|
+
--radius-md: max(0px, calc(var(--radius) - 2px));
|
|
82
|
+
--radius-lg: var(--radius);
|
|
83
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
84
|
+
--radius-2xl: calc(var(--radius) + 8px);
|
|
85
|
+
--radius-3xl: calc(var(--radius) + 12px);
|
|
86
|
+
--radius-4xl: calc(var(--radius) + 16px);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
@theme {
|
|
90
|
+
/* The micro step below xs, for eyebrows, counts and table heads. */
|
|
91
|
+
--text-2xs: 0.6875rem;
|
|
92
|
+
--text-2xs--line-height: 1rem;
|
|
93
|
+
|
|
94
|
+
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
|
95
|
+
--ease-emphasized: cubic-bezier(0.3, 0, 0, 1);
|
|
96
|
+
|
|
97
|
+
/* Overlays arrive calmly and leave at once. */
|
|
98
|
+
--animate-cui-fade-in: cui-fade-in var(--motion-fast) var(--ease-standard);
|
|
99
|
+
--animate-cui-pop-in: cui-pop-in var(--motion-base) var(--ease-emphasized);
|
|
100
|
+
--animate-cui-slide-in-right: cui-slide-in-right var(--motion-base) var(--ease-emphasized);
|
|
101
|
+
--animate-cui-slide-in-left: cui-slide-in-left var(--motion-base) var(--ease-emphasized);
|
|
102
|
+
--animate-cui-slide-in-bottom: cui-slide-in-bottom var(--motion-base) var(--ease-emphasized);
|
|
103
|
+
/* A table's rows being replaced: a short bar travelling along the top edge. */
|
|
104
|
+
--animate-cui-progress: cui-progress 1.4s var(--ease-standard) infinite;
|
|
105
|
+
|
|
106
|
+
@keyframes cui-fade-in {
|
|
107
|
+
from {
|
|
108
|
+
opacity: 0;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/* `transform` composes with the `translate` that centres a dialog. */
|
|
112
|
+
@keyframes cui-pop-in {
|
|
113
|
+
from {
|
|
114
|
+
opacity: 0;
|
|
115
|
+
transform: scale(0.98);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
@keyframes cui-slide-in-right {
|
|
119
|
+
from {
|
|
120
|
+
transform: translateX(1.5rem);
|
|
121
|
+
opacity: 0;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
@keyframes cui-slide-in-left {
|
|
125
|
+
from {
|
|
126
|
+
transform: translateX(-1.5rem);
|
|
127
|
+
opacity: 0;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
@keyframes cui-progress {
|
|
131
|
+
from {
|
|
132
|
+
translate: -100% 0;
|
|
133
|
+
}
|
|
134
|
+
to {
|
|
135
|
+
translate: 300% 0;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
@keyframes cui-slide-in-bottom {
|
|
139
|
+
from {
|
|
140
|
+
transform: translateY(1.5rem);
|
|
141
|
+
opacity: 0;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
@layer base {
|
|
147
|
+
*,
|
|
148
|
+
::before,
|
|
149
|
+
::after {
|
|
150
|
+
border-color: var(--border);
|
|
151
|
+
outline-color: color-mix(in oklab, var(--ring) 50%, transparent);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
body {
|
|
155
|
+
@apply bg-background font-sans text-foreground;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
h1,
|
|
159
|
+
h2,
|
|
160
|
+
h3 {
|
|
161
|
+
@apply font-head;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/* Motion is never the only carrier of meaning; with reduced motion it stops. */
|
|
165
|
+
@media (prefers-reduced-motion: reduce) {
|
|
166
|
+
*,
|
|
167
|
+
::before,
|
|
168
|
+
::after {
|
|
169
|
+
animation-duration: 0.01ms !important;
|
|
170
|
+
animation-iteration-count: 1 !important;
|
|
171
|
+
transition-duration: 0.01ms !important;
|
|
172
|
+
scroll-behavior: auto !important;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|