Sign In

@protolabsai/design

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@protolabsai/design - npm Package Compare versions

Comparing version
0.4.0
to
0.5.0
+88
-3
dist/tokens.css
/* GENERATED from src/tokens.js by scripts/build.mjs — do not edit by hand. */
:root {
color-scheme: dark;
--pl-color-brand-lavender: #9b87f2;
--pl-color-brand-lavender-light: #b8a6f5;
--pl-color-brand-lavender-deep: #5b3fc9;
--pl-color-brand-indigo: #6366f1;
--pl-color-brand-indigo-bright: #818cf8;
--pl-color-brand-indigo-deep: #4f46e5;
--pl-color-bg: #0a0a0c;

@@ -11,7 +14,14 @@ --pl-color-bg-raised: #131316;

--pl-color-bg-hover: #19191d;
--pl-color-bg-inset: #060608;
--pl-color-overlay: rgba(0, 0, 0, 0.6);
--pl-color-fg: #ededed;
--pl-color-fg-muted: #a1a1aa;
--pl-color-fg-subtle: #71717a;
--pl-color-fg-on-accent: #0a0a0c;
--pl-color-border: rgba(255, 255, 255, 0.08);
--pl-color-border-strong: rgba(255, 255, 255, 0.18);
--pl-color-overlay: rgba(0, 0, 0, 0.6);
--pl-color-accent: #9b87f2;
--pl-color-accent-hover: #b8a6f5;
--pl-color-accent-fg: #b8a6f5;
--pl-color-focus: #9b87f2;
--pl-color-status-success: oklch(0.72 0.13 145);

@@ -51,8 +61,83 @@ --pl-color-status-warning: oklch(0.78 0.12 75);

/* Light-ground sites: the dark-mode gradient stops wash out, so swap to the
* saturated variant. The rest of the palette is dark-first by design. */
/* Light mode — the user's OS preference drives it. Apps inherit automatically;
* marketing pins dark with [data-theme="dark"] below (attribute selectors beat
* this media block on specificity). */
@media (prefers-color-scheme: light) {
:root {
color-scheme: light;
--pl-color-bg: #f6f7f9;
--pl-color-bg-raised: #ffffff;
--pl-color-bg-subtle: #eceef2;
--pl-color-bg-hover: #e4e7ec;
--pl-color-bg-inset: #eef0f4;
--pl-color-overlay: rgba(20, 20, 30, 0.35);
--pl-color-fg: #18181b;
--pl-color-fg-muted: #52525b;
--pl-color-fg-subtle: #8a8a94;
--pl-color-fg-on-accent: #ffffff;
--pl-color-border: rgba(0, 0, 0, 0.10);
--pl-color-border-strong: rgba(0, 0, 0, 0.20);
--pl-color-accent: #6366f1;
--pl-color-accent-hover: #4f46e5;
--pl-color-accent-fg: #4f46e5;
--pl-color-focus: #6366f1;
--pl-color-status-success: oklch(0.62 0.15 150);
--pl-color-status-warning: oklch(0.74 0.16 92);
--pl-color-status-error: oklch(0.58 0.20 25);
--pl-color-status-info: oklch(0.58 0.17 255);
--pl-gradient-brand: linear-gradient(135deg, #7355e8 0%, #6366f1 50%, #4f46e5 100%);
--pl-shadow-popover: 0 8px 24px rgba(0, 0, 0, 0.12);
}
}
/* Explicit theme force — wins over the OS preference above. */
:root[data-theme="light"] {
color-scheme: light;
--pl-color-bg: #f6f7f9;
--pl-color-bg-raised: #ffffff;
--pl-color-bg-subtle: #eceef2;
--pl-color-bg-hover: #e4e7ec;
--pl-color-bg-inset: #eef0f4;
--pl-color-overlay: rgba(20, 20, 30, 0.35);
--pl-color-fg: #18181b;
--pl-color-fg-muted: #52525b;
--pl-color-fg-subtle: #8a8a94;
--pl-color-fg-on-accent: #ffffff;
--pl-color-border: rgba(0, 0, 0, 0.10);
--pl-color-border-strong: rgba(0, 0, 0, 0.20);
--pl-color-accent: #6366f1;
--pl-color-accent-hover: #4f46e5;
--pl-color-accent-fg: #4f46e5;
--pl-color-focus: #6366f1;
--pl-color-status-success: oklch(0.62 0.15 150);
--pl-color-status-warning: oklch(0.74 0.16 92);
--pl-color-status-error: oklch(0.58 0.20 25);
--pl-color-status-info: oklch(0.58 0.17 255);
--pl-gradient-brand: linear-gradient(135deg, #7355e8 0%, #6366f1 50%, #4f46e5 100%);
--pl-shadow-popover: 0 8px 24px rgba(0, 0, 0, 0.12);
}
:root[data-theme="dark"] {
color-scheme: dark;
--pl-color-bg: #0a0a0c;
--pl-color-bg-raised: #131316;
--pl-color-bg-subtle: #1c1c22;
--pl-color-bg-hover: #19191d;
--pl-color-bg-inset: #060608;
--pl-color-overlay: rgba(0, 0, 0, 0.6);
--pl-color-fg: #ededed;
--pl-color-fg-muted: #a1a1aa;
--pl-color-fg-subtle: #71717a;
--pl-color-fg-on-accent: #0a0a0c;
--pl-color-border: rgba(255, 255, 255, 0.08);
--pl-color-border-strong: rgba(255, 255, 255, 0.18);
--pl-color-accent: #9b87f2;
--pl-color-accent-hover: #b8a6f5;
--pl-color-accent-fg: #b8a6f5;
--pl-color-focus: #9b87f2;
--pl-color-status-success: oklch(0.72 0.13 145);
--pl-color-status-warning: oklch(0.78 0.12 75);
--pl-color-status-error: oklch(0.64 0.16 25);
--pl-color-status-info: oklch(0.68 0.12 230);
--pl-gradient-brand: linear-gradient(135deg, #9b87f2 0%, #818cf8 50%, #6366f1 100%);
--pl-shadow-popover: 0 8px 28px rgba(0, 0, 0, 0.5);
}

@@ -6,4 +6,6 @@ {

"lavenderLight": "#b8a6f5",
"lavenderDeep": "#5b3fc9",
"indigo": "#6366f1",
"indigoBright": "#818cf8"
"indigoBright": "#818cf8",
"indigoDeep": "#4f46e5"
},

@@ -14,7 +16,14 @@ "bg": "#0a0a0c",

"bgHover": "#19191d",
"bgInset": "#060608",
"overlay": "rgba(0, 0, 0, 0.6)",
"fg": "#ededed",
"fgMuted": "#a1a1aa",
"fgSubtle": "#71717a",
"fgOnAccent": "#0a0a0c",
"border": "rgba(255, 255, 255, 0.08)",
"borderStrong": "rgba(255, 255, 255, 0.18)",
"overlay": "rgba(0, 0, 0, 0.6)",
"accent": "#9b87f2",
"accentHover": "#b8a6f5",
"accentFg": "#b8a6f5",
"focus": "#9b87f2",
"status": {

@@ -66,3 +75,35 @@ "success": "oklch(0.72 0.13 145)",

"linear": "linear"
},
"light": {
"color": {
"bg": "#f6f7f9",
"bgRaised": "#ffffff",
"bgSubtle": "#eceef2",
"bgHover": "#e4e7ec",
"bgInset": "#eef0f4",
"overlay": "rgba(20, 20, 30, 0.35)",
"fg": "#18181b",
"fgMuted": "#52525b",
"fgSubtle": "#8a8a94",
"fgOnAccent": "#ffffff",
"border": "rgba(0, 0, 0, 0.10)",
"borderStrong": "rgba(0, 0, 0, 0.20)",
"accent": "#6366f1",
"accentHover": "#4f46e5",
"accentFg": "#4f46e5",
"focus": "#6366f1",
"status": {
"success": "oklch(0.62 0.15 150)",
"warning": "oklch(0.74 0.16 92)",
"error": "oklch(0.58 0.20 25)",
"info": "oklch(0.58 0.17 255)"
}
},
"gradient": {
"brand": "linear-gradient(135deg, #7355e8 0%, #6366f1 50%, #4f46e5 100%)"
},
"shadow": {
"popover": "0 8px 24px rgba(0, 0, 0, 0.12)"
}
}
}
+1
-1
{
"name": "@protolabsai/design",
"version": "0.4.0",
"version": "0.5.0",
"publishConfig": {

@@ -5,0 +5,0 @@ "access": "public",

@@ -6,8 +6,17 @@ /**

* Nothing downstream (CSS vars, Tailwind preset, docs) is hand-maintained —
* it all derives from this object, so the spec and the shipped values can't
* it all derives from these objects, so the spec and the shipped values can't
* drift apart again (which is exactly what bit us before this package existed).
*
* Locked 2026-05-29. Where visual-identity.md (spec) and the shipped site
* (styles.css) disagreed, the shipped site won: 4px radius, #0a0a0c ground,
* #ededed foreground, bordered (not filled) primary buttons.
* Locked 2026-05-29 (dark). Light mode added 2026-06-09.
*
* THEMING / WHITE-LABEL
* --------------------
* `tokens` holds the DEFAULT (protoLabs.studio dark) theme. `light` holds the light-mode
* COLOR overrides (same keys). The build emits:
* :root { ...dark... } — default
* @media (prefers-color-scheme: light){:root} — OS preference drives light
* :root[data-theme="light"|"dark"] — explicit force (beats the media query)
* Marketing stays dark by setting [data-theme="dark"]; apps inherit OS preference.
* White-label: a consumer overrides the `--pl-color-*` (esp. accent/bg/fg) under
* their own scope — our values are the default, theirs win where set.
*/

@@ -17,18 +26,34 @@

color: {
// ── Brand marks (theme-invariant — the literal brand colors) ──
brand: {
lavender: "#9b87f2", // the brand accent
lavenderLight: "#b8a6f5", // hover, link-lift
indigo: "#6366f1", // gradient end, secondary accent
// Lavender leads on dark; indigo leads on light. Each anchor has a
// light / base / deep step (the deep steps clear AA on white).
lavender: "#9b87f2", // base — brand accent + dark-mode interactive
lavenderLight: "#b8a6f5", // hover / link-lift on dark
lavenderDeep: "#5b3fc9", // deep step — light grounds / white-label
indigo: "#6366f1", // secondary anchor + light-mode interactive accent
indigoBright: "#818cf8", // gradient midpoint
indigoDeep: "#4f46e5", // deep step — light-mode links / gradient end
},
bg: "#0a0a0c", // default dark ground
bgRaised: "#131316", // cards, slight elevation
bgSubtle: "#1c1c22", // one step above raised — table stripes, list hover targets
bgHover: "#19191d", // interactive hover wash on raised/ground surfaces
fg: "#ededed", // primary text
fgMuted: "#a1a1aa", // labels, secondary text — lifted one step for legibility on the dark ground
// ── Surfaces ──
bg: "#0a0a0c", // default ground
bgRaised: "#131316", // cards, panels, slight elevation
bgSubtle: "#1c1c22", // table stripes, list hover targets
bgHover: "#19191d", // interactive hover wash
bgInset: "#060608", // sunken — code wells, deep inputs
overlay: "rgba(0, 0, 0, 0.6)", // modal / drawer scrim
// ── Text (three tiers + on-accent) ──
fg: "#ededed", // primary
fgMuted: "#a1a1aa", // secondary / labels
fgSubtle: "#71717a", // tertiary / placeholder / disabled
fgOnAccent: "#0a0a0c", // text/icon on an accent fill
// ── Lines ──
border: "rgba(255, 255, 255, 0.08)", // subtle 1px dividers
borderStrong: "rgba(255, 255, 255, 0.18)", // emphasized borders, buttons
overlay: "rgba(0, 0, 0, 0.6)", // modal / drawer scrim
// Status — low-chroma, never neon. They mean something; not decoration.
// ── Interactive accent (the white-label swap point; = brand lavender) ──
accent: "#9b87f2",
accentHover: "#b8a6f5",
accentFg: "#b8a6f5", // accent as text (links, active labels) on this ground
focus: "#9b87f2", // focus-visible ring
// ── Status — low-chroma, never neon. They mean something; not decoration. ──
status: {

@@ -43,3 +68,2 @@ success: "oklch(0.72 0.13 145)",

// The one gradient — hero text fills + large brand moments only. Not UI chrome.
// Lavender → indigo-bright → indigo.
brand: "linear-gradient(135deg, #9b87f2 0%, #818cf8 50%, #6366f1 100%)",

@@ -50,4 +74,3 @@ brandLight: "linear-gradient(135deg, #7355e8 0%, #6366f1 50%, #4f46e5 100%)",

glow: "0 0 80px rgba(155, 135, 242, 0.08)", // subtle lavender halo; brand moments only
// The one UI shadow family — reserved for popovers, command palette, dialogs,
// drawers, toasts (visual-identity §Geometry). Never on flat content.
// The one UI shadow family — popovers, command palette, dialogs, drawers, toasts.
popover: "0 8px 28px rgba(0, 0, 0, 0.5)",

@@ -78,2 +101,42 @@ },

/**
* Light-mode COLOR overrides (apps; marketing stays dark). Same keys as
* tokens.color, minus `brand` (the marks are invariant). Status colors are
* darkened for contrast on a light ground; the accent darkens to clear AA on
* white. Surfaces invert their elevation relation (cards become the lightest).
*/
export const light = {
color: {
// Cool-neutral surfaces (matching the cool-purple brand), cards the lightest.
bg: "#f6f7f9", // cool off-white ground
bgRaised: "#ffffff", // cards / panels — the lightest surface (elevation flips)
bgSubtle: "#eceef2", // table stripes, list hover targets
bgHover: "#e4e7ec", // interactive hover wash
bgInset: "#eef0f4", // sunken — code wells, deep inputs
overlay: "rgba(20, 20, 30, 0.35)", // slightly cool scrim
fg: "#18181b", // primary
fgMuted: "#52525b", // secondary / labels
fgSubtle: "#8a8a94", // tertiary / placeholder
fgOnAccent: "#ffffff", // text on the indigo accent fill
border: "rgba(0, 0, 0, 0.10)",
borderStrong: "rgba(0, 0, 0, 0.20)",
// Indigo leads light: base indigo for fills, indigo-deep for links/accent text (AA).
accent: "#6366f1",
accentHover: "#4f46e5",
accentFg: "#4f46e5",
focus: "#6366f1",
// Status — used as accents (dots, borders, badge tints), so they read as
// their hue rather than chase body-text AA. Lifted a couple steps from the
// over-dark first pass; warning is a true yellow, not amber/brown.
status: {
success: "oklch(0.62 0.15 150)",
warning: "oklch(0.74 0.16 92)",
error: "oklch(0.58 0.20 25)",
info: "oklch(0.58 0.17 255)",
},
},
gradient: { brand: tokens.gradient.brandLight },
shadow: { popover: "0 8px 24px rgba(0, 0, 0, 0.12)" },
};
export default tokens;