react-embed-docs 0.1.0 → 0.3.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 (38) hide show
  1. package/dist/client/components/Breadcrumbs.d.ts.map +1 -1
  2. package/dist/client/components/Breadcrumbs.js +9 -6
  3. package/dist/client/components/DocumentEdit.d.ts.map +1 -1
  4. package/dist/client/components/DocumentEdit.js +336 -8
  5. package/dist/client/components/DocumentList.d.ts.map +1 -1
  6. package/dist/client/components/DocumentList.js +18 -8
  7. package/dist/client/components/DocumentProvider.d.ts +1 -1
  8. package/dist/client/components/DocumentProvider.d.ts.map +1 -1
  9. package/dist/client/components/DocumentProvider.js +5 -1
  10. package/dist/client/components/DocumentView.d.ts.map +1 -1
  11. package/dist/client/components/DocumentView.js +5 -3
  12. package/dist/client/components/EmojiPicker.d.ts.map +1 -1
  13. package/dist/client/components/EmojiPicker.js +3 -1
  14. package/dist/client/components/ExportButton.d.ts.map +1 -1
  15. package/dist/client/components/ExportButton.js +14 -12
  16. package/dist/client/components/Layout.d.ts.map +1 -1
  17. package/dist/client/components/Layout.js +7 -3
  18. package/dist/client/components/ReactEmbedDocs.d.ts.map +1 -1
  19. package/dist/client/components/ReactEmbedDocs.js +2 -1
  20. package/dist/client/components/Sidebar.d.ts.map +1 -1
  21. package/dist/client/components/Sidebar.js +4 -2
  22. package/dist/client/components/VersionHistory.d.ts.map +1 -1
  23. package/dist/client/components/VersionHistory.js +13 -11
  24. package/dist/client/hooks/useTranslation.d.ts +13 -0
  25. package/dist/client/hooks/useTranslation.d.ts.map +1 -0
  26. package/dist/client/hooks/useTranslation.js +27 -0
  27. package/dist/client/index.d.ts +1 -0
  28. package/dist/client/index.d.ts.map +1 -1
  29. package/dist/client/index.js +1 -0
  30. package/dist/client/locales/en.json +83 -0
  31. package/dist/client/locales/ru.json +83 -0
  32. package/package.json +1 -1
  33. package/dist/client/components/DocsLayout.d.ts +0 -20
  34. package/dist/client/components/DocsLayout.d.ts.map +0 -1
  35. package/dist/client/components/DocsLayout.js +0 -387
  36. package/dist/client/providers/DocumentProvider.d.ts +0 -1
  37. package/dist/client/providers/DocumentProvider.d.ts.map +0 -1
  38. package/dist/client/providers/DocumentProvider.js +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"Breadcrumbs.d.ts","sourceRoot":"","sources":["../../../src/client/components/Breadcrumbs.tsx"],"names":[],"mappings":"AAKA,UAAU,aAAa;IACrB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB;AAED,UAAU,gBAAgB;IACxB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;OAGG;IACH,SAAS,CAAC,EAAE,aAAa,EAAE,CAAA;IAC3B,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAwCD,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,SAAS,EACT,UAAU,EACV,SAAkB,EAClB,SAAc,GACf,EAAE,gBAAgB,2CAmLlB"}
1
+ {"version":3,"file":"Breadcrumbs.d.ts","sourceRoot":"","sources":["../../../src/client/components/Breadcrumbs.tsx"],"names":[],"mappings":"AAMA,UAAU,aAAa;IACrB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB;AAED,UAAU,gBAAgB;IACxB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;OAGG;IACH,SAAS,CAAC,EAAE,aAAa,EAAE,CAAA;IAC3B,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAwCD,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,SAAS,EACT,UAAU,EACV,SAAS,EACT,SAAc,GACf,EAAE,gBAAgB,2CAqLlB"}
@@ -2,6 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { ChevronRight, Home, Loader2 } from 'lucide-react';
4
4
  import { useEffect, useMemo, useState } from 'react';
5
+ import { useTranslation } from '../hooks/useTranslation.js';
5
6
  // Fetch breadcrumbs from API
6
7
  async function fetchBreadcrumbs(docId) {
7
8
  const response = await fetch(`/api/docs/${docId}/breadcrumbs`);
@@ -31,7 +32,9 @@ function buildPath(docId, allDocs, basePath = '/docs') {
31
32
  return basePath;
32
33
  return `${basePath}/${pathParts.join('/')}`;
33
34
  }
34
- export function Breadcrumbs({ docId, documents, onNavigate, homeLabel = 'Home', className = '', }) {
35
+ export function Breadcrumbs({ docId, documents, onNavigate, homeLabel, className = '', }) {
36
+ const { t } = useTranslation();
37
+ const label = homeLabel || t('breadcrumbs.home');
35
38
  const [fetchedBreadcrumbs, setFetchedBreadcrumbs] = useState([]);
36
39
  const [isLoading, setIsLoading] = useState(false);
37
40
  const [error, setError] = useState(null);
@@ -104,18 +107,18 @@ export function Breadcrumbs({ docId, documents, onNavigate, homeLabel = 'Home',
104
107
  }
105
108
  };
106
109
  if (!docId) {
107
- return (_jsx("nav", { className: `flex items-center gap-1 text-sm ${className}`, children: _jsxs("button", { onClick: () => handleNavigate(null), className: "flex items-center gap-1.5 text-gray-500 hover:text-gray-700 transition-colors", children: [_jsx(Home, { className: "h-4 w-4" }), _jsx("span", { children: homeLabel })] }) }));
110
+ return (_jsx("nav", { className: `flex items-center gap-1 text-sm ${className}`, children: _jsxs("button", { onClick: () => handleNavigate(null), className: "flex items-center gap-1.5 text-gray-500 hover:text-gray-700 transition-colors", children: [_jsx(Home, { className: "h-4 w-4" }), _jsx("span", { children: label })] }) }));
108
111
  }
109
112
  if (isLoading && !documents) {
110
- return (_jsxs("div", { className: `flex items-center gap-2 text-sm text-gray-400 ${className}`, children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), _jsx("span", { children: "Loading..." })] }));
113
+ return (_jsxs("div", { className: `flex items-center gap-2 text-sm text-gray-400 ${className}`, children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), _jsx("span", { children: t('breadcrumbs.loading') })] }));
111
114
  }
