Refresh UI components and showcase; release updated framework packages
This commit is contained in:
1 parent
d800228585
commit
c77f5e1cec
293 files changed
+22544
-35778
No files matched your search
@@ -27,6 +27,16 @@ Part of the **WrNexus** framework — an SSR-first, Bun-native full-stack web fr
|
||||
|
||||
## Overview
|
||||
|
||||
### Production CSS inlining
|
||||
|
||||
`styles.inlineMaxBytes` controls the maximum uncompressed size of the combined
|
||||
production stylesheet to embed in the document. The default is 4096 bytes; `0`
|
||||
disables inlining. A measured first-visit optimization can use, for example,
|
||||
`styles: { inlineMaxBytes: 128 * 1024 }`. Larger limits remove a blocking stylesheet
|
||||
request but repeat the CSS in each HTML response. Stylesheets containing relative
|
||||
asset URLs stay external so their URL base does not change. Theme switching and
|
||||
the separately served stylesheet remain available.
|
||||
|
||||
This package owns three server-side concerns that shape every page a WrNexus app renders:
|
||||
|
||||
1. **Global stylesheet pipeline** — finds `app/styles/global.css` (or aggregates `app/styles/*.css`), bundles it with Bun's CSS bundler (which resolves `@import`, including from `node_modules`), and produces one stylesheet that is `<link>`ed into every page's `<head>`. Because it is a plain global sheet, it styles server-rendered markup and hydrated client islands identically. A custom `process` hook lets you swap in Tailwind / PostCSS / Sass.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/styles",
|
||||
"version": "0.8.22",
|
||||
"version": "0.8.23",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -39,6 +39,8 @@ export interface StylesConfig {
|
||||
entry?: string;
|
||||
/** Include the complete @wrnexus/ui component catalog stylesheet. Default true. */
|
||||
includeUi?: boolean;
|
||||
/** Maximum uncompressed production CSS bytes to inline in the document. Default 4096; 0 disables inlining. Larger limits trade repeat HTML bytes for one fewer blocking request. */
|
||||
inlineMaxBytes?: number;
|
||||
/**
|
||||
* Optional custom processor. Return the final CSS string. Use this to run
|
||||
* Tailwind, PostCSS, Sass, etc. When omitted, the built-in Bun CSS bundler is
|
||||
|
||||
@@ -39,6 +39,13 @@ export type ThemeToken =
|
||||
| `color-on-${"primary" | "secondary"}`
|
||||
| "radius"
|
||||
| "radius-sm"
|
||||
| "radius-md"
|
||||
| "radius-lg"
|
||||
| "control-height-sm"
|
||||
| "control-height"
|
||||
| "control-height-lg"
|
||||
| "space-panel"
|
||||
| "font-size-ui"
|
||||
| "shadow-1"
|
||||
| "shadow-2"
|
||||
| "shadow-3"
|
||||
@@ -452,16 +459,16 @@ function resolveDefaultAccent(
|
||||
export const DEFAULT_THEMES: Record<string, ThemeTokens> = {
|
||||
light: {
|
||||
"color-scheme": "light",
|
||||
"color-bg": "#ffffff",
|
||||
"color-background": "#ffffff",
|
||||
"color-foreground": "#0b1020",
|
||||
"color-bg": "#f7f8fa",
|
||||
"color-background": "#f7f8fa",
|
||||
"color-foreground": "#20232b",
|
||||
"color-surface-raised": "#ffffff",
|
||||
"color-surface-muted": "#eceff6",
|
||||
"color-surface-soft": "#f1f4f9",
|
||||
"color-text-muted": "#5a6178",
|
||||
"color-text-subtle": "#737b91",
|
||||
"color-border-strong": "#c7cedd",
|
||||
"color-code-background": "#0b1020",
|
||||
"color-surface-muted": "#eef0f4",
|
||||
"color-surface-soft": "#f6f7f9",
|
||||
"color-text-muted": "#606776",
|
||||
"color-text-subtle": "#6b7280",
|
||||
"color-border-strong": "#b9c0cc",
|
||||
"color-code-background": "#20232b",
|
||||
"color-code-surface": "#141a30",
|
||||
"color-code-text": "#e7ecff",
|
||||
"color-code-muted": "#9aa6d0",
|
||||
@@ -472,34 +479,41 @@ export const DEFAULT_THEMES: Record<string, ThemeTokens> = {
|
||||
"space-section": "5rem",
|
||||
"space-section-sm": "3.5rem",
|
||||
"container-max": "80rem",
|
||||
"color-surface": "#f6f7fb",
|
||||
"color-surface-2": "#eceff6",
|
||||
"color-text": "#0b1020",
|
||||
"color-muted": "#5a6178",
|
||||
"color-border": "#e2e6f0",
|
||||
"color-surface": "#ffffff",
|
||||
"color-surface-2": "#eef0f4",
|
||||
"color-text": "#20232b",
|
||||
"color-muted": "#606776",
|
||||
"color-border": "#e1e4ea",
|
||||
...paletteTokens(THEME_PALETTES.blue, "light"),
|
||||
radius: "8px",
|
||||
"radius-sm": "5px",
|
||||
radius: "10px",
|
||||
"radius-sm": "6px",
|
||||
"radius-md": "10px",
|
||||
"radius-lg": "12px",
|
||||
"control-height-sm": "2rem",
|
||||
"control-height": "2.5rem",
|
||||
"control-height-lg": "2.75rem",
|
||||
"space-panel": "1.25rem",
|
||||
"font-size-ui": "0.875rem",
|
||||
"font-sans": '"Plus Jakarta Sans",ui-sans-serif,system-ui,sans-serif',
|
||||
"shadow-1": "0 1px 2px rgba(16,24,40,0.06), 0 1px 3px rgba(16,24,40,0.1)",
|
||||
"shadow-1": "0 1px 3px rgba(16,24,40,0.05)",
|
||||
"shadow-2": "0 8px 24px rgba(16,24,40,0.10)",
|
||||
"shadow-3": "0 20px 50px rgba(16,24,40,0.14)",
|
||||
},
|
||||
dark: {
|
||||
"color-scheme": "dark",
|
||||
"color-bg": "#000000",
|
||||
"color-background": "#000000",
|
||||
"color-foreground": "#f5f5f5",
|
||||
"color-surface-raised": "#111111",
|
||||
"color-surface-muted": "#181818",
|
||||
"color-surface-soft": "#141414",
|
||||
"color-text-muted": "#b3b3b3",
|
||||
"color-text-subtle": "#8a8a8a",
|
||||
"color-border-strong": "#ffffff38",
|
||||
"color-bg": "#101114",
|
||||
"color-background": "#101114",
|
||||
"color-foreground": "#f0f1f4",
|
||||
"color-surface-raised": "#22252d",
|
||||
"color-surface-muted": "#242730",
|
||||
"color-surface-soft": "#1c1f26",
|
||||
"color-text-muted": "#b5bac5",
|
||||
"color-text-subtle": "#959cab",
|
||||
"color-border-strong": "#555d6c",
|
||||
"color-code-background": "#050505",
|
||||
"color-code-surface": "#101010",
|
||||
"color-code-text": "#f5f5f5",
|
||||
"color-code-muted": "#a3a3a3",
|
||||
"color-code-text": "#f0f1f4",
|
||||
"color-code-muted": "#a7aeba",
|
||||
"color-code-border": "#ffffff24",
|
||||
"shadow-sm": "0 1px 2px rgba(0,0,0,0.28)",
|
||||
"shadow-md": "0 10px 30px rgba(0,0,0,0.35)",
|
||||
@@ -507,16 +521,23 @@ export const DEFAULT_THEMES: Record<string, ThemeTokens> = {
|
||||
"space-section": "5rem",
|
||||
"space-section-sm": "3.5rem",
|
||||
"container-max": "80rem",
|
||||
"color-surface": "#0a0a0a",
|
||||
"color-surface-2": "#171717",
|
||||
"color-text": "#f5f5f5",
|
||||
"color-muted": "#a3a3a3",
|
||||
"color-border": "#ffffff1f",
|
||||
"color-surface": "#181a20",
|
||||
"color-surface-2": "#20232b",
|
||||
"color-text": "#f0f1f4",
|
||||
"color-muted": "#a7aeba",
|
||||
"color-border": "#30343e",
|
||||
...paletteTokens(THEME_PALETTES.blue, "dark"),
|
||||
radius: "10px",
|
||||
"radius-sm": "6px",
|
||||
"radius-md": "10px",
|
||||
"radius-lg": "12px",
|
||||
"control-height-sm": "2rem",
|
||||
"control-height": "2.5rem",
|
||||
"control-height-lg": "2.75rem",
|
||||
"space-panel": "1.25rem",
|
||||
"font-size-ui": "0.875rem",
|
||||
"font-sans": '"Plus Jakarta Sans",ui-sans-serif,system-ui,sans-serif',
|
||||
"shadow-1": "0 1px 2px rgba(0,0,0,0.3), 0 4px 16px rgba(0,0,0,0.35)",
|
||||
"shadow-1": "0 1px 3px rgba(0,0,0,0.18)",
|
||||
"shadow-2": "0 10px 30px rgba(0,0,0,0.35)",
|
||||
"shadow-3": "0 24px 64px rgba(0,0,0,0.45)",
|
||||
},
|
||||
@@ -599,11 +620,6 @@ function selectorValue(value: string): string {
|
||||
function globalThemeCss(): string {
|
||||
return (
|
||||
'\nhtml,body{font-family:var(--wrn-font-sans,"Plus Jakarta Sans",ui-sans-serif,system-ui,sans-serif);}\n' +
|
||||
":root{--wrn-radius-sm:0.55rem;--wrn-radius-md:0.9rem;--wrn-radius-lg:1.35rem;" +
|
||||
"--wrn-shadow-1:0 1px 2px color-mix(in srgb, black 22%, transparent)," +
|
||||
"0 10px 30px color-mix(in srgb, black 14%, transparent);" +
|
||||
"--wrn-shadow-2:0 10px 30px color-mix(in srgb, black 18%, transparent);" +
|
||||
"--wrn-shadow-3:0 24px 64px color-mix(in srgb, black 24%, transparent);}\n" +
|
||||
"wrn-slot{display:contents;}\n" +
|
||||
"[data-for]{display:none !important;}\n"
|
||||
);
|
||||
|
||||
@@ -56,15 +56,15 @@ test("resolveThemeConfig merges user tokens over built-in light/dark", () => {
|
||||
expect(t.themes.dark["color-bg"]).toBeDefined(); // built-in kept
|
||||
});
|
||||
|
||||
test("built-in themes use Plus Jakarta Sans and neutral black dark surfaces", () => {
|
||||
test("built-in themes use Plus Jakarta Sans and layered charcoal dark surfaces", () => {
|
||||
const t = resolveThemeConfig();
|
||||
expect(t.themes.light["font-sans"]).toBe(
|
||||
'"Plus Jakarta Sans",ui-sans-serif,system-ui,sans-serif',
|
||||
);
|
||||
expect(t.themes.dark["font-sans"]).toBe('"Plus Jakarta Sans",ui-sans-serif,system-ui,sans-serif');
|
||||
expect(t.themes.dark["color-bg"]).toBe("#000000");
|
||||
expect(t.themes.dark["color-surface"]).toBe("#0a0a0a");
|
||||
expect(t.themes.dark["color-surface-2"]).toBe("#171717");
|
||||
expect(t.themes.dark["color-bg"]).toBe("#101114");
|
||||
expect(t.themes.dark["color-surface"]).toBe("#181a20");
|
||||
expect(t.themes.dark["color-surface-2"]).toBe("#20232b");
|
||||
});
|
||||
|
||||
test("resolveThemeName validates against configured names", () => {
|
||||
@@ -105,3 +105,16 @@ test("renderThemeRuntime bakes the theme names for cycling", () => {
|
||||
expect(js).toContain(JSON.stringify(t.names));
|
||||
expect(js).toContain('addEventListener("wrnexus:navigated"');
|
||||
});
|
||||
|
||||
test("active stylesheets preserve configured geometry and elevation without a later reset", () => {
|
||||
const theme = resolveThemeConfig({
|
||||
themes: { dark: { "radius-sm": "3px", "radius-lg": "9px", "shadow-1": "none" } },
|
||||
});
|
||||
const css = renderActiveThemeCss(theme, "dark");
|
||||
expect(css.match(/--wrn-radius-sm:/g)).toHaveLength(1);
|
||||
expect(css.match(/--wrn-radius-lg:/g)).toHaveLength(1);
|
||||
expect(css.match(/--wrn-shadow-1:/g)).toHaveLength(1);
|
||||
expect(css).toContain("--wrn-radius-sm:3px");
|
||||
expect(css).toContain("--wrn-radius-lg:9px");
|
||||
expect(css).toContain("--wrn-shadow-1:none");
|
||||
});
|
||||
Reference in new issue
Block a user