| author | |
| committer | |
| log | 53510d44ea7b4a44c10c122dd9245194f2f14d09 |
| tree | 72ef847f8f5295593849bb05b88df499f07d9737 |
| parent | 3fd5d6439d8fd49d173503ecda96500463a39bd2 |
| signature | Signed by PGP key B5690EEEBB952194 |
4 files changed, 115 insertions(+), 27 deletions(-)
apps/mobile/generated-uniwind-themes.css+60| ... | @@ -59,6 +59,11 @@ | ... | @@ -59,6 +59,11 @@ |
| 59 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%); | 59 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%); |
| 60 | --color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938); | 60 | --color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938); |
| 61 | --color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786); | 61 | --color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786); |
| 62 | --color-clerk-page: #f2f2f7; | ||
| 63 | --color-clerk-foreground: #262626; | ||
| 64 | --color-clerk-foreground-muted: #737373; | ||
| 65 | --color-clerk-border: rgba(229, 229, 234, 0.06); | ||
| 66 | --color-clerk-danger: #dc2626; | ||
| 62 | } | 67 | } |
| 63 | 68 | ||
| 64 | @variant dark { | 69 | @variant dark { |
| ... | @@ -119,6 +124,11 @@ | ... | @@ -119,6 +124,11 @@ |
| 119 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%); | 124 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%); |
| 120 | --color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067); | 125 | --color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067); |
| 121 | --color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286); | 126 | --color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286); |
| 127 | --color-clerk-page: #0e0e0e; | ||
| 128 | --color-clerk-foreground: #f5f5f5; | ||
| 129 | --color-clerk-foreground-muted: #a3a3a3; | ||
| 130 | --color-clerk-border: rgba(42, 42, 42, 0.06); | ||
| 131 | --color-clerk-danger: #fca5a5; | ||
| 122 | } | 132 | } |
| 123 | 133 | ||
| 124 | @variant t3-chat-light { | 134 | @variant t3-chat-light { |
| ... | @@ -254,6 +264,11 @@ | ... | @@ -254,6 +264,11 @@ |
| 254 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%); | 264 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%); |
| 255 | --color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938); | 265 | --color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938); |
| 256 | --color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786); | 266 | --color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786); |
| 267 | --color-clerk-page: #f2f2f7; | ||
| 268 | --color-clerk-foreground: #262626; | ||
| 269 | --color-clerk-foreground-muted: #737373; | ||
| 270 | --color-clerk-border: rgba(229, 229, 234, 0.06); | ||
| 271 | --color-clerk-danger: #dc2626; | ||
| 257 | } | 272 | } |
| 258 | 273 | ||
| 259 | @variant t3-chat-dark { | 274 | @variant t3-chat-dark { |
| ... | @@ -389,6 +404,11 @@ | ... | @@ -389,6 +404,11 @@ |
| 389 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%); | 404 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%); |
| 390 | --color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067); | 405 | --color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067); |
| 391 | --color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286); | 406 | --color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286); |
| 407 | --color-clerk-page: #0e0e0e; | ||
| 408 | --color-clerk-foreground: #f5f5f5; | ||
| 409 | --color-clerk-foreground-muted: #a3a3a3; | ||
| 410 | --color-clerk-border: rgba(42, 42, 42, 0.06); | ||
| 411 | --color-clerk-danger: #fca5a5; | ||
| 392 | } | 412 | } |
| 393 | 413 | ||
| 394 | @variant grove-light { | 414 | @variant grove-light { |
| ... | @@ -524,6 +544,11 @@ | ... | @@ -524,6 +544,11 @@ |
| 524 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%); | 544 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%); |
| 525 | --color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938); | 545 | --color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938); |
| 526 | --color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786); | 546 | --color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786); |
| 547 | --color-clerk-page: #f2f2f7; | ||
| 548 | --color-clerk-foreground: #262626; | ||
| 549 | --color-clerk-foreground-muted: #737373; | ||
| 550 | --color-clerk-border: rgba(229, 229, 234, 0.06); | ||
| 551 | --color-clerk-danger: #dc2626; | ||
| 527 | } | 552 | } |
| 528 | 553 | ||
| 529 | @variant grove-dark { | 554 | @variant grove-dark { |
| ... | @@ -659,6 +684,11 @@ | ... | @@ -659,6 +684,11 @@ |
| 659 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%); | 684 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%); |
| 660 | --color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067); | 685 | --color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067); |
| 661 | --color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286); | 686 | --color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286); |
| 687 | --color-clerk-page: #0e0e0e; | ||
| 688 | --color-clerk-foreground: #f5f5f5; | ||
| 689 | --color-clerk-foreground-muted: #a3a3a3; | ||
| 690 | --color-clerk-border: rgba(42, 42, 42, 0.06); | ||
| 691 | --color-clerk-danger: #fca5a5; | ||
| 662 | } | 692 | } |
| 663 | 693 | ||
| 664 | @variant ocean-light { | 694 | @variant ocean-light { |
| ... | @@ -794,6 +824,11 @@ | ... | @@ -794,6 +824,11 @@ |
| 794 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%); | 824 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%); |
| 795 | --color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938); | 825 | --color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938); |
| 796 | --color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786); | 826 | --color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786); |
| 827 | --color-clerk-page: #f2f2f7; | ||
| 828 | --color-clerk-foreground: #262626; | ||
| 829 | --color-clerk-foreground-muted: #737373; | ||
| 830 | --color-clerk-border: rgba(229, 229, 234, 0.06); | ||
| 831 | --color-clerk-danger: #dc2626; | ||
| 797 | } | 832 | } |
| 798 | 833 | ||
| 799 | @variant ocean-dark { | 834 | @variant ocean-dark { |
| ... | @@ -929,6 +964,11 @@ | ... | @@ -929,6 +964,11 @@ |
| 929 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%); | 964 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%); |
| 930 | --color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067); | 965 | --color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067); |
| 931 | --color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286); | 966 | --color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286); |
| 967 | --color-clerk-page: #0e0e0e; | ||
| 968 | --color-clerk-foreground: #f5f5f5; | ||
| 969 | --color-clerk-foreground-muted: #a3a3a3; | ||
| 970 | --color-clerk-border: rgba(42, 42, 42, 0.06); | ||
| 971 | --color-clerk-danger: #fca5a5; | ||
| 932 | } | 972 | } |
| 933 | 973 | ||
| 934 | @variant ember-light { | 974 | @variant ember-light { |
| ... | @@ -1064,6 +1104,11 @@ | ... | @@ -1064,6 +1104,11 @@ |
| 1064 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%); | 1104 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%); |
| 1065 | --color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938); | 1105 | --color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938); |
| 1066 | --color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786); | 1106 | --color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786); |
| 1107 | --color-clerk-page: #f2f2f7; | ||
| 1108 | --color-clerk-foreground: #262626; | ||
| 1109 | --color-clerk-foreground-muted: #737373; | ||
| 1110 | --color-clerk-border: rgba(229, 229, 234, 0.06); | ||
| 1111 | --color-clerk-danger: #dc2626; | ||
| 1067 | } | 1112 | } |
| 1068 | 1113 | ||
| 1069 | @variant ember-dark { | 1114 | @variant ember-dark { |
| ... | @@ -1199,6 +1244,11 @@ | ... | @@ -1199,6 +1244,11 @@ |
| 1199 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%); | 1244 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%); |
| 1200 | --color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067); | 1245 | --color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067); |
| 1201 | --color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286); | 1246 | --color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286); |
| 1247 | --color-clerk-page: #0e0e0e; | ||
| 1248 | --color-clerk-foreground: #f5f5f5; | ||
| 1249 | --color-clerk-foreground-muted: #a3a3a3; | ||
| 1250 | --color-clerk-border: rgba(42, 42, 42, 0.06); | ||
| 1251 | --color-clerk-danger: #fca5a5; | ||
| 1202 | } | 1252 | } |
| 1203 | 1253 | ||
| 1204 | @variant iris-light { | 1254 | @variant iris-light { |
| ... | @@ -1334,6 +1384,11 @@ | ... | @@ -1334,6 +1384,11 @@ |
| 1334 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%); | 1384 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 12%); |
| 1335 | --color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938); | 1385 | --color-adaptive-zinc-500-400: oklch(55.2% 0.016 285.938); |
| 1336 | --color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786); | 1386 | --color-adaptive-zinc-600-300: oklch(44.2% 0.017 285.786); |
| 1387 | --color-clerk-page: #f2f2f7; | ||
| 1388 | --color-clerk-foreground: #262626; | ||
| 1389 | --color-clerk-foreground-muted: #737373; | ||
| 1390 | --color-clerk-border: rgba(229, 229, 234, 0.06); | ||
| 1391 | --color-clerk-danger: #dc2626; | ||
| 1337 | } | 1392 | } |
| 1338 | 1393 | ||
| 1339 | @variant iris-dark { | 1394 | @variant iris-dark { |
| ... | @@ -1469,6 +1524,11 @@ | ... | @@ -1469,6 +1524,11 @@ |
| 1469 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%); | 1524 | --color-adaptive-zinc-500-a12-a16: oklch(55.2% 0.016 285.938 / 16%); |
| 1470 | --color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067); | 1525 | --color-adaptive-zinc-500-400: oklch(70.5% 0.015 286.067); |
| 1471 | --color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286); | 1526 | --color-adaptive-zinc-600-300: oklch(87.1% 0.006 286.286); |
| 1527 | --color-clerk-page: #0e0e0e; | ||
| 1528 | --color-clerk-foreground: #f5f5f5; | ||
| 1529 | --color-clerk-foreground-muted: #a3a3a3; | ||
| 1530 | --color-clerk-border: rgba(42, 42, 42, 0.06); | ||
| 1531 | --color-clerk-danger: #fca5a5; | ||
| 1472 | } | 1532 | } |
| 1473 | } | 1533 | } |
| 1474 | } | 1534 | } |
apps/mobile/global.css-25| ... | @@ -233,31 +233,6 @@ | ... | @@ -233,31 +233,6 @@ |
| 233 | } | 233 | } |
| 234 | } | 234 | } |
| 235 | 235 | ||
| 236 | /* ─── Clerk native profile ──────────────────────────────────────────── */ | ||
| 237 | /* Fixed palette for custom pages inside Clerk's native user profile. Mirrors | ||
| 238 | clerk-theme.json, which themes the SDK's own screens, so ours match them. | ||
| 239 | Kept out of the runtime palette above on purpose: custom themes must not | ||
| 240 | restyle Clerk's chrome. Keep in sync with clerk-theme.json. */ | ||
| 241 | @layer theme { | ||
| 242 | :root { | ||
| 243 | @variant light { | ||
| 244 | --color-clerk-page: #f2f2f7; | ||
| 245 | --color-clerk-foreground: #262626; | ||
| 246 | --color-clerk-foreground-muted: #737373; | ||
| 247 | --color-clerk-border: rgba(229, 229, 234, 0.06); | ||
| 248 | --color-clerk-danger: #dc2626; | ||
| 249 | } | ||
| 250 | |||
| 251 | @variant dark { | ||
| 252 | --color-clerk-page: #0e0e0e; | ||
| 253 | --color-clerk-foreground: #f5f5f5; | ||
| 254 | --color-clerk-foreground-muted: #a3a3a3; | ||
| 255 | --color-clerk-border: rgba(42, 42, 42, 0.06); | ||
| 256 | --color-clerk-danger: #fca5a5; | ||
| 257 | } | ||
| 258 | } | ||
| 259 | } | ||
| 260 | |||
| 261 | /* ─── Typography ────────────────────────────────────────────────────── */ | 236 | /* ─── Typography ────────────────────────────────────────────────────── */ |
| 262 | @theme { | 237 | @theme { |
| 263 | /* Keep these native family names aligned with app.config.ts. */ | 238 | /* Keep these native family names aligned with app.config.ts. */ |
apps/mobile/scripts/generate-uniwind-themes.mts+22-2| ... | @@ -5,9 +5,11 @@ import * as NodePath from "node:path"; | ... | @@ -5,9 +5,11 @@ import * as NodePath from "node:path"; |
| 5 | import tailwindColors from "tailwindcss/colors"; | 5 | import tailwindColors from "tailwindcss/colors"; |
| 6 | import { BUILT_IN_THEME_IDS, type BuiltInThemeId } from "@t3tools/shared/themePalettes"; | 6 | import { BUILT_IN_THEME_IDS, type BuiltInThemeId } from "@t3tools/shared/themePalettes"; |
| 7 | 7 | ||
| 8 | import clerkTheme from "../clerk-theme.json" with { type: "json" }; | ||
| 8 | import { | 9 | import { |
| 9 | getMobileThemeVariables, | 10 | getMobileThemeVariables, |
| 10 | MOBILE_THEME_VARIABLE_NAMES, | 11 | MOBILE_THEME_VARIABLE_NAMES, |
| 12 | themeColorWithAlpha, | ||
| 11 | type MobileThemeAppearance, | 13 | type MobileThemeAppearance, |
| 12 | type MobileThemeVariables, | 14 | type MobileThemeVariables, |
| 13 | } from "../src/lib/mobileTheme.ts"; | 15 | } from "../src/lib/mobileTheme.ts"; |
| ... | @@ -152,8 +154,22 @@ const adaptiveVariablesFor = (appearance: MobileThemeAppearance) => | ... | @@ -152,8 +154,22 @@ const adaptiveVariablesFor = (appearance: MobileThemeAppearance) => |
| 152 | const variablesFor = (themeId: BuiltInThemeId, appearance: MobileThemeAppearance) => ({ | 154 | const variablesFor = (themeId: BuiltInThemeId, appearance: MobileThemeAppearance) => ({ |
| 153 | ...getMobileThemeVariables(themeId, appearance), | 155 | ...getMobileThemeVariables(themeId, appearance), |
| 154 | ...adaptiveVariablesFor(appearance), | 156 | ...adaptiveVariablesFor(appearance), |
| 157 | ...clerkVariablesFor(appearance), | ||
| 155 | }); | 158 | }); |
| 156 | 159 | ||
| 160 | // Clerk's native screens use one build-time palette per appearance. Custom | ||
| 161 | // profile pages must match it even when the rest of the app uses a named theme. | ||
| 162 | const clerkVariablesFor = (appearance: MobileThemeAppearance) => { | ||
| 163 | const colors = appearance === "dark" ? clerkTheme.darkColors : clerkTheme.colors; | ||
| 164 | return { | ||
| 165 | "--color-clerk-page": colors.background.toLowerCase(), | ||
| 166 | "--color-clerk-foreground": colors.foreground.toLowerCase(), | ||
| 167 | "--color-clerk-foreground-muted": colors.mutedForeground.toLowerCase(), | ||
| 168 | "--color-clerk-border": themeColorWithAlpha(colors.border, 0.06), | ||
| 169 | "--color-clerk-danger": colors.danger.toLowerCase(), | ||
| 170 | }; | ||
| 171 | }; | ||
| 172 | |||
| 157 | const renderVariant = (name: string, variables: Readonly<Record<string, string>>) => { | 173 | const renderVariant = (name: string, variables: Readonly<Record<string, string>>) => { |
| 158 | const declarations = Object.entries(variables) | 174 | const declarations = Object.entries(variables) |
| 159 | .map(([variable, value]) => ` ${variable}: ${value};`) | 175 | .map(([variable, value]) => ` ${variable}: ${value};`) |
| ... | @@ -163,8 +179,12 @@ const renderVariant = (name: string, variables: Readonly<Record<string, string>> | ... | @@ -163,8 +179,12 @@ const renderVariant = (name: string, variables: Readonly<Record<string, string>> |
| 163 | 179 | ||
| 164 | export const renderUniwindThemesCSS = () => { | 180 | export const renderUniwindThemesCSS = () => { |
| 165 | const variants = [ | 181 | const variants = [ |
| 166 | renderVariant("light", adaptiveVariablesFor("light")), | 182 | ...APPEARANCES.map((appearance) => |
| 167 | renderVariant("dark", adaptiveVariablesFor("dark")), | 183 | renderVariant(appearance, { |
| 184 | ...adaptiveVariablesFor(appearance), | ||
| 185 | ...clerkVariablesFor(appearance), | ||
| 186 | }), | ||
| 187 | ), | ||
| 168 | ...BUILT_IN_THEME_IDS.flatMap((themeId) => | 188 | ...BUILT_IN_THEME_IDS.flatMap((themeId) => |
| 169 | APPEARANCES.map((appearance) => | 189 | APPEARANCES.map((appearance) => |
| 170 | renderVariant(`${themeId}-${appearance}`, variablesFor(themeId, appearance)), | 190 | renderVariant(`${themeId}-${appearance}`, variablesFor(themeId, appearance)), |
apps/mobile/scripts/generate-uniwind-themes.test.ts+33| ... | @@ -52,4 +52,37 @@ describe("generate mobile Uniwind themes", () => { | ... | @@ -52,4 +52,37 @@ describe("generate mobile Uniwind themes", () => { |
| 52 | expect(variables.dark["--color-screen"]).toBe("#0a0a0a"); | 52 | expect(variables.dark["--color-screen"]).toBe("#0a0a0a"); |
| 53 | expect(Object.keys(variables.light)).toEqual(Object.keys(variables.dark)); | 53 | expect(Object.keys(variables.light)).toEqual(Object.keys(variables.dark)); |
| 54 | }); | 54 | }); |
| 55 | |||
| 56 | it("gives every theme the same variables and a fixed Clerk palette for its appearance", () => { | ||
| 57 | const css = | ||
| 58 | NodeFS.readFileSync(NodePath.resolve(import.meta.dirname, "../global.css"), "utf8") + | ||
| 59 | renderUniwindThemesCSS(); | ||
| 60 | const themes = new Map<string, Map<string, string>>( | ||
| 61 | ["light", "dark", ...customThemeNames].map((name) => [name, new Map()]), | ||
| 62 | ); | ||
| 63 | for (const [, name, body] of css.matchAll(/@variant ([\w-]+) \{([^}]+)\}/gu)) { | ||
| 64 | const variables = themes.get(name!); | ||
| 65 | for (const [, variable, value] of body!.matchAll(/(--[\w-]+):\s*([^;]+);/gu)) { | ||
| 66 | variables?.set(variable!, value!.trim().toLowerCase()); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | const lightVariables = themes.get("light")!; | ||
| 71 | for (const [name, variables] of themes) { | ||
| 72 | expect([...variables.keys()].sort(), name).toEqual([...lightVariables.keys()].sort()); | ||
| 73 | const isDark = name === "dark" || name.endsWith("-dark"); | ||
| 74 | expect( | ||
| 75 | Object.fromEntries( | ||
| 76 | [...variables].filter(([variable]) => variable.startsWith("--color-clerk-")), | ||
| 77 | ), | ||
| 78 | name, | ||
| 79 | ).toEqual({ | ||
| 80 | "--color-clerk-page": isDark ? "#0e0e0e" : "#f2f2f7", | ||
| 81 | "--color-clerk-foreground": isDark ? "#f5f5f5" : "#262626", | ||
| 82 | "--color-clerk-foreground-muted": isDark ? "#a3a3a3" : "#737373", | ||
| 83 | "--color-clerk-border": isDark ? "rgba(42, 42, 42, 0.06)" : "rgba(229, 229, 234, 0.06)", | ||
| 84 | "--color-clerk-danger": isDark ? "#fca5a5" : "#dc2626", | ||
| 85 | }); | ||
| 86 | } | ||
| 87 | }); | ||
| 55 | }); | 88 | }); |