@nuasite/cms 0.1.0
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 +237 -0
- package/dist/src/build-processor.d.ts +20 -0
- package/dist/src/build-processor.d.ts.map +1 -0
- package/dist/src/collection-scanner.d.ts +6 -0
- package/dist/src/collection-scanner.d.ts.map +1 -0
- package/dist/src/component-registry.d.ts +63 -0
- package/dist/src/component-registry.d.ts.map +1 -0
- package/dist/src/config.d.ts +24 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/dev-middleware.d.ts +20 -0
- package/dist/src/dev-middleware.d.ts.map +1 -0
- package/dist/src/editor/ai.d.ts +60 -0
- package/dist/src/editor/ai.d.ts.map +1 -0
- package/dist/src/editor/api.d.ts +140 -0
- package/dist/src/editor/api.d.ts.map +1 -0
- package/dist/src/editor/color-utils.d.ts +106 -0
- package/dist/src/editor/color-utils.d.ts.map +1 -0
- package/dist/src/editor/components/ai-chat.d.ts +11 -0
- package/dist/src/editor/components/ai-chat.d.ts.map +1 -0
- package/dist/src/editor/components/ai-tooltip.d.ts +12 -0
- package/dist/src/editor/components/ai-tooltip.d.ts.map +1 -0
- package/dist/src/editor/components/attribute-editor.d.ts +5 -0
- package/dist/src/editor/components/attribute-editor.d.ts.map +1 -0
- package/dist/src/editor/components/block-editor.d.ts +12 -0
- package/dist/src/editor/components/block-editor.d.ts.map +1 -0
- package/dist/src/editor/components/collections-browser.d.ts +2 -0
- package/dist/src/editor/components/collections-browser.d.ts.map +1 -0
- package/dist/src/editor/components/color-toolbar.d.ts +12 -0
- package/dist/src/editor/components/color-toolbar.d.ts.map +1 -0
- package/dist/src/editor/components/confirm-dialog.d.ts +2 -0
- package/dist/src/editor/components/confirm-dialog.d.ts.map +1 -0
- package/dist/src/editor/components/create-page-modal.d.ts +2 -0
- package/dist/src/editor/components/create-page-modal.d.ts.map +1 -0
- package/dist/src/editor/components/editable-highlights.d.ts +9 -0
- package/dist/src/editor/components/editable-highlights.d.ts.map +1 -0
- package/dist/src/editor/components/error-boundary.d.ts +32 -0
- package/dist/src/editor/components/error-boundary.d.ts.map +1 -0
- package/dist/src/editor/components/fields.d.ts +75 -0
- package/dist/src/editor/components/fields.d.ts.map +1 -0
- package/dist/src/editor/components/frontmatter-fields.d.ts +29 -0
- package/dist/src/editor/components/frontmatter-fields.d.ts.map +1 -0
- package/dist/src/editor/components/highlight-overlay.d.ts +64 -0
- package/dist/src/editor/components/highlight-overlay.d.ts.map +1 -0
- package/dist/src/editor/components/image-overlay.d.ts +12 -0
- package/dist/src/editor/components/image-overlay.d.ts.map +1 -0
- package/dist/src/editor/components/markdown-editor-overlay.d.ts +6 -0
- package/dist/src/editor/components/markdown-editor-overlay.d.ts.map +1 -0
- package/dist/src/editor/components/markdown-inline-editor.d.ts +10 -0
- package/dist/src/editor/components/markdown-inline-editor.d.ts.map +1 -0
- package/dist/src/editor/components/media-library.d.ts +2 -0
- package/dist/src/editor/components/media-library.d.ts.map +1 -0
- package/dist/src/editor/components/outline.d.ts +21 -0
- package/dist/src/editor/components/outline.d.ts.map +1 -0
- package/dist/src/editor/components/redirect-countdown.d.ts +2 -0
- package/dist/src/editor/components/redirect-countdown.d.ts.map +1 -0
- package/dist/src/editor/components/seo-editor.d.ts +2 -0
- package/dist/src/editor/components/seo-editor.d.ts.map +1 -0
- package/dist/src/editor/components/text-style-toolbar.d.ts +8 -0
- package/dist/src/editor/components/text-style-toolbar.d.ts.map +1 -0
- package/dist/src/editor/components/toast/toast-container.d.ts +7 -0
- package/dist/src/editor/components/toast/toast-container.d.ts.map +1 -0
- package/dist/src/editor/components/toast/toast.d.ts +7 -0
- package/dist/src/editor/components/toast/toast.d.ts.map +1 -0
- package/dist/src/editor/components/toast/types.d.ts +7 -0
- package/dist/src/editor/components/toast/types.d.ts.map +1 -0
- package/dist/src/editor/components/toolbar.d.ts +21 -0
- package/dist/src/editor/components/toolbar.d.ts.map +1 -0
- package/dist/src/editor/config.d.ts +4 -0
- package/dist/src/editor/config.d.ts.map +1 -0
- package/dist/src/editor/constants.d.ts +101 -0
- package/dist/src/editor/constants.d.ts.map +1 -0
- package/dist/src/editor/context.d.ts +14 -0
- package/dist/src/editor/context.d.ts.map +1 -0
- package/dist/src/editor/dom.d.ts +77 -0
- package/dist/src/editor/dom.d.ts.map +1 -0
- package/dist/src/editor/editor.d.ts +64 -0
- package/dist/src/editor/editor.d.ts.map +1 -0
- package/dist/src/editor/history.d.ts +20 -0
- package/dist/src/editor/history.d.ts.map +1 -0
- package/dist/src/editor/hooks/index.d.ts +14 -0
- package/dist/src/editor/hooks/index.d.ts.map +1 -0
- package/dist/src/editor/hooks/useAIHandlers.d.ts +22 -0
- package/dist/src/editor/hooks/useAIHandlers.d.ts.map +1 -0
- package/dist/src/editor/hooks/useBlockEditorHandlers.d.ts +18 -0
- package/dist/src/editor/hooks/useBlockEditorHandlers.d.ts.map +1 -0
- package/dist/src/editor/hooks/useElementDetection.d.ts +26 -0
- package/dist/src/editor/hooks/useElementDetection.d.ts.map +1 -0
- package/dist/src/editor/hooks/useImageHoverDetection.d.ts +12 -0
- package/dist/src/editor/hooks/useImageHoverDetection.d.ts.map +1 -0
- package/dist/src/editor/hooks/useTextSelection.d.ts +23 -0
- package/dist/src/editor/hooks/useTextSelection.d.ts.map +1 -0
- package/dist/src/editor/hooks/useTooltipState.d.ts +19 -0
- package/dist/src/editor/hooks/useTooltipState.d.ts.map +1 -0
- package/dist/src/editor/hooks/utils.d.ts +32 -0
- package/dist/src/editor/hooks/utils.d.ts.map +1 -0
- package/dist/src/editor/index.d.ts +12 -0
- package/dist/src/editor/index.d.ts.map +1 -0
- package/dist/src/editor/lib/cn.d.ts +3 -0
- package/dist/src/editor/lib/cn.d.ts.map +1 -0
- package/dist/src/editor/manifest.d.ts +19 -0
- package/dist/src/editor/manifest.d.ts.map +1 -0
- package/dist/src/editor/markdown-api.d.ts +36 -0
- package/dist/src/editor/markdown-api.d.ts.map +1 -0
- package/dist/src/editor/signals.d.ts +242 -0
- package/dist/src/editor/signals.d.ts.map +1 -0
- package/dist/src/editor/storage.d.ts +27 -0
- package/dist/src/editor/storage.d.ts.map +1 -0
- package/dist/src/editor/text-styling.d.ts +350 -0
- package/dist/src/editor/text-styling.d.ts.map +1 -0
- package/dist/src/editor/themes.d.ts +38 -0
- package/dist/src/editor/themes.d.ts.map +1 -0
- package/dist/src/editor/types.d.ts +454 -0
- package/dist/src/editor/types.d.ts.map +1 -0
- package/dist/src/error-collector.d.ts +56 -0
- package/dist/src/error-collector.d.ts.map +1 -0
- package/dist/src/handlers/component-ops.d.ts +34 -0
- package/dist/src/handlers/component-ops.d.ts.map +1 -0
- package/dist/src/handlers/markdown-ops.d.ts +41 -0
- package/dist/src/handlers/markdown-ops.d.ts.map +1 -0
- package/dist/src/handlers/request-utils.d.ts +20 -0
- package/dist/src/handlers/request-utils.d.ts.map +1 -0
- package/dist/src/handlers/source-writer.d.ts +51 -0
- package/dist/src/handlers/source-writer.d.ts.map +1 -0
- package/dist/src/html-processor.d.ts +63 -0
- package/dist/src/html-processor.d.ts.map +1 -0
- package/dist/src/index.d.ts +41 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/manifest-writer.d.ts +111 -0
- package/dist/src/manifest-writer.d.ts.map +1 -0
- package/dist/src/media/contember.d.ts +15 -0
- package/dist/src/media/contember.d.ts.map +1 -0
- package/dist/src/media/local.d.ts +9 -0
- package/dist/src/media/local.d.ts.map +1 -0
- package/dist/src/media/s3.d.ts +12 -0
- package/dist/src/media/s3.d.ts.map +1 -0
- package/dist/src/media/types.d.ts +40 -0
- package/dist/src/media/types.d.ts.map +1 -0
- package/dist/src/preview-generator.d.ts +19 -0
- package/dist/src/preview-generator.d.ts.map +1 -0
- package/dist/src/seo-processor.d.ts +23 -0
- package/dist/src/seo-processor.d.ts.map +1 -0
- package/dist/src/source-finder/ast-extractors.d.ts +35 -0
- package/dist/src/source-finder/ast-extractors.d.ts.map +1 -0
- package/dist/src/source-finder/ast-parser.d.ts +16 -0
- package/dist/src/source-finder/ast-parser.d.ts.map +1 -0
- package/dist/src/source-finder/cache.d.ts +18 -0
- package/dist/src/source-finder/cache.d.ts.map +1 -0
- package/dist/src/source-finder/collection-finder.d.ts +29 -0
- package/dist/src/source-finder/collection-finder.d.ts.map +1 -0
- package/dist/src/source-finder/cross-file-tracker.d.ts +39 -0
- package/dist/src/source-finder/cross-file-tracker.d.ts.map +1 -0
- package/dist/src/source-finder/element-finder.d.ts +42 -0
- package/dist/src/source-finder/element-finder.d.ts.map +1 -0
- package/dist/src/source-finder/image-finder.d.ts +24 -0
- package/dist/src/source-finder/image-finder.d.ts.map +1 -0
- package/dist/src/source-finder/index.d.ts +9 -0
- package/dist/src/source-finder/index.d.ts.map +1 -0
- package/dist/src/source-finder/search-index.d.ts +27 -0
- package/dist/src/source-finder/search-index.d.ts.map +1 -0
- package/dist/src/source-finder/snippet-utils.d.ts +90 -0
- package/dist/src/source-finder/snippet-utils.d.ts.map +1 -0
- package/dist/src/source-finder/source-lookup.d.ts +16 -0
- package/dist/src/source-finder/source-lookup.d.ts.map +1 -0
- package/dist/src/source-finder/types.d.ts +167 -0
- package/dist/src/source-finder/types.d.ts.map +1 -0
- package/dist/src/source-finder/variable-extraction.d.ts +37 -0
- package/dist/src/source-finder/variable-extraction.d.ts.map +1 -0
- package/dist/src/tailwind-colors.d.ts +54 -0
- package/dist/src/tailwind-colors.d.ts.map +1 -0
- package/dist/src/tsconfig.tsbuildinfo +1 -0
- package/dist/src/types.d.ts +367 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/utils.d.ts +61 -0
- package/dist/src/utils.d.ts.map +1 -0
- package/dist/src/vite-plugin.d.ts +14 -0
- package/dist/src/vite-plugin.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/package.json +80 -0
- package/src/build-processor.ts +784 -0
- package/src/collection-scanner.ts +304 -0
- package/src/component-registry.ts +393 -0
- package/src/config.ts +74 -0
- package/src/dev-middleware.ts +525 -0
- package/src/dist/src/tsconfig.tsbuildinfo +1 -0
- package/src/editor/ai.ts +185 -0
- package/src/editor/api.ts +513 -0
- package/src/editor/color-utils.ts +556 -0
- package/src/editor/components/ai-chat.tsx +632 -0
- package/src/editor/components/ai-tooltip.tsx +179 -0
- package/src/editor/components/attribute-editor.tsx +596 -0
- package/src/editor/components/block-editor.tsx +546 -0
- package/src/editor/components/collections-browser.tsx +248 -0
- package/src/editor/components/color-toolbar.tsx +314 -0
- package/src/editor/components/confirm-dialog.tsx +69 -0
- package/src/editor/components/create-page-modal.tsx +163 -0
- package/src/editor/components/editable-highlights.tsx +260 -0
- package/src/editor/components/error-boundary.tsx +87 -0
- package/src/editor/components/fields.tsx +387 -0
- package/src/editor/components/frontmatter-fields.tsx +469 -0
- package/src/editor/components/highlight-overlay.ts +229 -0
- package/src/editor/components/image-overlay.tsx +230 -0
- package/src/editor/components/markdown-editor-overlay.tsx +505 -0
- package/src/editor/components/markdown-inline-editor.tsx +780 -0
- package/src/editor/components/media-library.tsx +297 -0
- package/src/editor/components/outline.tsx +402 -0
- package/src/editor/components/redirect-countdown.tsx +45 -0
- package/src/editor/components/seo-editor.tsx +498 -0
- package/src/editor/components/text-style-toolbar.tsx +362 -0
- package/src/editor/components/toast/toast-container.tsx +15 -0
- package/src/editor/components/toast/toast.tsx +49 -0
- package/src/editor/components/toast/types.ts +7 -0
- package/src/editor/components/toolbar.tsx +366 -0
- package/src/editor/config.ts +12 -0
- package/src/editor/constants.ts +106 -0
- package/src/editor/context.tsx +38 -0
- package/src/editor/dom.ts +357 -0
- package/src/editor/editor.ts +1510 -0
- package/src/editor/env.d.ts +4 -0
- package/src/editor/history.ts +355 -0
- package/src/editor/hooks/index.ts +19 -0
- package/src/editor/hooks/useAIHandlers.ts +345 -0
- package/src/editor/hooks/useBlockEditorHandlers.ts +206 -0
- package/src/editor/hooks/useElementDetection.ts +284 -0
- package/src/editor/hooks/useImageHoverDetection.ts +102 -0
- package/src/editor/hooks/useTextSelection.ts +187 -0
- package/src/editor/hooks/useTooltipState.ts +126 -0
- package/src/editor/hooks/utils.ts +101 -0
- package/src/editor/index.tsx +481 -0
- package/src/editor/lib/cn.ts +4 -0
- package/src/editor/manifest.ts +25 -0
- package/src/editor/markdown-api.ts +209 -0
- package/src/editor/signals.ts +1351 -0
- package/src/editor/storage.ts +266 -0
- package/src/editor/styles.css +465 -0
- package/src/editor/text-styling.ts +773 -0
- package/src/editor/themes.ts +210 -0
- package/src/editor/types.ts +591 -0
- package/src/error-collector.ts +106 -0
- package/src/handlers/component-ops.ts +463 -0
- package/src/handlers/markdown-ops.ts +202 -0
- package/src/handlers/request-utils.ts +151 -0
- package/src/handlers/source-writer.ts +649 -0
- package/src/html-processor.ts +1108 -0
- package/src/index.ts +284 -0
- package/src/manifest-writer.ts +371 -0
- package/src/media/contember.ts +84 -0
- package/src/media/local.ts +114 -0
- package/src/media/s3.ts +133 -0
- package/src/media/types.ts +33 -0
- package/src/preview-generator.ts +293 -0
- package/src/seo-processor.ts +567 -0
- package/src/source-finder/ast-extractors.ts +185 -0
- package/src/source-finder/ast-parser.ts +150 -0
- package/src/source-finder/cache.ts +76 -0
- package/src/source-finder/collection-finder.ts +335 -0
- package/src/source-finder/cross-file-tracker.ts +741 -0
- package/src/source-finder/element-finder.ts +387 -0
- package/src/source-finder/image-finder.ts +283 -0
- package/src/source-finder/index.ts +37 -0
- package/src/source-finder/search-index.ts +525 -0
- package/src/source-finder/snippet-utils.ts +668 -0
- package/src/source-finder/source-lookup.ts +200 -0
- package/src/source-finder/types.ts +210 -0
- package/src/source-finder/variable-extraction.ts +406 -0
- package/src/tailwind-colors.ts +874 -0
- package/src/tsconfig.json +25 -0
- package/src/types.ts +406 -0
- package/src/utils.ts +186 -0
- package/src/vite-plugin.ts +42 -0
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
import type { Attribute, AvailableColors, TailwindColor } from './types'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Default Tailwind CSS v4 color names.
|
|
5
|
+
*/
|
|
6
|
+
export const DEFAULT_TAILWIND_COLORS = [
|
|
7
|
+
'slate',
|
|
8
|
+
'gray',
|
|
9
|
+
'zinc',
|
|
10
|
+
'neutral',
|
|
11
|
+
'stone',
|
|
12
|
+
'red',
|
|
13
|
+
'orange',
|
|
14
|
+
'amber',
|
|
15
|
+
'yellow',
|
|
16
|
+
'lime',
|
|
17
|
+
'green',
|
|
18
|
+
'emerald',
|
|
19
|
+
'teal',
|
|
20
|
+
'cyan',
|
|
21
|
+
'sky',
|
|
22
|
+
'blue',
|
|
23
|
+
'indigo',
|
|
24
|
+
'violet',
|
|
25
|
+
'purple',
|
|
26
|
+
'fuchsia',
|
|
27
|
+
'pink',
|
|
28
|
+
'rose',
|
|
29
|
+
] as const
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Standard Tailwind color shades.
|
|
33
|
+
*/
|
|
34
|
+
export const STANDARD_SHADES = ['50', '100', '200', '300', '400', '500', '600', '700', '800', '900', '950'] as const
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Special color values that don't have shades.
|
|
38
|
+
*/
|
|
39
|
+
export const SPECIAL_COLORS = ['transparent', 'current', 'inherit', 'white', 'black'] as const
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Map of Tailwind color names to their CSS color values for preview.
|
|
43
|
+
* Uses the 500 shade as the representative color.
|
|
44
|
+
* This is a fallback when availableColors is not loaded yet.
|
|
45
|
+
*/
|
|
46
|
+
export const COLOR_PREVIEW_MAP: Record<string, string> = {
|
|
47
|
+
// Special colors
|
|
48
|
+
transparent: 'transparent',
|
|
49
|
+
current: 'currentColor',
|
|
50
|
+
inherit: 'inherit',
|
|
51
|
+
white: '#ffffff',
|
|
52
|
+
black: '#000000',
|
|
53
|
+
// Standard colors (500 shade)
|
|
54
|
+
slate: '#64748b',
|
|
55
|
+
gray: '#6b7280',
|
|
56
|
+
zinc: '#71717a',
|
|
57
|
+
neutral: '#737373',
|
|
58
|
+
stone: '#78716c',
|
|
59
|
+
red: '#ef4444',
|
|
60
|
+
orange: '#f97316',
|
|
61
|
+
amber: '#f59e0b',
|
|
62
|
+
yellow: '#eab308',
|
|
63
|
+
lime: '#84cc16',
|
|
64
|
+
green: '#22c55e',
|
|
65
|
+
emerald: '#10b981',
|
|
66
|
+
teal: '#14b8a6',
|
|
67
|
+
cyan: '#06b6d4',
|
|
68
|
+
sky: '#0ea5e9',
|
|
69
|
+
blue: '#3b82f6',
|
|
70
|
+
indigo: '#6366f1',
|
|
71
|
+
violet: '#8b5cf6',
|
|
72
|
+
purple: '#a855f7',
|
|
73
|
+
fuchsia: '#d946ef',
|
|
74
|
+
pink: '#ec4899',
|
|
75
|
+
rose: '#f43f5e',
|
|
76
|
+
// Common custom colors
|
|
77
|
+
primary: '#3b82f6',
|
|
78
|
+
secondary: '#6b7280',
|
|
79
|
+
accent: '#f59e0b',
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Map of shade numbers to their relative lightness.
|
|
84
|
+
* Used to generate preview colors for different shades.
|
|
85
|
+
*/
|
|
86
|
+
export const SHADE_LIGHTNESS: Record<string, number> = {
|
|
87
|
+
'50': 0.95,
|
|
88
|
+
'100': 0.9,
|
|
89
|
+
'200': 0.8,
|
|
90
|
+
'300': 0.7,
|
|
91
|
+
'400': 0.6,
|
|
92
|
+
'500': 0.5,
|
|
93
|
+
'600': 0.4,
|
|
94
|
+
'700': 0.3,
|
|
95
|
+
'800': 0.2,
|
|
96
|
+
'900': 0.1,
|
|
97
|
+
'950': 0.05,
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Non-color text-* utility classes that should NOT be treated as color classes.
|
|
102
|
+
* These are Tailwind utilities like text alignment, sizing, wrapping, etc.
|
|
103
|
+
*/
|
|
104
|
+
const NON_COLOR_TEXT_CLASSES = new Set([
|
|
105
|
+
// Text alignment
|
|
106
|
+
'text-left',
|
|
107
|
+
'text-center',
|
|
108
|
+
'text-right',
|
|
109
|
+
'text-justify',
|
|
110
|
+
'text-start',
|
|
111
|
+
'text-end',
|
|
112
|
+
// Text wrapping
|
|
113
|
+
'text-wrap',
|
|
114
|
+
'text-nowrap',
|
|
115
|
+
'text-balance',
|
|
116
|
+
'text-pretty',
|
|
117
|
+
// Text overflow
|
|
118
|
+
'text-ellipsis',
|
|
119
|
+
'text-clip',
|
|
120
|
+
// Text transform (these don't start with text- but just in case)
|
|
121
|
+
])
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Regex patterns to match Tailwind color classes.
|
|
125
|
+
*/
|
|
126
|
+
const COLOR_CLASS_PATTERNS = {
|
|
127
|
+
bg: /^bg-([a-z]+)(?:-(\d+))?$/,
|
|
128
|
+
text: /^text-([a-z]+)(?:-(\d+))?$/,
|
|
129
|
+
border: /^border-([a-z]+)(?:-(\d+))?$/,
|
|
130
|
+
hoverBg: /^hover:bg-([a-z]+)(?:-(\d+))?$/,
|
|
131
|
+
hoverText: /^hover:text-([a-z]+)(?:-(\d+))?$/,
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Check if a class is a text color class (not a non-color text utility).
|
|
136
|
+
*/
|
|
137
|
+
function isTextColorClass(className: string): boolean {
|
|
138
|
+
if (NON_COLOR_TEXT_CLASSES.has(className)) {
|
|
139
|
+
return false
|
|
140
|
+
}
|
|
141
|
+
return COLOR_CLASS_PATTERNS.text.test(className)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Parse a color class into its components.
|
|
146
|
+
*/
|
|
147
|
+
export function parseColorClass(colorClass: string): {
|
|
148
|
+
prefix: string
|
|
149
|
+
colorName: string
|
|
150
|
+
shade?: string
|
|
151
|
+
isHover: boolean
|
|
152
|
+
} | undefined {
|
|
153
|
+
// Exclude non-color text utility classes
|
|
154
|
+
if (NON_COLOR_TEXT_CLASSES.has(colorClass)) {
|
|
155
|
+
return undefined
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const isHover = colorClass.startsWith('hover:')
|
|
159
|
+
const classWithoutHover = isHover ? colorClass.slice(6) : colorClass
|
|
160
|
+
|
|
161
|
+
// Also check hover variants of non-color text classes
|
|
162
|
+
if (isHover && NON_COLOR_TEXT_CLASSES.has(`text-${classWithoutHover.slice(5)}`)) {
|
|
163
|
+
return undefined
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const match = classWithoutHover.match(/^(bg|text|border)-([a-z]+)(?:-(\d+))?$/)
|
|
167
|
+
|
|
168
|
+
if (!match) return undefined
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
prefix: isHover ? `hover:${match[1]}` : match[1]!,
|
|
172
|
+
colorName: match[2]!,
|
|
173
|
+
shade: match[3],
|
|
174
|
+
isHover,
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Build a color class from components.
|
|
180
|
+
*/
|
|
181
|
+
export function buildColorClass(
|
|
182
|
+
prefix: string,
|
|
183
|
+
colorName: string,
|
|
184
|
+
shade?: string,
|
|
185
|
+
): string {
|
|
186
|
+
if (shade) {
|
|
187
|
+
return `${prefix}-${colorName}-${shade}`
|
|
188
|
+
}
|
|
189
|
+
return `${prefix}-${colorName}`
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Get the color type from a color class.
|
|
194
|
+
*/
|
|
195
|
+
export function getColorType(colorClass: string): keyof typeof COLOR_CLASS_PATTERNS | undefined {
|
|
196
|
+
for (const [key, pattern] of Object.entries(COLOR_CLASS_PATTERNS)) {
|
|
197
|
+
// For text type, use the helper to exclude non-color text utilities
|
|
198
|
+
if (key === 'text' || key === 'hoverText') {
|
|
199
|
+
if (key === 'text' && isTextColorClass(colorClass)) {
|
|
200
|
+
return key as keyof typeof COLOR_CLASS_PATTERNS
|
|
201
|
+
}
|
|
202
|
+
if (key === 'hoverText' && colorClass.startsWith('hover:') && isTextColorClass(colorClass.slice(6))) {
|
|
203
|
+
return key as keyof typeof COLOR_CLASS_PATTERNS
|
|
204
|
+
}
|
|
205
|
+
} else if (pattern.test(colorClass)) {
|
|
206
|
+
return key as keyof typeof COLOR_CLASS_PATTERNS
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return undefined
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Check if a class is a color class.
|
|
214
|
+
*/
|
|
215
|
+
export function isColorClass(className: string): boolean {
|
|
216
|
+
// Check text color separately to exclude non-color text utilities
|
|
217
|
+
if (COLOR_CLASS_PATTERNS.text.test(className)) {
|
|
218
|
+
return isTextColorClass(className)
|
|
219
|
+
}
|
|
220
|
+
if (COLOR_CLASS_PATTERNS.hoverText.test(className)) {
|
|
221
|
+
return isTextColorClass(className.slice(6)) // Remove 'hover:' prefix
|
|
222
|
+
}
|
|
223
|
+
return Object.entries(COLOR_CLASS_PATTERNS)
|
|
224
|
+
.filter(([key]) => key !== 'text' && key !== 'hoverText')
|
|
225
|
+
.some(([, pattern]) => pattern.test(className))
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Get a preview CSS color for a Tailwind color.
|
|
230
|
+
*/
|
|
231
|
+
export function getColorPreview(colorName: string, shade?: string): string {
|
|
232
|
+
// Special colors without shades
|
|
233
|
+
if (SPECIAL_COLORS.includes(colorName as any)) {
|
|
234
|
+
return COLOR_PREVIEW_MAP[colorName] || colorName
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Get base color
|
|
238
|
+
const baseColor = COLOR_PREVIEW_MAP[colorName]
|
|
239
|
+
if (!baseColor) {
|
|
240
|
+
// Unknown color, return a placeholder
|
|
241
|
+
return '#888888'
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// If no shade specified, return the base (500) color
|
|
245
|
+
if (!shade) {
|
|
246
|
+
return baseColor
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// For now, return the base color
|
|
250
|
+
// A more sophisticated implementation would adjust lightness based on shade
|
|
251
|
+
return baseColor
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Resolve a color to its CSS value using availableColors from the manifest.
|
|
256
|
+
*/
|
|
257
|
+
export function resolveColorValue(
|
|
258
|
+
colorName: string,
|
|
259
|
+
shade: string | undefined,
|
|
260
|
+
availableColors: AvailableColors | undefined,
|
|
261
|
+
): string | undefined {
|
|
262
|
+
// Special colors
|
|
263
|
+
if (colorName === 'white') return '#ffffff'
|
|
264
|
+
if (colorName === 'black') return '#000000'
|
|
265
|
+
if (colorName === 'transparent') return 'transparent'
|
|
266
|
+
if (colorName === 'current') return 'currentColor'
|
|
267
|
+
if (colorName === 'inherit') return 'inherit'
|
|
268
|
+
|
|
269
|
+
if (!availableColors) {
|
|
270
|
+
// Fallback to preview map
|
|
271
|
+
return COLOR_PREVIEW_MAP[colorName]
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Find the color in availableColors
|
|
275
|
+
const color = availableColors.colors.find(c => c.name === colorName)
|
|
276
|
+
if (!color) return undefined
|
|
277
|
+
|
|
278
|
+
// Get the value for the shade (or empty string for colors without shades)
|
|
279
|
+
const shadeKey = shade || '500'
|
|
280
|
+
return color.values[shadeKey]
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Replace a color class in an element's class list.
|
|
285
|
+
* Returns the old class that was replaced, or undefined if not found.
|
|
286
|
+
*/
|
|
287
|
+
export function replaceColorClass(
|
|
288
|
+
element: HTMLElement,
|
|
289
|
+
colorType: 'bg' | 'text' | 'border' | 'hoverBg' | 'hoverText',
|
|
290
|
+
newColorName: string,
|
|
291
|
+
newShade?: string,
|
|
292
|
+
): { oldClass: string; newClass: string } | undefined {
|
|
293
|
+
const classes = element.className.split(/\s+/).filter(Boolean)
|
|
294
|
+
const pattern = COLOR_CLASS_PATTERNS[colorType]
|
|
295
|
+
|
|
296
|
+
let oldClass: string | undefined
|
|
297
|
+
const newClasses: string[] = []
|
|
298
|
+
|
|
299
|
+
for (const cls of classes) {
|
|
300
|
+
// For text types, use the helper to exclude non-color text utilities
|
|
301
|
+
let isColorMatch: boolean
|
|
302
|
+
if (colorType === 'text') {
|
|
303
|
+
isColorMatch = isTextColorClass(cls)
|
|
304
|
+
} else if (colorType === 'hoverText') {
|
|
305
|
+
isColorMatch = cls.startsWith('hover:') && isTextColorClass(cls.slice(6))
|
|
306
|
+
} else {
|
|
307
|
+
isColorMatch = pattern.test(cls)
|
|
308
|
+
}
|
|
309
|
+
if (isColorMatch) {
|
|
310
|
+
oldClass = cls
|
|
311
|
+
// Build the new class with the same prefix
|
|
312
|
+
const isHover = colorType.startsWith('hover')
|
|
313
|
+
const prefix = isHover
|
|
314
|
+
? colorType.replace('hover', 'hover:').toLowerCase().replace('hover:bg', 'hover:bg').replace('hover:text', 'hover:text')
|
|
315
|
+
: colorType
|
|
316
|
+
const newClass = buildColorClass(prefix, newColorName, newShade)
|
|
317
|
+
newClasses.push(newClass)
|
|
318
|
+
} else {
|
|
319
|
+
newClasses.push(cls)
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (!oldClass) {
|
|
324
|
+
return undefined
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const newClass = buildColorClass(
|
|
328
|
+
colorType.startsWith('hover') ? `hover:${colorType.slice(5).toLowerCase()}` : colorType,
|
|
329
|
+
newColorName,
|
|
330
|
+
newShade,
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
element.className = newClasses.join(' ')
|
|
334
|
+
|
|
335
|
+
return { oldClass, newClass }
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Get the current color classes from an element as Record<string, Attribute>.
|
|
340
|
+
*/
|
|
341
|
+
export function getElementColorClasses(element: HTMLElement): Record<string, Attribute> {
|
|
342
|
+
const classes = element.className.split(/\s+/).filter(Boolean)
|
|
343
|
+
const colorClasses: Record<string, Attribute> = {}
|
|
344
|
+
|
|
345
|
+
for (const cls of classes) {
|
|
346
|
+
for (const [key, pattern] of Object.entries(COLOR_CLASS_PATTERNS)) {
|
|
347
|
+
// For text types, use the helper to exclude non-color text utilities
|
|
348
|
+
let isColorMatch: boolean
|
|
349
|
+
if (key === 'text') {
|
|
350
|
+
isColorMatch = isTextColorClass(cls)
|
|
351
|
+
} else if (key === 'hoverText') {
|
|
352
|
+
isColorMatch = cls.startsWith('hover:') && isTextColorClass(cls.slice(6))
|
|
353
|
+
} else {
|
|
354
|
+
isColorMatch = pattern.test(cls)
|
|
355
|
+
}
|
|
356
|
+
if (isColorMatch) {
|
|
357
|
+
if (!(key in colorClasses)) {
|
|
358
|
+
colorClasses[key] = { value: cls }
|
|
359
|
+
}
|
|
360
|
+
break
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
return colorClasses
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Inject global hover preview styles once.
|
|
370
|
+
* Uses CSS custom properties with !important to preview hover colors.
|
|
371
|
+
*/
|
|
372
|
+
let hoverStylesInjected = false
|
|
373
|
+
function ensureHoverStyles(): void {
|
|
374
|
+
if (hoverStylesInjected) return
|
|
375
|
+
hoverStylesInjected = true
|
|
376
|
+
|
|
377
|
+
const style = document.createElement('style')
|
|
378
|
+
style.textContent = `
|
|
379
|
+
[data-cms-hover-bg]:hover {
|
|
380
|
+
background-color: var(--cms-hover-bg) !important;
|
|
381
|
+
}
|
|
382
|
+
[data-cms-hover-text]:hover {
|
|
383
|
+
color: var(--cms-hover-text) !important;
|
|
384
|
+
}
|
|
385
|
+
`
|
|
386
|
+
document.head.appendChild(style)
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Apply a color change to an element.
|
|
391
|
+
* Updates the DOM immediately with both class and inline style for preview.
|
|
392
|
+
* The inline style ensures the color is visible even if Tailwind hasn't compiled the class.
|
|
393
|
+
*/
|
|
394
|
+
export function applyColorChange(
|
|
395
|
+
element: HTMLElement,
|
|
396
|
+
colorType: 'bg' | 'text' | 'border' | 'hoverBg' | 'hoverText',
|
|
397
|
+
newColorName: string,
|
|
398
|
+
newShade: string | undefined,
|
|
399
|
+
availableColors: AvailableColors | undefined,
|
|
400
|
+
): { oldClass: string; newClass: string } | undefined {
|
|
401
|
+
const classes = element.className.split(/\s+/).filter(Boolean)
|
|
402
|
+
const pattern = COLOR_CLASS_PATTERNS[colorType]
|
|
403
|
+
|
|
404
|
+
let oldClass: string | undefined
|
|
405
|
+
const newClasses: string[] = []
|
|
406
|
+
|
|
407
|
+
// Determine the new class prefix
|
|
408
|
+
const prefix = colorType === 'hoverBg'
|
|
409
|
+
? 'hover:bg'
|
|
410
|
+
: colorType === 'hoverText'
|
|
411
|
+
? 'hover:text'
|
|
412
|
+
: colorType
|
|
413
|
+
const newClass = buildColorClass(prefix, newColorName, newShade)
|
|
414
|
+
|
|
415
|
+
for (const cls of classes) {
|
|
416
|
+
// For text types, use the helper to exclude non-color text utilities
|
|
417
|
+
let isColorMatch: boolean
|
|
418
|
+
if (colorType === 'text') {
|
|
419
|
+
isColorMatch = isTextColorClass(cls)
|
|
420
|
+
} else if (colorType === 'hoverText') {
|
|
421
|
+
isColorMatch = cls.startsWith('hover:') && isTextColorClass(cls.slice(6))
|
|
422
|
+
} else {
|
|
423
|
+
isColorMatch = pattern.test(cls)
|
|
424
|
+
}
|
|
425
|
+
if (isColorMatch) {
|
|
426
|
+
oldClass = cls
|
|
427
|
+
// Replace with new class
|
|
428
|
+
newClasses.push(newClass)
|
|
429
|
+
} else {
|
|
430
|
+
newClasses.push(cls)
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// If no existing color class was found, add the new one
|
|
435
|
+
if (!oldClass) {
|
|
436
|
+
newClasses.push(newClass)
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
element.className = newClasses.join(' ')
|
|
440
|
+
|
|
441
|
+
// Apply inline style for immediate visual feedback
|
|
442
|
+
// This ensures the color is visible even if Tailwind hasn't compiled the new class
|
|
443
|
+
const cssValue = resolveColorValue(newColorName, newShade, availableColors)
|
|
444
|
+
if (cssValue) {
|
|
445
|
+
// For hover states, use CSS custom properties with global :hover rules
|
|
446
|
+
if (colorType === 'hoverBg') {
|
|
447
|
+
ensureHoverStyles()
|
|
448
|
+
element.dataset.cmsHoverBg = ''
|
|
449
|
+
element.style.setProperty('--cms-hover-bg', cssValue)
|
|
450
|
+
} else if (colorType === 'hoverText') {
|
|
451
|
+
ensureHoverStyles()
|
|
452
|
+
element.dataset.cmsHoverText = ''
|
|
453
|
+
element.style.setProperty('--cms-hover-text', cssValue)
|
|
454
|
+
} else {
|
|
455
|
+
// Map color type to CSS property for non-hover states
|
|
456
|
+
const styleProperty = colorType === 'bg'
|
|
457
|
+
? 'backgroundColor'
|
|
458
|
+
: colorType === 'text'
|
|
459
|
+
? 'color'
|
|
460
|
+
: colorType === 'border'
|
|
461
|
+
? 'borderColor'
|
|
462
|
+
: 'color'
|
|
463
|
+
element.style[styleProperty] = cssValue
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
return { oldClass: oldClass || '', newClass }
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Get popular colors for quick selection.
|
|
472
|
+
* Returns a curated list of commonly used colors.
|
|
473
|
+
*/
|
|
474
|
+
export function getPopularColors(): Array<{ name: string; shade: string; preview: string }> {
|
|
475
|
+
const popularColorNames = ['blue', 'green', 'red', 'purple', 'orange', 'slate', 'black', 'white']
|
|
476
|
+
const popularShades = ['500', '600', '700']
|
|
477
|
+
|
|
478
|
+
const colors: Array<{ name: string; shade: string; preview: string }> = []
|
|
479
|
+
|
|
480
|
+
// Add special colors first
|
|
481
|
+
colors.push({ name: 'white', shade: '', preview: '#ffffff' })
|
|
482
|
+
colors.push({ name: 'black', shade: '', preview: '#000000' })
|
|
483
|
+
|
|
484
|
+
// Add popular color/shade combinations
|
|
485
|
+
for (const name of popularColorNames) {
|
|
486
|
+
if (name === 'white' || name === 'black') continue
|
|
487
|
+
for (const shade of popularShades) {
|
|
488
|
+
colors.push({
|
|
489
|
+
name,
|
|
490
|
+
shade,
|
|
491
|
+
preview: getColorPreview(name, shade),
|
|
492
|
+
})
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
return colors
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Get all available colors with their shades from manifest.
|
|
501
|
+
*/
|
|
502
|
+
export function getAllColorsWithShades(availableColors: AvailableColors | undefined): Array<{
|
|
503
|
+
name: string
|
|
504
|
+
shades: Array<{ shade: string; preview: string }>
|
|
505
|
+
isSpecial: boolean
|
|
506
|
+
}> {
|
|
507
|
+
if (!availableColors) {
|
|
508
|
+
// Return default colors
|
|
509
|
+
const result: Array<{
|
|
510
|
+
name: string
|
|
511
|
+
shades: Array<{ shade: string; preview: string }>
|
|
512
|
+
isSpecial: boolean
|
|
513
|
+
}> = []
|
|
514
|
+
|
|
515
|
+
// Special colors
|
|
516
|
+
for (const color of SPECIAL_COLORS) {
|
|
517
|
+
if (color !== 'current' && color !== 'inherit' && color !== 'transparent') {
|
|
518
|
+
result.push({
|
|
519
|
+
name: color,
|
|
520
|
+
shades: [{ shade: '', preview: getColorPreview(color) }],
|
|
521
|
+
isSpecial: true,
|
|
522
|
+
})
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
// Standard colors
|
|
527
|
+
for (const color of DEFAULT_TAILWIND_COLORS) {
|
|
528
|
+
result.push({
|
|
529
|
+
name: color,
|
|
530
|
+
shades: STANDARD_SHADES.map(shade => ({
|
|
531
|
+
shade,
|
|
532
|
+
preview: getColorPreview(color, shade),
|
|
533
|
+
})),
|
|
534
|
+
isSpecial: false,
|
|
535
|
+
})
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
return result
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
return availableColors.colors.map(color => {
|
|
542
|
+
const shades = Object.keys(color.values)
|
|
543
|
+
const isSpecial = SPECIAL_COLORS.includes(color.name as any)
|
|
544
|
+
|
|
545
|
+
return {
|
|
546
|
+
name: color.name,
|
|
547
|
+
shades: shades.length > 0
|
|
548
|
+
? shades.map(shade => ({
|
|
549
|
+
shade,
|
|
550
|
+
preview: color.values[shade] || getColorPreview(color.name, shade),
|
|
551
|
+
}))
|
|
552
|
+
: [{ shade: '', preview: color.values[''] || getColorPreview(color.name) }],
|
|
553
|
+
isSpecial,
|
|
554
|
+
}
|
|
555
|
+
})
|
|
556
|
+
}
|