@kilivi/payloadcms-theme-management 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +26 -4
  2. package/dist/extended-presets.d.ts +16 -1
  3. package/dist/extended-presets.d.ts.map +1 -1
  4. package/dist/extended-presets.js +8 -1
  5. package/dist/extended-presets.js.map +1 -1
  6. package/dist/fields/ThemeColorPickerField.css +350 -65
  7. package/dist/fields/ThemeColorPickerField.d.ts.map +1 -1
  8. package/dist/fields/ThemeColorPickerField.js +131 -13
  9. package/dist/fields/ThemeColorPickerField.js.map +1 -1
  10. package/dist/fields/ThemeLivePreview.css +190 -0
  11. package/dist/fields/ThemeLivePreview.d.ts +4 -0
  12. package/dist/fields/ThemeLivePreview.d.ts.map +1 -0
  13. package/dist/fields/ThemeLivePreview.js +199 -0
  14. package/dist/fields/ThemeLivePreview.js.map +1 -0
  15. package/dist/fields/extendedThemeFields.d.ts +121 -9
  16. package/dist/fields/extendedThemeFields.d.ts.map +1 -1
  17. package/dist/fields/extendedThemeFields.js +296 -101
  18. package/dist/fields/extendedThemeFields.js.map +1 -1
  19. package/dist/fields/themeConfigurationField.d.ts.map +1 -1
  20. package/dist/fields/themeConfigurationField.js +259 -252
  21. package/dist/fields/themeConfigurationField.js.map +1 -1
  22. package/dist/index.d.ts +2 -1
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +24 -2
  25. package/dist/index.js.map +1 -1
  26. package/dist/tweakcn-presets.d.ts +10 -0
  27. package/dist/tweakcn-presets.d.ts.map +1 -0
  28. package/dist/tweakcn-presets.js +714 -0
  29. package/dist/tweakcn-presets.js.map +1 -0
  30. package/dist/tweakcn-special-themes.d.ts +8 -0
  31. package/dist/tweakcn-special-themes.d.ts.map +1 -0
  32. package/dist/tweakcn-special-themes.js +614 -0
  33. package/dist/tweakcn-special-themes.js.map +1 -0
  34. package/dist/views/ThemePreviewView.d.ts +8 -0
  35. package/dist/views/ThemePreviewView.d.ts.map +1 -0
  36. package/dist/views/ThemePreviewView.js +44 -0
  37. package/dist/views/ThemePreviewView.js.map +1 -0
  38. package/dist/views/ThemePreviewViewClient.d.ts +7 -0
  39. package/dist/views/ThemePreviewViewClient.d.ts.map +1 -0
  40. package/dist/views/ThemePreviewViewClient.js +12 -0
  41. package/dist/views/ThemePreviewViewClient.js.map +1 -0
  42. package/package.json +7 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ThemeColorPickerField.d.ts","sourceRoot":"","sources":["../../src/fields/ThemeColorPickerField.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAA;AAEvD,OAAO,6BAA6B,CAAA;AAkBpC,QAAA,MAAM,qBAAqB,EAAE,wBA8H5B,CAAA;AAED,eAAe,qBAAqB,CAAA"}
1
+ {"version":3,"file":"ThemeColorPickerField.d.ts","sourceRoot":"","sources":["../../src/fields/ThemeColorPickerField.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAA;AAGvD,OAAO,6BAA6B,CAAA;AAyFpC,QAAA,MAAM,qBAAqB,EAAE,wBA8K5B,CAAA;AAED,eAAe,qBAAqB,CAAA"}
@@ -1,7 +1,8 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useField, useFormFields } from '@payloadcms/ui';
4
- import { useEffect, useMemo, useState } from 'react';
4
+ import { useEffect, useMemo, useState, useCallback, useRef } from 'react';
5
+ import { HexColorPicker, HexColorInput } from 'react-colorful';
5
6
  import './ThemeColorPickerField.css';
