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
60 changes: 60 additions & 0 deletions apps/mobile/generated-uniwind-themes.css
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@
--color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%);
--color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938);
--color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786);
--color-clerk-page: #f2f2f7;
--color-clerk-foreground: #262626;
--color-clerk-foreground-muted: #737373;
--color-clerk-border: rgba(229, 229, 234, 0.06);
--color-clerk-danger: #dc2626;
}

@variant dark {
Expand Down Expand Up @@ -119,6 +124,11 @@
--color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%);
--color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067);
--color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286);
--color-clerk-page: #0e0e0e;
--color-clerk-foreground: #f5f5f5;
--color-clerk-foreground-muted: #a3a3a3;
--color-clerk-border: rgba(42, 42, 42, 0.06);
--color-clerk-danger: #fca5a5;
}

@variant t3-chat-light {
Expand Down Expand Up @@ -254,6 +264,11 @@
--color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%);
--color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938);
--color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786);
--color-clerk-page: #f2f2f7;
--color-clerk-foreground: #262626;
--color-clerk-foreground-muted: #737373;
--color-clerk-border: rgba(229, 229, 234, 0.06);
--color-clerk-danger: #dc2626;
}

@variant t3-chat-dark {
Expand Down Expand Up @@ -389,6 +404,11 @@
--color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%);
--color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067);
--color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286);
--color-clerk-page: #0e0e0e;
--color-clerk-foreground: #f5f5f5;
--color-clerk-foreground-muted: #a3a3a3;
--color-clerk-border: rgba(42, 42, 42, 0.06);
--color-clerk-danger: #fca5a5;
}

@variant grove-light {
Expand Down Expand Up @@ -524,6 +544,11 @@
--color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%);
--color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938);
--color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786);
--color-clerk-page: #f2f2f7;
--color-clerk-foreground: #262626;
--color-clerk-foreground-muted: #737373;
--color-clerk-border: rgba(229, 229, 234, 0.06);
--color-clerk-danger: #dc2626;
}

@variant grove-dark {
Expand Down Expand Up @@ -659,6 +684,11 @@
--color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%);
--color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067);
--color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286);
--color-clerk-page: #0e0e0e;
--color-clerk-foreground: #f5f5f5;
--color-clerk-foreground-muted: #a3a3a3;
--color-clerk-border: rgba(42, 42, 42, 0.06);
--color-clerk-danger: #fca5a5;
}

@variant ocean-light {
Expand Down Expand Up @@ -794,6 +824,11 @@
--color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%);
--color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938);
--color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786);
--color-clerk-page: #f2f2f7;
--color-clerk-foreground: #262626;
--color-clerk-foreground-muted: #737373;
--color-clerk-border: rgba(229, 229, 234, 0.06);
--color-clerk-danger: #dc2626;
}

@variant ocean-dark {
Expand Down Expand Up @@ -929,6 +964,11 @@
--color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%);
--color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067);
--color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286);
--color-clerk-page: #0e0e0e;
--color-clerk-foreground: #f5f5f5;
--color-clerk-foreground-muted: #a3a3a3;
--color-clerk-border: rgba(42, 42, 42, 0.06);
--color-clerk-danger: #fca5a5;
}

@variant ember-light {
Expand Down Expand Up @@ -1064,6 +1104,11 @@
--color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%);
--color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938);
--color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786);
--color-clerk-page: #f2f2f7;
--color-clerk-foreground: #262626;
--color-clerk-foreground-muted: #737373;
--color-clerk-border: rgba(229, 229, 234, 0.06);
--color-clerk-danger: #dc2626;
}

@variant ember-dark {
Expand Down Expand Up @@ -1199,6 +1244,11 @@
--color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%);
--color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067);
--color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286);
--color-clerk-page: #0e0e0e;
--color-clerk-foreground: #f5f5f5;
--color-clerk-foreground-muted: #a3a3a3;
--color-clerk-border: rgba(42, 42, 42, 0.06);
--color-clerk-danger: #fca5a5;
}

@variant iris-light {
Expand Down Expand Up @@ -1334,6 +1384,11 @@
--color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%);
--color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938);
--color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786);
--color-clerk-page: #f2f2f7;
--color-clerk-foreground: #262626;
--color-clerk-foreground-muted: #737373;
--color-clerk-border: rgba(229, 229, 234, 0.06);
--color-clerk-danger: #dc2626;
}

@variant iris-dark {
Expand Down Expand Up @@ -1469,6 +1524,11 @@
--color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%);
--color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067);
--color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286);
--color-clerk-page: #0e0e0e;
--color-clerk-foreground: #f5f5f5;
--color-clerk-foreground-muted: #a3a3a3;
--color-clerk-border: rgba(42, 42, 42, 0.06);
--color-clerk-danger: #fca5a5;
}
}
}
25 changes: 0 additions & 25 deletions apps/mobile/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -233,31 +233,6 @@
}
}