112
115
  if (error && !documents) {
113
- return (_jsxs("div", { className: `flex items-center gap-1 text-sm text-gray-500 ${className}`, children: [_jsxs("button", { onClick: () => handleNavigate(null), className: "flex items-center gap-1.5 hover:text-gray-700 transition-colors", children: [_jsx(Home, { className: "h-4 w-4" }), _jsx("span", { children: homeLabel })] }), _jsx(ChevronRight, { className: "h-4 w-4 text-gray-400" }), _jsx("span", { className: "text-gray-400", children: "Error loading path" })] }));
116
+ return (_jsxs("div", { className: `flex items-center gap-1 text-sm text-gray-500 ${className}`, children: [_jsxs("button", { onClick: () => handleNavigate(null), className: "flex items-center gap-1.5 hover:text-gray-700 transition-colors", children: [_jsx(Home, { className: "h-4 w-4" }), _jsx("span", { children: label })] }), _jsx(ChevronRight, { className: "h-4 w-4 text-gray-400" }), _jsx("span", { className: "text-gray-400", children: t('breadcrumbs.error') })] }));
114
117
  }
115
118
  if (breadcrumbs.length === 0) {
116
- return (_jsx("nav", { className: `flex items-center gap-1 text-sm ${className}`, children: _jsxs("button", { onClick: () => handleNavigate(null), className: "flex items-center gap-1.5 text-gray-500 hover:text-gray-700 transition-colors", children: [_jsx(Home, { className: "h-4 w-4" }), _jsx("span", { children: homeLabel })] }) }));
119
+ return (_jsx("nav", { className: `flex items-center gap-1 text-sm ${className}`, children: _jsxs("button", { onClick: () => handleNavigate(null), className: "flex items-center gap-1.5 text-gray-500 hover:text-gray-700 transition-colors", children: [_jsx(Home, { className: "h-4 w-4" }), _jsx("span", { children: label })] }) }));
117
120
  }
