@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.
Files changed (269) hide show
  1. package/README.md +237 -0
  2. package/dist/src/build-processor.d.ts +20 -0
  3. package/dist/src/build-processor.d.ts.map +1 -0
  4. package/dist/src/collection-scanner.d.ts +6 -0
  5. package/dist/src/collection-scanner.d.ts.map +1 -0
  6. package/dist/src/component-registry.d.ts +63 -0
  7. package/dist/src/component-registry.d.ts.map +1 -0
  8. package/dist/src/config.d.ts +24 -0
  9. package/dist/src/config.d.ts.map +1 -0
  10. package/dist/src/dev-middleware.d.ts +20 -0
  11. package/dist/src/dev-middleware.d.ts.map +1 -0
  12. package/dist/src/editor/ai.d.ts +60 -0
  13. package/dist/src/editor/ai.d.ts.map +1 -0
  14. package/dist/src/editor/api.d.ts +140 -0
  15. package/dist/src/editor/api.d.ts.map +1 -0
  16. package/dist/src/editor/color-utils.d.ts +106 -0
  17. package/dist/src/editor/color-utils.d.ts.map +1 -0
  18. package/dist/src/editor/components/ai-chat.d.ts +11 -0
  19. package/dist/src/editor/components/ai-chat.d.ts.map +1 -0
  20. package/dist/src/editor/components/ai-tooltip.d.ts +12 -0
  21. package/dist/src/editor/components/ai-tooltip.d.ts.map +1 -0
  22. package/dist/src/editor/components/attribute-editor.d.ts +5 -0
  23. package/dist/src/editor/components/attribute-editor.d.ts.map +1 -0
  24. package/dist/src/editor/components/block-editor.d.ts +12 -0
  25. package/dist/src/editor/components/block-editor.d.ts.map +1 -0
  26. package/dist/src/editor/components/collections-browser.d.ts +2 -0
  27. package/dist/src/editor/components/collections-browser.d.ts.map +1 -0
  28. package/dist/src/editor/components/color-toolbar.d.ts +12 -0
  29. package/dist/src/editor/components/color-toolbar.d.ts.map +1 -0
  30. package/dist/src/editor/components/confirm-dialog.d.ts +2 -0
  31. package/dist/src/editor/components/confirm-dialog.d.ts.map +1 -0
  32. package/dist/src/editor/components/create-page-modal.d.ts +2 -0
  33. package/dist/src/editor/components/create-page-modal.d.ts.map +1 -0
  34. package/dist/src/editor/components/editable-highlights.d.ts +9 -0
  35. package/dist/src/editor/components/editable-highlights.d.ts.map +1 -0
  36. package/dist/src/editor/components/error-boundary.d.ts +32 -0
  37. package/dist/src/editor/components/error-boundary.d.ts.map +1 -0
  38. package/dist/src/editor/components/fields.d.ts +75 -0
  39. package/dist/src/editor/components/fields.d.ts.map +1 -0
  40. package/dist/src/editor/components/frontmatter-fields.d.ts +29 -0
  41. package/dist/src/editor/components/frontmatter-fields.d.ts.map +1 -0
  42. package/dist/src/editor/components/highlight-overlay.d.ts +64 -0
  43. package/dist/src/editor/components/highlight-overlay.d.ts.map +1 -0
  44. package/dist/src/editor/components/image-overlay.d.ts +12 -0
  45. package/dist/src/editor/components/image-overlay.d.ts.map +1 -0
  46. package/dist/src/editor/components/markdown-editor-overlay.d.ts +6 -0
  47. package/dist/src/editor/components/markdown-editor-overlay.d.ts.map +1 -0
  48. package/dist/src/editor/components/markdown-inline-editor.d.ts +10 -0
  49. package/dist/src/editor/components/markdown-inline-editor.d.ts.map +1 -0
  50. package/dist/src/editor/components/media-library.d.ts +2 -0
  51. package/dist/src/editor/components/media-library.d.ts.map +1 -0
  52. package/dist/src/editor/components/outline.d.ts +21 -0
  53. package/dist/src/editor/components/outline.d.ts.map +1 -0
  54. package/dist/src/editor/components/redirect-countdown.d.ts +2 -0
  55. package/dist/src/editor/components/redirect-countdown.d.ts.map +1 -0
  56. package/dist/src/editor/components/seo-editor.d.ts +2 -0
  57. package/dist/src/editor/components/seo-editor.d.ts.map +1 -0
  58. package/dist/src/editor/components/text-style-toolbar.d.ts +8 -0
  59. package/dist/src/editor/components/text-style-toolbar.d.ts.map +1 -0
  60. package/dist/src/editor/components/toast/toast-container.d.ts +7 -0
  61. package/dist/src/editor/components/toast/toast-container.d.ts.map +1 -0
  62. package/dist/src/editor/components/toast/toast.d.ts +7 -0
  63. package/dist/src/editor/components/toast/toast.d.ts.map +1 -0
  64. package/dist/src/editor/components/toast/types.d.ts +7 -0
  65. package/dist/src/editor/components/toast/types.d.ts.map +1 -0
  66. package/dist/src/editor/components/toolbar.d.ts +21 -0
  67. package/dist/src/editor/components/toolbar.d.ts.map +1 -0
  68. package/dist/src/editor/config.d.ts +4 -0
  69. package/dist/src/editor/config.d.ts.map +1 -0
  70. package/dist/src/editor/constants.d.ts +101 -0
  71. package/dist/src/editor/constants.d.ts.map +1 -0
  72. package/dist/src/editor/context.d.ts +14 -0
  73. package/dist/src/editor/context.d.ts.map +1 -0
  74. package/dist/src/editor/dom.d.ts +77 -0
  75. package/dist/src/editor/dom.d.ts.map +1 -0
  76. package/dist/src/editor/editor.d.ts +64 -0
  77. package/dist/src/editor/editor.d.ts.map +1 -0
  78. package/dist/src/editor/history.d.ts +20 -0
  79. package/dist/src/editor/history.d.ts.map +1 -0
  80. package/dist/src/editor/hooks/index.d.ts +14 -0
  81. package/dist/src/editor/hooks/index.d.ts.map +1 -0
  82. package/dist/src/editor/hooks/useAIHandlers.d.ts +22 -0
  83. package/dist/src/editor/hooks/useAIHandlers.d.ts.map +1 -0
  84. package/dist/src/editor/hooks/useBlockEditorHandlers.d.ts +18 -0
  85. package/dist/src/editor/hooks/useBlockEditorHandlers.d.ts.map +1 -0
  86. package/dist/src/editor/hooks/useElementDetection.d.ts +26 -0
  87. package/dist/src/editor/hooks/useElementDetection.d.ts.map +1 -0
  88. package/dist/src/editor/hooks/useImageHoverDetection.d.ts +12 -0
  89. package/dist/src/editor/hooks/useImageHoverDetection.d.ts.map +1 -0
  90. package/dist/src/editor/hooks/useTextSelection.d.ts +23 -0
  91. package/dist/src/editor/hooks/useTextSelection.d.ts.map +1 -0
  92. package/dist/src/editor/hooks/useTooltipState.d.ts +19 -0
  93. package/dist/src/editor/hooks/useTooltipState.d.ts.map +1 -0
  94. package/dist/src/editor/hooks/utils.d.ts +32 -0
  95. package/dist/src/editor/hooks/utils.d.ts.map +1 -0
  96. package/dist/src/editor/index.d.ts +12 -0
  97. package/dist/src/editor/index.d.ts.map +1 -0
  98. package/dist/src/editor/lib/cn.d.ts +3 -0
  99. package/dist/src/editor/lib/cn.d.ts.map +1 -0
  100. package/dist/src/editor/manifest.d.ts +19 -0
  101. package/dist/src/editor/manifest.d.ts.map +1 -0
  102. package/dist/src/editor/markdown-api.d.ts +36 -0
  103. package/dist/src/editor/markdown-api.d.ts.map +1 -0
  104. package/dist/src/editor/signals.d.ts +242 -0
  105. package/dist/src/editor/signals.d.ts.map +1 -0
  106. package/dist/src/editor/storage.d.ts +27 -0
  107. package/dist/src/editor/storage.d.ts.map +1 -0
  108. package/dist/src/editor/text-styling.d.ts +350 -0
  109. package/dist/src/editor/text-styling.d.ts.map +1 -0
  110. package/dist/src/editor/themes.d.ts +38 -0
  111. package/dist/src/editor/themes.d.ts.map +1 -0
  112. package/dist/src/editor/types.d.ts +454 -0
  113. package/dist/src/editor/types.d.ts.map +1 -0
  114. package/dist/src/error-collector.d.ts +56 -0
  115. package/dist/src/error-collector.d.ts.map +1 -0
  116. package/dist/src/handlers/component-ops.d.ts +34 -0
  117. package/dist/src/handlers/component-ops.d.ts.map +1 -0
  118. package/dist/src/handlers/markdown-ops.d.ts +41 -0
  119. package/dist/src/handlers/markdown-ops.d.ts.map +1 -0
  120. package/dist/src/handlers/request-utils.d.ts +20 -0
  121. package/dist/src/handlers/request-utils.d.ts.map +1 -0
  122. package/dist/src/handlers/source-writer.d.ts +51 -0
  123. package/dist/src/handlers/source-writer.d.ts.map +1 -0
  124. package/dist/src/html-processor.d.ts +63 -0
  125. package/dist/src/html-processor.d.ts.map +1 -0
  126. package/dist/src/index.d.ts +41 -0
  127. package/dist/src/index.d.ts.map +1 -0
  128. package/dist/src/manifest-writer.d.ts +111 -0
  129. package/dist/src/manifest-writer.d.ts.map +1 -0
  130. package/dist/src/media/contember.d.ts +15 -0
  131. package/dist/src/media/contember.d.ts.map +1 -0
  132. package/dist/src/media/local.d.ts +9 -0
  133. package/dist/src/media/local.d.ts.map +1 -0
  134. package/dist/src/media/s3.d.ts +12 -0
  135. package/dist/src/media/s3.d.ts.map +1 -0
  136. package/dist/src/media/types.d.ts +40 -0
  137. package/dist/src/media/types.d.ts.map +1 -0
  138. package/dist/src/preview-generator.d.ts +19 -0
  139. package/dist/src/preview-generator.d.ts.map +1 -0
  140. package/dist/src/seo-processor.d.ts +23 -0
  141. package/dist/src/seo-processor.d.ts.map +1 -0
  142. package/dist/src/source-finder/ast-extractors.d.ts +35 -0
  143. package/dist/src/source-finder/ast-extractors.d.ts.map +1 -0
  144. package/dist/src/source-finder/ast-parser.d.ts +16 -0
  145. package/dist/src/source-finder/ast-parser.d.ts.map +1 -0
  146. package/dist/src/source-finder/cache.d.ts +18 -0
  147. package/dist/src/source-finder/cache.d.ts.map +1 -0
  148. package/dist/src/source-finder/collection-finder.d.ts +29 -0
  149. package/dist/src/source-finder/collection-finder.d.ts.map +1 -0
  150. package/dist/src/source-finder/cross-file-tracker.d.ts +39 -0
  151. package/dist/src/source-finder/cross-file-tracker.d.ts.map +1 -0
  152. package/dist/src/source-finder/element-finder.d.ts +42 -0
  153. package/dist/src/source-finder/element-finder.d.ts.map +1 -0
  154. package/dist/src/source-finder/image-finder.d.ts +24 -0
  155. package/dist/src/source-finder/image-finder.d.ts.map +1 -0
  156. package/dist/src/source-finder/index.d.ts +9 -0
  157. package/dist/src/source-finder/index.d.ts.map +1 -0
  158. package/dist/src/source-finder/search-index.d.ts +27 -0
  159. package/dist/src/source-finder/search-index.d.ts.map +1 -0
  160. package/dist/src/source-finder/snippet-utils.d.ts +90 -0
  161. package/dist/src/source-finder/snippet-utils.d.ts.map +1 -0
  162. package/dist/src/source-finder/source-lookup.d.ts +16 -0
  163. package/dist/src/source-finder/source-lookup.d.ts.map +1 -0
  164. package/dist/src/source-finder/types.d.ts +167 -0
  165. package/dist/src/source-finder/types.d.ts.map +1 -0
  166. package/dist/src/source-finder/variable-extraction.d.ts +37 -0
  167. package/dist/src/source-finder/variable-extraction.d.ts.map +1 -0
  168. package/dist/src/tailwind-colors.d.ts +54 -0
  169. package/dist/src/tailwind-colors.d.ts.map +1 -0
  170. package/dist/src/tsconfig.tsbuildinfo +1 -0
  171. package/dist/src/types.d.ts +367 -0
  172. package/dist/src/types.d.ts.map +1 -0
  173. package/dist/src/utils.d.ts +61 -0
  174. package/dist/src/utils.d.ts.map +1 -0
  175. package/dist/src/vite-plugin.d.ts +14 -0
  176. package/dist/src/vite-plugin.d.ts.map +1 -0
  177. package/dist/types/tsconfig.tsbuildinfo +1 -0
  178. package/package.json +80 -0
  179. package/src/build-processor.ts +784 -0
  180. package/src/collection-scanner.ts +304 -0
  181. package/src/component-registry.ts +393 -0
  182. package/src/config.ts +74 -0
  183. package/src/dev-middleware.ts +525 -0
  184. package/src/dist/src/tsconfig.tsbuildinfo +1 -0
  185. package/src/editor/ai.ts +185 -0
  186. package/src/editor/api.ts +513 -0
  187. package/src/editor/color-utils.ts +556 -0
  188. package/src/editor/components/ai-chat.tsx +632 -0
  189. package/src/editor/components/ai-tooltip.tsx +179 -0
  190. package/src/editor/components/attribute-editor.tsx +596 -0
  191. package/src/editor/components/block-editor.tsx +546 -0
  192. package/src/editor/components/collections-browser.tsx +248 -0
  193. package/src/editor/components/color-toolbar.tsx +314 -0
  194. package/src/editor/components/confirm-dialog.tsx +69 -0
  195. package/src/editor/components/create-page-modal.tsx +163 -0
  196. package/src/editor/components/editable-highlights.tsx +260 -0
  197. package/src/editor/components/error-boundary.tsx +87 -0
  198. package/src/editor/components/fields.tsx +387 -0
  199. package/src/editor/components/frontmatter-fields.tsx +469 -0
  200. package/src/editor/components/highlight-overlay.ts +229 -0
  201. package/src/editor/components/image-overlay.tsx +230 -0
  202. package/src/editor/components/markdown-editor-overlay.tsx +505 -0
  203. package/src/editor/components/markdown-inline-editor.tsx +780 -0
  204. package/src/editor/components/media-library.tsx +297 -0
  205. package/src/editor/components/outline.tsx +402 -0
  206. package/src/editor/components/redirect-countdown.tsx +45 -0
  207. package/src/editor/components/seo-editor.tsx +498 -0
  208. package/src/editor/components/text-style-toolbar.tsx +362 -0
  209. package/src/editor/components/toast/toast-container.tsx +15 -0
  210. package/src/editor/components/toast/toast.tsx +49 -0
  211. package/src/editor/components/toast/types.ts +7 -0
  212. package/src/editor/components/toolbar.tsx +366 -0
  213. package/src/editor/config.ts +12 -0
  214. package/src/editor/constants.ts +106 -0
  215. package/src/editor/context.tsx +38 -0
  216. package/src/editor/dom.ts +357 -0
  217. package/src/editor/editor.ts +1510 -0
  218. package/src/editor/env.d.ts +4 -0
  219. package/src/editor/history.ts +355 -0
  220. package/src/editor/hooks/index.ts +19 -0
  221. package/src/editor/hooks/useAIHandlers.ts +345 -0
  222. package/src/editor/hooks/useBlockEditorHandlers.ts +206 -0
  223. package/src/editor/hooks/useElementDetection.ts +284 -0
  224. package/src/editor/hooks/useImageHoverDetection.ts +102 -0
  225. package/src/editor/hooks/useTextSelection.ts +187 -0
  226. package/src/editor/hooks/useTooltipState.ts +126 -0
  227. package/src/editor/hooks/utils.ts +101 -0
  228. package/src/editor/index.tsx +481 -0
  229. package/src/editor/lib/cn.ts +4 -0
  230. package/src/editor/manifest.ts +25 -0
  231. package/src/editor/markdown-api.ts +209 -0
  232. package/src/editor/signals.ts +1351 -0
  233. package/src/editor/storage.ts +266 -0
  234. package/src/editor/styles.css +465 -0
  235. package/src/editor/text-styling.ts +773 -0
  236. package/src/editor/themes.ts +210 -0
  237. package/src/editor/types.ts +591 -0
  238. package/src/error-collector.ts +106 -0
  239. package/src/handlers/component-ops.ts +463 -0
  240. package/src/handlers/markdown-ops.ts +202 -0
  241. package/src/handlers/request-utils.ts +151 -0
  242. package/src/handlers/source-writer.ts +649 -0
  243. package/src/html-processor.ts +1108 -0
  244. package/src/index.ts +284 -0
  245. package/src/manifest-writer.ts +371 -0
  246. package/src/media/contember.ts +84 -0
  247. package/src/media/local.ts +114 -0
  248. package/src/media/s3.ts +133 -0
  249. package/src/media/types.ts +33 -0
  250. package/src/preview-generator.ts +293 -0
  251. package/src/seo-processor.ts +567 -0
  252. package/src/source-finder/ast-extractors.ts +185 -0
  253. package/src/source-finder/ast-parser.ts +150 -0
  254. package/src/source-finder/cache.ts +76 -0
  255. package/src/source-finder/collection-finder.ts +335 -0
  256. package/src/source-finder/cross-file-tracker.ts +741 -0
  257. package/src/source-finder/element-finder.ts +387 -0
  258. package/src/source-finder/image-finder.ts +283 -0
  259. package/src/source-finder/index.ts +37 -0
  260. package/src/source-finder/search-index.ts +525 -0
  261. package/src/source-finder/snippet-utils.ts +668 -0
  262. package/src/source-finder/source-lookup.ts +200 -0
  263. package/src/source-finder/types.ts +210 -0
  264. package/src/source-finder/variable-extraction.ts +406 -0
  265. package/src/tailwind-colors.ts +874 -0
  266. package/src/tsconfig.json +25 -0
  267. package/src/types.ts +406 -0
  268. package/src/utils.ts +186 -0
  269. package/src/vite-plugin.ts +42 -0
