feat: establish shared Ekklesia design system
CI / verify (pull_request) Successful in 48s
CI / infrastructure-smoke (pull_request) Successful in 20s
CI / migration-smoke (pull_request) Successful in 1m47s

This commit is contained in:
ekklesia
2026-09-30 18:21:09 -05:00
parent 3ca6b2cb32
commit 3a26ef49ad
9 changed files with 336 additions and 110 deletions
+42 -30
View File
@@ -12,7 +12,7 @@ import {
* every consumer's meaning changing with it: `background.raised` stays "the surface that sits above
* an ordinary surface" whatever a church's brand makes it.
*
* The default values are a neutral, high-contrast light theme. They are defaults, not a brand —
* The default values are Ekklesia's calm, teal-accented light theme. They remain semantic defaults —
* a deployment overrides them by installing different values at its host root, and this pass
* deliberately ships no theme editor, brand builder, or dark-mode variant to do that with.
*
@@ -31,14 +31,14 @@ const declarations = [
description: "The furthest-back background of a whole page or a full-viewport display.",
label: "Page background",
name: "background.page",
value: "#f6f6f5",
value: "#f3f7f6",
},
{
description:
"A large working area inside a page — a scrolling list region, a preview area, an editor body.",
label: "Canvas background",
name: "background.canvas",
value: "#fbfbfa",
value: "#f8faf9",
},
{
description: "An ordinary panel, card, table, or dialog body sitting on the page.",
@@ -62,7 +62,7 @@ const declarations = [
description: "A recessed area such as a text input, a code block, or a well.",
label: "Inset background",
name: "background.inset",
value: "#f2f2f0",
value: "#edf3f1",
},
// ---------------------------------------------------------------------------------------------
@@ -72,19 +72,19 @@ const declarations = [
description: "Body copy and headings — the default foreground for readable content.",
label: "Primary text",
name: "text.primary",
value: "#1c1917",
value: "#182321",
},
{
description: "Supporting text that is still content: captions, secondary columns, help text.",
label: "Secondary text",
name: "text.secondary",
value: "#57534e",
value: "#4f5f5b",
},
{
description: "De-emphasised text such as placeholders, timestamps, and disabled labels.",
label: "Muted text",
name: "text.muted",
value: "#79716b",
value: "#6c7b77",
},
{
description: "Text drawn on a strongly coloured background, such as a primary button.",
@@ -118,31 +118,43 @@ const declarations = [
description: "The primary action colour: primary buttons, selected tabs, active links.",
label: "Accent",
name: "accent.base",
value: "#1d4ed8",
value: "#4fb3a8",
},
{
description: "The accent background under a hovered primary action.",
label: "Accent hover",
name: "accent.hover",
value: "#5ab9ae",
},
{
description: "The accent background while a primary action is pressed.",
label: "Accent active",
name: "accent.active",
value: "#45a59b",
},
{
description: "A deeper accent for pressed primary actions and high-emphasis emphasis.",
label: "Strong accent",
name: "accent.strong",
value: "#1e3a8a",
value: "#246b64",
},
{
description: "A faint accent wash for selected rows and subtle accent backgrounds.",
label: "Subtle accent",
name: "accent.subtle",
value: "#e8effc",
value: "#def2ef",
},
{
description: "Foreground drawn on top of the accent background.",
label: "Accent foreground",
name: "accent.foreground",
value: "#ffffff",
value: "#102a27",
},
{
description: "The focus ring colour. Never the only signal that something has focus.",
label: "Focus ring",
name: "accent.focus",
value: "#1d4ed8",
value: "#287a72",
},
// ---------------------------------------------------------------------------------------------
@@ -152,19 +164,19 @@ const declarations = [
description: "The default border around panels, inputs, and table cells.",
label: "Border",
name: "border.base",
value: "#d7d3d0",
value: "#d3dedb",
},
{
description: "A heavier border for emphasis, active inputs, and selected outlines.",
label: "Strong border",
name: "border.strong",
value: "#a8a29e",
value: "#91a6a1",
},
{
description: "A hairline rule separating rows or sections inside one surface.",
label: "Divider",
name: "border.divider",
value: "#e7e5e4",
value: "#e2eae8",
},
{
description: "The border width used by controls and panels.",
@@ -234,13 +246,13 @@ const declarations = [
description: "Background of a neutral informational badge or banner.",
label: "Info background",
name: "status.info-background",
value: "#e8effc",
value: "#def2ef",
},
{
description: "Border of a neutral informational badge or banner.",
label: "Info border",
name: "status.info-border",
value: "#bfd3f7",
value: "#9bd5ce",
},
{
description: "The non-colour signal for information, rendered beside the label.",
@@ -256,25 +268,25 @@ const declarations = [
description: "Background wash under a hovered control or row.",
label: "Hover background",
name: "state.hover-background",
value: "#f2f2f0",
value: "#edf3f1",
},
{
description: "Background wash under a control being pressed.",
label: "Pressed background",
name: "state.pressed-background",
value: "#e7e5e4",
value: "#e1ebe8",
},
{
description: "Background of a selected row, tab, or list item.",
label: "Selected background",
name: "state.selected-background",
value: "#e8effc",
value: "#def2ef",
},
{
description: "Foreground of a selected row, tab, or list item.",
label: "Selected foreground",
name: "state.selected-foreground",
value: "#1e3a8a",
value: "#205f59",
},
{
description: "Opacity applied to a disabled control. Disabled state is never colour alone.",
@@ -408,7 +420,7 @@ const declarations = [
description: "Spacing inside a compact control.",
label: "Extra small spacing",
name: "spacing.xs",
value: "0.25rem",
value: "0.375rem",
},
{
description: "Spacing between a label and its field.",
@@ -460,13 +472,13 @@ const declarations = [
description: "Corner radius for controls, inputs, and buttons.",
label: "Medium radius",
name: "radius.md",
value: "0.375rem",
value: "0.625rem",
},
{
description: "Corner radius for panels and dialogs.",
label: "Large radius",
name: "radius.lg",
value: "0.75rem",
value: "0.875rem",
},
{
description: "Fully rounded ends, for pills and status dots.",
@@ -484,19 +496,19 @@ const declarations = [
description: "Subtle lift for a resting panel.",
label: "Small shadow",
name: "shadow.sm",
value: "0 1px 2px rgba(23, 23, 21, 0.08)",
value: "0 1px 3px rgba(24, 35, 33, 0.08)",
},
{
description: "Shadow for a popover or a raised surface.",
label: "Medium shadow",
name: "shadow.md",
value: "0 4px 12px rgba(23, 23, 21, 0.12)",
value: "0 8px 24px rgba(24, 35, 33, 0.12)",
},
{
description: "Shadow for a modal dialog.",
label: "Large shadow",
name: "shadow.lg",
value: "0 16px 40px rgba(23, 23, 21, 0.22)",
value: "0 18px 48px rgba(24, 35, 33, 0.2)",
},
// ---------------------------------------------------------------------------------------------
@@ -506,19 +518,19 @@ const declarations = [
description: "Height of a compact control.",
label: "Small control height",
name: "control.height-sm",
value: "1.75rem",
value: "2rem",
},
{
description: "Height of an ordinary button, input, or select.",
label: "Medium control height",
name: "control.height-md",
value: "2.25rem",
value: "2.5rem",
},
{
description: "Height of a prominent primary control.",
label: "Large control height",
name: "control.height-lg",
value: "2.75rem",
value: "3rem",
},
{
description: "Horizontal padding inside a control.",
@@ -60,6 +60,8 @@ describe("the Ekklesia design token registry", () => {
"text.warning",
"text.danger",
"accent.base",
"accent.hover",
"accent.active",
"accent.focus",
"border.base",
"border.divider",