sdocs-dev 1.3.0 → 1.4.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/public/index.html DELETED
@@ -1,694 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>SDocs</title>
7
- <link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32' fill='none'%3E%3Crect x='2' y='2' width='28' height='28' rx='7' fill='%232563EB' fill-opacity='.15'/%3E%3Crect x='2' y='2' width='28' height='28' rx='7' stroke='%232563EB' stroke-width='2'/%3E%3Cpath d='M9 11h14M9 16h11M9 21h8' stroke='%232563EB' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E">
8
- <link rel="stylesheet" href="/public/css/tokens.css">
9
- <link rel="stylesheet" href="/public/css/layout.css">
10
- <link rel="stylesheet" href="/public/css/rendered.css">
11
- <link rel="stylesheet" href="/public/css/panel.css">
12
- <link rel="stylesheet" href="/public/css/write.css">
13
- <link rel="stylesheet" href="/public/css/mobile.css">
14
- <script nonce="__CSP_NONCE__">
15
- (function(){
16
- var t = localStorage.getItem('sdocs-theme');
17
- if (!t) t = window.matchMedia('(prefers-color-scheme:dark)').matches ? 'dark' : 'light';
18
- if (t === 'dark') document.documentElement.dataset.theme = 'dark';
19
- })();
20
- </script>
21
- </head>
22
- <body>
23
-
24
- <div id="main">
25
- <!-- ── Left panel ── -->
26
- <div id="left">
27
- <div id="left-toolbar">
28
- <a id="toolbar-brand" href="#" title="SDocs — reset to defaults">
29
- <span class="toolbar-brand-text toolbar-brand-full">SmallDocs</span>
30
- <span class="toolbar-brand-text toolbar-brand-short">SDocs</span>
31
- <span class="toolbar-brand-text toolbar-brand-tiny">SD</span>
32
- </a>
33
- <div class="toggle-group">
34
- <button class="btn active" id="btn-read" title="Read">
35
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 7v14"/><path d="M16 12h2"/><path d="M16 8h2"/><path d="M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z"/><path d="M6 12h2"/><path d="M6 8h2"/></svg>
36
- </button>
37
- <button class="btn" id="btn-style" title="Style">
38
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m14.622 17.897-10.68-2.913"/><path d="M18.376 2.622a1 1 0 1 1 3.002 3.002L17.36 9.643a.5.5 0 0 0 0 .707l.944.944a2.41 2.41 0 0 1 0 3.408l-.944.944a.5.5 0 0 1-.707 0L8.354 7.348a.5.5 0 0 1 0-.707l.944-.944a2.41 2.41 0 0 1 3.408 0l.944.944a.5.5 0 0 0 .707 0z"/><path d="M9 8c-1.804 2.71-3.97 3.46-6.583 3.948a.507.507 0 0 0-.302.819l7.32 8.883a1 1 0 0 0 1.185.204C12.735 20.405 16 16.792 16 15"/></svg>
39
- </button>
40
- <button class="btn" id="btn-write" title="Write">
41
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.375 2.625a1 1 0 0 1 3 3l-9.013 9.014a2 2 0 0 1-.853.505l-2.873.84a.5.5 0 0 1-.62-.62l.84-2.873a2 2 0 0 1 .506-.852z"/></svg>
42
- </button>
43
- <button class="btn" id="btn-raw" title="Raw">
44
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>
45
- </button>
46
- <button class="btn" id="btn-export" title="Export">
47
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
48
- </button>
49
- <button class="btn" id="btn-new" title="New document">
50
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M11.35 22H6a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.706.706l3.588 3.588A2.4 2.4 0 0 1 20 8v5.35"/><path d="M14 2v5a1 1 0 0 0 1 1h5"/><path d="M14 19h6"/><path d="M17 16v6"/></svg>
51
- </button>
52
- <span class="write-tb-sep"></span>
53
- <button class="btn" id="btn-theme" title="Toggle dark mode" aria-label="Toggle dark mode">
54
- <svg id="icon-theme" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z" stroke-width="2"/></svg>
55
- </button>
56
- </div>
57
- <span id="drop-hint">
58
- <svg width="12" height="12" viewBox="0 0 12 12" fill="none"><path d="M6 1v7M3.5 5.5L6 8l2.5-2.5M2 10h8" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/></svg>
59
- Drop .md to load
60
- </span>
61
- </div>
62
- <div id="write-toolbar">
63
- <button class="write-tb-btn" id="wb-bold" title="Bold (Ctrl+B)"><strong>B</strong></button>
64
- <button class="write-tb-btn" id="wb-italic" title="Italic (Ctrl+I)"><em>I</em></button>
65
- <button class="write-tb-btn" id="wb-strike" title="Strikethrough (Ctrl+Shift+X)"><s>S</s></button>
66
- <button class="write-tb-btn" id="wb-code" title="Inline code (Ctrl+E)"><code>&lt;/&gt;</code></button>
67
- <span class="write-tb-sep"></span>
68
- <button class="write-tb-btn" id="wb-h1" title="Heading 1">H1</button>
69
- <button class="write-tb-btn" id="wb-h2" title="Heading 2">H2</button>
70
- <button class="write-tb-btn" id="wb-h3" title="Heading 3">H3</button>
71
- <button class="write-tb-btn" id="wb-h4" title="Heading 4">H4</button>
72
- <button class="write-tb-btn" id="wb-h5" title="Heading 5">H5</button>
73
- <button class="write-tb-btn" id="wb-p" title="Normal paragraph">&#182;</button>
74
- <span class="write-tb-sep"></span>
75
- <button class="write-tb-btn" id="wb-ul" title="Bullet list">
76
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><circle cx="3" cy="6" r="1.5" fill="currentColor" stroke="none"/><circle cx="3" cy="12" r="1.5" fill="currentColor" stroke="none"/><circle cx="3" cy="18" r="1.5" fill="currentColor" stroke="none"/></svg>
77
- </button>
78
- <button class="write-tb-btn" id="wb-ol" title="Numbered list">
79
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="10" y1="6" x2="21" y2="6"/><line x1="10" y1="12" x2="21" y2="12"/><line x1="10" y1="18" x2="21" y2="18"/><text x="2" y="8" font-size="8" fill="currentColor" stroke="none" font-family="sans-serif">1</text><text x="2" y="14" font-size="8" fill="currentColor" stroke="none" font-family="sans-serif">2</text><text x="2" y="20" font-size="8" fill="currentColor" stroke="none" font-family="sans-serif">3</text></svg>
80
- </button>
81
- <button class="write-tb-btn" id="wb-bq" title="Blockquote">
82
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="3" y1="4" x2="3" y2="20"/><line x1="9" y1="8" x2="20" y2="8"/><line x1="9" y1="12" x2="18" y2="12"/><line x1="9" y1="16" x2="16" y2="16"/></svg>
83
- </button>
84
- <button class="write-tb-btn" id="wb-codeblock" title="Code block">
85
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>
86
- </button>
87
- <span class="write-tb-sep"></span>
88
- <button class="write-tb-btn" id="wb-link" title="Insert link (Ctrl+K)">
89
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>
90
- </button>
91
- <button class="write-tb-btn" id="wb-image" title="Insert image">
92
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2" ry="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"/></svg>
93
- </button>
94
- <button class="write-tb-btn" id="wb-hr" title="Horizontal rule">&#8212;</button>
95
- <span class="write-tb-sep"></span>
96
- <button class="write-tb-btn" id="wb-clear" title="Clear formatting">
97
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7V4h16v3"/><path d="M9 20h6"/><path d="M12 4v16"/><line x1="4" y1="20" x2="20" y2="4" stroke-width="1.5" opacity="0.5"/></svg>
98
- </button>
99
- </div>
100
- <div id="content-area" tabindex="0">
101
- <div id="file-info-card" hidden>
102
- <div class="fic-rows"></div>
103
- <div class="fic-footer">
104
- <button class="fic-action" id="fic-copy-all" title="Copy the full markdown (body + front matter)">
105
- <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
106
- <span>Copy whole file</span>
107
- </button>
108
- <span class="fic-privacy-note" hidden><span class="fic-local-pill">local only</span> rows aren't included in shared sdocs</span>
109
- </div>
110
- </div>
111
- <div id="rendered"></div>
112
- <div id="write" contenteditable="true" spellcheck="true"></div>
113
- <textarea id="raw" spellcheck="false"></textarea>
114
- </div>
115
- </div>
116
-
117
- <div id="divider"></div>
118
-
119
- <!-- ── Right panel ── -->
120
- <div id="right">
121
- <div id="right-header">Styles</div>
122
-
123
- <!-- GENERAL -->
124
- <div class="panel-section">
125
- <div class="panel-header open" data-target="body-general">
126
- <span class="arrow">
127
- <svg width="10" height="10" viewBox="0 0 10 10" fill="none"><path d="M3 2l4 3-4 3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
128
- </span>
129
- General
130
- </div>
131
- <div class="panel-body open" id="body-general">
132
- <div class="control-row">
133
- <label>Font family</label>
134
- <select id="ctrl-font-family"></select>
135
- </div>
136
- <div class="control-row">
137
- <label>Base size</label>
138
- <input type="range" id="ctrl-base-size-range" min="10" max="28" step="1" value="16">
139
- <input type="number" id="ctrl-base-size-num" min="10" max="28" value="16">
140
- <span class="unit">px</span>
141
- </div>
142
- <div class="control-row">
143
- <label>Line height</label>
144
- <input type="range" id="ctrl-line-height-range" min="1.0" max="2.5" step="0.05" value="1.75">
145
- <input type="number" id="ctrl-line-height-num" min="1.0" max="2.5" step="0.05" value="1.75">
146
- </div>
147
- <button class="factory-reset-btn" id="factory-reset-styles" title="Reset all styles to defaults">Reset all styles</button>
148
- </div>
149
- </div>
150
-
151
- <!-- COLORS -->
152
- <div class="panel-section">
153
- <div class="panel-header" data-target="body-colors">
154
- <span class="arrow">
155
- <svg width="10" height="10" viewBox="0 0 10 10" fill="none"><path d="M3 2l4 3-4 3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
156
- </span>
157
- Colors
158
- </div>
159
- <div class="panel-body" id="body-colors">
160
- <div id="theme-tabs">
161
- <div class="toggle-group">
162
- <button class="btn active" id="theme-tab-light">
163
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>
164
- Light
165
- </button>
166
- <button class="btn" id="theme-tab-dark">
167
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/></svg>
168
- Dark
169
- </button>
170
- </div>
171
- </div>
172
- <div class="control-row">
173
- <label>Background</label>
174
- <div class="color-pair"><input type="color" id="ctrl-bg-color" value="#ffffff"><button class="reset-btn" id="reset-bg-color" title="Reset to default">↺</button></div>
175
- </div>
176
- <div class="control-row">
177
- <label>Text</label>
178
- <div class="color-pair"><input type="color" id="ctrl-color" value="#1c1917"><button class="reset-btn" id="reset-color" title="Reset to default">↺</button></div>
179
- </div>
180
-
181
- <div class="sub-section">
182
- <div class="sub-header" data-target="sub-colors-headings">
183
- <span class="arrow">▶</span> Headings
184
- </div>
185
- <div class="sub-body" id="sub-colors-headings">
186
- <div class="control-row">
187
- <label>All</label>
188
- <div class="color-pair"><input type="color" id="ctrl-h-color" value="#1c1917"><button class="reset-btn" id="reset-h-color" title="Follow body text color">↺</button></div>
189
- </div>
190
- <div class="control-row">
191
- <label>H1</label>
192
- <div class="color-pair"><input type="color" id="ctrl-h1-color" value="#1c1917"><button class="reset-btn" id="reset-h1-color" title="Follow header color">↺</button></div>
193
- </div>
194
- <div class="control-row">
195
- <label>H2</label>
196
- <div class="color-pair"><input type="color" id="ctrl-h2-color" value="#1c1917"><button class="reset-btn" id="reset-h2-color" title="Follow header color">↺</button></div>
197
- </div>
198
- <div class="control-row">
199
- <label>H3</label>
200
- <div class="color-pair"><input type="color" id="ctrl-h3-color" value="#1c1917"><button class="reset-btn" id="reset-h3-color" title="Follow header color">↺</button></div>
201
- </div>
202
- <div class="control-row">
203
- <label>H4</label>
204
- <div class="color-pair"><input type="color" id="ctrl-h4-color" value="#1c1917"><button class="reset-btn" id="reset-h4-color" title="Follow header color">↺</button></div>
205
- </div>
206
- </div>
207
- </div>
208
-
209
- <div class="control-row">
210
- <label>Paragraph</label>
211
- <div class="color-pair"><input type="color" id="ctrl-p-color" value="#1c1917"><button class="reset-btn" id="reset-p-color" title="Follow body text color">↺</button></div>
212
- </div>
213
- <div class="control-row">
214
- <label>Lists</label>
215
- <div class="color-pair"><input type="color" id="ctrl-list-color" value="#1c1917"><button class="reset-btn" id="reset-list-color" title="Follow paragraph color">↺</button></div>
216
- </div>
217
- <div class="control-row">
218
- <label>Link</label>
219
- <div class="color-pair"><input type="color" id="ctrl-link-color" value="#2563eb"><button class="reset-btn" id="reset-link-color" title="Reset to default">↺</button></div>
220
- </div>
221
-
222
- <div class="sub-section">
223
- <div class="sub-header" data-target="sub-colors-blocks">
224
- <span class="arrow">▶</span> Blocks
225
- </div>
226
- <div class="sub-body" id="sub-colors-blocks">
227
- <p style="font-size:11px; color:var(--text-3); margin:0 0 8px; line-height:1.5;">Default for code blocks, blockquotes, and charts. Override individually below.</p>
228
- <div class="control-row">
229
- <label>Background</label>
230
- <div class="color-pair"><input type="color" id="ctrl-block-bg" value="#f4f1ed"><button class="reset-btn" id="reset-block-bg" title="Reset to default">↺</button></div>
231
- </div>
232
- <div class="control-row">
233
- <label>Text</label>
234
- <div class="color-pair"><input type="color" id="ctrl-block-text" value="#6b6560"><button class="reset-btn" id="reset-block-text" title="Reset to default">↺</button></div>
235
- </div>
236
-
237
- <div class="sub-section">
238
- <div class="sub-header" data-target="sub-colors-code">
239
- <span class="arrow">▶</span> Code
240
- </div>
241
- <div class="sub-body" id="sub-colors-code">
242
- <div class="control-row">
243
- <label>Background</label>
244
- <div class="color-pair"><input type="color" id="ctrl-code-bg" value="#f4f1ed"><button class="reset-btn" id="reset-code-bg" title="Follow block background">↺</button></div>
245
- </div>
246
- <div class="control-row">
247
- <label>Text</label>
248
- <div class="color-pair"><input type="color" id="ctrl-code-color" value="#6b21a8"><button class="reset-btn" id="reset-code-color" title="Follow block text">↺</button></div>
249
- </div>
250
- </div>
251
- </div>
252
-
253
- <div class="sub-section">
254
- <div class="sub-header" data-target="sub-colors-bq">
255
- <span class="arrow">▶</span> Blockquote
256
- </div>
257
- <div class="sub-body" id="sub-colors-bq">
258
- <div class="control-row">
259
- <label>Border</label>
260
- <div class="color-pair"><input type="color" id="ctrl-bq-border-color" value="#2563eb"><button class="reset-btn" id="reset-bq-border-color" title="Reset to default">↺</button></div>
261
- </div>
262
- <div class="control-row">
263
- <label>Background</label>
264
- <div class="color-pair"><input type="color" id="ctrl-bq-bg" value="#f7f5f2"><button class="reset-btn" id="reset-bq-bg" title="Follow block background">↺</button></div>
265
- </div>
266
- <div class="control-row">
267
- <label>Text</label>
268
- <div class="color-pair"><input type="color" id="ctrl-bq-color" value="#6b6560"><button class="reset-btn" id="reset-bq-color" title="Follow block text">↺</button></div>
269
- </div>
270
- </div>
271
- </div>
272
-
273
- <div class="sub-section">
274
- <div class="sub-header" data-target="sub-colors-charts">
275
- <span class="arrow">▶</span> Charts
276
- </div>
277
- <div class="sub-body" id="sub-colors-charts">
278
- <div class="control-row">
279
- <label>Background</label>
280
- <div class="color-pair"><input type="color" id="ctrl-chart-bg" value="#f4f1ed"><button class="reset-btn" id="reset-chart-bg" title="Follow block background">↺</button></div>
281
- </div>
282
- <div class="control-row">
283
- <label>Text</label>
284
- <div class="color-pair"><input type="color" id="ctrl-chart-text" value="#78716c"><button class="reset-btn" id="reset-chart-text" title="Follow block text">↺</button></div>
285
- </div>
286
- <div class="control-row">
287
- <label>Accent</label>
288
- <div class="color-pair"><input type="color" id="ctrl-chart-accent" value="#3b82f6"><button class="reset-btn" id="reset-chart-accent" title="Reset to default palette">↺</button></div>
289
- </div>
290
- <div class="control-row">
291
- <label>Palette</label>
292
- <select id="ctrl-chart-palette">
293
- <option value="monochrome" selected>Monochrome</option>
294
- <option value="complementary">Complementary</option>
295
- <option value="analogous">Analogous</option>
296
- <option value="triadic">Triadic</option>
297
- <option value="pastel">Pastel</option>
298
- <option value="warm">Warm</option>
299
- <option value="cool">Cool</option>
300
- <option value="earth">Earth</option>
301
- </select>
302
- </div>
303
- </div>
304
- </div>
305
- </div>
306
- </div>
307
- </div>
308
- </div>
309
-
310
- <!-- HEADERS -->
311
- <div class="panel-section">
312
- <div class="panel-header" data-target="body-headers">
313
- <span class="arrow">
314
- <svg width="10" height="10" viewBox="0 0 10 10" fill="none"><path d="M3 2l4 3-4 3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
315
- </span>
316
- Headers
317
- </div>
318
- <div class="panel-body" id="body-headers">
319
-
320
- <div class="sub-section">
321
- <div class="sub-header" data-target="sub-headers-general">
322
- <span class="arrow">▶</span> General <span class="tag">h1–h4</span>
323
- </div>
324
- <div class="sub-body" id="sub-headers-general">
325
- <div class="control-row">
326
- <label>Font family</label>
327
- <select id="ctrl-h-font-family"><option value="inherit">Same as body</option></select>
328
- </div>
329
- <div class="control-row">
330
- <label>Size scale</label>
331
- <input type="range" id="ctrl-h-scale-range" min="0.5" max="2.0" step="0.05" value="1.0">
332
- <input type="number" id="ctrl-h-scale-num" min="0.5" max="2.0" step="0.05" value="1.0">
333
- </div>
334
- <div class="control-row">
335
- <label>Margin bottom</label>
336
- <input type="range" id="ctrl-h-mb-range" min="0" max="2" step="0.1" value="0.4">
337
- <input type="number" id="ctrl-h-mb-num" min="0" max="2" step="0.1" value="0.4">
338
- <span class="unit">em</span>
339
- </div>
340
- </div>
341
- </div>
342
-
343
- <div class="sub-section">
344
- <div class="sub-header" data-target="sub-h1">
345
- <span class="arrow">▶</span> H1 <span class="tag">h1</span>
346
- </div>
347
- <div class="sub-body" id="sub-h1">
348
- <div class="control-row">
349
- <label>Size</label>
350
- <input type="range" id="ctrl-h1-size-range" min="1" max="4" step="0.1" value="2.1">
351
- <input type="number" id="ctrl-h1-size-num" min="1" max="4" step="0.1" value="2.1">
352
- <span class="unit">em</span>
353
- </div>
354
- <div class="control-row">
355
- <label>Weight</label>
356
- <select id="ctrl-h1-weight">
357
- <option value="400">Regular</option>
358
- <option value="500">Medium</option>
359
- <option value="600">SemiBold</option>
360
- <option value="700" selected>Bold</option>
361
- <option value="800">ExtraBold</option>
362
- </select>
363
- </div>
364
- </div>
365
- </div>
366
-
367
- <div class="sub-section">
368
- <div class="sub-header" data-target="sub-h2">
369
- <span class="arrow">▶</span> H2 <span class="tag">h2</span>
370
- </div>
371
- <div class="sub-body" id="sub-h2">
372
- <div class="control-row">
373
- <label>Size</label>
374
- <input type="range" id="ctrl-h2-size-range" min="1" max="3" step="0.1" value="1.55">
375
- <input type="number" id="ctrl-h2-size-num" min="1" max="3" step="0.1" value="1.55">
376
- <span class="unit">em</span>
377
- </div>
378
- <div class="control-row">
379
- <label>Weight</label>
380
- <select id="ctrl-h2-weight">
381
- <option value="400">Regular</option>
382
- <option value="500">Medium</option>
383
- <option value="600" selected>SemiBold</option>
384
- <option value="700">Bold</option>
385
- </select>
386
- </div>
387
- </div>
388
- </div>
389
-
390
- <div class="sub-section">
391
- <div class="sub-header" data-target="sub-h3">
392
- <span class="arrow">▶</span> H3 <span class="tag">h3</span>
393
- </div>
394
- <div class="sub-body" id="sub-h3">
395
- <div class="control-row">
396
- <label>Size</label>
397
- <input type="range" id="ctrl-h3-size-range" min="0.8" max="2.5" step="0.1" value="1.2">
398
- <input type="number" id="ctrl-h3-size-num" min="0.8" max="2.5" step="0.1" value="1.2">
399
- <span class="unit">em</span>
400
- </div>
401
- <div class="control-row">
402
- <label>Weight</label>
403
- <select id="ctrl-h3-weight">
404
- <option value="400">Regular</option>
405
- <option value="500">Medium</option>
406
- <option value="600" selected>SemiBold</option>
407
- <option value="700">Bold</option>
408
- </select>
409
- </div>
410
- </div>
411
- </div>
412
-
413
- <div class="sub-section">
414
- <div class="sub-header" data-target="sub-h4">
415
- <span class="arrow">▶</span> H4 <span class="tag">h4</span>
416
- </div>
417
- <div class="sub-body" id="sub-h4">
418
- <div class="control-row">
419
- <label>Size</label>
420
- <input type="range" id="ctrl-h4-size-range" min="0.8" max="2" step="0.1" value="1.0">
421
- <input type="number" id="ctrl-h4-size-num" min="0.8" max="2" step="0.1" value="1.0">
422
- <span class="unit">em</span>
423
- </div>
424
- <div class="control-row">
425
- <label>Weight</label>
426
- <select id="ctrl-h4-weight">
427
- <option value="400">Regular</option>
428
- <option value="500">Medium</option>
429
- <option value="600" selected>SemiBold</option>
430
- <option value="700">Bold</option>
431
- </select>
432
- </div>
433
- </div>
434
- </div>
435
-
436
- </div>
437
- </div>
438
-
439
- <!-- PARAGRAPH -->
440
- <div class="panel-section">
441
- <div class="panel-header" data-target="body-paragraph">
442
- <span class="arrow">
443
- <svg width="10" height="10" viewBox="0 0 10 10" fill="none"><path d="M3 2l4 3-4 3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
444
- </span>
445
- Paragraph
446
- </div>
447
- <div class="panel-body" id="body-paragraph">
448
- <div class="control-row">
449
- <label>Line height</label>
450
- <input type="range" id="ctrl-p-lh-range" min="1.0" max="2.5" step="0.05" value="1.75">
451
- <input type="number" id="ctrl-p-lh-num" min="1.0" max="2.5" step="0.05" value="1.75">
452
- </div>
453
- <div class="control-row">
454
- <label>Margin bottom</label>
455
- <input type="range" id="ctrl-p-mb-range" min="0" max="3" step="0.1" value="1.1">
456
- <input type="number" id="ctrl-p-mb-num" min="0" max="3" step="0.1" value="1.1">
457
- <span class="unit">em</span>
458
- </div>
459
- </div>
460
- </div>
461
-
462
- <!-- LISTS -->
463
- <div class="panel-section">
464
- <div class="panel-header" data-target="body-lists">
465
- <span class="arrow">
466
- <svg width="10" height="10" viewBox="0 0 10 10" fill="none"><path d="M3 2l4 3-4 3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
467
- </span>
468
- Lists
469
- </div>
470
- <div class="panel-body" id="body-lists">
471
- <div class="control-row">
472
- <label>Item spacing</label>
473
- <input type="range" id="ctrl-list-spacing-range" min="0" max="1.5" step="0.05" value="0.3">
474
- <input type="number" id="ctrl-list-spacing-num" min="0" max="1.5" step="0.05" value="0.3">
475
- <span class="unit">em</span>
476
- </div>
477
- <div class="control-row">
478
- <label>Indent</label>
479
- <input type="range" id="ctrl-list-indent-range" min="0.5" max="3" step="0.1" value="1.6">
480
- <input type="number" id="ctrl-list-indent-num" min="0.5" max="3" step="0.1" value="1.6">
481
- <span class="unit">em</span>
482
- </div>
483
- </div>
484
- </div>
485
-
486
- <!-- LINKS -->
487
- <div class="panel-section">
488
- <div class="panel-header" data-target="body-links">
489
- <span class="arrow">
490
- <svg width="10" height="10" viewBox="0 0 10 10" fill="none"><path d="M3 2l4 3-4 3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
491
- </span>
492
- Links
493
- </div>
494
- <div class="panel-body" id="body-links">
495
- <div class="control-row">
496
- <label>Decoration</label>
497
- <select id="ctrl-link-decoration">
498
- <option value="underline" selected>Underline</option>
499
- <option value="none">None</option>
500
- <option value="dotted underline">Dotted</option>
501
- <option value="dashed underline">Dashed</option>
502
- </select>
503
- </div>
504
- </div>
505
- </div>
506
-
507
- <!-- CODE -->
508
- <div class="panel-section">
509
- <div class="panel-header" data-target="body-code">
510
- <span class="arrow">
511
- <svg width="10" height="10" viewBox="0 0 10 10" fill="none"><path d="M3 2l4 3-4 3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
512
- </span>
513
- Code
514
- </div>
515
- <div class="panel-body" id="body-code">
516
- <div class="control-row">
517
- <label>Font family</label>
518
- <select id="ctrl-code-font">
519
- <option value="'JetBrains Mono', 'Fira Mono', monospace" selected>JetBrains Mono</option>
520
- <option value="'Fira Mono', monospace">Fira Mono</option>
521
- <option value="'Source Code Pro', monospace">Source Code Pro</option>
522
- <option value="'Courier New', monospace">Courier New</option>
523
- <option value="monospace">System mono</option>
524
- </select>
525
- </div>
526
- </div>
527
- </div>
528
-
529
- <!-- BLOCKQUOTE -->
530
- <div class="panel-section">
531
- <div class="panel-header" data-target="body-blockquote">
532
- <span class="arrow">
533
- <svg width="10" height="10" viewBox="0 0 10 10" fill="none"><path d="M3 2l4 3-4 3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
534
- </span>
535
- Blockquote
536
- </div>
537
- <div class="panel-body" id="body-blockquote">
538
- <div class="control-row">
539
- <label>Border width</label>
540
- <input type="range" id="ctrl-bq-bw-range" min="1" max="8" step="1" value="3">
541
- <input type="number" id="ctrl-bq-bw-num" min="1" max="8" value="3">
542
- <span class="unit">px</span>
543
- </div>
544
- <div class="control-row">
545
- <label>Font size</label>
546
- <input type="range" id="ctrl-bq-size-range" min="0.7" max="1.5" step="0.05" value="1.0">
547
- <input type="number" id="ctrl-bq-size-num" min="0.7" max="1.5" step="0.05" value="1.0">
548
- <span class="unit">em</span>
549
- </div>
550
- </div>
551
- </div>
552
-
553
- <!-- SAVE AS DEFAULT -->
554
- <div class="panel-section">
555
- <div class="panel-header" data-target="body-save-default" style="color: var(--accent-text);">
556
- <span class="arrow">
557
- <svg width="10" height="10" viewBox="0 0 10 10" fill="none"><path d="M3 2l4 3-4 3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
558
- </span>
559
- Save as default styles
560
- </div>
561
- <div class="panel-body" id="body-save-default">
562
- <ul style="font-size:11.5px; color:var(--text-2); margin:0 0 10px; padding-left:1.2em; line-height:1.6; list-style:disc;">
563
- <li>Requires <strong>sdocs-dev</strong> CLI
564
- <ul style="padding-left:1.2em; margin:2px 0 0; list-style:circle;">
565
- <li style="color:var(--text-3);">Install: <code style="font-size:10px; background:var(--bg-surface); border:1px solid var(--border); border-radius:3px; padding:1px 4px;">npm link</code> from project root</li>
566
- </ul>
567
- </li>
568
- <li>Saves to <code style="font-size:10px; background:var(--bg-surface); border:1px solid var(--border); border-radius:3px; padding:1px 4px;">~/.sdocs/styles.yaml</code></li>
569
- <li>Paste the command below in your terminal</li>
570
- </ul>
571
- <div style="display:flex; gap:6px; margin-bottom:8px;">
572
- <button class="btn" id="btn-copy-default" style="flex:1; justify-content:center;">
573
- <svg width="12" height="12" viewBox="0 0 12 12" fill="none"><rect x="3.5" y="3.5" width="7" height="7" rx="1" stroke="currentColor" stroke-width="1.3"/><path d="M8.5 3.5V2a1 1 0 00-1-1H2a1 1 0 00-1 1v5.5a1 1 0 001 1h1.5" stroke="currentColor" stroke-width="1.3"/></svg>
574
- Copy
575
- </button>
576
- </div>
577
- <pre id="save-default-display" style="font-size:10.5px; line-height:1.55; background:var(--bg-input); border:1px solid var(--border); border-radius:var(--radius); padding:10px; overflow-x:auto; white-space:pre-wrap; word-break:break-all; color:var(--text-2); margin:0;"></pre>
578
- <div id="save-default-msg" style="display:none; margin-top:6px; font-size:11px; color:var(--accent-text); text-align:center;"></div>
579
- </div>
580
- </div>
581
-
582
- </div><!-- /#right -->
583
-
584
- <!-- ── Export panel ── -->
585
- <div id="export-panel">
586
- <div id="export-panel-header">Export</div>
587
- <div id="export-panel-body">
588
- <button class="export-option" id="exp-pdf">
589
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="2" width="12" height="16" rx="2"/><path d="M8 2v4h8"/><path d="M4 14h16" stroke-dasharray="2 2"/><path d="M8 19h8"/></svg>
590
- <div class="export-option-text">
591
- <span class="export-option-title">PDF</span>
592
- <span class="export-option-desc">Opens print dialog for PDF save</span>
593
- </div>
594
- </button>
595
- <button class="export-option" id="exp-word">
596
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="2" width="12" height="16" rx="2"/><path d="M8 2v4h8"/><path d="M8 12l1.5 4 2-3 2 3 1.5-4"/></svg>
597
- <div class="export-option-text">
598
- <span class="export-option-title">Word (.docx)</span>
599
- <span class="export-option-desc">Download as Word document</span>
600
- </div>
601
- </button>
602
- <button class="export-option" id="exp-raw">
603
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z"/><polyline points="14 2 14 8 20 8"/></svg>
604
- <div class="export-option-text">
605
- <span class="export-option-title">.md</span>
606
- <span class="export-option-desc">Plain markdown, no styles</span>
607
- </div>
608
- </button>
609
- <button class="export-option" id="exp-styled">
610
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z"/><polyline points="14 2 14 8 20 8"/><path d="M9 15h6"/><path d="M9 11h6"/></svg>
611
- <div class="export-option-text">
612
- <span class="export-option-title">Styled .md</span>
613
- <span class="export-option-desc">Markdown with YAML front matter styles</span>
614
- </div>
615
- </button>
616
- </div>
617
- </div>
618
- </div><!-- /#main -->
619
-
620
- <!-- Status bar -->
621
- <div id="statusbar">
622
- <span id="status-text"></span>
623
- <span style="margin-left:auto; font-size:10.5px; color:var(--text-2); display:flex; align-items:center; gap:4px; flex-wrap:wrap; justify-content:flex-end">
624
- <span>100% private (<a href="https://sdocs.dev/#sec=privacy" target="_blank" rel="noopener" style="color:var(--text-2); text-decoration:underline">learn why</a>)</span>
625
- · CLI for you &amp; your agents: <span id="cli-install-wrap" style="display:inline-flex; align-items:center; gap:3px; cursor:pointer" title="Click to copy install command"><code id="cli-install-cmd" style="background:var(--bg-surface); border:1px solid var(--md-link-color, #2563eb); border-radius:3px; padding:1px 5px; font-size:10px; color:var(--md-link-color, #2563eb)">npm i -g sdocs-dev</code><button id="cli-copy-btn" style="background:none; border:none; cursor:pointer; color:var(--md-link-color, #2563eb); padding:0; vertical-align:middle; opacity:0.5; transition:opacity .15s"><svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg></button></span>
626
- · <a href="https://github.com/JoshInLisbon/SDocs" target="_blank" rel="noopener" style="color:var(--text-2); text-decoration:underline">GitHub</a>
627
- </span>
628
- </div>
629
- <style>
630
- #cli-install-wrap:hover #cli-copy-btn { opacity: 1 !important; }
631
- </style>
632
- <script nonce="__CSP_NONCE__">
633
- (function () {
634
- var COPY_ICON = '<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>';
635
- var CHECK_ICON = '<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>';
636
- var wrap = document.getElementById('cli-install-wrap');
637
- var btn = document.getElementById('cli-copy-btn');
638
- if (wrap && btn) wrap.addEventListener('click', function () {
639
- navigator.clipboard.writeText('npm i -g sdocs-dev').then(function () {
640
- btn.innerHTML = CHECK_ICON;
641
- setTimeout(function () { btn.innerHTML = COPY_ICON; }, 1500);
642
- });
643
- });
644
- })();
645
- </script>
646
-
647
- <script src="/public/brotli-wasm-v1.js"></script>
648
- <script src="/public/vendor/marked.min.js"></script>
649
- <script src="/public/vendor/purify.min.js"></script>
650
- <script src="/public/sdocs-yaml.js"></script>
651
- <script src="/public/sdocs-styles.js"></script>
652
- <script src="/public/sdocs-state.js"></script>
653
- <script src="/public/sdocs-slugify.js"></script>
654
- <script src="/public/sdocs-theme.js"></script>
655
- <script src="/public/sdocs-controls.js"></script>
656
- <script src="/public/sdocs-export.js"></script>
657
- <script src="/public/sdocs-write.js"></script>
658
- <script src="/public/sdocs-charts.js"></script>
659
- <script src="/public/sdocs-app.js"></script>
660
- <script nonce="__CSP_NONCE__">
661
- var APP_VERSION = '__APP_VERSION__';
662
- var SDOCS_DEV = '__SDOCS_DEV__' === '1';
663
- // Cohort: store the ISO week of first visit for retention tracking.
664
- // Not a unique ID — groups all visitors who first came the same week.
665
- if (!localStorage.getItem('sdocs_cohort')) {
666
- try {
667
- var _d = new Date(), _u = new Date(Date.UTC(_d.getFullYear(), _d.getMonth(), _d.getDate()));
668
- var _dn = _u.getUTCDay() || 7;
669
- _u.setUTCDate(_u.getUTCDate() + 4 - _dn);
670
- var _ys = new Date(Date.UTC(_u.getUTCFullYear(), 0, 1));
671
- var _wn = Math.ceil((((_u - _ys) / 86400000) + 1) / 7);
672
- localStorage.setItem('sdocs_cohort', _u.getUTCFullYear() + '-W' + String(_wn).padStart(2, '0'));
673
- } catch (e) { /* private browsing or storage disabled */ }
674
- }
675
- if (SDOCS_DEV && 'serviceWorker' in navigator) {
676
- // Dev mode: unregister any existing SW and clear caches so edits are picked up instantly.
677
- navigator.serviceWorker.getRegistrations().then(function (regs) {
678
- regs.forEach(function (r) { r.unregister(); });
679
- });
680
- if (window.caches) caches.keys().then(function (ks) { ks.forEach(function (k) { caches.delete(k); }); });
681
- } else if ('serviceWorker' in navigator) {
682
- var _cohort = '';
683
- try { _cohort = localStorage.getItem('sdocs_cohort') || ''; } catch (e) {}
684
- navigator.serviceWorker.register('/sw.js').then(function (reg) {
685
- var msg = { type: 'check-update', version: APP_VERSION, cohort: _cohort };
686
- if (reg.active) reg.active.postMessage(msg);
687
- navigator.serviceWorker.addEventListener('controllerchange', function () {
688
- if (navigator.serviceWorker.controller) navigator.serviceWorker.controller.postMessage(msg);
689
- });
690
- });
691
- }
692
- </script>
693
- </body>
694
- </html>