@@ -0,0 +1,266 @@
1
+ import { STORAGE_KEYS } from './constants'
2
+ import type {
3
+ CmsSettings,
4
+ PendingAttributeChange,
5
+ PendingChange,
6
+ PendingColorChange,
7
+ PendingImageChange,
8
+ SavedAttributeEdits,
9
+ SavedColorEdits,
10
+ SavedEdits,
11
+ SavedImageEdits,
12
+ } from './types'
13
+
14
+ // ============================================================================
15
+ // Text Edits
16
+ // ============================================================================
17
+
18
+ export function saveEditsToStorage(pendingChanges: Map<string, PendingChange>): void {
19
+ const edits: SavedEdits = {}
20
+
21
+ pendingChanges.forEach((change, cmsId) => {
22
+ if (change.isDirty) {
23
+ edits[cmsId] = {
24
+ originalText: change.originalText,
25
+ newText: change.newText,
26
+ currentHTML: change.currentHTML,
27
+ hasStyledContent: change.hasStyledContent,
28
+ }
29
+ }
30
+ })
31
+
32
+ try {
33
+ sessionStorage.setItem(STORAGE_KEYS.PENDING_EDITS, JSON.stringify(edits))
34
+ } catch (e) {
35
+ console.warn('[CMS] Failed to save edits to storage:', e)
36
+ }
37
+ }
38
+
39
+ export function loadEditsFromStorage(): SavedEdits {
40
+ try {
41
+ const stored = sessionStorage.getItem(STORAGE_KEYS.PENDING_EDITS)
42
+ return stored ? JSON.parse(stored) : {}
43
+ } catch (e) {
44
+ console.warn('[CMS] Failed to load edits from storage:', e)
45
+ return {}
46
+ }
47
+ }
48
+
49
+ export function clearEditsFromStorage(): void {
50
+ try {
51
+ sessionStorage.removeItem(STORAGE_KEYS.PENDING_EDITS)
52
+ } catch (e) {
53
+ console.warn('[CMS] Failed to clear edits from storage:', e)
54
+ }
55
+ }
56
+
57
+ // ============================================================================
58
+ // Image Edits
59
+ // ============================================================================
60
+
61
+ export function saveImageEditsToStorage(pendingImageChanges: Map<string, PendingImageChange>): void {
62
+ const edits: SavedImageEdits = {}
63
+
64
+ pendingImageChanges.forEach((change, cmsId) => {
65
+ if (change.isDirty) {
66
+ edits[cmsId] = {
67
+ originalSrc: change.originalSrc,
68
+ newSrc: change.newSrc,
69
+ originalAlt: change.originalAlt,
70
+ newAlt: change.newAlt,
71
+ originalSrcSet: change.originalSrcSet,
72
+ }
73
+ }
74
+ })
75
+
76
+ try {
77
+ sessionStorage.setItem(STORAGE_KEYS.PENDING_IMAGE_EDITS, JSON.stringify(edits))
78
+ } catch (e) {
79
+ console.warn('[CMS] Failed to save image edits to storage:', e)
80
+ }
81
+ }
82
+
83
+ export function loadImageEditsFromStorage(): SavedImageEdits {
84
+ try {
85
+ const stored = sessionStorage.getItem(STORAGE_KEYS.PENDING_IMAGE_EDITS)
86
+ return stored ? JSON.parse(stored) : {}
87
+ } catch (e) {
88
+ console.warn('[CMS] Failed to load image edits from storage:', e)
89
+ return {}
90
+ }
91
+ }
92
+
93
+ export function clearImageEditsFromStorage(): void {
94
+ try {
95
+ sessionStorage.removeItem(STORAGE_KEYS.PENDING_IMAGE_EDITS)
96
+ } catch (e) {
97
+ console.warn('[CMS] Failed to clear image edits from storage:', e)
98
+ }
99
+ }
100
+
101
+ // ============================================================================
102
+ // Color Edits
103
+ // ============================================================================
104
+
105
+ export function saveColorEditsToStorage(pendingColorChanges: Map<string, PendingColorChange>): void {
106
+ const edits: SavedColorEdits = {}
107
+
108
+ pendingColorChanges.forEach((change, cmsId) => {
109
+ if (change.isDirty) {
110
+ edits[cmsId] = {
111
+ originalClasses: change.originalClasses,
112
+ newClasses: change.newClasses,
113
+ }
114
+ }
115
+ })
116
+
117
+ try {
118
+ sessionStorage.setItem(STORAGE_KEYS.PENDING_COLOR_EDITS, JSON.stringify(edits))
119
+ } catch (e) {
120
+ console.warn('[CMS] Failed to save color edits to storage:', e)
121
+ }
122
+ }
123
+
124
+ export function loadColorEditsFromStorage(): SavedColorEdits {
125
+ try {
126
+ const stored = sessionStorage.getItem(STORAGE_KEYS.PENDING_COLOR_EDITS)
127
+ return stored ? JSON.parse(stored) : {}
128
+ } catch (e) {
129
+ console.warn('[CMS] Failed to load color edits from storage:', e)
130
+ return {}
131
+ }
132
+ }
133
+
134
+ export function clearColorEditsFromStorage(): void {
135
+ try {
136
+ sessionStorage.removeItem(STORAGE_KEYS.PENDING_COLOR_EDITS)
137
+ } catch (e) {
138
+ console.warn('[CMS] Failed to clear color edits from storage:', e)
139
+ }
140
+ }
141
+
142
+ // ============================================================================
143
+ // Attribute Edits
144
+ // ============================================================================
145
+
146
+ export function saveAttributeEditsToStorage(pendingAttributeChanges: Map<string, PendingAttributeChange>): void {
147
+ const edits: SavedAttributeEdits = {}
148
+
149
+ pendingAttributeChanges.forEach((change, cmsId) => {
150
+ if (change.isDirty) {
151
+ edits[cmsId] = {
152
+ originalAttributes: change.originalAttributes,
153
+ newAttributes: change.newAttributes,
154
+ }
155
+ }
156
+ })
157
+
158
+ try {
159
+ sessionStorage.setItem(STORAGE_KEYS.PENDING_ATTRIBUTE_EDITS, JSON.stringify(edits))
160
+ } catch (e) {
161
+ console.warn('[CMS] Failed to save attribute edits to storage:', e)
162
+ }
163
+ }
164
+
165
+ export function loadAttributeEditsFromStorage(): SavedAttributeEdits {
166
+ try {
167
+ const stored = sessionStorage.getItem(STORAGE_KEYS.PENDING_ATTRIBUTE_EDITS)
168
+ return stored ? JSON.parse(stored) : {}
169
+ } catch (e) {
170
+ console.warn('[CMS] Failed to load attribute edits from storage:', e)
171
+ return {}
172
+ }
173
+ }
174
+
175
+ export function clearAttributeEditsFromStorage(): void {
176
+ try {
177
+ sessionStorage.removeItem(STORAGE_KEYS.PENDING_ATTRIBUTE_EDITS)
178
+ } catch (e) {
179
+ console.warn('[CMS] Failed to clear attribute edits from storage:', e)
180
+ }
181
+ }
182
+
183
+ // ============================================================================
184
+ // Settings
185
+ // ============================================================================
186
+
187
+ export function saveSettingsToStorage(settings: CmsSettings): void {
188
+ try {
189
+ localStorage.setItem(STORAGE_KEYS.SETTINGS, JSON.stringify(settings))
190
+ } catch (e) {
191
+ console.warn('[CMS] Failed to save settings to storage:', e)
192
+ }
193
+ }
194
+
195
+ export function loadSettingsFromStorage(): CmsSettings | null {
196
+ try {
197
+ const stored = localStorage.getItem(STORAGE_KEYS.SETTINGS)
198
+ return stored ? JSON.parse(stored) : null
199
+ } catch (e) {
200
+ console.warn('[CMS] Failed to load settings from storage:', e)
201
+ return null
202
+ }
203
+ }
204
+
205
+ export function clearSettingsFromStorage(): void {
206
+ try {
207
+ localStorage.removeItem(STORAGE_KEYS.SETTINGS)
208
+ } catch (e) {
209
+ console.warn('[CMS] Failed to clear settings from storage:', e)
210
+ }
211
+ }
212
+
213
+ // ============================================================================
214
+ // Pending Entry Navigation (for navigating to a collection entry page and auto-opening editor)
215
+ // ============================================================================
216
+
217
+ export interface PendingEntryNavigation {
218
+ collectionName: string
219
+ slug: string
220
+ sourcePath: string
221
+ pathname: string
222
+ }
223
+
224
+ export function savePendingEntryNavigation(entry: PendingEntryNavigation): void {
225
+ try {
226
+ sessionStorage.setItem(STORAGE_KEYS.PENDING_ENTRY_NAVIGATION, JSON.stringify(entry))
227
+ } catch (e) {
228
+ console.warn('[CMS] Failed to save pending entry navigation:', e)
229
+ }
230
+ }
231
+
232
+ export function hasPendingEntryNavigation(): boolean {
233
+ try {
234
+ const stored = sessionStorage.getItem(STORAGE_KEYS.PENDING_ENTRY_NAVIGATION)
235
+ if (!stored) return false
236
+ const entry: PendingEntryNavigation = JSON.parse(stored)
237
+ return window.location.pathname === entry.pathname
238
+ } catch {
239
+ return false
240
+ }
241
+ }
242
+
243
+ export function loadPendingEntryNavigation(): PendingEntryNavigation | null {
244
+ try {
245
+ const stored = sessionStorage.getItem(STORAGE_KEYS.PENDING_ENTRY_NAVIGATION)
246
+ if (!stored) return null
247
+ const entry: PendingEntryNavigation = JSON.parse(stored)
248
+ if (window.location.pathname !== entry.pathname) return null
249
+ sessionStorage.removeItem(STORAGE_KEYS.PENDING_ENTRY_NAVIGATION)
250
+ return entry
251
+ } catch (e) {
252
+ console.warn('[CMS] Failed to load pending entry navigation:', e)
253
+ return null
254
+ }
255
+ }
256
+
257
+ // ============================================================================
258
+ // Clear All
259
+ // ============================================================================
260
+
261
+ export function clearAllEditsFromStorage(): void {
262
+ clearEditsFromStorage()
263
+ clearImageEditsFromStorage()
264
+ clearColorEditsFromStorage()
265
+ clearAttributeEditsFromStorage()
266
+ }
@@ -0,0 +1,465 @@
1
+ @import "tailwindcss";
2
+
3
+ @source "./components/**/*.tsx";
4
+ @source "./index.tsx";
5
+
6
+ @theme {
7
+ /* Surface Colors */
8
+ --color-cms-bg: #E8E8E8;
9
+ --color-cms-card: #FFFFFF;
10
+ --color-cms-overlay: rgba(0, 0, 0, 0.3);
11
+
12
+ /* Brand Colors - Neutral with lime accent */
13
+ --color-cms-primary: #DFFF40;
14
+ --color-cms-primary-hover: #d4f535;
15
+ --color-cms-primary-text: #1A1A1A;
16
+ --color-cms-accent: #B8C5F2;
17
+ --color-cms-accent-hover: #a8b5e2;
18
+ --color-cms-dark: #1A1A1A;
19
+ --color-cms-dark-hover: #333333;
20
+
21
+ /* Text Colors */
22
+ --color-cms-text: #1A1A1A;
23
+ --color-cms-text-muted: #6B6B6B;
24
+ --color-cms-text-subtle: #9A9A9A;
25
+
26
+ /* Semantic Colors */
27
+ --color-cms-success: #1A1A1A;
28
+ --color-cms-error: #E53935;
29
+ --color-cms-warning: #F59E0B;
30
+
31
+ /* Border & Radius */
32
+ --color-cms-border: rgba(0, 0, 0, 0.08);
33
+ --radius-cms-sm: 8px;
34
+ --radius-cms-md: 16px;
35
+ --radius-cms-lg: 24px;
36
+ --radius-cms-xl: 32px;
37
+ --radius-cms-pill: 9999px;
38
+
39
+ /* Shadows (soft, diffused) */
40
+ --shadow-cms-sm: 0 1px 3px rgba(0,0,0,0.04);
41
+ --shadow-cms-md: 0 2px 8px rgba(0,0,0,0.04);
42
+ --shadow-cms-lg: 0 4px 20px rgba(0,0,0,0.06);
43
+ --shadow-cms-xl: 0 8px 30px rgba(0,0,0,0.08);
44
+
45
+ /* Legacy mappings for backwards compat */
46
+ --color-blue-bold: var(--color-cms-dark);
47
+ --shadow-brutalist-sm: var(--shadow-cms-md);
48
+ --shadow-brutalist-md: var(--shadow-cms-lg);
49
+ }
50
+
51
+ /* Reset for shadow DOM isolation */
52
+ :host {
53
+ all: initial;
54
+ }
55
+
56
+ .cms-root {
57
+ font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
58
+ line-height: 1.5;
59
+ -webkit-font-smoothing: antialiased;
60
+ -moz-osx-font-smoothing: grayscale;
61
+ }
62
+
63
+ .cms-root *,
64
+ .cms-root *::before,
65
+ .cms-root *::after {
66
+ box-sizing: border-box;
67
+ }
68
+
69
+ /* Custom animations for CMS */
70
+ @keyframes spin {
71
+ from { transform: rotate(0deg); }
72
+ to { transform: rotate(360deg); }
73
+ }
74
+
75
+ @keyframes slideIn {
76
+ from {
77
+ opacity: 0;
78
+ transform: translateY(10px);
79
+ }
80
+ to {
81
+ opacity: 1;
82
+ transform: translateY(0);
83
+ }
84
+ }
85
+
86
+ .spinning {
87
+ animation: spin 1s linear infinite;
88
+ }
89
+
90
+ /* Markdown styles for AI chat messages */
91
+ .cms-markdown p {
92
+ margin: 0 0 0.5em 0;
93
+ }
94
+
95
+ .cms-markdown p:last-child {
96
+ margin-bottom: 0;
97
+ }
98
+
99
+ .cms-markdown strong {
100
+ font-weight: 700;
101
+ }
102
+
103
+ .cms-markdown em {
104
+ font-style: italic;
105
+ }
106
+
107
+ .cms-markdown code {
108
+ background: rgba(255, 255, 255, 0.1);
109
+ padding: 0.1em 0.3em;
110
+ border-radius: 3px;
111
+ font-family: ui-monospace, monospace;
112
+ font-size: 0.9em;
113
+ }
114
+
115
+ .cms-markdown pre {
116
+ background: rgba(0, 0, 0, 0.3);
117
+ padding: 0.75em;
118
+ border-radius: 4px;
119
+ overflow-x: auto;
120
+ margin: 0.5em 0;
121
+ }
122
+
123
+ .cms-markdown pre code {
124
+ background: none;
125
+ padding: 0;
126
+ }
127
+
128
+ .cms-markdown ul {
129
+ margin: 0.5em 0;
130
+ padding-left: 1.5em;
131
+ list-style-type: disc;
132
+ }
133
+
134
+ .cms-markdown ol {
135
+ margin: 0.5em 0;
136
+ padding-left: 1.5em;
137
+ list-style-type: decimal;
138
+ }
139
+
140
+ .cms-markdown ul ul {
141
+ list-style-type: circle;
142
+ }
143
+
144
+ .cms-markdown ul ul ul {
145
+ list-style-type: square;
146
+ }
147
+
148
+ .cms-markdown li {
149
+ margin: 0.25em 0;
150
+ display: list-item;
151
+ }
152
+
153
+ .cms-markdown h1, .cms-markdown h2, .cms-markdown h3,
154
+ .cms-markdown h4, .cms-markdown h5, .cms-markdown h6 {
155
+ margin: 0.75em 0 0.25em 0;
156
+ font-weight: 600;
157
+ line-height: 1.3;
158
+ }
159
+
160
+ .cms-markdown h1 {
161
+ font-size: 1.4em;
162
+ }
163
+
164
+ .cms-markdown h2 {
165
+ font-size: 1.2em;
166
+ }
167
+
168
+ .cms-markdown h3 {
169
+ font-size: 1.1em;
170
+ }
171
+
172
+ .cms-markdown h1:first-child, .cms-markdown h2:first-child, .cms-markdown h3:first-child {
173
+ margin-top: 0;
174
+ }
175
+
176
+ .cms-markdown hr {
177
+ border: none;
178
+ border-top: 1px solid rgba(255, 255, 255, 0.15);
179
+ margin: 0.75em 0;
180
+ }
181
+
182
+ .cms-markdown a {
183
+ color: #93c5fd;
184
+ text-decoration: underline;
185
+ }
186
+
187
+ .cms-markdown a:hover {
188
+ color: #bfdbfe;
189
+ }
190
+
191
+ .cms-markdown blockquote {
192
+ border-left: 3px solid #93c5fd;
193
+ margin: 0.5em 0;
194
+ padding-left: 1em;
195
+ color: rgba(255, 255, 255, 0.7);
196
+ }
197
+
198
+ /* Soft Design System Card Component */
199
+ .cms-card {
200
+ background: var(--color-cms-card);
201
+ border-radius: var(--radius-cms-lg);
202
+ box-shadow: var(--shadow-cms-lg);
203
+ border: 1px solid var(--color-cms-border);
204
+ }
205
+
206
+ /* Button variants */
207
+ .cms-btn {
208
+ padding: 10px 20px;
209
+ border-radius: var(--radius-cms-pill);
210
+ font-weight: 500;
211
+ transition: all 150ms ease;
212
+ border: none;
213
+ cursor: pointer;
214
+ }
215
+
216
+ .cms-btn-primary {
217
+ background: var(--color-cms-primary);
218
+ color: var(--color-cms-primary-text);
219
+ }
220
+
221
+ .cms-btn-primary:hover {
222
+ background: var(--color-cms-primary-hover);
223
+ }
224
+
225
+ .cms-btn-secondary {
226
+ background: var(--color-cms-secondary);
227
+ color: white;
228
+ }
229
+
230
+ .cms-btn-secondary:hover {
231
+ background: var(--color-cms-secondary-hover);
232
+ }
233
+
234
+ .slide-in {
235
+ animation: slideIn 0.2s ease;
236
+ }
237
+
238
+ /* Milkdown editor styles */
239
+ .milkdown-editor {
240
+ min-height: 200px;
241
+ }
242
+
243
+ .milkdown-editor .editor {
244
+ outline: none;
245
+ }
246
+
247
+ .milkdown-editor .ProseMirror {
248
+ outline: none;
249
+ min-height: 150px;
250
+ }
251
+
252
+ .milkdown-editor .ProseMirror p {
253
+ margin: 0 0 1em 0;
254
+ }
255
+
256
+ .milkdown-editor .ProseMirror img {
257
+ max-width: 100%;
258
+ height: auto;
259
+ display: block;
260
+ margin: 1em 0;
261
+ border-radius: 8px;
262
+ }
263
+
264
+ .milkdown-editor .ProseMirror h1,
265
+ .milkdown-editor .ProseMirror h2,
266
+ .milkdown-editor .ProseMirror h3,
267
+ .milkdown-editor .ProseMirror h4,
268
+ .milkdown-editor .ProseMirror h5,
269
+ .milkdown-editor .ProseMirror h6 {
270
+ margin-top: 1.5em;
271
+ margin-bottom: 0.5em;
272
+ font-weight: 600;
273
+ }
274
+
275
+ .milkdown-editor .ProseMirror ul {
276
+ padding-left: 1.5em;
277
+ margin: 1em 0;
278
+ list-style-type: disc;
279
+ }
280
+
281
+ .milkdown-editor .ProseMirror ol {
282
+ padding-left: 1.5em;
283
+ margin: 1em 0;
284
+ list-style-type: decimal;
285
+ }
286
+
287
+ .milkdown-editor .ProseMirror li {
288
+ display: list-item;
289
+ margin: 0.25em 0;
290
+ }
291
+
292
+ .milkdown-editor .ProseMirror ul ul {
293
+ list-style-type: circle;
294
+ }
295
+
296
+ .milkdown-editor .ProseMirror ul ul ul {
297
+ list-style-type: square;
298
+ }
299
+
300
+ .milkdown-editor .ProseMirror blockquote {
301
+ border-left: 3px solid #e5e5e5;
302
+ padding-left: 1em;
303
+ margin: 1em 0;
304
+ color: #666;
305
+ }
306
+
307
+ .milkdown-editor .ProseMirror code {
308
+ background: rgba(0, 0, 0, 0.05);
309
+ padding: 0.1em 0.3em;
310
+ border-radius: 3px;
311
+ font-family: ui-monospace, monospace;
312
+ font-size: 0.9em;
313
+ }
314
+
315
+ .milkdown-editor .ProseMirror pre {
316
+ background: rgba(0, 0, 0, 0.05);
317
+ padding: 1em;
318
+ border-radius: 4px;
319
+ overflow-x: auto;
320
+ }
321
+
322
+ .milkdown-editor .ProseMirror a {
323
+ color: #2563eb;
324
+ text-decoration: underline;
325
+ }
326
+
327
+ /* Dark mode milkdown editor */
328
+ .milkdown-dark.milkdown-editor {
329
+ background: transparent;
330
+ color: rgba(255, 255, 255, 0.9);
331
+ }
332
+
333
+ .milkdown-dark .ProseMirror {
334
+ color: rgba(255, 255, 255, 0.9);
335
+ caret-color: var(--color-cms-primary);
336
+ }
337
+
338
+ .milkdown-dark .ProseMirror p {
339
+ color: rgba(255, 255, 255, 0.85);
340
+ }
341
+
342
+ .milkdown-dark .ProseMirror h1,
343
+ .milkdown-dark .ProseMirror h2,
344
+ .milkdown-dark .ProseMirror h3,
345
+ .milkdown-dark .ProseMirror h4,
346
+ .milkdown-dark .ProseMirror h5,
347
+ .milkdown-dark .ProseMirror h6 {
348
+ color: white;
349
+ }
350
+
351
+ .milkdown-dark .ProseMirror h1 {
352
+ font-size: 1.75em;
353
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
354
+ padding-bottom: 0.3em;
355
+ }
356
+
357
+ .milkdown-dark .ProseMirror h2 {
358
+ font-size: 1.5em;
359
+ }
360
+
361
+ .milkdown-dark .ProseMirror h3 {
362
+ font-size: 1.25em;
363
+ }
364
+
365
+ .milkdown-dark .ProseMirror strong {
366
+ color: white;
367
+ font-weight: 600;
368
+ }
369
+
370
+ .milkdown-dark .ProseMirror em {
371
+ color: rgba(255, 255, 255, 0.9);
372
+ }
373
+
374
+ .milkdown-dark .ProseMirror blockquote {
375
+ border-left: 3px solid var(--color-cms-primary);
376
+ background: rgba(255, 255, 255, 0.05);
377
+ padding: 0.5em 1em;
378
+ margin: 1em 0;
379
+ color: rgba(255, 255, 255, 0.7);
380
+ border-radius: 0 8px 8px 0;
381
+ }
382
+
383
+ .milkdown-dark .ProseMirror code {
384
+ background: rgba(255, 255, 255, 0.1);
385
+ color: var(--color-cms-primary);
386
+ padding: 0.15em 0.4em;
387
+ border-radius: 4px;
388
+ }
389
+
390
+ .milkdown-dark .ProseMirror pre {
391
+ background: rgba(0, 0, 0, 0.3);
392
+ border: 1px solid rgba(255, 255, 255, 0.1);
393
+ border-radius: 8px;
394
+ padding: 1em;
395
+ }
396
+
397
+ .milkdown-dark .ProseMirror pre code {
398
+ background: none;
399
+ color: rgba(255, 255, 255, 0.85);
400
+ padding: 0;
401
+ }
402
+
403
+ .milkdown-dark .ProseMirror a {
404
+ color: var(--color-cms-primary);
405
+ text-decoration: underline;
406
+ text-underline-offset: 2px;
407
+ }
408
+
409
+ .milkdown-dark .ProseMirror a:hover {
410
+ color: var(--color-cms-primary-hover);
411
+ }
412
+
413
+ .milkdown-dark .ProseMirror ul {
414
+ color: rgba(255, 255, 255, 0.85);
415
+ list-style-type: disc;
416
+ padding-left: 1.5em;
417
+ }
418
+
419
+ .milkdown-dark .ProseMirror ol {
420
+ color: rgba(255, 255, 255, 0.85);
421
+ list-style-type: decimal;
422
+ padding-left: 1.5em;
423
+ }
424
+
425
+ .milkdown-dark .ProseMirror ul ul {
426
+ list-style-type: circle;
427
+ }
428
+
429
+ .milkdown-dark .ProseMirror ul ul ul {
430
+ list-style-type: square;
431
+ }
432
+
433
+ .milkdown-dark .ProseMirror li {
434
+ display: list-item;
435
+ margin: 0.5em 0;
436
+ }
437
+
438
+ .milkdown-dark .ProseMirror li::marker {
439
+ color: var(--color-cms-primary);
440
+ }
441
+
442
+ .milkdown-dark .ProseMirror hr {
443
+ border: none;
444
+ border-top: 1px solid rgba(255, 255, 255, 0.1);
445
+ margin: 2em 0;
446
+ }
447
+
448
+ .milkdown-dark .ProseMirror img {
449
+ border-radius: 8px;
450
+ border: 1px solid rgba(255, 255, 255, 0.1);
451
+ }
452
+
453
+ /* Selection styling for dark mode */
454
+ .milkdown-dark .ProseMirror ::selection {
455
+ background: rgba(223, 255, 64, 0.3);
456
+ }
457
+
458
+ /* Placeholder styling */
459
+ .milkdown-dark .ProseMirror p.is-editor-empty:first-child::before {
460
+ content: 'Start writing...';
461
+ color: rgba(255, 255, 255, 0.3);
462
+ pointer-events: none;
463
+ float: left;
464
+ height: 0;
465
+ }