living-documentation 7.0.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/LICENSE +661 -0
- package/README.md +329 -0
- package/dist/bin/cli.d.ts +3 -0
- package/dist/bin/cli.d.ts.map +1 -0
- package/dist/bin/cli.js +62 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/src/frontend/admin.html +1073 -0
- package/dist/src/frontend/annotations.js +546 -0
- package/dist/src/frontend/boot.js +90 -0
- package/dist/src/frontend/config.js +19 -0
- package/dist/src/frontend/dark-mode.js +20 -0
- package/dist/src/frontend/diagram/alignment.js +161 -0
- package/dist/src/frontend/diagram/clipboard.js +172 -0
- package/dist/src/frontend/diagram/constants.js +109 -0
- package/dist/src/frontend/diagram/debug.js +43 -0
- package/dist/src/frontend/diagram/edge-panel.js +260 -0
- package/dist/src/frontend/diagram/edge-rendering.js +12 -0
- package/dist/src/frontend/diagram/grid.js +78 -0
- package/dist/src/frontend/diagram/groups.js +102 -0
- package/dist/src/frontend/diagram/history.js +153 -0
- package/dist/src/frontend/diagram/image-name-modal.js +48 -0
- package/dist/src/frontend/diagram/image-upload.js +36 -0
- package/dist/src/frontend/diagram/label-editor.js +115 -0
- package/dist/src/frontend/diagram/link-panel.js +144 -0
- package/dist/src/frontend/diagram/main.js +299 -0
- package/dist/src/frontend/diagram/network.js +1473 -0
- package/dist/src/frontend/diagram/node-panel.js +267 -0
- package/dist/src/frontend/diagram/node-rendering.js +773 -0
- package/dist/src/frontend/diagram/persistence.js +161 -0
- package/dist/src/frontend/diagram/ports.js +386 -0
- package/dist/src/frontend/diagram/selection-overlay.js +336 -0
- package/dist/src/frontend/diagram/state.js +39 -0
- package/dist/src/frontend/diagram/t.js +3 -0
- package/dist/src/frontend/diagram/toast.js +21 -0
- package/dist/src/frontend/diagram/unlock-hold.js +182 -0
- package/dist/src/frontend/diagram/zoom.js +20 -0
- package/dist/src/frontend/diagram-link-modal.js +137 -0
- package/dist/src/frontend/diagram.html +1279 -0
- package/dist/src/frontend/documents.js +373 -0
- package/dist/src/frontend/export.js +338 -0
- package/dist/src/frontend/i18n/en.json +406 -0
- package/dist/src/frontend/i18n/fr.json +406 -0
- package/dist/src/frontend/i18n.js +32 -0
- package/dist/src/frontend/image-paste.js +101 -0
- package/dist/src/frontend/index.html +2314 -0
- package/dist/src/frontend/misc.js +25 -0
- package/dist/src/frontend/new-doc-modal.js +260 -0
- package/dist/src/frontend/new-folder-modal.js +174 -0
- package/dist/src/frontend/search.js +157 -0
- package/dist/src/frontend/sidebar-helpers.js +58 -0
- package/dist/src/frontend/sidebar.js +182 -0
- package/dist/src/frontend/snippet-detect.js +25 -0
- package/dist/src/frontend/snippet-table.js +85 -0
- package/dist/src/frontend/snippet-tree.js +94 -0
- package/dist/src/frontend/snippets.js +534 -0
- package/dist/src/frontend/state.js +28 -0
- package/dist/src/frontend/utils.js +21 -0
- package/dist/src/frontend/vendor/wordcloud2.js +1187 -0
- package/dist/src/frontend/wordcloud.js +693 -0
- package/dist/src/lib/config.d.ts +17 -0
- package/dist/src/lib/config.d.ts.map +1 -0
- package/dist/src/lib/config.js +79 -0
- package/dist/src/lib/config.js.map +1 -0
- package/dist/src/lib/parser.d.ts +11 -0
- package/dist/src/lib/parser.d.ts.map +1 -0
- package/dist/src/lib/parser.js +111 -0
- package/dist/src/lib/parser.js.map +1 -0
- package/dist/src/mcp/server.d.ts +3 -0
- package/dist/src/mcp/server.d.ts.map +1 -0
- package/dist/src/mcp/server.js +986 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/dist/src/mcp/tools/diagrams.d.ts +44 -0
- package/dist/src/mcp/tools/diagrams.d.ts.map +1 -0
- package/dist/src/mcp/tools/diagrams.js +245 -0
- package/dist/src/mcp/tools/diagrams.js.map +1 -0
- package/dist/src/mcp/tools/documents.d.ts +26 -0
- package/dist/src/mcp/tools/documents.d.ts.map +1 -0
- package/dist/src/mcp/tools/documents.js +127 -0
- package/dist/src/mcp/tools/documents.js.map +1 -0
- package/dist/src/mcp/tools/source.d.ts +29 -0
- package/dist/src/mcp/tools/source.d.ts.map +1 -0
- package/dist/src/mcp/tools/source.js +200 -0
- package/dist/src/mcp/tools/source.js.map +1 -0
- package/dist/src/routes/annotations.d.ts +3 -0
- package/dist/src/routes/annotations.d.ts.map +1 -0
- package/dist/src/routes/annotations.js +83 -0
- package/dist/src/routes/annotations.js.map +1 -0
- package/dist/src/routes/browse.d.ts +3 -0
- package/dist/src/routes/browse.d.ts.map +1 -0
- package/dist/src/routes/browse.js +75 -0
- package/dist/src/routes/browse.js.map +1 -0
- package/dist/src/routes/config.d.ts +3 -0
- package/dist/src/routes/config.d.ts.map +1 -0
- package/dist/src/routes/config.js +97 -0
- package/dist/src/routes/config.js.map +1 -0
- package/dist/src/routes/diagrams.d.ts +3 -0
- package/dist/src/routes/diagrams.d.ts.map +1 -0
- package/dist/src/routes/diagrams.js +69 -0
- package/dist/src/routes/diagrams.js.map +1 -0
- package/dist/src/routes/documents.d.ts +8 -0
- package/dist/src/routes/documents.d.ts.map +1 -0
- package/dist/src/routes/documents.js +332 -0
- package/dist/src/routes/documents.js.map +1 -0
- package/dist/src/routes/export.d.ts +3 -0
- package/dist/src/routes/export.d.ts.map +1 -0
- package/dist/src/routes/export.js +277 -0
- package/dist/src/routes/export.js.map +1 -0
- package/dist/src/routes/images.d.ts +3 -0
- package/dist/src/routes/images.d.ts.map +1 -0
- package/dist/src/routes/images.js +49 -0
- package/dist/src/routes/images.js.map +1 -0
- package/dist/src/routes/wordcloud.d.ts +3 -0
- package/dist/src/routes/wordcloud.d.ts.map +1 -0
- package/dist/src/routes/wordcloud.js +95 -0
- package/dist/src/routes/wordcloud.js.map +1 -0
- package/dist/src/server.d.ts +7 -0
- package/dist/src/server.d.ts.map +1 -0
- package/dist/src/server.js +76 -0
- package/dist/src/server.js.map +1 -0
- package/dist/starting-doc/.annotations.json +3 -0
- package/dist/starting-doc/.diagrams.json +1884 -0
- package/dist/starting-doc/.living-doc.json +39 -0
- package/dist/starting-doc/1_tutorial/2026_04_11_13_25_[General]_crer_vos_dossiers.md +16 -0
- package/dist/starting-doc/1_tutorial/2026_04_11_18_58_[General]_creer_un_document_dans_un_dossier.md +9 -0
- package/dist/starting-doc/1_tutorial/2026_04_12_09_00_[General]_editer_et_sauvegarder.md +39 -0
- package/dist/starting-doc/1_tutorial/2026_04_12_10_00_[General]_utiliser_les_snippets.md +71 -0
- package/dist/starting-doc/2026_04_08_20_52_[General]_welcome.md +17 -0
- package/dist/starting-doc/2026_04_11_12_55_[General]_premiers_pas.md +271 -0
- package/dist/starting-doc/2_guide/2026_04_08_00_04_[DOCUMENT]_utilisation_des_images_plein_ecran_lien_clickable.md +40 -0
- package/dist/starting-doc/2_guide/2026_04_08_23_38_[Configuration]_demarrage_de_living_documentation.md +32 -0
- package/dist/starting-doc/2_guide/2026_04_09_09_00_[NAVIGATION]_recherche_plein_texte.md +65 -0
- package/dist/starting-doc/2_guide/2026_04_09_10_00_[EXPORT]_exporter_en_pdf.md +43 -0
- package/dist/starting-doc/2_guide/2026_04_09_11_00_[Configuration]_configurer_le_panneau_admin.md +55 -0
- package/dist/starting-doc/2_guide/2026_04_09_12_00_[Configuration]_extra_files.md +68 -0
- package/dist/starting-doc/2_guide/2026_04_09_13_00_[WORDCLOUD]_word_cloud.md +54 -0
- package/dist/starting-doc/2_guide/2026_04_09_14_00_[DIAGRAM]_creer_et_lier_un_diagramme.md +77 -0
- package/dist/starting-doc/3_concept/2026_04_08_20_58_[DOCUMENTING]_ADRS.md +20 -0
- package/dist/starting-doc/3_concept/2026_04_08_22_15_[DOCUMENTING]_living_documentation.md +17 -0
- package/dist/starting-doc/3_concept/2026_04_08_22_46_[METHODOLOGY]_diataxis_architecture_du_contenu.md +16 -0
- package/dist/starting-doc/4_reference/2026_04_08_23_14_[FUNDAMENTALS]_the_living_documentation_tool.md +41 -0
- package/dist/starting-doc/4_reference/2026_04_09_01_00_[REFERENCE]_raccourcis_clavier.md +61 -0
- package/dist/starting-doc/4_reference/2026_04_09_02_00_[REFERENCE]_tokens_pattern_nommage.md +75 -0
- package/dist/starting-doc/4_reference/2026_04_09_03_00_[REFERENCE]_types_de_snippets.md +68 -0
- package/dist/starting-doc/4_reference/2026_04_11_17_31_[FUNDAMENTALS]_architecturer_une_documentation.md +12 -0
- package/dist/starting-doc/4_reference/2026_04_12_14_07_[FUNDAMENTALS]_dossiers_et_catgories.md +89 -0
- package/dist/starting-doc/images/admin_screenshot.png +0 -0
- package/dist/starting-doc/images/ajout-document.png +0 -0
- package/dist/starting-doc/images/ajouter-document-categorie.png +0 -0
- package/dist/starting-doc/images/ajouter_un_document_dans_un_dossier.png +0 -0
- package/dist/starting-doc/images/architecturer_une_documentation_reference.png +0 -0
- package/dist/starting-doc/images/cr_er_un_document.png +0 -0
- package/dist/starting-doc/images/creation-nouveau-dossier.png +0 -0
- package/dist/starting-doc/images/creer-document-context-engineering.png +0 -0
- package/dist/starting-doc/images/creer-dossier-only-tutoriel.png +0 -0
- package/dist/starting-doc/images/creer-dossier-tutoriel.png +0 -0
- package/dist/starting-doc/images/creer-dossiers-done.png +0 -0
- package/dist/starting-doc/images/creer-un-document.png +0 -0
- package/dist/starting-doc/images/creer-vos-dossiers-tutoriel.png +0 -0
- package/dist/starting-doc/images/creer-vos-dossiers.png +0 -0
- package/dist/starting-doc/images/decouverte_adrs.png +0 -0
- package/dist/starting-doc/images/diataxis.png +0 -0
- package/dist/starting-doc/images/diataxis_callout.png +0 -0
- package/dist/starting-doc/images/document-cree.png +0 -0
- package/dist/starting-doc/images/liens_snippets.png +0 -0
- package/dist/starting-doc/images/living_documentation.png +0 -0
- package/dist/starting-doc/images/npm_logo.png +0 -0
- package/dist/starting-doc/images/popup-creer-document.png +0 -0
- package/dist/starting-doc/images/popup-creer-dossier.png +0 -0
- package/dist/starting-doc/images/popup-dossier-cree.png +0 -0
- package/dist/starting-doc/images/quatre-dossiers-crees.png +0 -0
- package/dist/starting-doc/images/screenshot-living-doc.png +0 -0
- package/dist/starting-doc/images/the_living_documentation_tool.png +0 -0
- package/package.json +49 -0
|
@@ -0,0 +1,2314 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en" class="h-full">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Living Documentation</title>
|
|
7
|
+
|
|
8
|
+
<!-- i18n -->
|
|
9
|
+
<script src="/i18n.js"></script>
|
|
10
|
+
|
|
11
|
+
<!-- Tailwind CSS + Typography plugin via CDN -->
|
|
12
|
+
<script src="https://cdn.tailwindcss.com?plugins=typography"></script>
|
|
13
|
+
|
|
14
|
+
<!-- Highlight.js — syntax highlighting (always dark) -->
|
|
15
|
+
<link
|
|
16
|
+
rel="stylesheet"
|
|
17
|
+
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css"
|
|
18
|
+
/>
|
|
19
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
|
|
20
|
+
|
|
21
|
+
<!-- Font Awesome — icons -->
|
|
22
|
+
<link
|
|
23
|
+
rel="stylesheet"
|
|
24
|
+
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css"
|
|
25
|
+
/>
|
|
26
|
+
|
|
27
|
+
<!-- WordCloud2.js — vendored from npm, no CDN dependency -->
|
|
28
|
+
<script src="/vendor/wordcloud2.js"></script>
|
|
29
|
+
<!-- Word Cloud logic — stop words, browser, rendering -->
|
|
30
|
+
<script src="/wordcloud.js"></script>
|
|
31
|
+
|
|
32
|
+
<!-- Extracted modules (classic scripts, global symbols).
|
|
33
|
+
Use `defer` so they execute in order AFTER the DOM is parsed. -->
|
|
34
|
+
<script defer src="/utils.js"></script>
|
|
35
|
+
<script defer src="/state.js"></script>
|
|
36
|
+
<script defer src="/sidebar-helpers.js"></script>
|
|
37
|
+
<script defer src="/snippet-detect.js"></script>
|
|
38
|
+
<script defer src="/snippet-table.js"></script>
|
|
39
|
+
<script defer src="/snippet-tree.js"></script>
|
|
40
|
+
<script defer src="/dark-mode.js"></script>
|
|
41
|
+
<script defer src="/config.js"></script>
|
|
42
|
+
<script defer src="/sidebar.js"></script>
|
|
43
|
+
<script defer src="/search.js"></script>
|
|
44
|
+
<script defer src="/image-paste.js"></script>
|
|
45
|
+
<script defer src="/documents.js"></script>
|
|
46
|
+
<script defer src="/misc.js"></script>
|
|
47
|
+
<script defer src="/snippets.js"></script>
|
|
48
|
+
<script defer src="/annotations.js"></script>
|
|
49
|
+
<script defer src="/export.js"></script>
|
|
50
|
+
<script defer src="/diagram-link-modal.js"></script>
|
|
51
|
+
<script defer src="/new-folder-modal.js"></script>
|
|
52
|
+
<script defer src="/new-doc-modal.js"></script>
|
|
53
|
+
<script defer src="/boot.js"></script>
|
|
54
|
+
|
|
55
|
+
<script>
|
|
56
|
+
tailwind.config = {
|
|
57
|
+
darkMode: "class",
|
|
58
|
+
theme: { extend: {} },
|
|
59
|
+
};
|
|
60
|
+
</script>
|
|
61
|
+
|
|
62
|
+
<style>
|
|
63
|
+
/* Smooth sidebar transitions */
|
|
64
|
+
.category-docs {
|
|
65
|
+
transition:
|
|
66
|
+
max-height 0.2s ease,
|
|
67
|
+
opacity 0.2s ease;
|
|
68
|
+
}
|
|
69
|
+
.category-docs.collapsed {
|
|
70
|
+
max-height: 0;
|
|
71
|
+
opacity: 0;
|
|
72
|
+
overflow: hidden;
|
|
73
|
+
}
|
|
74
|
+
.category-docs.expanded {
|
|
75
|
+
max-height: 9999px;
|
|
76
|
+
opacity: 1;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/* Color swatch selection ring */
|
|
80
|
+
.color-swatch-btn.selected-swatch,
|
|
81
|
+
.color-text-swatch-btn.selected-text-swatch {
|
|
82
|
+
outline: 2px solid currentColor;
|
|
83
|
+
outline-offset: 2px;
|
|
84
|
+
box-shadow: 0 0 0 3px rgba(0,0,0,0.15);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/* Active doc highlight */
|
|
88
|
+
.doc-item.active {
|
|
89
|
+
background-color: rgba(59, 130, 246, 0.12);
|
|
90
|
+
color: rgb(59, 130, 246);
|
|
91
|
+
font-weight: 600;
|
|
92
|
+
}
|
|
93
|
+
.dark .doc-item.active {
|
|
94
|
+
background-color: rgba(96, 165, 250, 0.15);
|
|
95
|
+
color: rgb(96, 165, 250);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/* Prose overrides for correct dark mode */
|
|
99
|
+
.dark .prose {
|
|
100
|
+
color: #d1d5db;
|
|
101
|
+
}
|
|
102
|
+
.dark .prose h1,
|
|
103
|
+
.dark .prose h2,
|
|
104
|
+
.dark .prose h3,
|
|
105
|
+
.dark .prose h4,
|
|
106
|
+
.dark .prose h5,
|
|
107
|
+
.dark .prose h6 {
|
|
108
|
+
color: #f9fafb;
|
|
109
|
+
}
|
|
110
|
+
.dark .prose a {
|
|
111
|
+
color: #60a5fa;
|
|
112
|
+
}
|
|
113
|
+
.dark .prose strong {
|
|
114
|
+
color: #f3f4f6;
|
|
115
|
+
}
|
|
116
|
+
.prose code:not(pre code) {
|
|
117
|
+
background: #e5e7eb;
|
|
118
|
+
color: #111827;
|
|
119
|
+
padding: 0.1em 0.35em;
|
|
120
|
+
border-radius: 0.25em;
|
|
121
|
+
font-size: 0.875em;
|
|
122
|
+
font-weight: 400;
|
|
123
|
+
}
|
|
124
|
+
.dark .prose code:not(pre code) {
|
|
125
|
+
background: #4b5563;
|
|
126
|
+
color: #f87171;
|
|
127
|
+
padding: 0.1em 0.35em;
|
|
128
|
+
border-radius: 0.25em;
|
|
129
|
+
font-size: 0.875em;
|
|
130
|
+
font-weight: 400;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.dark .prose blockquote {
|
|
134
|
+
border-color: #4b5563;
|
|
135
|
+
color: #9ca3af;
|
|
136
|
+
}
|
|
137
|
+
.dark .prose hr {
|
|
138
|
+
border-color: #374151;
|
|
139
|
+
}
|
|
140
|
+
.dark .prose table th {
|
|
141
|
+
background: #1f2937;
|
|
142
|
+
color: #f9fafb;
|
|
143
|
+
}
|
|
144
|
+
.dark .prose table td {
|
|
145
|
+
border-color: #374151;
|
|
146
|
+
}
|
|
147
|
+
.dark .prose table tr:nth-child(even) {
|
|
148
|
+
background: #111827;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/* Print / Export PDF */
|
|
152
|
+
@media print {
|
|
153
|
+
#sidebar,
|
|
154
|
+
#header {
|
|
155
|
+
display: none !important;
|
|
156
|
+
}
|
|
157
|
+
#content-area {
|
|
158
|
+
margin: 0 !important;
|
|
159
|
+
}
|
|
160
|
+
.no-print {
|
|
161
|
+
display: none !important;
|
|
162
|
+
}
|
|
163
|
+
.prose {
|
|
164
|
+
max-width: 100% !important;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/* Scrollbar thin */
|
|
169
|
+
::-webkit-scrollbar {
|
|
170
|
+
width: 6px;
|
|
171
|
+
height: 6px;
|
|
172
|
+
}
|
|
173
|
+
::-webkit-scrollbar-track {
|
|
174
|
+
background: transparent;
|
|
175
|
+
}
|
|
176
|
+
::-webkit-scrollbar-thumb {
|
|
177
|
+
background: #d1d5db;
|
|
178
|
+
border-radius: 3px;
|
|
179
|
+
}
|
|
180
|
+
.dark ::-webkit-scrollbar-thumb {
|
|
181
|
+
background: #4b5563;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/* Search highlight */
|
|
185
|
+
mark {
|
|
186
|
+
background: #fef08a;
|
|
187
|
+
color: inherit;
|
|
188
|
+
border-radius: 2px;
|
|
189
|
+
padding: 0 2px;
|
|
190
|
+
}
|
|
191
|
+
mark.match-active {
|
|
192
|
+
background: #f97316;
|
|
193
|
+
color: #fff;
|
|
194
|
+
}
|
|
195
|
+
.dark mark {
|
|
196
|
+
background: #713f12;
|
|
197
|
+
color: #fef9c3;
|
|
198
|
+
}
|
|
199
|
+
.dark mark.match-active {
|
|
200
|
+
background: #ea580c;
|
|
201
|
+
color: #fff;
|
|
202
|
+
}
|
|
203
|
+
</style>
|
|
204
|
+
</head>
|
|
205
|
+
|
|
206
|
+
<body
|
|
207
|
+
class="h-full bg-gray-50 dark:bg-gray-950 text-gray-900 dark:text-gray-100 transition-colors duration-200"
|
|
208
|
+
>
|
|
209
|
+
<div class="h-full flex flex-col">
|
|
210
|
+
<!-- ── Header ── -->
|
|
211
|
+
<header
|
|
212
|
+
id="header"
|
|
213
|
+
class="no-print flex items-center justify-between px-4 h-14 border-b border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 shrink-0 z-10 shadow-sm"
|
|
214
|
+
>
|
|
215
|
+
<div class="flex items-center gap-3">
|
|
216
|
+
<span
|
|
217
|
+
onclick="toggleSidebar()"
|
|
218
|
+
data-i18n-title="nav.toggle_sidebar"
|
|
219
|
+
title="Toggle sidebar"
|
|
220
|
+
class="text-blue-600 dark:text-blue-400 text-xl select-none cursor-pointer hover:opacity-70 transition-opacity"
|
|
221
|
+
>📚</span
|
|
222
|
+
>
|
|
223
|
+
<span id="app-title" class="font-semibold text-base tracking-tight"
|
|
224
|
+
>Living Documentation</span
|
|
225
|
+
>
|
|
226
|
+
</div>
|
|
227
|
+
|
|
228
|
+
<div class="flex items-center gap-2">
|
|
229
|
+
<!-- Search (desktop — mirrors sidebar search) -->
|
|
230
|
+
<div class="relative hidden sm:block">
|
|
231
|
+
<input
|
|
232
|
+
id="header-search"
|
|
233
|
+
type="search"
|
|
234
|
+
data-i18n-placeholder="nav.search_placeholder"
|
|
235
|
+
placeholder="Search docs…"
|
|
236
|
+
class="w-56 pl-8 pr-3 py-1.5 text-sm rounded-lg border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 placeholder:text-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
237
|
+
/>
|
|
238
|
+
<span
|
|
239
|
+
class="absolute left-2.5 top-2 text-gray-400 text-sm pointer-events-none"
|
|
240
|
+
>🔍</span
|
|
241
|
+
>
|
|
242
|
+
</div>
|
|
243
|
+
|
|
244
|
+
<!-- Dark mode toggle -->
|
|
245
|
+
<button
|
|
246
|
+
id="dark-toggle"
|
|
247
|
+
data-i18n-title="nav.toggle_dark"
|
|
248
|
+
title="Toggle dark mode"
|
|
249
|
+
class="p-2 rounded-lg text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
|
|
250
|
+
>
|
|
251
|
+
<span id="dark-icon" class="text-lg leading-none">☾</span>
|
|
252
|
+
</button>
|
|
253
|
+
|
|
254
|
+
<!-- Word Cloud -->
|
|
255
|
+
<button
|
|
256
|
+
onclick="openWordCloud()"
|
|
257
|
+
data-i18n="nav.word_cloud"
|
|
258
|
+
class="text-sm px-3 py-1.5 rounded-lg text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors font-medium"
|
|
259
|
+
>
|
|
260
|
+
☁ Word Cloud
|
|
261
|
+
</button>
|
|
262
|
+
|
|
263
|
+
<!-- Diagram link -->
|
|
264
|
+
<a
|
|
265
|
+
href="/diagram"
|
|
266
|
+
data-i18n="nav.diagram"
|
|
267
|
+
class="text-sm px-3 py-1.5 rounded-lg text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors font-medium"
|
|
268
|
+
>
|
|
269
|
+
◇ Diagram
|
|
270
|
+
</a>
|
|
271
|
+
|
|
272
|
+
<!-- Admin link -->
|
|
273
|
+
<a
|
|
274
|
+
href="/admin"
|
|
275
|
+
data-i18n="nav.admin"
|
|
276
|
+
class="text-sm px-3 py-1.5 rounded-lg text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors font-medium"
|
|
277
|
+
>
|
|
278
|
+
⚙ Admin
|
|
279
|
+
</a>
|
|
280
|
+
</div>
|
|
281
|
+
</header>
|
|
282
|
+
|
|
283
|
+
<!-- ── Body ── -->
|
|
284
|
+
<div class="flex flex-1 overflow-hidden">
|
|
285
|
+
<!-- ── Sidebar ── -->
|
|
286
|
+
<aside
|
|
287
|
+
id="sidebar"
|
|
288
|
+
class="no-print w-72 shrink-0 flex flex-col border-r border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 overflow-y-auto"
|
|
289
|
+
>
|
|
290
|
+
<!-- Mobile / sidebar search -->
|
|
291
|
+
<div class="p-3 border-b border-gray-100 dark:border-gray-800">
|
|
292
|
+
<div class="relative sm:hidden">
|
|
293
|
+
<input
|
|
294
|
+
id="sidebar-search"
|
|
295
|
+
type="search"
|
|
296
|
+
data-i18n-placeholder="nav.search_mobile_placeholder"
|
|
297
|
+
placeholder="Search…"
|
|
298
|
+
class="w-full pl-8 pr-3 py-1.5 text-sm rounded-lg border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 placeholder:text-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
299
|
+
/>
|
|
300
|
+
<span
|
|
301
|
+
class="absolute left-2.5 top-2 text-gray-400 text-sm pointer-events-none"
|
|
302
|
+
>🔍</span
|
|
303
|
+
>
|
|
304
|
+
</div>
|
|
305
|
+
|
|
306
|
+
<!-- Stats -->
|
|
307
|
+
<div class="flex items-center justify-between mt-2 sm:mt-0">
|
|
308
|
+
<p
|
|
309
|
+
id="doc-count"
|
|
310
|
+
class="text-xs text-gray-400 dark:text-gray-500"
|
|
311
|
+
></p>
|
|
312
|
+
<div class="flex items-center gap-2">
|
|
313
|
+
<button
|
|
314
|
+
onclick="openExportModal()"
|
|
315
|
+
data-i18n-title="nav.export"
|
|
316
|
+
title="Export"
|
|
317
|
+
class="text-gray-400 hover:text-blue-500 dark:text-gray-500 dark:hover:text-blue-400 transition-colors leading-none"
|
|
318
|
+
>
|
|
319
|
+
<i class="fa-solid fa-file-export"></i>
|
|
320
|
+
</button>
|
|
321
|
+
<button
|
|
322
|
+
onclick="openNewFolderModal()"
|
|
323
|
+
data-i18n-title="nav.new_folder"
|
|
324
|
+
title="New folder"
|
|
325
|
+
class="text-gray-400 hover:text-blue-500 dark:text-gray-500 dark:hover:text-blue-400 transition-colors leading-none"
|
|
326
|
+
>
|
|
327
|
+
<i class="fa-solid fa-folder-plus"></i>
|
|
328
|
+
</button>
|
|
329
|
+
<button
|
|
330
|
+
onclick="openNewDocModal()"
|
|
331
|
+
data-i18n-title="nav.new_document"
|
|
332
|
+
title="New document"
|
|
333
|
+
class="text-gray-400 hover:text-blue-500 dark:text-gray-500 dark:hover:text-blue-400 transition-colors leading-none"
|
|
334
|
+
>
|
|
335
|
+
<i class="fa-solid fa-file-circle-plus"></i>
|
|
336
|
+
</button>
|
|
337
|
+
</div>
|
|
338
|
+
</div>
|
|
339
|
+
</div>
|
|
340
|
+
|
|
341
|
+
<!-- Category tree -->
|
|
342
|
+
<nav id="category-tree" class="flex-1 py-2 space-y-0.5">
|
|
343
|
+
<p class="px-4 py-8 text-sm text-gray-400 text-center" data-i18n="common.loading">Loading…</p>
|
|
344
|
+
</nav>
|
|
345
|
+
</aside>
|
|
346
|
+
|
|
347
|
+
<!-- ── Main content ── -->
|
|
348
|
+
<main id="content-area" class="flex-1 overflow-y-auto">
|
|
349
|
+
<!-- Welcome / empty state -->
|
|
350
|
+
<div id="welcome" class="h-full flex items-center justify-center p-8">
|
|
351
|
+
<div class="max-w-md text-center">
|
|
352
|
+
<div class="text-5xl mb-4 select-none" aria-hidden="true">
|
|
353
|
+
📚
|
|
354
|
+
</div>
|
|
355
|
+
<h2
|
|
356
|
+
data-i18n="welcome.title"
|
|
357
|
+
class="text-xl font-semibold text-gray-700 dark:text-gray-300 mb-2"
|
|
358
|
+
>
|
|
359
|
+
Select a document
|
|
360
|
+
</h2>
|
|
361
|
+
<p data-i18n="welcome.hint" class="text-sm text-gray-500 dark:text-gray-500">
|
|
362
|
+
Choose a document from the sidebar to start reading.
|
|
363
|
+
</p>
|
|
364
|
+
<p
|
|
365
|
+
id="welcome-pattern"
|
|
366
|
+
class="mt-4 text-xs text-gray-400 dark:text-gray-600 font-mono bg-gray-100 dark:bg-gray-800 rounded-lg px-3 py-2 inline-block"
|
|
367
|
+
>
|
|
368
|
+
YYYY_MM_DD_HH_mm_[Category]_title.md
|
|
369
|
+
</p>
|
|
370
|
+
<p data-i18n="welcome.pattern_hint" class="mt-2 text-xs text-gray-400">
|
|
371
|
+
Expected filename pattern
|
|
372
|
+
</p>
|
|
373
|
+
</div>
|
|
374
|
+
</div>
|
|
375
|
+
|
|
376
|
+
<!-- Document viewer -->
|
|
377
|
+
<article id="doc-view" class="hidden max-w-4xl mx-auto px-6 py-8">
|
|
378
|
+
<!-- Doc header -->
|
|
379
|
+
<header
|
|
380
|
+
class="sticky top-0 z-10 bg-gray-50 dark:bg-gray-950 -mx-6 px-6 pt-8 mb-8 pb-6 border-b border-gray-300 dark:border-gray-800"
|
|
381
|
+
>
|
|
382
|
+
<div class="flex items-start gap-4 flex-wrap">
|
|
383
|
+
<div class="shrink min-w-0">
|
|
384
|
+
<div class="flex items-center gap-2 mb-2 flex-wrap">
|
|
385
|
+
<span
|
|
386
|
+
id="doc-breadcrumbs"
|
|
387
|
+
class="flex items-center gap-2 flex-wrap"
|
|
388
|
+
></span>
|
|
389
|
+
<span
|
|
390
|
+
id="doc-date"
|
|
391
|
+
class="text-xs text-gray-400 dark:text-gray-500"
|
|
392
|
+
></span>
|
|
393
|
+
</div>
|
|
394
|
+
<h1
|
|
395
|
+
id="doc-title"
|
|
396
|
+
class="text-2xl font-bold text-gray-900 dark:text-gray-50 leading-tight"
|
|
397
|
+
></h1>
|
|
398
|
+
</div>
|
|
399
|
+
<!-- Actions -->
|
|
400
|
+
<div class="flex items-center gap-2 flex-wrap ml-auto">
|
|
401
|
+
<!-- View mode actions -->
|
|
402
|
+
<div id="view-actions" class="flex items-center gap-2">
|
|
403
|
+
<button
|
|
404
|
+
onclick="toggleMarker()"
|
|
405
|
+
id="stabilo-btn"
|
|
406
|
+
data-i18n-title="doc.marker_mode"
|
|
407
|
+
title="Mode Marker — surligner pour annoter"
|
|
408
|
+
class="no-print text-sm px-3 py-1.5 rounded-lg border border-gray-200 dark:border-gray-700 text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
|
|
409
|
+
>
|
|
410
|
+
<svg
|
|
411
|
+
id="stabilo-icon"
|
|
412
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
413
|
+
width="18"
|
|
414
|
+
height="18"
|
|
415
|
+
viewBox="0 0 100 100"
|
|
416
|
+
fill="none"
|
|
417
|
+
style="
|
|
418
|
+
display: inline-block;
|
|
419
|
+
vertical-align: middle;
|
|
420
|
+
margin-right: 4px;
|
|
421
|
+
"
|
|
422
|
+
>
|
|
423
|
+
<!-- body -->
|
|
424
|
+
<rect
|
|
425
|
+
x="28"
|
|
426
|
+
y="10"
|
|
427
|
+
width="44"
|
|
428
|
+
height="52"
|
|
429
|
+
rx="6"
|
|
430
|
+
transform="rotate(40 50 50)"
|
|
431
|
+
fill="#bfdbfe"
|
|
432
|
+
stroke="currentColor"
|
|
433
|
+
stroke-width="6"
|
|
434
|
+
/>
|
|
435
|
+
<!-- cap -->
|
|
436
|
+
<rect
|
|
437
|
+
x="52"
|
|
438
|
+
y="8"
|
|
439
|
+
width="22"
|
|
440
|
+
height="30"
|
|
441
|
+
rx="6"
|
|
442
|
+
transform="rotate(40 50 50)"
|
|
443
|
+
fill="#93c5fd"
|
|
444
|
+
stroke="currentColor"
|
|
445
|
+
stroke-width="6"
|
|
446
|
+
/>
|
|
447
|
+
<!-- nib -->
|
|
448
|
+
<polygon
|
|
449
|
+
points="28,60 10,80 30,80 38,72"
|
|
450
|
+
fill="#93c5fd"
|
|
451
|
+
stroke="currentColor"
|
|
452
|
+
stroke-width="5"
|
|
453
|
+
stroke-linejoin="round"
|
|
454
|
+
/>
|
|
455
|
+
<polygon
|
|
456
|
+
points="28,48 19,70 36,75 55,70"
|
|
457
|
+
fill="#93c5fd"
|
|
458
|
+
stroke="currentColor"
|
|
459
|
+
stroke-width="5"
|
|
460
|
+
stroke-linejoin="round"
|
|
461
|
+
/>
|
|
462
|
+
<!-- underline stroke -->
|
|
463
|
+
<line
|
|
464
|
+
x1="10"
|
|
465
|
+
y1="90"
|
|
466
|
+
x2="72"
|
|
467
|
+
y2="90"
|
|
468
|
+
stroke="currentColor"
|
|
469
|
+
stroke-width="6"
|
|
470
|
+
stroke-linecap="round"
|
|
471
|
+
/>
|
|
472
|
+
<!-- hidden cross (two diagonal bars) -->
|
|
473
|
+
<g id="stabilo-cross" style="display: none">
|
|
474
|
+
<line
|
|
475
|
+
x1="8"
|
|
476
|
+
y1="8"
|
|
477
|
+
x2="92"
|
|
478
|
+
y2="92"
|
|
479
|
+
stroke="currentColor"
|
|
480
|
+
stroke-width="8"
|
|
481
|
+
stroke-linecap="round"
|
|
482
|
+
/>
|
|
483
|
+
<line
|
|
484
|
+
x1="92"
|
|
485
|
+
y1="8"
|
|
486
|
+
x2="8"
|
|
487
|
+
y2="92"
|
|
488
|
+
stroke="currentColor"
|
|
489
|
+
stroke-width="8"
|
|
490
|
+
stroke-linecap="round"
|
|
491
|
+
/>
|
|
492
|
+
</g></svg
|
|
493
|
+
><span data-i18n="doc.marker_btn">Marker</span>
|
|
494
|
+
</button>
|
|
495
|
+
<button
|
|
496
|
+
onclick="toggleFullWidth()"
|
|
497
|
+
id="full-width-btn"
|
|
498
|
+
data-i18n-title="doc.toggle_width"
|
|
499
|
+
title="Toggle full width"
|
|
500
|
+
class="no-print text-sm px-3 py-1.5 rounded-lg border border-gray-200 dark:border-gray-700 text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
|
|
501
|
+
>
|
|
502
|
+
<span data-i18n="doc.full_width_btn">↔ Full width</span>
|
|
503
|
+
</button>
|
|
504
|
+
<button
|
|
505
|
+
onclick="exportPDF()"
|
|
506
|
+
data-i18n-title="doc.export_pdf"
|
|
507
|
+
title="Export as PDF"
|
|
508
|
+
class="no-print text-sm px-3 py-1.5 rounded-lg border border-gray-200 dark:border-gray-700 text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
|
|
509
|
+
>
|
|
510
|
+
📄 <span data-i18n="doc.export_pdf_btn">Export PDF</span>
|
|
511
|
+
</button>
|
|
512
|
+
<button
|
|
513
|
+
onclick="copyLink()"
|
|
514
|
+
id="copy-link-btn"
|
|
515
|
+
data-i18n-title="doc.copy_link"
|
|
516
|
+
title="Copy link"
|
|
517
|
+
class="no-print text-sm px-3 py-1.5 rounded-lg border border-gray-200 dark:border-gray-700 text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
|
|
518
|
+
>
|
|
519
|
+
<i class="fa-solid fa-link"></i> <span data-i18n="doc.copy_link_btn">Copy link</span>
|
|
520
|
+
</button>
|
|
521
|
+
<button
|
|
522
|
+
onclick="enterEditMode()"
|
|
523
|
+
data-i18n-title="doc.edit"
|
|
524
|
+
title="Edit document"
|
|
525
|
+
class="no-print text-sm px-3 py-1.5 rounded-lg border border-gray-200 dark:border-gray-700 text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
|
|
526
|
+
>
|
|
527
|
+
<i class="fa-solid fa-file-pen"></i> <span data-i18n="doc.edit_btn">Edit</span>
|
|
528
|
+
</button>
|
|
529
|
+
<button
|
|
530
|
+
onclick="askDeleteDocument()"
|
|
531
|
+
data-i18n-title="doc.delete"
|
|
532
|
+
title="Delete document"
|
|
533
|
+
class="no-print text-sm px-3 py-1.5 rounded-lg border border-red-200 dark:border-red-700 text-red-500 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/40 transition-colors"
|
|
534
|
+
>
|
|
535
|
+
<i class="fa-solid fa-trash"></i> <span data-i18n="doc.delete_btn">Delete</span>
|
|
536
|
+
</button>
|
|
537
|
+
</div>
|
|
538
|
+
<!-- Edit mode actions -->
|
|
539
|
+
<div id="edit-actions" class="hidden flex items-center gap-2">
|
|
540
|
+
<span id="edit-save-msg" class="text-xs"></span>
|
|
541
|
+
<button
|
|
542
|
+
onclick="exitEditMode()"
|
|
543
|
+
data-i18n-title="doc.cancel_edit"
|
|
544
|
+
title="Cancel editing"
|
|
545
|
+
class="text-sm px-3 py-1.5 rounded-lg border border-gray-200 dark:border-gray-700 text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
|
|
546
|
+
>
|
|
547
|
+
<span data-i18n="common.cancel">Cancel</span>
|
|
548
|
+
</button>
|
|
549
|
+
<button
|
|
550
|
+
onclick="openSnippetsModal()"
|
|
551
|
+
data-i18n-title="doc.snippets"
|
|
552
|
+
title="Insert a snippet"
|
|
553
|
+
class="text-sm px-3 py-1.5 rounded-lg border border-gray-200 dark:border-gray-700 text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
|
|
554
|
+
>
|
|
555
|
+
<span data-i18n="doc.snippets_btn">🧩 Snippets</span>
|
|
556
|
+
</button>
|
|
557
|
+
<button
|
|
558
|
+
onclick="saveDocument()"
|
|
559
|
+
data-i18n-title="doc.save"
|
|
560
|
+
title="Save document"
|
|
561
|
+
class="text-sm px-4 py-1.5 rounded-lg bg-blue-600 hover:bg-blue-700 text-white font-semibold transition-colors"
|
|
562
|
+
>
|
|
563
|
+
<span data-i18n="common.save">Save</span>
|
|
564
|
+
</button>
|
|
565
|
+
</div>
|
|
566
|
+
</div>
|
|
567
|
+
</div>
|
|
568
|
+
<!-- Navigation history back-links -->
|
|
569
|
+
<div
|
|
570
|
+
id="doc-back"
|
|
571
|
+
class="hidden mt-2 flex flex-wrap gap-1 text-xs"
|
|
572
|
+
></div>
|
|
573
|
+
<!-- Search match notice (inside sticky header) -->
|
|
574
|
+
<div
|
|
575
|
+
id="search-notice"
|
|
576
|
+
class="hidden mt-4 rounded-lg bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 text-sm text-yellow-800 dark:text-yellow-300 overflow-hidden"
|
|
577
|
+
>
|
|
578
|
+
<div
|
|
579
|
+
id="search-notice-title"
|
|
580
|
+
class="px-3 py-2 font-medium border-b border-yellow-200 dark:border-yellow-800"
|
|
581
|
+
></div>
|
|
582
|
+
<ol
|
|
583
|
+
id="search-notice-list"
|
|
584
|
+
class="max-h-40 overflow-y-auto divide-y divide-yellow-100 dark:divide-yellow-900/40 list-none m-0 p-0"
|
|
585
|
+
></ol>
|
|
586
|
+
</div>
|
|
587
|
+
</header>
|
|
588
|
+
|
|
589
|
+
<!-- Rendered markdown -->
|
|
590
|
+
<div
|
|
591
|
+
id="doc-content"
|
|
592
|
+
class="prose prose-gray dark:prose-invert max-w-none prose-headings:scroll-mt-4 prose-a:text-blue-600 dark:prose-a:text-blue-400 prose-code:before:content-none prose-code:after:content-none prose-pre:bg-[#0d1117] prose-pre:border prose-pre:border-gray-700"
|
|
593
|
+
></div>
|
|
594
|
+
|
|
595
|
+
<!-- Markdown editor -->
|
|
596
|
+
<textarea
|
|
597
|
+
id="doc-editor"
|
|
598
|
+
class="hidden w-full min-h-[70vh] px-4 py-3 text-sm font-mono leading-relaxed rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-900 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500 resize-y"
|
|
599
|
+
spellcheck="false"
|
|
600
|
+
></textarea>
|
|
601
|
+
</article>
|
|
602
|
+
</main>
|
|
603
|
+
</div>
|
|
604
|
+
<!-- end body row -->
|
|
605
|
+
</div>
|
|
606
|
+
<!-- end root -->
|
|
607
|
+
|
|
608
|
+
<!-- ── New Folder modal ── -->
|
|
609
|
+
<div
|
|
610
|
+
id="new-folder-modal"
|
|
611
|
+
class="hidden fixed inset-0 z-50 flex items-center justify-center bg-black/50"
|
|
612
|
+
>
|
|
613
|
+
<div
|
|
614
|
+
class="bg-white dark:bg-gray-900 rounded-xl shadow-xl w-full max-w-md mx-4 p-6 space-y-4"
|
|
615
|
+
>
|
|
616
|
+
<h3 class="text-base font-semibold text-gray-900 dark:text-gray-50">
|
|
617
|
+
<svg
|
|
618
|
+
width="16"
|
|
619
|
+
height="16"
|
|
620
|
+
viewBox="0 0 20 20"
|
|
621
|
+
fill="none"
|
|
622
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
623
|
+
class="inline-block mr-1 align-text-bottom"
|
|
624
|
+
>
|
|
625
|
+
<path
|
|
626
|
+
d="M2 5a2 2 0 012-2h3.586a1 1 0 01.707.293L9.707 4.707A1 1 0 0010.414 5H16a2 2 0 012 2v8a2 2 0 01-2 2H4a2 2 0 01-2-2V5z"
|
|
627
|
+
stroke="currentColor"
|
|
628
|
+
stroke-width="1.5"
|
|
629
|
+
fill="none"
|
|
630
|
+
/>
|
|
631
|
+
<line
|
|
632
|
+
x1="10"
|
|
633
|
+
y1="8"
|
|
634
|
+
x2="10"
|
|
635
|
+
y2="14"
|
|
636
|
+
stroke="currentColor"
|
|
637
|
+
stroke-width="1.5"
|
|
638
|
+
stroke-linecap="round"
|
|
639
|
+
/>
|
|
640
|
+
<line
|
|
641
|
+
x1="7"
|
|
642
|
+
y1="11"
|
|
643
|
+
x2="13"
|
|
644
|
+
y2="11"
|
|
645
|
+
stroke="currentColor"
|
|
646
|
+
stroke-width="1.5"
|
|
647
|
+
stroke-linecap="round"
|
|
648
|
+
/>
|
|
649
|
+
</svg>
|
|
650
|
+
<span data-i18n="modal.new_folder.title">New Folder</span>
|
|
651
|
+
</h3>
|
|
652
|
+
|
|
653
|
+
<!-- Folder name -->
|
|
654
|
+
<div class="space-y-1.5">
|
|
655
|
+
<label
|
|
656
|
+
data-i18n="modal.new_folder.name_label"
|
|
657
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
658
|
+
>Folder name</label
|
|
659
|
+
>
|
|
660
|
+
<input
|
|
661
|
+
id="new-folder-name"
|
|
662
|
+
type="text"
|
|
663
|
+
data-i18n-placeholder="modal.new_folder.name_placeholder"
|
|
664
|
+
placeholder="my-folder"
|
|
665
|
+
oninput="newFolderUpdatePreview()"
|
|
666
|
+
class="w-full px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
667
|
+
/>
|
|
668
|
+
</div>
|
|
669
|
+
|
|
670
|
+
<!-- Location -->
|
|
671
|
+
<div class="space-y-1.5">
|
|
672
|
+
<label
|
|
673
|
+
data-i18n="modal.new_folder.location_label"
|
|
674
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
675
|
+
>Location</label
|
|
676
|
+
>
|
|
677
|
+
<div class="flex items-center gap-2">
|
|
678
|
+
<span
|
|
679
|
+
id="new-folder-location-display"
|
|
680
|
+
class="flex-1 text-sm text-gray-600 dark:text-gray-300 font-mono truncate"
|
|
681
|
+
>/ (root)</span
|
|
682
|
+
>
|
|
683
|
+
<button
|
|
684
|
+
onclick="newFolderToggleBrowser()"
|
|
685
|
+
data-i18n="modal.new_folder.browse_btn"
|
|
686
|
+
class="text-xs px-2 py-1.5 rounded-lg border border-gray-200 dark:border-gray-700 text-gray-500 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors shrink-0"
|
|
687
|
+
>
|
|
688
|
+
Browse…
|
|
689
|
+
</button>
|
|
690
|
+
</div>
|
|
691
|
+
<!-- Inline browser -->
|
|
692
|
+
<div
|
|
693
|
+
id="new-folder-browser"
|
|
694
|
+
class="hidden border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden text-sm"
|
|
695
|
+
>
|
|
696
|
+
<div
|
|
697
|
+
class="flex items-center gap-2 px-3 py-2 bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700"
|
|
698
|
+
>
|
|
699
|
+
<button
|
|
700
|
+
id="new-folder-browse-up"
|
|
701
|
+
onclick="newFolderBrowseUp()"
|
|
702
|
+
class="text-gray-400 hover:text-gray-600 dark:hover:text-gray-200 disabled:opacity-30"
|
|
703
|
+
>
|
|
704
|
+
↑
|
|
705
|
+
</button>
|
|
706
|
+
<span
|
|
707
|
+
id="new-folder-browse-path"
|
|
708
|
+
class="text-xs text-gray-500 dark:text-gray-400 font-mono truncate flex-1"
|
|
709
|
+
></span>
|
|
710
|
+
<button
|
|
711
|
+
onclick="newFolderSelectCurrentLocation()"
|
|
712
|
+
data-i18n="modal.new_folder.select_btn"
|
|
713
|
+
class="text-xs text-blue-600 dark:text-blue-400 hover:underline shrink-0"
|
|
714
|
+
>
|
|
715
|
+
Select this folder
|
|
716
|
+
</button>
|
|
717
|
+
</div>
|
|
718
|
+
<div
|
|
719
|
+
id="new-folder-browse-list"
|
|
720
|
+
class="max-h-40 overflow-y-auto divide-y divide-gray-100 dark:divide-gray-800"
|
|
721
|
+
></div>
|
|
722
|
+
</div>
|
|
723
|
+
</div>
|
|
724
|
+
|
|
725
|
+
<!-- Preview -->
|
|
726
|
+
<div class="space-y-1">
|
|
727
|
+
<label
|
|
728
|
+
data-i18n="modal.new_folder.will_be_created"
|
|
729
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
730
|
+
>Will be created at</label
|
|
731
|
+
>
|
|
732
|
+
<p
|
|
733
|
+
id="new-folder-preview"
|
|
734
|
+
data-i18n="modal.new_folder.enter_name"
|
|
735
|
+
class="text-xs font-mono text-gray-500 dark:text-gray-400 bg-gray-100 dark:bg-gray-800 rounded-lg px-3 py-2 truncate"
|
|
736
|
+
>
|
|
737
|
+
(enter a name)
|
|
738
|
+
</p>
|
|
739
|
+
</div>
|
|
740
|
+
|
|
741
|
+
<p id="new-folder-error" class="hidden text-xs text-red-500"></p>
|
|
742
|
+
|
|
743
|
+
<div class="flex justify-end gap-3 pt-1">
|
|
744
|
+
<button
|
|
745
|
+
onclick="closeNewFolderModal()"
|
|
746
|
+
data-i18n="common.cancel"
|
|
747
|
+
class="text-sm px-4 py-2 rounded-lg border border-gray-200 dark:border-gray-700 text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
|
|
748
|
+
>
|
|
749
|
+
Cancel
|
|
750
|
+
</button>
|
|
751
|
+
<button
|
|
752
|
+
onclick="createNewFolder()"
|
|
753
|
+
id="new-folder-create-btn"
|
|
754
|
+
data-i18n="modal.new_folder.create_btn"
|
|
755
|
+
class="text-sm px-4 py-2 rounded-lg bg-blue-600 hover:bg-blue-700 text-white font-semibold transition-colors"
|
|
756
|
+
>
|
|
757
|
+
Create
|
|
758
|
+
</button>
|
|
759
|
+
</div>
|
|
760
|
+
</div>
|
|
761
|
+
</div>
|
|
762
|
+
|
|
763
|
+
<!-- ── New Document modal ── -->
|
|
764
|
+
<div
|
|
765
|
+
id="new-doc-modal"
|
|
766
|
+
class="hidden fixed inset-0 z-50 flex items-center justify-center bg-black/50"
|
|
767
|
+
>
|
|
768
|
+
<div
|
|
769
|
+
class="bg-white dark:bg-gray-900 rounded-xl shadow-xl w-full max-w-lg mx-4 p-6 space-y-4"
|
|
770
|
+
>
|
|
771
|
+
<h3 class="text-base font-semibold text-gray-900 dark:text-gray-50">
|
|
772
|
+
➕ <span data-i18n="modal.new_doc.title">New Document</span>
|
|
773
|
+
</h3>
|
|
774
|
+
|
|
775
|
+
<!-- Title -->
|
|
776
|
+
<div class="space-y-1.5">
|
|
777
|
+
<label
|
|
778
|
+
data-i18n="modal.new_doc.title_label"
|
|
779
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
780
|
+
>Title</label
|
|
781
|
+
>
|
|
782
|
+
<input
|
|
783
|
+
id="new-doc-title"
|
|
784
|
+
type="text"
|
|
785
|
+
data-i18n-placeholder="modal.new_doc.title_placeholder"
|
|
786
|
+
placeholder="My document"
|
|
787
|
+
oninput="newDocUpdatePreview()"
|
|
788
|
+
class="w-full px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
789
|
+
/>
|
|
790
|
+
</div>
|
|
791
|
+
|
|
792
|
+
<!-- Category -->
|
|
793
|
+
<div class="space-y-1.5">
|
|
794
|
+
<label
|
|
795
|
+
data-i18n="modal.new_doc.category_label"
|
|
796
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
797
|
+
>Category</label
|
|
798
|
+
>
|
|
799
|
+
<input
|
|
800
|
+
id="new-doc-category"
|
|
801
|
+
type="text"
|
|
802
|
+
placeholder="General"
|
|
803
|
+
oninput="newDocUpdatePreview()"
|
|
804
|
+
class="w-full px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
805
|
+
/>
|
|
806
|
+
</div>
|
|
807
|
+
|
|
808
|
+
<!-- Location -->
|
|
809
|
+
<div class="space-y-1.5">
|
|
810
|
+
<label
|
|
811
|
+
data-i18n="modal.new_doc.location_label"
|
|
812
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
813
|
+
>Location</label
|
|
814
|
+
>
|
|
815
|
+
<div class="flex items-center gap-2">
|
|
816
|
+
<span
|
|
817
|
+
id="new-doc-folder-display"
|
|
818
|
+
class="flex-1 px-3 py-2 text-xs rounded-lg border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800 text-gray-500 dark:text-gray-400 font-mono truncate"
|
|
819
|
+
>
|
|
820
|
+
/ (root)
|
|
821
|
+
</span>
|
|
822
|
+
<button
|
|
823
|
+
onclick="newDocToggleBrowser()"
|
|
824
|
+
class="text-sm px-3 py-1.5 rounded-lg border border-gray-200 dark:border-gray-700 text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors shrink-0"
|
|
825
|
+
>
|
|
826
|
+
📁 <span data-i18n="modal.new_doc.browse_btn">Browse</span>
|
|
827
|
+
</button>
|
|
828
|
+
</div>
|
|
829
|
+
<!-- Inline folder browser -->
|
|
830
|
+
<div
|
|
831
|
+
id="new-doc-browser"
|
|
832
|
+
class="hidden border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden"
|
|
833
|
+
>
|
|
834
|
+
<div
|
|
835
|
+
class="flex items-center gap-2 px-3 py-2 bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700"
|
|
836
|
+
>
|
|
837
|
+
<button
|
|
838
|
+
id="new-doc-browse-up"
|
|
839
|
+
onclick="newDocBrowseUp()"
|
|
840
|
+
class="text-xs text-blue-600 dark:text-blue-400 hover:underline disabled:opacity-30 disabled:pointer-events-none shrink-0"
|
|
841
|
+
>
|
|
842
|
+
↑ Up
|
|
843
|
+
</button>
|
|
844
|
+
<span
|
|
845
|
+
id="new-doc-browse-path"
|
|
846
|
+
class="font-mono text-xs text-gray-400 dark:text-gray-500 truncate flex-1 text-right"
|
|
847
|
+
></span>
|
|
848
|
+
</div>
|
|
849
|
+
<div
|
|
850
|
+
id="new-doc-browse-list"
|
|
851
|
+
class="divide-y divide-gray-100 dark:divide-gray-800 max-h-40 overflow-y-auto"
|
|
852
|
+
></div>
|
|
853
|
+
<!-- Create new folder row -->
|
|
854
|
+
<div
|
|
855
|
+
class="border-t border-gray-200 dark:border-gray-700 flex items-center gap-2 px-3 py-2 bg-gray-50 dark:bg-gray-800/50"
|
|
856
|
+
>
|
|
857
|
+
<input
|
|
858
|
+
id="new-doc-new-folder-name"
|
|
859
|
+
type="text"
|
|
860
|
+
data-i18n-placeholder="modal.new_doc.new_folder_placeholder"
|
|
861
|
+
placeholder="New folder name…"
|
|
862
|
+
class="flex-1 px-2 py-1 text-xs rounded border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-1 focus:ring-blue-400"
|
|
863
|
+
/>
|
|
864
|
+
<button
|
|
865
|
+
onclick="newDocCreateFolder()"
|
|
866
|
+
data-i18n="modal.new_doc.create_folder_btn"
|
|
867
|
+
class="text-xs px-2 py-1 rounded bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400 hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors shrink-0"
|
|
868
|
+
>
|
|
869
|
+
+ Create
|
|
870
|
+
</button>
|
|
871
|
+
</div>
|
|
872
|
+
</div>
|
|
873
|
+
</div>
|
|
874
|
+
|
|
875
|
+
<!-- Filename preview -->
|
|
876
|
+
<div class="space-y-1.5">
|
|
877
|
+
<label
|
|
878
|
+
data-i18n="modal.new_doc.filename_label"
|
|
879
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
880
|
+
>Generated filename</label
|
|
881
|
+
>
|
|
882
|
+
<p
|
|
883
|
+
id="new-doc-filename-preview"
|
|
884
|
+
data-i18n="modal.new_doc.title_placeholder"
|
|
885
|
+
class="text-xs bg-gray-100 dark:bg-gray-800 rounded-lg px-3 py-2 font-mono text-gray-600 dark:text-gray-300 break-all"
|
|
886
|
+
>
|
|
887
|
+
(enter a title)
|
|
888
|
+
</p>
|
|
889
|
+
</div>
|
|
890
|
+
|
|
891
|
+
<!-- Error -->
|
|
892
|
+
<p id="new-doc-error" class="hidden text-xs text-red-500"></p>
|
|
893
|
+
|
|
894
|
+
<!-- Actions -->
|
|
895
|
+
<div class="flex justify-end gap-3 pt-1">
|
|
896
|
+
<button
|
|
897
|
+
onclick="closeNewDocModal()"
|
|
898
|
+
data-i18n="common.cancel"
|
|
899
|
+
class="text-sm px-4 py-2 rounded-lg border border-gray-200 dark:border-gray-700 text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
|
|
900
|
+
>
|
|
901
|
+
Cancel
|
|
902
|
+
</button>
|
|
903
|
+
<button
|
|
904
|
+
onclick="createNewDocument()"
|
|
905
|
+
id="new-doc-create-btn"
|
|
906
|
+
data-i18n="common.create"
|
|
907
|
+
class="text-sm px-4 py-2 rounded-lg bg-blue-600 hover:bg-blue-700 text-white font-semibold transition-colors"
|
|
908
|
+
>
|
|
909
|
+
Create
|
|
910
|
+
</button>
|
|
911
|
+
</div>
|
|
912
|
+
</div>
|
|
913
|
+
</div>
|
|
914
|
+
|
|
915
|
+
<!-- ── Diagram link modal ── -->
|
|
916
|
+
<div
|
|
917
|
+
id="diag-link-modal"
|
|
918
|
+
class="hidden fixed inset-0 z-50 flex items-center justify-center bg-black/50"
|
|
919
|
+
>
|
|
920
|
+
<div
|
|
921
|
+
class="bg-white dark:bg-gray-900 rounded-xl shadow-xl w-full max-w-lg mx-4 p-6 space-y-5"
|
|
922
|
+
>
|
|
923
|
+
<h3 class="text-base font-semibold text-gray-900 dark:text-gray-50">
|
|
924
|
+
<span data-i18n="modal.diag_link.title">◇ Link a diagram</span>
|
|
925
|
+
</h3>
|
|
926
|
+
|
|
927
|
+
<!-- Mode toggle -->
|
|
928
|
+
<div class="flex gap-4 text-sm">
|
|
929
|
+
<label class="flex items-center gap-2 cursor-pointer">
|
|
930
|
+
<input
|
|
931
|
+
type="radio"
|
|
932
|
+
name="diag-mode"
|
|
933
|
+
id="diag-mode-existing"
|
|
934
|
+
value="existing"
|
|
935
|
+
checked
|
|
936
|
+
onchange="diagModeChanged()"
|
|
937
|
+
/>
|
|
938
|
+
<span data-i18n="modal.diag_link.existing_radio" class="text-gray-700 dark:text-gray-300"
|
|
939
|
+
>Existing diagram</span
|
|
940
|
+
>
|
|
941
|
+
</label>
|
|
942
|
+
<label class="flex items-center gap-2 cursor-pointer">
|
|
943
|
+
<input
|
|
944
|
+
type="radio"
|
|
945
|
+
name="diag-mode"
|
|
946
|
+
id="diag-mode-new"
|
|
947
|
+
value="new"
|
|
948
|
+
onchange="diagModeChanged()"
|
|
949
|
+
/>
|
|
950
|
+
<span data-i18n="modal.diag_link.new_radio" class="text-gray-700 dark:text-gray-300">New diagram</span>
|
|
951
|
+
</label>
|
|
952
|
+
</div>
|
|
953
|
+
|
|
954
|
+
<!-- Existing diagram picker -->
|
|
955
|
+
<div id="diag-existing-section" class="space-y-1.5">
|
|
956
|
+
<label
|
|
957
|
+
data-i18n="modal.diag_link.select_label"
|
|
958
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
959
|
+
>Select diagram</label
|
|
960
|
+
>
|
|
961
|
+
<select
|
|
962
|
+
id="diag-select"
|
|
963
|
+
onchange="diagUpdatePreview()"
|
|
964
|
+
class="w-full px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
965
|
+
></select>
|
|
966
|
+
</div>
|
|
967
|
+
|
|
968
|
+
<!-- New diagram name -->
|
|
969
|
+
<div id="diag-new-section" class="hidden space-y-1.5">
|
|
970
|
+
<label
|
|
971
|
+
data-i18n="modal.diag_link.name_label"
|
|
972
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
973
|
+
>Diagram name</label
|
|
974
|
+
>
|
|
975
|
+
<input
|
|
976
|
+
id="diag-new-name"
|
|
977
|
+
type="text"
|
|
978
|
+
data-i18n-placeholder="modal.diag_link.name_placeholder"
|
|
979
|
+
placeholder="My diagram"
|
|
980
|
+
oninput="diagUpdatePreview()"
|
|
981
|
+
class="w-full px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
982
|
+
/>
|
|
983
|
+
</div>
|
|
984
|
+
|
|
985
|
+
<!-- Image filename -->
|
|
986
|
+
<div class="space-y-1.5">
|
|
987
|
+
<label
|
|
988
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
989
|
+
><span data-i18n="modal.diag_link.img_label">Image filename</span>
|
|
990
|
+
<span data-i18n="modal.diag_link.img_hint" class="font-normal text-gray-400"
|
|
991
|
+
>(saved in ./images/)</span
|
|
992
|
+
></label
|
|
993
|
+
>
|
|
994
|
+
<input
|
|
995
|
+
id="diag-img-name"
|
|
996
|
+
type="text"
|
|
997
|
+
placeholder="diagram.png"
|
|
998
|
+
oninput="diagUpdatePreview()"
|
|
999
|
+
class="w-full px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 font-mono focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
1000
|
+
/>
|
|
1001
|
+
</div>
|
|
1002
|
+
|
|
1003
|
+
<!-- Markdown preview -->
|
|
1004
|
+
<div class="space-y-1.5">
|
|
1005
|
+
<label
|
|
1006
|
+
data-i18n="modal.diag_link.markdown_label"
|
|
1007
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
1008
|
+
>Markdown that will be appended</label
|
|
1009
|
+
>
|
|
1010
|
+
<pre
|
|
1011
|
+
id="diag-preview"
|
|
1012
|
+
class="text-xs bg-gray-100 dark:bg-gray-800 rounded-lg px-3 py-2 overflow-x-auto text-gray-700 dark:text-gray-300 whitespace-pre-wrap"
|
|
1013
|
+
></pre>
|
|
1014
|
+
</div>
|
|
1015
|
+
|
|
1016
|
+
<!-- Actions -->
|
|
1017
|
+
<div class="flex justify-end gap-3 pt-1">
|
|
1018
|
+
<button
|
|
1019
|
+
onclick="closeDiagramLinkModal()"
|
|
1020
|
+
data-i18n="common.cancel"
|
|
1021
|
+
class="text-sm px-4 py-2 rounded-lg border border-gray-200 dark:border-gray-700 text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
|
|
1022
|
+
>
|
|
1023
|
+
Cancel
|
|
1024
|
+
</button>
|
|
1025
|
+
<button
|
|
1026
|
+
onclick="insertDiagramLink()"
|
|
1027
|
+
id="diag-insert-btn"
|
|
1028
|
+
data-i18n="modal.diag_link.insert_btn"
|
|
1029
|
+
class="text-sm px-4 py-2 rounded-lg bg-blue-600 hover:bg-blue-700 text-white font-semibold transition-colors"
|
|
1030
|
+
>
|
|
1031
|
+
Insert & Open Diagram
|
|
1032
|
+
</button>
|
|
1033
|
+
</div>
|
|
1034
|
+
</div>
|
|
1035
|
+
</div>
|
|
1036
|
+
|
|
1037
|
+
<!-- ── Snippets modal ── -->
|
|
1038
|
+
<div
|
|
1039
|
+
id="snippets-modal"
|
|
1040
|
+
class="hidden fixed inset-0 z-50 flex items-center justify-center bg-black/50"
|
|
1041
|
+
>
|
|
1042
|
+
<div
|
|
1043
|
+
class="bg-white dark:bg-gray-900 rounded-xl shadow-xl w-full max-w-lg mx-4 p-6 space-y-5 max-h-[90vh] overflow-y-auto"
|
|
1044
|
+
>
|
|
1045
|
+
<h3 class="text-base font-semibold text-gray-900 dark:text-gray-50">
|
|
1046
|
+
<span data-i18n="snippet.modal_title">🧩 Insert a snippet</span>
|
|
1047
|
+
</h3>
|
|
1048
|
+
|
|
1049
|
+
<div
|
|
1050
|
+
id="snippet-detect-msg"
|
|
1051
|
+
class="hidden rounded-lg px-3 py-2 text-xs"
|
|
1052
|
+
></div>
|
|
1053
|
+
|
|
1054
|
+
<!-- Snippet type selector -->
|
|
1055
|
+
<div class="space-y-1.5">
|
|
1056
|
+
<label
|
|
1057
|
+
data-i18n="snippet.type_label"
|
|
1058
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
1059
|
+
>Snippet type</label
|
|
1060
|
+
>
|
|
1061
|
+
<select
|
|
1062
|
+
id="snippet-type"
|
|
1063
|
+
onchange="snippetTypeChanged()"
|
|
1064
|
+
class="w-full px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
1065
|
+
>
|
|
1066
|
+
<option data-i18n="snippet.diagram" value="diagram" selected>Diagram</option>
|
|
1067
|
+
<option data-i18n="snippet.collapsible" value="collapsible">Collapsible block (details)</option>
|
|
1068
|
+
<option data-i18n="snippet.link" value="link">Link</option>
|
|
1069
|
+
<option data-i18n="snippet.link_doc" value="doc-link">Link to document</option>
|
|
1070
|
+
<option data-i18n="snippet.link_anchor" value="anchor-link">Link to anchor</option>
|
|
1071
|
+
<option data-i18n="snippet.link_doc_anchor" value="anchor-doc-link">
|
|
1072
|
+
Link to document with anchor
|
|
1073
|
+
</option>
|
|
1074
|
+
<option data-i18n="snippet.numbered_list" value="ordered-list">Numbered list</option>
|
|
1075
|
+
<option data-i18n="snippet.bullet_list" value="unordered-list">Bullet list</option>
|
|
1076
|
+
<option data-i18n="snippet.code_block" value="code-block">Code block</option>
|
|
1077
|
+
<option data-i18n="snippet.blockquote" value="blockquote">Blockquote</option>
|
|
1078
|
+
<option data-i18n="snippet.separator" value="separator">Horizontal rule</option>
|
|
1079
|
+
<option data-i18n="snippet.image" value="image">Image</option>
|
|
1080
|
+
<option data-i18n="snippet.table" value="table">Table</option>
|
|
1081
|
+
<option data-i18n="snippet.tree" value="tree">Tree</option>
|
|
1082
|
+
<option data-i18n="snippet.colored_section" value="colored-section">Colored section</option>
|
|
1083
|
+
<option data-i18n="snippet.colored_text" value="colored-text">Colored text</option>
|
|
1084
|
+
</select>
|
|
1085
|
+
</div>
|
|
1086
|
+
|
|
1087
|
+
<!-- Panel: collapsible -->
|
|
1088
|
+
<div id="snip-panel-collapsible" class="space-y-3">
|
|
1089
|
+
<div class="space-y-1.5">
|
|
1090
|
+
<label
|
|
1091
|
+
data-i18n="snippet.collapsible_summary_label"
|
|
1092
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
1093
|
+
>Summary title</label
|
|
1094
|
+
>
|
|
1095
|
+
<input
|
|
1096
|
+
id="snip-collapsible-summary"
|
|
1097
|
+
type="text"
|
|
1098
|
+
value="Details"
|
|
1099
|
+
oninput="snippetUpdatePreview()"
|
|
1100
|
+
class="w-full px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
1101
|
+
/>
|
|
1102
|
+
</div>
|
|
1103
|
+
</div>
|
|
1104
|
+
|
|
1105
|
+
<!-- Panel: link -->
|
|
1106
|
+
<div id="snip-panel-link" class="hidden space-y-3">
|
|
1107
|
+
<div class="space-y-1.5">
|
|
1108
|
+
<label
|
|
1109
|
+
data-i18n="snippet.link_text_label"
|
|
1110
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
1111
|
+
>Link text</label
|
|
1112
|
+
>
|
|
1113
|
+
<input
|
|
1114
|
+
id="snip-link-text"
|
|
1115
|
+
type="text"
|
|
1116
|
+
data-i18n-placeholder="snippet.link_text_placeholder"
|
|
1117
|
+
placeholder="My link"
|
|
1118
|
+
oninput="snippetUpdatePreview()"
|
|
1119
|
+
class="w-full px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
1120
|
+
/>
|
|
1121
|
+
</div>
|
|
1122
|
+
<div class="space-y-1.5">
|
|
1123
|
+
<label
|
|
1124
|
+
data-i18n="snippet.link_url_label"
|
|
1125
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
1126
|
+
>URL</label
|
|
1127
|
+
>
|
|
1128
|
+
<input
|
|
1129
|
+
id="snip-link-url"
|
|
1130
|
+
type="text"
|
|
1131
|
+
data-i18n-placeholder="snippet.link_url_placeholder"
|
|
1132
|
+
placeholder="https://..."
|
|
1133
|
+
oninput="snippetUpdatePreview()"
|
|
1134
|
+
class="w-full px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
1135
|
+
/>
|
|
1136
|
+
</div>
|
|
1137
|
+
</div>
|
|
1138
|
+
|
|
1139
|
+
<!-- Panel: doc-link -->
|
|
1140
|
+
<div id="snip-panel-doc-link" class="hidden space-y-3">
|
|
1141
|
+
<div class="space-y-1.5">
|
|
1142
|
+
<label
|
|
1143
|
+
data-i18n="snippet.link_doc_label"
|
|
1144
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
1145
|
+
>Document</label
|
|
1146
|
+
>
|
|
1147
|
+
<select
|
|
1148
|
+
id="snip-doc-select"
|
|
1149
|
+
onchange="snippetUpdatePreview()"
|
|
1150
|
+
class="w-full px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
1151
|
+
></select>
|
|
1152
|
+
</div>
|
|
1153
|
+
<div class="space-y-1.5">
|
|
1154
|
+
<label
|
|
1155
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
1156
|
+
><span data-i18n="snippet.link_text_label">Link text</span>
|
|
1157
|
+
<span data-i18n="snippet.link_doc_text_hint" class="font-normal text-gray-400"
|
|
1158
|
+
>(optional, uses default title)</span
|
|
1159
|
+
></label
|
|
1160
|
+
>
|
|
1161
|
+
<input
|
|
1162
|
+
id="snip-doc-link-text"
|
|
1163
|
+
type="text"
|
|
1164
|
+
placeholder=""
|
|
1165
|
+
oninput="snippetUpdatePreview()"
|
|
1166
|
+
class="w-full px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
1167
|
+
/>
|
|
1168
|
+
</div>
|
|
1169
|
+
</div>
|
|
1170
|
+
|
|
1171
|
+
<!-- Panel: anchor-link -->
|
|
1172
|
+
<div id="snip-panel-anchor-link" class="hidden space-y-3">
|
|
1173
|
+
<div class="space-y-1.5">
|
|
1174
|
+
<label
|
|
1175
|
+
data-i18n="snippet.link_text_label"
|
|
1176
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
1177
|
+
>Link text</label
|
|
1178
|
+
>
|
|
1179
|
+
<input
|
|
1180
|
+
id="snip-anchor-text"
|
|
1181
|
+
type="text"
|
|
1182
|
+
data-i18n-placeholder="snippet.link_section_placeholder"
|
|
1183
|
+
placeholder="View section"
|
|
1184
|
+
oninput="snippetUpdatePreview()"
|
|
1185
|
+
class="w-full px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
1186
|
+
/>
|
|
1187
|
+
</div>
|
|
1188
|
+
<div class="space-y-1.5">
|
|
1189
|
+
<label
|
|
1190
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
1191
|
+
><span data-i18n="snippet.link_anchor_label">Anchor</span>
|
|
1192
|
+
<span data-i18n="snippet.link_anchor_hint" class="font-normal text-gray-400"
|
|
1193
|
+
>(without #, e.g. my-heading)</span
|
|
1194
|
+
></label
|
|
1195
|
+
>
|
|
1196
|
+
<input
|
|
1197
|
+
id="snip-anchor-id"
|
|
1198
|
+
type="text"
|
|
1199
|
+
data-i18n-placeholder="snippet.link_anchor_placeholder"
|
|
1200
|
+
placeholder="my-heading"
|
|
1201
|
+
oninput="snippetUpdatePreview()"
|
|
1202
|
+
class="w-full px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
1203
|
+
/>
|
|
1204
|
+
</div>
|
|
1205
|
+
</div>
|
|
1206
|
+
|
|
1207
|
+
<!-- Panel: anchor-doc-link -->
|
|
1208
|
+
<div id="snip-panel-anchor-doc-link" class="hidden space-y-3">
|
|
1209
|
+
<div class="space-y-1.5">
|
|
1210
|
+
<label
|
|
1211
|
+
data-i18n="snippet.link_target_doc_label"
|
|
1212
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
1213
|
+
>Target document</label
|
|
1214
|
+
>
|
|
1215
|
+
<select
|
|
1216
|
+
id="snip-anchor-doc-select"
|
|
1217
|
+
onchange="snippetUpdatePreview()"
|
|
1218
|
+
class="w-full px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
1219
|
+
></select>
|
|
1220
|
+
</div>
|
|
1221
|
+
<div class="space-y-1.5">
|
|
1222
|
+
<label
|
|
1223
|
+
data-i18n="snippet.link_text_label"
|
|
1224
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
1225
|
+
>Link text</label
|
|
1226
|
+
>
|
|
1227
|
+
<input
|
|
1228
|
+
id="snip-anchor-doc-text"
|
|
1229
|
+
type="text"
|
|
1230
|
+
data-i18n-placeholder="snippet.link_section_placeholder"
|
|
1231
|
+
placeholder="View section"
|
|
1232
|
+
oninput="snippetUpdatePreview()"
|
|
1233
|
+
class="w-full px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
1234
|
+
/>
|
|
1235
|
+
</div>
|
|
1236
|
+
<div class="space-y-1.5">
|
|
1237
|
+
<label
|
|
1238
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
1239
|
+
><span data-i18n="snippet.link_anchor_label">Anchor</span>
|
|
1240
|
+
<span data-i18n="snippet.link_anchor_hint" class="font-normal text-gray-400"
|
|
1241
|
+
>(without #, e.g. my-heading)</span
|
|
1242
|
+
></label
|
|
1243
|
+
>
|
|
1244
|
+
<input
|
|
1245
|
+
id="snip-anchor-doc-id"
|
|
1246
|
+
type="text"
|
|
1247
|
+
data-i18n-placeholder="snippet.link_anchor_placeholder"
|
|
1248
|
+
placeholder="my-heading"
|
|
1249
|
+
oninput="snippetUpdatePreview()"
|
|
1250
|
+
class="w-full px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
1251
|
+
/>
|
|
1252
|
+
</div>
|
|
1253
|
+
</div>
|
|
1254
|
+
|
|
1255
|
+
<!-- Panel: code-block -->
|
|
1256
|
+
<div id="snip-panel-code-block" class="hidden space-y-3">
|
|
1257
|
+
<div class="space-y-1.5">
|
|
1258
|
+
<label
|
|
1259
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
1260
|
+
><span data-i18n="snippet.code_lang_label">Language</span>
|
|
1261
|
+
<span data-i18n="snippet.code_lang_hint" class="font-normal text-gray-400"
|
|
1262
|
+
>(e.g. javascript, python, bash…)</span
|
|
1263
|
+
></label
|
|
1264
|
+
>
|
|
1265
|
+
<input
|
|
1266
|
+
id="snip-code-lang"
|
|
1267
|
+
type="text"
|
|
1268
|
+
placeholder="javascript"
|
|
1269
|
+
oninput="snippetUpdatePreview()"
|
|
1270
|
+
class="w-full px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
1271
|
+
/>
|
|
1272
|
+
</div>
|
|
1273
|
+
</div>
|
|
1274
|
+
|
|
1275
|
+
<!-- Panel: image -->
|
|
1276
|
+
<div id="snip-panel-image" class="hidden space-y-3">
|
|
1277
|
+
<div class="space-y-1.5">
|
|
1278
|
+
<label
|
|
1279
|
+
data-i18n="snippet.image_alt_label"
|
|
1280
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
1281
|
+
>Alt text</label
|
|
1282
|
+
>
|
|
1283
|
+
<input
|
|
1284
|
+
id="snip-image-alt"
|
|
1285
|
+
type="text"
|
|
1286
|
+
data-i18n-placeholder="snippet.image_alt_placeholder"
|
|
1287
|
+
placeholder="Image description"
|
|
1288
|
+
oninput="snippetUpdatePreview()"
|
|
1289
|
+
class="w-full px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
1290
|
+
/>
|
|
1291
|
+
</div>
|
|
1292
|
+
<div class="space-y-1.5">
|
|
1293
|
+
<label
|
|
1294
|
+
data-i18n="snippet.image_url_label"
|
|
1295
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
1296
|
+
>Image URL</label
|
|
1297
|
+
>
|
|
1298
|
+
<input
|
|
1299
|
+
id="snip-image-url"
|
|
1300
|
+
type="text"
|
|
1301
|
+
data-i18n-placeholder="snippet.image_src_placeholder"
|
|
1302
|
+
placeholder="./images/my-image.png"
|
|
1303
|
+
oninput="snippetUpdatePreview()"
|
|
1304
|
+
class="w-full px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
1305
|
+
/>
|
|
1306
|
+
</div>
|
|
1307
|
+
</div>
|
|
1308
|
+
|
|
1309
|
+
<!-- Panel: table -->
|
|
1310
|
+
<div id="snip-panel-table" class="hidden space-y-3">
|
|
1311
|
+
<div class="flex items-center gap-5">
|
|
1312
|
+
<div class="flex items-center gap-2">
|
|
1313
|
+
<span data-i18n="snippet.table_rows_label" class="text-xs text-gray-500 dark:text-gray-400"
|
|
1314
|
+
>Rows</span
|
|
1315
|
+
>
|
|
1316
|
+
<button
|
|
1317
|
+
onclick="tableChangeRows(-1)"
|
|
1318
|
+
class="text-xs px-2 py-0.5 rounded border border-gray-200 dark:border-gray-700 text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"
|
|
1319
|
+
>
|
|
1320
|
+
−
|
|
1321
|
+
</button>
|
|
1322
|
+
<span
|
|
1323
|
+
id="snip-table-rows"
|
|
1324
|
+
class="text-xs font-mono w-4 text-center"
|
|
1325
|
+
>3</span
|
|
1326
|
+
>
|
|
1327
|
+
<button
|
|
1328
|
+
onclick="tableChangeRows(1)"
|
|
1329
|
+
class="text-xs px-2 py-0.5 rounded border border-gray-200 dark:border-gray-700 text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"
|
|
1330
|
+
>
|
|
1331
|
+
+
|
|
1332
|
+
</button>
|
|
1333
|
+
</div>
|
|
1334
|
+
<div class="flex items-center gap-2">
|
|
1335
|
+
<span data-i18n="snippet.table_cols_label" class="text-xs text-gray-500 dark:text-gray-400"
|
|
1336
|
+
>Columns</span
|
|
1337
|
+
>
|
|
1338
|
+
<button
|
|
1339
|
+
onclick="tableChangeCols(-1)"
|
|
1340
|
+
class="text-xs px-2 py-0.5 rounded border border-gray-200 dark:border-gray-700 text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"
|
|
1341
|
+
>
|
|
1342
|
+
−
|
|
1343
|
+
</button>
|
|
1344
|
+
<span
|
|
1345
|
+
id="snip-table-cols"
|
|
1346
|
+
class="text-xs font-mono w-4 text-center"
|
|
1347
|
+
>3</span
|
|
1348
|
+
>
|
|
1349
|
+
<button
|
|
1350
|
+
onclick="tableChangeCols(1)"
|
|
1351
|
+
class="text-xs px-2 py-0.5 rounded border border-gray-200 dark:border-gray-700 text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"
|
|
1352
|
+
>
|
|
1353
|
+
+
|
|
1354
|
+
</button>
|
|
1355
|
+
</div>
|
|
1356
|
+
</div>
|
|
1357
|
+
<div id="snip-table-grid" class="overflow-x-auto"></div>
|
|
1358
|
+
</div>
|
|
1359
|
+
|
|
1360
|
+
<!-- Panel: tree -->
|
|
1361
|
+
<div id="snip-panel-tree" class="hidden space-y-2">
|
|
1362
|
+
<p data-i18n="snippet.tree_hint" class="text-xs text-gray-400 dark:text-gray-500">
|
|
1363
|
+
← → to indent · names with / will be folders
|
|
1364
|
+
</p>
|
|
1365
|
+
<div id="snip-tree-list" class="space-y-1"></div>
|
|
1366
|
+
<button
|
|
1367
|
+
onclick="treeAddItem()"
|
|
1368
|
+
data-i18n="snippet.tree_add_btn"
|
|
1369
|
+
class="text-xs px-3 py-1.5 rounded-lg border border-dashed border-gray-300 dark:border-gray-600 text-gray-500 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors w-full"
|
|
1370
|
+
>
|
|
1371
|
+
+ Add item
|
|
1372
|
+
</button>
|
|
1373
|
+
</div>
|
|
1374
|
+
|
|
1375
|
+
<!-- Panel: diagram -->
|
|
1376
|
+
<div id="snip-panel-diagram" class="hidden space-y-3">
|
|
1377
|
+
<!-- Mode toggle -->
|
|
1378
|
+
<div class="flex gap-4 text-sm">
|
|
1379
|
+
<label class="flex items-center gap-2 cursor-pointer">
|
|
1380
|
+
<input
|
|
1381
|
+
type="radio"
|
|
1382
|
+
name="snip-diag-mode"
|
|
1383
|
+
id="snip-diag-mode-existing"
|
|
1384
|
+
value="existing"
|
|
1385
|
+
checked
|
|
1386
|
+
onchange="snippetDiagModeChanged()"
|
|
1387
|
+
/>
|
|
1388
|
+
<span data-i18n="snippet.diagram_existing" class="text-gray-700 dark:text-gray-300"
|
|
1389
|
+
>Existing diagram</span
|
|
1390
|
+
>
|
|
1391
|
+
</label>
|
|
1392
|
+
<label class="flex items-center gap-2 cursor-pointer">
|
|
1393
|
+
<input
|
|
1394
|
+
type="radio"
|
|
1395
|
+
name="snip-diag-mode"
|
|
1396
|
+
id="snip-diag-mode-new"
|
|
1397
|
+
value="new"
|
|
1398
|
+
onchange="snippetDiagModeChanged()"
|
|
1399
|
+
/>
|
|
1400
|
+
<span data-i18n="snippet.diagram_new" class="text-gray-700 dark:text-gray-300"
|
|
1401
|
+
>New diagram</span
|
|
1402
|
+
>
|
|
1403
|
+
</label>
|
|
1404
|
+
</div>
|
|
1405
|
+
<!-- Existing picker -->
|
|
1406
|
+
<div id="snip-diag-existing-section" class="space-y-1.5">
|
|
1407
|
+
<label
|
|
1408
|
+
data-i18n="snippet.diagram_select_label"
|
|
1409
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
1410
|
+
>Select diagram</label
|
|
1411
|
+
>
|
|
1412
|
+
<select
|
|
1413
|
+
id="snip-diag-select"
|
|
1414
|
+
onchange="
|
|
1415
|
+
snippetDiagSyncImgName();
|
|
1416
|
+
snippetUpdatePreview();
|
|
1417
|
+
"
|
|
1418
|
+
class="w-full px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
1419
|
+
></select>
|
|
1420
|
+
</div>
|
|
1421
|
+
<!-- New diagram name -->
|
|
1422
|
+
<div id="snip-diag-new-section" class="hidden space-y-1.5">
|
|
1423
|
+
<label
|
|
1424
|
+
data-i18n="snippet.diagram_name_label"
|
|
1425
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
1426
|
+
>Diagram name</label
|
|
1427
|
+
>
|
|
1428
|
+
<input
|
|
1429
|
+
id="snip-diag-new-name"
|
|
1430
|
+
type="text"
|
|
1431
|
+
data-i18n-placeholder="snippet.diagram_name_placeholder"
|
|
1432
|
+
placeholder="Diagram name…"
|
|
1433
|
+
oninput="
|
|
1434
|
+
snippetDiagSyncImgName();
|
|
1435
|
+
snippetUpdatePreview();
|
|
1436
|
+
"
|
|
1437
|
+
class="w-full px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
1438
|
+
/>
|
|
1439
|
+
</div>
|
|
1440
|
+
<!-- Image filename -->
|
|
1441
|
+
<div class="space-y-1.5">
|
|
1442
|
+
<label
|
|
1443
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
1444
|
+
>
|
|
1445
|
+
<span data-i18n="snippet.diag_img_label">Image filename</span>
|
|
1446
|
+
<span data-i18n="snippet.diag_img_saved_hint" class="font-normal text-gray-400"
|
|
1447
|
+
>(saved in ./images/)</span
|
|
1448
|
+
>
|
|
1449
|
+
</label>
|
|
1450
|
+
<input
|
|
1451
|
+
id="snip-diag-img-name"
|
|
1452
|
+
type="text"
|
|
1453
|
+
placeholder="diagram.png"
|
|
1454
|
+
oninput="snippetUpdatePreview()"
|
|
1455
|
+
class="w-full px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 font-mono focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
1456
|
+
/>
|
|
1457
|
+
</div>
|
|
1458
|
+
</div>
|
|
1459
|
+
|
|
1460
|
+
<!-- Panel: colored-section -->
|
|
1461
|
+
<div id="snip-panel-colored-section" class="hidden space-y-3">
|
|
1462
|
+
<div class="space-y-1.5">
|
|
1463
|
+
<label
|
|
1464
|
+
data-i18n="snippet.colored_section_color_label"
|
|
1465
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
1466
|
+
>Color</label
|
|
1467
|
+
>
|
|
1468
|
+
<div class="flex flex-wrap gap-2">
|
|
1469
|
+
<button
|
|
1470
|
+
type="button"
|
|
1471
|
+
data-color-swatch="info"
|
|
1472
|
+
onclick="colorSectionPickSwatch(this)"
|
|
1473
|
+
data-i18n-title="snippet.colored_section_swatch_info"
|
|
1474
|
+
title="Info (blue)"
|
|
1475
|
+
class="w-7 h-7 rounded-full border-2 border-blue-400 bg-blue-100 ring-2 ring-transparent hover:ring-blue-400 transition-all color-swatch-btn selected-swatch"
|
|
1476
|
+
></button>
|
|
1477
|
+
<button
|
|
1478
|
+
type="button"
|
|
1479
|
+
data-color-swatch="success"
|
|
1480
|
+
onclick="colorSectionPickSwatch(this)"
|
|
1481
|
+
data-i18n-title="snippet.colored_section_swatch_success"
|
|
1482
|
+
title="Success (green)"
|
|
1483
|
+
class="w-7 h-7 rounded-full border-2 border-green-400 bg-green-100 ring-2 ring-transparent hover:ring-green-400 transition-all color-swatch-btn"
|
|
1484
|
+
></button>
|
|
1485
|
+
<button
|
|
1486
|
+
type="button"
|
|
1487
|
+
data-color-swatch="warning"
|
|
1488
|
+
onclick="colorSectionPickSwatch(this)"
|
|
1489
|
+
data-i18n-title="snippet.colored_section_swatch_warning"
|
|
1490
|
+
title="Warning (amber)"
|
|
1491
|
+
class="w-7 h-7 rounded-full border-2 border-amber-400 bg-amber-100 ring-2 ring-transparent hover:ring-amber-400 transition-all color-swatch-btn"
|
|
1492
|
+
></button>
|
|
1493
|
+
<button
|
|
1494
|
+
type="button"
|
|
1495
|
+
data-color-swatch="danger"
|
|
1496
|
+
onclick="colorSectionPickSwatch(this)"
|
|
1497
|
+
data-i18n-title="snippet.colored_section_swatch_danger"
|
|
1498
|
+
title="Danger (red)"
|
|
1499
|
+
class="w-7 h-7 rounded-full border-2 border-red-400 bg-red-100 ring-2 ring-transparent hover:ring-red-400 transition-all color-swatch-btn"
|
|
1500
|
+
></button>
|
|
1501
|
+
<button
|
|
1502
|
+
type="button"
|
|
1503
|
+
data-color-swatch="note"
|
|
1504
|
+
onclick="colorSectionPickSwatch(this)"
|
|
1505
|
+
data-i18n-title="snippet.colored_section_swatch_note"
|
|
1506
|
+
title="Note (purple)"
|
|
1507
|
+
class="w-7 h-7 rounded-full border-2 border-purple-400 bg-purple-100 ring-2 ring-transparent hover:ring-purple-400 transition-all color-swatch-btn"
|
|
1508
|
+
></button>
|
|
1509
|
+
<button
|
|
1510
|
+
type="button"
|
|
1511
|
+
data-color-swatch="neutral"
|
|
1512
|
+
onclick="colorSectionPickSwatch(this)"
|
|
1513
|
+
data-i18n-title="snippet.colored_section_swatch_neutral"
|
|
1514
|
+
title="Neutral (gray)"
|
|
1515
|
+
class="w-7 h-7 rounded-full border-2 border-gray-400 bg-gray-100 ring-2 ring-transparent hover:ring-gray-400 transition-all color-swatch-btn"
|
|
1516
|
+
></button>
|
|
1517
|
+
</div>
|
|
1518
|
+
</div>
|
|
1519
|
+
<div class="space-y-1.5">
|
|
1520
|
+
<label
|
|
1521
|
+
data-i18n="snippet.colored_section_content_label"
|
|
1522
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
1523
|
+
>Content</label
|
|
1524
|
+
>
|
|
1525
|
+
<textarea
|
|
1526
|
+
id="snip-colored-content"
|
|
1527
|
+
rows="4"
|
|
1528
|
+
data-i18n-placeholder="snippet.colored_section_content_placeholder"
|
|
1529
|
+
placeholder="Your text here…"
|
|
1530
|
+
oninput="snippetUpdatePreview()"
|
|
1531
|
+
class="w-full px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500 resize-y font-mono"
|
|
1532
|
+
></textarea>
|
|
1533
|
+
</div>
|
|
1534
|
+
</div>
|
|
1535
|
+
|
|
1536
|
+
<!-- Panel: colored-text -->
|
|
1537
|
+
<div id="snip-panel-colored-text" class="hidden space-y-3">
|
|
1538
|
+
<div class="space-y-1.5">
|
|
1539
|
+
<label
|
|
1540
|
+
data-i18n="snippet.colored_text_color_label"
|
|
1541
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
1542
|
+
>Color</label
|
|
1543
|
+
>
|
|
1544
|
+
<div class="flex flex-wrap gap-2">
|
|
1545
|
+
<button
|
|
1546
|
+
type="button"
|
|
1547
|
+
data-color-text-swatch="info"
|
|
1548
|
+
onclick="colorTextPickSwatch(this)"
|
|
1549
|
+
data-i18n-title="snippet.colored_section_swatch_info"
|
|
1550
|
+
title="Info (blue)"
|
|
1551
|
+
class="w-7 h-7 rounded-full border-2 border-blue-500 bg-blue-500 ring-2 ring-transparent hover:ring-blue-400 transition-all color-text-swatch-btn selected-text-swatch"
|
|
1552
|
+
></button>
|
|
1553
|
+
<button
|
|
1554
|
+
type="button"
|
|
1555
|
+
data-color-text-swatch="success"
|
|
1556
|
+
onclick="colorTextPickSwatch(this)"
|
|
1557
|
+
data-i18n-title="snippet.colored_section_swatch_success"
|
|
1558
|
+
title="Success (green)"
|
|
1559
|
+
class="w-7 h-7 rounded-full border-2 border-green-500 bg-green-500 ring-2 ring-transparent hover:ring-green-400 transition-all color-text-swatch-btn"
|
|
1560
|
+
></button>
|
|
1561
|
+
<button
|
|
1562
|
+
type="button"
|
|
1563
|
+
data-color-text-swatch="warning"
|
|
1564
|
+
onclick="colorTextPickSwatch(this)"
|
|
1565
|
+
data-i18n-title="snippet.colored_section_swatch_warning"
|
|
1566
|
+
title="Warning (amber)"
|
|
1567
|
+
class="w-7 h-7 rounded-full border-2 border-amber-500 bg-amber-500 ring-2 ring-transparent hover:ring-amber-400 transition-all color-text-swatch-btn"
|
|
1568
|
+
></button>
|
|
1569
|
+
<button
|
|
1570
|
+
type="button"
|
|
1571
|
+
data-color-text-swatch="danger"
|
|
1572
|
+
onclick="colorTextPickSwatch(this)"
|
|
1573
|
+
data-i18n-title="snippet.colored_section_swatch_danger"
|
|
1574
|
+
title="Danger (red)"
|
|
1575
|
+
class="w-7 h-7 rounded-full border-2 border-red-500 bg-red-500 ring-2 ring-transparent hover:ring-red-400 transition-all color-text-swatch-btn"
|
|
1576
|
+
></button>
|
|
1577
|
+
<button
|
|
1578
|
+
type="button"
|
|
1579
|
+
data-color-text-swatch="note"
|
|
1580
|
+
onclick="colorTextPickSwatch(this)"
|
|
1581
|
+
data-i18n-title="snippet.colored_section_swatch_note"
|
|
1582
|
+
title="Note (purple)"
|
|
1583
|
+
class="w-7 h-7 rounded-full border-2 border-purple-500 bg-purple-500 ring-2 ring-transparent hover:ring-purple-400 transition-all color-text-swatch-btn"
|
|
1584
|
+
></button>
|
|
1585
|
+
<button
|
|
1586
|
+
type="button"
|
|
1587
|
+
data-color-text-swatch="neutral"
|
|
1588
|
+
onclick="colorTextPickSwatch(this)"
|
|
1589
|
+
data-i18n-title="snippet.colored_section_swatch_neutral"
|
|
1590
|
+
title="Neutral (gray)"
|
|
1591
|
+
class="w-7 h-7 rounded-full border-2 border-gray-500 bg-gray-500 ring-2 ring-transparent hover:ring-gray-400 transition-all color-text-swatch-btn"
|
|
1592
|
+
></button>
|
|
1593
|
+
</div>
|
|
1594
|
+
</div>
|
|
1595
|
+
<div class="space-y-1.5">
|
|
1596
|
+
<label
|
|
1597
|
+
data-i18n="snippet.colored_text_content_label"
|
|
1598
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
1599
|
+
>Text</label
|
|
1600
|
+
>
|
|
1601
|
+
<input
|
|
1602
|
+
id="snip-colored-text-content"
|
|
1603
|
+
type="text"
|
|
1604
|
+
data-i18n-placeholder="snippet.colored_text_content_placeholder"
|
|
1605
|
+
placeholder="Your text…"
|
|
1606
|
+
oninput="snippetUpdatePreview()"
|
|
1607
|
+
class="w-full px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
1608
|
+
/>
|
|
1609
|
+
</div>
|
|
1610
|
+
</div>
|
|
1611
|
+
|
|
1612
|
+
<!-- Markdown preview -->
|
|
1613
|
+
<div class="space-y-1.5">
|
|
1614
|
+
<label
|
|
1615
|
+
data-i18n="snippet.markdown_preview_label"
|
|
1616
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
1617
|
+
>Markdown preview</label
|
|
1618
|
+
>
|
|
1619
|
+
<pre
|
|
1620
|
+
id="snippet-preview"
|
|
1621
|
+
class="text-xs bg-gray-100 dark:bg-gray-800 rounded-lg px-3 py-2 overflow-x-auto text-gray-700 dark:text-gray-300 whitespace-pre-wrap"
|
|
1622
|
+
></pre>
|
|
1623
|
+
</div>
|
|
1624
|
+
|
|
1625
|
+
<!-- Actions -->
|
|
1626
|
+
<div class="flex justify-end gap-3 pt-1">
|
|
1627
|
+
<button
|
|
1628
|
+
onclick="closeSnippetsModal()"
|
|
1629
|
+
data-i18n="common.cancel"
|
|
1630
|
+
class="text-sm px-4 py-2 rounded-lg border border-gray-200 dark:border-gray-700 text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
|
|
1631
|
+
>
|
|
1632
|
+
Cancel
|
|
1633
|
+
</button>
|
|
1634
|
+
<button
|
|
1635
|
+
onclick="insertSnippet()"
|
|
1636
|
+
data-i18n="snippet.insert_btn"
|
|
1637
|
+
class="text-sm px-4 py-2 rounded-lg bg-blue-600 hover:bg-blue-700 text-white font-semibold transition-colors"
|
|
1638
|
+
>
|
|
1639
|
+
Insert
|
|
1640
|
+
</button>
|
|
1641
|
+
</div>
|
|
1642
|
+
</div>
|
|
1643
|
+
</div>
|
|
1644
|
+
|
|
1645
|
+
<!-- ── Image paste confirmation modal ── -->
|
|
1646
|
+
<div
|
|
1647
|
+
id="img-paste-modal"
|
|
1648
|
+
class="hidden fixed inset-0 z-50 flex items-center justify-center bg-black/50"
|
|
1649
|
+
>
|
|
1650
|
+
<div
|
|
1651
|
+
class="bg-white dark:bg-gray-900 rounded-xl shadow-xl w-full max-w-sm mx-4 p-6 space-y-5"
|
|
1652
|
+
>
|
|
1653
|
+
<h3 class="text-base font-semibold text-gray-900 dark:text-gray-50">
|
|
1654
|
+
🖼️ <span data-i18n="modal.img_paste.title">Paste clipboard image?</span>
|
|
1655
|
+
</h3>
|
|
1656
|
+
<div class="space-y-1.5">
|
|
1657
|
+
<label
|
|
1658
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
1659
|
+
>
|
|
1660
|
+
<span data-i18n="modal.img_paste.filename_label">Filename</span>
|
|
1661
|
+
<span data-i18n="modal.img_paste.saved_hint" class="font-normal text-gray-400"
|
|
1662
|
+
>(saved in images/)</span
|
|
1663
|
+
>
|
|
1664
|
+
</label>
|
|
1665
|
+
<div class="flex items-center gap-2">
|
|
1666
|
+
<input
|
|
1667
|
+
id="img-paste-name"
|
|
1668
|
+
type="text"
|
|
1669
|
+
class="flex-1 px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 font-mono focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
1670
|
+
/>
|
|
1671
|
+
<span
|
|
1672
|
+
id="img-paste-ext"
|
|
1673
|
+
class="text-xs text-gray-400 shrink-0"
|
|
1674
|
+
></span>
|
|
1675
|
+
</div>
|
|
1676
|
+
</div>
|
|
1677
|
+
<div class="flex justify-end gap-3 pt-1">
|
|
1678
|
+
<button
|
|
1679
|
+
onclick="imgPasteCancel()"
|
|
1680
|
+
data-i18n="common.cancel"
|
|
1681
|
+
class="text-sm px-4 py-2 rounded-lg border border-gray-200 dark:border-gray-700 text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
|
|
1682
|
+
>
|
|
1683
|
+
Cancel
|
|
1684
|
+
</button>
|
|
1685
|
+
<button
|
|
1686
|
+
onclick="imgPasteConfirm()"
|
|
1687
|
+
data-i18n="modal.img_paste.paste_btn"
|
|
1688
|
+
class="text-sm px-4 py-2 rounded-lg bg-blue-600 hover:bg-blue-700 text-white font-semibold transition-colors"
|
|
1689
|
+
>
|
|
1690
|
+
Paste
|
|
1691
|
+
</button>
|
|
1692
|
+
</div>
|
|
1693
|
+
</div>
|
|
1694
|
+
</div>
|
|
1695
|
+
|
|
1696
|
+
<!-- ── Marker: post-it creation popup ── -->
|
|
1697
|
+
<div
|
|
1698
|
+
id="stabilo-popup"
|
|
1699
|
+
class="hidden fixed z-50 w-80 bg-yellow-50 dark:bg-yellow-900/80 border-2 border-yellow-300 dark:border-yellow-600 rounded-xl shadow-2xl p-4 flex flex-col gap-3"
|
|
1700
|
+
style="top: 0; left: 0"
|
|
1701
|
+
>
|
|
1702
|
+
<div
|
|
1703
|
+
class="text-xs font-semibold text-yellow-700 dark:text-yellow-300 flex items-center gap-2"
|
|
1704
|
+
>
|
|
1705
|
+
<span>✏</span> <span data-i18n="annotation.title">Annotation</span>
|
|
1706
|
+
</div>
|
|
1707
|
+
<div
|
|
1708
|
+
id="stabilo-selected-preview"
|
|
1709
|
+
class="text-xs text-yellow-800 dark:text-yellow-200 bg-yellow-100 dark:bg-yellow-800/50 rounded px-2 py-1 italic max-h-16 overflow-y-auto border border-yellow-200 dark:border-yellow-700"
|
|
1710
|
+
></div>
|
|
1711
|
+
<textarea
|
|
1712
|
+
id="stabilo-note-input"
|
|
1713
|
+
rows="4"
|
|
1714
|
+
data-i18n-placeholder="annotation.placeholder"
|
|
1715
|
+
placeholder="Your comment or suggestion…"
|
|
1716
|
+
class="w-full text-sm rounded-lg border border-yellow-300 dark:border-yellow-600 bg-white dark:bg-yellow-950 text-gray-900 dark:text-gray-100 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-yellow-400 resize-none"
|
|
1717
|
+
>
|
|
1718
|
+
</textarea>
|
|
1719
|
+
<div class="flex justify-end gap-2">
|
|
1720
|
+
<button
|
|
1721
|
+
onclick="cancelMarkerPopup()"
|
|
1722
|
+
data-i18n="common.cancel"
|
|
1723
|
+
class="text-sm px-3 py-1.5 rounded-lg border border-yellow-300 dark:border-yellow-600 text-yellow-700 dark:text-yellow-300 hover:bg-yellow-100 dark:hover:bg-yellow-800 transition-colors"
|
|
1724
|
+
>
|
|
1725
|
+
Cancel
|
|
1726
|
+
</button>
|
|
1727
|
+
<button
|
|
1728
|
+
onclick="saveAnnotation()"
|
|
1729
|
+
data-i18n="annotation.save_btn"
|
|
1730
|
+
class="text-sm px-4 py-1.5 rounded-lg bg-yellow-400 hover:bg-yellow-500 dark:bg-yellow-600 dark:hover:bg-yellow-500 text-yellow-900 dark:text-white font-semibold transition-colors"
|
|
1731
|
+
>
|
|
1732
|
+
Save
|
|
1733
|
+
</button>
|
|
1734
|
+
</div>
|
|
1735
|
+
</div>
|
|
1736
|
+
|
|
1737
|
+
<!-- ── Marker: read-only post-it hover popup ── -->
|
|
1738
|
+
<div
|
|
1739
|
+
id="stabilo-read-popup"
|
|
1740
|
+
class="hidden fixed z-50 w-80 bg-yellow-50 dark:bg-yellow-900/80 border-2 border-yellow-300 dark:border-yellow-600 rounded-xl shadow-2xl p-4 flex flex-col gap-2 pointer-events-auto"
|
|
1741
|
+
style="top: 0; left: 0"
|
|
1742
|
+
>
|
|
1743
|
+
<div
|
|
1744
|
+
class="text-xs font-semibold text-yellow-700 dark:text-yellow-300 flex items-center gap-2"
|
|
1745
|
+
>
|
|
1746
|
+
<span>✏</span>
|
|
1747
|
+
<span
|
|
1748
|
+
id="stabilo-read-date"
|
|
1749
|
+
class="font-normal text-yellow-600 dark:text-yellow-400"
|
|
1750
|
+
></span>
|
|
1751
|
+
</div>
|
|
1752
|
+
<div
|
|
1753
|
+
id="stabilo-read-orphan"
|
|
1754
|
+
data-i18n="annotation.orphan"
|
|
1755
|
+
class="hidden text-xs font-semibold text-red-600 dark:text-red-400 bg-red-50 dark:bg-red-900/30 border border-red-200 dark:border-red-700 rounded px-2 py-1"
|
|
1756
|
+
></div>
|
|
1757
|
+
<div
|
|
1758
|
+
id="stabilo-read-text"
|
|
1759
|
+
class="text-sm text-gray-800 dark:text-gray-100 whitespace-pre-wrap max-h-48 overflow-y-auto"
|
|
1760
|
+
></div>
|
|
1761
|
+
<div
|
|
1762
|
+
class="flex justify-end pt-1 border-t border-yellow-200 dark:border-yellow-700"
|
|
1763
|
+
>
|
|
1764
|
+
<button
|
|
1765
|
+
id="stabilo-delete-btn"
|
|
1766
|
+
data-i18n="annotation.delete_btn"
|
|
1767
|
+
class="text-xs px-3 py-1.5 rounded-lg border border-red-200 dark:border-red-700 text-red-500 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/40 transition-colors flex items-center gap-1"
|
|
1768
|
+
>
|
|
1769
|
+
🗑 Delete
|
|
1770
|
+
</button>
|
|
1771
|
+
</div>
|
|
1772
|
+
</div>
|
|
1773
|
+
|
|
1774
|
+
<!-- ── Marker: delete confirmation ── -->
|
|
1775
|
+
<div
|
|
1776
|
+
id="stabilo-confirm-delete"
|
|
1777
|
+
class="hidden fixed z-50 w-72 bg-white dark:bg-gray-900 border border-red-200 dark:border-red-700 rounded-xl shadow-2xl p-4 flex flex-col gap-3"
|
|
1778
|
+
style="top: 0; left: 0"
|
|
1779
|
+
>
|
|
1780
|
+
<p data-i18n="annotation.confirm_delete" class="text-sm text-gray-700 dark:text-gray-200">
|
|
1781
|
+
Delete this annotation?
|
|
1782
|
+
</p>
|
|
1783
|
+
<div class="flex justify-end gap-2">
|
|
1784
|
+
<button
|
|
1785
|
+
onclick="cancelDeleteAnnotation()"
|
|
1786
|
+
data-i18n="common.cancel"
|
|
1787
|
+
class="text-sm px-3 py-1.5 rounded-lg border border-gray-200 dark:border-gray-700 text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
|
|
1788
|
+
>
|
|
1789
|
+
Cancel
|
|
1790
|
+
</button>
|
|
1791
|
+
<button
|
|
1792
|
+
onclick="confirmDeleteAnnotation()"
|
|
1793
|
+
data-i18n="annotation.confirm_btn"
|
|
1794
|
+
class="text-sm px-4 py-1.5 rounded-lg bg-red-500 hover:bg-red-600 text-white font-semibold transition-colors"
|
|
1795
|
+
>
|
|
1796
|
+
Delete
|
|
1797
|
+
</button>
|
|
1798
|
+
</div>
|
|
1799
|
+
</div>
|
|
1800
|
+
|
|
1801
|
+
<!-- ── Document: delete confirmation ── -->
|
|
1802
|
+
<div
|
|
1803
|
+
id="doc-confirm-delete"
|
|
1804
|
+
class="hidden fixed inset-0 z-50 bg-black/50 flex items-center justify-center p-4"
|
|
1805
|
+
onclick="cancelDeleteDocument(event)"
|
|
1806
|
+
>
|
|
1807
|
+
<div
|
|
1808
|
+
class="w-full max-w-sm bg-white dark:bg-gray-900 border border-red-200 dark:border-red-700 rounded-xl shadow-2xl p-5 flex flex-col gap-3"
|
|
1809
|
+
onclick="event.stopPropagation()"
|
|
1810
|
+
>
|
|
1811
|
+
<p data-i18n="doc.confirm_delete" class="text-sm text-gray-700 dark:text-gray-200">
|
|
1812
|
+
Permanently delete this document?
|
|
1813
|
+
</p>
|
|
1814
|
+
<p id="doc-confirm-delete-title" class="text-xs text-gray-500 dark:text-gray-400 italic truncate"></p>
|
|
1815
|
+
<div class="flex justify-end gap-2 mt-2">
|
|
1816
|
+
<button
|
|
1817
|
+
onclick="cancelDeleteDocument()"
|
|
1818
|
+
data-i18n="common.cancel"
|
|
1819
|
+
class="text-sm px-3 py-1.5 rounded-lg border border-gray-200 dark:border-gray-700 text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
|
|
1820
|
+
>
|
|
1821
|
+
Cancel
|
|
1822
|
+
</button>
|
|
1823
|
+
<button
|
|
1824
|
+
onclick="confirmDeleteDocument()"
|
|
1825
|
+
data-i18n="doc.confirm_delete_btn"
|
|
1826
|
+
class="text-sm px-4 py-1.5 rounded-lg bg-red-500 hover:bg-red-600 text-white font-semibold transition-colors"
|
|
1827
|
+
>
|
|
1828
|
+
Delete
|
|
1829
|
+
</button>
|
|
1830
|
+
</div>
|
|
1831
|
+
</div>
|
|
1832
|
+
</div>
|
|
1833
|
+
|
|
1834
|
+
<!-- ── Marker: right elevator ── -->
|
|
1835
|
+
<div
|
|
1836
|
+
id="stabilo-elevator"
|
|
1837
|
+
class="hidden fixed top-14 right-0 w-10 flex flex-col items-center py-2 gap-2 z-40 overflow-y-auto"
|
|
1838
|
+
style="max-height: calc(100vh - 3.5rem)"
|
|
1839
|
+
></div>
|
|
1840
|
+
|
|
1841
|
+
<!-- ── Image lightbox overlay ── -->
|
|
1842
|
+
<div
|
|
1843
|
+
id="img-lightbox"
|
|
1844
|
+
class="hidden fixed inset-0 z-50 bg-black/90 flex items-center justify-center cursor-pointer"
|
|
1845
|
+
onclick="closeLightbox()"
|
|
1846
|
+
>
|
|
1847
|
+
<img
|
|
1848
|
+
id="img-lightbox-img"
|
|
1849
|
+
src=""
|
|
1850
|
+
alt=""
|
|
1851
|
+
class="max-w-full max-h-full object-contain select-none"
|
|
1852
|
+
onclick="event.stopPropagation()"
|
|
1853
|
+
/>
|
|
1854
|
+
<button
|
|
1855
|
+
onclick="closeLightbox()"
|
|
1856
|
+
class="absolute top-4 right-4 text-white/70 hover:text-white text-2xl leading-none"
|
|
1857
|
+
>
|
|
1858
|
+
×
|
|
1859
|
+
</button>
|
|
1860
|
+
</div>
|
|
1861
|
+
|
|
1862
|
+
<!-- ── Word Cloud overlay ── -->
|
|
1863
|
+
<div
|
|
1864
|
+
id="wc-overlay"
|
|
1865
|
+
class="hidden fixed inset-0 z-50 flex flex-col bg-white dark:bg-gray-950"
|
|
1866
|
+
>
|
|
1867
|
+
<div
|
|
1868
|
+
class="flex items-center justify-between px-6 h-14 border-b border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 shrink-0"
|
|
1869
|
+
>
|
|
1870
|
+
<h2 data-i18n="wc.title" class="font-semibold text-base">☁ Word Cloud</h2>
|
|
1871
|
+
<button
|
|
1872
|
+
onclick="closeWordCloud()"
|
|
1873
|
+
data-i18n="wc.close_btn"
|
|
1874
|
+
class="text-sm px-3 py-1.5 rounded-lg text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
|
|
1875
|
+
>
|
|
1876
|
+
✕ Close
|
|
1877
|
+
</button>
|
|
1878
|
+
</div>
|
|
1879
|
+
<!-- Search root toolbar -->
|
|
1880
|
+
<div
|
|
1881
|
+
class="border-b border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 shrink-0"
|
|
1882
|
+
>
|
|
1883
|
+
<!-- Row 1: path + browse + launch -->
|
|
1884
|
+
<div class="flex items-center gap-3 px-6 py-3">
|
|
1885
|
+
<label
|
|
1886
|
+
data-i18n="wc.search_root_label"
|
|
1887
|
+
class="text-xs font-medium text-gray-500 dark:text-gray-400 shrink-0"
|
|
1888
|
+
>Search root</label
|
|
1889
|
+
>
|
|
1890
|
+
<input
|
|
1891
|
+
id="wc-root"
|
|
1892
|
+
type="text"
|
|
1893
|
+
readonly
|
|
1894
|
+
spellcheck="false"
|
|
1895
|
+
class="flex-1 px-3 py-1.5 text-sm rounded-lg border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 font-mono cursor-default focus:outline-none"
|
|
1896
|
+
/>
|
|
1897
|
+
<button
|
|
1898
|
+
onclick="wcToggleBrowser()"
|
|
1899
|
+
class="text-sm px-3 py-1.5 rounded-lg border border-gray-200 dark:border-gray-700 text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors shrink-0"
|
|
1900
|
+
>
|
|
1901
|
+
📁 <span data-i18n="wc.browse_btn">Browse</span>
|
|
1902
|
+
</button>
|
|
1903
|
+
<button
|
|
1904
|
+
onclick="launchWordCloud()"
|
|
1905
|
+
data-i18n="wc.launch_btn"
|
|
1906
|
+
class="text-sm px-4 py-1.5 rounded-lg bg-blue-600 hover:bg-blue-700 text-white font-semibold transition-colors shrink-0"
|
|
1907
|
+
>
|
|
1908
|
+
▶ Launch
|
|
1909
|
+
</button>
|
|
1910
|
+
</div>
|
|
1911
|
+
<!-- Row 1b: exclude folders -->
|
|
1912
|
+
<div class="flex items-start gap-3 px-6 pb-2">
|
|
1913
|
+
<label
|
|
1914
|
+
data-i18n="wc.exclude_label"
|
|
1915
|
+
class="text-xs font-medium text-gray-500 dark:text-gray-400 shrink-0 pt-1.5"
|
|
1916
|
+
>Exclude</label
|
|
1917
|
+
>
|
|
1918
|
+
<textarea
|
|
1919
|
+
id="wc-exclude"
|
|
1920
|
+
rows="3"
|
|
1921
|
+
spellcheck="false"
|
|
1922
|
+
data-i18n-placeholder="wc.exclude_placeholder"
|
|
1923
|
+
placeholder="components/ui, package-lock.json (one per line or comma-separated)"
|
|
1924
|
+
oninput="wcOnExcludeChange()"
|
|
1925
|
+
class="flex-1 px-3 py-1.5 text-sm rounded-lg border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 font-mono focus:outline-none focus:ring-1 focus:ring-blue-400 resize-y"
|
|
1926
|
+
></textarea>
|
|
1927
|
+
<button
|
|
1928
|
+
onclick="wcToggleExcludeBrowser()"
|
|
1929
|
+
class="text-sm px-3 py-1.5 rounded-lg border border-gray-200 dark:border-gray-700 text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors shrink-0"
|
|
1930
|
+
>
|
|
1931
|
+
📁 <span data-i18n="wc.browse_btn">Browse</span>
|
|
1932
|
+
</button>
|
|
1933
|
+
</div>
|
|
1934
|
+
<!-- Row 1c: exclude browser (collapsed by default) -->
|
|
1935
|
+
<div
|
|
1936
|
+
id="wc-exclude-browser"
|
|
1937
|
+
class="hidden border-t border-gray-200 dark:border-gray-700"
|
|
1938
|
+
>
|
|
1939
|
+
<div
|
|
1940
|
+
class="flex items-center gap-2 px-3 py-2 bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700"
|
|
1941
|
+
>
|
|
1942
|
+
<button
|
|
1943
|
+
id="wc-excl-browse-up"
|
|
1944
|
+
onclick="wcExclBrowseUp()"
|
|
1945
|
+
class="text-xs text-blue-600 dark:text-blue-400 hover:underline disabled:opacity-30 disabled:pointer-events-none shrink-0"
|
|
1946
|
+
>
|
|
1947
|
+
↑ Up
|
|
1948
|
+
</button>
|
|
1949
|
+
<span
|
|
1950
|
+
id="wc-excl-browse-path"
|
|
1951
|
+
class="font-mono text-xs text-gray-400 dark:text-gray-500 truncate flex-1 text-right"
|
|
1952
|
+
></span>
|
|
1953
|
+
</div>
|
|
1954
|
+
<div
|
|
1955
|
+
id="wc-excl-browse-list"
|
|
1956
|
+
class="divide-y divide-gray-100 dark:divide-gray-800 max-h-52 overflow-y-auto"
|
|
1957
|
+
></div>
|
|
1958
|
+
</div>
|
|
1959
|
+
<!-- Row 2: extension checkboxes -->
|
|
1960
|
+
<div class="flex items-center gap-x-4 gap-y-2 px-6 pb-3 flex-wrap">
|
|
1961
|
+
<span
|
|
1962
|
+
data-i18n="wc.extensions_label"
|
|
1963
|
+
class="text-xs font-medium text-gray-500 dark:text-gray-400 shrink-0"
|
|
1964
|
+
>Extensions</span
|
|
1965
|
+
>
|
|
1966
|
+
<button
|
|
1967
|
+
onclick="wcToggleAllExts()"
|
|
1968
|
+
id="wcToggleAllBtn"
|
|
1969
|
+
data-i18n="wc.all_btn"
|
|
1970
|
+
class="text-xs text-blue-600 dark:text-blue-400 hover:underline shrink-0"
|
|
1971
|
+
>
|
|
1972
|
+
All
|
|
1973
|
+
</button>
|
|
1974
|
+
<label
|
|
1975
|
+
class="flex items-center gap-1.5 text-xs text-gray-700 dark:text-gray-300 cursor-pointer"
|
|
1976
|
+
><input type="checkbox" class="wc-ext" value="md" checked />
|
|
1977
|
+
.md</label
|
|
1978
|
+
>
|
|
1979
|
+
<label
|
|
1980
|
+
class="flex items-center gap-1.5 text-xs text-gray-700 dark:text-gray-300 cursor-pointer"
|
|
1981
|
+
><input type="checkbox" class="wc-ext" value="mdx" /> .mdx</label
|
|
1982
|
+
>
|
|
1983
|
+
<label
|
|
1984
|
+
class="flex items-center gap-1.5 text-xs text-gray-700 dark:text-gray-300 cursor-pointer"
|
|
1985
|
+
><input type="checkbox" class="wc-ext" value="txt" /> .txt</label
|
|
1986
|
+
>
|
|
1987
|
+
<span class="text-gray-200 dark:text-gray-700 text-xs">|</span>
|
|
1988
|
+
<label
|
|
1989
|
+
class="flex items-center gap-1.5 text-xs text-gray-700 dark:text-gray-300 cursor-pointer"
|
|
1990
|
+
><input type="checkbox" class="wc-ext" value="ts" /> .ts</label
|
|
1991
|
+
>
|
|
1992
|
+
<label
|
|
1993
|
+
class="flex items-center gap-1.5 text-xs text-gray-700 dark:text-gray-300 cursor-pointer"
|
|
1994
|
+
><input type="checkbox" class="wc-ext" value="tsx" /> .tsx</label
|
|
1995
|
+
>
|
|
1996
|
+
<label
|
|
1997
|
+
class="flex items-center gap-1.5 text-xs text-gray-700 dark:text-gray-300 cursor-pointer"
|
|
1998
|
+
><input type="checkbox" class="wc-ext" value="js" /> .js</label
|
|
1999
|
+
>
|
|
2000
|
+
<label
|
|
2001
|
+
class="flex items-center gap-1.5 text-xs text-gray-700 dark:text-gray-300 cursor-pointer"
|
|
2002
|
+
><input type="checkbox" class="wc-ext" value="jsx" /> .jsx</label
|
|
2003
|
+
>
|
|
2004
|
+
<label
|
|
2005
|
+
class="flex items-center gap-1.5 text-xs text-gray-700 dark:text-gray-300 cursor-pointer"
|
|
2006
|
+
><input type="checkbox" class="wc-ext" value="mjs" /> .mjs</label
|
|
2007
|
+
>
|
|
2008
|
+
<span class="text-gray-200 dark:text-gray-700 text-xs">|</span>
|
|
2009
|
+
<label
|
|
2010
|
+
class="flex items-center gap-1.5 text-xs text-gray-700 dark:text-gray-300 cursor-pointer"
|
|
2011
|
+
><input type="checkbox" class="wc-ext" value="java" /> .java</label
|
|
2012
|
+
>
|
|
2013
|
+
<label
|
|
2014
|
+
class="flex items-center gap-1.5 text-xs text-gray-700 dark:text-gray-300 cursor-pointer"
|
|
2015
|
+
><input type="checkbox" class="wc-ext" value="kt" /> .kt</label
|
|
2016
|
+
>
|
|
2017
|
+
<label
|
|
2018
|
+
class="flex items-center gap-1.5 text-xs text-gray-700 dark:text-gray-300 cursor-pointer"
|
|
2019
|
+
><input type="checkbox" class="wc-ext" value="py" /> .py</label
|
|
2020
|
+
>
|
|
2021
|
+
<label
|
|
2022
|
+
class="flex items-center gap-1.5 text-xs text-gray-700 dark:text-gray-300 cursor-pointer"
|
|
2023
|
+
><input type="checkbox" class="wc-ext" value="go" /> .go</label
|
|
2024
|
+
>
|
|
2025
|
+
<label
|
|
2026
|
+
class="flex items-center gap-1.5 text-xs text-gray-700 dark:text-gray-300 cursor-pointer"
|
|
2027
|
+
><input type="checkbox" class="wc-ext" value="rs" /> .rs</label
|
|
2028
|
+
>
|
|
2029
|
+
<label
|
|
2030
|
+
class="flex items-center gap-1.5 text-xs text-gray-700 dark:text-gray-300 cursor-pointer"
|
|
2031
|
+
><input type="checkbox" class="wc-ext" value="cs" /> .cs</label
|
|
2032
|
+
>
|
|
2033
|
+
<label
|
|
2034
|
+
class="flex items-center gap-1.5 text-xs text-gray-700 dark:text-gray-300 cursor-pointer"
|
|
2035
|
+
><input type="checkbox" class="wc-ext" value="swift" />
|
|
2036
|
+
.swift</label
|
|
2037
|
+
>
|
|
2038
|
+
<label
|
|
2039
|
+
class="flex items-center gap-1.5 text-xs text-gray-700 dark:text-gray-300 cursor-pointer"
|
|
2040
|
+
><input type="checkbox" class="wc-ext" value="rb" /> .rb</label
|
|
2041
|
+
>
|
|
2042
|
+
<span class="text-gray-200 dark:text-gray-700 text-xs">|</span>
|
|
2043
|
+
<label
|
|
2044
|
+
class="flex items-center gap-1.5 text-xs text-gray-700 dark:text-gray-300 cursor-pointer"
|
|
2045
|
+
><input type="checkbox" class="wc-ext" value="prisma" />
|
|
2046
|
+
.prisma</label
|
|
2047
|
+
>
|
|
2048
|
+
<label
|
|
2049
|
+
class="flex items-center gap-1.5 text-xs text-gray-700 dark:text-gray-300 cursor-pointer"
|
|
2050
|
+
><input type="checkbox" class="wc-ext" value="graphql" />
|
|
2051
|
+
.graphql</label
|
|
2052
|
+
>
|
|
2053
|
+
<label
|
|
2054
|
+
class="flex items-center gap-1.5 text-xs text-gray-700 dark:text-gray-300 cursor-pointer"
|
|
2055
|
+
><input type="checkbox" class="wc-ext" value="gql" /> .gql</label
|
|
2056
|
+
>
|
|
2057
|
+
<span class="text-gray-200 dark:text-gray-700 text-xs">|</span>
|
|
2058
|
+
<label
|
|
2059
|
+
class="flex items-center gap-1.5 text-xs text-gray-700 dark:text-gray-300 cursor-pointer"
|
|
2060
|
+
><input type="checkbox" class="wc-ext" value="html" /> .html</label
|
|
2061
|
+
>
|
|
2062
|
+
<label
|
|
2063
|
+
class="flex items-center gap-1.5 text-xs text-gray-700 dark:text-gray-300 cursor-pointer"
|
|
2064
|
+
><input type="checkbox" class="wc-ext" value="css" /> .css</label
|
|
2065
|
+
>
|
|
2066
|
+
<label
|
|
2067
|
+
class="flex items-center gap-1.5 text-xs text-gray-700 dark:text-gray-300 cursor-pointer"
|
|
2068
|
+
><input type="checkbox" class="wc-ext" value="scss" /> .scss</label
|
|
2069
|
+
>
|
|
2070
|
+
<span class="text-gray-200 dark:text-gray-700 text-xs">|</span>
|
|
2071
|
+
<label
|
|
2072
|
+
class="flex items-center gap-1.5 text-xs text-gray-700 dark:text-gray-300 cursor-pointer"
|
|
2073
|
+
><input type="checkbox" class="wc-ext" value="yml" /> .yml</label
|
|
2074
|
+
>
|
|
2075
|
+
<label
|
|
2076
|
+
class="flex items-center gap-1.5 text-xs text-gray-700 dark:text-gray-300 cursor-pointer"
|
|
2077
|
+
><input type="checkbox" class="wc-ext" value="yaml" /> .yaml</label
|
|
2078
|
+
>
|
|
2079
|
+
<label
|
|
2080
|
+
class="flex items-center gap-1.5 text-xs text-gray-700 dark:text-gray-300 cursor-pointer"
|
|
2081
|
+
><input type="checkbox" class="wc-ext" value="json" /> .json</label
|
|
2082
|
+
>
|
|
2083
|
+
<label
|
|
2084
|
+
class="flex items-center gap-1.5 text-xs text-gray-700 dark:text-gray-300 cursor-pointer"
|
|
2085
|
+
><input type="checkbox" class="wc-ext" value="xml" /> .xml</label
|
|
2086
|
+
>
|
|
2087
|
+
<label
|
|
2088
|
+
class="flex items-center gap-1.5 text-xs text-gray-700 dark:text-gray-300 cursor-pointer"
|
|
2089
|
+
><input type="checkbox" class="wc-ext" value="toml" /> .toml</label
|
|
2090
|
+
>
|
|
2091
|
+
</div>
|
|
2092
|
+
<!-- Row 3: inline folder browser (collapsed by default) -->
|
|
2093
|
+
<div
|
|
2094
|
+
id="wc-browser"
|
|
2095
|
+
class="hidden border-t border-gray-200 dark:border-gray-700"
|
|
2096
|
+
>
|
|
2097
|
+
<div
|
|
2098
|
+
class="flex items-center gap-2 px-3 py-2 bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700"
|
|
2099
|
+
>
|
|
2100
|
+
<button
|
|
2101
|
+
id="wc-browse-up"
|
|
2102
|
+
onclick="wcBrowseUp()"
|
|
2103
|
+
class="text-xs text-blue-600 dark:text-blue-400 hover:underline disabled:opacity-30 disabled:pointer-events-none shrink-0"
|
|
2104
|
+
>
|
|
2105
|
+
↑ Up
|
|
2106
|
+
</button>
|
|
2107
|
+
<span
|
|
2108
|
+
id="wc-browse-path"
|
|
2109
|
+
class="font-mono text-xs text-gray-400 dark:text-gray-500 truncate flex-1 text-right"
|
|
2110
|
+
></span>
|
|
2111
|
+
</div>
|
|
2112
|
+
<div
|
|
2113
|
+
id="wc-browse-list"
|
|
2114
|
+
class="divide-y divide-gray-100 dark:divide-gray-800 max-h-52 overflow-y-auto"
|
|
2115
|
+
></div>
|
|
2116
|
+
</div>
|
|
2117
|
+
</div>
|
|
2118
|
+
<div id="wc-body" class="flex-1 overflow-hidden flex">
|
|
2119
|
+
<!-- Left sidebar: stats + controls + top-50 words -->
|
|
2120
|
+
<div
|
|
2121
|
+
id="wc-sidebar"
|
|
2122
|
+
class="hidden w-56 shrink-0 border-r border-gray-200 dark:border-gray-800 flex flex-col bg-white dark:bg-gray-900 overflow-hidden"
|
|
2123
|
+
>
|
|
2124
|
+
<div
|
|
2125
|
+
id="wc-stats"
|
|
2126
|
+
class="px-3 py-2 text-xs text-gray-500 dark:text-gray-400 space-y-0.5 border-b border-gray-100 dark:border-gray-800"
|
|
2127
|
+
></div>
|
|
2128
|
+
<div
|
|
2129
|
+
class="px-3 py-2 border-b border-gray-100 dark:border-gray-800 flex items-center gap-2"
|
|
2130
|
+
>
|
|
2131
|
+
<span data-i18n="wc.min_files_label" class="text-xs text-gray-500 dark:text-gray-400 shrink-0"
|
|
2132
|
+
>Min files</span
|
|
2133
|
+
>
|
|
2134
|
+
<input
|
|
2135
|
+
id="wc-min-files"
|
|
2136
|
+
type="number"
|
|
2137
|
+
min="1"
|
|
2138
|
+
max="20"
|
|
2139
|
+
value="1"
|
|
2140
|
+
class="w-12 px-1.5 py-0.5 text-xs rounded border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800 text-gray-800 dark:text-gray-200 focus:outline-none"
|
|
2141
|
+
/>
|
|
2142
|
+
<button
|
|
2143
|
+
onclick="wcApplyFilter()"
|
|
2144
|
+
data-i18n="wc.apply_btn"
|
|
2145
|
+
class="text-xs text-blue-600 dark:text-blue-400 hover:underline"
|
|
2146
|
+
>
|
|
2147
|
+
Apply
|
|
2148
|
+
</button>
|
|
2149
|
+
</div>
|
|
2150
|
+
<p
|
|
2151
|
+
data-i18n="wc.top_words"
|
|
2152
|
+
class="px-3 pt-2 pb-1 text-xs font-semibold text-gray-400 dark:text-gray-600 uppercase tracking-wider"
|
|
2153
|
+
>
|
|
2154
|
+
Top words
|
|
2155
|
+
</p>
|
|
2156
|
+
<div id="wc-top-list" class="flex-1 overflow-y-auto"></div>
|
|
2157
|
+
</div>
|
|
2158
|
+
<!-- Canvas / status area -->
|
|
2159
|
+
<div id="wc-canvas-wrap" class="flex-1 relative overflow-hidden">
|
|
2160
|
+
<p
|
|
2161
|
+
id="wc-status"
|
|
2162
|
+
class="absolute inset-0 flex items-center justify-center text-gray-400 dark:text-gray-500 text-sm animate-pulse"
|
|
2163
|
+
></p>
|
|
2164
|
+
<canvas
|
|
2165
|
+
id="wc-canvas"
|
|
2166
|
+
class="hidden"
|
|
2167
|
+
style="position: absolute; inset: 0"
|
|
2168
|
+
></canvas>
|
|
2169
|
+
</div>
|
|
2170
|
+
<!-- Right detail panel: shown on word click -->
|
|
2171
|
+
<div
|
|
2172
|
+
id="wc-detail"
|
|
2173
|
+
class="hidden w-80 shrink-0 border-l border-gray-200 dark:border-gray-800 flex flex-col bg-white dark:bg-gray-900 overflow-hidden"
|
|
2174
|
+
>
|
|
2175
|
+
<div
|
|
2176
|
+
class="px-3 py-2 border-b border-gray-100 dark:border-gray-800 flex items-center justify-between"
|
|
2177
|
+
>
|
|
2178
|
+
<span
|
|
2179
|
+
id="wc-detail-word"
|
|
2180
|
+
class="font-bold text-sm text-gray-900 dark:text-gray-100"
|
|
2181
|
+
></span>
|
|
2182
|
+
<button
|
|
2183
|
+
onclick="wcCloseDetail()"
|
|
2184
|
+
class="text-gray-400 hover:text-gray-600 dark:hover:text-gray-200 text-xs leading-none"
|
|
2185
|
+
>
|
|
2186
|
+
✕
|
|
2187
|
+
</button>
|
|
2188
|
+
</div>
|
|
2189
|
+
<p
|
|
2190
|
+
data-i18n="wc.found_in"
|
|
2191
|
+
class="px-3 pt-2 pb-1 text-xs font-semibold text-gray-400 dark:text-gray-600 uppercase tracking-wider"
|
|
2192
|
+
>
|
|
2193
|
+
Found in
|
|
2194
|
+
</p>
|
|
2195
|
+
<div
|
|
2196
|
+
id="wc-detail-files"
|
|
2197
|
+
class="flex-1 overflow-y-auto px-3 py-1 space-y-1 text-xs"
|
|
2198
|
+
></div>
|
|
2199
|
+
</div>
|
|
2200
|
+
</div>
|
|
2201
|
+
</div>
|
|
2202
|
+
<!-- All inline logic extracted to modules under src/frontend/*.js -->
|
|
2203
|
+
|
|
2204
|
+
<!-- ── Export modal (Markdown / HTML / PDF) ────────────────────────────── -->
|
|
2205
|
+
<div
|
|
2206
|
+
id="export-modal"
|
|
2207
|
+
class="hidden fixed inset-0 z-50 flex items-center justify-center bg-black/50"
|
|
2208
|
+
>
|
|
2209
|
+
<div class="bg-white dark:bg-gray-900 rounded-xl shadow-xl w-full max-w-sm mx-4 p-6 space-y-4">
|
|
2210
|
+
<!-- Title -->
|
|
2211
|
+
<h3 class="text-base font-semibold text-gray-900 dark:text-gray-50">
|
|
2212
|
+
<i class="fa-solid fa-file-export mr-2 text-blue-500"></i>
|
|
2213
|
+
<span data-i18n="modal.export.title">Export</span>
|
|
2214
|
+
</h3>
|
|
2215
|
+
|
|
2216
|
+
<!-- Tabs -->
|
|
2217
|
+
<div class="flex gap-0 border-b border-gray-200 dark:border-gray-700">
|
|
2218
|
+
<button
|
|
2219
|
+
id="export-tab-markdown"
|
|
2220
|
+
onclick="switchExportTab('markdown')"
|
|
2221
|
+
data-i18n="modal.export.tab_markdown"
|
|
2222
|
+
class="px-4 py-2 text-sm border-b-2 border-blue-500 text-blue-600 dark:text-blue-400 font-semibold transition-colors"
|
|
2223
|
+
>Markdown</button>
|
|
2224
|
+
<button
|
|
2225
|
+
id="export-tab-html"
|
|
2226
|
+
onclick="switchExportTab('html')"
|
|
2227
|
+
data-i18n="modal.export.tab_html"
|
|
2228
|
+
class="px-4 py-2 text-sm text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 transition-colors"
|
|
2229
|
+
>HTML</button>
|
|
2230
|
+
<button
|
|
2231
|
+
id="export-tab-pdf"
|
|
2232
|
+
onclick="switchExportTab('pdf')"
|
|
2233
|
+
data-i18n="modal.export.tab_pdf"
|
|
2234
|
+
class="px-4 py-2 text-sm text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 transition-colors"
|
|
2235
|
+
>PDF</button>
|
|
2236
|
+
</div>
|
|
2237
|
+
|
|
2238
|
+
<!-- Folder list (html tab only) -->
|
|
2239
|
+
<div id="export-folder-section" class="hidden">
|
|
2240
|
+
<div
|
|
2241
|
+
id="export-folder-list"
|
|
2242
|
+
class="max-h-48 overflow-y-auto space-y-0.5 border border-gray-200 dark:border-gray-700 rounded-lg p-2"
|
|
2243
|
+
></div>
|
|
2244
|
+
</div>
|
|
2245
|
+
|
|
2246
|
+
<!-- Markdown tab content -->
|
|
2247
|
+
<div id="export-content-markdown">
|
|
2248
|
+
<p class="text-xs text-gray-500 dark:text-gray-400" data-i18n="modal.export.markdown_hint">
|
|
2249
|
+
Export all documents and images as Markdown files, with internal links rewritten to relative paths.
|
|
2250
|
+
</p>
|
|
2251
|
+
<div class="flex justify-end gap-3 pt-2">
|
|
2252
|
+
<button
|
|
2253
|
+
onclick="closeExportModal()"
|
|
2254
|
+
data-i18n="common.cancel"
|
|
2255
|
+
class="text-sm px-4 py-2 rounded-lg border border-gray-200 dark:border-gray-700 text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
|
|
2256
|
+
>Cancel</button>
|
|
2257
|
+
<button
|
|
2258
|
+
id="export-md-btn"
|
|
2259
|
+
onclick="exportMarkdown()"
|
|
2260
|
+
data-i18n="modal.export.markdown_btn"
|
|
2261
|
+
class="text-sm px-4 py-2 rounded-lg bg-blue-600 hover:bg-blue-700 text-white font-semibold transition-colors"
|
|
2262
|
+
>Export Markdown</button>
|
|
2263
|
+
</div>
|
|
2264
|
+
</div>
|
|
2265
|
+
|
|
2266
|
+
<!-- HTML tab content -->
|
|
2267
|
+
<div id="export-content-html" class="hidden">
|
|
2268
|
+
<p class="text-xs text-gray-500 dark:text-gray-400" data-i18n="modal.export_html.hint">
|
|
2269
|
+
Select the folders to include in the ZIP archive.
|
|
2270
|
+
</p>
|
|
2271
|
+
<div class="flex justify-end gap-3 pt-2">
|
|
2272
|
+
<button
|
|
2273
|
+
onclick="closeExportModal()"
|
|
2274
|
+
data-i18n="common.cancel"
|
|
2275
|
+
class="text-sm px-4 py-2 rounded-lg border border-gray-200 dark:border-gray-700 text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
|
|
2276
|
+
>Cancel</button>
|
|
2277
|
+
<button
|
|
2278
|
+
id="export-notion-btn"
|
|
2279
|
+
onclick="exportHtml('notion')"
|
|
2280
|
+
data-i18n="modal.export_html.notion_btn"
|
|
2281
|
+
class="text-sm px-4 py-2 rounded-lg border border-blue-500 text-blue-600 dark:text-blue-400 hover:bg-blue-50 dark:hover:bg-blue-900/20 font-semibold transition-colors"
|
|
2282
|
+
>Export Notion</button>
|
|
2283
|
+
<button
|
|
2284
|
+
id="export-confluence-btn"
|
|
2285
|
+
onclick="exportHtml('confluence')"
|
|
2286
|
+
data-i18n="modal.export_html.confluence_btn"
|
|
2287
|
+
class="text-sm px-4 py-2 rounded-lg bg-blue-600 hover:bg-blue-700 text-white font-semibold transition-colors"
|
|
2288
|
+
>Export Confluence</button>
|
|
2289
|
+
</div>
|
|
2290
|
+
</div>
|
|
2291
|
+
|
|
2292
|
+
<!-- PDF tab content -->
|
|
2293
|
+
<div id="export-content-pdf" class="hidden">
|
|
2294
|
+
<p class="text-xs text-gray-500 dark:text-gray-400" data-i18n="modal.export.pdf_hint">
|
|
2295
|
+
Export all documents as a single PDF with table of contents.
|
|
2296
|
+
</p>
|
|
2297
|
+
<div class="flex justify-end gap-3 pt-2">
|
|
2298
|
+
<button
|
|
2299
|
+
onclick="closeExportModal()"
|
|
2300
|
+
data-i18n="common.cancel"
|
|
2301
|
+
class="text-sm px-4 py-2 rounded-lg border border-gray-200 dark:border-gray-700 text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
|
|
2302
|
+
>Cancel</button>
|
|
2303
|
+
<button
|
|
2304
|
+
id="export-pdf-btn"
|
|
2305
|
+
onclick="exportAllPdfFromModal()"
|
|
2306
|
+
data-i18n="modal.export.pdf_btn"
|
|
2307
|
+
class="text-sm px-4 py-2 rounded-lg bg-blue-600 hover:bg-blue-700 text-white font-semibold transition-colors"
|
|
2308
|
+
>Export all PDF</button>
|
|
2309
|
+
</div>
|
|
2310
|
+
</div>
|
|
2311
|
+
</div>
|
|
2312
|
+
</div>
|
|
2313
|
+
</body>
|
|
2314
|
+
</html>
|