@imjp/writenex-astro 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 (141) hide show
  1. package/README.md +539 -0
  2. package/dist/chunk-5PM6EQE5.js +151 -0
  3. package/dist/chunk-5PM6EQE5.js.map +1 -0
  4. package/dist/chunk-7XU5X6CW.js +1331 -0
  5. package/dist/chunk-7XU5X6CW.js.map +1 -0
  6. package/dist/chunk-AAOQHQPU.js +574 -0
  7. package/dist/chunk-AAOQHQPU.js.map +1 -0
  8. package/dist/chunk-CF2XXJFF.js +1410 -0
  9. package/dist/chunk-CF2XXJFF.js.map +1 -0
  10. package/dist/chunk-CRPZUUDU.js +52 -0
  11. package/dist/chunk-CRPZUUDU.js.map +1 -0
  12. package/dist/chunk-CYLDJ3HZ.js +310 -0
  13. package/dist/chunk-CYLDJ3HZ.js.map +1 -0
  14. package/dist/chunk-KIKIPIFA.js +1 -0
  15. package/dist/chunk-KIKIPIFA.js.map +1 -0
  16. package/dist/chunk-XNTQTTJU.js +145 -0
  17. package/dist/chunk-XNTQTTJU.js.map +1 -0
  18. package/dist/client/index.css +2 -0
  19. package/dist/client/index.css.map +1 -0
  20. package/dist/client/index.js +375 -0
  21. package/dist/client/index.js.map +1 -0
  22. package/dist/client/styles.css +584 -0
  23. package/dist/client/variables.css +304 -0
  24. package/dist/config/index.d.ts +54 -0
  25. package/dist/config/index.js +38 -0
  26. package/dist/config/index.js.map +1 -0
  27. package/dist/config-BmEdBDo_.d.ts +220 -0
  28. package/dist/content-BWR52vD-.d.ts +64 -0
  29. package/dist/discovery/index.d.ts +310 -0
  30. package/dist/discovery/index.js +38 -0
  31. package/dist/discovery/index.js.map +1 -0
  32. package/dist/errors-C0iYiDTv.d.ts +107 -0
  33. package/dist/filesystem/index.d.ts +1292 -0
  34. package/dist/filesystem/index.js +203 -0
  35. package/dist/filesystem/index.js.map +1 -0
  36. package/dist/image-FP7w5ZIs.d.ts +47 -0
  37. package/dist/index.d.ts +64 -0
  38. package/dist/index.js +151 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/loader-55LWCXHA.js +12 -0
  41. package/dist/loader-55LWCXHA.js.map +1 -0
  42. package/dist/loader-CrdnaAWR.d.ts +327 -0
  43. package/dist/server/index.d.ts +357 -0
  44. package/dist/server/index.js +37 -0
  45. package/dist/server/index.js.map +1 -0
  46. package/package.json +94 -0
  47. package/src/client/App.tsx +900 -0
  48. package/src/client/components/ConfigPanel/ConfigPanel.css +553 -0
  49. package/src/client/components/ConfigPanel/ConfigPanel.tsx +396 -0
  50. package/src/client/components/ConfigPanel/index.ts +6 -0
  51. package/src/client/components/CreateContentModal/CreateContentModal.css +327 -0
  52. package/src/client/components/CreateContentModal/CreateContentModal.tsx +216 -0
  53. package/src/client/components/CreateContentModal/index.ts +7 -0
  54. package/src/client/components/Editor/Editor.css +885 -0
  55. package/src/client/components/Editor/Editor.tsx +484 -0
  56. package/src/client/components/Editor/ImageDialog.css +344 -0
  57. package/src/client/components/Editor/ImageDialog.tsx +367 -0
  58. package/src/client/components/Editor/LinkDialog.css +326 -0
  59. package/src/client/components/Editor/LinkDialog.tsx +332 -0
  60. package/src/client/components/Editor/index.ts +6 -0
  61. package/src/client/components/FrontmatterForm/FrontmatterForm.css +468 -0
  62. package/src/client/components/FrontmatterForm/FrontmatterForm.tsx +914 -0
  63. package/src/client/components/FrontmatterForm/index.ts +7 -0
  64. package/src/client/components/Header/Header.css +300 -0
  65. package/src/client/components/Header/Header.tsx +300 -0
  66. package/src/client/components/Header/index.ts +7 -0
  67. package/src/client/components/KeyboardShortcuts/KeyboardShortcuts.css +239 -0
  68. package/src/client/components/KeyboardShortcuts/KeyboardShortcuts.tsx +151 -0
  69. package/src/client/components/KeyboardShortcuts/index.ts +6 -0
  70. package/src/client/components/LazyEditor.tsx +75 -0
  71. package/src/client/components/LiveRegion/LiveRegion.css +19 -0
  72. package/src/client/components/LiveRegion/LiveRegion.tsx +60 -0
  73. package/src/client/components/LiveRegion/index.ts +7 -0
  74. package/src/client/components/SearchReplace/SearchReplacePanel.css +300 -0
  75. package/src/client/components/SearchReplace/SearchReplacePanel.tsx +332 -0
  76. package/src/client/components/SearchReplace/index.ts +7 -0
  77. package/src/client/components/SelectCollectionModal/SelectCollectionModal.css +308 -0
  78. package/src/client/components/SelectCollectionModal/SelectCollectionModal.tsx +223 -0
  79. package/src/client/components/SelectCollectionModal/index.ts +7 -0
  80. package/src/client/components/Sidebar/Sidebar.css +570 -0
  81. package/src/client/components/Sidebar/Sidebar.tsx +617 -0
  82. package/src/client/components/Sidebar/index.ts +7 -0
  83. package/src/client/components/SkipLink/SkipLink.css +51 -0
  84. package/src/client/components/SkipLink/SkipLink.tsx +67 -0
  85. package/src/client/components/SkipLink/index.ts +7 -0
  86. package/src/client/components/UnsavedChangesModal/UnsavedChangesModal.css +233 -0
  87. package/src/client/components/UnsavedChangesModal/UnsavedChangesModal.tsx +160 -0
  88. package/src/client/components/UnsavedChangesModal/index.ts +1 -0
  89. package/src/client/components/VersionHistory/DiffViewer.css +430 -0
  90. package/src/client/components/VersionHistory/DiffViewer.tsx +383 -0
  91. package/src/client/components/VersionHistory/VersionActions.css +318 -0
  92. package/src/client/components/VersionHistory/VersionActions.tsx +277 -0
  93. package/src/client/components/VersionHistory/VersionHistoryPanel.css +369 -0
  94. package/src/client/components/VersionHistory/VersionHistoryPanel.tsx +469 -0
  95. package/src/client/components/VersionHistory/index.ts +9 -0
  96. package/src/client/context/ApiContext.tsx +154 -0
  97. package/src/client/context/ThemeContext.tsx +172 -0
  98. package/src/client/hooks/useAnnounce.ts +201 -0
  99. package/src/client/hooks/useApi.ts +374 -0
  100. package/src/client/hooks/useArrowNavigation.ts +286 -0
  101. package/src/client/hooks/useAutosave.ts +241 -0
  102. package/src/client/hooks/useFocusTrap.ts +178 -0
  103. package/src/client/hooks/useKeyboardShortcuts.ts +203 -0
  104. package/src/client/hooks/useSearch.ts +206 -0
  105. package/src/client/hooks/useVersionHistory.ts +451 -0
  106. package/src/client/index.tsx +70 -0
  107. package/src/client/styles.css +584 -0
  108. package/src/client/utils/focus.ts +57 -0
  109. package/src/client/utils/openInEditor.ts +130 -0
  110. package/src/client/variables.css +304 -0
  111. package/src/config/defaults.ts +109 -0
  112. package/src/config/index.ts +32 -0
  113. package/src/config/loader.ts +174 -0
  114. package/src/config/schema.ts +161 -0
  115. package/src/core/constants.ts +39 -0
  116. package/src/core/errors.ts +739 -0
  117. package/src/core/index.ts +11 -0
  118. package/src/discovery/collections.ts +216 -0
  119. package/src/discovery/index.ts +33 -0
  120. package/src/discovery/patterns.ts +702 -0
  121. package/src/discovery/schema.ts +453 -0
  122. package/src/filesystem/images.ts +798 -0
  123. package/src/filesystem/index.ts +107 -0
  124. package/src/filesystem/reader.ts +452 -0
  125. package/src/filesystem/version-config.ts +390 -0
  126. package/src/filesystem/versions.ts +1339 -0
  127. package/src/filesystem/watcher.ts +226 -0
  128. package/src/filesystem/writer.ts +540 -0
  129. package/src/index.ts +61 -0
  130. package/src/integration.ts +228 -0
  131. package/src/server/assets.ts +254 -0
  132. package/src/server/cache.ts +355 -0
  133. package/src/server/index.ts +33 -0
  134. package/src/server/middleware.ts +209 -0
  135. package/src/server/routes.ts +1428 -0
  136. package/src/types/api.ts +61 -0
  137. package/src/types/config.ts +134 -0
  138. package/src/types/content.ts +64 -0
  139. package/src/types/image.ts +48 -0
  140. package/src/types/index.ts +58 -0
  141. package/src/types/version.ts +117 -0
