@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,874 @@
|
|
|
1
|
+
import fs from 'node:fs/promises'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { getProjectRoot } from './config'
|
|
4
|
+
import type { Attribute, AvailableColors, AvailableTextStyles, TailwindColor, TextStyleValue } from './types'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Default Tailwind CSS v4 color names.
|
|
8
|
+
*/
|
|
9
|
+
export const DEFAULT_TAILWIND_COLORS = [
|
|
10
|
+
'slate',
|
|
11
|
+
'gray',
|
|
12
|
+
'zinc',
|
|
13
|
+
'neutral',
|
|
14
|
+
'stone',
|
|
15
|
+
'red',
|
|
16
|
+
'orange',
|
|
17
|
+
'amber',
|
|
18
|
+
'yellow',
|
|
19
|
+
'lime',
|
|
20
|
+
'green',
|
|
21
|
+
'emerald',
|
|
22
|
+
'teal',
|
|
23
|
+
'cyan',
|
|
24
|
+
'sky',
|
|
25
|
+
'blue',
|
|
26
|
+
'indigo',
|
|
27
|
+
'violet',
|
|
28
|
+
'purple',
|
|
29
|
+
'fuchsia',
|
|
30
|
+
'pink',
|
|
31
|
+
'rose',
|
|
32
|
+
] as const
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Standard Tailwind color shades.
|
|
36
|
+
*/
|
|
37
|
+
export const STANDARD_SHADES = ['50', '100', '200', '300', '400', '500', '600', '700', '800', '900', '950'] as const
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Special color values that don't have shades.
|
|
41
|
+
*/
|
|
42
|
+
export const SPECIAL_COLORS = ['transparent', 'current', 'inherit', 'white', 'black'] as const
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Complete Tailwind v4 default color palette with all shade values.
|
|
46
|
+
*/
|
|
47
|
+
const DEFAULT_COLOR_VALUES: Record<string, Record<string, string>> = {
|
|
48
|
+
slate: {
|
|
49
|
+
'50': '#f8fafc',
|
|
50
|
+
'100': '#f1f5f9',
|
|
51
|
+
'200': '#e2e8f0',
|
|
52
|
+
'300': '#cbd5e1',
|
|
53
|
+
'400': '#94a3b8',
|
|
54
|
+
'500': '#64748b',
|
|
55
|
+
'600': '#475569',
|
|
56
|
+
'700': '#334155',
|
|
57
|
+
'800': '#1e293b',
|
|
58
|
+
'900': '#0f172a',
|
|
59
|
+
'950': '#020617',
|
|
60
|
+
},
|
|
61
|
+
gray: {
|
|
62
|
+
'50': '#f9fafb',
|
|
63
|
+
'100': '#f3f4f6',
|
|
64
|
+
'200': '#e5e7eb',
|
|
65
|
+
'300': '#d1d5db',
|
|
66
|
+
'400': '#9ca3af',
|
|
67
|
+
'500': '#6b7280',
|
|
68
|
+
'600': '#4b5563',
|
|
69
|
+
'700': '#374151',
|
|
70
|
+
'800': '#1f2937',
|
|
71
|
+
'900': '#111827',
|
|
72
|
+
'950': '#030712',
|
|
73
|
+
},
|
|
74
|
+
zinc: {
|
|
75
|
+
'50': '#fafafa',
|
|
76
|
+
'100': '#f4f4f5',
|
|
77
|
+
'200': '#e4e4e7',
|
|
78
|
+
'300': '#d4d4d8',
|
|
79
|
+
'400': '#a1a1aa',
|
|
80
|
+
'500': '#71717a',
|
|
81
|
+
'600': '#52525b',
|
|
82
|
+
'700': '#3f3f46',
|
|
83
|
+
'800': '#27272a',
|
|
84
|
+
'900': '#18181b',
|
|
85
|
+
'950': '#09090b',
|
|
86
|
+
},
|
|
87
|
+
neutral: {
|
|
88
|
+
'50': '#fafafa',
|
|
89
|
+
'100': '#f5f5f5',
|
|
90
|
+
'200': '#e5e5e5',
|
|
91
|
+
'300': '#d4d4d4',
|
|
92
|
+
'400': '#a3a3a3',
|
|
93
|
+
'500': '#737373',
|
|
94
|
+
'600': '#525252',
|
|
95
|
+
'700': '#404040',
|
|
96
|
+
'800': '#262626',
|
|
97
|
+
'900': '#171717',
|
|
98
|
+
'950': '#0a0a0a',
|
|
99
|
+
},
|
|
100
|
+
stone: {
|
|
101
|
+
'50': '#fafaf9',
|
|
102
|
+
'100': '#f5f5f4',
|
|
103
|
+
'200': '#e7e5e4',
|
|
104
|
+
'300': '#d6d3d1',
|
|
105
|
+
'400': '#a8a29e',
|
|
106
|
+
'500': '#78716c',
|
|
107
|
+
'600': '#57534e',
|
|
108
|
+
'700': '#44403c',
|
|
109
|
+
'800': '#292524',
|
|
110
|
+
'900': '#1c1917',
|
|
111
|
+
'950': '#0c0a09',
|
|
112
|
+
},
|
|
113
|
+
red: {
|
|
114
|
+
'50': '#fef2f2',
|
|
115
|
+
'100': '#fee2e2',
|
|
116
|
+
'200': '#fecaca',
|
|
117
|
+
'300': '#fca5a5',
|
|
118
|
+
'400': '#f87171',
|
|
119
|
+
'500': '#ef4444',
|
|
120
|
+
'600': '#dc2626',
|
|
121
|
+
'700': '#b91c1c',
|
|
122
|
+
'800': '#991b1b',
|
|
123
|
+
'900': '#7f1d1d',
|
|
124
|
+
'950': '#450a0a',
|
|
125
|
+
},
|
|
126
|
+
orange: {
|
|
127
|
+
'50': '#fff7ed',
|
|
128
|
+
'100': '#ffedd5',
|
|
129
|
+
'200': '#fed7aa',
|
|
130
|
+
'300': '#fdba74',
|
|
131
|
+
'400': '#fb923c',
|
|
132
|
+
'500': '#f97316',
|
|
133
|
+
'600': '#ea580c',
|
|
134
|
+
'700': '#c2410c',
|
|
135
|
+
'800': '#9a3412',
|
|
136
|
+
'900': '#7c2d12',
|
|
137
|
+
'950': '#431407',
|
|
138
|
+
},
|
|
139
|
+
amber: {
|
|
140
|
+
'50': '#fffbeb',
|
|
141
|
+
'100': '#fef3c7',
|
|
142
|
+
'200': '#fde68a',
|
|
143
|
+
'300': '#fcd34d',
|
|
144
|
+
'400': '#fbbf24',
|
|
145
|
+
'500': '#f59e0b',
|
|
146
|
+
'600': '#d97706',
|
|
147
|
+
'700': '#b45309',
|
|
148
|
+
'800': '#92400e',
|
|
149
|
+
'900': '#78350f',
|
|
150
|
+
'950': '#451a03',
|
|
151
|
+
},
|
|
152
|
+
yellow: {
|
|
153
|
+
'50': '#fefce8',
|
|
154
|
+
'100': '#fef9c3',
|
|
155
|
+
'200': '#fef08a',
|
|
156
|
+
'300': '#fde047',
|
|
157
|
+
'400': '#facc15',
|
|
158
|
+
'500': '#eab308',
|
|
159
|
+
'600': '#ca8a04',
|
|
160
|
+
'700': '#a16207',
|
|
161
|
+
'800': '#854d0e',
|
|
162
|
+
'900': '#713f12',
|
|
163
|
+
'950': '#422006',
|
|
164
|
+
},
|
|
165
|
+
lime: {
|
|
166
|
+
'50': '#f7fee7',
|
|
167
|
+
'100': '#ecfccb',
|
|
168
|
+
'200': '#d9f99d',
|
|
169
|
+
'300': '#bef264',
|
|
170
|
+
'400': '#a3e635',
|
|
171
|
+
'500': '#84cc16',
|
|
172
|
+
'600': '#65a30d',
|
|
173
|
+
'700': '#4d7c0f',
|
|
174
|
+
'800': '#3f6212',
|
|
175
|
+
'900': '#365314',
|
|
176
|
+
'950': '#1a2e05',
|
|
177
|
+
},
|
|
178
|
+
green: {
|
|
179
|
+
'50': '#f0fdf4',
|
|
180
|
+
'100': '#dcfce7',
|
|
181
|
+
'200': '#bbf7d0',
|
|
182
|
+
'300': '#86efac',
|
|
183
|
+
'400': '#4ade80',
|
|
184
|
+
'500': '#22c55e',
|
|
185
|
+
'600': '#16a34a',
|
|
186
|
+
'700': '#15803d',
|
|
187
|
+
'800': '#166534',
|
|
188
|
+
'900': '#14532d',
|
|
189
|
+
'950': '#052e16',
|
|
190
|
+
},
|
|
191
|
+
emerald: {
|
|
192
|
+
'50': '#ecfdf5',
|
|
193
|
+
'100': '#d1fae5',
|
|
194
|
+
'200': '#a7f3d0',
|
|
195
|
+
'300': '#6ee7b7',
|
|
196
|
+
'400': '#34d399',
|
|
197
|
+
'500': '#10b981',
|
|
198
|
+
'600': '#059669',
|
|
199
|
+
'700': '#047857',
|
|
200
|
+
'800': '#065f46',
|
|
201
|
+
'900': '#064e3b',
|
|
202
|
+
'950': '#022c22',
|
|
203
|
+
},
|
|
204
|
+
teal: {
|
|
205
|
+
'50': '#f0fdfa',
|
|
206
|
+
'100': '#ccfbf1',
|
|
207
|
+
'200': '#99f6e4',
|
|
208
|
+
'300': '#5eead4',
|
|
209
|
+
'400': '#2dd4bf',
|
|
210
|
+
'500': '#14b8a6',
|
|
211
|
+
'600': '#0d9488',
|
|
212
|
+
'700': '#0f766e',
|
|
213
|
+
'800': '#115e59',
|
|
214
|
+
'900': '#134e4a',
|
|
215
|
+
'950': '#042f2e',
|
|
216
|
+
},
|
|
217
|
+
cyan: {
|
|
218
|
+
'50': '#ecfeff',
|
|
219
|
+
'100': '#cffafe',
|
|
220
|
+
'200': '#a5f3fc',
|
|
221
|
+
'300': '#67e8f9',
|
|
222
|
+
'400': '#22d3ee',
|
|
223
|
+
'500': '#06b6d4',
|
|
224
|
+
'600': '#0891b2',
|
|
225
|
+
'700': '#0e7490',
|
|
226
|
+
'800': '#155e75',
|
|
227
|
+
'900': '#164e63',
|
|
228
|
+
'950': '#083344',
|
|
229
|
+
},
|
|
230
|
+
sky: {
|
|
231
|
+
'50': '#f0f9ff',
|
|
232
|
+
'100': '#e0f2fe',
|
|
233
|
+
'200': '#bae6fd',
|
|
234
|
+
'300': '#7dd3fc',
|
|
235
|
+
'400': '#38bdf8',
|
|
236
|
+
'500': '#0ea5e9',
|
|
237
|
+
'600': '#0284c7',
|
|
238
|
+
'700': '#0369a1',
|
|
239
|
+
'800': '#075985',
|
|
240
|
+
'900': '#0c4a6e',
|
|
241
|
+
'950': '#082f49',
|
|
242
|
+
},
|
|
243
|
+
blue: {
|
|
244
|
+
'50': '#eff6ff',
|
|
245
|
+
'100': '#dbeafe',
|
|
246
|
+
'200': '#bfdbfe',
|
|
247
|
+
'300': '#93c5fd',
|
|
248
|
+
'400': '#60a5fa',
|
|
249
|
+
'500': '#3b82f6',
|
|
250
|
+
'600': '#2563eb',
|
|
251
|
+
'700': '#1d4ed8',
|
|
252
|
+
'800': '#1e40af',
|
|
253
|
+
'900': '#1e3a8a',
|
|
254
|
+
'950': '#172554',
|
|
255
|
+
},
|
|
256
|
+
indigo: {
|
|
257
|
+
'50': '#eef2ff',
|
|
258
|
+
'100': '#e0e7ff',
|
|
259
|
+
'200': '#c7d2fe',
|
|
260
|
+
'300': '#a5b4fc',
|
|
261
|
+
'400': '#818cf8',
|
|
262
|
+
'500': '#6366f1',
|
|
263
|
+
'600': '#4f46e5',
|
|
264
|
+
'700': '#4338ca',
|
|
265
|
+
'800': '#3730a3',
|
|
266
|
+
'900': '#312e81',
|
|
267
|
+
'950': '#1e1b4b',
|
|
268
|
+
},
|
|
269
|
+
violet: {
|
|
270
|
+
'50': '#f5f3ff',
|
|
271
|
+
'100': '#ede9fe',
|
|
272
|
+
'200': '#ddd6fe',
|
|
273
|
+
'300': '#c4b5fd',
|
|
274
|
+
'400': '#a78bfa',
|
|
275
|
+
'500': '#8b5cf6',
|
|
276
|
+
'600': '#7c3aed',
|
|
277
|
+
'700': '#6d28d9',
|
|
278
|
+
'800': '#5b21b6',
|
|
279
|
+
'900': '#4c1d95',
|
|
280
|
+
'950': '#2e1065',
|
|
281
|
+
},
|
|
282
|
+
purple: {
|
|
283
|
+
'50': '#faf5ff',
|
|
284
|
+
'100': '#f3e8ff',
|
|
285
|
+
'200': '#e9d5ff',
|
|
286
|
+
'300': '#d8b4fe',
|
|
287
|
+
'400': '#c084fc',
|
|
288
|
+
'500': '#a855f7',
|
|
289
|
+
'600': '#9333ea',
|
|
290
|
+
'700': '#7e22ce',
|
|
291
|
+
'800': '#6b21a8',
|
|
292
|
+
'900': '#581c87',
|
|
293
|
+
'950': '#3b0764',
|
|
294
|
+
},
|
|
295
|
+
fuchsia: {
|
|
296
|
+
'50': '#fdf4ff',
|
|
297
|
+
'100': '#fae8ff',
|
|
298
|
+
'200': '#f5d0fe',
|
|
299
|
+
'300': '#f0abfc',
|
|
300
|
+
'400': '#e879f9',
|
|
301
|
+
'500': '#d946ef',
|
|
302
|
+
'600': '#c026d3',
|
|
303
|
+
'700': '#a21caf',
|
|
304
|
+
'800': '#86198f',
|
|
305
|
+
'900': '#701a75',
|
|
306
|
+
'950': '#4a044e',
|
|
307
|
+
},
|
|
308
|
+
pink: {
|
|
309
|
+
'50': '#fdf2f8',
|
|
310
|
+
'100': '#fce7f3',
|
|
311
|
+
'200': '#fbcfe8',
|
|
312
|
+
'300': '#f9a8d4',
|
|
313
|
+
'400': '#f472b6',
|
|
314
|
+
'500': '#ec4899',
|
|
315
|
+
'600': '#db2777',
|
|
316
|
+
'700': '#be185d',
|
|
317
|
+
'800': '#9d174d',
|
|
318
|
+
'900': '#831843',
|
|
319
|
+
'950': '#500724',
|
|
320
|
+
},
|
|
321
|
+
rose: {
|
|
322
|
+
'50': '#fff1f2',
|
|
323
|
+
'100': '#ffe4e6',
|
|
324
|
+
'200': '#fecdd3',
|
|
325
|
+
'300': '#fda4af',
|
|
326
|
+
'400': '#fb7185',
|
|
327
|
+
'500': '#f43f5e',
|
|
328
|
+
'600': '#e11d48',
|
|
329
|
+
'700': '#be123c',
|
|
330
|
+
'800': '#9f1239',
|
|
331
|
+
'900': '#881337',
|
|
332
|
+
'950': '#4c0519',
|
|
333
|
+
},
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Special color values.
|
|
338
|
+
*/
|
|
339
|
+
const SPECIAL_COLOR_VALUES: Record<string, string> = {
|
|
340
|
+
transparent: 'transparent',
|
|
341
|
+
current: 'currentColor',
|
|
342
|
+
inherit: 'inherit',
|
|
343
|
+
white: '#ffffff',
|
|
344
|
+
black: '#000000',
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Default Tailwind v4 font weight values.
|
|
349
|
+
*/
|
|
350
|
+
const DEFAULT_FONT_WEIGHTS: TextStyleValue[] = [
|
|
351
|
+
{ class: 'font-thin', label: 'Thin', css: { fontWeight: '100' } },
|
|
352
|
+
{ class: 'font-extralight', label: 'Extra Light', css: { fontWeight: '200' } },
|
|
353
|
+
{ class: 'font-light', label: 'Light', css: { fontWeight: '300' } },
|
|
354
|
+
{ class: 'font-normal', label: 'Normal', css: { fontWeight: '400' } },
|
|
355
|
+
{ class: 'font-medium', label: 'Medium', css: { fontWeight: '500' } },
|
|
356
|
+
{ class: 'font-semibold', label: 'Semibold', css: { fontWeight: '600' } },
|
|
357
|
+
{ class: 'font-bold', label: 'Bold', css: { fontWeight: '700' } },
|
|
358
|
+
{ class: 'font-extrabold', label: 'Extra Bold', css: { fontWeight: '800' } },
|
|
359
|
+
{ class: 'font-black', label: 'Black', css: { fontWeight: '900' } },
|
|
360
|
+
]
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Default Tailwind v4 font size values.
|
|
364
|
+
*/
|
|
365
|
+
const DEFAULT_FONT_SIZES: TextStyleValue[] = [
|
|
366
|
+
{ class: 'text-xs', label: 'XS', css: { fontSize: '0.75rem', lineHeight: '1rem' } },
|
|
367
|
+
{ class: 'text-sm', label: 'SM', css: { fontSize: '0.875rem', lineHeight: '1.25rem' } },
|
|
368
|
+
{ class: 'text-base', label: 'Base', css: { fontSize: '1rem', lineHeight: '1.5rem' } },
|
|
369
|
+
{ class: 'text-lg', label: 'LG', css: { fontSize: '1.125rem', lineHeight: '1.75rem' } },
|
|
370
|
+
{ class: 'text-xl', label: 'XL', css: { fontSize: '1.25rem', lineHeight: '1.75rem' } },
|
|
371
|
+
{ class: 'text-2xl', label: '2XL', css: { fontSize: '1.5rem', lineHeight: '2rem' } },
|
|
372
|
+
{ class: 'text-3xl', label: '3XL', css: { fontSize: '1.875rem', lineHeight: '2.25rem' } },
|
|
373
|
+
{ class: 'text-4xl', label: '4XL', css: { fontSize: '2.25rem', lineHeight: '2.5rem' } },
|
|
374
|
+
{ class: 'text-5xl', label: '5XL', css: { fontSize: '3rem', lineHeight: '1' } },
|
|
375
|
+
{ class: 'text-6xl', label: '6XL', css: { fontSize: '3.75rem', lineHeight: '1' } },
|
|
376
|
+
{ class: 'text-7xl', label: '7XL', css: { fontSize: '4.5rem', lineHeight: '1' } },
|
|
377
|
+
{ class: 'text-8xl', label: '8XL', css: { fontSize: '6rem', lineHeight: '1' } },
|
|
378
|
+
{ class: 'text-9xl', label: '9XL', css: { fontSize: '8rem', lineHeight: '1' } },
|
|
379
|
+
]
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Default text decoration values.
|
|
383
|
+
*/
|
|
384
|
+
const DEFAULT_TEXT_DECORATIONS: TextStyleValue[] = [
|
|
385
|
+
{ class: 'no-underline', label: 'None', css: { textDecoration: 'none' } },
|
|
386
|
+
{ class: 'underline', label: 'Underline', css: { textDecoration: 'underline' } },
|
|
387
|
+
{ class: 'overline', label: 'Overline', css: { textDecoration: 'overline' } },
|
|
388
|
+
{ class: 'line-through', label: 'Strikethrough', css: { textDecoration: 'line-through' } },
|
|
389
|
+
]
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Default font style values.
|
|
393
|
+
*/
|
|
394
|
+
const DEFAULT_FONT_STYLES: TextStyleValue[] = [
|
|
395
|
+
{ class: 'not-italic', label: 'Normal', css: { fontStyle: 'normal' } },
|
|
396
|
+
{ class: 'italic', label: 'Italic', css: { fontStyle: 'italic' } },
|
|
397
|
+
]
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Non-color utility suffixes that should not be matched as custom colors.
|
|
401
|
+
* These follow the pattern `prefix-word-number` but are not colors.
|
|
402
|
+
*/
|
|
403
|
+
const NON_COLOR_SUFFIXES = ['opacity'] as const
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Build a regex pattern for matching color classes.
|
|
407
|
+
* Matches:
|
|
408
|
+
* - Default colors with optional shades: bg-blue-500, bg-white
|
|
409
|
+
* - Custom theme colors with shades: bg-primary-500
|
|
410
|
+
* - Arbitrary hex values: bg-[#41b883], bg-[#fff]
|
|
411
|
+
* - Arbitrary rgb/hsl values: bg-[rgb(255,0,0)], bg-[hsl(0,100%,50%)]
|
|
412
|
+
* Excludes non-color utilities like opacity.
|
|
413
|
+
*/
|
|
414
|
+
function buildColorPattern(prefix: string): RegExp {
|
|
415
|
+
const colorNames = [...DEFAULT_TAILWIND_COLORS, ...SPECIAL_COLORS].join('|')
|
|
416
|
+
const excluded = NON_COLOR_SUFFIXES.join('|')
|
|
417
|
+
// Arbitrary value patterns for colors
|
|
418
|
+
const arbitraryHex = '\\[#[0-9a-fA-F]{3,8}\\]'
|
|
419
|
+
const arbitraryFunc = '\\[(?:rgba?|hsla?)\\([^\\]]+\\)\\]'
|
|
420
|
+
// Match: prefix-(colorName[-shade]?) OR prefix-(customColor-shade) OR prefix-[arbitrary] but NOT prefix-(excluded-number)
|
|
421
|
+
return new RegExp(`^${prefix}-((?:${colorNames})(?:-(\\d+))?|(?!(?:${excluded})-)(\\w+)-(\\d+)|${arbitraryHex}|${arbitraryFunc})$`)
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Build a regex pattern for matching opacity classes.
|
|
426
|
+
*/
|
|
427
|
+
function buildOpacityPattern(prefix: string): RegExp {
|
|
428
|
+
return new RegExp(`^${prefix}-opacity-(\\d+)$`)
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Regex patterns to match Tailwind color classes.
|
|
433
|
+
*/
|
|
434
|
+
const COLOR_CLASS_PATTERNS = {
|
|
435
|
+
bg: buildColorPattern('bg'),
|
|
436
|
+
text: buildColorPattern('text'),
|
|
437
|
+
border: buildColorPattern('border'),
|
|
438
|
+
hoverBg: buildColorPattern('hover:bg'),
|
|
439
|
+
hoverText: buildColorPattern('hover:text'),
|
|
440
|
+
hoverBorder: buildColorPattern('hover:border'),
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Regex patterns to match Tailwind opacity classes.
|
|
445
|
+
*/
|
|
446
|
+
const OPACITY_CLASS_PATTERNS = {
|
|
447
|
+
bgOpacity: buildOpacityPattern('bg'),
|
|
448
|
+
textOpacity: buildOpacityPattern('text'),
|
|
449
|
+
borderOpacity: buildOpacityPattern('border'),
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Regex patterns to match Tailwind gradient color classes.
|
|
454
|
+
*/
|
|
455
|
+
const GRADIENT_CLASS_PATTERNS = {
|
|
456
|
+
from: buildColorPattern('from'),
|
|
457
|
+
via: buildColorPattern('via'),
|
|
458
|
+
to: buildColorPattern('to'),
|
|
459
|
+
hoverFrom: buildColorPattern('hover:from'),
|
|
460
|
+
hoverVia: buildColorPattern('hover:via'),
|
|
461
|
+
hoverTo: buildColorPattern('hover:to'),
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* Parse Tailwind v4 CSS config to extract available colors with their values.
|
|
466
|
+
*/
|
|
467
|
+
export async function parseTailwindConfig(projectRoot: string = getProjectRoot()): Promise<AvailableColors> {
|
|
468
|
+
// Tailwind v4 CSS files to search
|
|
469
|
+
const cssFiles = [
|
|
470
|
+
'src/styles/global.css',
|
|
471
|
+
'src/styles/tailwind.css',
|
|
472
|
+
'src/styles/app.css',
|
|
473
|
+
'src/app.css',
|
|
474
|
+
'src/global.css',
|
|
475
|
+
'src/index.css',
|
|
476
|
+
'app/globals.css',
|
|
477
|
+
'styles/globals.css',
|
|
478
|
+
]
|
|
479
|
+
|
|
480
|
+
let customColors: TailwindColor[] = []
|
|
481
|
+
|
|
482
|
+
for (const cssFile of cssFiles) {
|
|
483
|
+
const fullPath = path.join(projectRoot, cssFile)
|
|
484
|
+
try {
|
|
485
|
+
const content = await fs.readFile(fullPath, 'utf-8')
|
|
486
|
+
customColors = extractColorsFromCss(content)
|
|
487
|
+
if (customColors.length > 0) {
|
|
488
|
+
break
|
|
489
|
+
}
|
|
490
|
+
} catch {
|
|
491
|
+
// File doesn't exist, continue
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// Build default colors with values
|
|
496
|
+
const defaultColors: TailwindColor[] = DEFAULT_TAILWIND_COLORS.map(name => ({
|
|
497
|
+
name,
|
|
498
|
+
values: DEFAULT_COLOR_VALUES[name] || {},
|
|
499
|
+
isCustom: false,
|
|
500
|
+
}))
|
|
501
|
+
|
|
502
|
+
// Add special colors
|
|
503
|
+
const specialColors: TailwindColor[] = SPECIAL_COLORS.map(name => ({
|
|
504
|
+
name,
|
|
505
|
+
values: { '': SPECIAL_COLOR_VALUES[name] || name },
|
|
506
|
+
isCustom: false,
|
|
507
|
+
}))
|
|
508
|
+
|
|
509
|
+
return {
|
|
510
|
+
colors: [...specialColors, ...defaultColors, ...customColors],
|
|
511
|
+
defaultColors: [...SPECIAL_COLORS, ...DEFAULT_TAILWIND_COLORS],
|
|
512
|
+
customColors: customColors.map(c => c.name),
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Extract custom colors from Tailwind v4 CSS @theme block.
|
|
518
|
+
* Extracts both color names and their actual CSS values.
|
|
519
|
+
*/
|
|
520
|
+
function extractColorsFromCss(content: string): TailwindColor[] {
|
|
521
|
+
const colors = new Map<string, Record<string, string>>()
|
|
522
|
+
|
|
523
|
+
// Find @theme blocks (including inline)
|
|
524
|
+
const themeBlockPattern = /@theme(?:\s+inline)?\s*\{([^}]+)\}/gs
|
|
525
|
+
let themeMatch: RegExpExecArray | null
|
|
526
|
+
|
|
527
|
+
while ((themeMatch = themeBlockPattern.exec(content)) !== null) {
|
|
528
|
+
const themeContent = themeMatch[1]
|
|
529
|
+
if (!themeContent) continue
|
|
530
|
+
|
|
531
|
+
// Find all --color-* definitions with their values
|
|
532
|
+
// Pattern: --color-{name}-{shade}: value; or --color-{name}: value;
|
|
533
|
+
const colorVarPattern = /--color-([a-z]+)(?:-(\d+))?:\s*([^;]+);/gi
|
|
534
|
+
let colorMatch: RegExpExecArray | null
|
|
535
|
+
|
|
536
|
+
while ((colorMatch = colorVarPattern.exec(themeContent)) !== null) {
|
|
537
|
+
const colorName = colorMatch[1]?.toLowerCase()
|
|
538
|
+
const shade = colorMatch[2] || ''
|
|
539
|
+
const value = colorMatch[3]?.trim()
|
|
540
|
+
|
|
541
|
+
if (!colorName || !value) continue
|
|
542
|
+
|
|
543
|
+
// Skip if it's a default color (we already have values for those)
|
|
544
|
+
if (DEFAULT_TAILWIND_COLORS.includes(colorName as any)) {
|
|
545
|
+
continue
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
if (!colors.has(colorName)) {
|
|
549
|
+
colors.set(colorName, {})
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
colors.get(colorName)![shade] = value
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// Convert to TailwindColor array
|
|
557
|
+
const result: TailwindColor[] = []
|
|
558
|
+
for (const [name, values] of colors) {
|
|
559
|
+
result.push({
|
|
560
|
+
name,
|
|
561
|
+
values,
|
|
562
|
+
isCustom: true,
|
|
563
|
+
})
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
return result
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* Parse Tailwind v4 CSS config to extract available text styles.
|
|
571
|
+
*/
|
|
572
|
+
export async function parseTextStyles(projectRoot: string = getProjectRoot()): Promise<AvailableTextStyles> {
|
|
573
|
+
// Tailwind v4 CSS files to search
|
|
574
|
+
const cssFiles = [
|
|
575
|
+
'src/styles/global.css',
|
|
576
|
+
'src/styles/tailwind.css',
|
|
577
|
+
'src/styles/app.css',
|
|
578
|
+
'src/app.css',
|
|
579
|
+
'src/global.css',
|
|
580
|
+
'src/index.css',
|
|
581
|
+
'app/globals.css',
|
|
582
|
+
'styles/globals.css',
|
|
583
|
+
]
|
|
584
|
+
|
|
585
|
+
let customTextStyles: Partial<AvailableTextStyles> = {}
|
|
586
|
+
|
|
587
|
+
for (const cssFile of cssFiles) {
|
|
588
|
+
const fullPath = path.join(projectRoot, cssFile)
|
|
589
|
+
try {
|
|
590
|
+
const content = await fs.readFile(fullPath, 'utf-8')
|
|
591
|
+
customTextStyles = extractTextStylesFromCss(content)
|
|
592
|
+
// If we found any custom styles, use this file
|
|
593
|
+
if (Object.values(customTextStyles).some(arr => arr && arr.length > 0)) {
|
|
594
|
+
break
|
|
595
|
+
}
|
|
596
|
+
} catch {
|
|
597
|
+
// File doesn't exist, continue
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// Merge custom styles with defaults (custom overrides default)
|
|
602
|
+
return {
|
|
603
|
+
fontWeight: mergeTextStyles(DEFAULT_FONT_WEIGHTS, customTextStyles.fontWeight),
|
|
604
|
+
fontSize: mergeTextStyles(DEFAULT_FONT_SIZES, customTextStyles.fontSize),
|
|
605
|
+
textDecoration: mergeTextStyles(DEFAULT_TEXT_DECORATIONS, customTextStyles.textDecoration),
|
|
606
|
+
fontStyle: mergeTextStyles(DEFAULT_FONT_STYLES, customTextStyles.fontStyle),
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
/**
|
|
611
|
+
* Merge custom text styles with defaults.
|
|
612
|
+
* Custom styles with matching class names override defaults.
|
|
613
|
+
*/
|
|
614
|
+
function mergeTextStyles(defaults: TextStyleValue[], custom?: TextStyleValue[]): TextStyleValue[] {
|
|
615
|
+
if (!custom || custom.length === 0) {
|
|
616
|
+
return defaults
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
const customByClass = new Map(custom.map(s => [s.class, s]))
|
|
620
|
+
const result: TextStyleValue[] = []
|
|
621
|
+
|
|
622
|
+
// Update defaults with custom overrides
|
|
623
|
+
for (const def of defaults) {
|
|
624
|
+
const customStyle = customByClass.get(def.class)
|
|
625
|
+
if (customStyle) {
|
|
626
|
+
result.push(customStyle)
|
|
627
|
+
customByClass.delete(def.class)
|
|
628
|
+
} else {
|
|
629
|
+
result.push(def)
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// Add any remaining custom styles that weren't overrides
|
|
634
|
+
for (const style of customByClass.values()) {
|
|
635
|
+
result.push(style)
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
return result
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
/**
|
|
642
|
+
* Extract custom text styles from Tailwind v4 CSS @theme block.
|
|
643
|
+
*/
|
|
644
|
+
function extractTextStylesFromCss(content: string): Partial<AvailableTextStyles> {
|
|
645
|
+
const fontWeights: TextStyleValue[] = []
|
|
646
|
+
const fontSizes: TextStyleValue[] = []
|
|
647
|
+
|
|
648
|
+
// Find @theme blocks (including inline)
|
|
649
|
+
const themeBlockPattern = /@theme(?:\s+inline)?\s*\{([^}]+)\}/gs
|
|
650
|
+
let themeMatch: RegExpExecArray | null
|
|
651
|
+
|
|
652
|
+
while ((themeMatch = themeBlockPattern.exec(content)) !== null) {
|
|
653
|
+
const themeContent = themeMatch[1]
|
|
654
|
+
if (!themeContent) continue
|
|
655
|
+
|
|
656
|
+
// Extract font-weight overrides: --font-weight-{name}: value;
|
|
657
|
+
const fontWeightPattern = /--font-weight-([a-z]+):\s*([^;]+);/gi
|
|
658
|
+
let weightMatch: RegExpExecArray | null
|
|
659
|
+
while ((weightMatch = fontWeightPattern.exec(themeContent)) !== null) {
|
|
660
|
+
const name = weightMatch[1]?.toLowerCase()
|
|
661
|
+
const value = weightMatch[2]?.trim()
|
|
662
|
+
if (!name || !value) continue
|
|
663
|
+
|
|
664
|
+
fontWeights.push({
|
|
665
|
+
class: `font-${name}`,
|
|
666
|
+
label: name.charAt(0).toUpperCase() + name.slice(1),
|
|
667
|
+
css: { fontWeight: value },
|
|
668
|
+
})
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
// Extract font-size overrides: --font-size-{name}: value;
|
|
672
|
+
// Also look for corresponding line-height: --line-height-{name}: value;
|
|
673
|
+
const fontSizePattern = /--font-size-([a-z0-9]+):\s*([^;]+);/gi
|
|
674
|
+
let sizeMatch: RegExpExecArray | null
|
|
675
|
+
while ((sizeMatch = fontSizePattern.exec(themeContent)) !== null) {
|
|
676
|
+
const name = sizeMatch[1]?.toLowerCase()
|
|
677
|
+
const value = sizeMatch[2]?.trim()
|
|
678
|
+
if (!name || !value) continue
|
|
679
|
+
|
|
680
|
+
// Try to find matching line-height
|
|
681
|
+
const lineHeightPattern = new RegExp(`--line-height-${name}:\\s*([^;]+);`, 'i')
|
|
682
|
+
const lineHeightMatch = themeContent.match(lineHeightPattern)
|
|
683
|
+
const lineHeight = lineHeightMatch?.[1]?.trim()
|
|
684
|
+
|
|
685
|
+
const css: Record<string, string> = { fontSize: value }
|
|
686
|
+
if (lineHeight) {
|
|
687
|
+
css.lineHeight = lineHeight
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
fontSizes.push({
|
|
691
|
+
class: `text-${name}`,
|
|
692
|
+
label: name.toUpperCase(),
|
|
693
|
+
css,
|
|
694
|
+
})
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
return {
|
|
699
|
+
fontWeight: fontWeights.length > 0 ? fontWeights : undefined,
|
|
700
|
+
fontSize: fontSizes.length > 0 ? fontSizes : undefined,
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
/** Flat key names for color class categories */
|
|
705
|
+
const COLOR_FLAT_KEYS: Record<string, string> = {
|
|
706
|
+
// COLOR_CLASS_PATTERNS keys map directly
|
|
707
|
+
bg: 'bg',
|
|
708
|
+
text: 'text',
|
|
709
|
+
border: 'border',
|
|
710
|
+
hoverBg: 'hoverBg',
|
|
711
|
+
hoverText: 'hoverText',
|
|
712
|
+
hoverBorder: 'hoverBorder',
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
const GRADIENT_FLAT_KEYS: Record<string, string> = {
|
|
716
|
+
from: 'gradientFrom',
|
|
717
|
+
via: 'gradientVia',
|
|
718
|
+
to: 'gradientTo',
|
|
719
|
+
hoverFrom: 'hoverGradientFrom',
|
|
720
|
+
hoverVia: 'hoverGradientVia',
|
|
721
|
+
hoverTo: 'hoverGradientTo',
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
/**
|
|
725
|
+
* Extract color classes from an element's class attribute.
|
|
726
|
+
* Returns a flat Record<string, Attribute> with keys like bg, text, gradientFrom, bgOpacity, etc.
|
|
727
|
+
*/
|
|
728
|
+
export function extractColorClasses(classAttr: string | null | undefined): Record<string, Attribute> | undefined {
|
|
729
|
+
if (!classAttr) return undefined
|
|
730
|
+
|
|
731
|
+
const classes = classAttr.split(/\s+/).filter(Boolean)
|
|
732
|
+
const result: Record<string, Attribute> = {}
|
|
733
|
+
|
|
734
|
+
for (const cls of classes) {
|
|
735
|
+
let matched = false
|
|
736
|
+
|
|
737
|
+
// Check color patterns
|
|
738
|
+
for (const [key, pattern] of Object.entries(COLOR_CLASS_PATTERNS)) {
|
|
739
|
+
if (pattern.test(cls)) {
|
|
740
|
+
const flatKey = COLOR_FLAT_KEYS[key]
|
|
741
|
+
if (flatKey && !(flatKey in result)) {
|
|
742
|
+
result[flatKey] = { value: cls }
|
|
743
|
+
}
|
|
744
|
+
matched = true
|
|
745
|
+
break
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
// Check gradient patterns
|
|
750
|
+
if (!matched) {
|
|
751
|
+
for (const [key, pattern] of Object.entries(GRADIENT_CLASS_PATTERNS)) {
|
|
752
|
+
if (pattern.test(cls)) {
|
|
753
|
+
const flatKey = GRADIENT_FLAT_KEYS[key]
|
|
754
|
+
if (flatKey && !(flatKey in result)) {
|
|
755
|
+
result[flatKey] = { value: cls }
|
|
756
|
+
}
|
|
757
|
+
matched = true
|
|
758
|
+
break
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
// Check opacity patterns
|
|
764
|
+
if (!matched) {
|
|
765
|
+
for (const [key, pattern] of Object.entries(OPACITY_CLASS_PATTERNS)) {
|
|
766
|
+
if (pattern.test(cls)) {
|
|
767
|
+
if (!(key in result)) {
|
|
768
|
+
result[key] = { value: cls }
|
|
769
|
+
}
|
|
770
|
+
break
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
return Object.keys(result).length > 0 ? result : undefined
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
/**
|
|
780
|
+
* Check if a class is a color class (including gradient colors).
|
|
781
|
+
*/
|
|
782
|
+
export function isColorClass(className: string): boolean {
|
|
783
|
+
return Object.values(COLOR_CLASS_PATTERNS).some(pattern => pattern.test(className))
|
|
784
|
+
|| Object.values(GRADIENT_CLASS_PATTERNS).some(pattern => pattern.test(className))
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
/**
|
|
788
|
+
* Generate a new class string with a color class replaced.
|
|
789
|
+
*/
|
|
790
|
+
export function replaceColorClass(
|
|
791
|
+
currentClasses: string,
|
|
792
|
+
oldColorClass: string,
|
|
793
|
+
newColorClass: string,
|
|
794
|
+
): string {
|
|
795
|
+
const classes = currentClasses.split(/\s+/).filter(Boolean)
|
|
796
|
+
const newClasses = classes.map(cls => cls === oldColorClass ? newColorClass : cls)
|
|
797
|
+
return newClasses.join(' ')
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
/**
|
|
801
|
+
* Get the color type from a color class.
|
|
802
|
+
* Returns the flat key name (e.g., 'bg', 'gradientFrom', 'bgOpacity').
|
|
803
|
+
*/
|
|
804
|
+
export function getColorType(colorClass: string): string | undefined {
|
|
805
|
+
for (const [key, pattern] of Object.entries(COLOR_CLASS_PATTERNS)) {
|
|
806
|
+
if (pattern.test(colorClass)) {
|
|
807
|
+
return COLOR_FLAT_KEYS[key]
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
for (const [key, pattern] of Object.entries(GRADIENT_CLASS_PATTERNS)) {
|
|
811
|
+
if (pattern.test(colorClass)) {
|
|
812
|
+
return GRADIENT_FLAT_KEYS[key]
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
for (const [key, pattern] of Object.entries(OPACITY_CLASS_PATTERNS)) {
|
|
816
|
+
if (pattern.test(colorClass)) {
|
|
817
|
+
return key
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
return undefined
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
/**
|
|
824
|
+
* Parse a color class into its components.
|
|
825
|
+
*/
|
|
826
|
+
export function parseColorClass(colorClass: string): {
|
|
827
|
+
prefix: string
|
|
828
|
+
colorName: string
|
|
829
|
+
shade?: string
|
|
830
|
+
isHover: boolean
|
|
831
|
+
isArbitrary?: boolean
|
|
832
|
+
} | undefined {
|
|
833
|
+
const isHover = colorClass.startsWith('hover:')
|
|
834
|
+
const classWithoutHover = isHover ? colorClass.slice(6) : colorClass
|
|
835
|
+
|
|
836
|
+
// Try matching standard color classes (default colors, custom theme colors, and gradients)
|
|
837
|
+
const standardMatch = classWithoutHover.match(/^(bg|text|border|from|via|to)-([a-z]+)(?:-(\d+))?$/)
|
|
838
|
+
if (standardMatch) {
|
|
839
|
+
return {
|
|
840
|
+
prefix: isHover ? `hover:${standardMatch[1]}` : standardMatch[1]!,
|
|
841
|
+
colorName: standardMatch[2]!,
|
|
842
|
+
shade: standardMatch[3],
|
|
843
|
+
isHover,
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
// Try matching arbitrary value classes like bg-[#41b883] or from-[#41b883]
|
|
848
|
+
const arbitraryMatch = classWithoutHover.match(/^(bg|text|border|from|via|to)-(\[.+\])$/)
|
|
849
|
+
if (arbitraryMatch) {
|
|
850
|
+
return {
|
|
851
|
+
prefix: isHover ? `hover:${arbitraryMatch[1]}` : arbitraryMatch[1]!,
|
|
852
|
+
colorName: arbitraryMatch[2]!,
|
|
853
|
+
shade: undefined,
|
|
854
|
+
isHover,
|
|
855
|
+
isArbitrary: true,
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
return undefined
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
/**
|
|
863
|
+
* Build a color class from components.
|
|
864
|
+
*/
|
|
865
|
+
export function buildColorClass(
|
|
866
|
+
prefix: string,
|
|
867
|
+
colorName: string,
|
|
868
|
+
shade?: string,
|
|
869
|
+
): string {
|
|
870
|
+
if (shade) {
|
|
871
|
+
return `${prefix}-${colorName}-${shade}`
|
|
872
|
+
}
|
|
873
|
+
return `${prefix}-${colorName}`
|
|
874
|
+
}
|