Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions web/oss/src/styles/theme/controlScale.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/**
* Control geometry scale — the ONE definition of control dimensions.
*
* Shared because two toolchains consume it: web/oss (Tailwind v3, JS config) spreads it into
* `theme.extend`, and web/mobile (Tailwind v4, CSS-first) emits it as `@theme` custom
* properties. Keeping it in the v3 config forced mobile to copy the pixel values by hand,
* which drifts silently — a shared component would then render at different sizes per app.
*/
// ── Control scale ────────────────────────────────────────────────
// Geometry + typography for the shadcn control primitives (Button/Input/Badge).
// The single place to retune control sizing: components reference these names and never
// raw pixels. Namespaced (`control-*`, `btn-*`, `input-*`) and purely ADDITIVE, exactly
// like the `tremor-*` scale below, so no existing `h-*`/`rounded-*`/`text-*` changes.
//
// Values are theme-invariant (they don't flip light/dark), which is why they live here
// rather than in palette.ts. They currently encode antd's measured geometry so the
// migration is visually neutral — retune HERE once antd is gone, not in the components.
//
// v4 note: this whole object becomes a `@theme` block; the class names do not change.
export const controlScale = {
height: {
"control-sm": "24px",
control: "28px",
"control-lg": "34px",
// antd Switch track (default/small) + handle. Own dims — not the control heights.
switch: "22px",
"switch-sm": "16px",
"switch-thumb": "18px",
"switch-thumb-sm": "12px",
// antd Checkbox/Radio box (16px) + Radio inner dot (8px) + Checkbox indeterminate dash (7px).
"control-check": "16px",
"control-dot": "8px",
"control-check-dash": "7px",
},
width: {
"control-sm": "24px",
control: "28px",
"control-lg": "34px",
// antd Switch min track width (default/small) + handle.
switch: "44px",
"switch-sm": "28px",
"switch-thumb": "18px",
"switch-thumb-sm": "12px",
// antd Checkbox/Radio box (16px) + Radio inner dot (8px) + Checkbox indeterminate dash (7px).
"control-check": "16px",
"control-dot": "8px",
"control-check-dash": "7px",
},
borderRadius: {
"control-sm": "6px",
control: "8px",
"control-lg": "10px",
// antd shape="circle". 50%, not 9999px — they render identically on a square but
// the parity gate compares computed values.
"control-round": "50%",
},
spacing: {
// Horizontal padding differs between buttons and inputs at md/lg, so they are
// separate families rather than one fudged scale.
"btn-sm": "7px",
btn: "15px",
"btn-lg": "15px",
"input-sm": "7px",
input: "11px",
"input-lg": "11px",
// Vertical padding for inputs: heights are padding + line-height derived (antd's
// model), not fixed. `ghost` adds 1px to compensate for its missing border.
"input-y-sm": "0px",
"input-y": "4px",
"input-y-lg": "7px",
"input-y-ghost-sm": "1px",
"input-y-ghost": "5px",
"input-y-ghost-lg": "8px",
},
// Type ramps. Buttons and fields differ at `sm` (12px vs 10px), so they are separate
// ramps rather than one averaged scale. Names avoid every colour-token name, because
// `text-*` is shared between font-size and text-colour utilities.
// Exact ratios, not rounded decimals: 1.8667 computes to 22.4004px where antd renders
// 22.4 and the parity gate flags the difference.
fontSize: {
"btn-sm": ["12px", {lineHeight: "normal"}] as [string, {lineHeight: string}],
"btn-md": ["12px", {lineHeight: "normal"}] as [string, {lineHeight: string}],
"btn-lg": ["14px", {lineHeight: "normal"}] as [string, {lineHeight: string}],
"field-sm": ["10px", {lineHeight: "1.6666666666666667"}] as [string, {lineHeight: string}],
"field-md": ["12px", {lineHeight: "1.6666666666666667"}] as [string, {lineHeight: string}],
"field-lg": ["14px", {lineHeight: "1.5714285714285714"}] as [string, {lineHeight: string}],
"badge-md": ["12px", {lineHeight: "1.8666666666666667"}] as [string, {lineHeight: string}],
},
}
119 changes: 119 additions & 0 deletions web/oss/src/styles/theme/shadcnTokens.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/**
* Token contract for the shadcn primitives in @agenta/ui — utility name → CSS variable.
*
* Three consumers compile this: web/oss (Tailwind v3 `theme.extend.colors`), Storybook, and
* web/mobile (Tailwind v4, via scripts/generate-shadcn-tokens.ts). Shared so a component
* written against `bg-btn-default-bg` resolves identically everywhere, instead of each app
* maintaining its own alias table and drifting.
*/
// ── shadcn token bridge ──────────────────────────────────────────
// Semantic token names consumed by the shadcn components in
// @agenta/ui, mapped to the palette-derived --ag-* layer (theme-variables.css,
// generated from palette.ts). ONE shared definition for the app + Storybook: flip
// the underlying layer and every component follows; when antd is removed nothing here
// changes. Purely ADDITIVE — the app uses `colorX`-named + default Tailwind classes,
// never these shadcn names, so nothing is overridden. Radius is intentionally NOT
// bridged (theme-invariant; overriding it would change every `rounded-*` in the app).
export const shadcnTokens = {
background: "var(--ag-colorBgContainer)",
foreground: "var(--ag-colorText)",
border: "var(--ag-colorBorder)",
input: "var(--ag-colorBorder)",
ring: "var(--ag-colorPrimary)",
// antd's keyboard focus ring is `colorPrimaryBorder` (4px, offset 1px). NOTE: it equals
// colorInfoBorder in LIGHT (both #d6dee6) but diverges in DARK (olive vs navy) — needs its
// own token, which the forced-state gate caught.
"focus-ring": "var(--ag-colorPrimaryBorder)",
primary: {
DEFAULT: "var(--ag-colorPrimary)",
// antd fills a CHECKED control with colorPrimaryHover on hover (Radio/Checkbox).
hover: "var(--ag-colorPrimaryHover)",
foreground: "var(--ag-colorTextLightSolid)",
},
secondary: {DEFAULT: "var(--ag-colorFillSecondary)", foreground: "var(--ag-colorText)"},
muted: {DEFAULT: "var(--ag-colorFillTertiary)", foreground: "var(--ag-colorTextSecondary)"},
accent: {DEFAULT: "var(--ag-colorFillSecondary)", foreground: "var(--ag-colorText)"},
destructive: {DEFAULT: "var(--ag-colorError)", foreground: "var(--ag-colorTextLightSolid)"},
popover: {DEFAULT: "var(--ag-colorBgElevated)", foreground: "var(--ag-colorText)"},
card: {DEFAULT: "var(--ag-colorBgContainer)", foreground: "var(--ag-colorText)"},
placeholder: "var(--ag-colorTextPlaceholder)",
// Disabled + interaction states used by the control primitives.
disabled: {
DEFAULT: "var(--ag-colorTextDisabled)",
bg: "var(--ag-colorBgContainerDisabled)",
border: "var(--ag-input-disabled-border)",
},
// Semantic status families (Badge/Tag/status chips): {DEFAULT = text, bg, border}.
success: {
DEFAULT: "var(--ag-colorSuccess)",
bg: "var(--ag-colorSuccessBg)",
border: "var(--ag-colorSuccessBorder)",
},
warning: {
DEFAULT: "var(--ag-colorWarningText)",
bg: "var(--ag-colorWarningBg)",
border: "var(--ag-colorWarningBorder)",
},
error: {
DEFAULT: "var(--ag-colorError)",
bg: "var(--ag-colorErrorBg)",
border: "var(--ag-colorErrorBorder)",
hover: "var(--ag-colorErrorHover)",
active: "var(--ag-colorErrorActive)",
},
info: {
DEFAULT: "var(--ag-colorInfo)",
bg: "var(--ag-colorInfoBg)",
border: "var(--ag-colorInfoBorder)",
},
draft: {
DEFAULT: "var(--ag-draft-text)",
bg: "var(--ag-draft-bg)",
border: "var(--ag-draft-border)",
},
// antd preset Tag colors (color="blue"/"green"). Namespaced `tag-*` to avoid
// clobbering Tailwind's default `blue`/`green` scales (used across the app).
"tag-blue": {DEFAULT: "var(--ag-preset-blue-text)", bg: "var(--ag-preset-blue-bg)"},
"tag-green": {DEFAULT: "var(--ag-preset-green-text)", bg: "var(--ag-preset-green-bg)"},
"tag-orange": {DEFAULT: "var(--ag-preset-orange-text)", bg: "var(--ag-preset-orange-bg)"},
"tag-red": {DEFAULT: "var(--ag-preset-red-text)", bg: "var(--ag-preset-red-bg)"},
"tag-purple": {DEFAULT: "var(--ag-preset-purple-text)", bg: "var(--ag-preset-purple-bg)"},
"tag-pink": {DEFAULT: "var(--ag-preset-pink-text)", bg: "var(--ag-preset-pink-bg)"},
"tag-yellow": {DEFAULT: "var(--ag-preset-yellow-text)", bg: "var(--ag-preset-yellow-bg)"},
"tag-volcano": {DEFAULT: "var(--ag-preset-volcano-text)", bg: "var(--ag-preset-volcano-bg)"},
"tag-geekblue": {DEFAULT: "var(--ag-preset-geekblue-text)", bg: "var(--ag-preset-geekblue-bg)"},
"tag-lime": {DEFAULT: "var(--ag-preset-lime-text)", bg: "var(--ag-preset-lime-bg)"},
"tag-cyan": {DEFAULT: "var(--ag-preset-cyan-text)", bg: "var(--ag-preset-cyan-bg)"},
"tag-magenta": {DEFAULT: "var(--ag-preset-magenta-text)", bg: "var(--ag-preset-magenta-bg)"},
"tag-gold": {DEFAULT: "var(--ag-preset-gold-text)", bg: "var(--ag-preset-gold-bg)"},
// Button state tokens.
btn: {
"primary-fg": "var(--ag-btn-primary-text)",
"primary-hover": "var(--ag-btn-primary-hover)",
"primary-active": "var(--ag-btn-primary-active)",
"default-bg": "var(--ag-btn-default-bg)",
"default-hover-bg": "var(--ag-btn-default-hover-bg)",
"default-active-bg": "var(--ag-btn-default-active-bg)",
"text-hover-bg": "var(--ag-btn-text-hover-bg)",
"text-active-bg": "var(--ag-btn-text-active-bg)",
link: "var(--ag-btn-link)",
"link-hover": "var(--ag-btn-link-hover)",
"link-active": "var(--ag-btn-link-active)",
},
// antd Empty's DEFAULT illustration greys (opaque — see palette.ts `emptyImage`).
empty: {
shadow: "var(--ag-empty-shadow)",
sheet: "var(--ag-empty-sheet)",
flap: "var(--ag-empty-flap)",
front: "var(--ag-empty-front)",
hole: "var(--ag-empty-hole)",
},
// Fills.
chip: "var(--ag-colorFillChip)",
fill: {
DEFAULT: "var(--ag-colorFill)",
secondary: "var(--ag-colorFillSecondary)",
tertiary: "var(--ag-colorFillTertiary)",
quaternary: "var(--ag-colorFillQuaternary)",
},
}
Loading
Loading