@@ -0,0 +1,383 @@
1
+ /**
2
+ * @fileoverview Diff Viewer component
3
+ *
4
+ * Side-by-side or inline diff display for comparing version content.
5
+ * Highlights additions and deletions with color coding.
6
+ * Includes focus trap and ARIA attributes for accessibility compliance.
7
+ *
8
+ * @module @writenex/astro/client/components/VersionHistory/DiffViewer
9
+ */
10
+
11
+ import { useState, useMemo, useEffect, useRef } from "react";
12
+ import { X, Columns, AlignLeft } from "lucide-react";
13
+ import { useFocusTrap } from "../../hooks/useFocusTrap";
14
+ import "./DiffViewer.css";
15
+
16
+ /**
17
+ * Props for the DiffViewer component
18
+ */
19
+ interface DiffViewerProps {
20
+ /** Old content (version) */
21
+ oldContent: string;
22
+ /** New content (current) */
23
+ newContent: string;
24
+ /** Label for old content */
25
+ oldLabel: string;
26
+ /** Label for new content */
27
+ newLabel: string;
28
+ /** Callback to close the viewer */
29
+ onClose: () => void;
30
+ }
31
+
32
+ /**
33
+ * Diff line type
34
+ */
35
+ type DiffLineType = "unchanged" | "added" | "removed";
36
+
37
+ /**
38
+ * Diff line data
39
+ */
40
+ interface DiffLine {
41
+ type: DiffLineType;
42
+ content: string;
43
+ oldLineNum?: number;
44
+ newLineNum?: number;
45
+ }
46
+
47
+ /**
48
+ * Simple line-by-line diff algorithm
49
+ * Uses longest common subsequence approach
50
+ */
51
+ function computeDiff(oldText: string, newText: string): DiffLine[] {
52
+ const oldLines = oldText.split("\n");
53
+ const newLines = newText.split("\n");
54
+ const result: DiffLine[] = [];
55
+
56
+ // Build LCS table
57
+ const m = oldLines.length;
58
+ const n = newLines.length;
59
+ const dp: number[][] = Array(m + 1)
60
+ .fill(null)
61
+ .map(() => Array(n + 1).fill(0));
62
+
63
+ for (let i = 1; i <= m; i++) {
64
+ for (let j = 1; j <= n; j++) {
65
+ if (oldLines[i - 1] === newLines[j - 1]) {
66
+ dp[i][j] = dp[i - 1][j - 1] + 1;
67
+ } else {
68
+ dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
69
+ }
70
+ }
71
+ }
72
+
73
+ // Backtrack to find diff
74
+ let i = m;
75
+ let j = n;
76
+ const stack: DiffLine[] = [];
77
+
78
+ while (i > 0 || j > 0) {
79
+ if (i > 0 && j > 0 && oldLines[i - 1] === newLines[j - 1]) {
80
+ stack.push({
81
+ type: "unchanged",
82
+ content: oldLines[i - 1],
83
+ oldLineNum: i,
84
+ newLineNum: j,
85
+ });
86
+ i--;
87
+ j--;
88
+ } else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
89
+ stack.push({
90
+ type: "added",
91
+ content: newLines[j - 1],
92
+ newLineNum: j,
93
+ });
94
+ j--;
95
+ } else if (i > 0) {
96
+ stack.push({
97
+ type: "removed",
98
+ content: oldLines[i - 1],
99
+ oldLineNum: i,
100
+ });
101
+ i--;
102
+ }
103
+ }
104
+
105
+ // Reverse to get correct order
106
+ while (stack.length > 0) {
107
+ result.push(stack.pop()!);
108
+ }
109
+
110
+ return result;
111
+ }
112
+
113
+ /**
114
+ * Diff Viewer component
115
+ *
116
+ * @component
117
+ * @example
118
+ * ```tsx
119
+ * <DiffViewer
120
+ * oldContent={versionContent}
121
+ * newContent={currentContent}
122
+ * oldLabel="Version: 2h ago"
123
+ * newLabel="Current"
124
+ * onClose={() => setShowDiff(false)}
125
+ * />
126
+ * ```
127
+ */
128
+ export function DiffViewer({
129
+ oldContent,
130
+ newContent,
131
+ oldLabel,
132
+ newLabel,
133
+ onClose,
134
+ }: DiffViewerProps): React.ReactElement {
135
+ const [viewMode, setViewMode] = useState<"split" | "unified">("split");
136
+ const triggerRef = useRef<HTMLElement | null>(null);
137
+
138
+ // Store the trigger element when modal mounts
139
+ useEffect(() => {
140
+ triggerRef.current = document.activeElement as HTMLElement;
141
+ }, []);
142
+
143
+ // Focus trap for accessibility
144
+ const { containerRef } = useFocusTrap({
145
+ enabled: true,
146
+ onEscape: onClose,
147
+ returnFocusTo: triggerRef.current,
148
+ });
149
+
150
+ const diffLines = useMemo(
151
+ () => computeDiff(oldContent, newContent),
152
+ [oldContent, newContent]
153
+ );
154
+
155
+ const stats = useMemo(() => {
156
+ let additions = 0;
157
+ let deletions = 0;
158
+ for (const line of diffLines) {
159
+ if (line.type === "added") additions++;
160
+ if (line.type === "removed") deletions++;
161
+ }
162
+ return { additions, deletions };
163
+ }, [diffLines]);
164
+
165
+ const handleOverlayClick = (e: React.MouseEvent) => {
166
+ if (e.target === e.currentTarget) onClose();
167
+ };
168
+
169
+ return (
170
+ <div className="wn-diff-overlay" onClick={handleOverlayClick}>
171
+ <div
172
+ ref={containerRef}
173
+ className="wn-diff-modal"
174
+ role="dialog"
175
+ aria-modal="true"
176
+ aria-labelledby="diff-viewer-title"
177
+ >
178
+ {/* Header */}
179
+ <div className="wn-diff-header">
180
+ <div className="wn-diff-header-left">
181
+ <h2 id="diff-viewer-title" className="wn-diff-title">
182
+ Compare Versions
183
+ </h2>
184
+ <div className="wn-diff-stats">
185
+ <span className="wn-diff-stat wn-diff-stat--added">
186
+ +{stats.additions}
187
+ </span>
188
+ <span className="wn-diff-stat wn-diff-stat--removed">
189
+ -{stats.deletions}
190
+ </span>
191
+ </div>
192
+ </div>
193
+ <div className="wn-diff-header-right">
194
+ <div
195
+ className="wn-diff-view-toggle"
196
+ role="group"
197
+ aria-label="View mode"
198
+ >
199
+ <button
200
+ className={`wn-diff-view-btn ${viewMode === "split" ? "wn-diff-view-btn--active" : ""}`}
201
+ onClick={() => setViewMode("split")}
202
+ title="Split view"
203
+ aria-pressed={viewMode === "split"}
204
+ aria-label="Split view"
205
+ >
206
+ <Columns size={14} />
207
+ </button>
208
+ <button
209
+ className={`wn-diff-view-btn ${viewMode === "unified" ? "wn-diff-view-btn--active" : ""}`}
210
+ onClick={() => setViewMode("unified")}
211
+ title="Unified view"
212
+ aria-pressed={viewMode === "unified"}
213
+ aria-label="Unified view"
214
+ >
215
+ <AlignLeft size={14} />
216
+ </button>
217
+ </div>
218
+ <button
219
+ className="wn-diff-close"
220
+ onClick={onClose}
221
+ title="Close"
222
+ aria-label="Close diff viewer"
223
+ >
224
+ <X size={16} />
225
+ </button>
226
+ </div>
227
+ </div>
228
+
229
+ {/* Content */}
230
+ <div className="wn-diff-content">
231
+ {viewMode === "split" ? (
232
+ <SplitView
233
+ diffLines={diffLines}
234
+ oldLabel={oldLabel}
235
+ newLabel={newLabel}
236
+ />
237
+ ) : (
238
+ <UnifiedView
239
+ diffLines={diffLines}
240
+ oldLabel={oldLabel}
241
+ newLabel={newLabel}
242
+ />
243
+ )}
244
+ </div>
245
+ </div>
246
+ </div>
247
+ );
248
+ }
249
+
250
+ /**
251
+ * Split view component
252
+ */
253
+ function SplitView({
254
+ diffLines,
255
+ oldLabel,
256
+ newLabel,
257
+ }: {
258
+ diffLines: DiffLine[];
259
+ oldLabel: string;
260
+ newLabel: string;
261
+ }): React.ReactElement {
262
+ return (
263
+ <div className="wn-diff-split">
264
+ {/* Old content column */}
265
+ <div className="wn-diff-column">
266
+ <div className="wn-diff-column-header">{oldLabel}</div>
267
+ <div className="wn-diff-column-content">
268
+ {diffLines.map((line, idx) => {
269
+ if (line.type === "added") {
270
+ return (
271
+ <div key={idx} className="wn-diff-line wn-diff-line--empty">
272
+ <span className="wn-diff-line-num"></span>
273
+ <span className="wn-diff-line-content"></span>
274
+ </div>
275
+ );
276
+ }
277
+ return (
278
+ <div
279
+ key={idx}
280
+ className={`wn-diff-line ${line.type === "removed" ? "wn-diff-line--removed" : ""}`}
281
+ >
282
+ <span className="wn-diff-line-num">{line.oldLineNum}</span>
283
+ <span className="wn-diff-line-content">
284
+ {line.type === "removed" && (
285
+ <span className="wn-diff-line-marker">-</span>
286
+ )}
287
+ {line.content}
288
+ </span>
289
+ </div>
290
+ );
291
+ })}
292
+ </div>
293
+ </div>
294
+
295
+ {/* New content column */}
296
+ <div className="wn-diff-column">
297
+ <div className="wn-diff-column-header">{newLabel}</div>
298
+ <div className="wn-diff-column-content">
299
+ {diffLines.map((line, idx) => {
300
+ if (line.type === "removed") {
301
+ return (
302
+ <div key={idx} className="wn-diff-line wn-diff-line--empty">
303
+ <span className="wn-diff-line-num"></span>
304
+ <span className="wn-diff-line-content"></span>
305
+ </div>
306
+ );
307
+ }
308
+ return (
309
+ <div
310
+ key={idx}
311
+ className={`wn-diff-line ${line.type === "added" ? "wn-diff-line--added" : ""}`}
312
+ >
313
+ <span className="wn-diff-line-num">{line.newLineNum}</span>
314
+ <span className="wn-diff-line-content">
315
+ {line.type === "added" && (
316
+ <span className="wn-diff-line-marker">+</span>
317
+ )}
318
+ {line.content}
319
+ </span>
320
+ </div>
321
+ );
322
+ })}
323
+ </div>
324
+ </div>
325
+ </div>
326
+ );
327
+ }
328
+
329
+ /**
330
+ * Unified view component
331
+ */
332
+ function UnifiedView({
333
+ diffLines,
334
+ oldLabel,
335
+ newLabel,
336
+ }: {
337
+ diffLines: DiffLine[];
338
+ oldLabel: string;
339
+ newLabel: string;
340
+ }): React.ReactElement {
341
+ return (
342
+ <div className="wn-diff-unified">
343
+ <div className="wn-diff-unified-header">
344
+ <span className="wn-diff-unified-label wn-diff-unified-label--old">
345
+ {oldLabel}
346
+ </span>
347
+ <span className="wn-diff-unified-arrow">→</span>
348
+ <span className="wn-diff-unified-label wn-diff-unified-label--new">
349
+ {newLabel}
350
+ </span>
351
+ </div>
352
+ <div className="wn-diff-unified-content">
353
+ {diffLines.map((line, idx) => (
354
+ <div
355
+ key={idx}
356
+ className={`wn-diff-line ${
357
+ line.type === "added"
358
+ ? "wn-diff-line--added"
359
+ : line.type === "removed"
360
+ ? "wn-diff-line--removed"
361
+ : ""
362
+ }`}
363
+ >
364
+ <span className="wn-diff-line-num wn-diff-line-num--old">
365
+ {line.oldLineNum ?? ""}
366
+ </span>
367
+ <span className="wn-diff-line-num wn-diff-line-num--new">
368
+ {line.newLineNum ?? ""}
369
+ </span>
370
+ <span className="wn-diff-line-content">
371
+ {line.type !== "unchanged" && (
372
+ <span className="wn-diff-line-marker">
373
+ {line.type === "added" ? "+" : "-"}
374
+ </span>
375
+ )}
376
+ {line.content}
377
+ </span>
378
+ </div>
379
+ ))}
380
+ </div>
381
+ </div>
382
+ );
383
+ }
@@ -0,0 +1,318 @@
1
+ /**
2
+ * @fileoverview Version Actions styles
3
+ *
4
+ * Styling for version action buttons and confirmation modals.
5
+ */
6
+
7
+ /* ============================================================================
8
+ VERSION ACTIONS BAR
9
+ ============================================================================ */
10
+
11
+ .wn-version-actions {
12
+ display: flex;
13
+ flex-wrap: wrap;
14
+ gap: var(--wn-space-2);
15
+ padding: var(--wn-space-4);
16
+ border-top: 1px solid var(--wn-zinc-700);
17
+ background-color: var(--wn-zinc-950);
18
+ flex-shrink: 0;
19
+ }
20
+
21
+ .wn-version-action {
22
+ display: flex;
23
+ align-items: center;
24
+ justify-content: center;
25
+ gap: var(--wn-space-2);
26
+ flex: 1 1 calc(50% - 0.1875rem);
27
+ min-width: 0;
28
+ padding: var(--wn-space-3) var(--wn-space-2);
29
+ border: 1px solid var(--wn-zinc-700);
30
+ border-radius: var(--wn-radius-sm);
31
+ background-color: transparent;
32
+ font-size: var(--wn-font-xs);
33
+ font-weight: 500;
34
+ color: var(--wn-zinc-400);
35
+ cursor: pointer;
36
+ white-space: nowrap;
37
+ overflow: hidden;
38
+ text-overflow: ellipsis;
39
+ transition:
40
+ background-color var(--wn-transition-fast),
41
+ border-color var(--wn-transition-fast),
42
+ color var(--wn-transition-fast);
43
+ }
44
+
45
+ .wn-version-action:hover:not(:disabled) {
46
+ background-color: var(--wn-overlay-5);
47
+ border-color: var(--wn-zinc-600);
48
+ color: var(--wn-zinc-50);
49
+ }
50
+
51
+ .wn-version-action:disabled {
52
+ opacity: 0.5;
53
+ cursor: not-allowed;
54
+ }
55
+
56
+ .wn-version-action--primary {
57
+ border-color: var(--wn-brand-500);
58
+ background-color: var(--wn-brand-alpha-10);
59
+ color: var(--wn-brand-400);
60
+ }
61
+
62
+ .wn-version-action--primary:hover:not(:disabled) {
63
+ background-color: var(--wn-brand-alpha-20);
64
+ border-color: var(--wn-brand-400);
65
+ color: #93c5fd;
66
+ }
67
+
68
+ .wn-version-action--danger {
69
+ border-color: var(--wn-error-500);
70
+ background-color: var(--wn-error-alpha-10);
71
+ color: var(--wn-error-400);
72
+ }
73
+
74
+ .wn-version-action--danger:hover:not(:disabled) {
75
+ background-color: var(--wn-error-alpha-20);
76
+ border-color: var(--wn-error-400);
77
+ color: #fca5a5;
78
+ }
79
+
80
+ /* ============================================================================
81
+ CONFIRMATION MODAL
82
+ ============================================================================ */
83
+
84
+ .wn-confirm-overlay {
85
+ position: fixed;
86
+ inset: 0;
87
+ z-index: var(--wn-z-confirm);
88
+ display: flex;
89
+ align-items: center;
90
+ justify-content: center;
91
+ background-color: var(--wn-backdrop);
92
+ animation: fadeIn var(--wn-transition-fast) ease-out;
93
+ }
94
+
95
+ @keyframes fadeIn {
96
+ from {
97
+ opacity: 0;
98
+ }
99
+ to {
100
+ opacity: 1;
101
+ }
102
+ }
103
+
104
+ .wn-confirm-modal {
105
+ width: 100%;
106
+ max-width: var(--wn-modal-sm);
107
+ padding: var(--wn-space-6);
108
+ border-radius: var(--wn-radius-lg);
109
+ border: 1px solid var(--wn-zinc-700);
110
+ background-color: var(--wn-zinc-900);
111
+ box-shadow: var(--wn-shadow-lg);
112
+ animation: zoomIn var(--wn-transition-fast) ease-out;
113
+ }
114
+
115
+ @keyframes zoomIn {
116
+ from {
117
+ opacity: 0;
118
+ transform: scale(0.95);
119
+ }
120
+ to {
121
+ opacity: 1;
122
+ transform: scale(1);
123
+ }
124
+ }
125
+
126
+ .wn-confirm-header {
127
+ display: flex;
128
+ align-items: center;
129
+ gap: var(--wn-space-3);
130
+ margin-bottom: var(--wn-space-4);
131
+ }
132
+
133
+ .wn-confirm-icon {
134
+ color: var(--wn-warning-400);
135
+ flex-shrink: 0;
136
+ }
137
+
138
+ .wn-confirm-title {
139
+ flex: 1;
140
+ margin: 0;
141
+ font-size: var(--wn-font-md);
142
+ font-weight: 600;
143
+ color: var(--wn-zinc-50);
144
+ }
145
+
146
+ .wn-confirm-close {
147
+ display: flex;
148
+ align-items: center;
149
+ justify-content: center;
150
+ width: var(--wn-icon-btn-md);
151
+ height: var(--wn-icon-btn-md);
152
+ padding: 0;
153
+ border: none;
154
+ border-radius: var(--wn-radius-sm);
155
+ background-color: transparent;
156
+ color: var(--wn-zinc-500);
157
+ cursor: pointer;
158
+ transition:
159
+ background-color var(--wn-transition-fast),
160
+ color var(--wn-transition-fast);
161
+ }
162
+
163
+ .wn-confirm-close:hover:not(:disabled) {
164
+ background-color: var(--wn-overlay-10);
165
+ color: var(--wn-zinc-50);
166
+ }
167
+
168
+ .wn-confirm-close:disabled {
169
+ opacity: 0.5;
170
+ cursor: not-allowed;
171
+ }
172
+
173
+ .wn-confirm-message {
174
+ margin: 0 0 var(--wn-space-6);
175
+ font-size: var(--wn-font-base);
176
+ line-height: 1.5;
177
+ color: var(--wn-zinc-400);
178
+ }
179
+
180
+ .wn-confirm-actions {
181
+ display: flex;
182
+ gap: var(--wn-space-3);
183
+ justify-content: flex-end;
184
+ }
185
+
186
+ .wn-confirm-btn {
187
+ display: flex;
188
+ align-items: center;
189
+ gap: var(--wn-space-2);
190
+ padding: var(--wn-space-3) var(--wn-space-5);
191
+ border-radius: var(--wn-radius-md);
192
+ font-size: var(--wn-font-base);
193
+ font-weight: 500;
194
+ cursor: pointer;
195
+ transition:
196
+ background-color var(--wn-transition-fast),
197
+ border-color var(--wn-transition-fast);
198
+ }
199
+
200
+ .wn-confirm-btn:disabled {
201
+ opacity: 0.7;
202
+ cursor: not-allowed;
203
+ }
204
+
205
+ .wn-confirm-btn--cancel {
206
+ border: 1px solid var(--wn-zinc-700);
207
+ background-color: transparent;
208
+ color: var(--wn-zinc-400);
209
+ }
210
+
211
+ .wn-confirm-btn--cancel:hover:not(:disabled) {
212
+ background-color: var(--wn-overlay-5);
213
+ border-color: var(--wn-zinc-600);
214
+ color: var(--wn-zinc-50);
215
+ }
216
+
217
+ .wn-confirm-btn--primary {
218
+ border: 1px solid var(--wn-brand-500);
219
+ background-color: var(--wn-brand-500);
220
+ color: #fff;
221
+ }
222
+
223
+ .wn-confirm-btn--primary:hover:not(:disabled) {
224
+ background-color: var(--wn-brand-600);
225
+ border-color: var(--wn-brand-600);
226
+ }
227
+
228
+ .wn-confirm-btn--danger {
229
+ border: 1px solid var(--wn-error-500);
230
+ background-color: var(--wn-error-500);
231
+ color: #fff;
232
+ }
233
+
234
+ .wn-confirm-btn--danger:hover:not(:disabled) {
235
+ background-color: var(--wn-error-600);
236
+ border-color: var(--wn-error-600);
237
+ }
238
+
239
+ /* ============================================================================
240
+ LIGHT MODE OVERRIDES
241
+ ============================================================================ */
242
+
243
+ .wn-light .wn-version-actions {
244
+ border-top-color: var(--wn-zinc-200);
245
+ background-color: var(--wn-zinc-50);
246
+ }
247
+
248
+ .wn-light .wn-version-action {
249
+ border-color: var(--wn-zinc-200);
250
+ color: var(--wn-zinc-500);
251
+ }
252
+
253
+ .wn-light .wn-version-action:hover:not(:disabled) {
254
+ background-color: var(--wn-overlay-light-3);
255
+ border-color: var(--wn-zinc-300);
256
+ color: var(--wn-zinc-900);
257
+ }
258
+
259
+ .wn-light .wn-version-action--primary {
260
+ border-color: var(--wn-brand-500);
261
+ background-color: var(--wn-brand-alpha-10);
262
+ color: var(--wn-brand-600);
263
+ }
264
+
265
+ .wn-light .wn-version-action--primary:hover:not(:disabled) {
266
+ background-color: var(--wn-brand-alpha-15);
267
+ border-color: var(--wn-brand-600);
268
+ color: #1d4ed8;
269
+ }
270
+
271
+ .wn-light .wn-version-action--danger {
272
+ border-color: var(--wn-error-500);
273
+ background-color: var(--wn-error-alpha-10);
274
+ color: var(--wn-error-600);
275
+ }
276
+
277
+ .wn-light .wn-version-action--danger:hover:not(:disabled) {
278
+ background-color: var(--wn-error-alpha-15);
279
+ border-color: var(--wn-error-600);
280
+ color: #b91c1c;
281
+ }
282
+
283
+ .wn-light .wn-confirm-overlay {
284
+ background-color: var(--wn-backdrop-light);
285
+ }
286
+
287
+ .wn-light .wn-confirm-modal {
288
+ border-color: var(--wn-zinc-200);
289
+ background-color: #fff;
290
+ }
291
+
292
+ .wn-light .wn-confirm-title {
293
+ color: var(--wn-zinc-900);
294
+ }
295
+
296
+ .wn-light .wn-confirm-close {
297
+ color: var(--wn-zinc-400);
298
+ }
299
+
300
+ .wn-light .wn-confirm-close:hover:not(:disabled) {
301
+ background-color: var(--wn-overlay-light-5);
302
+ color: var(--wn-zinc-900);
303
+ }
304
+
305
+ .wn-light .wn-confirm-message {
306
+ color: var(--wn-zinc-500);
307
+ }
308
+
309
+ .wn-light .wn-confirm-btn--cancel {
310
+ border-color: var(--wn-zinc-200);
311
+ color: var(--wn-zinc-500);
312
+ }
313
+
314
+ .wn-light .wn-confirm-btn--cancel:hover:not(:disabled) {
315
+ background-color: var(--wn-overlay-light-3);
316
+ border-color: var(--wn-zinc-300);
317
+ color: var(--wn-zinc-900);
318
+ }