@mattli/dotmd 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/cli/commands/init.d.ts.map +1 -1
  2. package/dist/cli/commands/init.js +12 -7
  3. package/dist/cli/commands/init.js.map +1 -1
  4. package/dist/cli/commands/serve.d.ts.map +1 -1
  5. package/dist/cli/commands/serve.js +18 -1
  6. package/dist/cli/commands/serve.js.map +1 -1
  7. package/dist/cli/commands/status.d.ts.map +1 -1
  8. package/dist/cli/commands/status.js +10 -5
  9. package/dist/cli/commands/status.js.map +1 -1
  10. package/dist/dashboard/_archive/wizard-client.d.ts +2 -0
  11. package/dist/dashboard/_archive/wizard-client.d.ts.map +1 -0
  12. package/dist/dashboard/_archive/wizard-client.js +412 -0
  13. package/dist/dashboard/_archive/wizard-client.js.map +1 -0
  14. package/dist/dashboard/_archive/wizard.d.ts +9 -0
  15. package/dist/dashboard/_archive/wizard.d.ts.map +1 -0
  16. package/dist/dashboard/_archive/wizard.js +317 -0
  17. package/dist/dashboard/_archive/wizard.js.map +1 -0
  18. package/dist/dashboard/help.d.ts +2 -0
  19. package/dist/dashboard/help.d.ts.map +1 -0
  20. package/dist/dashboard/help.js +73 -0
  21. package/dist/dashboard/help.js.map +1 -0
  22. package/dist/dashboard/layout.d.ts.map +1 -1
  23. package/dist/dashboard/layout.js +1 -0
  24. package/dist/dashboard/layout.js.map +1 -1
  25. package/dist/dashboard/server.d.ts +1 -1
  26. package/dist/dashboard/server.d.ts.map +1 -1
  27. package/dist/dashboard/server.js +39 -51
  28. package/dist/dashboard/server.js.map +1 -1
  29. package/dist/dashboard/settings-client.d.ts +1 -1
  30. package/dist/dashboard/settings-client.d.ts.map +1 -1
  31. package/dist/dashboard/settings-client.js +367 -162
  32. package/dist/dashboard/settings-client.js.map +1 -1
  33. package/dist/dashboard/settings.d.ts +5 -1
  34. package/dist/dashboard/settings.d.ts.map +1 -1
  35. package/dist/dashboard/settings.js +60 -45
  36. package/dist/dashboard/settings.js.map +1 -1
  37. package/dist/dashboard/wizard-client.d.ts +1 -1
  38. package/dist/dashboard/wizard-client.d.ts.map +1 -1
  39. package/dist/dashboard/wizard-client.js +226 -80
  40. package/dist/dashboard/wizard-client.js.map +1 -1
  41. package/dist/dashboard/wizard.d.ts +2 -2
  42. package/dist/dashboard/wizard.d.ts.map +1 -1
  43. package/dist/dashboard/wizard.js +113 -32
  44. package/dist/dashboard/wizard.js.map +1 -1
  45. package/package.json +1 -1
