@kilivi/payloadcms-theme-management 0.1.8 → 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +331 -41
  2. package/dist/components/ServerThemeInjector.d.ts +12 -3
  3. package/dist/components/ServerThemeInjector.d.ts.map +1 -1
  4. package/dist/components/ServerThemeInjector.js +8 -12
  5. package/dist/components/ServerThemeInjector.js.map +1 -1
  6. package/dist/components/ThemePreview.js.map +1 -1
  7. package/dist/components/typographyPreviewUtils.js.map +1 -1
  8. package/dist/constants/themeFonts.js.map +1 -1
  9. package/dist/fields/ColorPickerField.js.map +1 -1
  10. package/dist/fields/RadiusField.js.map +1 -1
  11. package/dist/fields/ThemeColorPickerField.css +138 -138
  12. package/dist/fields/ThemeColorPickerField.js.map +1 -1
  13. package/dist/fields/ThemePreviewField.js.map +1 -1
  14. package/dist/fields/ThemeTokenSelectField.js.map +1 -1
  15. package/dist/fields/colorModeFields.js.map +1 -1
  16. package/dist/fields/themeConfigurationField.js +3 -3
  17. package/dist/fields/themeConfigurationField.js.map +1 -1
  18. package/dist/index.d.ts +0 -1
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +0 -1
  21. package/dist/index.js.map +1 -1
  22. package/dist/payload-types.js +3 -3
  23. package/dist/payload-types.js.map +1 -1
  24. package/dist/plugin.js.map +1 -1
  25. package/dist/presets.js.map +1 -1
  26. package/dist/providers/Theme/index.js.map +1 -1
  27. package/dist/providers/Theme/shared.js.map +1 -1
  28. package/dist/providers/Theme/themeConfig.js.map +1 -1
  29. package/dist/providers/Theme/types.js.map +1 -1
  30. package/dist/server.d.ts +1 -0
  31. package/dist/server.d.ts.map +1 -1
  32. package/dist/server.js +1 -0
  33. package/dist/server.js.map +1 -1
  34. package/dist/src/--verbose/dist/fields/ThemeColorPickerField.scss +138 -0
  35. package/dist/src/dist/fields/ThemeColorPickerField.scss +138 -0
  36. package/dist/types.js.map +1 -1
  37. package/dist/utils/resolveThemeConfiguration.js.map +1 -1
  38. package/dist/utils/themeAssets.js.map +1 -1
  39. package/dist/utils/themeColors.js.map +1 -1
  40. package/dist/utils/themeUtils.js +6 -6
  41. package/dist/utils/themeUtils.js.map +1 -1
  42. package/package.json +10 -6
package/README.md CHANGED
@@ -1,80 +1,335 @@
1
- # Theme Configuration Plugin for Payload CMS
1
+ # Theme Management Plugin for Payload CMS v3
2
2
 
3
- A flexible theme configuration plugin for Payload CMS v3 that allows you to manage theme settings through the admin UI.
3
+ A comprehensive theme management plugin for Payload CMS v3 that provides powerful theming capabilities with SSR support, preventing FOUC (Flash of Unstyled Content).
4
4
 
5
5
  ## Features
6
6
 
7
- - 🎨 **Theme Management** - Configure primary and secondary colors
8
- - 🔤 **Typography Control** - Set custom font families
9
- - 📐 **Layout Settings** - Adjust header height and other layout properties
10
- - 🌓 **Theme Switcher** - Optional theme switching capability (light/dark/auto)
11
- - ⚙️ **Configurable** - Exclude specific collections or globals as needed
7
+ - 🎨 **Multiple Theme Presets** - Cool, Brutal, Neon, Solar, and more
8
+ - 🎨 **Custom Color Palette** - Full HSL color customization
9
+ - 🔤 **Typography Control** - Google Fonts integration for headings, body, and code
10
+ - 📐 **Border Radius Presets** - Sharp, Rounded, or Pill styles
11
+ - 🌓 **Dark Mode Support** - Built-in light/dark/system mode toggle
12
+ - 🚀 **SSR Theme Injection** - Zero FOUC with server-side rendering
13
+ - ⚡ **Performance Optimized** - Critical CSS inlining, preload links
14
+ - 🎯 **Type Safe** - Full TypeScript support
15
+ - 🔧 **Highly Configurable** - Flexible plugin options
12
16
 
13
17
  ## Installation
14
18
 
15
19
  ```bash
16
- npm install @payloadcms-plugins/theme-management
20
+ pnpm add @kilivi/payloadcms-theme-management
17
21
  # or
18
- yarn add @payloadcms-plugins/theme-management
22
+ npm install @kilivi/payloadcms-theme-management
19
23
  # or
20
- pnpm add @payloadcms-plugins/theme-management
24
+ yarn add @kilivi/payloadcms-theme-management
21
25
  ```
22
26
 
23
- ## Usage
27
+ ## Quick Start
24
28
 
25
- Add the plugin to your Payload config:
29
+ ### 1. Add Plugin to Payload Config
26
30
 
27
31
  ```typescript
28
- import { buildConfig } from 'payload';
29
- import { ThemeConfigurationPlugin } from '@payloadcms-plugins/theme-management';
32
+ import { buildConfig } from 'payload'
33
+ import { themeManagementPlugin } from '@kilivi/payloadcms-theme-management'
30
34
 
31
35
  export default buildConfig({
32
36
  // ... other config
37
+
38
+ globals: [
39
+ {
40
+ slug: 'site-settings',
41
+ fields: [
42
+ {
43
+ name: 'siteName',
44
+ type: 'text',
45
+ },
46
+ // Theme configuration will be injected here
47
+ ],
48
+ },
49
+ ],
50
+
33
51
  plugins: [
34
- ThemeConfigurationPlugin({
35
- enableThemeSwitcher: true,
36
- defaultTheme: 'auto',
37
- excludedCollections: [], // Collections to exclude
38
- excludedGlobals: [], // Globals to exclude
52
+ themeManagementPlugin({
53
+ enabled: true,
54
+ targetCollection: 'site-settings',
55
+ defaultTheme: 'cool',
56
+ includeColorModeToggle: true,
57
+ enableLogging: true,
39
58
  }),
40
59
  ],
41
- });
60
+ })
42
61
  ```
43
62
 
44
- ## Configuration Options
63
+ ### 2. Add Server Theme Injection (Next.js)
64
+
65
+ **⚠️ IMPORTANT:** Import from `/server` entry point!
66
+
67
+ ```tsx
68
+ // app/layout.tsx
69
+ import { ServerThemeInjector } from '@kilivi/payloadcms-theme-management/server'
70
+ import configPromise from '@payload-config'
71
+ import { getPayload } from 'payload'
72
+
73
+ export default async function RootLayout({
74
+ children,
75
+ }: {
76
+ children: React.ReactNode
77
+ }) {
78
+ const payload = await getPayload({ config: configPromise })
79
+
80
+ const { docs } = await payload.find({
81
+ collection: 'site-settings',
82
+ limit: 1,
83
+ })
84
+
85
+ return (
86
+ <html lang="en">
87
+ <head>
88
+ <ServerThemeInjector themeConfiguration={docs[0]?.themeConfiguration} />
89
+ </head>
90
+ <body>{children}</body>
91
+ </html>
92
+ )
93
+ }
94
+ ```
45
95
 
46
- ### `ThemeConfigurationPluginConfig`
96
+ ### 3. Use Theme Variables in Your CSS
97
+
98
+ The plugin injects CSS custom properties you can use:
99
+
100
+ ```css
101
+ .my-component {
102
+ background-color: hsl(var(--background));
103
+ color: hsl(var(--foreground));
104
+ border-radius: var(--radius);
105
+ font-family: var(--font-body);
106
+ }
107
+ ```
108
+
109
+ Or with Tailwind CSS:
110
+
111
+ ```tsx
112
+ <div className="bg-primary text-primary-foreground rounded-lg">
113
+ Themed Content
114
+ </div>
115
+ ```
116
+
117
+
118
+ ## Plugin Configuration Options
47
119
 
48
120
  | Option | Type | Default | Description |
49
121
  |--------|------|---------|-------------|
50
- | `excludedCollections` | `string[]` | `[]` | Array of collection slugs to exclude |
51
- | `excludedGlobals` | `string[]` | `[]` | Array of global slugs to exclude |
52
- | `enableThemeSwitcher` | `boolean` | `true` | Enable theme switcher in admin UI |
53
- | `defaultTheme` | `'light' \| 'dark' \| 'auto'` | `'auto'` | Default theme |
122
+ | `enabled` | `boolean` | `true` | Enable/disable the plugin |
123
+ | `targetCollection` | `string` | `'site-settings'` | Global or collection slug to add theme field to |
124
+ | `themePresets` | `ThemePreset[]` | Built-in presets | Custom theme presets |
125
+ | `defaultTheme` | `string` | `'cool'` | Default theme preset name |
126
+ | `includeColorModeToggle` | `boolean` | `true` | Show light/dark mode toggle |
127
+ | `includeCustomCSS` | `boolean` | `true` | Allow custom CSS injection |
128
+ | `includeBrandIdentity` | `boolean` | `false` | Show brand identity fields |
129
+ | `enableAdvancedFeatures` | `boolean` | `true` | Enable advanced customization |
130
+ | `enableLogging` | `boolean` | `false` | Log plugin actions to console |
131
+
132
+ ## Available Theme Presets
133
+
134
+ - **Cool** - Professional blue theme
135
+ - **Brutal** - High contrast, bold design
136
+ - **Neon** - Vibrant, energetic colors
137
+ - **Solar** - Warm, golden tones
138
+ - **Dealership** - Automotive-inspired
139
+ - **Real Estate** - Professional property theme (+ Gold, Neutral variants)
140
+
141
+ ## API Reference
142
+
143
+ ### Main Entry Point
144
+
145
+ Import from `@kilivi/payloadcms-theme-management` for client-safe code:
146
+
147
+ ```typescript
148
+ // Plugin
149
+ import { themeManagementPlugin } from '@kilivi/payloadcms-theme-management'
150
+
151
+ // Client Components
152
+ import { ThemeProvider } from '@kilivi/payloadcms-theme-management'
153
+
154
+ // Utilities
155
+ import {
156
+ generateThemeColorsCss,
157
+ generateThemeCSS,
158
+ getThemeStyles,
159
+ resolveThemeConfiguration,
160
+ fetchThemeConfiguration,
161
+ } from '@kilivi/payloadcms-theme-management'
162
+
163
+ // Types
164
+ import type {
165
+ ThemePreset,
166
+ ThemeDefaults,
167
+ ThemeManagementPluginOptions,
168
+ } from '@kilivi/payloadcms-theme-management'
169
+ ```
170
+
171
+ ### Server Entry Point
172
+
173
+ ⚠️ **Import from `/server` for server components only:**
174
+
175
+ ```typescript
176
+ import {
177
+ ServerThemeInjector,
178
+ getThemeCriticalCSS,
179
+ getThemeCSSPath,
180
+ generateThemePreloadLinks,
181
+ } from '@kilivi/payloadcms-theme-management/server'
182
+ ```
183
+
184
+ ### Subpath Exports
185
+
186
+ ```typescript
187
+ // Direct field imports
188
+ import { ThemeColorPickerField } from '@kilivi/payloadcms-theme-management/fields/ThemeColorPickerField'
189
+ import { ThemeTokenSelectField } from '@kilivi/payloadcms-theme-management/fields/ThemeTokenSelectField'
190
+
191
+ // Direct component imports
192
+ import { ThemePreview } from '@kilivi/payloadcms-theme-management/components/ThemePreview'
193
+ ```
194
+
195
+ ## Integration Examples
196
+
197
+ ### With Tailwind CSS
198
+
199
+ ```typescript
200
+ // tailwind.config.ts
201
+ import type { Config } from 'tailwindcss'
202
+
203
+ const config: Config = {
204
+ theme: {
205
+ extend: {
206
+ colors: {
207
+ background: 'hsl(var(--background))',
208
+ foreground: 'hsl(var(--foreground))',
209
+ primary: {
210
+ DEFAULT: 'hsl(var(--primary))',
211
+ foreground: 'hsl(var(--primary-foreground))',
212
+ },
213
+ // ... other color variables
214
+ },
215
+ borderRadius: {
216
+ lg: 'var(--radius)',
217
+ md: 'calc(var(--radius) - 2px)',
218
+ sm: 'calc(var(--radius) - 4px)',
219
+ },
220
+ fontFamily: {
221
+ heading: ['var(--font-heading)', 'sans-serif'],
222
+ body: ['var(--font-body)', 'sans-serif'],
223
+ },
224
+ },
225
+ },
226
+ }
227
+ ```
228
+
229
+ ### Fetching Theme Configuration
54
230
 
