@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,277 @@
1
+ /**
2
+ * @fileoverview Version Actions component
3
+ *
4
+ * Action buttons for version operations: restore, compare, download, delete.
5
+ * Includes confirmation dialogs for destructive actions.
6
+ * Includes focus trap for accessibility compliance.
7
+ *
8
+ * @module @writenex/astro/client/components/VersionHistory/VersionActions
9
+ */
10
+
11
+ import { useState, useEffect, useRef } from "react";
12
+ import {
13
+ RotateCcw,
14
+ GitCompare,
15
+ Download,
16
+ Trash2,
17
+ Loader2,
18
+ AlertTriangle,
19
+ X,
20
+ } from "lucide-react";
21
+ import { useFocusTrap } from "../../hooks/useFocusTrap";
22
+ import type { VersionEntry } from "../../../types";
23
+ import "./VersionActions.css";
24
+
25
+ /**
26
+ * Props for the VersionActions component
27
+ */
28
+ interface VersionActionsProps {
29
+ /** The selected version */
30
+ version: VersionEntry;
31
+ /** Callback to restore the version */
32
+ onRestore: () => void;
33
+ /** Callback to compare the version */
34
+ onCompare: () => void;
35
+ /** Callback to download the version */
36
+ onDownload: () => void;
37
+ /** Callback to delete the version */
38
+ onDelete: () => void;
39
+ /** Current loading action */
40
+ loading: string | null;
41
+ }
42
+
43
+ /**
44
+ * Props for ConfirmModal component
45
+ */
46
+ interface ConfirmModalProps {
47
+ title: string;
48
+ message: string;
49
+ confirmLabel: string;
50
+ confirmVariant?: "danger" | "primary";
51
+ onConfirm: () => void;
52
+ onCancel: () => void;
53
+ loading?: boolean;
54
+ }
55
+
56
+ /**
57
+ * Confirmation modal component with focus trap
58
+ */
59
+ function ConfirmModal({
60
+ title,
61
+ message,
62
+ confirmLabel,
63
+ confirmVariant = "danger",
64
+ onConfirm,
65
+ onCancel,
66
+ loading,
67
+ }: ConfirmModalProps): React.ReactElement {
68
+ const triggerRef = useRef<HTMLElement | null>(null);
69
+ const cancelButtonRef = useRef<HTMLButtonElement>(null);
70
+
71
+ // Store the trigger element when modal mounts
72
+ useEffect(() => {
73
+ triggerRef.current = document.activeElement as HTMLElement;
74
+ }, []);
75
+
76
+ // Focus trap for accessibility
77
+ const { containerRef } = useFocusTrap({
78
+ enabled: true,
79
+ onEscape: loading ? undefined : onCancel,
80
+ returnFocusTo: triggerRef.current,
81
+ });
82
+
83
+ // Focus cancel button when modal opens
84
+ useEffect(() => {
85
+ setTimeout(() => {
86
+ cancelButtonRef.current?.focus();
87
+ }, 50);
88
+ }, []);
89
+
90
+ const handleOverlayClick = (e: React.MouseEvent) => {
91
+ if (e.target === e.currentTarget && !loading) onCancel();
92
+ };
93
+
94
+ return (
95
+ <div className="wn-confirm-overlay" onClick={handleOverlayClick}>
96
+ <div
97
+ ref={containerRef}
98
+ className="wn-confirm-modal"
99
+ role="alertdialog"
100
+ aria-modal="true"
101
+ aria-labelledby="confirm-modal-title"
102
+ aria-describedby="confirm-modal-message"
103
+ >
104
+ <div className="wn-confirm-header">
105
+ <AlertTriangle size={20} className="wn-confirm-icon" />
106
+ <h3 id="confirm-modal-title" className="wn-confirm-title">
107
+ {title}
108
+ </h3>
109
+ <button
110
+ className="wn-confirm-close"
111
+ onClick={onCancel}
112
+ disabled={loading}
113
+ aria-label="Close"
114
+ >
115
+ <X size={16} />
116
+ </button>
117
+ </div>
118
+ <p id="confirm-modal-message" className="wn-confirm-message">
119
+ {message}
120
+ </p>
121
+ <div className="wn-confirm-actions">
122
+ <button
123
+ ref={cancelButtonRef}
124
+ className="wn-confirm-btn wn-confirm-btn--cancel"
125
+ onClick={onCancel}
126
+ disabled={loading}
127
+ >
128
+ Cancel
129
+ </button>
130
+ <button
131
+ className={`wn-confirm-btn wn-confirm-btn--${confirmVariant}`}
132
+ onClick={onConfirm}
133
+ disabled={loading}
134
+ >
135
+ {loading ? (
136
+ <>
137
+ <Loader2 size={14} className="wn-spin" />
138
+ Processing...
139
+ </>
140
+ ) : (
141
+ confirmLabel
142
+ )}
143
+ </button>
144
+ </div>
145
+ </div>
146
+ </div>
147
+ );
148
+ }
149
+
150
+ /**
151
+ * Version Actions component
152
+ *
153
+ * @component
154
+ * @example
155
+ * ```tsx
156
+ * <VersionActions
157
+ * version={selectedVersion}
158
+ * onRestore={handleRestore}
159
+ * onCompare={handleCompare}
160
+ * onDownload={handleDownload}
161
+ * onDelete={handleDelete}
162
+ * loading={actionLoading}
163
+ * />
164
+ * ```
165
+ */
166
+ export function VersionActions({
167
+ version,
168
+ onRestore,
169
+ onCompare,
170
+ onDownload,
171
+ onDelete,
172
+ loading,
173
+ }: VersionActionsProps): React.ReactElement {
174
+ const [showRestoreConfirm, setShowRestoreConfirm] = useState(false);
175
+ const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
176
+
177
+ const handleRestoreClick = () => {
178
+ setShowRestoreConfirm(true);
179
+ };
180
+
181
+ const handleRestoreConfirm = () => {
182
+ onRestore();
183
+ setShowRestoreConfirm(false);
184
+ };
185
+
186
+ const handleDeleteClick = () => {
187
+ setShowDeleteConfirm(true);
188
+ };
189
+
190
+ const handleDeleteConfirm = () => {
191
+ onDelete();
192
+ setShowDeleteConfirm(false);
193
+ };
194
+
195
+ const isLoading = loading !== null;
196
+
197
+ return (
198
+ <>
199
+ <div className="wn-version-actions">
200
+ <button
201
+ className="wn-version-action wn-version-action--primary"
202
+ onClick={handleRestoreClick}
203
+ disabled={isLoading}
204
+ title="Restore this version"
205
+ >
206
+ {loading === "restore" ? (
207
+ <Loader2 size={14} className="wn-spin" />
208
+ ) : (
209
+ <RotateCcw size={14} />
210
+ )}
211
+ Restore
212
+ </button>
213
+ <button
214
+ className="wn-version-action"
215
+ onClick={onCompare}
216
+ disabled={isLoading}
217
+ title="Compare with current"
218
+ >
219
+ {loading === "compare" ? (
220
+ <Loader2 size={14} className="wn-spin" />
221
+ ) : (
222
+ <GitCompare size={14} />
223
+ )}
224
+ Compare
225
+ </button>
226
+ <button
227
+ className="wn-version-action"
228
+ onClick={onDownload}
229
+ disabled={isLoading}
230
+ title="Download as markdown"
231
+ >
232
+ <Download size={14} />
233
+ Download
234
+ </button>
235
+ <button
236
+ className="wn-version-action wn-version-action--danger"
237
+ onClick={handleDeleteClick}
238
+ disabled={isLoading}
239
+ title="Delete this version"
240
+ >
241
+ {loading === "delete" ? (
242
+ <Loader2 size={14} className="wn-spin" />
243
+ ) : (
244
+ <Trash2 size={14} />
245
+ )}
246
+ Delete
247
+ </button>
248
+ </div>
249
+
250
+ {/* Restore Confirmation Modal */}
251
+ {showRestoreConfirm && (
252
+ <ConfirmModal
253
+ title="Restore Version"
254
+ message="This will replace your current content with this version. A safety snapshot will be created before restoring. Are you sure you want to continue?"
255
+ confirmLabel="Restore"
256
+ confirmVariant="primary"
257
+ onConfirm={handleRestoreConfirm}
258
+ onCancel={() => setShowRestoreConfirm(false)}
259
+ loading={loading === "restore"}
260
+ />
261
+ )}
262
+
263
+ {/* Delete Confirmation Modal */}
264
+ {showDeleteConfirm && (
265
+ <ConfirmModal
266
+ title="Delete Version"
267
+ message={`Are you sure you want to delete this version${version.label ? ` "${version.label}"` : ""}? This action cannot be undone.`}
268
+ confirmLabel="Delete"
269
+ confirmVariant="danger"
270
+ onConfirm={handleDeleteConfirm}
271
+ onCancel={() => setShowDeleteConfirm(false)}
272
+ loading={loading === "delete"}
273
+ />
274
+ )}
275
+ </>
276
+ );
277
+ }
@@ -0,0 +1,369 @@
1
+ /**
2
+ * @fileoverview Version History Panel styles
3
+ *
4
+ * Styling for the version history slide-in panel.
5
+ */
6
+
7
+ /* ============================================================================
8
+ PANEL CONTAINER
9
+ ============================================================================ */
10
+
11
+ .wn-version-panel {
12
+ position: fixed;
13
+ top: 0;
14
+ right: 0;
15
+ bottom: 0;
16
+ width: var(--wn-panel-md);
17
+ max-width: 100vw;
18
+ display: flex;
19
+ flex-direction: column;
20
+ z-index: var(--wn-z-panel);
21
+ border-left: 1px solid var(--wn-zinc-700);
22
+ background-color: var(--wn-zinc-900);
23
+ box-shadow: var(--wn-shadow-panel);
24
+ animation: slideIn var(--wn-transition-normal) ease-out;
25
+ overflow: hidden;
26
+ }
27
+
28
+ @keyframes slideIn {
29
+ from {
30
+ transform: translateX(100%);
31
+ }
32
+ to {
33
+ transform: translateX(0);
34
+ }
35
+ }
36
+
37
+ /* ============================================================================
38
+ PANEL HEADER
39
+ ============================================================================ */
40
+
41
+ .wn-version-panel-header {
42
+ display: flex;
43
+ align-items: center;
44
+ justify-content: space-between;
45
+ padding: var(--wn-space-4) var(--wn-space-5);
46
+ border-bottom: 1px solid var(--wn-zinc-700);
47
+ flex-shrink: 0;
48
+ }
49
+
50
+ .wn-version-panel-title {
51
+ display: flex;
52
+ align-items: center;
53
+ gap: var(--wn-space-3);
54
+ font-size: var(--wn-font-base);
55
+ font-weight: 600;
56
+ color: var(--wn-zinc-50);
57
+ margin: 0;
58
+ }
59
+
60
+ .wn-version-panel-actions {
61
+ display: flex;
62
+ align-items: center;
63
+ gap: var(--wn-space-1);
64
+ }
65
+
66
+ .wn-version-panel-btn {
67
+ display: flex;
68
+ align-items: center;
69
+ justify-content: center;
70
+ width: var(--wn-icon-btn-md);
71
+ height: var(--wn-icon-btn-md);
72
+ padding: 0;
73
+ border: none;
74
+ border-radius: var(--wn-radius-sm);
75
+ background-color: transparent;
76
+ color: var(--wn-zinc-400);
77
+ cursor: pointer;
78
+ transition:
79
+ background-color var(--wn-transition-fast),
80
+ color var(--wn-transition-fast);
81
+ }
82
+
83
+ .wn-version-panel-btn:hover {
84
+ background-color: var(--wn-overlay-10);
85
+ color: var(--wn-zinc-50);
86
+ }
87
+
88
+ .wn-version-panel-btn:disabled {
89
+ opacity: 0.5;
90
+ cursor: not-allowed;
91
+ }
92
+
93
+ .wn-version-panel-btn--danger {
94
+ color: var(--wn-error-400);
95
+ }
96
+
97
+ .wn-version-panel-btn--danger:hover:not(:disabled) {
98
+ background-color: var(--wn-error-alpha-10);
99
+ color: var(--wn-error-300);
100
+ }
101
+
102
+ /* ============================================================================
103
+ PANEL CONTENT
104
+ ============================================================================ */
105
+
106
+ .wn-version-panel-content {
107
+ flex: 1;
108
+ overflow-y: auto;
109
+ padding: var(--wn-space-3);
110
+ }
111
+
112
+ /* ============================================================================
113
+ LOADING STATE
114
+ ============================================================================ */
115
+
116
+ .wn-version-panel-loading {
117
+ display: flex;
118
+ flex-direction: column;
119
+ align-items: center;
120
+ justify-content: center;
121
+ gap: var(--wn-space-4);
122
+ padding: var(--wn-space-8);
123
+ color: var(--wn-zinc-500);
124
+ font-size: var(--wn-font-base);
125
+ }
126
+
127
+ /* ============================================================================
128
+ ERROR STATE
129
+ ============================================================================ */
130
+
131
+ .wn-version-panel-error {
132
+ display: flex;
133
+ flex-direction: column;
134
+ align-items: center;
135
+ gap: var(--wn-space-4);
136
+ padding: var(--wn-space-8);
137
+ text-align: center;
138
+ color: var(--wn-error-400);
139
+ font-size: var(--wn-font-base);
140
+ }
141
+
142
+ .wn-version-panel-error button {
143
+ padding: var(--wn-space-2) var(--wn-space-4);
144
+ border: 1px solid var(--wn-zinc-700);
145
+ border-radius: var(--wn-radius-sm);
146
+ background-color: transparent;
147
+ color: var(--wn-zinc-400);
148
+ font-size: var(--wn-font-xs);
149
+ cursor: pointer;
150
+ transition:
151
+ background-color var(--wn-transition-fast),
152
+ color var(--wn-transition-fast);
153
+ }
154
+
155
+ .wn-version-panel-error button:hover {
156
+ background-color: var(--wn-overlay-10);
157
+ color: var(--wn-zinc-50);
158
+ }
159
+
160
+ /* ============================================================================
161
+ EMPTY STATE
162
+ ============================================================================ */
163
+
164
+ .wn-version-panel-empty {
165
+ display: flex;
166
+ flex-direction: column;
167
+ align-items: center;
168
+ justify-content: center;
169
+ gap: var(--wn-space-3);
170
+ padding: var(--wn-space-9) var(--wn-space-5);
171
+ text-align: center;
172
+ color: var(--wn-zinc-600);
173
+ }
174
+
175
+ .wn-version-panel-empty p {
176
+ margin: 0;
177
+ font-size: var(--wn-font-base);
178
+ font-weight: 500;
179
+ color: var(--wn-zinc-500);
180
+ }
181
+
182
+ .wn-version-panel-empty span {
183
+ font-size: var(--wn-font-xs);
184
+ }
185
+
186
+ /* ============================================================================
187
+ VERSION LIST
188
+ ============================================================================ */
189
+
190
+ .wn-version-list {
191
+ display: flex;
192
+ flex-direction: column;
193
+ gap: var(--wn-space-2);
194
+ }
195
+
196
+ /* ============================================================================
197
+ VERSION ITEM
198
+ ============================================================================ */
199
+
200
+ .wn-version-item {
201
+ display: flex;
202
+ flex-direction: column;
203
+ gap: var(--wn-space-2);
204
+ width: 100%;
205
+ padding: var(--wn-space-3) var(--wn-space-4);
206
+ border: 1px solid transparent;
207
+ border-radius: var(--wn-radius-md);
208
+ background-color: transparent;
209
+ text-align: left;
210
+ cursor: pointer;
211
+ transition:
212
+ background-color var(--wn-transition-fast),
213
+ border-color var(--wn-transition-fast);
214
+ }
215
+
216
+ .wn-version-item:hover {
217
+ background-color: var(--wn-overlay-5);
218
+ }
219
+
220
+ .wn-version-item--selected {
221
+ border-color: var(--wn-brand-500);
222
+ background-color: var(--wn-brand-alpha-10);
223
+ }
224
+
225
+ .wn-version-item-header {
226
+ display: flex;
227
+ align-items: center;
228
+ justify-content: space-between;
229
+ }
230
+
231
+ .wn-version-item-time {
232
+ display: flex;
233
+ align-items: center;
234
+ gap: var(--wn-space-2);
235
+ font-size: var(--wn-font-xs);
236
+ font-weight: 500;
237
+ color: var(--wn-zinc-50);
238
+ }
239
+
240
+ .wn-version-item-size {
241
+ font-size: var(--wn-font-xs);
242
+ color: var(--wn-zinc-600);
243
+ }
244
+
245
+ .wn-version-item-label {
246
+ display: inline-flex;
247
+ align-items: center;
248
+ gap: var(--wn-space-1);
249
+ padding: var(--wn-space-1) var(--wn-space-2);
250
+ border-radius: var(--wn-radius-sm);
251
+ background-color: var(--wn-info-alpha-20);
252
+ font-size: var(--wn-font-xs);
253
+ font-weight: 500;
254
+ color: var(--wn-info-400);
255
+ width: fit-content;
256
+ }
257
+
258
+ .wn-version-item-preview {
259
+ margin: 0;
260
+ font-size: var(--wn-font-xs);
261
+ color: var(--wn-zinc-500);
262
+ line-height: 1.4;
263
+ overflow: hidden;
264
+ text-overflow: ellipsis;
265
+ display: -webkit-box;
266
+ line-clamp: 2;
267
+ -webkit-line-clamp: 2;
268
+ -webkit-box-orient: vertical;
269
+ }
270
+
271
+ /* ============================================================================
272
+ SPIN ANIMATION
273
+ ============================================================================ */
274
+
275
+ .wn-spin {
276
+ animation: spin 1s linear infinite;
277
+ }
278
+
279
+ @keyframes spin {
280
+ from {
281
+ transform: rotate(0deg);
282
+ }
283
+ to {
284
+ transform: rotate(360deg);
285
+ }
286
+ }
287
+
288
+ /* ============================================================================
289
+ LIGHT MODE OVERRIDES
290
+ ============================================================================ */
291
+
292
+ .wn-light .wn-version-panel {
293
+ border-left-color: var(--wn-zinc-200);
294
+ background-color: #fff;
295
+ box-shadow: var(--wn-shadow-panel);
296
+ }
297
+
298
+ .wn-light .wn-version-panel-header {
299
+ border-bottom-color: var(--wn-zinc-200);
300
+ }
301
+
302
+ .wn-light .wn-version-panel-title {
303
+ color: var(--wn-zinc-900);
304
+ }
305
+
306
+ .wn-light .wn-version-panel-btn {
307
+ color: var(--wn-zinc-500);
308
+ }
309
+
310
+ .wn-light .wn-version-panel-btn:hover {
311
+ background-color: var(--wn-overlay-light-5);
312
+ color: var(--wn-zinc-900);
313
+ }
314
+
315
+ .wn-light .wn-version-panel-btn--danger {
316
+ color: var(--wn-error-500);
317
+ }
318
+
319
+ .wn-light .wn-version-panel-btn--danger:hover:not(:disabled) {
320
+ background-color: var(--wn-error-alpha-10);
321
+ color: var(--wn-error-600);
322
+ }
323
+
324
+ .wn-light .wn-version-panel-loading {
325
+ color: var(--wn-zinc-400);
326
+ }
327
+
328
+ .wn-light .wn-version-panel-error button {
329
+ border-color: var(--wn-zinc-200);
330
+ color: var(--wn-zinc-500);
331
+ }
332
+
333
+ .wn-light .wn-version-panel-error button:hover {
334
+ background-color: var(--wn-overlay-light-5);
335
+ color: var(--wn-zinc-900);
336
+ }
337
+
338
+ .wn-light .wn-version-panel-empty {
339
+ color: var(--wn-zinc-400);
340
+ }
341
+
342
+ .wn-light .wn-version-panel-empty p {
343
+ color: var(--wn-zinc-500);
344
+ }
345
+
346
+ .wn-light .wn-version-item:hover {
347
+ background-color: var(--wn-overlay-light-3);
348
+ }
349
+
350
+ .wn-light .wn-version-item--selected {
351
+ border-color: var(--wn-brand-500);
352
+ background-color: var(--wn-brand-alpha-10);
353
+ }
354
+
355
+ .wn-light .wn-version-item-time {
356
+ color: var(--wn-zinc-900);
357
+ }
358
+
359
+ .wn-light .wn-version-item-size {
360
+ color: var(--wn-zinc-400);
361
+ }
362
+
363
+ .wn-light .wn-version-item-label {
364
+ background-color: var(--wn-info-alpha-15);
365
+ }
366
+
367
+ .wn-light .wn-version-item-preview {
368
+ color: var(--wn-zinc-500);
369
+ }