/* ─── Clerk native profile ──────────────────────────────────────────── */
/* Fixed palette for custom pages inside Clerk's native user profile. Mirrors
clerk-theme.json, which themes the SDK's own screens, so ours match them.
Kept out of the runtime palette above on purpose: custom themes must not
restyle Clerk's chrome. Keep in sync with clerk-theme.json. */
@layer theme {
:root {
@variant light {
--color-clerk-page: #f2f2f7;
--color-clerk-foreground: #262626;
--color-clerk-foreground-muted: #737373;
--color-clerk-border: rgba(229, 229, 234, 0.06);
--color-clerk-danger: #dc2626;
}

@variant dark {
--color-clerk-page: #0e0e0e;
--color-clerk-foreground: #f5f5f5;
--color-clerk-foreground-muted: #a3a3a3;
--color-clerk-border: rgba(42, 42, 42, 0.06);
--color-clerk-danger: #fca5a5;
}
}
}

/* ─── Typography ────────────────────────────────────────────────────── */
@theme {
/* Keep these native family names aligned with app.config.ts. */
Expand Down
24 changes: 22 additions & 2 deletions apps/mobile/scripts/generate-uniwind-themes.mts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import * as NodePath from "node:path";
import tailwindColors from "tailwindcss/colors";
import { BUILT_IN_THEME_IDS, type BuiltInThemeId } from "@t3tools/shared/themePalettes";

import clerkTheme from "../clerk-theme.json" with { type: "json" };
import {
getMobileThemeVariables,
MOBILE_THEME_VARIABLE_NAMES,
themeColorWithAlpha,
type MobileThemeAppearance,
type MobileThemeVariables,
} from "../src/lib/mobileTheme.ts";
Expand Down Expand Up @@ -152,8 +154,22 @@ const adaptiveVariablesFor = (appearance: MobileThemeAppearance) =>
const variablesFor = (themeId: BuiltInThemeId, appearance: MobileThemeAppearance) => ({
...getMobileThemeVariables(themeId, appearance),
...adaptiveVariablesFor(appearance),
...clerkVariablesFor(appearance),
});

// Clerk's native screens use one build-time palette per appearance. Custom
// profile pages must match it even when the rest of the app uses a named theme.
const clerkVariablesFor = (appearance: MobileThemeAppearance) => {
const colors = appearance === "dark" ? clerkTheme.darkColors : clerkTheme.colors;
return {
"--color-clerk-page": colors.background.toLowerCase(),
"--color-clerk-foreground": colors.foreground.toLowerCase(),
"--color-clerk-foreground-muted": colors.mutedForeground.toLowerCase(),
"--color-clerk-border": themeColorWithAlpha(colors.border, 0.06),
"--color-clerk-danger": colors.danger.toLowerCase(),
};
};

const renderVariant = (name: string, variables: Readonly<Record<string, string>>) => {
const declarations = Object.entries(variables)
.map(([variable, value]) => ` ${variable}: ${value};`)
Expand All @@ -163,8 +179,12 @@ const renderVariant = (name: string, variables: Readonly<Record<string, string>>

export const renderUniwindThemesCSS = () => {
const variants = [
renderVariant("light", adaptiveVariablesFor("light")),
renderVariant("dark", adaptiveVariablesFor("dark")),
...APPEARANCES.map((appearance) =>
renderVariant(appearance, {
...adaptiveVariablesFor(appearance),
...clerkVariablesFor(appearance),
}),
),
...BUILT_IN_THEME_IDS.flatMap((themeId) =>
APPEARANCES.map((appearance) =>
renderVariant(`${themeId}-${appearance}`, variablesFor(themeId, appearance)),
Expand Down
33 changes: 33 additions & 0 deletions apps/mobile/scripts/generate-uniwind-themes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,37 @@ describe("generate mobile Uniwind themes", () => {
expect(variables.dark["--color-screen"]).toBe("#0a0a0a");
expect(Object.keys(variables.light)).toEqual(Object.keys(variables.dark));
});

it("gives every theme the same variables and a fixed Clerk palette for its appearance", () => {
const css =
NodeFS.readFileSync(NodePath.resolve(import.meta.dirname, "../global.css"), "utf8") +
renderUniwindThemesCSS();
const themes = new Map<string, Map<string, string>>(
["light", "dark", ...customThemeNames].map((name) => [name, new Map()]),
);
for (const [, name, body] of css.matchAll(/@variant ([\w-]+) \{([^}]+)\}/gu)) {
const variables = themes.get(name!);
for (const [, variable, value] of body!.matchAll(/(--[\w-]+):\s*([^;]+);/gu)) {
variables?.set(variable!, value!.trim().toLowerCase());
}
}

const lightVariables = themes.get("light")!;
for (const [name, variables] of themes) {
expect([...variables.keys()].sort(), name).toEqual([...lightVariables.keys()].sort());
const isDark = name === "dark" || name.endsWith("-dark");
expect(
Object.fromEntries(
[...variables].filter(([variable]) => variable.startsWith("--color-clerk-")),
),
name,
).toEqual({
"--color-clerk-page": isDark ? "#0e0e0e" : "#f2f2f7",
"--color-clerk-foreground": isDark ? "#f5f5f5" : "#262626",
"--color-clerk-foreground-muted": isDark ? "#a3a3a3" : "#737373",
"--color-clerk-border": isDark ? "rgba(42, 42, 42, 0.06)" : "rgba(229, 229, 234, 0.06)",
"--color-clerk-danger": isDark ? "#fca5a5" : "#dc2626",
});
}
});
});
Loading