55
- ## Theme Configuration Fields
231
+ ```typescript
232
+ import { fetchThemeConfiguration } from '@kilivi/payloadcms-theme-management'
233
+
234
+ // Simple usage
235
+ const theme = await fetchThemeConfiguration()
236
+
237
+ // With options
238
+ const theme = await fetchThemeConfiguration({
239
+ collectionSlug: 'site-settings',
240
+ depth: 2,
241
+ locale: 'en',
242
+ })
243
+ ```
56
244
 
57
- The plugin adds a global called `theme-management` with the following fields:
245
+ ### Custom Theme Preset
58
246
 
59
- - **Primary Color** - Main theme color (e.g., #3B82F6)
60
- - **Secondary Color** - Secondary theme color (e.g., #10B981)
61
- - **Font Family** - Primary font family for the site
62
- - **Header Height** - Height of the site header in pixels
247
+ ```typescript
248
+ import type { ThemePreset } from '@kilivi/payloadcms-theme-management'
63
249
 
64
- ## Accessing Theme Configuration
250
+ const myTheme: ThemePreset = {
251
+ name: 'my-custom-theme',
252
+ label: 'My Custom Theme',
253
+ colors: {
254
+ primary: { h: 220, s: 70, l: 50 },
255
+ secondary: { h: 180, s: 60, l: 45 },
256
+ // ... other colors
257
+ },
258
+ borderRadius: 'rounded',
259
+ typography: {
260
+ heading: 'Poppins',
261
+ body: 'Inter',
262
+ code: 'Fira Code',
263
+ },
264
+ }
65
265
 
66
- You can access the theme configuration in your application:
266
+ // Use in plugin config
267
+ themeManagementPlugin({
268
+ themePresets: [myTheme],
269
+ defaultTheme: 'my-custom-theme',
270
+ })
271
+ ```
272
+
273
+ ## Migrating from Older Versions
274
+
275
+ See [MIGRATION_GUIDE.md](./MIGRATION_GUIDE.md) for detailed migration instructions.
276
+
277
+ ### Key Changes in v0.1.9+
278
+
279
+ - **Server components must import from `/server`**
280
+ - Added `server-only` package to prevent client bundling errors
281
+ - Removed `ServerThemeInjector` from main entry point
282
+
283
+ ```diff
284
+ - import { ServerThemeInjector } from '@kilivi/payloadcms-theme-management'
285
+ + import { ServerThemeInjector } from '@kilivi/payloadcms-theme-management/server'
286
+ ```
287
+
288
+
289
+ ## Testing
290
+
291
+ See [TEST_APP_GUIDE.md](./TEST_APP_GUIDE.md) for instructions on creating a test application.
292
+
293
+ ## Troubleshooting
294
+
295
+ ### `Module not found: Can't resolve 'fs/promises'`
296
+
297
+ **Solution:** Make sure you're using v0.1.9+ and importing server components from `/server`:
67
298
 
68
299
  ```typescript
69
- const payload = await getPayloadClient();
300
+ import { ServerThemeInjector } from '@kilivi/payloadcms-theme-management/server'
301
+ ```
302
+
303
+ Then clear your cache:
304
+ ```bash
305
+ rm -rf .next node_modules/.cache
306
+ pnpm install
307
+ ```
308
+
309
+ ### Theme Not Applying
70
310
 
71
- const themeConfig = await payload.findGlobal({
72
- slug: 'theme-management',
73
- });
311
+ 1. Verify `ServerThemeInjector` is in your `<head>` tag
312
+ 2. Check that site settings exist with theme configuration
313
+ 3. Inspect page source - should see `<style>` tag with CSS variables
314
+ 4. Ensure Tailwind/CSS is configured to use the CSS variables
315
+
316
+ ### TypeScript Errors
317
+
318
+ ```bash
319
+ # Regenerate Payload types
320
+ pnpm payload generate:types
74
321
 
75
- console.log(themeConfig.primaryColor); // e.g., "#3B82F6"
322
+ # Restart TypeScript server
323
+ # VS Code: Ctrl+Shift+P → "TypeScript: Restart TS Server"
76
324
  ```
77
325
 
326
+ ## Documentation
327
+
328
+ - [Migration Guide](./MIGRATION_GUIDE.md) - Upgrading from older versions
329
+ - [Test App Guide](./TEST_APP_GUIDE.md) - Create a test application
330
+ - [Server/Client Separation](./SERVER_CLIENT_SEPARATION.md) - Technical details
331
+ - [Build Setup](./BUILD_SETUP.md) - Build configuration details
332
+
78
333
  ## Development
79
334
 
80
335
  ```bash
@@ -86,12 +341,47 @@ pnpm build
86
341
 
87
342
  # Watch mode for development
88
343
  pnpm dev
344
+
345
+ # Clean build artifacts
346
+ pnpm clean
89
347
  ```
90
348
 
349
+ ## Contributing
350
+
351
+ Contributions are welcome! Please:
352
+
353
+ 1. Fork the repository
354
+ 2. Create a feature branch
355
+ 3. Make your changes
356
+ 4. Add tests if applicable
357
+ 5. Submit a pull request
358
+
91
359
  ## License
92
360
 
93
361
  Apache-2.0
94
362
 
95
- ## Contributing
363
+ ## Author
364
+
365
+ Created for Payload CMS v3 applications.
366
+
367
+ ## Links
368
+
369
+ - [NPM Package](https://www.npmjs.com/package/@kilivi/payloadcms-theme-management)
370
+ - [GitHub Repository](https://github.com/vitakili/payload-plugins)
371
+ - [Payload CMS](https://payloadcms.com)
372
+
373
+ ## Changelog
374
+
375
+ ### v0.1.9 (Latest)
376
+ - ✅ **Fixed:** Server/client component separation
377
+ - ✅ **Added:** `server-only` package to prevent bundling errors
378
+ - ✅ **Changed:** `ServerThemeInjector` now exported from `/server` entry
379
+ - ✅ **Added:** Comprehensive documentation
380
+
381
+ ### v0.1.7
382
+ - ✅ **Fixed:** ESM import resolution with `.js` extensions
383
+ - ✅ **Added:** SWC + TypeScript build pipeline
384
+
385
+ ### v0.1.5
386
+ - Initial release with theme management features
96
387
 
97
- Contributions are welcome! Please feel free to submit a Pull Request.
@@ -1,11 +1,20 @@
1
- import type { SiteSetting } from '../payload-types.js';
2
1
  interface ServerThemeInjectorProps {
3
- siteSettings: SiteSetting | null;
2
+ /**
3
+ * Theme configuration object from your site settings.
4
+ * Pass the themeConfiguration field directly, not the entire site settings object.
5
+ *
6
+ * @example
7
+ * ```tsx
8
+ * const siteSettings = await payload.findGlobal({ slug: 'site-settings' })
9
+ * <ServerThemeInjector themeConfiguration={siteSettings.themeConfiguration} />
10
+ * ```
11
+ */
12
+ themeConfiguration?: unknown;
4
13
  }
5
14
  /**
6
15
  * Server-side theme CSS injector to prevent FOUC
7
16
  * This component injects critical theme CSS directly into the HTML head during SSR
8
17
  */
9
- export declare function ServerThemeInjector({ siteSettings }: Readonly<ServerThemeInjectorProps>): Promise<import("react").JSX.Element>;
18
+ export declare function ServerThemeInjector({ themeConfiguration }: Readonly<ServerThemeInjectorProps>): Promise<import("react").JSX.Element>;
10
19
  export {};
11
20
  //# sourceMappingURL=ServerThemeInjector.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ServerThemeInjector.d.ts","sourceRoot":"","sources":["../../src/components/ServerThemeInjector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAatD,UAAU,wBAAwB;IAChC,YAAY,EAAE,WAAW,GAAG,IAAI,CAAA;CACjC;AAMD;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,EAAE,YAAY,EAAE,EAAE,QAAQ,CAAC,wBAAwB,CAAC,wCA0F7F"}
1
+ {"version":3,"file":"ServerThemeInjector.d.ts","sourceRoot":"","sources":["../../src/components/ServerThemeInjector.tsx"],"names":[],"mappings":"AAaA,UAAU,wBAAwB;IAChC;;;;;;;;;OASG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC7B;AAMD;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,EAAE,kBAAkB,EAAE,EAAE,QAAQ,CAAC,wBAAwB,CAAC,wCAuFnG"}
@@ -4,20 +4,16 @@ import { resolveThemeConfiguration } from '../utils/resolveThemeConfiguration.js
4
4
  import { createFallbackCriticalCSS, getThemeCriticalCSS, getThemeCSSPath } from '../utils/themeAssets.js';
5
5
  import { generateThemeColorsCss } from '../utils/themeColors.js';
6
6
  import { generateThemeCSS } from '../utils/themeUtils.js';
7
- /**
8
- * Server-side theme CSS injector to prevent FOUC
9
- * This component injects critical theme CSS directly into the HTML head during SSR
10
- */ export async function ServerThemeInjector({ siteSettings }) {
11
- const resolvedConfiguration = resolveThemeConfiguration(siteSettings?.themeConfiguration);
7
+ /**
8
+ * Server-side theme CSS injector to prevent FOUC
9
+ * This component injects critical theme CSS directly into the HTML head during SSR
10
+ */ export async function ServerThemeInjector({ themeConfiguration }) {
11
+ // Accept unknown type to avoid type conflicts between app's payload-types and plugin's payload-types
12
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
13
+ const resolvedConfiguration = resolveThemeConfiguration(themeConfiguration);
12
14
  const { theme, borderRadius, customCSS, lightMode, darkMode, fontScale, spacing, animationLevel, allowColorModeToggle, colorMode, typography } = resolvedConfiguration;
13
- const baseThemeConfiguration = {
14
- ...siteSettings?.themeConfiguration ?? {}
15
- };
16
- if ('typography' in baseThemeConfiguration) {
17
- delete baseThemeConfiguration.typography;
18
- }
15
+ // Use resolved configuration directly
19
16
  const normalizedThemeConfiguration = {
20
- ...baseThemeConfiguration,
21
17
  theme,
22
18
  colorMode,
23
19
  allowColorModeToggle,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/ServerThemeInjector.tsx"],"sourcesContent":["import type { SiteSetting } from '../payload-types.js'\nimport { getBorderRadiusConfig } from '../providers/Theme/themeConfig.js'\nimport type { BorderRadiusPreset, ThemeDefaults } from '../providers/Theme/types.js'\nimport type { ThemeTypographyPreset } from '../presets.js'\nimport { resolveThemeConfiguration } from '../utils/resolveThemeConfiguration.js'\nimport {\n createFallbackCriticalCSS,\n getThemeCriticalCSS,\n getThemeCSSPath,\n} from '../utils/themeAssets.js'\nimport { generateThemeColorsCss } from '../utils/themeColors.js'\nimport { generateThemeCSS } from '../utils/themeUtils.js'\n\ninterface ServerThemeInjectorProps {\n siteSettings: SiteSetting | null\n}\n\ntype RuntimeThemeConfiguration = Omit<NonNullable<SiteSetting['themeConfiguration']>, 'typography'> & {\n typography?: ThemeTypographyPreset | null\n}\n\n/**\n * Server-side theme CSS injector to prevent FOUC\n * This component injects critical theme CSS directly into the HTML head during SSR\n */\nexport async function ServerThemeInjector({ siteSettings }: Readonly<ServerThemeInjectorProps>) {\n const resolvedConfiguration = resolveThemeConfiguration(siteSettings?.themeConfiguration)\n const {\n theme,\n borderRadius,\n customCSS,\n lightMode,\n darkMode,\n fontScale,\n spacing,\n animationLevel,\n allowColorModeToggle,\n colorMode,\n typography,\n } = resolvedConfiguration\n\n const baseThemeConfiguration = { ...(siteSettings?.themeConfiguration ?? {}) }\n if ('typography' in baseThemeConfiguration) {\n delete (baseThemeConfiguration as Record<string, unknown>).typography\n }\n\n const normalizedThemeConfiguration: RuntimeThemeConfiguration = {\n ...baseThemeConfiguration,\n theme,\n colorMode,\n allowColorModeToggle,\n borderRadius,\n fontScale,\n spacing,\n animationLevel,\n customCSS: customCSS ?? undefined,\n lightMode,\n darkMode,\n typography: typography ?? undefined,\n }\n\n let criticalCSS = await getThemeCriticalCSS(theme as ThemeDefaults)\n criticalCSS ??= createFallbackCriticalCSS(theme as ThemeDefaults)\n\n const borderRadiusMap: Record<string, BorderRadiusPreset> = {\n none: 'none',\n small: 'small',\n medium: 'medium',\n large: 'large',\n xl: 'xl',\n full: 'xl',\n }\n const mappedBorderRadius = borderRadiusMap[borderRadius ?? 'medium'] ?? 'medium'\n const borderRadiusConfig = getBorderRadiusConfig(mappedBorderRadius)\n const cssRecord = typeof borderRadiusConfig?.css === 'string'\n ? { '--radius-default': borderRadiusConfig.css }\n : borderRadiusConfig?.css ?? {}\n\n const borderRadiusCSS = Object.entries(cssRecord)\n .map(([property, value]) => ` ${property}: ${value};`)\n .join('\\n')\n\n const borderRadiusBlock = borderRadiusCSS\n ? `:root {\n${borderRadiusCSS}\n}`\n : ''\n\n const themeConfigurationCSS = generateThemeCSS(normalizedThemeConfiguration)\n const colorModesCSS = generateThemeColorsCss({ themeName: theme, lightMode, darkMode })\n const customCSSBlock = typeof customCSS === 'string' ? customCSS.trim() : ''\n\n const combinedCSS = [\n criticalCSS,\n borderRadiusBlock,\n themeConfigurationCSS,\n colorModesCSS,\n customCSSBlock,\n ]\n .filter((block) => Boolean(block?.trim?.().length))\n .join('\\n\\n')\n\n const themeCSSPath = getThemeCSSPath(theme as ThemeDefaults)\n return (\n <>\n <style\n id=\"theme-critical-css\"\n dangerouslySetInnerHTML={{\n __html: combinedCSS,\n }}\n />\n <link rel=\"preload\" href={themeCSSPath} as=\"style\" />\n <link rel=\"stylesheet\" href={themeCSSPath} />\n </>\n )\n}\n"],"names":["getBorderRadiusConfig","resolveThemeConfiguration","createFallbackCriticalCSS","getThemeCriticalCSS","getThemeCSSPath","generateThemeColorsCss","generateThemeCSS","ServerThemeInjector","siteSettings","resolvedConfiguration","themeConfiguration","theme","borderRadius","customCSS","lightMode","darkMode","fontScale","spacing","animationLevel","allowColorModeToggle","colorMode","typography","baseThemeConfiguration","normalizedThemeConfiguration","undefined","criticalCSS","borderRadiusMap","none","small","medium","large","xl","full","mappedBorderRadius","borderRadiusConfig","cssRecord","css","borderRadiusCSS","Object","entries","map","property","value","join","borderRadiusBlock","themeConfigurationCSS","colorModesCSS","themeName","customCSSBlock","trim","combinedCSS","filter","block","Boolean","length","themeCSSPath","style","id","dangerouslySetInnerHTML","__html","link","rel","href","as"],"mappings":";AACA,SAASA,qBAAqB,QAAQ,oCAAmC;AAGzE,SAASC,yBAAyB,QAAQ,wCAAuC;AACjF,SACEC,yBAAyB,EACzBC,mBAAmB,EACnBC,eAAe,QACV,0BAAyB;AAChC,SAASC,sBAAsB,QAAQ,0BAAyB;AAChE,SAASC,gBAAgB,QAAQ,yBAAwB;AAUzD;;;CAGC,GACD,OAAO,eAAeC,oBAAoB,EAAEC,YAAY,EAAsC;IAC5F,MAAMC,wBAAwBR,0BAA0BO,cAAcE;IACtE,MAAM,EACJC,KAAK,EACLC,YAAY,EACZC,SAAS,EACTC,SAAS,EACTC,QAAQ,EACRC,SAAS,EACTC,OAAO,EACPC,cAAc,EACdC,oBAAoB,EACpBC,SAAS,EACTC,UAAU,EACX,GAAGZ;IAEJ,MAAMa,yBAAyB;QAAE,GAAId,cAAcE,sBAAsB,CAAC,CAAC;IAAE;IAC7E,IAAI,gBAAgBY,wBAAwB;QAC1C,OAAO,AAACA,uBAAmDD,UAAU;IACvE;IAEA,MAAME,+BAA0D;QAC9D,GAAGD,sBAAsB;QACzBX;QACAS;QACAD;QACAP;QACAI;QACAC;QACAC;QACAL,WAAWA,aAAaW;QACxBV;QACAC;QACAM,YAAYA,cAAcG;IAC5B;IAEA,IAAIC,cAAc,MAAMtB,oBAAoBQ;IAC5Cc,gBAAgBvB,0BAA0BS;IAE1C,MAAMe,kBAAsD;QAC1DC,MAAM;QACNC,OAAO;QACPC,QAAQ;QACRC,OAAO;QACPC,IAAI;QACJC,MAAM;IACR;IACA,MAAMC,qBAAqBP,eAAe,CAACd,gBAAgB,SAAS,IAAI;IACxE,MAAMsB,qBAAqBlC,sBAAsBiC;IACjD,MAAME,YAAY,OAAOD,oBAAoBE,QAAQ,WACjD;QAAE,oBAAoBF,mBAAmBE,GAAG;IAAC,IAC7CF,oBAAoBE,OAAO,CAAC;IAEhC,MAAMC,kBAAkBC,OAAOC,OAAO,CAACJ,WACpCK,GAAG,CAAC,CAAC,CAACC,UAAUC,MAAM,GAAK,CAAC,EAAE,EAAED,SAAS,EAAE,EAAEC,MAAM,CAAC,CAAC,EACrDC,IAAI,CAAC;IAER,MAAMC,oBAAoBP,kBACtB,CAAC;AACP,EAAEA,gBAAgB;CACjB,CAAC,GACI;IAEJ,MAAMQ,wBAAwBvC,iBAAiBiB;IAC/C,MAAMuB,gBAAgBzC,uBAAuB;QAAE0C,WAAWpC;QAAOG;QAAWC;IAAS;IACrF,MAAMiC,iBAAiB,OAAOnC,cAAc,WAAWA,UAAUoC,IAAI,KAAK;IAE1E,MAAMC,cAAc;QAClBzB;QACAmB;QACAC;QACAC;QACAE;KACD,CACEG,MAAM,CAAC,CAACC,QAAUC,QAAQD,OAAOH,SAASK,SAC1CX,IAAI,CAAC;IAER,MAAMY,eAAenD,gBAAgBO;IACrC,qBACE;;0BACE,KAAC6C;gBACCC,IAAG;gBACHC,yBAAyB;oBACvBC,QAAQT;gBACV;;0BAEF,KAACU;gBAAKC,KAAI;gBAAUC,MAAMP;gBAAcQ,IAAG;;0BAC3C,KAACH;gBAAKC,KAAI;gBAAaC,MAAMP;;;;AAGnC"}
1
+ {"version":3,"sources":["../../src/components/ServerThemeInjector.tsx"],"sourcesContent":["import { getBorderRadiusConfig } from '../providers/Theme/themeConfig.js'\r\nimport type { BorderRadiusPreset, ThemeDefaults } from '../providers/Theme/types.js'\r\nimport type { ThemeTypographyPreset } from '../presets.js'\r\nimport { resolveThemeConfiguration } from '../utils/resolveThemeConfiguration.js'\r\nimport type { ResolvedThemeConfiguration } from '../utils/resolveThemeConfiguration.js'\r\nimport {\r\n createFallbackCriticalCSS,\r\n getThemeCriticalCSS,\r\n getThemeCSSPath,\r\n} from '../utils/themeAssets.js'\r\nimport { generateThemeColorsCss } from '../utils/themeColors.js'\r\nimport { generateThemeCSS } from '../utils/themeUtils.js'\r\n\r\ninterface ServerThemeInjectorProps {\r\n /**\r\n * Theme configuration object from your site settings.\r\n * Pass the themeConfiguration field directly, not the entire site settings object.\r\n * \r\n * @example\r\n * ```tsx\r\n * const siteSettings = await payload.findGlobal({ slug: 'site-settings' })\r\n * <ServerThemeInjector themeConfiguration={siteSettings.themeConfiguration} />\r\n * ```\r\n */\r\n themeConfiguration?: unknown\r\n}\r\n\r\ntype RuntimeThemeConfiguration = Omit<ResolvedThemeConfiguration, 'typography'> & {\r\n typography?: ThemeTypographyPreset | null\r\n}\r\n\r\n/**\r\n * Server-side theme CSS injector to prevent FOUC\r\n * This component injects critical theme CSS directly into the HTML head during SSR\r\n */\r\nexport async function ServerThemeInjector({ themeConfiguration }: Readonly<ServerThemeInjectorProps>) {\r\n // Accept unknown type to avoid type conflicts between app's payload-types and plugin's payload-types\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const resolvedConfiguration = resolveThemeConfiguration(themeConfiguration as any)\r\n const {\r\n theme,\r\n borderRadius,\r\n customCSS,\r\n lightMode,\r\n darkMode,\r\n fontScale,\r\n spacing,\r\n animationLevel,\r\n allowColorModeToggle,\r\n colorMode,\r\n typography,\r\n } = resolvedConfiguration\r\n\r\n // Use resolved configuration directly\r\n const normalizedThemeConfiguration: RuntimeThemeConfiguration = {\r\n theme,\r\n colorMode,\r\n allowColorModeToggle,\r\n borderRadius,\r\n fontScale,\r\n spacing,\r\n animationLevel,\r\n customCSS: customCSS ?? undefined,\r\n lightMode,\r\n darkMode,\r\n typography: typography ?? undefined,\r\n }\r\n\r\n let criticalCSS = await getThemeCriticalCSS(theme as ThemeDefaults)\r\n criticalCSS ??= createFallbackCriticalCSS(theme as ThemeDefaults)\r\n\r\n const borderRadiusMap: Record<string, BorderRadiusPreset> = {\r\n none: 'none',\r\n small: 'small',\r\n medium: 'medium',\r\n large: 'large',\r\n xl: 'xl',\r\n full: 'xl',\r\n }\r\n const mappedBorderRadius = borderRadiusMap[borderRadius ?? 'medium'] ?? 'medium'\r\n const borderRadiusConfig = getBorderRadiusConfig(mappedBorderRadius)\r\n const cssRecord = typeof borderRadiusConfig?.css === 'string'\r\n ? { '--radius-default': borderRadiusConfig.css }\r\n : borderRadiusConfig?.css ?? {}\r\n\r\n const borderRadiusCSS = Object.entries(cssRecord)\r\n .map(([property, value]) => ` ${property}: ${value};`)\r\n .join('\\n')\r\n\r\n const borderRadiusBlock = borderRadiusCSS\r\n ? `:root {\r\n${borderRadiusCSS}\r\n}`\r\n : ''\r\n\r\n const themeConfigurationCSS = generateThemeCSS(normalizedThemeConfiguration)\r\n const colorModesCSS = generateThemeColorsCss({ themeName: theme, lightMode, darkMode })\r\n const customCSSBlock = typeof customCSS === 'string' ? customCSS.trim() : ''\r\n\r\n const combinedCSS = [\r\n criticalCSS,\r\n borderRadiusBlock,\r\n themeConfigurationCSS,\r\n colorModesCSS,\r\n customCSSBlock,\r\n ]\r\n .filter((block) => Boolean(block?.trim?.().length))\r\n .join('\\n\\n')\r\n\r\n const themeCSSPath = getThemeCSSPath(theme as ThemeDefaults)\r\n return (\r\n <>\r\n <style\r\n id=\"theme-critical-css\"\r\n dangerouslySetInnerHTML={{\r\n __html: combinedCSS,\r\n }}\r\n />\r\n <link rel=\"preload\" href={themeCSSPath} as=\"style\" />\r\n <link rel=\"stylesheet\" href={themeCSSPath} />\r\n </>\r\n )\r\n}\r\n"],"names":["getBorderRadiusConfig","resolveThemeConfiguration","createFallbackCriticalCSS","getThemeCriticalCSS","getThemeCSSPath","generateThemeColorsCss","generateThemeCSS","ServerThemeInjector","themeConfiguration","resolvedConfiguration","theme","borderRadius","customCSS","lightMode","darkMode","fontScale","spacing","animationLevel","allowColorModeToggle","colorMode","typography","normalizedThemeConfiguration","undefined","criticalCSS","borderRadiusMap","none","small","medium","large","xl","full","mappedBorderRadius","borderRadiusConfig","cssRecord","css","borderRadiusCSS","Object","entries","map","property","value","join","borderRadiusBlock","themeConfigurationCSS","colorModesCSS","themeName","customCSSBlock","trim","combinedCSS","filter","block","Boolean","length","themeCSSPath","style","id","dangerouslySetInnerHTML","__html","link","rel","href","as"],"mappings":";AAAA,SAASA,qBAAqB,QAAQ,oCAAmC;AAGzE,SAASC,yBAAyB,QAAQ,wCAAuC;AAEjF,SACEC,yBAAyB,EACzBC,mBAAmB,EACnBC,eAAe,QACV,0BAAyB;AAChC,SAASC,sBAAsB,QAAQ,0BAAyB;AAChE,SAASC,gBAAgB,QAAQ,yBAAwB;AAoBzD;;;CAGC,GACD,OAAO,eAAeC,oBAAoB,EAAEC,kBAAkB,EAAsC;IAClG,qGAAqG;IACrG,8DAA8D;IAC9D,MAAMC,wBAAwBR,0BAA0BO;IACxD,MAAM,EACJE,KAAK,EACLC,YAAY,EACZC,SAAS,EACTC,SAAS,EACTC,QAAQ,EACRC,SAAS,EACTC,OAAO,EACPC,cAAc,EACdC,oBAAoB,EACpBC,SAAS,EACTC,UAAU,EACX,GAAGX;IAEJ,sCAAsC;IACtC,MAAMY,+BAA0D;QAC9DX;QACAS;QACAD;QACAP;QACAI;QACAC;QACAC;QACAL,WAAWA,aAAaU;QACxBT;QACAC;QACAM,YAAYA,cAAcE;IAC5B;IAEA,IAAIC,cAAc,MAAMpB,oBAAoBO;IAC5Ca,gBAAgBrB,0BAA0BQ;IAE1C,MAAMc,kBAAsD;QAC1DC,MAAM;QACNC,OAAO;QACPC,QAAQ;QACRC,OAAO;QACPC,IAAI;QACJC,MAAM;IACR;IACA,MAAMC,qBAAqBP,eAAe,CAACb,gBAAgB,SAAS,IAAI;IACxE,MAAMqB,qBAAqBhC,sBAAsB+B;IACjD,MAAME,YAAY,OAAOD,oBAAoBE,QAAQ,WACjD;QAAE,oBAAoBF,mBAAmBE,GAAG;IAAC,IAC7CF,oBAAoBE,OAAO,CAAC;IAEhC,MAAMC,kBAAkBC,OAAOC,OAAO,CAACJ,WACpCK,GAAG,CAAC,CAAC,CAACC,UAAUC,MAAM,GAAK,CAAC,EAAE,EAAED,SAAS,EAAE,EAAEC,MAAM,CAAC,CAAC,EACrDC,IAAI,CAAC;IAER,MAAMC,oBAAoBP,kBACtB,CAAC;AACP,EAAEA,gBAAgB;CACjB,CAAC,GACI;IAEJ,MAAMQ,wBAAwBrC,iBAAiBe;IAC/C,MAAMuB,gBAAgBvC,uBAAuB;QAAEwC,WAAWnC;QAAOG;QAAWC;IAAS;IACrF,MAAMgC,iBAAiB,OAAOlC,cAAc,WAAWA,UAAUmC,IAAI,KAAK;IAE1E,MAAMC,cAAc;QAClBzB;QACAmB;QACAC;QACAC;QACAE;KACD,CACEG,MAAM,CAAC,CAACC,QAAUC,QAAQD,OAAOH,SAASK,SAC1CX,IAAI,CAAC;IAER,MAAMY,eAAejD,gBAAgBM;IACrC,qBACE;;0BACE,KAAC4C;gBACCC,IAAG;gBACHC,yBAAyB;oBACvBC,QAAQT;gBACV;;0BAEF,KAACU;gBAAKC,KAAI;gBAAUC,MAAMP;gBAAcQ,IAAG;;0BAC3C,KAACH;gBAAKC,KAAI;gBAAaC,MAAMP;;;;AAGnC"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/ThemePreview.tsx"],"sourcesContent":["'use client'\n\nimport { useField } from '@payloadcms/ui'\nimport React, { useMemo } from 'react'\nimport { themeIsValid } from '../providers/Theme/types.js'\nimport { defaultThemePresets } from '../presets.js'\n\nconst DEFAULT_THEME_KEY = 'cool'\nconst basePresetMap = defaultThemePresets.reduce<\n Record<string, (typeof defaultThemePresets)[number]>\n>((accumulator, preset) => {\n accumulator[preset.name] = preset\n return accumulator\n}, {})\n\nconst fallbackPreset = basePresetMap[DEFAULT_THEME_KEY] ?? defaultThemePresets[0]\nconst fallbackLightMode = fallbackPreset?.lightMode ?? {\n primary: '#3b82f6',\n accent: '#06b6d4',\n background: '#ffffff',\n foreground: '#1f2937',\n}\n\nexport default function ThemePreview() {\n // Get individual field values using useField hooks\n const { value: selectedTheme } = useField<string>({ path: 'themeConfiguration.theme' })\n const { value: primaryColor } = useField<string>({\n path: 'themeConfiguration.customization.primaryColor',\n })\n const { value: accentColor } = useField<string>({\n path: 'themeConfiguration.customization.accentColor',\n })\n const { value: backgroundColor } = useField<string>({\n path: 'themeConfiguration.customization.backgroundColor',\n })\n const { value: textColor } = useField<string>({\n path: 'themeConfiguration.customization.textColor',\n })\n\n // Determine current theme and if overrides are active\n const currentTheme = themeIsValid(selectedTheme)\n ? selectedTheme\n : (fallbackPreset?.name ?? 'cool')\n const hasOverrides = Boolean(primaryColor || accentColor || backgroundColor || textColor)\n\n const themeColors = useMemo(() => {\n const preset = basePresetMap[currentTheme] ?? fallbackPreset\n const lightMode = preset?.lightMode ?? fallbackLightMode\n\n return {\n primary: lightMode?.primary ?? fallbackLightMode.primary,\n accent:\n lightMode?.accent ??\n lightMode?.secondary ??\n fallbackLightMode.accent ??\n fallbackLightMode.primary,\n background: lightMode?.background ?? fallbackLightMode.background,\n text: lightMode?.foreground ?? fallbackLightMode.foreground,\n }\n }, [currentTheme])\n\n const currentColors = useMemo(\n () => ({\n primary: primaryColor || themeColors.primary,\n accent: accentColor || themeColors.accent,\n background: backgroundColor || themeColors.background,\n text: textColor || themeColors.text,\n }),\n [primaryColor, accentColor, backgroundColor, textColor, themeColors],\n )\n\n return (\n <div className=\"theme-preview\" style={{ marginTop: '20px' }}>\n <div\n style={{\n fontSize: '16px',\n fontWeight: '600',\n marginBottom: '16px',\n color: '#374151',\n }}\n >\n 🎨 Live Theme Preview\n </div>\n\n <div\n className=\"preview-container\"\n style={{\n border: '2px solid #e5e7eb',\n borderRadius: '12px',\n overflow: 'hidden',\n backgroundColor: currentColors.background,\n color: currentColors.text,\n minHeight: '300px',\n }}\n >\n {/* Header */}\n <div\n style={{\n backgroundColor: currentColors.primary,\n color: currentColors.background,\n padding: '16px 24px',\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n }}\n >\n <div style={{ fontSize: '20px', fontWeight: '700' }}>Your Website</div>\n <nav style={{ display: 'flex', gap: '24px', fontSize: '14px' }}>\n <span>Home</span>\n <span>About</span>\n <span>Services</span>\n <span>Contact</span>\n </nav>\n </div>\n\n {/* Content */}\n <div style={{ padding: '32px 24px' }}>\n <h1\n style={{\n fontSize: '32px',\n fontWeight: '800',\n marginBottom: '16px',\n color: currentColors.text,\n }}\n >\n Welcome to Your Site\n </h1>\n\n <p\n style={{\n fontSize: '16px',\n lineHeight: '1.6',\n marginBottom: '24px',\n color: currentColors.text,\n opacity: 0.8,\n }}\n >\n This is how your content will look with the selected theme. The colors and styling will\n be applied across your entire website.\n </p>\n\n {/* Buttons */}\n <div style={{ display: 'flex', gap: '12px', marginBottom: '32px' }}>\n <button\n style={{\n backgroundColor: currentColors.primary,\n color: currentColors.background,\n border: 'none',\n padding: '12px 24px',\n borderRadius: '6px',\n fontSize: '14px',\n fontWeight: '600',\n cursor: 'pointer',\n }}\n >\n Primary Button\n </button>\n <button\n style={{\n backgroundColor: 'transparent',\n color: currentColors.primary,\n border: `2px solid ${currentColors.primary}`,\n padding: '10px 24px',\n borderRadius: '6px',\n fontSize: '14px',\n fontWeight: '600',\n cursor: 'pointer',\n }}\n >\n Secondary Button\n </button>\n </div>\n\n {/* Card */}\n <div\n style={{\n backgroundColor: currentColors.text,\n color: currentColors.background,\n padding: '24px',\n borderRadius: '8px',\n opacity: 0.05,\n marginBottom: '16px',\n }}\n />\n <div\n style={{\n border: `1px solid ${currentColors.text}`,\n padding: '20px',\n borderRadius: '8px',\n opacity: 0.1,\n }}\n >\n <h3\n style={{\n fontSize: '18px',\n fontWeight: '600',\n marginBottom: '12px',\n color: currentColors.text,\n }}\n >\n Sample Card\n </h3>\n <p\n style={{\n fontSize: '14px',\n color: currentColors.text,\n opacity: 0.7,\n }}\n >\n This shows how cards and content blocks will appear.\n </p>\n </div>\n </div>\n\n {/* Footer */}\n <div\n style={{\n backgroundColor: currentColors.accent,\n color: currentColors.background,\n padding: '16px 24px',\n textAlign: 'center',\n fontSize: '14px',\n marginTop: 'auto',\n }}\n >\n © 2025 Your Website. Powered by PayloadCMS.\n </div>\n </div>\n\n {/* Theme info */}\n <div\n style={{\n marginTop: '12px',\n fontSize: '12px',\n color: '#6b7280',\n display: 'grid',\n gridTemplateColumns: 'repeat(2, 1fr)',\n gap: '8px',\n }}\n >\n <div>\n <strong>Active Theme:</strong> {currentTheme}\n </div>\n <div>\n <strong>Primary:</strong> {currentColors.primary}\n </div>\n <div>\n <strong>Accent:</strong> {currentColors.accent}\n </div>\n <div>\n <strong>Background:</strong> {currentColors.background}\n </div>\n </div>\n\n {/* Customization indicator */}\n {hasOverrides && (\n <div\n style={{\n marginTop: '8px',\n padding: '8px 12px',\n backgroundColor: '#fef3c7',\n borderRadius: '6px',\n fontSize: '11px',\n color: '#92400e',\n display: 'flex',\n alignItems: 'center',\n gap: '6px',\n }}\n >\n <span>⚡</span>\n <span>\n <strong>Custom colors applied</strong> - overriding theme defaults\n </span>\n </div>\n )}\n </div>\n )\n}\n"],"names":["useField","React","useMemo","themeIsValid","defaultThemePresets","DEFAULT_THEME_KEY","basePresetMap","reduce","accumulator","preset","name","fallbackPreset","fallbackLightMode","lightMode","primary","accent","background","foreground","ThemePreview","value","selectedTheme","path","primaryColor","accentColor","backgroundColor","textColor","currentTheme","hasOverrides","Boolean","themeColors","secondary","text","currentColors","div","className","style","marginTop","fontSize","fontWeight","marginBottom","color","border","borderRadius","overflow","minHeight","padding","display","justifyContent","alignItems","nav","gap","span","h1","p","lineHeight","opacity","button","cursor","h3","textAlign","gridTemplateColumns","strong"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/components/ThemePreview.tsx"],"sourcesContent":["'use client'\r\n\r\nimport { useField } from '@payloadcms/ui'\r\nimport React, { useMemo } from 'react'\r\nimport { themeIsValid } from '../providers/Theme/types.js'\r\nimport { defaultThemePresets } from '../presets.js'\r\n\r\nconst DEFAULT_THEME_KEY = 'cool'\r\nconst basePresetMap = defaultThemePresets.reduce<\r\n Record<string, (typeof defaultThemePresets)[number]>\r\n>((accumulator, preset) => {\r\n accumulator[preset.name] = preset\r\n return accumulator\r\n}, {})\r\n\r\nconst fallbackPreset = basePresetMap[DEFAULT_THEME_KEY] ?? defaultThemePresets[0]\r\nconst fallbackLightMode = fallbackPreset?.lightMode ?? {\r\n primary: '#3b82f6',\r\n accent: '#06b6d4',\r\n background: '#ffffff',\r\n foreground: '#1f2937',\r\n}\r\n\r\nexport default function ThemePreview() {\r\n // Get individual field values using useField hooks\r\n const { value: selectedTheme } = useField<string>({ path: 'themeConfiguration.theme' })\r\n const { value: primaryColor } = useField<string>({\r\n path: 'themeConfiguration.customization.primaryColor',\r\n })\r\n const { value: accentColor } = useField<string>({\r\n path: 'themeConfiguration.customization.accentColor',\r\n })\r\n const { value: backgroundColor } = useField<string>({\r\n path: 'themeConfiguration.customization.backgroundColor',\r\n })\r\n const { value: textColor } = useField<string>({\r\n path: 'themeConfiguration.customization.textColor',\r\n })\r\n\r\n // Determine current theme and if overrides are active\r\n const currentTheme = themeIsValid(selectedTheme)\r\n ? selectedTheme\r\n : (fallbackPreset?.name ?? 'cool')\r\n const hasOverrides = Boolean(primaryColor || accentColor || backgroundColor || textColor)\r\n\r\n const themeColors = useMemo(() => {\r\n const preset = basePresetMap[currentTheme] ?? fallbackPreset\r\n const lightMode = preset?.lightMode ?? fallbackLightMode\r\n\r\n return {\r\n primary: lightMode?.primary ?? fallbackLightMode.primary,\r\n accent:\r\n lightMode?.accent ??\r\n lightMode?.secondary ??\r\n fallbackLightMode.accent ??\r\n fallbackLightMode.primary,\r\n background: lightMode?.background ?? fallbackLightMode.background,\r\n text: lightMode?.foreground ?? fallbackLightMode.foreground,\r\n }\r\n }, [currentTheme])\r\n\r\n const currentColors = useMemo(\r\n () => ({\r\n primary: primaryColor || themeColors.primary,\r\n accent: accentColor || themeColors.accent,\r\n background: backgroundColor || themeColors.background,\r\n text: textColor || themeColors.text,\r\n }),\r\n [primaryColor, accentColor, backgroundColor, textColor, themeColors],\r\n )\r\n\r\n return (\r\n <div className=\"theme-preview\" style={{ marginTop: '20px' }}>\r\n <div\r\n style={{\r\n fontSize: '16px',\r\n fontWeight: '600',\r\n marginBottom: '16px',\r\n color: '#374151',\r\n }}\r\n >\r\n 🎨 Live Theme Preview\r\n </div>\r\n\r\n <div\r\n className=\"preview-container\"\r\n style={{\r\n border: '2px solid #e5e7eb',\r\n borderRadius: '12px',\r\n overflow: 'hidden',\r\n backgroundColor: currentColors.background,\r\n color: currentColors.text,\r\n minHeight: '300px',\r\n }}\r\n >\r\n {/* Header */}\r\n <div\r\n style={{\r\n backgroundColor: currentColors.primary,\r\n color: currentColors.background,\r\n padding: '16px 24px',\r\n display: 'flex',\r\n justifyContent: 'space-between',\r\n alignItems: 'center',\r\n }}\r\n >\r\n <div style={{ fontSize: '20px', fontWeight: '700' }}>Your Website</div>\r\n <nav style={{ display: 'flex', gap: '24px', fontSize: '14px' }}>\r\n <span>Home</span>\r\n <span>About</span>\r\n <span>Services</span>\r\n <span>Contact</span>\r\n </nav>\r\n </div>\r\n\r\n {/* Content */}\r\n <div style={{ padding: '32px 24px' }}>\r\n <h1\r\n style={{\r\n fontSize: '32px',\r\n fontWeight: '800',\r\n marginBottom: '16px',\r\n color: currentColors.text,\r\n }}\r\n >\r\n Welcome to Your Site\r\n </h1>\r\n\r\n <p\r\n style={{\r\n fontSize: '16px',\r\n lineHeight: '1.6',\r\n marginBottom: '24px',\r\n color: currentColors.text,\r\n opacity: 0.8,\r\n }}\r\n >\r\n This is how your content will look with the selected theme. The colors and styling will\r\n be applied across your entire website.\r\n </p>\r\n\r\n {/* Buttons */}\r\n <div style={{ display: 'flex', gap: '12px', marginBottom: '32px' }}>\r\n <button\r\n style={{\r\n backgroundColor: currentColors.primary,\r\n color: currentColors.background,\r\n border: 'none',\r\n padding: '12px 24px',\r\n borderRadius: '6px',\r\n fontSize: '14px',\r\n fontWeight: '600',\r\n cursor: 'pointer',\r\n }}\r\n >\r\n Primary Button\r\n </button>\r\n <button\r\n style={{\r\n backgroundColor: 'transparent',\r\n color: currentColors.primary,\r\n border: `2px solid ${currentColors.primary}`,\r\n padding: '10px 24px',\r\n borderRadius: '6px',\r\n fontSize: '14px',\r\n fontWeight: '600',\r\n cursor: 'pointer',\r\n }}\r\n >\r\n Secondary Button\r\n </button>\r\n </div>\r\n\r\n {/* Card */}\r\n <div\r\n style={{\r\n backgroundColor: currentColors.text,\r\n color: currentColors.background,\r\n padding: '24px',\r\n borderRadius: '8px',\r\n opacity: 0.05,\r\n marginBottom: '16px',\r\n }}\r\n />\r\n <div\r\n style={{\r\n border: `1px solid ${currentColors.text}`,\r\n padding: '20px',\r\n borderRadius: '8px',\r\n opacity: 0.1,\r\n }}\r\n >\r\n <h3\r\n style={{\r\n fontSize: '18px',\r\n fontWeight: '600',\r\n marginBottom: '12px',\r\n color: currentColors.text,\r\n }}\r\n >\r\n Sample Card\r\n </h3>\r\n <p\r\n style={{\r\n fontSize: '14px',\r\n color: currentColors.text,\r\n opacity: 0.7,\r\n }}\r\n >\r\n This shows how cards and content blocks will appear.\r\n </p>\r\n </div>\r\n </div>\r\n\r\n {/* Footer */}\r\n <div\r\n style={{\r\n backgroundColor: currentColors.accent,\r\n color: currentColors.background,\r\n padding: '16px 24px',\r\n textAlign: 'center',\r\n fontSize: '14px',\r\n marginTop: 'auto',\r\n }}\r\n >\r\n © 2025 Your Website. Powered by PayloadCMS.\r\n </div>\r\n </div>\r\n\r\n {/* Theme info */}\r\n <div\r\n style={{\r\n marginTop: '12px',\r\n fontSize: '12px',\r\n color: '#6b7280',\r\n display: 'grid',\r\n gridTemplateColumns: 'repeat(2, 1fr)',\r\n gap: '8px',\r\n }}\r\n >\r\n <div>\r\n <strong>Active Theme:</strong> {currentTheme}\r\n </div>\r\n <div>\r\n <strong>Primary:</strong> {currentColors.primary}\r\n </div>\r\n <div>\r\n <strong>Accent:</strong> {currentColors.accent}\r\n </div>\r\n <div>\r\n <strong>Background:</strong> {currentColors.background}\r\n </div>\r\n </div>\r\n\r\n {/* Customization indicator */}\r\n {hasOverrides && (\r\n <div\r\n style={{\r\n marginTop: '8px',\r\n padding: '8px 12px',\r\n backgroundColor: '#fef3c7',\r\n borderRadius: '6px',\r\n fontSize: '11px',\r\n color: '#92400e',\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '6px',\r\n }}\r\n >\r\n <span>⚡</span>\r\n <span>\r\n <strong>Custom colors applied</strong> - overriding theme defaults\r\n </span>\r\n </div>\r\n )}\r\n </div>\r\n )\r\n}\r\n"],"names":["useField","React","useMemo","themeIsValid","defaultThemePresets","DEFAULT_THEME_KEY","basePresetMap","reduce","accumulator","preset","name","fallbackPreset","fallbackLightMode","lightMode","primary","accent","background","foreground","ThemePreview","value","selectedTheme","path","primaryColor","accentColor","backgroundColor","textColor","currentTheme","hasOverrides","Boolean","themeColors","secondary","text","currentColors","div","className","style","marginTop","fontSize","fontWeight","marginBottom","color","border","borderRadius","overflow","minHeight","padding","display","justifyContent","alignItems","nav","gap","span","h1","p","lineHeight","opacity","button","cursor","h3","textAlign","gridTemplateColumns","strong"],"mappings":"AAAA;;AAEA,SAASA,QAAQ,QAAQ,iBAAgB;AACzC,OAAOC,SAASC,OAAO,QAAQ,QAAO;AACtC,SAASC,YAAY,QAAQ,8BAA6B;AAC1D,SAASC,mBAAmB,QAAQ,gBAAe;AAEnD,MAAMC,oBAAoB;AAC1B,MAAMC,gBAAgBF,oBAAoBG,MAAM,CAE9C,CAACC,aAAaC;IACdD,WAAW,CAACC,OAAOC,IAAI,CAAC,GAAGD;IAC3B,OAAOD;AACT,GAAG,CAAC;AAEJ,MAAMG,iBAAiBL,aAAa,CAACD,kBAAkB,IAAID,mBAAmB,CAAC,EAAE;AACjF,MAAMQ,oBAAoBD,gBAAgBE,aAAa;IACrDC,SAAS;IACTC,QAAQ;IACRC,YAAY;IACZC,YAAY;AACd;AAEA,eAAe,SAASC;IACtB,mDAAmD;IACnD,MAAM,EAAEC,OAAOC,aAAa,EAAE,GAAGpB,SAAiB;QAAEqB,MAAM;IAA2B;IACrF,MAAM,EAAEF,OAAOG,YAAY,EAAE,GAAGtB,SAAiB;QAC/CqB,MAAM;IACR;IACA,MAAM,EAAEF,OAAOI,WAAW,EAAE,GAAGvB,SAAiB;QAC9CqB,MAAM;IACR;IACA,MAAM,EAAEF,OAAOK,eAAe,EAAE,GAAGxB,SAAiB;QAClDqB,MAAM;IACR;IACA,MAAM,EAAEF,OAAOM,SAAS,EAAE,GAAGzB,SAAiB;QAC5CqB,MAAM;IACR;IAEA,sDAAsD;IACtD,MAAMK,eAAevB,aAAaiB,iBAC9BA,gBACCT,gBAAgBD,QAAQ;IAC7B,MAAMiB,eAAeC,QAAQN,gBAAgBC,eAAeC,mBAAmBC;IAE/E,MAAMI,cAAc3B,QAAQ;QAC1B,MAAMO,SAASH,aAAa,CAACoB,aAAa,IAAIf;QAC9C,MAAME,YAAYJ,QAAQI,aAAaD;QAEvC,OAAO;YACLE,SAASD,WAAWC,WAAWF,kBAAkBE,OAAO;YACxDC,QACEF,WAAWE,UACXF,WAAWiB,aACXlB,kBAAkBG,MAAM,IACxBH,kBAAkBE,OAAO;YAC3BE,YAAYH,WAAWG,cAAcJ,kBAAkBI,UAAU;YACjEe,MAAMlB,WAAWI,cAAcL,kBAAkBK,UAAU;QAC7D;IACF,GAAG;QAACS;KAAa;IAEjB,MAAMM,gBAAgB9B,QACpB,IAAO,CAAA;YACLY,SAASQ,gBAAgBO,YAAYf,OAAO;YAC5CC,QAAQQ,eAAeM,YAAYd,MAAM;YACzCC,YAAYQ,mBAAmBK,YAAYb,UAAU;YACrDe,MAAMN,aAAaI,YAAYE,IAAI;QACrC,CAAA,GACA;QAACT;QAAcC;QAAaC;QAAiBC;QAAWI;KAAY;IAGtE,qBACE,MAACI;QAAIC,WAAU;QAAgBC,OAAO;YAAEC,WAAW;QAAO;;0BACxD,KAACH;gBACCE,OAAO;oBACLE,UAAU;oBACVC,YAAY;oBACZC,cAAc;oBACdC,OAAO;gBACT;0BACD;;0BAID,MAACP;gBACCC,WAAU;gBACVC,OAAO;oBACLM,QAAQ;oBACRC,cAAc;oBACdC,UAAU;oBACVnB,iBAAiBQ,cAAchB,UAAU;oBACzCwB,OAAOR,cAAcD,IAAI;oBACzBa,WAAW;gBACb;;kCAGA,MAACX;wBACCE,OAAO;4BACLX,iBAAiBQ,cAAclB,OAAO;4BACtC0B,OAAOR,cAAchB,UAAU;4BAC/B6B,SAAS;4BACTC,SAAS;4BACTC,gBAAgB;4BAChBC,YAAY;wBACd;;0CAEA,KAACf;gCAAIE,OAAO;oCAAEE,UAAU;oCAAQC,YAAY;gCAAM;0CAAG;;0CACrD,MAACW;gCAAId,OAAO;oCAAEW,SAAS;oCAAQI,KAAK;oCAAQb,UAAU;gCAAO;;kDAC3D,KAACc;kDAAK;;kDACN,KAACA;kDAAK;;kDACN,KAACA;kDAAK;;kDACN,KAACA;kDAAK;;;;;;kCAKV,MAAClB;wBAAIE,OAAO;4BAAEU,SAAS;wBAAY;;0CACjC,KAACO;gCACCjB,OAAO;oCACLE,UAAU;oCACVC,YAAY;oCACZC,cAAc;oCACdC,OAAOR,cAAcD,IAAI;gCAC3B;0CACD;;0CAID,KAACsB;gCACClB,OAAO;oCACLE,UAAU;oCACViB,YAAY;oCACZf,cAAc;oCACdC,OAAOR,cAAcD,IAAI;oCACzBwB,SAAS;gCACX;0CACD;;0CAMD,MAACtB;gCAAIE,OAAO;oCAAEW,SAAS;oCAAQI,KAAK;oCAAQX,cAAc;gCAAO;;kDAC/D,KAACiB;wCACCrB,OAAO;4CACLX,iBAAiBQ,cAAclB,OAAO;4CACtC0B,OAAOR,cAAchB,UAAU;4CAC/ByB,QAAQ;4CACRI,SAAS;4CACTH,cAAc;4CACdL,UAAU;4CACVC,YAAY;4CACZmB,QAAQ;wCACV;kDACD;;kDAGD,KAACD;wCACCrB,OAAO;4CACLX,iBAAiB;4CACjBgB,OAAOR,cAAclB,OAAO;4CAC5B2B,QAAQ,CAAC,UAAU,EAAET,cAAclB,OAAO,EAAE;4CAC5C+B,SAAS;4CACTH,cAAc;4CACdL,UAAU;4CACVC,YAAY;4CACZmB,QAAQ;wCACV;kDACD;;;;0CAMH,KAACxB;gCACCE,OAAO;oCACLX,iBAAiBQ,cAAcD,IAAI;oCACnCS,OAAOR,cAAchB,UAAU;oCAC/B6B,SAAS;oCACTH,cAAc;oCACda,SAAS;oCACThB,cAAc;gCAChB;;0CAEF,MAACN;gCACCE,OAAO;oCACLM,QAAQ,CAAC,UAAU,EAAET,cAAcD,IAAI,EAAE;oCACzCc,SAAS;oCACTH,cAAc;oCACda,SAAS;gCACX;;kDAEA,KAACG;wCACCvB,OAAO;4CACLE,UAAU;4CACVC,YAAY;4CACZC,cAAc;4CACdC,OAAOR,cAAcD,IAAI;wCAC3B;kDACD;;kDAGD,KAACsB;wCACClB,OAAO;4CACLE,UAAU;4CACVG,OAAOR,cAAcD,IAAI;4CACzBwB,SAAS;wCACX;kDACD;;;;;;kCAOL,KAACtB;wBACCE,OAAO;4BACLX,iBAAiBQ,cAAcjB,MAAM;4BACrCyB,OAAOR,cAAchB,UAAU;4BAC/B6B,SAAS;4BACTc,WAAW;4BACXtB,UAAU;4BACVD,WAAW;wBACb;kCACD;;;;0BAMH,MAACH;gBACCE,OAAO;oBACLC,WAAW;oBACXC,UAAU;oBACVG,OAAO;oBACPM,SAAS;oBACTc,qBAAqB;oBACrBV,KAAK;gBACP;;kCAEA,MAACjB;;0CACC,KAAC4B;0CAAO;;4BAAsB;4BAAEnC;;;kCAElC,MAACO;;0CACC,KAAC4B;0CAAO;;4BAAiB;4BAAE7B,cAAclB,OAAO;;;kCAElD,MAACmB;;0CACC,KAAC4B;0CAAO;;4BAAgB;4BAAE7B,cAAcjB,MAAM;;;kCAEhD,MAACkB;;0CACC,KAAC4B;0CAAO;;4BAAoB;4BAAE7B,cAAchB,UAAU;;;;;YAKzDW,8BACC,MAACM;gBACCE,OAAO;oBACLC,WAAW;oBACXS,SAAS;oBACTrB,iBAAiB;oBACjBkB,cAAc;oBACdL,UAAU;oBACVG,OAAO;oBACPM,SAAS;oBACTE,YAAY;oBACZE,KAAK;gBACP;;kCAEA,KAACC;kCAAK;;kCACN,MAACA;;0CACC,KAACU;0CAAO;;4BAA8B;;;;;;;AAMlD"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/typographyPreviewUtils.ts"],"sourcesContent":["import { BODY_FONT_OPTIONS, FONT_VALUE_TO_CSS, HEADING_FONT_OPTIONS } from '../constants/themeFonts.js'\nimport { defaultThemePresets } from '../presets.js'\n\nexport interface TypographySelection {\n bodyFont?: string | null\n headingFont?: string | null\n bodyFontCustom?: string | null\n headingFontCustom?: string | null\n baseFontSize?: string | null\n lineHeight?: string | null\n}\n\nexport interface ResolvedTypographyPreview {\n bodyFont: string\n headingFont: string\n baseFontSize: string\n lineHeight: string\n bodyLabel: string\n headingLabel: string\n}\n\nconst FALLBACK_THEME = defaultThemePresets[0]?.name ?? 'cool'\nconst fallbackPreset =\n defaultThemePresets.find((preset) => preset.name === FALLBACK_THEME) ?? defaultThemePresets[0]\n\nconst FONT_VAR_FALLBACK: Record<string, string> = {\n 'var(--font-geist-sans)': '\"Geist Sans\", system-ui, sans-serif',\n 'var(--font-geist-mono)': '\"Geist Mono\", SFMono-Regular, ui-monospace, monospace',\n 'var(--font-inter)': '\"Inter\", system-ui, sans-serif',\n 'var(--font-outfit)': '\"Outfit\", system-ui, sans-serif',\n 'var(--font-playfair)': '\"Playfair Display\", \"Times New Roman\", serif',\n 'var(--font-lora)': '\"Lora\", \"Times New Roman\", serif',\n 'var(--font-manrope)': '\"Manrope\", system-ui, sans-serif',\n 'var(--font-urbanist)': '\"Urbanist\", system-ui, sans-serif',\n}\n\nfunction withFallback(fontFamily: string, fallback: string): string {\n if (!fontFamily) return fallback\n\n if (fontFamily.startsWith('var(')) {\n const mappedFallback = FONT_VAR_FALLBACK[fontFamily] ?? fallback\n return `${fontFamily}, ${mappedFallback}`\n }\n\n return fontFamily\n}\n\nfunction getPresetTypography(themeName?: string) {\n const preset = defaultThemePresets.find((item) => item.name === themeName) ?? fallbackPreset\n return preset?.typography\n}\n\nfunction resolveFontFamily(\n value: string | null | undefined,\n customValue: string | null | undefined,\n fallback: string,\n): string {\n if (!value || value === 'preset') {\n return withFallback(fallback, fallbackPreset?.typography?.fontFamily ?? 'system-ui, sans-serif')\n }\n\n if (value === 'custom') {\n if (customValue && customValue.trim().length > 0) {\n return customValue.trim()\n }\n return withFallback(fallback, fallbackPreset?.typography?.fontFamily ?? 'system-ui, sans-serif')\n }\n\n const preconfigured = FONT_VALUE_TO_CSS[value]\n if (preconfigured) {\n return withFallback(\n preconfigured,\n fallbackPreset?.typography?.fontFamily ?? 'system-ui, sans-serif',\n )\n }\n\n return withFallback(fallback, fallbackPreset?.typography?.fontFamily ?? 'system-ui, sans-serif')\n}\n\nfunction resolveOptionLabel(\n options: ReadonlyArray<{ label: string | Record<string, string>; value: string }>,\n value?: string | null,\n locale: 'en' | 'cs' = 'en',\n): string {\n const option = options.find((item) => item.value === value)\n if (!option) return value ?? ''\n if (typeof option.label === 'string') {\n return option.label\n }\n return option.label?.[locale] ?? Object.values(option.label)[0] ?? option.value\n}\n\nexport function resolveTypographyPreview(\n selection: TypographySelection | null | undefined,\n themeName?: string,\n): ResolvedTypographyPreview {\n const presetTypography = getPresetTypography(themeName)\n const fallbackBody = presetTypography?.fontFamily ?? 'system-ui, sans-serif'\n const fallbackHeading = presetTypography?.headingFamily ?? fallbackBody\n const fallbackSize = presetTypography?.baseFontSize ?? '16px'\n const fallbackLineHeight = presetTypography?.lineHeight ?? '1.6'\n\n const bodyFontValue = selection?.bodyFont ?? 'preset'\n const headingFontValue = selection?.headingFont ?? 'preset'\n const bodyFontCustom = selection?.bodyFontCustom ?? undefined\n const headingFontCustom = selection?.headingFontCustom ?? undefined\n const resolvedBodyFont = resolveFontFamily(bodyFontValue, bodyFontCustom, fallbackBody)\n const resolvedHeadingFont = resolveFontFamily(\n headingFontValue,\n headingFontCustom,\n fallbackHeading,\n )\n\n const baseFontSize =\n selection?.baseFontSize && selection.baseFontSize !== 'preset'\n ? selection.baseFontSize\n : fallbackSize\n const lineHeight =\n selection?.lineHeight && selection.lineHeight !== 'preset'\n ? selection.lineHeight\n : fallbackLineHeight\n\n return {\n bodyFont: resolvedBodyFont,\n headingFont: resolvedHeadingFont,\n baseFontSize,\n lineHeight,\n bodyLabel: resolveOptionLabel(BODY_FONT_OPTIONS, bodyFontValue),\n headingLabel: resolveOptionLabel(HEADING_FONT_OPTIONS, headingFontValue),\n }\n}\n"],"names":["BODY_FONT_OPTIONS","FONT_VALUE_TO_CSS","HEADING_FONT_OPTIONS","defaultThemePresets","FALLBACK_THEME","name","fallbackPreset","find","preset","FONT_VAR_FALLBACK","withFallback","fontFamily","fallback","startsWith","mappedFallback","getPresetTypography","themeName","item","typography","resolveFontFamily","value","customValue","trim","length","preconfigured","resolveOptionLabel","options","locale","option","label","Object","values","resolveTypographyPreview","selection","presetTypography","fallbackBody","fallbackHeading","headingFamily","fallbackSize","baseFontSize","fallbackLineHeight","lineHeight","bodyFontValue","bodyFont","headingFontValue","headingFont","bodyFontCustom","undefined","headingFontCustom","resolvedBodyFont","resolvedHeadingFont","bodyLabel","headingLabel"],"mappings":"AAAA,SAASA,iBAAiB,EAAEC,iBAAiB,EAAEC,oBAAoB,QAAQ,6BAA4B;AACvG,SAASC,mBAAmB,QAAQ,gBAAe;AAoBnD,MAAMC,iBAAiBD,mBAAmB,CAAC,EAAE,EAAEE,QAAQ;AACvD,MAAMC,iBACJH,oBAAoBI,IAAI,CAAC,CAACC,SAAWA,OAAOH,IAAI,KAAKD,mBAAmBD,mBAAmB,CAAC,EAAE;AAEhG,MAAMM,oBAA4C;IAChD,0BAA0B;IAC1B,0BAA0B;IAC1B,qBAAqB;IACrB,sBAAsB;IACtB,wBAAwB;IACxB,oBAAoB;IACpB,uBAAuB;IACvB,wBAAwB;AAC1B;AAEA,SAASC,aAAaC,UAAkB,EAAEC,QAAgB;IACxD,IAAI,CAACD,YAAY,OAAOC;IAExB,IAAID,WAAWE,UAAU,CAAC,SAAS;QACjC,MAAMC,iBAAiBL,iBAAiB,CAACE,WAAW,IAAIC;QACxD,OAAO,GAAGD,WAAW,EAAE,EAAEG,gBAAgB;IAC3C;IAEA,OAAOH;AACT;AAEA,SAASI,oBAAoBC,SAAkB;IAC7C,MAAMR,SAASL,oBAAoBI,IAAI,CAAC,CAACU,OAASA,KAAKZ,IAAI,KAAKW,cAAcV;IAC9E,OAAOE,QAAQU;AACjB;AAEA,SAASC,kBACPC,KAAgC,EAChCC,WAAsC,EACtCT,QAAgB;IAEhB,IAAI,CAACQ,SAASA,UAAU,UAAU;QAChC,OAAOV,aAAaE,UAAUN,gBAAgBY,YAAYP,cAAc;IAC1E;IAEA,IAAIS,UAAU,UAAU;QACtB,IAAIC,eAAeA,YAAYC,IAAI,GAAGC,MAAM,GAAG,GAAG;YAChD,OAAOF,YAAYC,IAAI;QACzB;QACA,OAAOZ,aAAaE,UAAUN,gBAAgBY,YAAYP,cAAc;IAC1E;IAEA,MAAMa,gBAAgBvB,iBAAiB,CAACmB,MAAM;IAC9C,IAAII,eAAe;QACjB,OAAOd,aACLc,eACAlB,gBAAgBY,YAAYP,cAAc;IAE9C;IAEA,OAAOD,aAAaE,UAAUN,gBAAgBY,YAAYP,cAAc;AAC1E;AAEA,SAASc,mBACPC,OAAiF,EACjFN,KAAqB,EACrBO,SAAsB,IAAI;IAE1B,MAAMC,SAASF,QAAQnB,IAAI,CAAC,CAACU,OAASA,KAAKG,KAAK,KAAKA;IACrD,IAAI,CAACQ,QAAQ,OAAOR,SAAS;IAC7B,IAAI,OAAOQ,OAAOC,KAAK,KAAK,UAAU;QACpC,OAAOD,OAAOC,KAAK;IACrB;IACA,OAAOD,OAAOC,KAAK,EAAE,CAACF,OAAO,IAAIG,OAAOC,MAAM,CAACH,OAAOC,KAAK,CAAC,CAAC,EAAE,IAAID,OAAOR,KAAK;AACjF;AAEA,OAAO,SAASY,yBACdC,SAAiD,EACjDjB,SAAkB;IAElB,MAAMkB,mBAAmBnB,oBAAoBC;IAC7C,MAAMmB,eAAeD,kBAAkBvB,cAAc;IACrD,MAAMyB,kBAAkBF,kBAAkBG,iBAAiBF;IAC3D,MAAMG,eAAeJ,kBAAkBK,gBAAgB;IACvD,MAAMC,qBAAqBN,kBAAkBO,cAAc;IAE3D,MAAMC,gBAAgBT,WAAWU,YAAY;IAC7C,MAAMC,mBAAmBX,WAAWY,eAAe;IACnD,MAAMC,iBAAiBb,WAAWa,kBAAkBC;IACpD,MAAMC,oBAAoBf,WAAWe,qBAAqBD;IAC1D,MAAME,mBAAmB9B,kBAAkBuB,eAAeI,gBAAgBX;IAC1E,MAAMe,sBAAsB/B,kBAC1ByB,kBACAI,mBACAZ;IAGF,MAAMG,eACJN,WAAWM,gBAAgBN,UAAUM,YAAY,KAAK,WAClDN,UAAUM,YAAY,GACtBD;IACN,MAAMG,aACJR,WAAWQ,cAAcR,UAAUQ,UAAU,KAAK,WAC9CR,UAAUQ,UAAU,GACpBD;IAEN,OAAO;QACLG,UAAUM;QACVJ,aAAaK;QACbX;QACAE;QACAU,WAAW1B,mBAAmBzB,mBAAmB0C;QACjDU,cAAc3B,mBAAmBvB,sBAAsB0C;IACzD;AACF"}
1
+ {"version":3,"sources":["../../src/components/typographyPreviewUtils.ts"],"sourcesContent":["import { BODY_FONT_OPTIONS, FONT_VALUE_TO_CSS, HEADING_FONT_OPTIONS } from '../constants/themeFonts.js'\r\nimport { defaultThemePresets } from '../presets.js'\r\n\r\nexport interface TypographySelection {\r\n bodyFont?: string | null\r\n headingFont?: string | null\r\n bodyFontCustom?: string | null\r\n headingFontCustom?: string | null\r\n baseFontSize?: string | null\r\n lineHeight?: string | null\r\n}\r\n\r\nexport interface ResolvedTypographyPreview {\r\n bodyFont: string\r\n headingFont: string\r\n baseFontSize: string\r\n lineHeight: string\r\n bodyLabel: string\r\n headingLabel: string\r\n}\r\n\r\nconst FALLBACK_THEME = defaultThemePresets[0]?.name ?? 'cool'\r\nconst fallbackPreset =\r\n defaultThemePresets.find((preset) => preset.name === FALLBACK_THEME) ?? defaultThemePresets[0]\r\n\r\nconst FONT_VAR_FALLBACK: Record<string, string> = {\r\n 'var(--font-geist-sans)': '\"Geist Sans\", system-ui, sans-serif',\r\n 'var(--font-geist-mono)': '\"Geist Mono\", SFMono-Regular, ui-monospace, monospace',\r\n 'var(--font-inter)': '\"Inter\", system-ui, sans-serif',\r\n 'var(--font-outfit)': '\"Outfit\", system-ui, sans-serif',\r\n 'var(--font-playfair)': '\"Playfair Display\", \"Times New Roman\", serif',\r\n 'var(--font-lora)': '\"Lora\", \"Times New Roman\", serif',\r\n 'var(--font-manrope)': '\"Manrope\", system-ui, sans-serif',\r\n 'var(--font-urbanist)': '\"Urbanist\", system-ui, sans-serif',\r\n}\r\n\r\nfunction withFallback(fontFamily: string, fallback: string): string {\r\n if (!fontFamily) return fallback\r\n\r\n if (fontFamily.startsWith('var(')) {\r\n const mappedFallback = FONT_VAR_FALLBACK[fontFamily] ?? fallback\r\n return `${fontFamily}, ${mappedFallback}`\r\n }\r\n\r\n return fontFamily\r\n}\r\n\r\nfunction getPresetTypography(themeName?: string) {\r\n const preset = defaultThemePresets.find((item) => item.name === themeName) ?? fallbackPreset\r\n return preset?.typography\r\n}\r\n\r\nfunction resolveFontFamily(\r\n value: string | null | undefined,\r\n customValue: string | null | undefined,\r\n fallback: string,\r\n): string {\r\n if (!value || value === 'preset') {\r\n return withFallback(fallback, fallbackPreset?.typography?.fontFamily ?? 'system-ui, sans-serif')\r\n }\r\n\r\n if (value === 'custom') {\r\n if (customValue && customValue.trim().length > 0) {\r\n return customValue.trim()\r\n }\r\n return withFallback(fallback, fallbackPreset?.typography?.fontFamily ?? 'system-ui, sans-serif')\r\n }\r\n\r\n const preconfigured = FONT_VALUE_TO_CSS[value]\r\n if (preconfigured) {\r\n return withFallback(\r\n preconfigured,\r\n fallbackPreset?.typography?.fontFamily ?? 'system-ui, sans-serif',\r\n )\r\n }\r\n\r\n return withFallback(fallback, fallbackPreset?.typography?.fontFamily ?? 'system-ui, sans-serif')\r\n}\r\n\r\nfunction resolveOptionLabel(\r\n options: ReadonlyArray<{ label: string | Record<string, string>; value: string }>,\r\n value?: string | null,\r\n locale: 'en' | 'cs' = 'en',\r\n): string {\r\n const option = options.find((item) => item.value === value)\r\n if (!option) return value ?? ''\r\n if (typeof option.label === 'string') {\r\n return option.label\r\n }\r\n return option.label?.[locale] ?? Object.values(option.label)[0] ?? option.value\r\n}\r\n\r\nexport function resolveTypographyPreview(\r\n selection: TypographySelection | null | undefined,\r\n themeName?: string,\r\n): ResolvedTypographyPreview {\r\n const presetTypography = getPresetTypography(themeName)\r\n const fallbackBody = presetTypography?.fontFamily ?? 'system-ui, sans-serif'\r\n const fallbackHeading = presetTypography?.headingFamily ?? fallbackBody\r\n const fallbackSize = presetTypography?.baseFontSize ?? '16px'\r\n const fallbackLineHeight = presetTypography?.lineHeight ?? '1.6'\r\n\r\n const bodyFontValue = selection?.bodyFont ?? 'preset'\r\n const headingFontValue = selection?.headingFont ?? 'preset'\r\n const bodyFontCustom = selection?.bodyFontCustom ?? undefined\r\n const headingFontCustom = selection?.headingFontCustom ?? undefined\r\n const resolvedBodyFont = resolveFontFamily(bodyFontValue, bodyFontCustom, fallbackBody)\r\n const resolvedHeadingFont = resolveFontFamily(\r\n headingFontValue,\r\n headingFontCustom,\r\n fallbackHeading,\r\n )\r\n\r\n const baseFontSize =\r\n selection?.baseFontSize && selection.baseFontSize !== 'preset'\r\n ? selection.baseFontSize\r\n : fallbackSize\r\n const lineHeight =\r\n selection?.lineHeight && selection.lineHeight !== 'preset'\r\n ? selection.lineHeight\r\n : fallbackLineHeight\r\n\r\n return {\r\n bodyFont: resolvedBodyFont,\r\n headingFont: resolvedHeadingFont,\r\n baseFontSize,\r\n lineHeight,\r\n bodyLabel: resolveOptionLabel(BODY_FONT_OPTIONS, bodyFontValue),\r\n headingLabel: resolveOptionLabel(HEADING_FONT_OPTIONS, headingFontValue),\r\n }\r\n}\r\n"],"names":["BODY_FONT_OPTIONS","FONT_VALUE_TO_CSS","HEADING_FONT_OPTIONS","defaultThemePresets","FALLBACK_THEME","name","fallbackPreset","find","preset","FONT_VAR_FALLBACK","withFallback","fontFamily","fallback","startsWith","mappedFallback","getPresetTypography","themeName","item","typography","resolveFontFamily","value","customValue","trim","length","preconfigured","resolveOptionLabel","options","locale","option","label","Object","values","resolveTypographyPreview","selection","presetTypography","fallbackBody","fallbackHeading","headingFamily","fallbackSize","baseFontSize","fallbackLineHeight","lineHeight","bodyFontValue","bodyFont","headingFontValue","headingFont","bodyFontCustom","undefined","headingFontCustom","resolvedBodyFont","resolvedHeadingFont","bodyLabel","headingLabel"],"mappings":"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"}