118
- return (_jsxs("nav", { className: `flex items-center gap-1 text-sm ${className}`, children: [_jsxs("button", { onClick: () => handleNavigate(null), className: "flex items-center gap-1.5 text-gray-500 hover:text-gray-700 transition-colors shrink-0", title: homeLabel, children: [_jsx(Home, { className: "h-4 w-4" }), _jsx("span", { className: "hidden sm:inline", children: homeLabel })] }), breadcrumbs.map((doc, index) => {
121
+ return (_jsxs("nav", { className: `flex items-center gap-1 text-sm ${className}`, children: [_jsxs("button", { onClick: () => handleNavigate(null), className: "flex items-center gap-1.5 text-gray-500 hover:text-gray-700 transition-colors shrink-0", title: label, children: [_jsx(Home, { className: "h-4 w-4" }), _jsx("span", { className: "hidden sm:inline", children: label })] }), breadcrumbs.map((doc, index) => {
119
122
  const isLast = index === breadcrumbs.length - 1;
120
123
  const displayTitle = doc.title || 'Untitled';
121
124
  return (_jsxs("span", { className: "flex items-center gap-1 min-w-0", children: [_jsx(ChevronRight, { className: "h-4 w-4 text-gray-400 shrink-0" }), isLast ? (_jsxs("span", { className: "font-medium text-gray-900 truncate max-w-[200px] sm:max-w-[300px] md:max-w-[400px]", title: displayTitle, children: [doc.emoji && _jsx("span", { className: "mr-1", children: doc.emoji }), displayTitle] })) : (_jsxs("button", { onClick: () => handleNavigate(doc.id), className: "text-gray-500 hover:text-gray-700 transition-colors truncate max-w-[150px] sm:max-w-[200px]", title: displayTitle, children: [doc.emoji && _jsx("span", { className: "mr-1", children: doc.emoji }), displayTitle] }))] }, doc.id));
@@ -1 +1 @@
1
- {"version":3,"file":"DocumentEdit.d.ts","sourceRoot":"","sources":["../../../src/client/components/DocumentEdit.tsx"],"names":[],"mappings":"AAIA,OAAO,8BAA8B,CAAA;AAerC,UAAU,iBAAiB;CAAG;AAqB9B,wBAAgB,YAAY,CAAC,EAAE,EAAE,iBAAiB,2CA6PjD"}
1
+ {"version":3,"file":"DocumentEdit.d.ts","sourceRoot":"","sources":["../../../src/client/components/DocumentEdit.tsx"],"names":[],"mappings":"AAIA,OAAO,8BAA8B,CAAA;AAgBrC,UAAU,iBAAiB;CAAG;AAwU9B,wBAAgB,YAAY,CAAC,EAAE,EAAE,iBAAiB,2CA2RjD"}
@@ -7,6 +7,7 @@ import { Eye, ImageIcon, Loader2, Save, X } from 'lucide-react';
7
7
  import { useEffect, useState } from 'react';
8
8
  import { useCreateDocumentMutation, useDocumentQuery, useUpdateDocumentMutation, } from '../hooks/useDocsQuery.js';
9
9
  import { useFileUpload } from '../hooks/useFileUpload.js';
10
+ import { useTranslation } from '../hooks/useTranslation.js';
10
11
  import { blockNoteTheme } from '../lib/blocknoteTheme.js';
11
12
  import { useDocument } from './DocumentProvider.js';
12
13
  import { EmojiPicker } from './EmojiPicker.js';
@@ -17,9 +18,314 @@ const getDefaultContent = () => [
17
18
  content: '',
18
19
  },
19
20
  ];
21
+ // Transliteration map for common non-Latin characters (consolidated, no duplicates)
22
+ const transliterationMap = {
23
+ // Cyrillic
24
+ а: 'a',
25
+ б: 'b',
26
+ в: 'v',
27
+ г: 'g',
28
+ д: 'd',
29
+ е: 'e',
30
+ ё: 'yo',
31
+ ж: 'zh',
32
+ з: 'z',
33
+ и: 'i',
34
+ й: 'y',
35
+ к: 'k',
36
+ л: 'l',
37
+ м: 'm',
38
+ н: 'n',
39
+ о: 'o',
40
+ п: 'p',
41
+ р: 'r',
42
+ с: 's',
43
+ т: 't',
44
+ у: 'u',
45
+ ф: 'f',
46
+ х: 'h',
47
+ ц: 'ts',
48
+ ч: 'ch',
49
+ ш: 'sh',
50
+ щ: 'sch',
51
+ ъ: '',
52
+ ы: 'y',
53
+ ь: '',
54
+ э: 'e',
55
+ ю: 'yu',
56
+ я: 'ya',
57
+ А: 'A',
58
+ Б: 'B',
59
+ В: 'V',
60
+ Г: 'G',
61
+ Д: 'D',
62
+ Е: 'E',
63
+ Ё: 'Yo',
64
+ Ж: 'Zh',
65
+ З: 'Z',
66
+ И: 'I',
67
+ Й: 'Y',
68
+ К: 'K',
69
+ Л: 'L',
70
+ М: 'M',
71
+ Н: 'N',
72
+ О: 'O',
73
+ П: 'P',
74
+ Р: 'R',
75
+ С: 'S',
76
+ Т: 'T',
77
+ У: 'U',
78
+ Ф: 'F',
79
+ Х: 'H',
80
+ Ц: 'Ts',
81
+ Ч: 'Ch',
82
+ Ш: 'Sh',
83
+ Щ: 'Sch',
84
+ Ъ: '',
85
+ Ы: 'Y',
86
+ Ь: '',
87
+ Э: 'E',
88
+ Ю: 'Yu',
89
+ Я: 'Ya',
90
+ // Latin Extended
91
+ ä: 'ae',
92
+ ö: 'oe',
93
+ ü: 'ue',
94
+ ß: 'ss',
95
+ Ä: 'Ae',
96
+ Ö: 'Oe',
97
+ Ü: 'Ue',
98
+ à: 'a',
99
+ â: 'a',
100
+ æ: 'ae',
101
+ ç: 'c',
102
+ è: 'e',
103
+ é: 'e',
104
+ ê: 'e',
105
+ ë: 'e',
106
+ î: 'i',
107
+ ï: 'i',
108
+ ô: 'o',
109
+ œ: 'oe',
110
+ ù: 'u',
111
+ û: 'u',
112
+ ÿ: 'y',
113
+ À: 'A',
114
+ Â: 'A',
115
+ Æ: 'Ae',
116
+ Ç: 'C',
117
+ È: 'E',
118
+ É: 'E',
119
+ Ê: 'E',
120
+ Ë: 'E',
121
+ Î: 'I',
122
+ Ï: 'I',
123
+ Ô: 'O',
124
+ Œ: 'Oe',
125
+ Ù: 'U',
126
+ Û: 'U',
127
+ Ÿ: 'Y',
128
+ á: 'a',
129
+ í: 'i',
130
+ ó: 'o',
131
+ ú: 'u',
132
+ ñ: 'n',
133
+ Á: 'A',
134
+ Í: 'I',
135
+ Ó: 'O',
136
+ Ú: 'U',
137
+ Ñ: 'N',
138
+ ã: 'a',
139
+ õ: 'o',
140
+ Ã: 'A',
141
+ Õ: 'O',
142
+ ì: 'i',
143
+ ò: 'o',
144
+ Ì: 'I',
145
+ Ò: 'O',
146
+ ą: 'a',
147
+ ć: 'c',
148
+ ę: 'e',
149
+ ł: 'l',
150
+ ń: 'n',
151
+ ś: 's',
152
+ ź: 'z',
153
+ ż: 'z',
154
+ Ą: 'A',
155
+ Ć: 'C',
156
+ Ę: 'E',
157
+ Ł: 'L',
158
+ Ń: 'N',
159
+ Ś: 'S',
160
+ Ź: 'Z',
161
+ Ż: 'Z',
162
+ č: 'c',
163
+ ď: 'd',
164
+ ě: 'e',
165
+ ň: 'n',
166
+ ř: 'r',
167
+ š: 's',
168
+ ť: 't',
169
+ ů: 'u',
170
+ ž: 'z',
171
+ Č: 'C',
172
+ Ď: 'D',
173
+ Ě: 'E',
174
+ Ň: 'N',
175
+ Ř: 'R',
176
+ Š: 'S',
177
+ Ť: 'T',
178
+ Ů: 'U',
179
+ Ž: 'Z',
180
+ ș: 's',
181
+ ț: 't',
182
+ Ș: 'S',
183
+ Ț: 'T',
184
+ ő: 'o',
185
+ ű: 'u',
186
+ Ő: 'O',
187
+ Ű: 'U',
188
+ ğ: 'g',
189
+ ı: 'i',
190
+ ş: 's',
191
+ Ğ: 'G',
192
+ İ: 'I',
193
+ Ş: 'S',
194
+ '¿': '',
195
+ '¡': '',
196
+ // Greek
197
+ α: 'a',
198
+ β: 'b',
199
+ γ: 'g',
200
+ δ: 'd',
201
+ ε: 'e',
202
+ ζ: 'z',
203
+ η: 'i',
204
+ θ: 'th',
205
+ ι: 'i',
206
+ κ: 'k',
207
+ λ: 'l',
208
+ μ: 'm',
209
+ ν: 'n',
210
+ ξ: 'x',
211
+ ο: 'o',
212
+ π: 'p',
213
+ ρ: 'r',
214
+ σ: 's',
215
+ ς: 's',
216
+ τ: 't',
217
+ υ: 'y',
218
+ φ: 'f',
219
+ χ: 'ch',
220
+ ψ: 'ps',
221
+ ω: 'o',
222
+ ά: 'a',
223
+ έ: 'e',
224
+ ή: 'i',
225
+ ί: 'i',
226
+ ό: 'o',
227
+ ύ: 'y',
228
+ ώ: 'o',
229
+ Α: 'A',
230
+ Β: 'B',
231
+ Γ: 'G',
232
+ Δ: 'D',
233
+ Ε: 'E',
234
+ Ζ: 'Z',
235
+ Η: 'I',
236
+ Θ: 'Th',
237
+ Ι: 'I',
238
+ Κ: 'K',
239
+ Λ: 'L',
240
+ Μ: 'M',
241
+ Ν: 'N',
242
+ Ξ: 'X',
243
+ Ο: 'O',
244
+ Π: 'P',
245
+ Ρ: 'R',
246
+ Σ: 'S',
247
+ Τ: 'T',
248
+ Υ: 'Y',
249
+ Φ: 'F',
250
+ Χ: 'Ch',
251
+ Ψ: 'Ps',
252
+ Ω: 'O',
253
+ Ά: 'A',
254
+ Έ: 'E',
255
+ Ή: 'I',
256
+ Ί: 'I',
257
+ Ό: 'O',
258
+ Ύ: 'Y',
259
+ Ώ: 'O',
260
+ // Arabic
261
+ ا: 'a',
262
+ ب: 'b',
263
+ ت: 't',
264
+ ث: 'th',
265
+ ج: 'j',
266
+ ح: 'h',
267
+ خ: 'kh',
268
+ د: 'd',
269
+ ذ: 'dh',
270
+ ر: 'r',
271
+ ز: 'z',
272
+ س: 's',
273
+ ش: 'sh',
274
+ ص: 's',
275
+ ض: 'd',
276
+ ط: 't',
277
+ ظ: 'z',
278
+ ع: 'a',
279
+ غ: 'gh',
280
+ ف: 'f',
281
+ ق: 'q',
282
+ ك: 'k',
283
+ ل: 'l',
284
+ م: 'm',
285
+ ن: 'n',
286
+ ه: 'h',
287
+ و: 'w',
288
+ ي: 'y',
289
+ // Hebrew
290
+ א: 'a',
291
+ ב: 'b',
292
+ ג: 'g',
293
+ ד: 'd',
294
+ ה: 'h',
295
+ ו: 'v',
296
+ ז: 'z',
297
+ ח: 'ch',
298
+ ט: 't',
299
+ י: 'y',
300
+ כ: 'k',
301
+ ך: 'k',
302
+ ל: 'l',
303
+ מ: 'm',
304
+ ם: 'm',
305
+ נ: 'n',
306
+ ן: 'n',
307
+ ס: 's',
308
+ ע: 'a',
309
+ פ: 'p',
310
+ ף: 'p',
311
+ צ: 'ts',
312
+ ץ: 'ts',
313
+ ק: 'k',
314
+ ר: 'r',
315
+ ש: 'sh',
316
+ ת: 't',
317
+ };
318
+ // Transliterate non-Latin characters to Latin
319
+ const transliterate = (text) => {
320
+ return text
321
+ .split('')
322
+ .map((char) => transliterationMap[char] ?? char)
323
+ .join('');
324
+ };
20
325
  // Generate slug from title
21
326
  const generateSlug = (title) => {
22
- return (title
327
+ const transliterated = transliterate(title);
328
+ return (transliterated
23
329
  .toLowerCase()
24
330
  .replace(/[^a-z0-9]+/g, '-')
25
331
  .replace(/^-+|-+$/g, '')
@@ -27,6 +333,7 @@ const generateSlug = (title) => {
27
333
  };
28
334
  export function DocumentEdit({}) {
29
335
  const { onOpen, onEdit, theme, params } = useDocument();
336
+ const { t } = useTranslation();
30
337
  const isNewDocument = params.documentSlug === undefined;
31
338
  // Fetch existing document data if editing
32
339
  const { data: existingDoc, isLoading: isLoadingDoc } = useDocumentQuery(params.documentSlug);
@@ -35,6 +342,8 @@ export function DocumentEdit({}) {
35
342
  const updateMutation = useUpdateDocumentMutation();
36
343
  // Local state
37
344
  const [title, setTitle] = useState('');
345
+ const [slug, setSlug] = useState('');
346
+ const [isSlugManuallyEdited, setIsSlugManuallyEdited] = useState(false);
38
347
  const [emoji, setEmoji] = useState(undefined);
39
348
  const [cover, setCover] = useState(null);
40
349
  const [isSaving, setIsSaving] = useState(false);
@@ -52,6 +361,7 @@ export function DocumentEdit({}) {
52
361
  useEffect(() => {
53
362
  if (existingDoc && !hasLoaded) {
54
363
  setTitle(existingDoc.title);
364
+ setSlug(existingDoc.slug);
55
365
  if (existingDoc.emoji)
56
366
  setEmoji(existingDoc.emoji);
57
367
  if (existingDoc.cover)
@@ -70,6 +380,12 @@ export function DocumentEdit({}) {
70
380
  setHasLoaded(true);
71
381
  }
72
382
  }, [existingDoc, editor, hasLoaded]);
383
+ // Auto-generate slug from title for new documents (only when not manually edited)
384
+ useEffect(() => {
385
+ if (isNewDocument && !isSlugManuallyEdited && title) {
386
+ setSlug(generateSlug(title));
387
+ }
388
+ }, [title, isNewDocument, isSlugManuallyEdited]);
73
389
  const handleView = async () => {
74
390
  if (!existingDoc)
75
391
  return;
@@ -78,18 +394,22 @@ export function DocumentEdit({}) {
78
394
  };
79
395
  const handleSave = async () => {
80
396
  if (!title.trim()) {
81
- alert('Please enter a document title');
397
+ alert(t('editor.titleRequired'));
398
+ return;
399
+ }
400
+ if (!slug.trim()) {
401
+ alert(t('editor.slugRequired'));
82
402
  return;
83
403
  }
84
404
  setIsSaving(true);
85
405
  try {
86
406
  const content = editor.document;
87
- const slug = generateSlug(title);
407
+ const finalSlug = slug.trim() || generateSlug(title);
88
408
  if (!existingDoc) {
89
409
  // Create new document (with parentId if it's a child document)
90
410
  const newDoc = await createMutation.mutateAsync({
91
411
  title,
92
- slug,
412
+ slug: finalSlug,
93
413
  content,
94
414
  isPublished: true,
95
415
  parentSlugs: params.slugs,
@@ -104,7 +424,7 @@ export function DocumentEdit({}) {
104
424
  id: existingDoc.id,
105
425
  data: {
106
426
  title,
107
- slug,
427
+ slug: finalSlug,
108
428
  content,
109
429
  emoji,
110
430
  cover,
@@ -114,7 +434,7 @@ export function DocumentEdit({}) {
114
434
  }
115
435
  catch (error) {
116
436
  console.error('Failed to save document:', error);
117
- alert('Failed to save document. Please try again.');
437
+ alert(t('editor.saveFailed'));
118
438
  }
119
439
  finally {
120
440
  setIsSaving(false);
@@ -147,7 +467,15 @@ export function DocumentEdit({}) {
147
467
  if (!isNewDocument && isLoadingDoc) {
148
468
  return (_jsx("div", { className: "flex items-center justify-center min-h-100", children: _jsx(Loader2, { className: "h-8 w-8 animate-spin text-gray-400" }) }));
149
469
  }
150
- return (_jsxs("div", { className: "mx-auto h-full flex flex-col", children: [_jsxs("div", { className: "mb-6 shrink-0", children: [_jsxs("div", { className: "flex items-start justify-between gap-4", children: [_jsxs("div", { className: "flex items-center gap-2 flex-1", children: [_jsx(EmojiPicker, { value: emoji, onChange: setEmoji }), _jsx("input", { type: "text", value: title, onChange: (e) => setTitle(e.target.value), placeholder: "Document title", className: "text-2xl font-bold bg-transparent border-none outline-none px-0 flex-1 placeholder:text-gray-400" })] }), _jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [!isNewDocument && existingDoc && (_jsxs("button", { onClick: handleView, className: "px-3 py-1.5 text-sm border border-border rounded-md hover:bg-gray-50 flex items-center gap-2 transition-colors", children: [_jsx(Eye, { className: "h-4 w-4" }), "View"] })), _jsx("button", { onClick: handleSave, disabled: isSaving || createMutation.isPending || updateMutation.isPending, className: "px-3 py-1.5 text-sm bg-primary text-white rounded-md hover:bg-gray-800 disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2 transition-colors", children: isSaving ||
470
+ return (_jsxs("div", { className: "mx-auto h-full flex flex-col", children: [_jsxs("div", { className: "mb-6 shrink-0", children: [_jsxs("div", { className: "flex items-start justify-between gap-4", children: [_jsxs("div", { className: "flex items-center gap-2 flex-1", children: [_jsx(EmojiPicker, { value: emoji, onChange: setEmoji }), _jsx("input", { type: "text", value: title, onChange: (e) => setTitle(e.target.value), placeholder: t('editor.titlePlaceholder'), className: "text-2xl font-bold bg-transparent border-none outline-none px-0 flex-1 placeholder:text-gray-400" })] }), _jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [!isNewDocument && existingDoc && (_jsxs("button", { onClick: handleView, className: "px-3 py-1.5 text-sm border border-border rounded-md hover:bg-gray-50 flex items-center gap-2 transition-colors", children: [_jsx(Eye, { className: "h-4 w-4" }), t('editor.view')] })), _jsx("button", { onClick: handleSave, disabled: isSaving || createMutation.isPending || updateMutation.isPending, className: "px-3 py-1.5 text-sm bg-primary text-white rounded-md hover:bg-gray-800 disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2 transition-colors", children: isSaving ||
151
471
  createMutation.isPending ||
152
- updateMutation.isPending ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), "Saving..."] })) : (_jsxs(_Fragment, { children: [_jsx(Save, { className: "h-4 w-4" }), isNewDocument ? 'Create' : 'Save'] })) })] })] }), _jsxs("div", { className: "text-sm text-gray-500 mt-1", children: ["Slug: ", generateSlug(title)] })] }), _jsx("div", { className: "mb-6 shrink-0", children: cover ? (_jsxs("div", { className: "relative w-full h-80 rounded-lg overflow-hidden bg-gray-100", children: [_jsx("img", { src: cover, alt: "Cover", className: "w-full h-full object-cover" }), _jsx("button", { onClick: () => setCover(null), className: "absolute top-2 right-2 p-1.5 bg-secondary hover:bg-white rounded-md shadow-sm transition-colors", title: "Remove cover", children: _jsx(X, { className: "h-4 w-4" }) })] })) : (_jsxs("div", { onDrop: handleDrop, onDragOver: handleDragOver, className: "relative w-full h-32 border-2 border-dashed border-border rounded-lg bg-secondary hover:bg-gray-100 transition-colors cursor-pointer", children: [_jsx("input", { type: "file", accept: "image/jpeg,image/png,image/gif,image/webp", onChange: handleFileInput, className: "absolute inset-0 w-full h-full opacity-0 cursor-pointer" }), _jsx("div", { className: "flex flex-col items-center justify-center h-full gap-2 text-gray-400", children: isUploadingCover ? (_jsx(Loader2, { className: "h-6 w-6 animate-spin" })) : (_jsxs(_Fragment, { children: [_jsx(ImageIcon, { className: "h-6 w-6" }), _jsx("span", { className: "text-sm", children: "Drag & drop cover image here or click to upload" }), _jsx("span", { className: "text-xs text-gray-400", children: "JPEG, PNG, GIF, WebP up to 5MB" })] })) })] })) }), _jsx("div", { className: "flex-1 min-h-0 overflow-auto", children: _jsx("div", { className: "h-full", children: _jsx(BlockNoteView, { editor: editor, theme: blockNoteTheme[theme], className: "h-full" }) }) })] }));
472
+ updateMutation.isPending ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), t('editor.saving')] })) : (_jsxs(_Fragment, { children: [_jsx(Save, { className: "h-4 w-4" }), isNewDocument ? t('editor.create') : t('editor.save')] })) })] })] }), _jsxs("div", { className: "text-sm text-gray-500 mt-2 flex items-center gap-2", children: [_jsxs("span", { className: "shrink-0", children: [t('editor.slug'), ":"] }), _jsx("input", { type: "text", value: slug, onChange: (e) => {
473
+ setSlug(e.target.value);
474
+ setIsSlugManuallyEdited(true);
475
+ }, onBlur: (e) => {
476
+ if (e.target.value.trim() === '') {
477
+ setIsSlugManuallyEdited(false);
478
+ setSlug(generateSlug(title));
479
+ }
480
+ }, placeholder: generateSlug(title), className: "bg-transparent border-none outline-none px-0 flex-1 text-gray-500 placeholder:text-gray-400 font-mono text-sm" })] })] }), _jsx("div", { className: "mb-6 shrink-0", children: cover ? (_jsxs("div", { className: "relative w-full h-80 rounded-lg overflow-hidden bg-gray-100", children: [_jsx("img", { src: cover, alt: t('editor.coverAlt'), className: "w-full h-full object-cover" }), _jsx("button", { onClick: () => setCover(null), className: "absolute top-2 right-2 p-1.5 bg-secondary hover:bg-white rounded-md shadow-sm transition-colors", title: t('editor.removeCover'), children: _jsx(X, { className: "h-4 w-4" }) })] })) : (_jsxs("div", { onDrop: handleDrop, onDragOver: handleDragOver, className: "relative w-full h-32 border-2 border-dashed border-border rounded-lg bg-secondary hover:bg-gray-100 transition-colors cursor-pointer", children: [_jsx("input", { type: "file", accept: "image/jpeg,image/png,image/gif,image/webp", onChange: handleFileInput, className: "absolute inset-0 w-full h-full opacity-0 cursor-pointer" }), _jsx("div", { className: "flex flex-col items-center justify-center h-full gap-2 text-gray-400", children: isUploadingCover ? (_jsx(Loader2, { className: "h-6 w-6 animate-spin" })) : (_jsxs(_Fragment, { children: [_jsx(ImageIcon, { className: "h-6 w-6" }), _jsx("span", { className: "text-sm", children: t('editor.coverDropzone') }), _jsx("span", { className: "text-xs text-gray-400", children: t('editor.coverFormats') })] })) })] })) }), _jsx("div", { className: "flex-1 min-h-0 overflow-auto", children: _jsx("div", { className: "h-full", children: _jsx(BlockNoteView, { editor: editor, theme: blockNoteTheme[theme], className: "h-full" }) }) })] }));
153
481
  }
@@ -1 +1 @@
1
- {"version":3,"file":"DocumentList.d.ts","sourceRoot":"","sources":["../../../src/client/components/DocumentList.tsx"],"names":[],"mappings":"AAiBA,UAAU,iBAAiB;CAAG;AAuB9B,wBAAgB,YAAY,CAAC,EAAE,EAAE,iBAAiB,2CAiIjD"}
1
+ {"version":3,"file":"DocumentList.d.ts","sourceRoot":"","sources":["../../../src/client/components/DocumentList.tsx"],"names":[],"mappings":"AAkBA,UAAU,iBAAiB;CAAG;AAgC9B,wBAAgB,YAAY,CAAC,EAAE,EAAE,iBAAiB,2CAmIjD"}
@@ -2,8 +2,9 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { FileText, Folder, Plus } from 'lucide-react';
4
4
  import { useDocumentsQuery } from '../hooks/useDocsQuery.js';
5
+ import { useTranslation } from '../hooks/useTranslation.js';
5
6
  import { useDocument } from './DocumentProvider.js';
6
- function formatDistanceToNow(date) {
7
+ function formatDistanceToNow(date, t) {
7
8
  const now = new Date();
8
9
  const diffMs = now.getTime() - new Date(date).getTime();
9
10
  const diffSec = Math.round(diffMs / 1000);
@@ -11,16 +12,22 @@ function formatDistanceToNow(date) {
11
12
  const diffHour = Math.round(diffMin / 60);
12
13
  const diffDay = Math.round(diffHour / 24);
13
14
  if (diffSec < 60) {
14
- return 'just now';
15
+ return t('docList.justNow');
15
16
  }
16
17
  else if (diffMin < 60) {
17
- return `${diffMin} minute${diffMin === 1 ? '' : 's'} ago`;
18
+ return diffMin === 1
19
+ ? t('docList.minuteAgo', { n: diffMin })
20
+ : t('docList.minutesAgo', { n: diffMin });
18
21
  }
19
22
  else if (diffHour < 24) {
20
- return `${diffHour} hour${diffHour === 1 ? '' : 's'} ago`;
23
+ return diffHour === 1
24
+ ? t('docList.hourAgo', { n: diffHour })
25
+ : t('docList.hoursAgo', { n: diffHour });
21
26
  }
22
27
  else if (diffDay < 7) {
23
- return `${diffDay} day${diffDay === 1 ? '' : 's'} ago`;
28
+ return diffDay === 1
29
+ ? t('docList.dayAgo', { n: diffDay })
30
+ : t('docList.daysAgo', { n: diffDay });
24
31
  }
25
32
  else {
26
33
  return date.toLocaleDateString();
@@ -28,12 +35,15 @@ function formatDistanceToNow(date) {
28
35
  }
29
36
  export function DocumentList({}) {
30
37
  const { onOpen, onCreate } = useDocument();
38
+ const { t } = useTranslation();
31
39
  const { data, isLoading, error } = useDocumentsQuery();
32
40
  const documents = data?.documents ?? [];
33
41
  // Separate documents into folders (documents with children) and regular documents
34
42
  const folders = documents.filter((doc) => documents.some((d) => d.parentId === doc.id));
35
43
  const regularDocuments = documents.filter((doc) => !doc.parentId && !folders.some((f) => f.id === doc.id));
36
- return (_jsxs("div", { className: "space-y-6 max-w-5xl mx-auto", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("h2", { className: "text-2xl font-bold", children: "Welcome to Documentation" }), _jsx("p", { className: "text-gray-500", children: "Browse and manage your documentation. Create new documents or organize them into folders." })] }), folders.length > 0 && (_jsxs("section", { children: [_jsx("h3", { className: "text-lg font-semibold mb-4", children: "Folders" }), _jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4", children: [folders.map((folder) => (_jsxs("div", { onClick: () => onOpen?.(folder.slug), className: "border border-gray-200 rounded-lg p-4 hover:bg-gray-50 transition-colors cursor-pointer", children: [_jsxs("div", { className: "flex items-start justify-between mb-2", children: [folder.emoji ? (_jsx("span", { className: "text-2xl", children: folder.emoji })) : (_jsx(Folder, { className: "h-8 w-8 text-blue-600" })), _jsxs("span", { className: "text-xs text-gray-500", children: [documents.filter((d) => d.parentId === folder.id).length, ' ', "docs"] })] }), _jsx("h4", { className: "text-base font-medium", children: folder.title })] }, folder.id))), _jsxs("div", { onClick: onCreate, className: "border border-dashed border-gray-300 rounded-lg p-4 hover:bg-gray-50 transition-colors cursor-pointer", children: [_jsx("div", { className: "flex items-center justify-center h-8 mb-2", children: _jsx(Plus, { className: "h-6 w-6 text-gray-400" }) }), _jsx("h4", { className: "text-base font-medium text-center text-gray-500", children: "New Folder" })] })] })] })), _jsxs("section", { children: [_jsxs("div", { className: "flex items-center justify-between mb-4", children: [_jsx("h3", { className: "text-lg font-semibold", children: folders.length > 0 ? 'Documents' : 'Recent Documents' }), _jsxs("button", { onClick: onCreate, className: "px-3 py-1.5 text-sm bg-gray-900 text-white rounded-md hover:bg-gray-800 flex items-center gap-2 transition-colors", children: [_jsx(Plus, { className: "h-4 w-4" }), "New Document"] })] }), regularDocuments.length === 0 ? (_jsx("div", { className: "border border-dashed border-gray-300 rounded-lg p-8", children: _jsxs("div", { className: "flex flex-col items-center justify-center text-center", children: [_jsx(FileText, { className: "h-12 w-12 text-gray-400 mb-4" }), _jsx("h4", { className: "text-lg font-medium mb-2", children: "No documents yet" }), _jsx("p", { className: "text-sm text-gray-500 mb-4", children: "Get started by creating your first document" }), _jsxs("button", { onClick: onCreate, className: "px-4 py-2 bg-gray-900 text-white rounded-md hover:bg-gray-800 flex items-center gap-2 transition-colors", children: [_jsx(Plus, { className: "h-4 w-4" }), "Create Document"] })] }) })) : (_jsx("div", { className: "space-y-2", children: regularDocuments.map((doc) => (_jsxs("div", { onClick: () => onOpen?.(doc.slug), className: "flex items-center justify-between p-4 rounded-lg border border-gray-200 bg-white hover:bg-gray-50 transition-colors group cursor-pointer", children: [_jsxs("div", { className: "flex items-center gap-3", children: [doc.emoji ? (_jsx("span", { className: "text-xl", children: doc.emoji })) : (_jsx(FileText, { className: "h-5 w-5 text-gray-400 group-hover:text-gray-600 transition-colors" })), _jsxs("div", { children: [_jsx("h4", { className: "font-medium text-gray-900", children: doc.title }), _jsxs("p", { className: "text-sm text-gray-500", children: ["Updated", ' ', doc.updatedAt
37
- ? formatDistanceToNow(new Date(doc.updatedAt))
38
- : 'N/A'] })] })] }), _jsx("button", { className: "px-3 py-1.5 text-sm text-gray-600 hover:bg-gray-100 rounded-md transition-colors", children: "Open" })] }, doc.id))) }))] })] }));
44
+ return (_jsxs("div", { className: "space-y-6 max-w-5xl mx-auto", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("h2", { className: "text-2xl font-bold", children: t('docList.welcome') }), _jsx("p", { className: "text-gray-500", children: t('docList.welcomeDescription') })] }), folders.length > 0 && (_jsxs("section", { children: [_jsx("h3", { className: "text-lg font-semibold mb-4", children: t('docList.folders') }), _jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4", children: [folders.map((folder) => (_jsxs("div", { onClick: () => onOpen?.(folder.slug), className: "border border-gray-200 rounded-lg p-4 hover:bg-gray-50 transition-colors cursor-pointer", children: [_jsxs("div", { className: "flex items-start justify-between mb-2", children: [folder.emoji ? (_jsx("span", { className: "text-2xl", children: folder.emoji })) : (_jsx(Folder, { className: "h-8 w-8 text-blue-600" })), _jsxs("span", { className: "text-xs text-gray-500", children: [documents.filter((d) => d.parentId === folder.id).length, ' ', t('docList.docs')] })] }), _jsx("h4", { className: "text-base font-medium", children: folder.title })] }, folder.id))), _jsxs("div", { onClick: () => onCreate(), className: "border border-dashed border-gray-300 rounded-lg p-4 hover:bg-gray-50 transition-colors cursor-pointer", children: [_jsx("div", { className: "flex items-center justify-center h-8 mb-2", children: _jsx(Plus, { className: "h-6 w-6 text-gray-400" }) }), _jsx("h4", { className: "text-base font-medium text-center text-gray-500", children: t('docList.newFolder') })] })] })] })), _jsxs("section", { children: [_jsxs("div", { className: "flex items-center justify-between mb-4", children: [_jsx("h3", { className: "text-lg font-semibold", children: folders.length > 0
45
+ ? t('docList.documents')
46
+ : t('docList.recentDocuments') }), _jsxs("button", { onClick: () => onCreate(), className: "px-3 py-1.5 text-sm bg-gray-900 text-white rounded-md hover:bg-gray-800 flex items-center gap-2 transition-colors", children: [_jsx(Plus, { className: "h-4 w-4" }), t('docList.newDocument')] })] }), regularDocuments.length === 0 ? (_jsx("div", { className: "border border-dashed border-gray-300 rounded-lg p-8", children: _jsxs("div", { className: "flex flex-col items-center justify-center text-center", children: [_jsx(FileText, { className: "h-12 w-12 text-gray-400 mb-4" }), _jsx("h4", { className: "text-lg font-medium mb-2", children: t('docList.noDocuments') }), _jsx("p", { className: "text-sm text-gray-500 mb-4", children: t('docList.getStarted') }), _jsxs("button", { onClick: () => onCreate(), className: "px-4 py-2 bg-gray-900 text-white rounded-md hover:bg-gray-800 flex items-center gap-2 transition-colors", children: [_jsx(Plus, { className: "h-4 w-4" }), t('docList.createDocument')] })] }) })) : (_jsx("div", { className: "space-y-2", children: regularDocuments.map((doc) => (_jsxs("div", { onClick: () => onOpen?.(doc.slug), className: "flex items-center justify-between p-4 rounded-lg border border-gray-200 bg-white hover:bg-gray-50 transition-colors group cursor-pointer", children: [_jsxs("div", { className: "flex items-center gap-3", children: [doc.emoji ? (_jsx("span", { className: "text-xl", children: doc.emoji })) : (_jsx(FileText, { className: "h-5 w-5 text-gray-400 group-hover:text-gray-600 transition-colors" })), _jsxs("div", { children: [_jsx("h4", { className: "font-medium text-gray-900", children: doc.title }), _jsxs("p", { className: "text-sm text-gray-500", children: [t('docList.updated'), ' ', doc.updatedAt
47
+ ? formatDistanceToNow(new Date(doc.updatedAt), t)
48
+ : 'N/A'] })] })] }), _jsx("button", { className: "px-3 py-1.5 text-sm text-gray-600 hover:bg-gray-100 rounded-md transition-colors", children: t('docList.open') })] }, doc.id))) }))] })] }));
39
49
  }