@@ -9,59 +9,296 @@ document.addEventListener('DOMContentLoaded', function() {
9
9
  return div.innerHTML;
10
10
  }
11
11
 
12
- // --- Chip toggling ---
13
- function initChipToggling(container) {
14
- if (!container) return;
15
- container.querySelectorAll('[data-chip]').forEach(function(chip) {
16
- chip.addEventListener('click', function() {
17
- var isSelected = chip.getAttribute('data-selected') === 'true';
18
- chip.setAttribute('data-selected', isSelected ? 'false' : 'true');
19
- if (isSelected) {
20
- chip.classList.remove('bg-blue-100', 'text-blue-800', 'border-blue-300');
21
- chip.classList.add('bg-gray-100', 'text-gray-600', 'border-gray-300');
22
- } else {
23
- chip.classList.remove('bg-gray-100', 'text-gray-600', 'border-gray-300');
24
- chip.classList.add('bg-blue-100', 'text-blue-800', 'border-blue-300');
12
+ // ===== Folder management =====
13
+
14
+ var folderList = document.getElementById('folder-list');
15
+ var noFoldersMsg = document.getElementById('no-folders-msg');
16
+
17
+ function getAddedFolders() {
18
+ var folders = [];
19
+ if (!folderList) return folders;
20
+ folderList.querySelectorAll('[data-folder-chip]').forEach(function(chip) {
21
+ folders.push(chip.getAttribute('data-folder-chip'));
22
+ });
23
+ return folders;
24
+ }
25
+
26
+ function isFolderAdded(folderPath) {
27
+ var folders = getAddedFolders();
28
+ for (var i = 0; i < folders.length; i++) {
29
+ if (folders[i] === folderPath) return true;
30
+ }
31
+ return false;
32
+ }
33
+
34
+ function isCoveredByParent(folderPath) {
35
+ var folders = getAddedFolders();
36
+ for (var i = 0; i < folders.length; i++) {
37
+ if (folderPath !== folders[i] && folderPath.indexOf(folders[i] + '/') === 0) return true;
38
+ }
39
+ return false;
40
+ }
41
+
42
+ function updateNoFoldersMsg() {
43
+ if (!noFoldersMsg) return;
44
+ if (getAddedFolders().length === 0) {
45
+ noFoldersMsg.classList.remove('hidden');
46
+ } else {
47
+ noFoldersMsg.classList.add('hidden');
48
+ }
49
+ }
50
+
51
+ function removeFolderChip(chip) {
52
+ chip.remove();
53
+ updateNoFoldersMsg();
54
+ scheduleRefresh();
55
+ }
56
+
57
+ function addFolderChip(folderPath) {
58
+ if (!folderList) return;
59
+ if (isFolderAdded(folderPath)) return;
60
+
61
+ var tag = document.createElement('span');
62
+ tag.setAttribute('data-folder-chip', folderPath);
63
+ tag.className = 'inline-flex items-center gap-1 px-3 py-1.5 rounded-full text-sm font-medium bg-blue-100 text-blue-800 border border-blue-300';
64
+ tag.innerHTML = escapeHtml(folderPath) + ' <button type="button" class="ml-1 text-blue-500 hover:text-blue-700 font-bold">&times;</button>';
65
+ tag.querySelector('button').addEventListener('click', function() {
66
+ removeFolderChip(tag);
67
+ });
68
+ folderList.appendChild(tag);
69
+ updateNoFoldersMsg();
70
+ scheduleRefresh();
71
+ }
72
+
73
+ // Wire up x buttons on server-rendered folder chips
74
+ if (folderList) {
75
+ folderList.querySelectorAll('[data-folder-chip] button').forEach(function(btn) {
76
+ btn.addEventListener('click', function() {
77
+ removeFolderChip(btn.parentElement);
78
+ });
79
+ });
80
+ }
81
+
82
+ // ===== Folder browser =====
83
+
84
+ var openBrowserBtn = document.getElementById('open-browser');
85
+ var folderBrowser = document.getElementById('folder-browser');
86
+ var browserPath = document.getElementById('browser-path');
87
+ var browserList = document.getElementById('browser-list');
88
+ var browserUp = document.getElementById('browser-up');
89
+
90
+ function loadBrowserDir(dir) {
91
+ fetch('/api/setup/browse?dir=' + encodeURIComponent(dir || '~'))
92
+ .then(function(res) { return res.json(); })
93
+ .then(function(data) {
94
+ if (data.error) return;
95
+ currentBrowseDir = data.current;
96
+ if (browserPath) browserPath.textContent = data.current;
97
+ if (browserUp) {
98
+ browserUp.style.display = data.parent ? '' : 'none';
99
+ browserUp.onclick = function() { loadBrowserDir(data.parent); };
25
100
  }
26
- scheduleRefresh();
101
+ if (!browserList) return;
102
+ browserList.innerHTML = '';
103
+
104
+ data.dirs.forEach(function(entry) {
105
+ var added = isFolderAdded(entry.path);
106
+ var covered = isCoveredByParent(entry.path);
107
+
108
+ var row = document.createElement('div');
109
+ row.className = 'px-4 py-2 hover:bg-gray-50 flex items-center gap-2 text-sm';
110
+
111
+ var folderIcon = document.createElement('span');
112
+ folderIcon.innerHTML = '&#128193;';
113
+ folderIcon.className = covered ? 'text-gray-300' : 'text-gray-400';
114
+
115
+ var nameSpan = document.createElement('span');
116
+ nameSpan.textContent = entry.name;
117
+ nameSpan.className = covered
118
+ ? 'cursor-pointer flex-1 text-gray-300'
119
+ : 'cursor-pointer flex-1 hover:text-blue-600';
120
+ nameSpan.addEventListener('click', function() {
121
+ loadBrowserDir(entry.path);
122
+ });
123
+
124
+ row.appendChild(folderIcon);
125
+ row.appendChild(nameSpan);
126
+
127
+ if (added) {
128
+ var removeBtn = document.createElement('button');
129
+ removeBtn.textContent = 'Remove';
130
+ removeBtn.type = 'button';
131
+ removeBtn.className = 'text-red-500 hover:text-red-700 text-xs font-medium flex-shrink-0';
132
+ removeBtn.addEventListener('click', function(e) {
133
+ e.stopPropagation();
134
+ var chips = folderList.querySelectorAll('[data-folder-chip]');
135
+ for (var i = 0; i < chips.length; i++) {
136
+ if (chips[i].getAttribute('data-folder-chip') === entry.path) {
137
+ removeFolderChip(chips[i]);
138
+ break;
139
+ }
140
+ }
141
+ loadBrowserDir(currentBrowseDir);
142
+ });
143
+ row.appendChild(removeBtn);
144
+ } else if (!covered) {
145
+ var addBtn = document.createElement('button');
146
+ addBtn.textContent = 'Add';
147
+ addBtn.type = 'button';
148
+ addBtn.className = 'text-blue-600 hover:text-blue-800 text-xs font-medium flex-shrink-0';
149
+ addBtn.addEventListener('click', function(e) {
150
+ e.stopPropagation();
151
+ addFolderChip(entry.path);
152
+ loadBrowserDir(currentBrowseDir);
153
+ });
154
+ row.appendChild(addBtn);
155
+ }
156
+
157
+ browserList.appendChild(row);
158
+ });
27
159
  });
160
+ }
161
+
162
+ if (openBrowserBtn && folderBrowser) {
163
+ openBrowserBtn.addEventListener('click', function() {
164
+ var isHidden = folderBrowser.classList.contains('hidden');
165
+ if (isHidden) {
166
+ folderBrowser.classList.remove('hidden');
167
+ openBrowserBtn.textContent = 'Hide browser';
168
+ loadBrowserDir('~');
169
+ } else {
170
+ folderBrowser.classList.add('hidden');
171
+ openBrowserBtn.textContent = 'Browse for folder...';
172
+ }
28
173
  });
29
174
  }
30
175
 
31
- initChipToggling(document.getElementById('roots-list'));
32
- initChipToggling(document.getElementById('patterns-list'));
176
+ // ===== Pattern management =====
33
177
 
34
- // --- Collect selected values ---
35
- function getSelectedRoots() {
178
+ var patternList = document.getElementById('pattern-list');
179
+ var suggestedPatternsDiv = document.getElementById('suggested-patterns');
180
+ var noPatternsMsg = document.getElementById('no-patterns-msg');
181
+
182
+ function getSelectedPatterns() {
36
183
  var values = [];
37
- document.getElementById('roots-list').querySelectorAll('[data-chip][data-selected="true"]').forEach(function(chip) {
38
- values.push(chip.getAttribute('data-value'));
39
- });
40
- document.getElementById('roots-list').querySelectorAll('[data-custom-value]').forEach(function(tag) {
41
- values.push(tag.getAttribute('data-custom-value'));
184
+ if (!patternList) return values;
185
+ patternList.querySelectorAll('[data-pattern-chip]').forEach(function(chip) {
186
+ values.push(chip.getAttribute('data-pattern-chip'));
42
187
  });
43
188
  return values;
44
189
  }
45
190
 
46
- function getSelectedPatterns() {
47
- var values = [];
48
- document.getElementById('patterns-list').querySelectorAll('[data-chip][data-selected="true"]').forEach(function(chip) {
49
- values.push(chip.getAttribute('data-value'));
191
+ function updateNoPatternsMsg() {
192
+ if (!noPatternsMsg) return;
193
+ if (getSelectedPatterns().length === 0) {
194
+ noPatternsMsg.classList.remove('hidden');
195
+ } else {
196
+ noPatternsMsg.classList.add('hidden');
197
+ }
198
+ }
199
+
200
+ function removePatternChip(chip) {
201
+ var value = chip.getAttribute('data-pattern-chip');
202
+ chip.remove();
203
+ // If it's a suggested pattern, unhide it in the suggestions section
204
+ if (suggestedPatternsDiv && value) {
205
+ var suggestions = suggestedPatternsDiv.querySelectorAll('[data-suggested-pattern]');
206
+ for (var i = 0; i < suggestions.length; i++) {
207
+ if (suggestions[i].getAttribute('data-suggested-pattern') === value) {
208
+ suggestions[i].classList.remove('hidden');
209
+ // Show the suggestions section
210
+ var section = document.getElementById('suggestions-section');
211
+ if (section) section.classList.remove('hidden');
212
+ break;
213
+ }
214
+ }
215
+ }
216
+ updateNoPatternsMsg();
217
+ scheduleRefresh();
218
+ }
219
+
220
+ function addPatternChip(value) {
221
+ if (!patternList) return;
222
+ // Check for duplicates
223
+ var existing = patternList.querySelectorAll('[data-pattern-chip]');
224
+ for (var i = 0; i < existing.length; i++) {
225
+ if (existing[i].getAttribute('data-pattern-chip') === value) return;
226
+ }
227
+
228
+ var tag = document.createElement('span');
229
+ tag.setAttribute('data-pattern-chip', value);
230
+ tag.className = 'inline-flex items-center gap-1 px-3 py-1.5 rounded-full text-sm font-medium bg-blue-100 text-blue-800 border border-blue-300';
231
+ tag.innerHTML = escapeHtml(value) + ' <button type="button" class="ml-1 text-blue-500 hover:text-blue-700 font-bold">&times;</button>';
232
+ tag.querySelector('button').addEventListener('click', function() {
233
+ removePatternChip(tag);
50
234
  });
51
- document.getElementById('patterns-list').querySelectorAll('[data-custom-value]').forEach(function(tag) {
52
- values.push(tag.getAttribute('data-custom-value'));
235
+ patternList.appendChild(tag);
236
+ updateNoPatternsMsg();
237
+ scheduleRefresh();
238
+ }
239
+
240
+ // Wire up x buttons on server-rendered pattern chips
241
+ if (patternList) {
242
+ patternList.querySelectorAll('[data-pattern-chip] button').forEach(function(btn) {
243
+ btn.addEventListener('click', function() {
244
+ removePatternChip(btn.parentElement);
245
+ });
53
246
  });
54
- return values;
55
247
  }
56
248
 
57
- // --- Auto-refresh file preview ---
249
+ // Wire up suggested pattern chips — click to add
250
+ if (suggestedPatternsDiv) {
251
+ suggestedPatternsDiv.querySelectorAll('[data-suggested-pattern]').forEach(function(chip) {
252
+ chip.addEventListener('click', function() {
253
+ var value = chip.getAttribute('data-suggested-pattern');
254
+ addPatternChip(value);
255
+ chip.classList.add('hidden');
256
+ // Hide suggestions section if all hidden
257
+ var anyVisible = false;
258
+ suggestedPatternsDiv.querySelectorAll('[data-suggested-pattern]').forEach(function(s) {
259
+ if (!s.classList.contains('hidden')) anyVisible = true;
260
+ });
261
+ if (!anyVisible) {
262
+ var section = document.getElementById('suggestions-section');
263
+ if (section) section.classList.add('hidden');
264
+ }
265
+ });
266
+ });
267
+ }
268
+
269
+ // Custom pattern input
270
+ var addCustomBtn = document.getElementById('add-custom');
271
+ var customInput = document.getElementById('custom-input');
272
+
273
+ function addCustomPattern() {
274
+ if (!customInput) return;
275
+ var value = customInput.value.trim();
276
+ if (!value) return;
277
+ addPatternChip(value);
278
+ customInput.value = '';
279
+ }
280
+
281
+ if (addCustomBtn) {
282
+ addCustomBtn.addEventListener('click', addCustomPattern);
283
+ }
284
+ if (customInput) {
285
+ customInput.addEventListener('keydown', function(e) {
286
+ if (e.key === 'Enter') {
287
+ e.preventDefault();
288
+ addCustomPattern();
289
+ }
290
+ });
291
+ }
292
+
293
+ // ===== File preview =====
294
+
58
295
  function scheduleRefresh() {
59
296
  clearTimeout(debounceTimer);
60
297
  debounceTimer = setTimeout(refreshPreview, 300);
61
298
  }
62
299
 
63
300
  function refreshPreview() {
64
- var roots = getSelectedRoots();
301
+ var roots = getAddedFolders();
65
302
  var patterns = getSelectedPatterns();
66
303
  var preview = document.getElementById('file-preview');
67
304
 
@@ -94,7 +331,7 @@ document.addEventListener('DOMContentLoaded', function() {
94
331
  return;
95
332
  }
96
333
 
97
- // Group by root (provided by server)
334
+ // Group by root
98
335
  var groups = {};
99
336
  var rootOrder = [];
100
337
  files.forEach(function(f) {
@@ -106,173 +343,130 @@ document.addEventListener('DOMContentLoaded', function() {
106
343
  groups[root].push(f);
107
344
  });
108
345
 
109
- var html = '<div class="flex gap-3 mb-4">' +
346
+ var totalFiles = files.length;
347
+
348
+ var html = '<div class="flex gap-3 mb-4 items-center">' +
110
349
  '<button type="button" id="preview-select-all" class="text-sm text-blue-600 hover:underline">Select all</button>' +
111
350
  '<button type="button" id="preview-deselect-all" class="text-sm text-blue-600 hover:underline">Deselect all</button>' +
112
- '<span class="text-sm text-gray-400">' + files.length + ' file' + (files.length === 1 ? '' : 's') + '</span>' +
351
+ '<span id="file-count" class="text-sm text-gray-400"></span>' +
113
352
  '</div>';
114
353
 
354
+ function checkboxHtml(filePath, displayPath) {
355
+ return '<label class="flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-gray-50 cursor-pointer">' +
356
+ '<input type="checkbox" name="files" value="' + escapeHtml(filePath) + '" checked ' +
357
+ 'class="rounded border-gray-300 text-blue-600 focus:ring-blue-500">' +
358
+ '<span class="font-mono text-sm">' + escapeHtml(displayPath) + '</span>' +
359
+ '</label>';
360
+ }
361
+
115
362
  rootOrder.forEach(function(root) {
116
363
  var rootFiles = groups[root];
117
364
  if (!rootFiles || rootFiles.length === 0) return;
118
365
 
119
- html += '<div class="mb-4">';
120
- html += '<h3 class="text-sm font-semibold text-gray-500 uppercase tracking-wide mb-2">' + escapeHtml(root) + '</h3>';
121
- html += '<div class="space-y-1">';
366
+ // Group by first subdirectory
367
+ var subGroups = {};
368
+ var subGroupOrder = [];
122
369
 
123
370
  rootFiles.forEach(function(file) {
124
- // Show path relative to the root for cleaner display
125
371
  var displayPath = file.path;
126
372
  if (root !== 'Other' && displayPath.indexOf(root) === 0) {
127
373
  displayPath = displayPath.slice(root.length + 1);
128
374
  }
129
- html += '<label class="flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-gray-50 cursor-pointer">' +
130
- '<input type="checkbox" name="files" value="' + escapeHtml(file.path) + '" checked ' +
131
- 'class="rounded border-gray-300 text-blue-600 focus:ring-blue-500">' +
132
- '<span class="font-mono text-sm">' + escapeHtml(displayPath) + '</span>' +
133
- '</label>';
375
+ var firstSlash = displayPath.indexOf('/');
376
+ var groupName = firstSlash === -1 ? '' : displayPath.slice(0, firstSlash);
377
+ if (!subGroups[groupName]) {
378
+ subGroups[groupName] = [];
379
+ subGroupOrder.push(groupName);
380
+ }
381
+ subGroups[groupName].push({ path: file.path, displayPath: displayPath });
134
382
  });
135
383
 
384
+ var hasSubGroups = subGroupOrder.length > 1 || subGroupOrder[0] !== '';
385
+
386
+ html += '<div class="mb-4">';
387
+ html += '<h3 class="text-sm font-semibold text-gray-500 uppercase tracking-wide mb-2">' + escapeHtml(root) + '</h3>';
388
+ html += '<div class="space-y-1">';
389
+
390
+ if (!hasSubGroups) {
391
+ subGroups[''].forEach(function(file) {
392
+ html += checkboxHtml(file.path, file.displayPath);
393
+ });
394
+ } else {
395
+ if (subGroups['']) {
396
+ subGroups[''].forEach(function(file) {
397
+ html += checkboxHtml(file.path, file.displayPath);
398
+ });
399
+ }
400
+ subGroupOrder.forEach(function(groupName) {
401
+ if (groupName === '') return;
402
+ var groupFiles = subGroups[groupName];
403
+ html += '<details class="mt-1">' +
404
+ '<summary class="cursor-pointer text-sm text-gray-600 hover:text-gray-800 px-3 py-1.5 rounded-lg hover:bg-gray-50 select-none">' +
405
+ escapeHtml(groupName) + '/ <span class="text-gray-400">(' + groupFiles.length + ')</span>' +
406
+ '</summary><div class="ml-4">';
407
+ groupFiles.forEach(function(file) {
408
+ html += checkboxHtml(file.path, file.displayPath);
409
+ });
410
+ html += '</div></details>';
411
+ });
412
+ }
413
+
136
414
  html += '</div></div>';
137
415
  });
138
416
 
139
417
  preview.innerHTML = html;
140
418
  preview.style.minHeight = '';
141
419
 
142
- // Wire up select/deselect all
420
+ function updateFileCount() {
421
+ var checked = preview.querySelectorAll('input[name="files"]:checked').length;
422
+ var countEl = document.getElementById('file-count');
423
+ if (countEl) {
424
+ countEl.textContent = checked + ' of ' + totalFiles + ' file' + (totalFiles === 1 ? '' : 's') + ' selected';
425
+ }
426
+ }
427
+
428
+ // Listen for checkbox changes
429
+ preview.querySelectorAll('input[name="files"]').forEach(function(cb) {
430
+ cb.addEventListener('change', updateFileCount);
431
+ });
432
+
143
433
  var selectAll = document.getElementById('preview-select-all');
144
434
  var deselectAll = document.getElementById('preview-deselect-all');
145
435
  if (selectAll) {
146
436
  selectAll.addEventListener('click', function() {
147
437
  preview.querySelectorAll('input[name="files"]').forEach(function(cb) { cb.checked = true; });
438
+ updateFileCount();
148
439
  });
149
440
  }
150
441
  if (deselectAll) {
151
442
  deselectAll.addEventListener('click', function() {
152
443
  preview.querySelectorAll('input[name="files"]').forEach(function(cb) { cb.checked = false; });
444
+ updateFileCount();
153
445
  });
154
446
  }
155
- }
156
-
157
- // --- Folder browser ---
158
- var openBrowserBtn = document.getElementById('open-browser');
159
- var folderBrowser = document.getElementById('folder-browser');
160
- var browserPath = document.getElementById('browser-path');
161
- var browserList = document.getElementById('browser-list');
162
- var browserUp = document.getElementById('browser-up');
163
- var browserAdd = document.getElementById('browser-add');
164
- var rootsList = document.getElementById('roots-list');
165
-
166
- if (browserAdd) {
167
- browserAdd.addEventListener('click', function() {
168
- if (currentBrowseDir) {
169
- addCustomChip(rootsList, currentBrowseDir);
170
- scheduleRefresh();
171
- }
172
- });
173
- }
174
-
175
- function addCustomChip(container, value) {
176
- // Don't add duplicates
177
- var existing = container.querySelectorAll('[data-custom-value]');
178
- for (var i = 0; i < existing.length; i++) {
179
- if (existing[i].getAttribute('data-custom-value') === value) return;
180
- }
181
- var chips = container.querySelectorAll('[data-chip]');
182
- for (var i = 0; i < chips.length; i++) {
183
- if (chips[i].getAttribute('data-value') === value) return;
184
- }
185
-
186
- var tag = document.createElement('span');
187
- tag.setAttribute('data-custom-value', value);
188
- tag.className = 'inline-flex items-center gap-1 px-3 py-1.5 rounded-full text-sm font-medium bg-blue-100 text-blue-800 border border-blue-300';
189
- tag.innerHTML = escapeHtml(value) + ' <button type="button" class="ml-1 text-blue-500 hover:text-blue-700 font-bold">&times;</button>';
190
- tag.querySelector('button').addEventListener('click', function() {
191
- tag.remove();
192
- scheduleRefresh();
193
- });
194
- container.appendChild(tag);
195
- }
196
-
197
- function loadBrowserDir(dir) {
198
- fetch('/api/setup/browse?dir=' + encodeURIComponent(dir || '~'))
199
- .then(function(res) { return res.json(); })
200
- .then(function(data) {
201
- if (data.error) return;
202
- currentBrowseDir = data.current;
203
- if (browserPath) browserPath.textContent = data.current;
204
- if (browserUp) {
205
- browserUp.style.display = data.parent ? '' : 'none';
206
- browserUp.onclick = function() { loadBrowserDir(data.parent); };
207
- }
208
- if (!browserList) return;
209
- browserList.innerHTML = '';
210
-
211
- data.dirs.forEach(function(entry) {
212
- var row = document.createElement('div');
213
- row.className = 'px-4 py-2 hover:bg-gray-50 cursor-pointer flex items-center gap-2 text-sm';
214
- row.innerHTML = '<span class="text-gray-400">&#128193;</span> ' + escapeHtml(entry.name);
215
- row.addEventListener('click', function() {
216
- loadBrowserDir(entry.path);
217
- });
218
- browserList.appendChild(row);
219
- });
220
- });
221
- }
222
-
223
- if (openBrowserBtn && folderBrowser) {
224
- openBrowserBtn.addEventListener('click', function() {
225
- var isHidden = folderBrowser.classList.contains('hidden');
226
- if (isHidden) {
227
- folderBrowser.classList.remove('hidden');
228
- openBrowserBtn.textContent = 'Hide browser';
229
- loadBrowserDir('~');
230
- } else {
231
- folderBrowser.classList.add('hidden');
232
- openBrowserBtn.textContent = 'Browse for folder...';
233
- }
234
- });
235
- }
236
-
237
- // --- Custom pattern input ---
238
- var addBtn = document.getElementById('add-custom');
239
- var customInput = document.getElementById('custom-input');
240
- var patternsList = document.getElementById('patterns-list');
241
447
 
242
- function addCustomPattern() {
243
- if (!customInput || !patternsList) return;
244
- var value = customInput.value.trim();
245
- if (!value) return;
246
- addCustomChip(patternsList, value);
247
- customInput.value = '';
248
- scheduleRefresh();
448
+ updateFileCount();
249
449
  }
250
450
 
251
- if (addBtn) {
252
- addBtn.addEventListener('click', addCustomPattern);
253
- }
254
- if (customInput) {
255
- customInput.addEventListener('keydown', function(e) {
256
- if (e.key === 'Enter') {
257
- e.preventDefault();
258
- addCustomPattern();
259
- }
260
- });
261
- }
451
+ // ===== Save =====
262
452
 
263
- // --- Save ---
264
453
  var saveBtn = document.getElementById('save-btn');
265
454
  var saveStatus = document.getElementById('save-status');
266
455
 
267
456
  if (saveBtn) {
268
457
  saveBtn.addEventListener('click', function() {
458
+ var roots = getAddedFolders();
459
+ var patterns = getSelectedPatterns();
460
+
461
+ if (roots.length === 0 || patterns.length === 0) {
462
+ alert('Please select at least one folder and one pattern.');
463
+ return;
464
+ }
465
+
269
466
  saveBtn.disabled = true;
270
467
  saveBtn.textContent = 'Saving...';
271
468
  if (saveStatus) saveStatus.classList.add('hidden');
272
469
 
273
- var roots = getSelectedRoots();
274
- var patterns = getSelectedPatterns();
275
-
276
470
  var excludedFiles = [];
277
471
  document.querySelectorAll('#file-preview input[name="files"]').forEach(function(cb) {
278
472
  if (!cb.checked) {
@@ -287,23 +481,34 @@ document.addEventListener('DOMContentLoaded', function() {
287
481
  })
288
482
  .then(function(res) { return res.json(); })
289
483
  .then(function(data) {
290
- saveBtn.disabled = false;
291
- saveBtn.textContent = 'Save';
292
- if (data.success && saveStatus) {
293
- saveStatus.textContent = 'Settings saved. Tracking ' + data.trackedCount + ' file' + (data.trackedCount === 1 ? '' : 's') + '.';
294
- saveStatus.classList.remove('hidden');
295
- setTimeout(function() { saveStatus.classList.add('hidden'); }, 3000);
484
+ if (data.success) {
485
+ var shouldRedirect = saveBtn.getAttribute('data-redirect') === 'true';
486
+ if (shouldRedirect) {
487
+ window.location.href = '/?setup=complete&count=' + data.trackedCount;
488
+ } else {
489
+ saveBtn.disabled = false;
490
+ saveBtn.textContent = 'Save';
491
+ if (saveStatus) {
492
+ saveStatus.textContent = 'Settings saved. Tracking ' + data.trackedCount + ' file' + (data.trackedCount === 1 ? '' : 's') + '.';
493
+ saveStatus.classList.remove('hidden');
494
+ setTimeout(function() { saveStatus.classList.add('hidden'); }, 3000);
495
+ }
496
+ }
497
+ } else {
498
+ saveBtn.disabled = false;
499
+ saveBtn.textContent = saveBtn.getAttribute('data-redirect') === 'true' ? 'Start Tracking' : 'Save';
500
+ alert('Error saving. Please try again.');
296
501
  }
297
502
  })
298
503
  .catch(function() {
299
504
  saveBtn.disabled = false;
300
- saveBtn.textContent = 'Save';
301
- alert('Error saving settings. Please try again.');
505
+ saveBtn.textContent = saveBtn.getAttribute('data-redirect') === 'true' ? 'Start Tracking' : 'Save';
506
+ alert('Error saving. Please try again.');
302
507
  });
303
508
  });
304
509
  }
305
510
 
306
- // --- Initial load ---
511
+ // ===== Initial load =====
307
512
  refreshPreview();
308
513
  });
309
514
  </script>`;
@@ -1 +1 @@
1
- {"version":3,"file":"settings-client.js","sourceRoot":"","sources":["../../src/dashboard/settings-client.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,sBAAsB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAoT5B,CAAC"}
1
+ {"version":3,"file":"settings-client.js","sourceRoot":"","sources":["../../src/dashboard/settings-client.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,sBAAsB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAigB5B,CAAC"}
@@ -1,3 +1,7 @@
1
1
  import { DotmdConfig } from "../config/defaults.js";
2
- export declare function settingsPage(config: DotmdConfig, suggestedRoots: string[], suggestedPatterns: string[]): string;
2
+ interface SetupPageOptions {
3
+ isInit?: boolean;
4
+ }
5
+ export declare function setupPage(config: DotmdConfig, suggestedRoots: string[], suggestedPatterns: string[], options?: SetupPageOptions): string;
6
+ export {};
3
7
  //# sourceMappingURL=settings.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/dashboard/settings.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAwBpD,wBAAgB,YAAY,CAC1B,MAAM,EAAE,WAAW,EACnB,cAAc,EAAE,MAAM,EAAE,EACxB,iBAAiB,EAAE,MAAM,EAAE,GAC1B,MAAM,CAiFR"}
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/dashboard/settings.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAyBpD,UAAU,gBAAgB;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,SAAS,CACvB,MAAM,EAAE,WAAW,EACnB,cAAc,EAAE,MAAM,EAAE,EACxB,iBAAiB,EAAE,MAAM,EAAE,EAC3B,OAAO,GAAE,gBAAqB,GAC7B,MAAM,CAoGR"}