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.
- package/dist/client/components/Breadcrumbs.d.ts.map +1 -1
- package/dist/client/components/Breadcrumbs.js +9 -6
- package/dist/client/components/DocumentEdit.d.ts.map +1 -1
- package/dist/client/components/DocumentEdit.js +336 -8
- package/dist/client/components/DocumentList.d.ts.map +1 -1
- package/dist/client/components/DocumentList.js +18 -8
- package/dist/client/components/DocumentProvider.d.ts +1 -1
- package/dist/client/components/DocumentProvider.d.ts.map +1 -1
- package/dist/client/components/DocumentProvider.js +5 -1
- package/dist/client/components/DocumentView.d.ts.map +1 -1
- package/dist/client/components/DocumentView.js +5 -3
- package/dist/client/components/EmojiPicker.d.ts.map +1 -1
- package/dist/client/components/EmojiPicker.js +3 -1
- package/dist/client/components/ExportButton.d.ts.map +1 -1
- package/dist/client/components/ExportButton.js +14 -12
- package/dist/client/components/Layout.d.ts.map +1 -1
- package/dist/client/components/Layout.js +7 -3
- package/dist/client/components/ReactEmbedDocs.d.ts.map +1 -1
- package/dist/client/components/ReactEmbedDocs.js +2 -1
- package/dist/client/components/Sidebar.d.ts.map +1 -1
- package/dist/client/components/Sidebar.js +4 -2
- package/dist/client/components/VersionHistory.d.ts.map +1 -1
- package/dist/client/components/VersionHistory.js +13 -11
- package/dist/client/hooks/useTranslation.d.ts +13 -0
- package/dist/client/hooks/useTranslation.d.ts.map +1 -0
- package/dist/client/hooks/useTranslation.js +27 -0
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -0
- package/dist/client/locales/en.json +83 -0
- package/dist/client/locales/ru.json +83 -0
- package/package.json +1 -1
- package/dist/client/components/DocsLayout.d.ts +0 -20
- package/dist/client/components/DocsLayout.d.ts.map +0 -1
- package/dist/client/components/DocsLayout.js +0 -387
- package/dist/client/providers/DocumentProvider.d.ts +0 -1
- package/dist/client/providers/DocumentProvider.d.ts.map +0 -1
- 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":"
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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;
|
|
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
|
-
|
|
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('
|
|
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
|
|
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('
|
|
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:
|
|
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" }),
|
|
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":"
|
|
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 '
|
|
15
|
+
return t('docList.justNow');
|
|
15
16
|
}
|
|
16
17
|
else if (diffMin < 60) {
|
|
17
|
-
return
|
|
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
|
|
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
|
|
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:
|
|
37
|
-
|
|
38
|
-
|
|
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;
|
|
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;
|
|
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,
|
|
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:
|
|
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" }),
|
|
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":"
|
|
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"}
|