@@ -14,7 +14,7 @@ export interface DocumentContextValue {
14
14
  path: string;
15
15
  locale: string;
16
16
  params: Params;
17
- onCreate: () => void;
17
+ onCreate: (slug?: string) => void;
18
18
  onOpen: (path: string) => void;
19
19
  onEdit: (slug: string) => void;
20
20
  onDelete: (doc: DocumentSummary) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"DocumentProvider.d.ts","sourceRoot":"","sources":["../../../src/client/components/DocumentProvider.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAiB,SAAS,EAA2B,MAAM,OAAO,CAAA;AACzE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAEvC;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,MAAM,CAAA;AAE5C;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,oBAAoB;IACpB,KAAK,EAAE,aAAa,CAAA;IACpB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9B,QAAQ,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,CAAA;CACzC;AAOD;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,SAAS,CAAA;IACnB,KAAK,CAAC,EAAE,aAAa,CAAA;IACrB,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,CAAA;CACrB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EACR,MAAM,EACN,KAAe,EACf,IAAI,EACJ,UAAU,EACV,MAAa,GACd,EAAE,qBAAqB,GAAG,GAAG,CAAC,OAAO,CAyCrC;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,oBAAoB,CAQlD"}
1
+ {"version":3,"file":"DocumentProvider.d.ts","sourceRoot":"","sources":["../../../src/client/components/DocumentProvider.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAiB,SAAS,EAA2B,MAAM,OAAO,CAAA;AACzE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAEvC;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,MAAM,CAAA;AAE5C;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,oBAAoB;IACpB,KAAK,EAAE,aAAa,CAAA;IACpB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9B,QAAQ,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,CAAA;CACzC;AAOD;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,SAAS,CAAA;IACnB,KAAK,CAAC,EAAE,aAAa,CAAA;IACrB,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,CAAA;CACrB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EACR,MAAM,EACN,KAAe,EACf,IAAI,EACJ,UAAU,EACV,MAAa,GACd,EAAE,qBAAqB,GAAG,GAAG,CAAC,OAAO,CAgDrC;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,oBAAoB,CAQlD"}
@@ -16,7 +16,11 @@ export function DocumentProvider({ children, params, theme = 'light', path, onNa
16
16
  const onEdit = useCallback((slug) => {
17
17
  onNavigate?.(`${slug}/edit`);
18
18
  }, [onNavigate]);
19
- const onCreate = useCallback(() => {
19
+ const onCreate = useCallback((slug) => {
20
+ if (slug) {
21
+ onNavigate?.(`${slug}`);
22
+ return;
23
+ }
20
24
  onNavigate?.(`${path}/new`);
21
25
  }, [onNavigate]);
22
26
  const onDelete = useCallback((doc) => {
@@ -1 +1 @@
1
- {"version":3,"file":"DocumentView.d.ts","sourceRoot":"","sources":["../../../src/client/components/DocumentView.tsx"],"names":[],"mappings":"AAIA,OAAO,8BAA8B,CAAA;AASrC,UAAU,iBAAiB;CAAG;AAU9B,wBAAgB,YAAY,CAAC,EAAE,EAAE,iBAAiB,2CA0HjD"}
1
+ {"version":3,"file":"DocumentView.d.ts","sourceRoot":"","sources":["../../../src/client/components/DocumentView.tsx"],"names":[],"mappings":"AAIA,OAAO,8BAA8B,CAAA;AAUrC,UAAU,iBAAiB;CAAG;AAU9B,wBAAgB,YAAY,CAAC,EAAE,EAAE,iBAAiB,2CA2HjD"}
@@ -6,6 +6,7 @@ import { useCreateBlockNote } from '@blocknote/react';
6
6
  import { Clock, Edit, Loader2, User } from 'lucide-react';
7
7
  import { useCallback, useEffect, useState } from 'react';
8
8
  import { useDocumentQuery } from '../hooks/useDocsQuery.js';
9
+ import { useTranslation } from '../hooks/useTranslation.js';
9
10
  import { blockNoteTheme } from '../lib/blocknoteTheme.js';
10
11
  import { useDocument } from './DocumentProvider.js';
11
12
  import { ExportButton } from './ExportButton.js';
@@ -17,7 +18,8 @@ const getDefaultContent = () => [
17
18
  },
18
19
  ];
19
20
  export function DocumentView({}) {
20
- const { params, onCreate, onEdit, theme } = useDocument();
21
+ const { params, onEdit, theme } = useDocument();
22
+ const { t } = useTranslation();
21
23
  const { data: doc, isLoading, error } = useDocumentQuery(params.documentSlug);
22
24
  const [hasLoaded, setHasLoaded] = useState(false);
23
25
  // Creates a new editor instance in read-only mode
@@ -50,9 +52,9 @@ export function DocumentView({}) {
50
52
  return (_jsx("div", { className: "flex items-center justify-center min-h-[400px]", children: _jsx(Loader2, { className: "h-8 w-8 animate-spin text-gray-400" }) }));
51
53
  }
52
54
  if (error || !doc) {
53
- return (_jsx("div", { className: "flex items-center justify-center min-h-[400px]", children: _jsx("p", { className: "text-red-500", children: "Failed to load document. Please try again." }) }));
55
+ return (_jsx("div", { className: "flex items-center justify-center min-h-[400px]", children: _jsx("p", { className: "text-red-500", children: t('view.loadFailed') }) }));
54
56
  }
55
- return (_jsxs("div", { className: "max-w-[80%] mx-auto", children: [_jsxs("div", { className: "mb-8", children: [_jsxs("div", { className: "flex items-start justify-between gap-4 mb-4", children: [_jsxs("div", { className: "flex items-center gap-3", children: [doc.emoji && (_jsx("span", { className: "text-5xl leading-none", role: "img", "aria-label": "document emoji", children: doc.emoji })), _jsx("h1", { className: "text-3xl font-bold", children: doc.title })] }), _jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [doc && (_jsx(ExportButton, { documentId: doc.id, documentTitle: doc.title })), _jsxs("button", { onClick: handleEdit, className: "px-3 py-1.5 text-sm bg-secondary text-white rounded-md hover:bg-primary flex items-center gap-2 transition-colors", children: [_jsx(Edit, { className: "h-4 w-4" }), "Edit"] })] })] }), _jsxs("div", { className: "flex items-center gap-6 text-sm text-gray-500", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(User, { className: "h-4 w-4" }), _jsxs("span", { children: ["Author ID: ", doc.authorId] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Clock, { className: "h-4 w-4" }), _jsxs("span", { children: ["Updated", ' ', doc.updatedAt
57
+ return (_jsxs("div", { className: "max-w-[80%] mx-auto", children: [_jsxs("div", { className: "mb-8", children: [_jsxs("div", { className: "flex items-start justify-between gap-4 mb-4", children: [_jsxs("div", { className: "flex items-center gap-3", children: [doc.emoji && (_jsx("span", { className: "text-5xl leading-none", role: "img", "aria-label": "document emoji", children: doc.emoji })), _jsx("h1", { className: "text-3xl font-bold", children: doc.title })] }), _jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [doc && (_jsx(ExportButton, { documentId: doc.id, documentTitle: doc.title })), _jsxs("button", { onClick: handleEdit, className: "px-3 py-1.5 text-sm bg-secondary text-white rounded-md hover:bg-primary flex items-center gap-2 transition-colors", children: [_jsx(Edit, { className: "h-4 w-4" }), t('view.edit')] })] })] }), _jsxs("div", { className: "flex items-center gap-6 text-sm text-gray-500", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(User, { className: "h-4 w-4" }), _jsxs("span", { children: [t('view.authorId'), ": ", doc.authorId] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Clock, { className: "h-4 w-4" }), _jsxs("span", { children: [t('view.updated'), ' ', doc.updatedAt
56
58
  ? new Date(doc.updatedAt).toLocaleDateString()
57
59
  : 'N/A'] })] })] })] }), doc.cover && (_jsx("div", { className: "mb-8 -mx-4 sm:-mx-8 lg:-mx-12", children: _jsx("div", { className: "relative w-full max-h-80 overflow-hidden", children: _jsx("img", { src: doc.cover, alt: doc.title, className: "w-full h-full object-cover" }) }) })), _jsx("div", { children: _jsx(BlockNoteView, { editor: editor, editable: false, theme: blockNoteTheme[theme], className: "[&_.bn-editor]:p-0 [&_.bn-editor]:px-0 [&_.bn-container]:max-w-none [&_.bn-editor]:!px-0" }) })] }));
58
60
  }
@@ -1 +1 @@
1
- {"version":3,"file":"EmojiPicker.d.ts","sourceRoot":"","sources":["../../../src/client/components/EmojiPicker.tsx"],"names":[],"mappings":"AAIA,UAAU,gBAAgB;IACxB,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;IAChC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAgBD,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,gBAAgB,2CAoE3E"}
1
+ {"version":3,"file":"EmojiPicker.d.ts","sourceRoot":"","sources":["../../../src/client/components/EmojiPicker.tsx"],"names":[],"mappings":"AAKA,UAAU,gBAAgB;IACxB,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;IAChC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAgBD,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,gBAAgB,2CAqE3E"}