6
7
  function resolveLocalizedValue(value, fallback) {
7
8
  if (typeof value === 'string') {
@@ -16,19 +17,96 @@ function resolveLocalizedValue(value, fallback) {
16
17
  }
17
18
  return fallback;
18
19
  }
20
+ /**
21
+ * Convert various color formats to HEX for the color picker
22
+ */ function toHex(color) {
23
+ if (!color) return '#000000';
24
+ // Already hex
25
+ if (color.startsWith('#')) return color;
26
+ // OKLCH format - extract hue and convert to approximate hex
27
+ if (color.startsWith('oklch')) {
28
+ // For now, return a default - proper conversion requires color-conversion library
29
+ return '#3b82f6' // blue-500 as default
30
+ ;
31
+ }
32
+ // HSL format
33
+ if (color.startsWith('hsl')) {
34
+ const regex = /hsl\((\d+),\s*(\d+)%,\s*(\d+)%\)/;
35
+ const match = regex.exec(color);
36
+ if (match) {
37
+ const [, h, s, l] = match.map(Number);
38
+ return hslToHex(h, s, l);
39
+ }
40
+ }
41
+ return '#000000';
42
+ }
43
+ /**
44
+ * Convert HSL to HEX
45
+ */ function hslToHex(h, s, l) {
46
+ s /= 100;
47
+ l /= 100;
48
+ const c = (1 - Math.abs(2 * l - 1)) * s;
49
+ const x = c * (1 - Math.abs(h / 60 % 2 - 1));
50
+ const m = l - c / 2;
51
+ let r = 0;
52
+ let g = 0;
53
+ let b = 0;
54
+ if (h >= 0 && h < 60) {
55
+ r = c;
56
+ g = x;
57
+ } else if (h >= 60 && h < 120) {
58
+ r = x;
59
+ g = c;
60
+ } else if (h >= 120 && h < 180) {
61
+ g = c;
62
+ b = x;
63
+ } else if (h >= 180 && h < 240) {
64
+ g = x;
65
+ b = c;
66
+ } else if (h >= 240 && h < 300) {
67
+ r = x;
68
+ b = c;
69
+ } else if (h >= 300 && h < 360) {
70
+ r = c;
71
+ b = x;
72
+ }
73
+ const toHex = (n)=>{
74
+ const hex = Math.round((n + m) * 255).toString(16);
75
+ return hex.length === 1 ? '0' + hex : hex;
76
+ };
77
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
78
+ }
19
79
  const ThemeColorPickerField = ({ field, path })=>{
20
80
  const { value, setValue } = useField({
21
81
  path
22
82
  });
23
83
  const [localValue, setLocalValue] = useState(value || '');
84
+ const [showPicker, setShowPicker] = useState(false);
85
+ const [hexValue, setHexValue] = useState(toHex(value || ''));
86
+ const pickerRef = useRef(null);
24
87
  const allFields = useFormFields(([fields])=>fields);
25
88
  const mode = path.includes('lightMode') ? 'lightMode' : 'darkMode';
26
89
  const modePrefix = `themeConfiguration.${mode}`;
27
90
  useEffect(()=>{
28
91
  setLocalValue(value || '');
92
+ setHexValue(toHex(value || ''));
29
93
  }, [
30
94
  value
31
95
  ]);
96
+ // Close picker when clicking outside
97
+ useEffect(()=>{
98
+ function handleClickOutside(event) {
99
+ if (pickerRef.current && !pickerRef.current.contains(event.target)) {
100
+ setShowPicker(false);
101
+ }
102
+ }
103
+ if (showPicker) {
104
+ document.addEventListener('mousedown', handleClickOutside);
105
+ return ()=>document.removeEventListener('mousedown', handleClickOutside);
106
+ }
107
+ }, [
108
+ showPicker
109
+ ]);
32
110
  const colorValues = useMemo(()=>{
33
111
  if (!allFields) {
34
112
  return {};
@@ -64,10 +142,20 @@ const ThemeColorPickerField = ({ field, path })=>{
64
142
  allFields,
65
143
  modePrefix
66
144
  ]);
67
- function handleChange(nextValue) {
145
+ const handleHexChange = useCallback((hex)=>{
146
+ setHexValue(hex);
147
+ setLocalValue(hex);
148
+ setValue(hex);
149
+ }, [
150
+ setValue
151
+ ]);
152
+ const handleTextChange = useCallback((nextValue)=>{
68
153
  setLocalValue(nextValue);
69
154
  setValue(nextValue);
70
- }
155
+ setHexValue(toHex(nextValue));
156
+ }, [
157
+ setValue
158
+ ]);
71
159
  const fieldName = path.split('.').pop() || '';
72
160
  const label = resolveLocalizedValue(field.label, fieldName);
73
161
  const description = resolveLocalizedValue(field.admin?.description, '');
@@ -93,26 +181,56 @@ const ThemeColorPickerField = ({ field, path })=>{
93
181
  /*#__PURE__*/ _jsxs("div", {
94
182
  className: "color-input-wrapper",
95
183
  children: [
96
- /*#__PURE__*/ _jsx("input", {
97
- type: "color",
98
- value: localValue || '#000000',
99
- onChange: (event)=>handleChange(event.target.value),
100
- className: "color-input"
184
+ /*#__PURE__*/ _jsx("button", {
185
+ type: "button",
186
+ className: "color-swatch",
187
+ style: {
188
+ backgroundColor: hexValue
189
+ },
190
+ onClick: ()=>setShowPicker(!showPicker),
191
+ "aria-label": "Open color picker"
101
192
  }),
102
193
  /*#__PURE__*/ _jsx("input", {
103
194
  type: "text",
104
195
  value: localValue || '',
105
- onChange: (event)=>handleChange(event.target.value),
106
- placeholder: "#000000",
107
- className: "text-input",
108
- pattern: "^#[0-9A-Fa-f]{6}$"
196
+ onChange: (event)=>handleTextChange(event.target.value),
197
+ placeholder: "oklch(...) or #hex",
198
+ className: "text-input"
199
+ })
200
+ ]
201
+ }),
202
+ showPicker && /*#__PURE__*/ _jsxs("div", {
203
+ className: "color-picker-popover",
204
+ ref: pickerRef,
205
+ children: [
206
+ /*#__PURE__*/ _jsx(HexColorPicker, {
207
+ color: hexValue,
208
+ onChange: handleHexChange
209
+ }),
210
+ /*#__PURE__*/ _jsxs("div", {
211
+ className: "picker-footer",
212
+ children: [
213
+ /*#__PURE__*/ _jsx(HexColorInput, {
214
+ color: hexValue,
215
+ onChange: handleHexChange,
216
+ prefixed: true,
217
+ placeholder: "#000000",
218
+ className: "hex-input"
219
+ }),
220
+ /*#__PURE__*/ _jsx("button", {
221
+ type: "button",
222
+ onClick: ()=>setShowPicker(false),
223
+ className: "close-button",
224
+ children: "Done"
225
+ })
226
+ ]
109
227
  })
110
228
  ]
111
229
  }),
112
230
  /*#__PURE__*/ _jsx("div", {
113
231
  className: "color-preview",
114
232
  style: {
115
- backgroundColor: localValue || '#000000'
233
+ backgroundColor: hexValue
116
234
  },
117
235
  children: /*#__PURE__*/ _jsx("span", {
118
236
  className: "preview-label",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/fields/ThemeColorPickerField.tsx"],"sourcesContent":["'use client'\n\nimport { useField, useFormFields } from '@payloadcms/ui'\nimport type { TextFieldClientComponent } from 'payload'\nimport { useEffect, useMemo, useState } from 'react'\nimport './ThemeColorPickerField.css'\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\nconst ThemeColorPickerField: TextFieldClientComponent = ({ field, path }) => {\n const { value, setValue } = useField<string>({ path })\n const [localValue, setLocalValue] = useState(value || '')\n const allFields = useFormFields(([fields]) => fields)\n\n const mode = path.includes('lightMode') ? 'lightMode' : 'darkMode'\n const modePrefix = `themeConfiguration.${mode}`\n\n useEffect(() => {\n setLocalValue(value || '')\n }, [value])\n\n const colorValues = useMemo(() => {\n if (!allFields) {\n return {}\n }\n\n const names = [\n 'background',\n 'foreground',\n 'card',\n 'cardForeground',\n 'popover',\n 'popoverForeground',\n 'primary',\n 'primaryForeground',\n 'secondary',\n 'secondaryForeground',\n 'muted',\n 'mutedForeground',\n 'accent',\n 'accentForeground',\n 'destructive',\n 'destructiveForeground',\n 'border',\n 'input',\n 'ring',\n ]\n\n return names.reduce<Record<string, string>>((accumulator, name) => {\n const fieldState = allFields[`${modePrefix}.${name}`]\n const parsedValue = typeof fieldState?.value === 'string' ? fieldState.value : undefined\n accumulator[name] = parsedValue ?? ''\n return accumulator\n }, {})\n }, [allFields, modePrefix])\n\n function handleChange(nextValue: string) {\n setLocalValue(nextValue)\n setValue(nextValue)\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-wrapper\">\n <input\n type=\"color\"\n value={localValue || '#000000'}\n onChange={(event) => handleChange(event.target.value)}\n className=\"color-input\"\n />\n <input\n type=\"text\"\n value={localValue || ''}\n onChange={(event) => handleChange(event.target.value)}\n placeholder=\"#000000\"\n className=\"text-input\"\n pattern=\"^#[0-9A-Fa-f]{6}$\"\n />\n </div>\n\n <div className=\"color-preview\" style={{ backgroundColor: localValue || '#000000' }}>\n <span className=\"preview-label\">{localValue || 'Not set'}</span>\n </div>\n </div>\n\n {(fieldName === 'primary' || fieldName === 'background') && (\n <div\n className=\"mini-preview\"\n style={{\n backgroundColor: colorValues.background || '#ffffff',\n color: colorValues.foreground || '#000000',\n borderColor: colorValues.border || '#e2e8f0',\n }}\n >\n <div\n className=\"preview-card\"\n style={{\n backgroundColor: colorValues.card || '#ffffff',\n color: colorValues.cardForeground || '#000000',\n borderColor: colorValues.border || '#e2e8f0',\n }}\n >\n <button\n className=\"preview-button\"\n style={{\n backgroundColor: colorValues.primary || '#0070f3',\n color: colorValues.primaryForeground || '#ffffff',\n }}\n >\n Primary Button\n </button>\n <button\n className=\"preview-button secondary\"\n style={{\n backgroundColor: colorValues.secondary || '#f1f5f9',\n color: colorValues.secondaryForeground || '#0f172a',\n }}\n >\n Secondary\n </button>\n </div>\n </div>\n )}\n </div>\n )\n}\n\nexport default ThemeColorPickerField\n"],"names":["useField","useFormFields","useEffect","useMemo","useState","resolveLocalizedValue","value","fallback","localized","resolved","en","cs","ThemeColorPickerField","field","path","setValue","localValue","setLocalValue","allFields","fields","mode","includes","modePrefix","colorValues","names","reduce","accumulator","name","fieldState","parsedValue","undefined","handleChange","nextValue","fieldName","split","pop","label","description","admin","div","className","input","type","onChange","event","target","placeholder","pattern","style","backgroundColor","span","background","color","foreground","borderColor","border","card","cardForeground","button","primary","primaryForeground","secondary","secondaryForeground"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/fields/ThemeColorPickerField.tsx"],"sourcesContent":["'use client'\n\nimport { useField, useFormFields } from '@payloadcms/ui'\nimport type { TextFieldClientComponent } from 'payload'\nimport { useEffect, useMemo, useState, useCallback, useRef } from 'react'\nimport { HexColorPicker, HexColorInput } from 'react-colorful'\nimport './ThemeColorPickerField.css'\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 const allFields = useFormFields(([fields]) => fields)\n\n const mode = path.includes('lightMode') ? 'lightMode' : 'darkMode'\n const modePrefix = `themeConfiguration.${mode}`\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 colorValues = useMemo(() => {\n if (!allFields) {\n return {}\n }\n\n const names = [\n 'background',\n 'foreground',\n 'card',\n 'cardForeground',\n 'popover',\n 'popoverForeground',\n 'primary',\n 'primaryForeground',\n 'secondary',\n 'secondaryForeground',\n 'muted',\n 'mutedForeground',\n 'accent',\n 'accentForeground',\n 'destructive',\n 'destructiveForeground',\n 'border',\n 'input',\n 'ring',\n ]\n\n return names.reduce<Record<string, string>>((accumulator, name) => {\n const fieldState = allFields[`${modePrefix}.${name}`]\n const parsedValue = typeof fieldState?.value === 'string' ? fieldState.value : undefined\n accumulator[name] = parsedValue ?? ''\n return accumulator\n }, {})\n }, [allFields, modePrefix])\n\n const handleHexChange = useCallback((hex: string) => {\n setHexValue(hex)\n setLocalValue(hex)\n setValue(hex)\n }, [setValue])\n\n const handleTextChange = useCallback((nextValue: string) => {\n setLocalValue(nextValue)\n setValue(nextValue)\n setHexValue(toHex(nextValue))\n }, [setValue])\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-wrapper\">\n <button\n type=\"button\"\n className=\"color-swatch\"\n style={{ backgroundColor: hexValue }}\n onClick={() => setShowPicker(!showPicker)}\n aria-label=\"Open color picker\"\n />\n <input\n type=\"text\"\n value={localValue || ''}\n onChange={(event) => handleTextChange(event.target.value)}\n placeholder=\"oklch(...) or #hex\"\n className=\"text-input\"\n />\n </div>\n\n {/* Professional Color Picker Popover */}\n {showPicker && (\n <div className=\"color-picker-popover\" ref={pickerRef}>\n <HexColorPicker color={hexValue} onChange={handleHexChange} />\n <div className=\"picker-footer\">\n <HexColorInput\n color={hexValue}\n onChange={handleHexChange}\n prefixed\n placeholder=\"#000000\"\n className=\"hex-input\"\n />\n <button\n type=\"button\"\n onClick={() => setShowPicker(false)}\n className=\"close-button\"\n >\n Done\n </button>\n </div>\n </div>\n )}\n\n <div className=\"color-preview\" style={{ backgroundColor: hexValue }}>\n <span className=\"preview-label\">{localValue || 'Not set'}</span>\n </div>\n </div>\n\n {(fieldName === 'primary' || fieldName === 'background') && (\n <div\n className=\"mini-preview\"\n style={{\n backgroundColor: colorValues.background || '#ffffff',\n color: colorValues.foreground || '#000000',\n borderColor: colorValues.border || '#e2e8f0',\n }}\n >\n <div\n className=\"preview-card\"\n style={{\n backgroundColor: colorValues.card || '#ffffff',\n color: colorValues.cardForeground || '#000000',\n borderColor: colorValues.border || '#e2e8f0',\n }}\n >\n <button\n className=\"preview-button\"\n style={{\n backgroundColor: colorValues.primary || '#0070f3',\n color: colorValues.primaryForeground || '#ffffff',\n }}\n >\n Primary Button\n </button>\n <button\n className=\"preview-button secondary\"\n style={{\n backgroundColor: colorValues.secondary || '#f1f5f9',\n color: colorValues.secondaryForeground || '#0f172a',\n }}\n >\n Secondary\n </button>\n </div>\n </div>\n )}\n </div>\n )\n}\n\nexport default ThemeColorPickerField\n"],"names":["useField","useFormFields","useEffect","useMemo","useState","useCallback","useRef","HexColorPicker","HexColorInput","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","allFields","fields","mode","includes","modePrefix","handleClickOutside","event","current","contains","target","document","addEventListener","removeEventListener","colorValues","names","reduce","accumulator","name","fieldState","parsedValue","undefined","handleHexChange","handleTextChange","nextValue","fieldName","split","pop","label","description","admin","div","className","button","type","style","backgroundColor","onClick","aria-label","input","onChange","placeholder","ref","prefixed","span","background","foreground","borderColor","border","card","cardForeground","primary","primaryForeground","secondary","secondaryForeground"],"mappings":"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"}
@@ -0,0 +1,190 @@
1
+ /* Theme Live Preview Styles */
2
+ .theme-live-preview-container {
3
+ position: sticky;
4
+ top: 0;
5
+ height: 100vh;
6
+ overflow-y: auto;
7
+ background: var(--theme-elevation-50);
8
+ border-left: 1px solid var(--theme-elevation-200);
9
+ }
10
+
11
+ .theme-live-preview-empty {
12
+ display: flex;
13
+ align-items: center;
14
+ justify-content: center;
15
+ height: 100%;
16
+ padding: 2rem;
17
+ color: var(--theme-elevation-400);
18
+ font-size: 0.875rem;
19
+ text-align: center;
20
+ }
21
+
22
+ .preview-header {
23
+ position: sticky;
24
+ top: 0;
25
+ z-index: 10;
26
+ background: var(--theme-elevation-0);
27
+ border-bottom: 1px solid var(--theme-elevation-200);
28
+ padding: 1rem;
29
+ display: flex;
30
+ justify-content: space-between;
31
+ align-items: center;
32
+ }
33
+
34
+ .preview-header h3 {
35
+ margin: 0;
36
+ font-size: 1rem;
37
+ font-weight: 600;
38
+ color: var(--theme-text);
39
+ }
40
+
41
+ .mode-toggle {
42
+ display: flex;
43
+ gap: 0.5rem;
44
+ background: var(--theme-elevation-100);
45
+ padding: 0.25rem;
46
+ border-radius: 8px;
47
+ }
48
+
49
+ .mode-toggle button {
50
+ padding: 0.5rem 1rem;
51
+ border: none;
52
+ background: transparent;
53
+ color: var(--theme-text);
54
+ font-size: 0.875rem;
55
+ font-weight: 500;
56
+ cursor: pointer;
57
+ border-radius: 6px;
58
+ transition: all 0.2s;
59
+ }
60
+
61
+ .mode-toggle button.active {
62
+ background: white;
63
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
64
+ }
65
+
66
+ .preview-content {
67
+ padding: 2rem;
68
+ min-height: calc(100vh - 80px);
69
+ transition: all 0.3s;
70
+ }
71
+
72
+ .preview-section {
73
+ margin-bottom: 2rem;
74
+ }
75
+
76
+ .preview-section h1 {
77
+ font-size: 2rem;
78
+ font-weight: 700;
79
+ margin: 0 0 0.5rem 0;
80
+ }
81
+
82
+ .preview-section p {
83
+ font-size: 1rem;
84
+ margin: 0;
85
+ }
86
+
87
+ .preview-cards {
88
+ display: grid;
89
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
90
+ gap: 1.5rem;
91
+ margin-bottom: 2rem;
92
+ }
93
+
94
+ .preview-card {
95
+ padding: 1.5rem;
96
+ border-radius: 12px;
97
+ border: 2px solid;
98
+ transition: all 0.2s;
99
+ }
100
+
101
+ .preview-card:hover {
102
+ transform: translateY(-2px);
103
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
104
+ }
105
+
106
+ .preview-card h3 {
107
+ margin: 0 0 0.5rem 0;
108
+ font-size: 1.25rem;
109
+ font-weight: 600;
110
+ }
111
+
112
+ .preview-card p {
113
+ margin: 0 0 1rem 0;
114
+ font-size: 0.875rem;
115
+ }
116
+
117
+ .preview-btn-primary,
118
+ .preview-btn-secondary,
119
+ .preview-btn-destructive {
120
+ padding: 0.625rem 1.25rem;
121
+ border: none;
122
+ border-radius: 8px;
123
+ font-weight: 600;
124
+ font-size: 0.875rem;
125
+ cursor: pointer;
126
+ transition: all 0.2s;
127
+ }
128
+
129
+ .preview-btn-primary:hover,
130
+ .preview-btn-secondary:hover,
131
+ .preview-btn-destructive:hover {
132
+ opacity: 0.9;
133
+ transform: translateY(-1px);
134
+ }
135
+
136
+ .preview-ui-elements {
137
+ display: flex;
138
+ gap: 1rem;
139
+ align-items: center;
140
+ flex-wrap: wrap;
141
+ margin-bottom: 2rem;
142
+ }
143
+
144
+ .preview-input {
145
+ padding: 0.625rem 1rem;
146
+ border: 2px solid;
147
+ border-radius: 8px;
148
+ font-size: 0.875rem;
149
+ min-width: 200px;
150
+ transition: all 0.2s;
151
+ }
152
+
153
+ .preview-input:focus {
154
+ outline: none;
155
+ border-color: var(--preview-ring, #3b82f6);
156
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
157
+ }
158
+
159
+ .preview-badge {
160
+ padding: 0.375rem 0.875rem;
161
+ border-radius: 6px;
162
+ font-size: 0.75rem;
163
+ font-weight: 600;
164
+ text-transform: uppercase;
165
+ letter-spacing: 0.05em;
166
+ }
167
+
168
+ .preview-muted {
169
+ padding: 1.5rem;
170
+ border-radius: 8px;
171
+ margin-bottom: 2rem;
172
+ }
173
+
174
+ .preview-muted p {
175
+ margin: 0;
176
+ font-size: 0.875rem;
177
+ }
178
+
179
+ /* Dark mode adjustments */
180
+ .theme-live-preview-container[data-mode="dark"] .preview-content {
181
+ background: #1a1a1a;
182
+ }
183
+
184
+ .theme-live-preview-container[data-mode="dark"] .preview-card {
185
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
186
+ }
187
+
188
+ .theme-live-preview-container[data-mode="dark"] .preview-card:hover {
189
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
190
+ }
@@ -0,0 +1,4 @@
1
+ import './ThemeLivePreview.css';
2
+ export declare const ThemeLivePreview: () => import("react").JSX.Element;
3
+ export default ThemeLivePreview;
4
+ //# sourceMappingURL=ThemeLivePreview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ThemeLivePreview.d.ts","sourceRoot":"","sources":["../../src/fields/ThemeLivePreview.tsx"],"names":[],"mappings":"AAUA,OAAO,wBAAwB,CAAA;AAE/B,eAAO,MAAM,gBAAgB,mCA2K5B,CAAA;AAED,eAAe,gBAAgB,CAAA"}
@@ -0,0 +1,199 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ /**
4
+ * Theme Live Preview Component
5
+ * Real-time preview of theme configuration
6
+ * Inspired by Payload CMS 3 Live Preview
7
+ */ import { useFormFields } from '@payloadcms/ui';
8
+ import { useEffect, useState } from 'react';
9
+ import './ThemeLivePreview.css';
10
+ export const ThemeLivePreview = ()=>{
11
+ const allFields = useFormFields(([fields])=>fields);
12
+ const [previewMode, setPreviewMode] = useState('light');
13
+ const themeConfig = allFields?.themeConfiguration?.value;
14
+ // Extract colors from theme configuration
15
+ // Support both basic (lightMode/darkMode) and extended (extendedLightMode/extendedDarkMode)
16
+ const lightMode = themeConfig?.extendedLightMode || themeConfig?.lightMode;
17
+ const darkMode = themeConfig?.extendedDarkMode || themeConfig?.darkMode;
18
+ const activeMode = previewMode === 'light' ? lightMode : darkMode;
19
+ // Apply theme colors to preview
20
+ useEffect(()=>{
21
+ if (!activeMode) return;
22
+ const root = document.documentElement;
23
+ Object.entries(activeMode).forEach(([key, value])=>{
24
+ if (typeof value === 'string') {
25
+ root.style.setProperty(`--preview-${key}`, value);
26
+ }
27
+ });
28
+ }, [
29
+ activeMode
30
+ ]);
31
+ if (!themeConfig) {
32
+ return /*#__PURE__*/ _jsx("div", {
33
+ className: "theme-live-preview-empty",
34
+ children: /*#__PURE__*/ _jsx("p", {
35
+ children: "Configure your theme to see live preview"
36
+ })
37
+ });
38
+ }
39
+ return /*#__PURE__*/ _jsxs("div", {
40
+ className: "theme-live-preview-container",
41
+ "data-mode": previewMode,
42
+ children: [
43
+ /*#__PURE__*/ _jsxs("div", {
44
+ className: "preview-header",
45
+ children: [
46
+ /*#__PURE__*/ _jsx("h3", {
47
+ children: "Live Theme Preview"
48
+ }),
49
+ /*#__PURE__*/ _jsxs("div", {
50
+ className: "mode-toggle",
51
+ children: [
52
+ /*#__PURE__*/ _jsx("button", {
53
+ type: "button",
54
+ className: previewMode === 'light' ? 'active' : '',
55
+ onClick: ()=>setPreviewMode('light'),
56
+ children: "☀️ Light"
57
+ }),
58
+ /*#__PURE__*/ _jsx("button", {
59
+ type: "button",
60
+ className: previewMode === 'dark' ? 'active' : '',
61
+ onClick: ()=>setPreviewMode('dark'),
62
+ children: "🌙 Dark"
63
+ })
64
+ ]
65
+ })
66
+ ]
67
+ }),
68
+ /*#__PURE__*/ _jsxs("div", {
69
+ className: "preview-content",
70
+ style: {
71
+ backgroundColor: activeMode?.background || '#ffffff',
72
+ color: activeMode?.foreground || '#000000'
73
+ },
74
+ children: [
75
+ /*#__PURE__*/ _jsxs("div", {
76
+ className: "preview-section",
77
+ children: [
78
+ /*#__PURE__*/ _jsx("h1", {
79
+ style: {
80
+ color: activeMode?.foreground
81
+ },
82
+ children: "Welcome to Your Site"
83
+ }),
84
+ /*#__PURE__*/ _jsx("p", {
85
+ style: {
86
+ color: activeMode?.mutedForeground
87
+ },
88
+ children: "This is a live preview of your theme configuration"
89
+ })
90
+ ]
91
+ }),
92
+ /*#__PURE__*/ _jsxs("div", {
93
+ className: "preview-cards",
94
+ children: [
95
+ /*#__PURE__*/ _jsxs("div", {
96
+ className: "preview-card",
97
+ style: {
98
+ backgroundColor: activeMode?.card || '#ffffff',
99
+ color: activeMode?.cardForeground || '#000000',
100
+ borderColor: activeMode?.border || '#e2e8f0'
101
+ },
102
+ children: [
103
+ /*#__PURE__*/ _jsx("h3", {
104
+ children: "Featured Content"
105
+ }),
106
+ /*#__PURE__*/ _jsx("p", {
107
+ style: {
108
+ color: activeMode?.mutedForeground
109
+ },
110
+ children: "Card component with theme colors"
111
+ }),
112
+ /*#__PURE__*/ _jsx("button", {
113
+ className: "preview-btn-primary",
114
+ style: {
115
+ backgroundColor: activeMode?.primary || '#0070f3',
116
+ color: activeMode?.primaryForeground || '#ffffff'
117
+ },
118
+ children: "Primary Action"
119
+ })
120
+ ]
121
+ }),
122
+ /*#__PURE__*/ _jsxs("div", {
123
+ className: "preview-card",
124
+ style: {
125
+ backgroundColor: activeMode?.card || '#ffffff',
126
+ color: activeMode?.cardForeground || '#000000',
127
+ borderColor: activeMode?.border || '#e2e8f0'
128
+ },
129
+ children: [
130
+ /*#__PURE__*/ _jsx("h3", {
131
+ children: "Secondary Card"
132
+ }),
133
+ /*#__PURE__*/ _jsx("p", {
134
+ style: {
135
+ color: activeMode?.mutedForeground
136
+ },
137
+ children: "Another card to showcase your theme"
138
+ }),
139
+ /*#__PURE__*/ _jsx("button", {
140
+ className: "preview-btn-secondary",
141
+ style: {
142
+ backgroundColor: activeMode?.secondary || '#f1f5f9',
143
+ color: activeMode?.secondaryForeground || '#0f172a'
144
+ },
145
+ children: "Secondary"
146
+ })
147
+ ]
148
+ })
149
+ ]
150
+ }),
151
+ /*#__PURE__*/ _jsxs("div", {
152
+ className: "preview-ui-elements",
153
+ children: [
154
+ /*#__PURE__*/ _jsx("input", {
155
+ type: "text",
156
+ placeholder: "Input field",
157
+ className: "preview-input",
158
+ style: {
159
+ backgroundColor: activeMode?.background,
160
+ color: activeMode?.foreground,
161
+ borderColor: activeMode?.input || activeMode?.border
162
+ }
163
+ }),
164
+ /*#__PURE__*/ _jsx("div", {
165
+ className: "preview-badge",
166
+ style: {
167
+ backgroundColor: activeMode?.accent || '#f1f5f9',
168
+ color: activeMode?.accentForeground || '#0f172a'
169
+ },
170
+ children: "Accent Badge"
171
+ }),
172
+ /*#__PURE__*/ _jsx("button", {
173
+ className: "preview-btn-destructive",
174
+ style: {
175
+ backgroundColor: activeMode?.destructive || '#ef4444',
176
+ color: activeMode?.destructiveForeground || '#ffffff'
177
+ },
178
+ children: "Destructive"
179
+ })
180
+ ]
181
+ }),
182
+ /*#__PURE__*/ _jsx("div", {
183
+ className: "preview-muted",
184
+ style: {
185
+ backgroundColor: activeMode?.muted || '#f1f5f9',
186
+ color: activeMode?.mutedForeground || '#64748b'
187
+ },
188
+ children: /*#__PURE__*/ _jsx("p", {
189
+ children: "Muted background section for less prominent content"
190
+ })
191
+ })
192
+ ]
193
+ })
194
+ ]
195
+ });
196
+ };
197
+ export default ThemeLivePreview;
198
+
199
+ //# sourceMappingURL=ThemeLivePreview.js.map