@kilivi/payloadcms-theme-management 1.0.16 → 1.1.1
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.
- package/README.md +111 -40
- package/dist/fields/ThemeColorPickerField.d.ts.map +1 -1
- package/dist/fields/ThemeColorPickerField.js +2 -54
- package/dist/fields/ThemeColorPickerField.js.map +1 -1
- package/dist/fields/ThemeTokenSelectField.js +2 -2
- package/dist/fields/ThemeTokenSelectField.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
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
|
-
## 🎉 Version 0.
|
|
5
|
+
## 🎉 Version 1.0.2 - Production Ready!
|
|
6
6
|
|
|
7
7
|
- **✅ Standalone Global Support** - Create separate appearance settings as a global
|
|
8
8
|
- **✅ Auto-Populate Light/Dark Colors** - Theme selection hook automatically fills color fields
|
|
9
|
-
- **✅ Multi-Tenant Ready** - Full support for multi-tenant applications
|
|
10
|
-
- **✅
|
|
9
|
+
- **✅ Multi-Tenant Ready** - Full support for multi-tenant applications with isolated themes
|
|
10
|
+
- **✅ Cache Invalidation** - Automatic cache invalidation after saving appearance settings
|
|
11
11
|
- **✅ Live Theme Preview** - Real-time theme preview in admin panel at `/admin/theme-preview`
|
|
12
12
|
- **✅ Professional Color Picker** - Enhanced color picker with react-colorful library
|
|
13
13
|
- **✅ shadcn/ui Compatible** - Works with https://ui.shadcn.com/themes
|
|
@@ -147,7 +147,7 @@ export default async function RootLayout({ children }: { children: React.ReactNo
|
|
|
147
147
|
const payload = await getPayload({ config: configPromise })
|
|
148
148
|
|
|
149
149
|
// Fetch from standalone global
|
|
150
|
-
const appearanceSettings = await payload.
|
|
150
|
+
const appearanceSettings = await payload.findGlobal({
|
|
151
151
|
slug: 'appearance-settings', // Your standalone global slug
|
|
152
152
|
})
|
|
153
153
|
|
|
@@ -162,6 +162,62 @@ export default async function RootLayout({ children }: { children: React.ReactNo
|
|
|
162
162
|
}
|
|
163
163
|
```
|
|
164
164
|
|
|
165
|
+
#### Cache Optimization with Next.js
|
|
166
|
+
|
|
167
|
+
When using standalone global, the plugin automatically invalidates cache after saving appearance settings using the tag `global_appearance-settings` (or `global_{your-slug}` if you use a custom slug).
|
|
168
|
+
|
|
169
|
+
You can optimize your theme fetching by adding cache tags to your layout:
|
|
170
|
+
|
|
171
|
+
```tsx
|
|
172
|
+
// app/layout.tsx
|
|
173
|
+
import { ServerThemeInjector } from '@kilivi/payloadcms-theme-management/server'
|
|
174
|
+
import configPromise from '@payload-config'
|
|
175
|
+
import { getPayload } from 'payload'
|
|
176
|
+
import { unstable_cache } from 'next/cache'
|
|
177
|
+
|
|
178
|
+
// Create cached theme fetcher with automatic invalidation
|
|
179
|
+
const getCachedTheme = unstable_cache(
|
|
180
|
+
async () => {
|
|
181
|
+
const payload = await getPayload({ config: configPromise })
|
|
182
|
+
const appearanceSettings = await payload.findGlobal({
|
|
183
|
+
slug: 'appearance-settings',
|
|
184
|
+
})
|
|
185
|
+
return appearanceSettings?.themeConfiguration
|
|
186
|
+
},
|
|
187
|
+
['appearance-settings-theme'],
|
|
188
|
+
{
|
|
189
|
+
tags: ['global_appearance-settings'], // Matches the auto-invalidation tag from plugin
|
|
190
|
+
revalidate: 3600, // Optional: revalidate every hour as fallback
|
|
191
|
+
},
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
export default async function RootLayout({ children }: { children: React.ReactNode }) {
|
|
195
|
+
const themeConfiguration = await getCachedTheme()
|
|
196
|
+
|
|
197
|
+
return (
|
|
198
|
+
<html lang="en">
|
|
199
|
+
<head>
|
|
200
|
+
<ServerThemeInjector themeConfiguration={themeConfiguration} />
|
|
201
|
+
</head>
|
|
202
|
+
<body>{children}</body>
|
|
203
|
+
</html>
|
|
204
|
+
)
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**Benefits:**
|
|
209
|
+
|
|
210
|
+
- ⚡ Theme settings are cached and reused across requests
|
|
211
|
+
- 🔄 Cache automatically invalidates when you save appearance settings in admin
|
|
212
|
+
- 🚀 Reduces database queries and improves performance
|
|
213
|
+
|
|
214
|
+
**Cache Tag Format:**
|
|
215
|
+
|
|
216
|
+
- Default: `global_appearance-settings`
|
|
217
|
+
- Custom slug: `global_{standaloneCollectionSlug}`
|
|
218
|
+
|
|
219
|
+
> **Note:** The cache invalidation hook is only available for standalone global mode. When using the tab mode (default), implement your own caching strategy based on your collection structure.
|
|
220
|
+
|
|
165
221
|
### 3. Use Theme Variables in Your CSS
|
|
166
222
|
|
|
167
223
|
The plugin injects CSS custom properties you can use:
|
|
@@ -196,7 +252,9 @@ Or with Tailwind CSS:
|
|
|
196
252
|
| `includeCustomCSS` | `boolean` | `true` | Allow custom CSS injection |
|
|
197
253
|
| `includeBrandIdentity` | `boolean` | `false` | Show brand identity fields |
|
|
198
254
|
| `enableAdvancedFeatures` | `boolean` | `true` | Enable advanced customization |
|
|
199
|
-
| `enableLogging` | `boolean` | `false` | Log plugin actions to console
|
|
255
|
+
| `enableLogging` | `boolean` | `false` | Log plugin actions to console (includes cache invalidation logs) |
|
|
256
|
+
|
|
257
|
+
**Cache Invalidation Note:** When using `useStandaloneCollection: true`, the plugin automatically invalidates the cache tag `global_{standaloneCollectionSlug}` after saving appearance settings. Use `unstable_cache` with matching tags for optimal performance.
|
|
200
258
|
|
|
201
259
|
## Available Theme Presets
|
|
202
260
|
|
|
@@ -720,37 +778,52 @@ export default {
|
|
|
720
778
|
|
|
721
779
|
### Fetching Theme Configuration
|
|
722
780
|
|
|
781
|
+
The recommended way to fetch theme configuration is using Payload's native API with Next.js caching:
|
|
782
|
+
|
|
723
783
|
```typescript
|
|
724
|
-
import
|
|
784
|
+
import configPromise from '@payload-config'
|
|
785
|
+
import { getPayload } from 'payload'
|
|
786
|
+
import { unstable_cache } from 'next/cache'
|
|
787
|
+
|
|
788
|
+
// Cached theme fetcher with automatic invalidation
|
|
789
|
+
const getCachedTheme = unstable_cache(
|
|
790
|
+
async () => {
|
|
791
|
+
const payload = await getPayload({ config: configPromise })
|
|
792
|
+
const global = await payload.findGlobal({
|
|
793
|
+
slug: 'appearance-settings', // or 'your-global-slug'
|
|
794
|
+
})
|
|
795
|
+
return global?.themeConfiguration
|
|
796
|
+
},
|
|
797
|
+
['appearance-settings'],
|
|
798
|
+
{
|
|
799
|
+
tags: ['global_appearance-settings'],
|
|
800
|
+
revalidate: 3600, // Revalidate every hour
|
|
801
|
+
},
|
|
802
|
+
)
|
|
725
803
|
|
|
726
|
-
//
|
|
727
|
-
|
|
804
|
+
// Use in your layout
|
|
805
|
+
export default async function RootLayout({ children }: { children: React.ReactNode }) {
|
|
806
|
+
const themeConfiguration = await getCachedTheme()
|
|
807
|
+
// Use themeConfiguration...
|
|
808
|
+
}
|
|
809
|
+
```
|
|
728
810
|
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
useGlobal: true, // Set to true when using standalone global
|
|
733
|
-
depth: 2,
|
|
734
|
-
locale: 'en',
|
|
735
|
-
})
|
|
811
|
+
**Legacy Helper (still available):**
|
|
812
|
+
|
|
813
|
+
If you need the helper function, `fetchThemeConfiguration` is still exported:
|
|
736
814
|
|
|
737
|
-
|
|
815
|
+
```typescript
|
|
816
|
+
import { fetchThemeConfiguration } from '@kilivi/payloadcms-theme-management'
|
|
817
|
+
|
|
818
|
+
// Simple fetch without caching
|
|
738
819
|
const theme = await fetchThemeConfiguration({
|
|
739
|
-
tenantSlug: 'tenant-123', // Optional: tenant identifier
|
|
740
820
|
collectionSlug: 'appearance-settings',
|
|
741
821
|
useGlobal: true,
|
|
742
|
-
depth: 2,
|
|
743
|
-
})
|
|
744
|
-
|
|
745
|
-
// From collection (default behavior)
|
|
746
|
-
const theme = await fetchThemeConfiguration({
|
|
747
|
-
collectionSlug: 'site-settings', // Collection slug
|
|
748
|
-
useGlobal: false, // Use collection endpoint
|
|
749
|
-
depth: 2,
|
|
750
|
-
locale: 'en',
|
|
751
822
|
})
|
|
752
823
|
```
|
|
753
824
|
|
|
825
|
+
However, prefer the native Payload API + `unstable_cache` approach for better performance and automatic invalidation support.
|
|
826
|
+
|
|
754
827
|
### Custom Theme Preset
|
|
755
828
|
|
|
756
829
|
```typescript
|
|
@@ -906,7 +979,15 @@ Created for Payload CMS v3 applications.
|
|
|
906
979
|
|
|
907
980
|
## Changelog
|
|
908
981
|
|
|
909
|
-
###
|
|
982
|
+
### v1.0.2 (Latest)
|
|
983
|
+
|
|
984
|
+
- ✅ **Added:** Automatic cache invalidation for standalone globals
|
|
985
|
+
- ✅ **Fixed:** Correct Payload CMS v3 API usage (findGlobal instead of non-existent findBySlug)
|
|
986
|
+
- ✅ **Improved:** Multi-tenant documentation with proper examples
|
|
987
|
+
- ✅ **Improved:** Cache optimization examples with unstable_cache
|
|
988
|
+
- ✅ **Updated:** README and Multi-Tenant guide with accurate API methods
|
|
989
|
+
|
|
990
|
+
### v1.0.0
|
|
910
991
|
|
|
911
992
|
- ✅ **Added:** Standalone Global Support — create separate appearance settings as a global
|
|
912
993
|
- ✅ **Added:** Auto-populate Light/Dark colors when selecting a theme
|
|
@@ -916,20 +997,10 @@ Created for Payload CMS v3 applications.
|
|
|
916
997
|
- ✅ **Added:** Professional color picker (react-colorful)
|
|
917
998
|
- ✅ **Improved:** shadcn/ui and TweakCN compatibility
|
|
918
999
|
- ✅ **Improved:** SSR theme injection, zero FOUC, and performance optimizations
|
|
919
|
-
- ✅ **
|
|
920
|
-
|
|
921
|
-
### v0.1.9
|
|
922
|
-
|
|
923
|
-
- ✅ **Fixed:** Server/client component separation
|
|
1000
|
+
- ✅ **Added:** Server/client component separation
|
|
924
1001
|
- ✅ **Added:** `server-only` package to prevent bundling errors
|
|
925
1002
|
- ✅ **Changed:** `ServerThemeInjector` now exported from `/server` entry
|
|
926
|
-
- ✅ **Added:** Comprehensive documentation
|
|
927
|
-
|
|
928
|
-
### v0.1.7
|
|
929
|
-
|
|
930
|
-
- ✅ **Fixed:** ESM import resolution with `.js` extensions
|
|
931
|
-
- ✅ **Added:** SWC + TypeScript build pipeline
|
|
932
1003
|
|
|
933
|
-
### v0.
|
|
1004
|
+
### v0.6.0
|
|
934
1005
|
|
|
935
|
-
- Initial release with
|
|
1006
|
+
- Initial release with core theming functionality
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThemeColorPickerField.d.ts","sourceRoot":"","sources":["../../src/fields/ThemeColorPickerField.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ThemeColorPickerField.d.ts","sourceRoot":"","sources":["../../src/fields/ThemeColorPickerField.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAA;AAmCvD,QAAA,MAAM,qBAAqB,EAAE,wBAsI5B,CAAA;AAED,eAAe,qBAAqB,CAAA"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useField } from '@payloadcms/ui';
|
|
4
|
+
import Color from 'color';
|
|
4
5
|
import { HexColorInput, HexColorPicker } from 'react-colorful';
|
|
5
6
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
6
7
|
// Import CSS for styling
|
|
@@ -25,60 +26,7 @@ function resolveLocalizedValue(value, fallback) {
|
|
|
25
26
|
* Convert various color formats to HEX for the color picker
|
|
26
27
|
*/ function toHex(color) {
|
|
27
28
|
if (!color) return '#000000';
|
|
28
|
-
|
|
29
|
-
if (color.startsWith('#')) return color;
|
|
30
|
-
// OKLCH format - extract hue and convert to approximate hex
|
|
31
|
-
if (color.startsWith('oklch')) {
|
|
32
|
-
// For now, return a default - proper conversion requires color-conversion library
|
|
33
|
-
return '#3b82f6' // blue-500 as default
|
|
34
|
-
;
|
|
35
|
-
}
|
|
36
|
-
// HSL format
|
|
37
|
-
if (color.startsWith('hsl')) {
|
|
38
|
-
const regex = /hsl\((\d+),\s*(\d+)%,\s*(\d+)%\)/;
|
|
39
|
-
const match = regex.exec(color);
|
|
40
|
-
if (match) {
|
|
41
|
-
const [, h, s, l] = match.map(Number);
|
|
42
|
-
return hslToHex(h, s, l);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return '#000000';
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Convert HSL to HEX
|
|
49
|
-
*/ function hslToHex(h, s, l) {
|
|
50
|
-
s /= 100;
|
|
51
|
-
l /= 100;
|
|
52
|
-
const c = (1 - Math.abs(2 * l - 1)) * s;
|
|
53
|
-
const x = c * (1 - Math.abs(h / 60 % 2 - 1));
|
|
54
|
-
const m = l - c / 2;
|
|
55
|
-
let r = 0;
|
|
56
|
-
let g = 0;
|
|
57
|
-
let b = 0;
|
|
58
|
-
if (h >= 0 && h < 60) {
|
|
59
|
-
r = c;
|
|
60
|
-
g = x;
|
|
61
|
-
} else if (h >= 60 && h < 120) {
|
|
62
|
-
r = x;
|
|
63
|
-
g = c;
|
|
64
|
-
} else if (h >= 120 && h < 180) {
|
|
65
|
-
g = c;
|
|
66
|
-
b = x;
|
|
67
|
-
} else if (h >= 180 && h < 240) {
|
|
68
|
-
g = x;
|
|
69
|
-
b = c;
|
|
70
|
-
} else if (h >= 240 && h < 300) {
|
|
71
|
-
r = x;
|
|
72
|
-
b = c;
|
|
73
|
-
} else if (h >= 300 && h < 360) {
|
|
74
|
-
r = c;
|
|
75
|
-
b = x;
|
|
76
|
-
}
|
|
77
|
-
const toHex = (n)=>{
|
|
78
|
-
const hex = Math.round((n + m) * 255).toString(16);
|
|
79
|
-
return hex.length === 1 ? '0' + hex : hex;
|
|
80
|
-
};
|
|
81
|
-
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
|
29
|
+
return Color(color).hex().toString();
|
|
82
30
|
}
|
|
83
31
|
const ThemeColorPickerField = ({ field, path })=>{
|
|
84
32
|
const { value, setValue } = useField({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/fields/ThemeColorPickerField.tsx"],"sourcesContent":["'use client'\n\nimport { useField } from '@payloadcms/ui'\nimport type { TextFieldClientComponent } from 'payload'\nimport { HexColorInput, HexColorPicker } from 'react-colorful'\nimport { useCallback, useEffect, useRef, useState } from 'react'\n\n// Import CSS for styling\nif (typeof window !== 'undefined') {\n // @ts-expect-error - Dynamic CSS import\n import('./ThemeColorPickerField.css').catch(() => {})\n}\n\nfunction resolveLocalizedValue(value: unknown, fallback: string) {\n if (typeof value === 'string') {\n return value\n }\n\n if (typeof value === 'object' && value !== null) {\n const localized = value as Record<string, unknown>\n const resolved = localized.en ?? localized.cs ?? localized['']\n if (typeof resolved === 'string') {\n return resolved\n }\n }\n\n return fallback\n}\n\n/**\n * Convert various color formats to HEX for the color picker\n */\nfunction toHex(color: string): string {\n if (!color) return '#000000'\n\n // Already hex\n if (color.startsWith('#')) return color\n\n // OKLCH format - extract hue and convert to approximate hex\n if (color.startsWith('oklch')) {\n // For now, return a default - proper conversion requires color-conversion library\n return '#3b82f6' // blue-500 as default\n }\n\n // HSL format\n if (color.startsWith('hsl')) {\n const regex = /hsl\\((\\d+),\\s*(\\d+)%,\\s*(\\d+)%\\)/\n const match = regex.exec(color)\n if (match) {\n const [, h, s, l] = match.map(Number)\n return hslToHex(h, s, l)\n }\n }\n\n return '#000000'\n}\n\n/**\n * Convert HSL to HEX\n */\nfunction hslToHex(h: number, s: number, l: number): string {\n s /= 100\n l /= 100\n\n const c = (1 - Math.abs(2 * l - 1)) * s\n const x = c * (1 - Math.abs(((h / 60) % 2) - 1))\n const m = l - c / 2\n\n let r = 0\n let g = 0\n let b = 0\n\n if (h >= 0 && h < 60) {\n r = c\n g = x\n } else if (h >= 60 && h < 120) {\n r = x\n g = c\n } else if (h >= 120 && h < 180) {\n g = c\n b = x\n } else if (h >= 180 && h < 240) {\n g = x\n b = c\n } else if (h >= 240 && h < 300) {\n r = x\n b = c\n } else if (h >= 300 && h < 360) {\n r = c\n b = x\n }\n\n const toHex = (n: number) => {\n const hex = Math.round((n + m) * 255).toString(16)\n return hex.length === 1 ? '0' + hex : hex\n }\n\n return `#${toHex(r)}${toHex(g)}${toHex(b)}`\n}\n\nconst ThemeColorPickerField: TextFieldClientComponent = ({ field, path }) => {\n const { value, setValue } = useField<string>({ path })\n const [localValue, setLocalValue] = useState(value || '')\n const [showPicker, setShowPicker] = useState(false)\n const [hexValue, setHexValue] = useState(toHex(value || ''))\n const pickerRef = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n setLocalValue(value || '')\n setHexValue(toHex(value || ''))\n }, [value])\n\n // Close picker when clicking outside\n useEffect(() => {\n function handleClickOutside(event: MouseEvent) {\n if (pickerRef.current && !pickerRef.current.contains(event.target as Node)) {\n setShowPicker(false)\n }\n }\n\n if (showPicker) {\n document.addEventListener('mousedown', handleClickOutside)\n return () => document.removeEventListener('mousedown', handleClickOutside)\n }\n }, [showPicker])\n\n const handleHexChange = useCallback(\n (hex: string) => {\n setHexValue(hex)\n setLocalValue(hex)\n setValue(hex)\n },\n [setValue],\n )\n\n const handleTextChange = useCallback(\n (nextValue: string) => {\n setLocalValue(nextValue)\n setValue(nextValue)\n setHexValue(toHex(nextValue))\n },\n [setValue],\n )\n\n const fieldName = path.split('.').pop() || ''\n const label = resolveLocalizedValue(field.label, fieldName)\n const description = resolveLocalizedValue(field.admin?.description, '')\n\n return (\n <div className=\"theme-color-picker-field\">\n <div className=\"field-header\">\n <label className=\"field-label\">{label}</label>\n {description && <div className=\"field-description\">{description}</div>}\n </div>\n\n <div className=\"color-picker-container\">\n <div className=\"color-input-row\">\n <button\n type=\"button\"\n className=\"color-swatch-btn\"\n style={{ backgroundColor: hexValue }}\n onClick={() => setShowPicker(!showPicker)}\n aria-label=\"Open color picker\"\n title={hexValue}\n />\n <input\n type=\"text\"\n value={localValue || ''}\n onChange={(event) => handleTextChange(event.target.value)}\n placeholder=\"oklch(...) or #hex\"\n className=\"color-text-input\"\n />\n </div>\n\n {showPicker && (\n <div ref={pickerRef} className=\"color-picker-popover\">\n <div className=\"picker-header\">\n <span className=\"picker-title\">Color Picker</span>\n <button\n type=\"button\"\n onClick={() => setShowPicker(false)}\n className=\"picker-close-btn\"\n aria-label=\"Close\"\n >\n ✕\n </button>\n </div>\n\n <HexColorPicker color={hexValue} onChange={handleHexChange} className=\"hex-picker\" />\n\n <div className=\"hex-input-row\">\n <HexColorInput\n color={hexValue}\n onChange={handleHexChange}\n prefixed\n placeholder=\"#000000\"\n className=\"hex-input\"\n />\n </div>\n\n <div className=\"color-swatches\">\n <div className=\"swatches-label\">Quick Colors</div>\n <div className=\"swatches-grid\">\n {[\n '#ef4444',\n '#f97316',\n '#f59e0b',\n '#84cc16',\n '#10b981',\n '#06b6d4',\n '#3b82f6',\n '#8b5cf6',\n '#ec4899',\n '#64748b',\n '#000000',\n '#ffffff',\n ].map((color) => (\n <button\n key={color}\n type=\"button\"\n onClick={() => handleHexChange(color)}\n className={`swatch-btn ${hexValue.toLowerCase() === color.toLowerCase() ? 'selected' : ''}`}\n style={{ backgroundColor: color }}\n aria-label={`Select ${color}`}\n title={color}\n />\n ))}\n </div>\n </div>\n </div>\n )}\n </div>\n </div>\n )\n}\n\nexport default ThemeColorPickerField\n"],"names":["useField","HexColorInput","HexColorPicker","useCallback","useEffect","useRef","useState","window","catch","resolveLocalizedValue","value","fallback","localized","resolved","en","cs","toHex","color","startsWith","regex","match","exec","h","s","l","map","Number","hslToHex","c","Math","abs","x","m","r","g","b","n","hex","round","toString","length","ThemeColorPickerField","field","path","setValue","localValue","setLocalValue","showPicker","setShowPicker","hexValue","setHexValue","pickerRef","handleClickOutside","event","current","contains","target","document","addEventListener","removeEventListener","handleHexChange","handleTextChange","nextValue","fieldName","split","pop","label","description","admin","div","className","button","type","style","backgroundColor","onClick","aria-label","title","input","onChange","placeholder","ref","span","prefixed","toLowerCase"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/fields/ThemeColorPickerField.tsx"],"sourcesContent":["'use client'\n\nimport { useField } from '@payloadcms/ui'\nimport Color from 'color'\nimport type { TextFieldClientComponent } from 'payload'\nimport { HexColorInput, HexColorPicker } from 'react-colorful'\nimport { useCallback, useEffect, useRef, useState } from 'react'\n\n// Import CSS for styling\nif (typeof window !== 'undefined') {\n // @ts-expect-error - Dynamic CSS import\n import('./ThemeColorPickerField.css').catch(() => {})\n}\n\nfunction resolveLocalizedValue(value: unknown, fallback: string) {\n if (typeof value === 'string') {\n return value\n }\n\n if (typeof value === 'object' && value !== null) {\n const localized = value as Record<string, unknown>\n const resolved = localized.en ?? localized.cs ?? localized['']\n if (typeof resolved === 'string') {\n return resolved\n }\n }\n\n return fallback\n}\n\n/**\n * Convert various color formats to HEX for the color picker\n */\nfunction toHex(color: string): string {\n if (!color) return '#000000'\n\n return Color(color).hex().toString()\n}\n\nconst ThemeColorPickerField: TextFieldClientComponent = ({ field, path }) => {\n const { value, setValue } = useField<string>({ path })\n const [localValue, setLocalValue] = useState(value || '')\n const [showPicker, setShowPicker] = useState(false)\n const [hexValue, setHexValue] = useState(toHex(value || ''))\n const pickerRef = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n setLocalValue(value || '')\n setHexValue(toHex(value || ''))\n }, [value])\n\n // Close picker when clicking outside\n useEffect(() => {\n function handleClickOutside(event: MouseEvent) {\n if (pickerRef.current && !pickerRef.current.contains(event.target as Node)) {\n setShowPicker(false)\n }\n }\n\n if (showPicker) {\n document.addEventListener('mousedown', handleClickOutside)\n return () => document.removeEventListener('mousedown', handleClickOutside)\n }\n }, [showPicker])\n\n const handleHexChange = useCallback(\n (hex: string) => {\n setHexValue(hex)\n setLocalValue(hex)\n setValue(hex)\n },\n [setValue],\n )\n\n const handleTextChange = useCallback(\n (nextValue: string) => {\n setLocalValue(nextValue)\n setValue(nextValue)\n setHexValue(toHex(nextValue))\n },\n [setValue],\n )\n\n const fieldName = path.split('.').pop() || ''\n const label = resolveLocalizedValue(field.label, fieldName)\n const description = resolveLocalizedValue(field.admin?.description, '')\n\n return (\n <div className=\"theme-color-picker-field\">\n <div className=\"field-header\">\n <label className=\"field-label\">{label}</label>\n {description && <div className=\"field-description\">{description}</div>}\n </div>\n\n <div className=\"color-picker-container\">\n <div className=\"color-input-row\">\n <button\n type=\"button\"\n className=\"color-swatch-btn\"\n style={{ backgroundColor: hexValue }}\n onClick={() => setShowPicker(!showPicker)}\n aria-label=\"Open color picker\"\n title={hexValue}\n />\n <input\n type=\"text\"\n value={localValue || ''}\n onChange={(event) => handleTextChange(event.target.value)}\n placeholder=\"oklch(...) or #hex\"\n className=\"color-text-input\"\n />\n </div>\n\n {showPicker && (\n <div ref={pickerRef} className=\"color-picker-popover\">\n <div className=\"picker-header\">\n <span className=\"picker-title\">Color Picker</span>\n <button\n type=\"button\"\n onClick={() => setShowPicker(false)}\n className=\"picker-close-btn\"\n aria-label=\"Close\"\n >\n ✕\n </button>\n </div>\n\n <HexColorPicker color={hexValue} onChange={handleHexChange} className=\"hex-picker\" />\n\n <div className=\"hex-input-row\">\n <HexColorInput\n color={hexValue}\n onChange={handleHexChange}\n prefixed\n placeholder=\"#000000\"\n className=\"hex-input\"\n />\n </div>\n\n <div className=\"color-swatches\">\n <div className=\"swatches-label\">Quick Colors</div>\n <div className=\"swatches-grid\">\n {[\n '#ef4444',\n '#f97316',\n '#f59e0b',\n '#84cc16',\n '#10b981',\n '#06b6d4',\n '#3b82f6',\n '#8b5cf6',\n '#ec4899',\n '#64748b',\n '#000000',\n '#ffffff',\n ].map((color) => (\n <button\n key={color}\n type=\"button\"\n onClick={() => handleHexChange(color)}\n className={`swatch-btn ${hexValue.toLowerCase() === color.toLowerCase() ? 'selected' : ''}`}\n style={{ backgroundColor: color }}\n aria-label={`Select ${color}`}\n title={color}\n />\n ))}\n </div>\n </div>\n </div>\n )}\n </div>\n </div>\n )\n}\n\nexport default ThemeColorPickerField\n"],"names":["useField","Color","HexColorInput","HexColorPicker","useCallback","useEffect","useRef","useState","window","catch","resolveLocalizedValue","value","fallback","localized","resolved","en","cs","toHex","color","hex","toString","ThemeColorPickerField","field","path","setValue","localValue","setLocalValue","showPicker","setShowPicker","hexValue","setHexValue","pickerRef","handleClickOutside","event","current","contains","target","document","addEventListener","removeEventListener","handleHexChange","handleTextChange","nextValue","fieldName","split","pop","label","description","admin","div","className","button","type","style","backgroundColor","onClick","aria-label","title","input","onChange","placeholder","ref","span","prefixed","map","toLowerCase"],"mappings":"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"}
|
|
@@ -195,12 +195,12 @@ export default function ThemeTokenSelectField(props) {
|
|
|
195
195
|
if (!explicitlyRequestedGlobal) {
|
|
196
196
|
try {
|
|
197
197
|
// Prefer custom.collectionSlug if provided, otherwise try the default standalone slug
|
|
198
|
-
const fallbackCollection = custom
|
|
198
|
+
const fallbackCollection = custom?.collectionSlug || 'appearance-settings';
|
|
199
199
|
const fallbackOpts = {
|
|
200
200
|
useGlobal: true,
|
|
201
201
|
collectionSlug: fallbackCollection,
|
|
202
202
|
tenantSlug: inferredTenant,
|
|
203
|
-
locale: custom
|
|
203
|
+
locale: custom?.locale ?? adminLang
|
|
204
204
|
};
|
|
205
205
|
const fallbackConfig = await fetchThemeConfiguration(fallbackOpts);
|
|
206
206
|
if (!isMounted) return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/fields/ThemeTokenSelectField.tsx"],"sourcesContent":["'use client'\n\nimport { useField } from '@payloadcms/ui'\nimport type { SelectFieldClientProps } from 'payload'\nimport { useCallback, useEffect, useMemo, useState } from 'react'\nimport { allThemePresets, fetchThemeConfiguration } from '../index.js'\nimport type { SiteThemeConfiguration } from '../payload-types.js'\nimport type { ThemePreset } from '../presets.js'\nimport type { FetchThemeConfigurationOptions } from '../types.js'\nimport { getAdminLanguage } from '../utils/getAdminLanguage.js'\nimport { inferTenant } from '../utils/inferTenant.js'\nimport { resolveThemeConfiguration } from '../utils/resolveThemeConfiguration.js'\n\ninterface ThemeColorOption {\n value: string\n label: string | { [key: string]: string | undefined }\n color: string\n description?: string\n}\n\nconst FALLBACK_TOKENS: ThemeColorOption[] = [\n {\n value: 'background',\n label: { en: 'Theme background', cs: 'Pozadí tématu' },\n color: 'var(--background)',\n },\n { value: 'card', label: { en: 'Card background', cs: 'Pozadí karty' }, color: 'var(--card)' },\n { value: 'muted', label: { en: 'Muted surface', cs: 'Tlumený povrch' }, color: 'var(--muted)' },\n {\n value: 'accent',\n label: { en: 'Accent surface', cs: 'Akcentní povrch' },\n color: 'var(--accent)',\n },\n {\n value: 'secondary',\n label: { en: 'Secondary surface', cs: 'Sekundární povrch' },\n color: 'var(--secondary)',\n },\n {\n value: 'primary',\n label: { en: 'Primary surface', cs: 'Primární povrch' },\n color: 'var(--primary)',\n },\n]\n\n// Use plugin-provided fetch helper which supports collection/global and options\n// This will use `collectionSlug`, `useGlobal`, tenant, locale, depth, draft, etc.\n// Accept fetch options from field.admin.custom to allow overrides in different setups.\n\nfunction buildOptionsFromConfiguration(\n configuration: SiteThemeConfiguration | Record<string, unknown> | null,\n themePresets: ThemePreset[],\n): ThemeColorOption[] {\n if (!configuration) {\n return FALLBACK_TOKENS\n }\n\n const resolved = resolveThemeConfiguration(configuration)\n const lightMode = resolved.lightMode ?? themePresets[0]?.lightMode ?? {}\n const orderedKeys: string[] = [\n 'background',\n 'card',\n 'muted',\n 'accent',\n 'secondary',\n 'primary',\n 'popover',\n ]\n\n const typedLightMode = lightMode as Record<string, string | null | undefined>\n\n const tokens = orderedKeys\n .map((key) => {\n const value = typedLightMode?.[key]\n if (typeof value !== 'string' || value.trim().length === 0) {\n return null\n }\n\n const labelMap: Record<string, { en: string; cs: string }> = {\n background: { en: 'Theme background', cs: 'Pozadí tématu' },\n card: { en: 'Card background', cs: 'Pozadí karty' },\n muted: { en: 'Muted surface', cs: 'Tlumený povrch' },\n accent: { en: 'Accent surface', cs: 'Akcentní povrch' },\n secondary: { en: 'Secondary surface', cs: 'Sekundární povrch' },\n primary: { en: 'Primary surface', cs: 'Primární povrch' },\n popover: { en: 'Popover surface', cs: 'Popover povrch' },\n }\n\n return {\n value: key,\n label: labelMap[key] ?? { en: key, cs: key },\n color: value,\n }\n })\n .filter((token): token is NonNullable<typeof token> => token !== null)\n\n return tokens.length > 0 ? tokens : FALLBACK_TOKENS\n}\n\nexport default function ThemeTokenSelectField(props: SelectFieldClientProps) {\n const { path, field } = props\n const { value, setValue } = useField<string>({ path })\n // Try to read themeConfiguration from the active form (Site Settings) first\n const { value: formThemeConfiguration } = useField<SiteThemeConfiguration | null>({\n path: 'themeConfiguration',\n })\n\n // Read tenant from the current form (sibling data) where present.\n // Prefer `tenant` field as it is populated correctly in most setups.\n const { value: formTenant } = useField<any>({ path: 'tenant' })\n\n const [options, setOptions] = useState<ThemeColorOption[]>(FALLBACK_TOKENS)\n const selectedValue = value || 'background'\n\n // Get themePresets from admin.custom or use defaults\n const themePresets = useMemo(() => {\n const customPresets = (field.admin?.custom as { themePresets?: ThemePreset[] })?.themePresets\n return customPresets && customPresets.length > 0 ? customPresets : allThemePresets\n }, [field.admin?.custom])\n\n useEffect(() => {\n // If the active form contains themeConfiguration (e.g., editing Site Settings), prefer it\n if (formThemeConfiguration) {\n setOptions(buildOptionsFromConfiguration(formThemeConfiguration, themePresets))\n return\n }\n\n let isMounted = true\n\n // Allow fields to override fetch options via admin.custom\n type CustomAdmin = {\n fetchThemeConfigurationOptions?: FetchThemeConfigurationOptions\n fetchOptions?: FetchThemeConfigurationOptions\n collectionSlug?: string\n useGlobal?: boolean\n tenantSlug?: string\n depth?: number\n locale?: string\n draft?: boolean\n queryParams?: Record<string, unknown>\n }\n\n const custom = field.admin?.custom as unknown as CustomAdmin\n\n // Prefer tenant ID from the current form (`formTenant`) first since editor fills the relation id.\n // If the relation is an object, prefer `id` over `slug` to avoid passing a human-readable slug when an id is available.\n // Then respect an explicit `admin.custom.tenantSlug` override, otherwise fall back to other heuristics.\n const tenantFromForm = (() => {\n if (typeof formTenant === 'string' && formTenant.trim()) return formTenant\n if (formTenant && typeof formTenant === 'object') {\n // Prefer id first\n return (formTenant.id ?? formTenant.slug ?? formTenant.value) as string | undefined\n }\n return undefined\n })()\n\n const inferredTenant = tenantFromForm ?? custom?.tenantSlug ?? inferTenant()\n\n // Determine admin language to pass as `locale` to fetch, if not provided\n const adminLang = getAdminLanguage()\n\n // Normalize fetch options so that even when callers provide an empty object (\"{}\"),\n // we still ensure `tenantSlug` and `locale` are set to sensible defaults (inferred/form/adminLang).\n const rawFetchOpts =\n custom?.fetchThemeConfigurationOptions ??\n custom?.fetchOptions ??\n (custom?.collectionSlug || typeof custom?.useGlobal !== 'undefined'\n ? ({\n collectionSlug: custom.collectionSlug,\n useGlobal: custom.useGlobal,\n depth: custom.depth,\n locale: custom.locale,\n draft: custom.draft,\n queryParams: custom.queryParams,\n } as unknown as FetchThemeConfigurationOptions)\n : undefined)\n\n // Always build a fetch options object so we can inject sensible defaults (tenantSlug, locale)\n // even when callers passed an empty object or no options at all.\n const fetchOpts: FetchThemeConfigurationOptions = {\n ...(rawFetchOpts ?? {}),\n tenantSlug: rawFetchOpts?.tenantSlug ?? inferredTenant,\n locale: rawFetchOpts?.locale ?? adminLang,\n }\n\n fetchThemeConfiguration(fetchOpts).then(async (configuration) => {\n if (!isMounted) return\n if (configuration) {\n setOptions(buildOptionsFromConfiguration(configuration, themePresets))\n return\n }\n\n // If nothing found and fetchOpts didn't explicitly request global, try fallback to global\n // This helps in setups where plugin created a standalone global (default slug 'appearance-settings')\n const explicitlyRequestedGlobal = !!(\n (fetchOpts as FetchThemeConfigurationOptions | undefined)?.useGlobal === true ||\n (fetchOpts as FetchThemeConfigurationOptions | undefined)?.collectionSlug ===\n 'appearance-settings'\n )\n\n if (!explicitlyRequestedGlobal) {\n try {\n // Prefer custom.collectionSlug if provided, otherwise try the default standalone slug\n const fallbackCollection = (custom && custom.collectionSlug) || 'appearance-settings'\n const fallbackOpts: FetchThemeConfigurationOptions = {\n useGlobal: true,\n collectionSlug: fallbackCollection,\n tenantSlug: inferredTenant,\n locale: custom.locale ?? adminLang,\n }\n const fallbackConfig = await fetchThemeConfiguration(fallbackOpts)\n if (!isMounted) return\n if (fallbackConfig) {\n // Found theme config in global, use it\n setOptions(buildOptionsFromConfiguration(fallbackConfig, themePresets))\n return\n }\n } catch (e) {\n console.warn('[ThemeTokenSelectField] Fallback global fetch failed:', e)\n }\n }\n\n // final fallback: use empty tokens\n setOptions(buildOptionsFromConfiguration(configuration, themePresets))\n })\n\n return () => {\n isMounted = false\n }\n }, [themePresets, field.admin?.custom, formThemeConfiguration, formTenant])\n\n const handleSelect = useCallback(\n (nextValue: string) => {\n setValue(nextValue)\n },\n [setValue],\n )\n\n // Make admin language reactive so switching admin UI language updates labels\n const initialAdminLang = getAdminLanguage()\n const [adminLang, setAdminLang] = useState<string>(initialAdminLang)\n\n useEffect(() => {\n if (typeof document === 'undefined' || !('MutationObserver' in window)) return\n const el = document.documentElement\n const obs = new MutationObserver(() => {\n const next = getAdminLanguage()\n if (next !== adminLang) setAdminLang(next)\n })\n obs.observe(el, { attributes: true, attributeFilter: ['lang'] })\n return () => obs.disconnect()\n }, [adminLang])\n\n const label =\n typeof field.label === 'string'\n ? field.label\n : (field.label && (field.label as Record<string, string>)[adminLang]) ||\n field.label?.en ||\n field.label?.cs ||\n ''\n\n let description = ''\n if (typeof field.admin?.description === 'string') {\n description = field.admin.description\n } else if (field.admin?.description && typeof field.admin.description === 'object') {\n description =\n (field.admin.description as Record<string, string>)[adminLang] ||\n (field.admin.description as Record<string, string>).en ||\n (field.admin.description as Record<string, string>).cs ||\n ''\n }\n\n // Helper function to get label text from localized or string label\n const getOptionLabel = (option: ThemeColorOption): string => {\n if (typeof option.label === 'string') {\n return option.label\n }\n // Prefer current admin language, fallback to English/Czech, then any available language\n return (\n (option.label as Record<string, string>)[adminLang] ||\n option.label.en ||\n option.label.cs ||\n Object.values(option.label)[0] ||\n option.value\n )\n }\n\n // Resolve CSS variable colors (e.g., 'var(--primary)') to their computed values when possible\n const resolveCssColor = (color: string): string => {\n if (typeof window === 'undefined' || !color || !color.trim().startsWith('var(')) {\n return color\n }\n\n try {\n const match = color.trim().match(/var\\((--[^)]+)\\)/)\n if (!match) return color\n const varName = match[1]\n const computed = getComputedStyle(document.documentElement).getPropertyValue(varName).trim()\n return computed || color\n } catch (e) {\n return color\n }\n }\n\n return (\n <div className=\"field-type theme-token-select\">\n {label && (\n <label\n className=\"field-label\"\n htmlFor={path}\n style={{ display: 'block', marginBottom: '8px' }}\n >\n {label}\n {field.required && <span className=\"required\">*</span>}\n </label>\n )}\n\n {description && (\n <div\n className=\"field-description\"\n style={{ marginBottom: '12px', fontSize: '13px', color: 'var(--theme-elevation-500)' }}\n >\n {description}\n </div>\n )}\n\n <div\n className=\"token-grid\"\n style={{\n display: 'grid',\n gridTemplateColumns: 'repeat(auto-fill, minmax(140px, 1fr))',\n gap: '10px',\n }}\n >\n {options.map((option) => {\n const isActive = option.value === selectedValue\n return (\n <button\n type=\"button\"\n key={option.value}\n onClick={() => handleSelect(option.value)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '10px',\n padding: '10px 12px',\n borderRadius: '10px',\n border: isActive\n ? '2px solid var(--theme-success-500)'\n : '1px solid var(--theme-elevation-150)',\n backgroundColor: 'var(--theme-elevation-0)',\n boxShadow: isActive\n ? '0 10px 20px -10px rgba(59, 130, 246, 0.4)'\n : '0 1px 2px rgba(15, 23, 42, 0.08)',\n cursor: 'pointer',\n transition: 'border-color 0.2s ease, box-shadow 0.2s ease',\n }}\n >\n <span\n aria-hidden\n style={{\n width: '32px',\n height: '32px',\n borderRadius: '8px',\n border: '1px solid rgba(15, 23, 42, 0.08)',\n backgroundColor: resolveCssColor(option.color),\n flexShrink: 0,\n }}\n />\n <span\n style={{ fontSize: '13px', fontWeight: 600, color: 'var(--theme-elevation-800)' }}\n >\n {getOptionLabel(option)}\n </span>\n </button>\n )\n })}\n </div>\n\n <select\n id={path}\n value={selectedValue}\n onChange={(event) => handleSelect(event.target.value)}\n style={{ display: 'none' }}\n >\n {options.map((option) => (\n <option key={option.value} value={option.value}>\n {getOptionLabel(option)}\n </option>\n ))}\n </select>\n </div>\n )\n}\n"],"names":["useField","useCallback","useEffect","useMemo","useState","allThemePresets","fetchThemeConfiguration","getAdminLanguage","inferTenant","resolveThemeConfiguration","FALLBACK_TOKENS","value","label","en","cs","color","buildOptionsFromConfiguration","configuration","themePresets","resolved","lightMode","orderedKeys","typedLightMode","tokens","map","key","trim","length","labelMap","background","card","muted","accent","secondary","primary","popover","filter","token","ThemeTokenSelectField","props","path","field","setValue","formThemeConfiguration","formTenant","options","setOptions","selectedValue","customPresets","admin","custom","isMounted","tenantFromForm","id","slug","undefined","inferredTenant","tenantSlug","adminLang","rawFetchOpts","fetchThemeConfigurationOptions","fetchOptions","collectionSlug","useGlobal","depth","locale","draft","queryParams","fetchOpts","then","explicitlyRequestedGlobal","fallbackCollection","fallbackOpts","fallbackConfig","e","console","warn","handleSelect","nextValue","initialAdminLang","setAdminLang","document","window","el","documentElement","obs","MutationObserver","next","observe","attributes","attributeFilter","disconnect","description","getOptionLabel","option","Object","values","resolveCssColor","startsWith","match","varName","computed","getComputedStyle","getPropertyValue","div","className","htmlFor","style","display","marginBottom","required","span","fontSize","gridTemplateColumns","gap","isActive","button","type","onClick","alignItems","padding","borderRadius","border","backgroundColor","boxShadow","cursor","transition","aria-hidden","width","height","flexShrink","fontWeight","select","onChange","event","target"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/fields/ThemeTokenSelectField.tsx"],"sourcesContent":["'use client'\n\nimport { useField } from '@payloadcms/ui'\nimport type { SelectFieldClientProps } from 'payload'\nimport { useCallback, useEffect, useMemo, useState } from 'react'\nimport { allThemePresets, fetchThemeConfiguration } from '../index.js'\nimport type { SiteThemeConfiguration } from '../payload-types.js'\nimport type { ThemePreset } from '../presets.js'\nimport type { FetchThemeConfigurationOptions } from '../types.js'\nimport { getAdminLanguage } from '../utils/getAdminLanguage.js'\nimport { inferTenant } from '../utils/inferTenant.js'\nimport { resolveThemeConfiguration } from '../utils/resolveThemeConfiguration.js'\n\ninterface ThemeColorOption {\n value: string\n label: string | { [key: string]: string | undefined }\n color: string\n description?: string\n}\n\nconst FALLBACK_TOKENS: ThemeColorOption[] = [\n {\n value: 'background',\n label: { en: 'Theme background', cs: 'Pozadí tématu' },\n color: 'var(--background)',\n },\n { value: 'card', label: { en: 'Card background', cs: 'Pozadí karty' }, color: 'var(--card)' },\n { value: 'muted', label: { en: 'Muted surface', cs: 'Tlumený povrch' }, color: 'var(--muted)' },\n {\n value: 'accent',\n label: { en: 'Accent surface', cs: 'Akcentní povrch' },\n color: 'var(--accent)',\n },\n {\n value: 'secondary',\n label: { en: 'Secondary surface', cs: 'Sekundární povrch' },\n color: 'var(--secondary)',\n },\n {\n value: 'primary',\n label: { en: 'Primary surface', cs: 'Primární povrch' },\n color: 'var(--primary)',\n },\n]\n\n// Use plugin-provided fetch helper which supports collection/global and options\n// This will use `collectionSlug`, `useGlobal`, tenant, locale, depth, draft, etc.\n// Accept fetch options from field.admin.custom to allow overrides in different setups.\n\nfunction buildOptionsFromConfiguration(\n configuration: SiteThemeConfiguration | Record<string, unknown> | null,\n themePresets: ThemePreset[],\n): ThemeColorOption[] {\n if (!configuration) {\n return FALLBACK_TOKENS\n }\n\n const resolved = resolveThemeConfiguration(configuration)\n const lightMode = resolved.lightMode ?? themePresets[0]?.lightMode ?? {}\n const orderedKeys: string[] = [\n 'background',\n 'card',\n 'muted',\n 'accent',\n 'secondary',\n 'primary',\n 'popover',\n ]\n\n const typedLightMode = lightMode as Record<string, string | null | undefined>\n\n const tokens = orderedKeys\n .map((key) => {\n const value = typedLightMode?.[key]\n if (typeof value !== 'string' || value.trim().length === 0) {\n return null\n }\n\n const labelMap: Record<string, { en: string; cs: string }> = {\n background: { en: 'Theme background', cs: 'Pozadí tématu' },\n card: { en: 'Card background', cs: 'Pozadí karty' },\n muted: { en: 'Muted surface', cs: 'Tlumený povrch' },\n accent: { en: 'Accent surface', cs: 'Akcentní povrch' },\n secondary: { en: 'Secondary surface', cs: 'Sekundární povrch' },\n primary: { en: 'Primary surface', cs: 'Primární povrch' },\n popover: { en: 'Popover surface', cs: 'Popover povrch' },\n }\n\n return {\n value: key,\n label: labelMap[key] ?? { en: key, cs: key },\n color: value,\n }\n })\n .filter((token): token is NonNullable<typeof token> => token !== null)\n\n return tokens.length > 0 ? tokens : FALLBACK_TOKENS\n}\n\nexport default function ThemeTokenSelectField(props: SelectFieldClientProps) {\n const { path, field } = props\n const { value, setValue } = useField<string>({ path })\n // Try to read themeConfiguration from the active form (Site Settings) first\n const { value: formThemeConfiguration } = useField<SiteThemeConfiguration | null>({\n path: 'themeConfiguration',\n })\n\n // Read tenant from the current form (sibling data) where present.\n // Prefer `tenant` field as it is populated correctly in most setups.\n const { value: formTenant } = useField<any>({ path: 'tenant' })\n\n const [options, setOptions] = useState<ThemeColorOption[]>(FALLBACK_TOKENS)\n const selectedValue = value || 'background'\n\n // Get themePresets from admin.custom or use defaults\n const themePresets = useMemo(() => {\n const customPresets = (field.admin?.custom as { themePresets?: ThemePreset[] })?.themePresets\n return customPresets && customPresets.length > 0 ? customPresets : allThemePresets\n }, [field.admin?.custom])\n\n useEffect(() => {\n // If the active form contains themeConfiguration (e.g., editing Site Settings), prefer it\n if (formThemeConfiguration) {\n setOptions(buildOptionsFromConfiguration(formThemeConfiguration, themePresets))\n return\n }\n\n let isMounted = true\n\n // Allow fields to override fetch options via admin.custom\n type CustomAdmin = {\n fetchThemeConfigurationOptions?: FetchThemeConfigurationOptions\n fetchOptions?: FetchThemeConfigurationOptions\n collectionSlug?: string\n useGlobal?: boolean\n tenantSlug?: string\n depth?: number\n locale?: string\n draft?: boolean\n queryParams?: Record<string, unknown>\n }\n\n const custom = field.admin?.custom as unknown as CustomAdmin\n\n // Prefer tenant ID from the current form (`formTenant`) first since editor fills the relation id.\n // If the relation is an object, prefer `id` over `slug` to avoid passing a human-readable slug when an id is available.\n // Then respect an explicit `admin.custom.tenantSlug` override, otherwise fall back to other heuristics.\n const tenantFromForm = (() => {\n if (typeof formTenant === 'string' && formTenant.trim()) return formTenant\n if (formTenant && typeof formTenant === 'object') {\n // Prefer id first\n return (formTenant.id ?? formTenant.slug ?? formTenant.value) as string | undefined\n }\n return undefined\n })()\n\n const inferredTenant = tenantFromForm ?? custom?.tenantSlug ?? inferTenant()\n\n // Determine admin language to pass as `locale` to fetch, if not provided\n const adminLang = getAdminLanguage()\n\n // Normalize fetch options so that even when callers provide an empty object (\"{}\"),\n // we still ensure `tenantSlug` and `locale` are set to sensible defaults (inferred/form/adminLang).\n const rawFetchOpts =\n custom?.fetchThemeConfigurationOptions ??\n custom?.fetchOptions ??\n (custom?.collectionSlug || typeof custom?.useGlobal !== 'undefined'\n ? ({\n collectionSlug: custom.collectionSlug,\n useGlobal: custom.useGlobal,\n depth: custom.depth,\n locale: custom.locale,\n draft: custom.draft,\n queryParams: custom.queryParams,\n } as unknown as FetchThemeConfigurationOptions)\n : undefined)\n\n // Always build a fetch options object so we can inject sensible defaults (tenantSlug, locale)\n // even when callers passed an empty object or no options at all.\n const fetchOpts: FetchThemeConfigurationOptions = {\n ...(rawFetchOpts ?? {}),\n tenantSlug: rawFetchOpts?.tenantSlug ?? inferredTenant,\n locale: rawFetchOpts?.locale ?? adminLang,\n }\n\n fetchThemeConfiguration(fetchOpts).then(async (configuration) => {\n if (!isMounted) return\n if (configuration) {\n setOptions(buildOptionsFromConfiguration(configuration, themePresets))\n return\n }\n\n // If nothing found and fetchOpts didn't explicitly request global, try fallback to global\n // This helps in setups where plugin created a standalone global (default slug 'appearance-settings')\n const explicitlyRequestedGlobal = !!(\n (fetchOpts as FetchThemeConfigurationOptions | undefined)?.useGlobal === true ||\n (fetchOpts as FetchThemeConfigurationOptions | undefined)?.collectionSlug ===\n 'appearance-settings'\n )\n\n if (!explicitlyRequestedGlobal) {\n try {\n // Prefer custom.collectionSlug if provided, otherwise try the default standalone slug\n const fallbackCollection = custom?.collectionSlug || 'appearance-settings'\n const fallbackOpts: FetchThemeConfigurationOptions = {\n useGlobal: true,\n collectionSlug: fallbackCollection,\n tenantSlug: inferredTenant,\n locale: custom?.locale ?? adminLang,\n }\n const fallbackConfig = await fetchThemeConfiguration(fallbackOpts)\n if (!isMounted) return\n if (fallbackConfig) {\n // Found theme config in global, use it\n setOptions(buildOptionsFromConfiguration(fallbackConfig, themePresets))\n return\n }\n } catch (e) {\n console.warn('[ThemeTokenSelectField] Fallback global fetch failed:', e)\n }\n }\n\n // final fallback: use empty tokens\n setOptions(buildOptionsFromConfiguration(configuration, themePresets))\n })\n\n return () => {\n isMounted = false\n }\n }, [themePresets, field.admin?.custom, formThemeConfiguration, formTenant])\n\n const handleSelect = useCallback(\n (nextValue: string) => {\n setValue(nextValue)\n },\n [setValue],\n )\n\n // Make admin language reactive so switching admin UI language updates labels\n const initialAdminLang = getAdminLanguage()\n const [adminLang, setAdminLang] = useState<string>(initialAdminLang)\n\n useEffect(() => {\n if (typeof document === 'undefined' || !('MutationObserver' in window)) return\n const el = document.documentElement\n const obs = new MutationObserver(() => {\n const next = getAdminLanguage()\n if (next !== adminLang) setAdminLang(next)\n })\n obs.observe(el, { attributes: true, attributeFilter: ['lang'] })\n return () => obs.disconnect()\n }, [adminLang])\n\n const label =\n typeof field.label === 'string'\n ? field.label\n : (field.label && (field.label as Record<string, string>)[adminLang]) ||\n field.label?.en ||\n field.label?.cs ||\n ''\n\n let description = ''\n if (typeof field.admin?.description === 'string') {\n description = field.admin.description\n } else if (field.admin?.description && typeof field.admin.description === 'object') {\n description =\n (field.admin.description as Record<string, string>)[adminLang] ||\n (field.admin.description as Record<string, string>).en ||\n (field.admin.description as Record<string, string>).cs ||\n ''\n }\n\n // Helper function to get label text from localized or string label\n const getOptionLabel = (option: ThemeColorOption): string => {\n if (typeof option.label === 'string') {\n return option.label\n }\n // Prefer current admin language, fallback to English/Czech, then any available language\n return (\n (option.label as Record<string, string>)[adminLang] ||\n option.label.en ||\n option.label.cs ||\n Object.values(option.label)[0] ||\n option.value\n )\n }\n\n // Resolve CSS variable colors (e.g., 'var(--primary)') to their computed values when possible\n const resolveCssColor = (color: string): string => {\n if (typeof window === 'undefined' || !color || !color.trim().startsWith('var(')) {\n return color\n }\n\n try {\n const match = color.trim().match(/var\\((--[^)]+)\\)/)\n if (!match) return color\n const varName = match[1]\n const computed = getComputedStyle(document.documentElement).getPropertyValue(varName).trim()\n return computed || color\n } catch (e) {\n return color\n }\n }\n\n return (\n <div className=\"field-type theme-token-select\">\n {label && (\n <label\n className=\"field-label\"\n htmlFor={path}\n style={{ display: 'block', marginBottom: '8px' }}\n >\n {label}\n {field.required && <span className=\"required\">*</span>}\n </label>\n )}\n\n {description && (\n <div\n className=\"field-description\"\n style={{ marginBottom: '12px', fontSize: '13px', color: 'var(--theme-elevation-500)' }}\n >\n {description}\n </div>\n )}\n\n <div\n className=\"token-grid\"\n style={{\n display: 'grid',\n gridTemplateColumns: 'repeat(auto-fill, minmax(140px, 1fr))',\n gap: '10px',\n }}\n >\n {options.map((option) => {\n const isActive = option.value === selectedValue\n return (\n <button\n type=\"button\"\n key={option.value}\n onClick={() => handleSelect(option.value)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '10px',\n padding: '10px 12px',\n borderRadius: '10px',\n border: isActive\n ? '2px solid var(--theme-success-500)'\n : '1px solid var(--theme-elevation-150)',\n backgroundColor: 'var(--theme-elevation-0)',\n boxShadow: isActive\n ? '0 10px 20px -10px rgba(59, 130, 246, 0.4)'\n : '0 1px 2px rgba(15, 23, 42, 0.08)',\n cursor: 'pointer',\n transition: 'border-color 0.2s ease, box-shadow 0.2s ease',\n }}\n >\n <span\n aria-hidden\n style={{\n width: '32px',\n height: '32px',\n borderRadius: '8px',\n border: '1px solid rgba(15, 23, 42, 0.08)',\n backgroundColor: resolveCssColor(option.color),\n flexShrink: 0,\n }}\n />\n <span\n style={{ fontSize: '13px', fontWeight: 600, color: 'var(--theme-elevation-800)' }}\n >\n {getOptionLabel(option)}\n </span>\n </button>\n )\n })}\n </div>\n\n <select\n id={path}\n value={selectedValue}\n onChange={(event) => handleSelect(event.target.value)}\n style={{ display: 'none' }}\n >\n {options.map((option) => (\n <option key={option.value} value={option.value}>\n {getOptionLabel(option)}\n </option>\n ))}\n </select>\n </div>\n )\n}\n"],"names":["useField","useCallback","useEffect","useMemo","useState","allThemePresets","fetchThemeConfiguration","getAdminLanguage","inferTenant","resolveThemeConfiguration","FALLBACK_TOKENS","value","label","en","cs","color","buildOptionsFromConfiguration","configuration","themePresets","resolved","lightMode","orderedKeys","typedLightMode","tokens","map","key","trim","length","labelMap","background","card","muted","accent","secondary","primary","popover","filter","token","ThemeTokenSelectField","props","path","field","setValue","formThemeConfiguration","formTenant","options","setOptions","selectedValue","customPresets","admin","custom","isMounted","tenantFromForm","id","slug","undefined","inferredTenant","tenantSlug","adminLang","rawFetchOpts","fetchThemeConfigurationOptions","fetchOptions","collectionSlug","useGlobal","depth","locale","draft","queryParams","fetchOpts","then","explicitlyRequestedGlobal","fallbackCollection","fallbackOpts","fallbackConfig","e","console","warn","handleSelect","nextValue","initialAdminLang","setAdminLang","document","window","el","documentElement","obs","MutationObserver","next","observe","attributes","attributeFilter","disconnect","description","getOptionLabel","option","Object","values","resolveCssColor","startsWith","match","varName","computed","getComputedStyle","getPropertyValue","div","className","htmlFor","style","display","marginBottom","required","span","fontSize","gridTemplateColumns","gap","isActive","button","type","onClick","alignItems","padding","borderRadius","border","backgroundColor","boxShadow","cursor","transition","aria-hidden","width","height","flexShrink","fontWeight","select","onChange","event","target"],"mappings":"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"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiD,MAAM,EAAa,MAAM,SAAS,CAAA;AAG/F,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAG/C,OAAO,KAAK,EAAE,8BAA8B,EAAE,4BAA4B,EAAE,MAAM,YAAY,CAAA;AAqG9F,eAAO,MAAM,qBAAqB,GAAI,UAAS,4BAAiC,KAAG,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiD,MAAM,EAAa,MAAM,SAAS,CAAA;AAG/F,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAG/C,OAAO,KAAK,EAAE,8BAA8B,EAAE,4BAA4B,EAAE,MAAM,YAAY,CAAA;AAqG9F,eAAO,MAAM,qBAAqB,GAAI,UAAS,4BAAiC,KAAG,MAsMlF,CAAA;AAED,KAAK,iBAAiB,GAAG,MAAM,GAAG,8BAA8B,CAAA;AAEhE,eAAO,MAAM,uBAAuB,GAClC,UAAU,iBAAiB,KAC1B,OAAO,CAAC,sBAAsB,GAAG,IAAI,CA6EvC,CAAA;AAED,eAAO,MAAM,cAAc,GAAI,WAAW,MAAM,KAAG,WAAW,GAAG,IAEhE,CAAA;AAED,eAAO,MAAM,wBAAwB,QAAO,WAAW,EAEtD,CAAA;AAED,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AACnE,YAAY,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AACtE,YAAY,EAAE,QAAQ,EAAE,MAAM,qCAAqC,CAAA;AACnE,OAAO,EACL,oBAAoB,EACpB,uBAAuB,EACvB,2BAA2B,GAC5B,MAAM,uBAAuB,CAAA;AAC9B,YAAY,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AACnF,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACxB,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,iCAAiC,CAAA;AACxC,YAAY,EAAE,4BAA4B,EAAE,8BAA8B,EAAE,MAAM,YAAY,CAAA;AAC9F,OAAO,EACL,2BAA2B,EAC3B,yBAAyB,GAC1B,MAAM,sCAAsC,CAAA;AAC7C,YAAY,EAAE,0BAA0B,EAAE,MAAM,sCAAsC,CAAA;AACtF,OAAO,EAAE,sBAAsB,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACzE,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACxE,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAA;AAGvE,OAAO,EACL,gBAAgB,IAAI,iBAAiB,EACrC,oBAAoB,GACrB,MAAM,6BAA6B,CAAA;AACpC,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAEhF,YAAY,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAA;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAA;AAG1D,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,iBAAiB,EACjB,aAAa,EACb,eAAe,GAChB,MAAM,4BAA4B,CAAA;AAMnC,eAAO,MAAM,qBAAqB,aArVa,4BAA4B,KAAQ,MAqVzB,CAAA;AAC1D,oDAAoD;AACpD,eAAO,MAAM,wBAAwB,aAvVU,4BAA4B,KAAQ,MAuVtB,CAAA;AAG7D,OAAO,EACL,YAAY,EACZ,eAAe,EACf,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,mBAAmB,CAAA;AAE1B,eAAe,qBAAqB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -155,6 +155,27 @@ export const themeManagementPlugin = (options = {})=>{
|
|
|
155
155
|
hooks: {
|
|
156
156
|
beforeChange: [
|
|
157
157
|
beforeChangeHook
|
|
158
|
+
],
|
|
159
|
+
afterChange: [
|
|
160
|
+
async ({ doc, req })=>{
|
|
161
|
+
// Invalidate cache after appearance settings change
|
|
162
|
+
if (!req?.context?.disableRevalidate) {
|
|
163
|
+
try {
|
|
164
|
+
const cacheTag = `global_${standaloneCollectionSlug}`;
|
|
165
|
+
// Import revalidateTag dynamically to avoid issues in non-Next.js environments
|
|
166
|
+
const { revalidateTag } = await import('next/cache');
|
|
167
|
+
revalidateTag(cacheTag);
|
|
168
|
+
if (enableLogging) {
|
|
169
|
+
req.payload.logger.info(`🎨 Theme Management Plugin: cache invalidated for tag "${cacheTag}"`);
|
|
170
|
+
}
|
|
171
|
+
} catch (error) {
|
|
172
|
+
if (enableLogging) {
|
|
173
|
+
req.payload.logger.error('🎨 Theme Management Plugin: cache invalidation failed:', error);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return doc;
|
|
178
|
+
}
|
|
158
179
|
]
|
|
159
180
|
}
|
|
160
181
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { CollectionConfig, Config, Field, GlobalConfig, Plugin, TabsField } from 'payload'\nimport { createThemeConfigurationField } from './fields/themeConfigurationField.js'\nimport type { ThemeTab } from './fields/themeConfigurationField.js'\nimport type { SiteThemeConfiguration } from './payload-types.js'\nimport type { ThemePreset } from './presets.js'\nimport { allThemePresets } from './presets.js'\nimport { getTranslations, translations } from './translations.js'\nimport type { FetchThemeConfigurationOptions, ThemeManagementPluginOptions } from './types.js'\n\nconst THEME_FIELD_NAME = 'themeConfiguration'\n\n/**\n * Removes existing theme configuration from a group field (legacy)\n */\nconst removeExistingThemeField = (fields: Field[] = []): Field[] =>\n fields.filter((field) => {\n const candidate = field as { name?: unknown }\n return candidate?.name !== THEME_FIELD_NAME\n })\n\n/**\n * Finds the tabs field in the collection fields array\n */\nconst findTabsField = (fields: Field[] = []): TabsField | null => {\n for (const field of fields) {\n if (field.type === 'tabs') {\n return field as TabsField\n }\n }\n return null\n}\n\n/**\n * Removes existing Appearance Settings tab if it exists\n */\nconst removeExistingThemeTab = (\n tabs: NonNullable<TabsField['tabs']>,\n): NonNullable<TabsField['tabs']> => {\n const knownLabels = Object.values(translations).map((t) => t.tabLabel)\n return tabs.filter((tab) => {\n // Normalize label to string (support localized object or plain string)\n let labelValues: string[] = []\n if (typeof tab.label === 'object' && tab.label !== null) {\n labelValues = Object.values(tab.label as Record<string, string>)\n } else if (typeof tab.label === 'string') {\n labelValues = [tab.label]\n }\n\n // If any of the label values match a known plugin tab label, remove it\n const matchesKnown = labelValues.some((v) => knownLabels.includes(v))\n\n return !matchesKnown\n })\n}\n\n/**\n * Injects theme tab into existing tabs field\n */\nconst injectThemeTab = (\n fields: Field[] | undefined,\n themeTab: ThemeTab,\n enableLogging: boolean,\n): Field[] => {\n // First, remove any legacy theme field (group-based)\n const sanitizedFields = removeExistingThemeField(fields ?? [])\n\n // Find the tabs field\n const tabsField = findTabsField(sanitizedFields)\n\n if (!tabsField || !tabsField.tabs) {\n if (enableLogging) {\n console.warn(\n '🎨 Theme Management Plugin: No tabs field found. Creating a new tabs structure.',\n )\n }\n\n // If no tabs exist, create a basic tabs structure with just the theme tab\n const newTabsField: TabsField = {\n type: 'tabs',\n tabs: [themeTab],\n }\n\n return [...sanitizedFields, newTabsField]\n }\n\n // Remove existing theme tab if present\n const sanitizedTabs = removeExistingThemeTab(tabsField.tabs)\n\n // Add theme tab to the end\n const updatedTabs = [...sanitizedTabs, themeTab]\n\n if (enableLogging) {\n console.log('🎨 Theme Management Plugin: injecting Appearance Settings tab')\n }\n\n // Update the tabs field\n const updatedTabsField: TabsField = {\n ...tabsField,\n tabs: updatedTabs,\n }\n\n // Replace the old tabs field with the updated one\n return sanitizedFields.map((field) => (field.type === 'tabs' ? updatedTabsField : field))\n}\n\nconst ensureCollectionsArray = (collections: Config['collections']): CollectionConfig[] =>\n Array.isArray(collections) ? collections : []\n\nexport const themeManagementPlugin = (options: ThemeManagementPluginOptions = {}): Plugin => {\n return (config: Config): Config => {\n const {\n enabled = true,\n targetCollection = 'site-settings',\n useStandaloneCollection = false,\n standaloneCollectionSlug = 'appearance-settings',\n // Allow either string or localized object; default comes from plugin translations\n standaloneCollectionLabel = getTranslations().standaloneCollectionLabel,\n themePresets = allThemePresets,\n defaultTheme = 'cool',\n includeColorModeToggle = true,\n includeCustomCSS = true,\n includeBrandIdentity = false,\n enableAdvancedFeatures = true,\n enableLogging = false,\n } = options\n\n if (!enabled) {\n if (enableLogging) {\n console.log('🎨 Theme Management Plugin: disabled via options, skipping.')\n }\n return config\n }\n\n const themeTab = createThemeConfigurationField({\n themePresets,\n defaultTheme,\n includeColorModeToggle,\n includeCustomCSS,\n includeBrandIdentity: includeBrandIdentity ?? false,\n enableAdvancedFeatures,\n })\n\n // If using standalone collection, create a new global\n if (useStandaloneCollection) {\n if (enableLogging) {\n console.log(\n `🎨 Theme Management Plugin: creating standalone global \"${standaloneCollectionSlug}\"`,\n )\n }\n\n // Extract the fields from the tab directly (no wrapping in group)\n const tabFields = (themeTab.fields ?? []) as Field[]\n\n /**\n * Hook to auto-populate lightMode and darkMode colors when theme changes\n */\n type BeforeChangeArgs = {\n data?: {\n themeConfiguration?: {\n theme?: string\n lightMode?: Record<string, unknown>\n darkMode?: Record<string, unknown>\n }\n }\n }\n\n const beforeChangeHook = async (args: BeforeChangeArgs) => {\n const { data } = args\n\n // If theme is being changed, auto-populate color modes\n if (data?.themeConfiguration?.theme) {\n const themeName = data.themeConfiguration.theme\n const selectedPreset = themePresets.find((p) => p.name === themeName)\n\n if (selectedPreset) {\n // Initialize light and dark mode colors from preset if not already set\n if (!data.themeConfiguration.lightMode) {\n data.themeConfiguration.lightMode = {}\n }\n if (!data.themeConfiguration.darkMode) {\n data.themeConfiguration.darkMode = {}\n }\n\n // Only populate if not manually edited (first time or empty)\n const isLightModeEmpty = !data.themeConfiguration.lightMode?.background\n const isDarkModeEmpty = !data.themeConfiguration.darkMode?.background\n\n if (isLightModeEmpty && selectedPreset.lightMode) {\n data.themeConfiguration.lightMode = { ...selectedPreset.lightMode }\n }\n\n if (isDarkModeEmpty && selectedPreset.darkMode) {\n data.themeConfiguration.darkMode = { ...selectedPreset.darkMode }\n }\n }\n }\n\n return data\n }\n\n const standaloneGlobal: GlobalConfig = {\n slug: standaloneCollectionSlug,\n label: standaloneCollectionLabel,\n admin: {\n group: 'Settings',\n },\n // Provide a broad access object but cast to GlobalConfig['access'] to satisfy types\n access: ((): GlobalConfig['access'] => {\n const accessObj = {\n read: () => true,\n create: ({ req }: { req?: { user?: unknown } }) => !!req?.user,\n update: ({ req }: { req?: { user?: unknown } }) => !!req?.user,\n delete: ({ req }: { req?: { user?: unknown } }) => !!req?.user,\n } as unknown as GlobalConfig['access']\n return accessObj\n })(),\n fields: tabFields,\n hooks: {\n beforeChange: [beforeChangeHook],\n },\n }\n\n const globals = Array.isArray(config.globals) ? config.globals : []\n\n // Check if global already exists\n const existingIndex = globals.findIndex((g) => g.slug === standaloneCollectionSlug)\n\n if (existingIndex !== -1) {\n if (enableLogging) {\n console.warn(\n `🎨 Theme Management Plugin: global \"${standaloneCollectionSlug}\" already exists, skipping creation.`,\n )\n }\n return config\n }\n\n return {\n ...config,\n globals: [...globals, standaloneGlobal],\n }\n }\n\n // Otherwise, add as tab to existing collection\n let collectionTouched = false\n\n const collections = ensureCollectionsArray(config.collections).map((collection) => {\n if (collection.slug !== targetCollection) {\n return collection\n }\n\n collectionTouched = true\n\n if (enableLogging) {\n console.log(`🎨 Theme Management Plugin: enhancing collection \"${collection.slug}\"`)\n }\n\n const existingFields = Array.isArray(collection.fields) ? collection.fields : []\n\n const fields = injectThemeTab(existingFields, themeTab, enableLogging)\n\n return {\n ...collection,\n fields,\n }\n })\n\n if (!collectionTouched) {\n if (enableLogging) {\n console.warn(\n `🎨 Theme Management Plugin: collection \"${targetCollection}\" was not found, leaving config untouched.`,\n )\n }\n return config\n }\n\n return {\n ...config,\n collections,\n }\n }\n}\n\ntype FetchOptionsInput = string | FetchThemeConfigurationOptions\n\nexport const fetchThemeConfiguration = async (\n options?: FetchOptionsInput,\n): Promise<SiteThemeConfiguration | null> => {\n const normalizedOptions = typeof options === 'string' ? { tenantSlug: options } : (options ?? {})\n\n const {\n tenantSlug,\n collectionSlug = 'site-settings', // Can be overridden to 'appearance-settings' if using standalone\n depth,\n locale,\n draft,\n queryParams = {},\n useGlobal = false, // Set to true if using standalone global instead of collection\n } = normalizedOptions\n\n try {\n if (useGlobal) {\n // Fetch from global endpoint\n const params = new URLSearchParams()\n\n if (typeof depth === 'number') params.set('depth', String(depth))\n // For globals, keep tenant param for backwards compatibility, and also add where[...] filter\n if (tenantSlug) {\n params.set('tenant', tenantSlug)\n params.set('where[tenant][equals]', String(tenantSlug))\n }\n\n Object.entries(queryParams).forEach(([key, value]) => {\n if (value === undefined) return\n params.set(key, String(value))\n })\n\n const queryString = params.toString()\n const url = `/api/globals/${collectionSlug}${queryString ? `?${queryString}` : ''}`\n\n const response = await fetch(url)\n if (!response.ok) {\n throw new Error(`Failed to fetch theme global (status ${response.status})`)\n }\n\n const data = (await response.json()) as {\n themeConfiguration?: SiteThemeConfiguration\n }\n\n return data?.themeConfiguration ?? null\n } else {\n // Fetch from collection endpoint (legacy/default behavior)\n const params = new URLSearchParams({ limit: '1' })\n\n if (typeof depth === 'number') params.set('depth', String(depth))\n // For collections, use a where[tenant][equals] filter so Payload's find endpoint applies tenant scoping\n if (tenantSlug) params.set('where[tenant][equals]', String(tenantSlug))\n if (locale) params.set('locale', locale)\n if (draft) params.set('draft', 'true')\n\n Object.entries(queryParams).forEach(([key, value]) => {\n if (value === undefined) return\n params.set(key, String(value))\n })\n\n const url = `/api/${collectionSlug}?${params.toString()}`\n\n const response = await fetch(url)\n if (!response.ok) {\n throw new Error(`Failed to fetch theme configuration (status ${response.status})`)\n }\n\n const data = (await response.json()) as {\n docs?: Array<{ themeConfiguration?: SiteThemeConfiguration }>\n }\n\n const doc = data.docs?.[0]\n\n return doc?.themeConfiguration ?? null\n }\n } catch (error) {\n console.warn('Failed to fetch theme configuration:', error)\n return null\n }\n}\n\nexport const getThemePreset = (themeName: string): ThemePreset | null => {\n return allThemePresets.find((preset) => preset.name === themeName) || null\n}\n\nexport const getAvailableThemePresets = (): ThemePreset[] => {\n return allThemePresets\n}\n\nexport { defaultThemePresets, allThemePresets } from './presets.js'\nexport type { ThemePreset, ThemeTypographyPreset } from './presets.js'\nexport type { ThemeTab } from './fields/themeConfigurationField.js'\nexport {\n extendedThemePresets,\n allExtendedThemePresets,\n extendedThemeToCSSVariables,\n} from './extended-presets.js'\nexport type { ExtendedThemePreset, ShadcnColorTokens } from './extended-presets.js'\nexport {\n applyExtendedTheme,\n generateExtendedThemeCSS,\n resetExtendedTheme,\n getExtendedThemeTokens,\n createUseExtendedTheme,\n getTailwindVarReferences,\n} from './utils/extendedThemeHelpers.js'\nexport type { ThemeManagementPluginOptions, FetchThemeConfigurationOptions } from './types.js'\nexport {\n DEFAULT_THEME_CONFIGURATION,\n resolveThemeConfiguration,\n} from './utils/resolveThemeConfiguration.js'\nexport type { ResolvedThemeConfiguration } from './utils/resolveThemeConfiguration.js'\nexport { generateThemeColorsCss, hexToHsl } from './utils/themeColors.js'\nexport { generateThemeCSS, getThemeStyles } from './utils/themeUtils.js'\nexport { getThemeHtmlAttributes } from './utils/themeHtmlAttributes.js'\n\n// Dynamic theme CSS generation\nexport {\n generateThemeCSS as generatePresetCSS,\n generateAllThemesCSS,\n} from './utils/generateThemeCSS.js'\nexport { getThemeDynamicCSS, getAllDynamicThemesCSS } from './utils/themeCSS.js'\n\nexport type { Mode, ThemeDefaults } from './providers/Theme/types.js'\nexport { ThemeProvider } from './providers/Theme/index.js'\n\n// Font loading utilities for Next.js integration\nexport {\n getFontLoaderCode,\n getThemeFontFamilies,\n ThemeFontProvider,\n useThemeFonts,\n FONT_IMPORT_MAP,\n} from './providers/font-loader.js'\n\n// Note: Do NOT re-export client components from the root entry to avoid\n// server-side evaluation during `payload generate:importmap`.\n// If needed, import directly from subpath: `@kilivi/payloadcms-theme-management/fields/ThemeLivePreview`\n\nexport const ThemeManagementPlugin = themeManagementPlugin\n/** @deprecated use {@link themeManagementPlugin} */\nexport const themeConfigurationPlugin = themeManagementPlugin\n\n// Export plugin translations for consumers to merge into their payload translations\nexport {\n translations,\n getTranslations,\n registerTranslations,\n availableLanguages,\n} from './translations.js'\n\nexport default themeManagementPlugin\n"],"names":["createThemeConfigurationField","allThemePresets","getTranslations","translations","THEME_FIELD_NAME","removeExistingThemeField","fields","filter","field","candidate","name","findTabsField","type","removeExistingThemeTab","tabs","knownLabels","Object","values","map","t","tabLabel","tab","labelValues","label","matchesKnown","some","v","includes","injectThemeTab","themeTab","enableLogging","sanitizedFields","tabsField","console","warn","newTabsField","sanitizedTabs","updatedTabs","log","updatedTabsField","ensureCollectionsArray","collections","Array","isArray","themeManagementPlugin","options","config","enabled","targetCollection","useStandaloneCollection","standaloneCollectionSlug","standaloneCollectionLabel","themePresets","defaultTheme","includeColorModeToggle","includeCustomCSS","includeBrandIdentity","enableAdvancedFeatures","tabFields","beforeChangeHook","args","data","themeConfiguration","theme","themeName","selectedPreset","find","p","lightMode","darkMode","isLightModeEmpty","background","isDarkModeEmpty","standaloneGlobal","slug","admin","group","access","accessObj","read","create","req","user","update","delete","hooks","beforeChange","globals","existingIndex","findIndex","g","collectionTouched","collection","existingFields","fetchThemeConfiguration","normalizedOptions","tenantSlug","collectionSlug","depth","locale","draft","queryParams","useGlobal","params","URLSearchParams","set","String","entries","forEach","key","value","undefined","queryString","toString","url","response","fetch","ok","Error","status","json","limit","doc","docs","error","getThemePreset","preset","getAvailableThemePresets","defaultThemePresets","extendedThemePresets","allExtendedThemePresets","extendedThemeToCSSVariables","applyExtendedTheme","generateExtendedThemeCSS","resetExtendedTheme","getExtendedThemeTokens","createUseExtendedTheme","getTailwindVarReferences","DEFAULT_THEME_CONFIGURATION","resolveThemeConfiguration","generateThemeColorsCss","hexToHsl","generateThemeCSS","getThemeStyles","getThemeHtmlAttributes","generatePresetCSS","generateAllThemesCSS","getThemeDynamicCSS","getAllDynamicThemesCSS","ThemeProvider","getFontLoaderCode","getThemeFontFamilies","ThemeFontProvider","useThemeFonts","FONT_IMPORT_MAP","ThemeManagementPlugin","themeConfigurationPlugin","registerTranslations","availableLanguages"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { CollectionConfig, Config, Field, GlobalConfig, Plugin, TabsField } from 'payload'\nimport { createThemeConfigurationField } from './fields/themeConfigurationField.js'\nimport type { ThemeTab } from './fields/themeConfigurationField.js'\nimport type { SiteThemeConfiguration } from './payload-types.js'\nimport type { ThemePreset } from './presets.js'\nimport { allThemePresets } from './presets.js'\nimport { getTranslations, translations } from './translations.js'\nimport type { FetchThemeConfigurationOptions, ThemeManagementPluginOptions } from './types.js'\n\nconst THEME_FIELD_NAME = 'themeConfiguration'\n\n/**\n * Removes existing theme configuration from a group field (legacy)\n */\nconst removeExistingThemeField = (fields: Field[] = []): Field[] =>\n fields.filter((field) => {\n const candidate = field as { name?: unknown }\n return candidate?.name !== THEME_FIELD_NAME\n })\n\n/**\n * Finds the tabs field in the collection fields array\n */\nconst findTabsField = (fields: Field[] = []): TabsField | null => {\n for (const field of fields) {\n if (field.type === 'tabs') {\n return field as TabsField\n }\n }\n return null\n}\n\n/**\n * Removes existing Appearance Settings tab if it exists\n */\nconst removeExistingThemeTab = (\n tabs: NonNullable<TabsField['tabs']>,\n): NonNullable<TabsField['tabs']> => {\n const knownLabels = Object.values(translations).map((t) => t.tabLabel)\n return tabs.filter((tab) => {\n // Normalize label to string (support localized object or plain string)\n let labelValues: string[] = []\n if (typeof tab.label === 'object' && tab.label !== null) {\n labelValues = Object.values(tab.label as Record<string, string>)\n } else if (typeof tab.label === 'string') {\n labelValues = [tab.label]\n }\n\n // If any of the label values match a known plugin tab label, remove it\n const matchesKnown = labelValues.some((v) => knownLabels.includes(v))\n\n return !matchesKnown\n })\n}\n\n/**\n * Injects theme tab into existing tabs field\n */\nconst injectThemeTab = (\n fields: Field[] | undefined,\n themeTab: ThemeTab,\n enableLogging: boolean,\n): Field[] => {\n // First, remove any legacy theme field (group-based)\n const sanitizedFields = removeExistingThemeField(fields ?? [])\n\n // Find the tabs field\n const tabsField = findTabsField(sanitizedFields)\n\n if (!tabsField || !tabsField.tabs) {\n if (enableLogging) {\n console.warn(\n '🎨 Theme Management Plugin: No tabs field found. Creating a new tabs structure.',\n )\n }\n\n // If no tabs exist, create a basic tabs structure with just the theme tab\n const newTabsField: TabsField = {\n type: 'tabs',\n tabs: [themeTab],\n }\n\n return [...sanitizedFields, newTabsField]\n }\n\n // Remove existing theme tab if present\n const sanitizedTabs = removeExistingThemeTab(tabsField.tabs)\n\n // Add theme tab to the end\n const updatedTabs = [...sanitizedTabs, themeTab]\n\n if (enableLogging) {\n console.log('🎨 Theme Management Plugin: injecting Appearance Settings tab')\n }\n\n // Update the tabs field\n const updatedTabsField: TabsField = {\n ...tabsField,\n tabs: updatedTabs,\n }\n\n // Replace the old tabs field with the updated one\n return sanitizedFields.map((field) => (field.type === 'tabs' ? updatedTabsField : field))\n}\n\nconst ensureCollectionsArray = (collections: Config['collections']): CollectionConfig[] =>\n Array.isArray(collections) ? collections : []\n\nexport const themeManagementPlugin = (options: ThemeManagementPluginOptions = {}): Plugin => {\n return (config: Config): Config => {\n const {\n enabled = true,\n targetCollection = 'site-settings',\n useStandaloneCollection = false,\n standaloneCollectionSlug = 'appearance-settings',\n // Allow either string or localized object; default comes from plugin translations\n standaloneCollectionLabel = getTranslations().standaloneCollectionLabel,\n themePresets = allThemePresets,\n defaultTheme = 'cool',\n includeColorModeToggle = true,\n includeCustomCSS = true,\n includeBrandIdentity = false,\n enableAdvancedFeatures = true,\n enableLogging = false,\n } = options\n\n if (!enabled) {\n if (enableLogging) {\n console.log('🎨 Theme Management Plugin: disabled via options, skipping.')\n }\n return config\n }\n\n const themeTab = createThemeConfigurationField({\n themePresets,\n defaultTheme,\n includeColorModeToggle,\n includeCustomCSS,\n includeBrandIdentity: includeBrandIdentity ?? false,\n enableAdvancedFeatures,\n })\n\n // If using standalone collection, create a new global\n if (useStandaloneCollection) {\n if (enableLogging) {\n console.log(\n `🎨 Theme Management Plugin: creating standalone global \"${standaloneCollectionSlug}\"`,\n )\n }\n\n // Extract the fields from the tab directly (no wrapping in group)\n const tabFields = (themeTab.fields ?? []) as Field[]\n\n /**\n * Hook to auto-populate lightMode and darkMode colors when theme changes\n */\n type BeforeChangeArgs = {\n data?: {\n themeConfiguration?: {\n theme?: string\n lightMode?: Record<string, unknown>\n darkMode?: Record<string, unknown>\n }\n }\n }\n\n const beforeChangeHook = async (args: BeforeChangeArgs) => {\n const { data } = args\n\n // If theme is being changed, auto-populate color modes\n if (data?.themeConfiguration?.theme) {\n const themeName = data.themeConfiguration.theme\n const selectedPreset = themePresets.find((p) => p.name === themeName)\n\n if (selectedPreset) {\n // Initialize light and dark mode colors from preset if not already set\n if (!data.themeConfiguration.lightMode) {\n data.themeConfiguration.lightMode = {}\n }\n if (!data.themeConfiguration.darkMode) {\n data.themeConfiguration.darkMode = {}\n }\n\n // Only populate if not manually edited (first time or empty)\n const isLightModeEmpty = !data.themeConfiguration.lightMode?.background\n const isDarkModeEmpty = !data.themeConfiguration.darkMode?.background\n\n if (isLightModeEmpty && selectedPreset.lightMode) {\n data.themeConfiguration.lightMode = { ...selectedPreset.lightMode }\n }\n\n if (isDarkModeEmpty && selectedPreset.darkMode) {\n data.themeConfiguration.darkMode = { ...selectedPreset.darkMode }\n }\n }\n }\n\n return data\n }\n\n const standaloneGlobal: GlobalConfig = {\n slug: standaloneCollectionSlug,\n label: standaloneCollectionLabel,\n admin: {\n group: 'Settings',\n },\n // Provide a broad access object but cast to GlobalConfig['access'] to satisfy types\n access: ((): GlobalConfig['access'] => {\n const accessObj = {\n read: () => true,\n create: ({ req }: { req?: { user?: unknown } }) => !!req?.user,\n update: ({ req }: { req?: { user?: unknown } }) => !!req?.user,\n delete: ({ req }: { req?: { user?: unknown } }) => !!req?.user,\n } as unknown as GlobalConfig['access']\n return accessObj\n })(),\n fields: tabFields,\n hooks: {\n beforeChange: [beforeChangeHook],\n afterChange: [\n async ({ doc, req }) => {\n // Invalidate cache after appearance settings change\n if (!req?.context?.disableRevalidate) {\n try {\n const cacheTag = `global_${standaloneCollectionSlug}`\n // Import revalidateTag dynamically to avoid issues in non-Next.js environments\n const { revalidateTag } = await import('next/cache')\n revalidateTag(cacheTag)\n if (enableLogging) {\n req.payload.logger.info(\n `🎨 Theme Management Plugin: cache invalidated for tag \"${cacheTag}\"`,\n )\n }\n } catch (error) {\n if (enableLogging) {\n req.payload.logger.error(\n '🎨 Theme Management Plugin: cache invalidation failed:',\n error,\n )\n }\n }\n }\n return doc\n },\n ],\n },\n }\n\n const globals = Array.isArray(config.globals) ? config.globals : []\n\n // Check if global already exists\n const existingIndex = globals.findIndex((g) => g.slug === standaloneCollectionSlug)\n\n if (existingIndex !== -1) {\n if (enableLogging) {\n console.warn(\n `🎨 Theme Management Plugin: global \"${standaloneCollectionSlug}\" already exists, skipping creation.`,\n )\n }\n return config\n }\n\n return {\n ...config,\n globals: [...globals, standaloneGlobal],\n }\n }\n\n // Otherwise, add as tab to existing collection\n let collectionTouched = false\n\n const collections = ensureCollectionsArray(config.collections).map((collection) => {\n if (collection.slug !== targetCollection) {\n return collection\n }\n\n collectionTouched = true\n\n if (enableLogging) {\n console.log(`🎨 Theme Management Plugin: enhancing collection \"${collection.slug}\"`)\n }\n\n const existingFields = Array.isArray(collection.fields) ? collection.fields : []\n\n const fields = injectThemeTab(existingFields, themeTab, enableLogging)\n\n return {\n ...collection,\n fields,\n }\n })\n\n if (!collectionTouched) {\n if (enableLogging) {\n console.warn(\n `🎨 Theme Management Plugin: collection \"${targetCollection}\" was not found, leaving config untouched.`,\n )\n }\n return config\n }\n\n return {\n ...config,\n collections,\n }\n }\n}\n\ntype FetchOptionsInput = string | FetchThemeConfigurationOptions\n\nexport const fetchThemeConfiguration = async (\n options?: FetchOptionsInput,\n): Promise<SiteThemeConfiguration | null> => {\n const normalizedOptions = typeof options === 'string' ? { tenantSlug: options } : (options ?? {})\n\n const {\n tenantSlug,\n collectionSlug = 'site-settings', // Can be overridden to 'appearance-settings' if using standalone\n depth,\n locale,\n draft,\n queryParams = {},\n useGlobal = false, // Set to true if using standalone global instead of collection\n } = normalizedOptions\n\n try {\n if (useGlobal) {\n // Fetch from global endpoint\n const params = new URLSearchParams()\n\n if (typeof depth === 'number') params.set('depth', String(depth))\n // For globals, keep tenant param for backwards compatibility, and also add where[...] filter\n if (tenantSlug) {\n params.set('tenant', tenantSlug)\n params.set('where[tenant][equals]', String(tenantSlug))\n }\n\n Object.entries(queryParams).forEach(([key, value]) => {\n if (value === undefined) return\n params.set(key, String(value))\n })\n\n const queryString = params.toString()\n const url = `/api/globals/${collectionSlug}${queryString ? `?${queryString}` : ''}`\n\n const response = await fetch(url)\n if (!response.ok) {\n throw new Error(`Failed to fetch theme global (status ${response.status})`)\n }\n\n const data = (await response.json()) as {\n themeConfiguration?: SiteThemeConfiguration\n }\n\n return data?.themeConfiguration ?? null\n } else {\n // Fetch from collection endpoint (legacy/default behavior)\n const params = new URLSearchParams({ limit: '1' })\n\n if (typeof depth === 'number') params.set('depth', String(depth))\n // For collections, use a where[tenant][equals] filter so Payload's find endpoint applies tenant scoping\n if (tenantSlug) params.set('where[tenant][equals]', String(tenantSlug))\n if (locale) params.set('locale', locale)\n if (draft) params.set('draft', 'true')\n\n Object.entries(queryParams).forEach(([key, value]) => {\n if (value === undefined) return\n params.set(key, String(value))\n })\n\n const url = `/api/${collectionSlug}?${params.toString()}`\n\n const response = await fetch(url)\n if (!response.ok) {\n throw new Error(`Failed to fetch theme configuration (status ${response.status})`)\n }\n\n const data = (await response.json()) as {\n docs?: Array<{ themeConfiguration?: SiteThemeConfiguration }>\n }\n\n const doc = data.docs?.[0]\n\n return doc?.themeConfiguration ?? null\n }\n } catch (error) {\n console.warn('Failed to fetch theme configuration:', error)\n return null\n }\n}\n\nexport const getThemePreset = (themeName: string): ThemePreset | null => {\n return allThemePresets.find((preset) => preset.name === themeName) || null\n}\n\nexport const getAvailableThemePresets = (): ThemePreset[] => {\n return allThemePresets\n}\n\nexport { defaultThemePresets, allThemePresets } from './presets.js'\nexport type { ThemePreset, ThemeTypographyPreset } from './presets.js'\nexport type { ThemeTab } from './fields/themeConfigurationField.js'\nexport {\n extendedThemePresets,\n allExtendedThemePresets,\n extendedThemeToCSSVariables,\n} from './extended-presets.js'\nexport type { ExtendedThemePreset, ShadcnColorTokens } from './extended-presets.js'\nexport {\n applyExtendedTheme,\n generateExtendedThemeCSS,\n resetExtendedTheme,\n getExtendedThemeTokens,\n createUseExtendedTheme,\n getTailwindVarReferences,\n} from './utils/extendedThemeHelpers.js'\nexport type { ThemeManagementPluginOptions, FetchThemeConfigurationOptions } from './types.js'\nexport {\n DEFAULT_THEME_CONFIGURATION,\n resolveThemeConfiguration,\n} from './utils/resolveThemeConfiguration.js'\nexport type { ResolvedThemeConfiguration } from './utils/resolveThemeConfiguration.js'\nexport { generateThemeColorsCss, hexToHsl } from './utils/themeColors.js'\nexport { generateThemeCSS, getThemeStyles } from './utils/themeUtils.js'\nexport { getThemeHtmlAttributes } from './utils/themeHtmlAttributes.js'\n\n// Dynamic theme CSS generation\nexport {\n generateThemeCSS as generatePresetCSS,\n generateAllThemesCSS,\n} from './utils/generateThemeCSS.js'\nexport { getThemeDynamicCSS, getAllDynamicThemesCSS } from './utils/themeCSS.js'\n\nexport type { Mode, ThemeDefaults } from './providers/Theme/types.js'\nexport { ThemeProvider } from './providers/Theme/index.js'\n\n// Font loading utilities for Next.js integration\nexport {\n getFontLoaderCode,\n getThemeFontFamilies,\n ThemeFontProvider,\n useThemeFonts,\n FONT_IMPORT_MAP,\n} from './providers/font-loader.js'\n\n// Note: Do NOT re-export client components from the root entry to avoid\n// server-side evaluation during `payload generate:importmap`.\n// If needed, import directly from subpath: `@kilivi/payloadcms-theme-management/fields/ThemeLivePreview`\n\nexport const ThemeManagementPlugin = themeManagementPlugin\n/** @deprecated use {@link themeManagementPlugin} */\nexport const themeConfigurationPlugin = themeManagementPlugin\n\n// Export plugin translations for consumers to merge into their payload translations\nexport {\n translations,\n getTranslations,\n registerTranslations,\n availableLanguages,\n} from './translations.js'\n\nexport default themeManagementPlugin\n"],"names":["createThemeConfigurationField","allThemePresets","getTranslations","translations","THEME_FIELD_NAME","removeExistingThemeField","fields","filter","field","candidate","name","findTabsField","type","removeExistingThemeTab","tabs","knownLabels","Object","values","map","t","tabLabel","tab","labelValues","label","matchesKnown","some","v","includes","injectThemeTab","themeTab","enableLogging","sanitizedFields","tabsField","console","warn","newTabsField","sanitizedTabs","updatedTabs","log","updatedTabsField","ensureCollectionsArray","collections","Array","isArray","themeManagementPlugin","options","config","enabled","targetCollection","useStandaloneCollection","standaloneCollectionSlug","standaloneCollectionLabel","themePresets","defaultTheme","includeColorModeToggle","includeCustomCSS","includeBrandIdentity","enableAdvancedFeatures","tabFields","beforeChangeHook","args","data","themeConfiguration","theme","themeName","selectedPreset","find","p","lightMode","darkMode","isLightModeEmpty","background","isDarkModeEmpty","standaloneGlobal","slug","admin","group","access","accessObj","read","create","req","user","update","delete","hooks","beforeChange","afterChange","doc","context","disableRevalidate","cacheTag","revalidateTag","payload","logger","info","error","globals","existingIndex","findIndex","g","collectionTouched","collection","existingFields","fetchThemeConfiguration","normalizedOptions","tenantSlug","collectionSlug","depth","locale","draft","queryParams","useGlobal","params","URLSearchParams","set","String","entries","forEach","key","value","undefined","queryString","toString","url","response","fetch","ok","Error","status","json","limit","docs","getThemePreset","preset","getAvailableThemePresets","defaultThemePresets","extendedThemePresets","allExtendedThemePresets","extendedThemeToCSSVariables","applyExtendedTheme","generateExtendedThemeCSS","resetExtendedTheme","getExtendedThemeTokens","createUseExtendedTheme","getTailwindVarReferences","DEFAULT_THEME_CONFIGURATION","resolveThemeConfiguration","generateThemeColorsCss","hexToHsl","generateThemeCSS","getThemeStyles","getThemeHtmlAttributes","generatePresetCSS","generateAllThemesCSS","getThemeDynamicCSS","getAllDynamicThemesCSS","ThemeProvider","getFontLoaderCode","getThemeFontFamilies","ThemeFontProvider","useThemeFonts","FONT_IMPORT_MAP","ThemeManagementPlugin","themeConfigurationPlugin","registerTranslations","availableLanguages"],"mappings":"AACA,SAASA,6BAA6B,QAAQ,sCAAqC;AAInF,SAASC,eAAe,QAAQ,eAAc;AAC9C,SAASC,eAAe,EAAEC,YAAY,QAAQ,oBAAmB;AAGjE,MAAMC,mBAAmB;AAEzB;;CAEC,GACD,MAAMC,2BAA2B,CAACC,SAAkB,EAAE,GACpDA,OAAOC,MAAM,CAAC,CAACC;QACb,MAAMC,YAAYD;QAClB,OAAOC,WAAWC,SAASN;IAC7B;AAEF;;CAEC,GACD,MAAMO,gBAAgB,CAACL,SAAkB,EAAE;IACzC,KAAK,MAAME,SAASF,OAAQ;QAC1B,IAAIE,MAAMI,IAAI,KAAK,QAAQ;YACzB,OAAOJ;QACT;IACF;IACA,OAAO;AACT;AAEA;;CAEC,GACD,MAAMK,yBAAyB,CAC7BC;IAEA,MAAMC,cAAcC,OAAOC,MAAM,CAACd,cAAce,GAAG,CAAC,CAACC,IAAMA,EAAEC,QAAQ;IACrE,OAAON,KAAKP,MAAM,CAAC,CAACc;QAClB,uEAAuE;QACvE,IAAIC,cAAwB,EAAE;QAC9B,IAAI,OAAOD,IAAIE,KAAK,KAAK,YAAYF,IAAIE,KAAK,KAAK,MAAM;YACvDD,cAAcN,OAAOC,MAAM,CAACI,IAAIE,KAAK;QACvC,OAAO,IAAI,OAAOF,IAAIE,KAAK,KAAK,UAAU;YACxCD,cAAc;gBAACD,IAAIE,KAAK;aAAC;QAC3B;QAEA,uEAAuE;QACvE,MAAMC,eAAeF,YAAYG,IAAI,CAAC,CAACC,IAAMX,YAAYY,QAAQ,CAACD;QAElE,OAAO,CAACF;IACV;AACF;AAEA;;CAEC,GACD,MAAMI,iBAAiB,CACrBtB,QACAuB,UACAC;IAEA,qDAAqD;IACrD,MAAMC,kBAAkB1B,yBAAyBC,UAAU,EAAE;IAE7D,sBAAsB;IACtB,MAAM0B,YAAYrB,cAAcoB;IAEhC,IAAI,CAACC,aAAa,CAACA,UAAUlB,IAAI,EAAE;QACjC,IAAIgB,eAAe;YACjBG,QAAQC,IAAI,CACV;QAEJ;QAEA,0EAA0E;QAC1E,MAAMC,eAA0B;YAC9BvB,MAAM;YACNE,MAAM;gBAACe;aAAS;QAClB;QAEA,OAAO;eAAIE;YAAiBI;SAAa;IAC3C;IAEA,uCAAuC;IACvC,MAAMC,gBAAgBvB,uBAAuBmB,UAAUlB,IAAI;IAE3D,2BAA2B;IAC3B,MAAMuB,cAAc;WAAID;QAAeP;KAAS;IAEhD,IAAIC,eAAe;QACjBG,QAAQK,GAAG,CAAC;IACd;IAEA,wBAAwB;IACxB,MAAMC,mBAA8B;QAClC,GAAGP,SAAS;QACZlB,MAAMuB;IACR;IAEA,kDAAkD;IAClD,OAAON,gBAAgBb,GAAG,CAAC,CAACV,QAAWA,MAAMI,IAAI,KAAK,SAAS2B,mBAAmB/B;AACpF;AAEA,MAAMgC,yBAAyB,CAACC,cAC9BC,MAAMC,OAAO,CAACF,eAAeA,cAAc,EAAE;AAE/C,OAAO,MAAMG,wBAAwB,CAACC,UAAwC,CAAC,CAAC;IAC9E,OAAO,CAACC;QACN,MAAM,EACJC,UAAU,IAAI,EACdC,mBAAmB,eAAe,EAClCC,0BAA0B,KAAK,EAC/BC,2BAA2B,qBAAqB,EAChD,kFAAkF;QAClFC,4BAA4BjD,kBAAkBiD,yBAAyB,EACvEC,eAAenD,eAAe,EAC9BoD,eAAe,MAAM,EACrBC,yBAAyB,IAAI,EAC7BC,mBAAmB,IAAI,EACvBC,uBAAuB,KAAK,EAC5BC,yBAAyB,IAAI,EAC7B3B,gBAAgB,KAAK,EACtB,GAAGe;QAEJ,IAAI,CAACE,SAAS;YACZ,IAAIjB,eAAe;gBACjBG,QAAQK,GAAG,CAAC;YACd;YACA,OAAOQ;QACT;QAEA,MAAMjB,WAAW7B,8BAA8B;YAC7CoD;YACAC;YACAC;YACAC;YACAC,sBAAsBA,wBAAwB;YAC9CC;QACF;QAEA,sDAAsD;QACtD,IAAIR,yBAAyB;YAC3B,IAAInB,eAAe;gBACjBG,QAAQK,GAAG,CACT,CAAC,wDAAwD,EAAEY,yBAAyB,CAAC,CAAC;YAE1F;YAEA,kEAAkE;YAClE,MAAMQ,YAAa7B,SAASvB,MAAM,IAAI,EAAE;YAexC,MAAMqD,mBAAmB,OAAOC;gBAC9B,MAAM,EAAEC,IAAI,EAAE,GAAGD;gBAEjB,uDAAuD;gBACvD,IAAIC,MAAMC,oBAAoBC,OAAO;oBACnC,MAAMC,YAAYH,KAAKC,kBAAkB,CAACC,KAAK;oBAC/C,MAAME,iBAAiBb,aAAac,IAAI,CAAC,CAACC,IAAMA,EAAEzD,IAAI,KAAKsD;oBAE3D,IAAIC,gBAAgB;wBAClB,uEAAuE;wBACvE,IAAI,CAACJ,KAAKC,kBAAkB,CAACM,SAAS,EAAE;4BACtCP,KAAKC,kBAAkB,CAACM,SAAS,GAAG,CAAC;wBACvC;wBACA,IAAI,CAACP,KAAKC,kBAAkB,CAACO,QAAQ,EAAE;4BACrCR,KAAKC,kBAAkB,CAACO,QAAQ,GAAG,CAAC;wBACtC;wBAEA,6DAA6D;wBAC7D,MAAMC,mBAAmB,CAACT,KAAKC,kBAAkB,CAACM,SAAS,EAAEG;wBAC7D,MAAMC,kBAAkB,CAACX,KAAKC,kBAAkB,CAACO,QAAQ,EAAEE;wBAE3D,IAAID,oBAAoBL,eAAeG,SAAS,EAAE;4BAChDP,KAAKC,kBAAkB,CAACM,SAAS,GAAG;gCAAE,GAAGH,eAAeG,SAAS;4BAAC;wBACpE;wBAEA,IAAII,mBAAmBP,eAAeI,QAAQ,EAAE;4BAC9CR,KAAKC,kBAAkB,CAACO,QAAQ,GAAG;gCAAE,GAAGJ,eAAeI,QAAQ;4BAAC;wBAClE;oBACF;gBACF;gBAEA,OAAOR;YACT;YAEA,MAAMY,mBAAiC;gBACrCC,MAAMxB;gBACN3B,OAAO4B;gBACPwB,OAAO;oBACLC,OAAO;gBACT;gBACA,oFAAoF;gBACpFC,QAAQ,AAAC,CAAA;oBACP,MAAMC,YAAY;wBAChBC,MAAM,IAAM;wBACZC,QAAQ,CAAC,EAAEC,GAAG,EAAgC,GAAK,CAAC,CAACA,KAAKC;wBAC1DC,QAAQ,CAAC,EAAEF,GAAG,EAAgC,GAAK,CAAC,CAACA,KAAKC;wBAC1DE,QAAQ,CAAC,EAAEH,GAAG,EAAgC,GAAK,CAAC,CAACA,KAAKC;oBAC5D;oBACA,OAAOJ;gBACT,CAAA;gBACAxE,QAAQoD;gBACR2B,OAAO;oBACLC,cAAc;wBAAC3B;qBAAiB;oBAChC4B,aAAa;wBACX,OAAO,EAAEC,GAAG,EAAEP,GAAG,EAAE;4BACjB,oDAAoD;4BACpD,IAAI,CAACA,KAAKQ,SAASC,mBAAmB;gCACpC,IAAI;oCACF,MAAMC,WAAW,CAAC,OAAO,EAAEzC,0BAA0B;oCACrD,+EAA+E;oCAC/E,MAAM,EAAE0C,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC;oCACvCA,cAAcD;oCACd,IAAI7D,eAAe;wCACjBmD,IAAIY,OAAO,CAACC,MAAM,CAACC,IAAI,CACrB,CAAC,uDAAuD,EAAEJ,SAAS,CAAC,CAAC;oCAEzE;gCACF,EAAE,OAAOK,OAAO;oCACd,IAAIlE,eAAe;wCACjBmD,IAAIY,OAAO,CAACC,MAAM,CAACE,KAAK,CACtB,0DACAA;oCAEJ;gCACF;4BACF;4BACA,OAAOR;wBACT;qBACD;gBACH;YACF;YAEA,MAAMS,UAAUvD,MAAMC,OAAO,CAACG,OAAOmD,OAAO,IAAInD,OAAOmD,OAAO,GAAG,EAAE;YAEnE,iCAAiC;YACjC,MAAMC,gBAAgBD,QAAQE,SAAS,CAAC,CAACC,IAAMA,EAAE1B,IAAI,KAAKxB;YAE1D,IAAIgD,kBAAkB,CAAC,GAAG;gBACxB,IAAIpE,eAAe;oBACjBG,QAAQC,IAAI,CACV,CAAC,oCAAoC,EAAEgB,yBAAyB,oCAAoC,CAAC;gBAEzG;gBACA,OAAOJ;YACT;YAEA,OAAO;gBACL,GAAGA,MAAM;gBACTmD,SAAS;uBAAIA;oBAASxB;iBAAiB;YACzC;QACF;QAEA,+CAA+C;QAC/C,IAAI4B,oBAAoB;QAExB,MAAM5D,cAAcD,uBAAuBM,OAAOL,WAAW,EAAEvB,GAAG,CAAC,CAACoF;YAClE,IAAIA,WAAW5B,IAAI,KAAK1B,kBAAkB;gBACxC,OAAOsD;YACT;YAEAD,oBAAoB;YAEpB,IAAIvE,eAAe;gBACjBG,QAAQK,GAAG,CAAC,CAAC,kDAAkD,EAAEgE,WAAW5B,IAAI,CAAC,CAAC,CAAC;YACrF;YAEA,MAAM6B,iBAAiB7D,MAAMC,OAAO,CAAC2D,WAAWhG,MAAM,IAAIgG,WAAWhG,MAAM,GAAG,EAAE;YAEhF,MAAMA,SAASsB,eAAe2E,gBAAgB1E,UAAUC;YAExD,OAAO;gBACL,GAAGwE,UAAU;gBACbhG;YACF;QACF;QAEA,IAAI,CAAC+F,mBAAmB;YACtB,IAAIvE,eAAe;gBACjBG,QAAQC,IAAI,CACV,CAAC,wCAAwC,EAAEc,iBAAiB,0CAA0C,CAAC;YAE3G;YACA,OAAOF;QACT;QAEA,OAAO;YACL,GAAGA,MAAM;YACTL;QACF;IACF;AACF,EAAC;AAID,OAAO,MAAM+D,0BAA0B,OACrC3D;IAEA,MAAM4D,oBAAoB,OAAO5D,YAAY,WAAW;QAAE6D,YAAY7D;IAAQ,IAAKA,WAAW,CAAC;IAE/F,MAAM,EACJ6D,UAAU,EACVC,iBAAiB,eAAe,EAChCC,KAAK,EACLC,MAAM,EACNC,KAAK,EACLC,cAAc,CAAC,CAAC,EAChBC,YAAY,KAAK,EAClB,GAAGP;IAEJ,IAAI;QACF,IAAIO,WAAW;YACb,6BAA6B;YAC7B,MAAMC,SAAS,IAAIC;YAEnB,IAAI,OAAON,UAAU,UAAUK,OAAOE,GAAG,CAAC,SAASC,OAAOR;YAC1D,6FAA6F;YAC7F,IAAIF,YAAY;gBACdO,OAAOE,GAAG,CAAC,UAAUT;gBACrBO,OAAOE,GAAG,CAAC,yBAAyBC,OAAOV;YAC7C;YAEA1F,OAAOqG,OAAO,CAACN,aAAaO,OAAO,CAAC,CAAC,CAACC,KAAKC,MAAM;gBAC/C,IAAIA,UAAUC,WAAW;gBACzBR,OAAOE,GAAG,CAACI,KAAKH,OAAOI;YACzB;YAEA,MAAME,cAAcT,OAAOU,QAAQ;YACnC,MAAMC,MAAM,CAAC,aAAa,EAAEjB,iBAAiBe,cAAc,CAAC,CAAC,EAAEA,aAAa,GAAG,IAAI;YAEnF,MAAMG,WAAW,MAAMC,MAAMF;YAC7B,IAAI,CAACC,SAASE,EAAE,EAAE;gBAChB,MAAM,IAAIC,MAAM,CAAC,qCAAqC,EAAEH,SAASI,MAAM,CAAC,CAAC,CAAC;YAC5E;YAEA,MAAMpE,OAAQ,MAAMgE,SAASK,IAAI;YAIjC,OAAOrE,MAAMC,sBAAsB;QACrC,OAAO;YACL,2DAA2D;YAC3D,MAAMmD,SAAS,IAAIC,gBAAgB;gBAAEiB,OAAO;YAAI;YAEhD,IAAI,OAAOvB,UAAU,UAAUK,OAAOE,GAAG,CAAC,SAASC,OAAOR;YAC1D,wGAAwG;YACxG,IAAIF,YAAYO,OAAOE,GAAG,CAAC,yBAAyBC,OAAOV;YAC3D,IAAIG,QAAQI,OAAOE,GAAG,CAAC,UAAUN;YACjC,IAAIC,OAAOG,OAAOE,GAAG,CAAC,SAAS;YAE/BnG,OAAOqG,OAAO,CAACN,aAAaO,OAAO,CAAC,CAAC,CAACC,KAAKC,MAAM;gBAC/C,IAAIA,UAAUC,WAAW;gBACzBR,OAAOE,GAAG,CAACI,KAAKH,OAAOI;YACzB;YAEA,MAAMI,MAAM,CAAC,KAAK,EAAEjB,eAAe,CAAC,EAAEM,OAAOU,QAAQ,IAAI;YAEzD,MAAME,WAAW,MAAMC,MAAMF;YAC7B,IAAI,CAACC,SAASE,EAAE,EAAE;gBAChB,MAAM,IAAIC,MAAM,CAAC,4CAA4C,EAAEH,SAASI,MAAM,CAAC,CAAC,CAAC;YACnF;YAEA,MAAMpE,OAAQ,MAAMgE,SAASK,IAAI;YAIjC,MAAM1C,MAAM3B,KAAKuE,IAAI,EAAE,CAAC,EAAE;YAE1B,OAAO5C,KAAK1B,sBAAsB;QACpC;IACF,EAAE,OAAOkC,OAAO;QACd/D,QAAQC,IAAI,CAAC,wCAAwC8D;QACrD,OAAO;IACT;AACF,EAAC;AAED,OAAO,MAAMqC,iBAAiB,CAACrE;IAC7B,OAAO/D,gBAAgBiE,IAAI,CAAC,CAACoE,SAAWA,OAAO5H,IAAI,KAAKsD,cAAc;AACxE,EAAC;AAED,OAAO,MAAMuE,2BAA2B;IACtC,OAAOtI;AACT,EAAC;AAED,SAASuI,mBAAmB,EAAEvI,eAAe,QAAQ,eAAc;AAGnE,SACEwI,oBAAoB,EACpBC,uBAAuB,EACvBC,2BAA2B,QACtB,wBAAuB;AAE9B,SACEC,kBAAkB,EAClBC,wBAAwB,EACxBC,kBAAkB,EAClBC,sBAAsB,EACtBC,sBAAsB,EACtBC,wBAAwB,QACnB,kCAAiC;AAExC,SACEC,2BAA2B,EAC3BC,yBAAyB,QACpB,uCAAsC;AAE7C,SAASC,sBAAsB,EAAEC,QAAQ,QAAQ,yBAAwB;AACzE,SAASC,gBAAgB,EAAEC,cAAc,QAAQ,wBAAuB;AACxE,SAASC,sBAAsB,QAAQ,iCAAgC;AAEvE,+BAA+B;AAC/B,SACEF,oBAAoBG,iBAAiB,EACrCC,oBAAoB,QACf,8BAA6B;AACpC,SAASC,kBAAkB,EAAEC,sBAAsB,QAAQ,sBAAqB;AAGhF,SAASC,aAAa,QAAQ,6BAA4B;AAE1D,iDAAiD;AACjD,SACEC,iBAAiB,EACjBC,oBAAoB,EACpBC,iBAAiB,EACjBC,aAAa,EACbC,eAAe,QACV,6BAA4B;AAEnC,wEAAwE;AACxE,8DAA8D;AAC9D,yGAAyG;AAEzG,OAAO,MAAMC,wBAAwBvH,sBAAqB;AAC1D,kDAAkD,GAClD,OAAO,MAAMwH,2BAA2BxH,sBAAqB;AAE7D,oFAAoF;AACpF,SACEzC,YAAY,EACZD,eAAe,EACfmK,oBAAoB,EACpBC,kBAAkB,QACb,oBAAmB;AAE1B,eAAe1H,sBAAqB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kilivi/payloadcms-theme-management",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Theme configuration plugin for Payload CMS v3 with 60+ professional themes and standalone collection support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -112,6 +112,7 @@
|
|
|
112
112
|
"access": "public"
|
|
113
113
|
},
|
|
114
114
|
"dependencies": {
|
|
115
|
+
"color": "^5.0.3",
|
|
115
116
|
"react-colorful": "^5.6.1",
|
|
116
117
|
"server-only": "^0.0.1"
|
|
117
118
|
},
|