kyp-mem 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,42 +3,47 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>KYP-MEM — Know Your Project</title>
6
+ <title>KYP-MEM</title>
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
8
  <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;600;700&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
9
9
  <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
10
10
  <script src="https://cdn.jsdelivr.net/npm/d3@7/dist/d3.min.js"></script>
11
11
  <style>
12
12
  :root {
13
- --bg-void: #06060c;
14
- --bg-primary: #0a0a14;
15
- --bg-secondary: #0d0d1a;
16
- --bg-tertiary: #050510;
17
- --bg-hover: #141428;
18
- --bg-active: #1a1a35;
19
- --bg-card: #0f0f1e;
20
-
21
- --neon-cyan: #00fff5;
22
- --neon-green: #39ff14;
23
- --neon-magenta: #ff00e0;
24
- --neon-purple: #bf5af2;
25
- --neon-orange: #ff6b35;
26
- --neon-yellow: #ffd700;
27
- --neon-blue: #4d9fff;
28
- --neon-red: #ff3366;
29
-
30
- --glow-cyan: 0 0 10px #00fff540, 0 0 20px #00fff520;
31
- --glow-green: 0 0 10px #39ff1440, 0 0 20px #39ff1420;
32
- --glow-magenta: 0 0 10px #ff00e040, 0 0 20px #ff00e020;
33
-
34
- --text-primary: #e0e0f0;
35
- --text-secondary: #8888a8;
36
- --text-muted: #4a4a68;
37
- --border: #1a1a30;
38
- --border-glow: #1a1a4080;
13
+ --bg-void: #08080f;
14
+ --bg-primary: #0c0c16;
15
+ --bg-secondary: #0e0e1a;
16
+ --bg-tertiary: #070710;
17
+ --bg-hover: #121224;
18
+ --bg-active: #181836;
19
+ --bg-card: #101020;
20
+ --bg-surface: #0a0a15;
21
+
22
+ --neon-cyan: #00e8df;
23
+ --neon-green: #34d399;
24
+ --neon-magenta: #e879f9;
25
+ --neon-purple: #a78bfa;
26
+ --neon-orange: #fb923c;
27
+ --neon-yellow: #fbbf24;
28
+ --neon-blue: #60a5fa;
29
+ --neon-red: #f87171;
30
+
31
+ --glow-cyan: 0 0 8px #00e8df30;
32
+ --glow-green: 0 0 8px #34d39930;
33
+ --glow-magenta: 0 0 8px #e879f930;
34
+
35
+ --text-primary: #d4d4e8;
36
+ --text-secondary: #7a7a9a;
37
+ --text-muted: #3e3e5c;
38
+ --border: #16162a;
39
+ --border-subtle: #121225;
39
40
 
40
41
  --font: 'Inter', -apple-system, sans-serif;
41
42
  --font-mono: 'JetBrains Mono', monospace;
43
+
44
+ --radius-sm: 4px;
45
+ --radius: 6px;
46
+ --radius-lg: 10px;
42
47
  }
43
48
 
44
49
  * { margin: 0; padding: 0; box-sizing: border-box; }
@@ -49,91 +54,61 @@ body {
49
54
  color: var(--text-primary);
50
55
  height: 100vh;
51
56
  overflow: hidden;
57
+ -webkit-font-smoothing: antialiased;
52
58
  }
53
59
 
54
- /* Subtle grid background */
55
60
  body::before {
56
61
  content: '';
57
62
  position: fixed;
58
63
  inset: 0;
59
64
  background-image:
60
- linear-gradient(rgba(0,255,245,0.03) 1px, transparent 1px),
61
- linear-gradient(90deg, rgba(0,255,245,0.03) 1px, transparent 1px);
62
- background-size: 40px 40px;
65
+ linear-gradient(rgba(0,232,223,0.015) 1px, transparent 1px),
66
+ linear-gradient(90deg, rgba(0,232,223,0.015) 1px, transparent 1px);
67
+ background-size: 48px 48px;
63
68
  pointer-events: none;
64
69
  z-index: 0;
65
70
  }
66
71
 
67
72
  .layout {
68
73
  display: grid;
69
- grid-template-columns: var(--sidebar-w, 260px) 5px 1fr 5px var(--right-w, 280px);
70
- grid-template-rows: 52px 1fr;
74
+ grid-template-columns: var(--sidebar-w, 256px) 1px 1fr 1px var(--right-w, 272px);
75
+ grid-template-rows: 48px 1fr;
71
76
  height: 100vh;
72
77
  position: relative;
73
78
  z-index: 1;
74
79
  }
75
80
 
76
81
  .layout.no-right-panel {
77
- grid-template-columns: var(--sidebar-w, 260px) 5px 1fr;
82
+ grid-template-columns: var(--sidebar-w, 256px) 1px 1fr;
78
83
  }
79
84
  .layout.no-right-panel .right-panel,
80
85
  .layout.no-right-panel #resize-right { display: none; }
81
86
 
82
87
  /* ============ RESIZE HANDLES ============ */
83
88
  .resize-handle {
84
- background: transparent;
89
+ background: var(--border-subtle);
85
90
  cursor: col-resize;
86
91
  position: relative;
87
92
  z-index: 10;
88
- transition: background 0.2s;
93
+ transition: background 0.3s;
89
94
  }
90
95
 
91
96
  .resize-handle::before {
92
97
  content: '';
93
98
  position: absolute;
94
- inset: 0 -3px;
99
+ inset: 0 -4px;
95
100
  z-index: 1;
96
101
  }
97
102
 
98
- .resize-handle::after {
99
- content: '';
100
- position: absolute;
101
- top: 50%;
102
- left: 50%;
103
- transform: translate(-50%, -50%);
104
- width: 3px;
105
- height: 32px;
106
- border-radius: 2px;
107
- background: var(--text-muted);
108
- opacity: 0;
109
- transition: opacity 0.2s, background 0.2s, box-shadow 0.2s;
110
- }
111
-
112
- .resize-handle:hover::after,
113
- .resize-handle.dragging::after {
114
- opacity: 1;
115
- background: var(--neon-cyan);
116
- box-shadow: 0 0 8px rgba(0, 255, 245, 0.4);
117
- }
118
-
119
103
  .resize-handle:hover,
120
104
  .resize-handle.dragging {
121
- background: rgba(0, 255, 245, 0.08);
122
- }
123
-
124
- body.resizing {
125
- cursor: col-resize !important;
126
- user-select: none !important;
105
+ background: var(--neon-cyan);
106
+ box-shadow: 0 0 12px rgba(0,232,223,0.2);
127
107
  }
128
108
 
129
- body.resizing * {
130
- cursor: col-resize !important;
131
- pointer-events: none !important;
132
- }
133
-
134
- body.resizing .resize-handle {
135
- pointer-events: auto !important;
136
- }
109
+ body.resizing { cursor: col-resize !important; user-select: none !important; }
110
+ body.resizing * { cursor: col-resize !important; pointer-events: none !important; }
111
+ body.resizing .resize-handle { pointer-events: auto !important; }
137
112
 
138
113
  /* ============ HEADER ============ */
139
114
  .header {
@@ -150,21 +125,20 @@ body.resizing .resize-handle {
150
125
  .header::after {
151
126
  content: '';
152
127
  position: absolute;
153
- bottom: -1px;
128
+ bottom: 0;
154
129
  left: 0;
155
130
  right: 0;
156
131
  height: 1px;
157
- background: linear-gradient(90deg, transparent, var(--neon-cyan), var(--neon-magenta), var(--neon-purple), transparent);
158
- opacity: 0.4;
132
+ background: linear-gradient(90deg, transparent, var(--neon-cyan), var(--neon-magenta), transparent);
133
+ opacity: 0.2;
159
134
  }
160
135
 
161
136
  .logo {
162
137
  font-family: var(--font-mono);
163
138
  font-weight: 700;
164
- font-size: 15px;
139
+ font-size: 13px;
165
140
  color: var(--neon-cyan);
166
- text-shadow: var(--glow-cyan);
167
- letter-spacing: 1px;
141
+ letter-spacing: 2px;
168
142
  flex-shrink: 0;
169
143
  }
170
144
 
@@ -172,66 +146,65 @@ body.resizing .resize-handle {
172
146
  font-size: 10px;
173
147
  font-weight: 400;
174
148
  color: var(--text-muted);
175
- text-shadow: none;
176
149
  letter-spacing: 0.5px;
177
- margin-left: 8px;
150
+ margin-left: 10px;
178
151
  }
179
152
 
180
153
  .breadcrumb {
181
154
  font-family: var(--font-mono);
182
- font-size: 12px;
155
+ font-size: 11px;
183
156
  color: var(--text-secondary);
184
157
  overflow: hidden;
185
158
  text-overflow: ellipsis;
186
159
  white-space: nowrap;
187
160
  }
188
161
 
189
- .breadcrumb .sep { color: var(--text-muted); margin: 0 6px; }
190
- .breadcrumb .current { color: var(--neon-cyan); font-weight: 600; }
162
+ .breadcrumb .sep { color: var(--text-muted); margin: 0 5px; }
163
+ .breadcrumb .current { color: var(--neon-cyan); font-weight: 500; }
191
164
 
192
165
  .header-actions {
193
166
  margin-left: auto;
194
167
  display: flex;
195
168
  align-items: center;
196
- gap: 10px;
169
+ gap: 8px;
197
170
  }
198
171
 
199
- .toggle-btn {
200
- background: var(--bg-hover);
172
+ .header-btn {
173
+ background: transparent;
201
174
  border: 1px solid var(--border);
202
- color: var(--text-secondary);
175
+ color: var(--text-muted);
203
176
  font-family: var(--font-mono);
204
- font-size: 11px;
177
+ font-size: 10px;
205
178
  padding: 5px 10px;
206
- border-radius: 6px;
179
+ border-radius: var(--radius);
207
180
  cursor: pointer;
208
181
  transition: all 0.2s;
209
182
  display: flex;
210
183
  align-items: center;
211
184
  gap: 5px;
185
+ letter-spacing: 0.5px;
212
186
  }
213
187
 
214
- .toggle-btn:hover {
215
- border-color: var(--neon-cyan);
216
- color: var(--neon-cyan);
188
+ .header-btn:hover {
189
+ border-color: var(--text-muted);
190
+ color: var(--text-secondary);
217
191
  }
218
192
 
219
- .toggle-btn.active {
220
- border-color: var(--neon-cyan);
193
+ .header-btn.active {
194
+ border-color: rgba(0,232,223,0.3);
221
195
  color: var(--neon-cyan);
222
- background: rgba(0, 255, 245, 0.08);
223
- box-shadow: 0 0 8px rgba(0, 255, 245, 0.15);
196
+ background: rgba(0,232,223,0.05);
224
197
  }
225
198
 
226
- .toggle-btn .dot {
227
- width: 6px;
228
- height: 6px;
199
+ .header-btn .dot {
200
+ width: 5px;
201
+ height: 5px;
229
202
  border-radius: 50%;
230
203
  background: var(--text-muted);
231
204
  transition: all 0.2s;
232
205
  }
233
206
 
234
- .toggle-btn.active .dot {
207
+ .header-btn.active .dot {
235
208
  background: var(--neon-green);
236
209
  box-shadow: 0 0 6px var(--neon-green);
237
210
  }
@@ -241,33 +214,33 @@ body.resizing .resize-handle {
241
214
  }
242
215
 
243
216
  .search-box input {
244
- background: var(--bg-secondary);
217
+ background: var(--bg-surface);
245
218
  border: 1px solid var(--border);
246
219
  color: var(--text-primary);
247
220
  font-family: var(--font-mono);
248
221
  padding: 6px 12px 6px 28px;
249
- border-radius: 6px;
250
- font-size: 12px;
251
- width: 220px;
222
+ border-radius: var(--radius);
223
+ font-size: 11px;
224
+ width: 200px;
252
225
  outline: none;
253
- transition: all 0.2s;
226
+ transition: all 0.25s;
254
227
  }
255
228
 
256
229
  .search-box input::placeholder { color: var(--text-muted); }
257
230
 
258
231
  .search-box input:focus {
259
- border-color: var(--neon-cyan);
260
- box-shadow: 0 0 12px rgba(0, 255, 245, 0.15);
261
- width: 280px;
232
+ border-color: rgba(0,232,223,0.3);
233
+ box-shadow: 0 0 16px rgba(0,232,223,0.08);
234
+ width: 260px;
262
235
  }
263
236
 
264
237
  .search-box .search-icon {
265
238
  position: absolute;
266
- left: 9px;
239
+ left: 10px;
267
240
  top: 50%;
268
241
  transform: translateY(-50%);
269
242
  color: var(--text-muted);
270
- font-size: 12px;
243
+ font-size: 11px;
271
244
  }
272
245
 
273
246
  .search-box .search-hint {
@@ -276,36 +249,36 @@ body.resizing .resize-handle {
276
249
  top: 50%;
277
250
  transform: translateY(-50%);
278
251
  font-family: var(--font-mono);
279
- font-size: 10px;
252
+ font-size: 9px;
280
253
  color: var(--text-muted);
281
254
  background: var(--bg-hover);
282
255
  padding: 1px 5px;
283
256
  border-radius: 3px;
284
257
  border: 1px solid var(--border);
258
+ letter-spacing: 0.5px;
285
259
  }
286
260
 
287
261
  .search-results {
288
262
  position: absolute;
289
- top: calc(100% + 6px);
263
+ top: calc(100% + 8px);
290
264
  right: 0;
291
- width: 420px;
292
- max-height: 420px;
265
+ width: 400px;
266
+ max-height: 380px;
293
267
  overflow-y: auto;
294
268
  background: var(--bg-card);
295
269
  border: 1px solid var(--border);
296
- border-radius: 10px;
270
+ border-radius: var(--radius-lg);
297
271
  z-index: 100;
298
272
  display: none;
299
- backdrop-filter: blur(12px);
300
- box-shadow: 0 8px 32px rgba(0,0,0,0.6), 0 0 1px var(--neon-cyan);
273
+ box-shadow: 0 12px 40px rgba(0,0,0,0.5);
301
274
  }
302
275
 
303
276
  .search-results.active { display: block; }
304
277
 
305
278
  .search-result {
306
- padding: 12px 16px;
279
+ padding: 10px 14px;
307
280
  cursor: pointer;
308
- border-bottom: 1px solid var(--border);
281
+ border-bottom: 1px solid var(--border-subtle);
309
282
  transition: background 0.15s;
310
283
  }
311
284
 
@@ -313,8 +286,8 @@ body.resizing .resize-handle {
313
286
  .search-result:hover { background: var(--bg-hover); }
314
287
 
315
288
  .search-result .sr-title {
316
- font-size: 13px;
317
- font-weight: 600;
289
+ font-size: 12px;
290
+ font-weight: 500;
318
291
  color: var(--neon-cyan);
319
292
  }
320
293
 
@@ -322,20 +295,102 @@ body.resizing .resize-handle {
322
295
  font-family: var(--font-mono);
323
296
  font-size: 10px;
324
297
  color: var(--text-muted);
325
- margin-top: 3px;
298
+ margin-top: 2px;
326
299
  }
327
300
 
328
301
  .search-result .sr-snippet {
329
- font-size: 12px;
302
+ font-size: 11px;
330
303
  color: var(--text-secondary);
331
304
  margin-top: 4px;
332
- line-height: 1.4;
305
+ line-height: 1.5;
306
+ }
307
+
308
+ /* ============ QUICK SWITCHER ============ */
309
+ .quick-switcher-overlay {
310
+ position: fixed;
311
+ inset: 0;
312
+ background: rgba(6,6,12,0.7);
313
+ z-index: 200;
314
+ display: none;
315
+ align-items: flex-start;
316
+ justify-content: center;
317
+ padding-top: 15vh;
318
+ backdrop-filter: blur(4px);
319
+ }
320
+
321
+ .quick-switcher-overlay.active { display: flex; }
322
+
323
+ .quick-switcher {
324
+ width: 480px;
325
+ background: var(--bg-card);
326
+ border: 1px solid var(--border);
327
+ border-radius: var(--radius-lg);
328
+ box-shadow: 0 20px 60px rgba(0,0,0,0.6), 0 0 1px var(--neon-cyan);
329
+ overflow: hidden;
330
+ }
331
+
332
+ .quick-switcher input {
333
+ width: 100%;
334
+ background: transparent;
335
+ border: none;
336
+ border-bottom: 1px solid var(--border);
337
+ color: var(--text-primary);
338
+ font-family: var(--font-mono);
339
+ font-size: 14px;
340
+ padding: 16px 20px;
341
+ outline: none;
342
+ }
343
+
344
+ .quick-switcher input::placeholder { color: var(--text-muted); }
345
+
346
+ .quick-switcher-results {
347
+ max-height: 320px;
348
+ overflow-y: auto;
349
+ }
350
+
351
+ .qs-item {
352
+ padding: 10px 20px;
353
+ cursor: pointer;
354
+ display: flex;
355
+ align-items: center;
356
+ gap: 10px;
357
+ transition: background 0.1s;
358
+ }
359
+
360
+ .qs-item:hover, .qs-item.selected { background: var(--bg-hover); }
361
+
362
+ .qs-item .qs-icon {
363
+ color: var(--neon-purple);
364
+ font-size: 12px;
365
+ flex-shrink: 0;
366
+ opacity: 0.7;
367
+ }
368
+
369
+ .qs-item .qs-name {
370
+ font-size: 13px;
371
+ color: var(--text-primary);
372
+ font-weight: 500;
373
+ }
374
+
375
+ .qs-item .qs-path {
376
+ font-family: var(--font-mono);
377
+ font-size: 10px;
378
+ color: var(--text-muted);
379
+ margin-left: auto;
380
+ }
381
+
382
+ .qs-item.selected .qs-name { color: var(--neon-cyan); }
383
+
384
+ .qs-empty {
385
+ padding: 20px;
386
+ text-align: center;
387
+ color: var(--text-muted);
388
+ font-size: 12px;
333
389
  }
334
390
 
335
391
  /* ============ SIDEBAR ============ */
336
392
  .sidebar {
337
393
  background: var(--bg-secondary);
338
- border-right: 1px solid var(--border);
339
394
  display: flex;
340
395
  flex-direction: column;
341
396
  overflow: hidden;
@@ -344,38 +399,42 @@ body.resizing .resize-handle {
344
399
  .sidebar-scroll {
345
400
  flex: 1;
346
401
  overflow-y: auto;
347
- padding: 8px 0;
402
+ padding: 6px 0;
348
403
  }
349
404
 
350
- .sidebar-section { padding: 0 10px; }
405
+ .sidebar-section { padding: 0 8px; }
351
406
 
352
- .sidebar-section-title {
407
+ .section-label {
353
408
  font-family: var(--font-mono);
354
- font-size: 10px;
409
+ font-size: 9px;
355
410
  font-weight: 600;
356
411
  text-transform: uppercase;
357
412
  letter-spacing: 1.5px;
358
413
  color: var(--text-muted);
359
- padding: 10px 8px 8px;
414
+ padding: 12px 10px 6px;
415
+ display: flex;
416
+ align-items: center;
417
+ justify-content: space-between;
360
418
  }
361
419
 
362
420
  .tree-item {
363
421
  display: flex;
364
422
  align-items: center;
365
- padding: 5px 8px;
366
- border-radius: 5px;
423
+ padding: 4px 10px;
424
+ border-radius: var(--radius-sm);
367
425
  cursor: pointer;
368
- font-size: 13px;
426
+ font-size: 12px;
369
427
  gap: 6px;
370
428
  user-select: none;
371
- transition: all 0.12s;
429
+ transition: background 0.1s;
372
430
  position: relative;
431
+ margin: 1px 0;
373
432
  }
374
433
 
375
434
  .tree-item:hover { background: var(--bg-hover); }
376
435
 
377
436
  .tree-item.active {
378
- background: rgba(0, 255, 245, 0.06);
437
+ background: rgba(0,232,223,0.05);
379
438
  }
380
439
 
381
440
  .tree-item.active::before {
@@ -387,12 +446,11 @@ body.resizing .resize-handle {
387
446
  width: 2px;
388
447
  background: var(--neon-cyan);
389
448
  border-radius: 1px;
390
- box-shadow: 0 0 6px var(--neon-cyan);
391
449
  }
392
450
 
393
451
  .tree-item .arrow {
394
- width: 14px;
395
- font-size: 9px;
452
+ width: 12px;
453
+ font-size: 8px;
396
454
  color: var(--text-muted);
397
455
  text-align: center;
398
456
  flex-shrink: 0;
@@ -403,7 +461,8 @@ body.resizing .resize-handle {
403
461
 
404
462
  .tree-item .icon {
405
463
  flex-shrink: 0;
406
- font-size: 13px;
464
+ font-size: 11px;
465
+ opacity: 0.6;
407
466
  }
408
467
 
409
468
  .tree-item .folder-icon { color: var(--neon-yellow); }
@@ -413,146 +472,254 @@ body.resizing .resize-handle {
413
472
  overflow: hidden;
414
473
  text-overflow: ellipsis;
415
474
  white-space: nowrap;
416
- font-size: 13px;
475
+ font-size: 12px;
417
476
  color: var(--text-primary);
418
477
  }
419
478
 
420
479
  .tree-item.active .name { color: var(--neon-cyan); }
421
480
 
422
- .tree-children {
423
- padding-left: 14px;
424
- overflow: hidden;
481
+ .tree-children { padding-left: 12px; overflow: hidden; }
482
+ .tree-children.collapsed { display: none; }
483
+
484
+ /* ============ TAG FILTER ============ */
485
+ .tag-filter-section { padding: 0 8px 8px; }
486
+
487
+ .tag-filter-header {
488
+ font-family: var(--font-mono);
489
+ font-size: 9px;
490
+ font-weight: 600;
491
+ text-transform: uppercase;
492
+ letter-spacing: 1.5px;
493
+ color: var(--text-muted);
494
+ padding: 12px 10px 6px;
495
+ display: flex;
496
+ align-items: center;
497
+ justify-content: space-between;
498
+ cursor: pointer;
499
+ user-select: none;
425
500
  }
426
501
 
427
- .tree-children.collapsed { display: none; }
502
+ .tag-filter-header .arrow {
503
+ font-size: 8px;
504
+ transition: transform 0.15s;
505
+ }
506
+
507
+ .tag-filter-header .arrow.open { transform: rotate(90deg); }
508
+
509
+ .tag-filter-body { padding: 0 4px; }
510
+ .tag-filter-body.collapsed { display: none; }
511
+
512
+ .tag-filter-active {
513
+ display: flex;
514
+ flex-wrap: wrap;
515
+ gap: 4px;
516
+ margin-bottom: 6px;
517
+ }
518
+
519
+ .tag-filter-active:empty { display: none; }
520
+
521
+ .active-tag {
522
+ font-family: var(--font-mono);
523
+ font-size: 9px;
524
+ padding: 2px 7px;
525
+ border-radius: var(--radius-sm);
526
+ background: rgba(0,232,223,0.08);
527
+ color: var(--neon-cyan);
528
+ border: 1px solid rgba(0,232,223,0.2);
529
+ cursor: pointer;
530
+ display: flex;
531
+ align-items: center;
532
+ gap: 3px;
533
+ transition: all 0.15s;
534
+ }
535
+
536
+ .active-tag:hover { background: rgba(0,232,223,0.15); }
537
+ .active-tag .remove { font-size: 11px; opacity: 0.5; }
538
+ .active-tag .remove:hover { opacity: 1; }
539
+
540
+ .tag-cloud {
541
+ display: flex;
542
+ flex-wrap: wrap;
543
+ gap: 3px;
544
+ max-height: 140px;
545
+ overflow-y: auto;
546
+ padding: 2px 0;
547
+ }
548
+
549
+ .tag-chip {
550
+ font-family: var(--font-mono);
551
+ font-size: 9px;
552
+ font-weight: 500;
553
+ padding: 2px 7px;
554
+ border-radius: var(--radius-sm);
555
+ background: rgba(168,139,250,0.06);
556
+ color: var(--neon-purple);
557
+ border: 1px solid rgba(168,139,250,0.1);
558
+ cursor: pointer;
559
+ transition: all 0.15s;
560
+ user-select: none;
561
+ }
562
+
563
+ .tag-chip:hover {
564
+ background: rgba(168,139,250,0.12);
565
+ border-color: rgba(168,139,250,0.25);
566
+ }
567
+
568
+ .tag-chip.selected {
569
+ background: rgba(0,232,223,0.08);
570
+ color: var(--neon-cyan);
571
+ border-color: rgba(0,232,223,0.2);
572
+ }
573
+
574
+ .tag-chip .tag-count {
575
+ font-size: 8px;
576
+ opacity: 0.4;
577
+ margin-left: 2px;
578
+ }
579
+
580
+ .filter-info {
581
+ font-family: var(--font-mono);
582
+ font-size: 9px;
583
+ color: var(--text-muted);
584
+ padding: 2px 10px 4px;
585
+ display: flex;
586
+ align-items: center;
587
+ justify-content: space-between;
588
+ }
589
+
590
+ .filter-info .clear-btn {
591
+ color: var(--neon-cyan);
592
+ cursor: pointer;
593
+ font-size: 9px;
594
+ }
595
+
596
+ .filter-info .clear-btn:hover { text-decoration: underline; }
428
597
 
429
598
  .stats-bar {
430
- padding: 10px 14px;
431
- border-top: 1px solid var(--border);
599
+ padding: 8px 14px;
600
+ border-top: 1px solid var(--border-subtle);
432
601
  font-family: var(--font-mono);
433
- font-size: 10px;
602
+ font-size: 9px;
434
603
  color: var(--text-muted);
435
604
  display: flex;
436
- gap: 14px;
605
+ gap: 12px;
437
606
  flex-wrap: wrap;
438
607
  }
439
608
 
440
- .stat-val { color: var(--neon-green); font-weight: 600; }
609
+ .stat-val { color: var(--neon-green); font-weight: 500; }
441
610
 
442
611
  /* ============ CONTENT ============ */
443
612
  .content {
444
613
  overflow-y: auto;
445
- padding: 36px 52px;
614
+ padding: 40px 56px;
446
615
  background: var(--bg-primary);
447
616
  }
448
617
 
449
618
  .note-properties {
450
619
  display: flex;
451
620
  flex-wrap: wrap;
452
- gap: 6px;
453
- margin-bottom: 24px;
454
- padding-bottom: 18px;
455
- border-bottom: 1px solid var(--border);
621
+ gap: 5px;
622
+ margin-bottom: 28px;
623
+ padding-bottom: 20px;
624
+ border-bottom: 1px solid var(--border-subtle);
456
625
  }
457
626
 
458
627
  .tag {
459
628
  font-family: var(--font-mono);
460
- font-size: 11px;
629
+ font-size: 10px;
461
630
  font-weight: 500;
462
- padding: 3px 10px;
463
- border-radius: 4px;
464
- background: rgba(255, 0, 224, 0.1);
465
- color: var(--neon-magenta);
466
- border: 1px solid rgba(255, 0, 224, 0.2);
631
+ padding: 2px 9px;
632
+ border-radius: var(--radius-sm);
633
+ background: rgba(168,139,250,0.08);
634
+ color: var(--neon-purple);
635
+ border: 1px solid rgba(168,139,250,0.12);
636
+ transition: all 0.15s;
637
+ }
638
+
639
+ .tag.clickable-tag:hover {
640
+ background: rgba(0,232,223,0.08);
641
+ color: var(--neon-cyan);
642
+ border-color: rgba(0,232,223,0.2);
643
+ cursor: pointer;
467
644
  }
468
645
 
469
646
  .prop-item {
470
647
  font-family: var(--font-mono);
471
- font-size: 11px;
472
- padding: 3px 10px;
473
- border-radius: 4px;
648
+ font-size: 10px;
649
+ padding: 2px 9px;
650
+ border-radius: var(--radius-sm);
474
651
  background: var(--bg-card);
475
652
  color: var(--text-secondary);
476
- border: 1px solid var(--border);
653
+ border: 1px solid var(--border-subtle);
477
654
  }
478
655
 
479
656
  .prop-item .prop-key { color: var(--text-muted); }
480
657
 
481
658
  /* ============ MARKDOWN ============ */
482
659
  .md-body h1 {
483
- font-size: 28px;
660
+ font-size: 26px;
484
661
  font-weight: 700;
485
- margin: 0 0 20px;
486
- color: var(--neon-cyan);
487
- text-shadow: 0 0 20px rgba(0,255,245,0.15);
662
+ margin: 0 0 24px;
663
+ color: var(--text-primary);
664
+ letter-spacing: -0.3px;
488
665
  }
489
666
 
490
667
  .md-body h2 {
491
- font-size: 20px;
668
+ font-size: 18px;
492
669
  font-weight: 600;
493
- margin: 32px 0 12px;
494
- color: var(--neon-yellow);
670
+ margin: 36px 0 12px;
671
+ color: var(--text-primary);
495
672
  padding-bottom: 8px;
496
- border-bottom: 1px solid var(--border);
673
+ border-bottom: 1px solid var(--border-subtle);
497
674
  }
498
675
 
499
676
  .md-body h3 {
500
- font-size: 16px;
677
+ font-size: 15px;
501
678
  font-weight: 600;
502
- margin: 24px 0 8px;
679
+ margin: 28px 0 8px;
503
680
  color: var(--neon-purple);
504
681
  }
505
682
 
506
683
  .md-body p {
507
- line-height: 1.75;
508
- margin: 10px 0;
684
+ line-height: 1.8;
685
+ margin: 8px 0;
509
686
  color: var(--text-secondary);
687
+ font-size: 13.5px;
510
688
  }
511
689
 
512
690
  .md-body ul, .md-body ol { padding-left: 24px; margin: 8px 0; }
513
691
 
514
692
  .md-body li {
515
- line-height: 1.75;
693
+ line-height: 1.8;
516
694
  color: var(--text-secondary);
517
- margin: 3px 0;
695
+ margin: 2px 0;
696
+ font-size: 13.5px;
518
697
  }
519
698
 
520
- .md-body li::marker { color: var(--neon-cyan); }
699
+ .md-body li::marker { color: var(--text-muted); }
521
700
 
522
701
  .md-body a { color: var(--neon-blue); text-decoration: none; }
523
- .md-body a:hover { text-decoration: underline; text-shadow: 0 0 8px rgba(77,159,255,0.3); }
702
+ .md-body a:hover { text-decoration: underline; }
524
703
 
525
704
  .md-body strong { color: var(--text-primary); font-weight: 600; }
526
705
 
527
706
  .md-body code {
528
707
  background: var(--bg-card);
529
- padding: 2px 7px;
530
- border-radius: 4px;
708
+ padding: 1.5px 6px;
709
+ border-radius: 3px;
531
710
  font-family: var(--font-mono);
532
711
  font-size: 12px;
533
712
  color: var(--neon-orange);
534
- border: 1px solid var(--border);
713
+ border: 1px solid var(--border-subtle);
535
714
  }
536
715
 
537
716
  .md-body pre {
538
717
  background: var(--bg-tertiary);
539
718
  border: 1px solid var(--border);
540
- border-radius: 8px;
541
- padding: 18px;
719
+ border-radius: var(--radius);
720
+ padding: 16px 18px;
542
721
  overflow-x: auto;
543
722
  margin: 16px 0;
544
- position: relative;
545
- }
546
-
547
- .md-body pre::before {
548
- content: '';
549
- position: absolute;
550
- top: 0;
551
- left: 0;
552
- right: 0;
553
- height: 1px;
554
- background: linear-gradient(90deg, var(--neon-cyan), var(--neon-magenta), transparent);
555
- opacity: 0.3;
556
723
  }
557
724
 
558
725
  .md-body pre code {
@@ -560,65 +727,63 @@ body.resizing .resize-handle {
560
727
  padding: 0;
561
728
  border: none;
562
729
  color: var(--text-primary);
563
- font-size: 13px;
564
- line-height: 1.6;
730
+ font-size: 12px;
731
+ line-height: 1.7;
565
732
  }
566
733
 
567
734
  .md-body table {
568
735
  width: 100%;
569
736
  border-collapse: collapse;
570
737
  margin: 16px 0;
571
- font-size: 13px;
738
+ font-size: 12.5px;
572
739
  }
573
740
 
574
741
  .md-body th {
575
742
  text-align: left;
576
- padding: 10px 14px;
577
- border-bottom: 2px solid var(--neon-cyan);
578
- color: var(--neon-cyan);
743
+ padding: 8px 12px;
744
+ border-bottom: 1px solid var(--border);
745
+ color: var(--text-secondary);
579
746
  font-family: var(--font-mono);
580
747
  font-weight: 600;
581
- font-size: 12px;
748
+ font-size: 10px;
582
749
  text-transform: uppercase;
583
750
  letter-spacing: 0.5px;
584
751
  }
585
752
 
586
753
  .md-body td {
587
- padding: 10px 14px;
588
- border-bottom: 1px solid var(--border);
754
+ padding: 8px 12px;
755
+ border-bottom: 1px solid var(--border-subtle);
589
756
  color: var(--text-secondary);
590
757
  }
591
758
 
592
759
  .md-body tr:hover td { background: var(--bg-hover); }
593
760
 
594
761
  .md-body blockquote {
595
- border-left: 3px solid var(--neon-magenta);
762
+ border-left: 2px solid var(--neon-purple);
596
763
  padding-left: 16px;
597
764
  margin: 16px 0;
598
765
  color: var(--text-muted);
599
- box-shadow: -3px 0 8px rgba(255,0,224,0.1);
600
766
  }
601
767
 
602
768
  .md-body hr {
603
769
  border: none;
604
770
  height: 1px;
605
- background: linear-gradient(90deg, transparent, var(--border), transparent);
606
- margin: 24px 0;
771
+ background: var(--border);
772
+ margin: 28px 0;
607
773
  }
608
774
 
609
775
  .wikilink {
610
776
  color: var(--neon-purple);
611
777
  cursor: pointer;
612
778
  text-decoration: none;
613
- border-bottom: 1px dashed rgba(191, 90, 242, 0.4);
779
+ border-bottom: 1px dashed rgba(168,139,250,0.3);
614
780
  transition: all 0.15s;
615
781
  font-weight: 500;
616
782
  }
617
783
 
618
784
  .wikilink:hover {
619
- color: var(--neon-magenta);
620
- text-shadow: 0 0 8px rgba(255,0,224,0.3);
621
- border-bottom-color: var(--neon-magenta);
785
+ color: var(--neon-cyan);
786
+ border-bottom-color: rgba(0,232,223,0.4);
622
787
  }
623
788
 
624
789
  /* ============ EMPTY STATE ============ */
@@ -628,35 +793,35 @@ body.resizing .resize-handle {
628
793
  align-items: center;
629
794
  justify-content: center;
630
795
  height: 100%;
631
- gap: 16px;
796
+ gap: 12px;
632
797
  }
633
798
 
634
799
  .empty-state .es-logo {
635
800
  font-family: var(--font-mono);
636
- font-size: 32px;
801
+ font-size: 28px;
637
802
  font-weight: 700;
638
803
  color: var(--neon-cyan);
639
- text-shadow: var(--glow-cyan), 0 0 40px rgba(0,255,245,0.1);
640
- letter-spacing: 3px;
804
+ letter-spacing: 4px;
805
+ opacity: 0.6;
641
806
  }
642
807
 
643
808
  .empty-state .es-tagline {
644
809
  font-family: var(--font-mono);
645
- font-size: 12px;
810
+ font-size: 11px;
646
811
  color: var(--text-muted);
647
- letter-spacing: 2px;
812
+ letter-spacing: 3px;
648
813
  text-transform: uppercase;
649
814
  }
650
815
 
651
816
  .empty-state .es-hint {
652
- font-size: 13px;
817
+ font-size: 12px;
653
818
  color: var(--text-muted);
654
- margin-top: 20px;
819
+ margin-top: 24px;
655
820
  }
656
821
 
657
822
  .empty-state .es-hint kbd {
658
823
  font-family: var(--font-mono);
659
- font-size: 11px;
824
+ font-size: 10px;
660
825
  background: var(--bg-card);
661
826
  border: 1px solid var(--border);
662
827
  padding: 2px 6px;
@@ -667,21 +832,20 @@ body.resizing .resize-handle {
667
832
  /* ============ RIGHT PANEL ============ */
668
833
  .right-panel {
669
834
  background: var(--bg-secondary);
670
- border-left: 1px solid var(--border);
671
835
  overflow-y: auto;
672
- padding: 16px;
836
+ padding: 12px;
673
837
  }
674
838
 
675
- .rp-section { margin-bottom: 24px; }
839
+ .rp-section { margin-bottom: 20px; }
676
840
 
677
841
  .rp-section-title {
678
842
  font-family: var(--font-mono);
679
- font-size: 10px;
843
+ font-size: 9px;
680
844
  font-weight: 600;
681
845
  text-transform: uppercase;
682
846
  letter-spacing: 1.5px;
683
847
  color: var(--text-muted);
684
- margin-bottom: 10px;
848
+ margin-bottom: 8px;
685
849
  display: flex;
686
850
  align-items: center;
687
851
  gap: 6px;
@@ -691,32 +855,30 @@ body.resizing .resize-handle {
691
855
  background: var(--bg-hover);
692
856
  color: var(--text-muted);
693
857
  font-size: 9px;
694
- padding: 1px 5px;
858
+ padding: 0px 5px;
695
859
  border-radius: 8px;
696
860
  }
697
861
 
698
862
  .rp-item {
699
863
  display: flex;
700
864
  align-items: center;
701
- padding: 6px 8px;
702
- border-radius: 5px;
865
+ padding: 5px 8px;
866
+ border-radius: var(--radius-sm);
703
867
  cursor: pointer;
704
- font-size: 12px;
868
+ font-size: 11px;
705
869
  gap: 8px;
706
- margin-bottom: 2px;
707
- transition: all 0.12s;
870
+ margin-bottom: 1px;
871
+ transition: background 0.1s;
708
872
  }
709
873
 
710
- .rp-item:hover {
711
- background: var(--bg-hover);
712
- }
874
+ .rp-item:hover { background: var(--bg-hover); }
713
875
 
714
876
  .rp-item .rp-score {
715
877
  font-family: var(--font-mono);
716
- font-size: 11px;
878
+ font-size: 10px;
717
879
  color: var(--neon-green);
718
- min-width: 34px;
719
- text-shadow: 0 0 6px rgba(57,255,20,0.2);
880
+ min-width: 30px;
881
+ opacity: 0.8;
720
882
  }
721
883
 
722
884
  .rp-item .rp-title {
@@ -727,89 +889,214 @@ body.resizing .resize-handle {
727
889
  font-weight: 500;
728
890
  }
729
891
 
730
- .rp-item .rp-backlink-title {
731
- color: var(--neon-cyan);
892
+ .rp-item .rp-backlink-title { color: var(--neon-cyan); }
893
+
894
+ /* ============ OUTLINE ============ */
895
+ .outline-item {
896
+ display: block;
897
+ padding: 3px 8px;
898
+ border-radius: var(--radius-sm);
899
+ cursor: pointer;
900
+ font-size: 11px;
901
+ color: var(--text-secondary);
902
+ transition: all 0.1s;
903
+ overflow: hidden;
904
+ text-overflow: ellipsis;
905
+ white-space: nowrap;
906
+ margin-bottom: 1px;
732
907
  }
733
908
 
734
- /* ============ GRAPH ============ */
735
- #graph-section {
736
- margin-bottom: 16px;
909
+ .outline-item:hover {
910
+ background: var(--bg-hover);
911
+ color: var(--text-primary);
737
912
  }
738
913
 
914
+ .outline-item.h2 { padding-left: 8px; }
915
+ .outline-item.h3 { padding-left: 20px; font-size: 10px; color: var(--text-muted); }
916
+
917
+ /* ============ GRAPH ============ */
918
+ #graph-section { margin-bottom: 12px; }
739
919
  #graph-section.hidden { display: none; }
740
920
 
741
921
  #graph-container {
742
922
  width: 100%;
743
- height: 220px;
744
- border: 1px solid var(--border);
745
- border-radius: 8px;
923
+ height: 200px;
924
+ border: 1px solid var(--border-subtle);
925
+ border-radius: var(--radius);
746
926
  overflow: hidden;
747
927
  background: var(--bg-tertiary);
748
- position: relative;
749
- }
750
-
751
- #graph-container::before {
752
- content: '';
753
- position: absolute;
754
- inset: 0;
755
- background-image:
756
- radial-gradient(rgba(0,255,245,0.03) 1px, transparent 1px);
757
- background-size: 16px 16px;
758
- pointer-events: none;
759
928
  }
760
929
 
761
- #graph-container svg { width: 100%; height: 100%; position: relative; z-index: 1; }
930
+ #graph-container svg { width: 100%; height: 100%; }
762
931
 
763
932
  .graph-node { cursor: pointer; }
764
933
 
765
934
  .graph-node circle {
766
935
  fill: var(--neon-purple);
767
- filter: drop-shadow(0 0 3px rgba(191,90,242,0.5));
936
+ filter: drop-shadow(0 0 2px rgba(168,139,250,0.4));
768
937
  transition: all 0.2s;
769
938
  }
770
939
 
771
940
  .graph-node:hover circle {
772
941
  fill: var(--neon-cyan);
773
- filter: drop-shadow(0 0 6px rgba(0,255,245,0.6));
942
+ filter: drop-shadow(0 0 4px rgba(0,232,223,0.5));
774
943
  }
775
944
 
776
945
  .graph-node.active circle {
777
946
  fill: var(--neon-cyan);
778
- r: 7;
779
- filter: drop-shadow(0 0 8px rgba(0,255,245,0.7));
947
+ r: 6;
948
+ filter: drop-shadow(0 0 6px rgba(0,232,223,0.5));
780
949
  }
781
950
 
782
951
  .graph-node text {
783
- fill: var(--text-secondary);
952
+ fill: var(--text-muted);
784
953
  font-family: var(--font-mono);
785
- font-size: 9px;
954
+ font-size: 8px;
786
955
  }
787
956
 
788
957
  .graph-link {
789
- stroke: rgba(191, 90, 242, 0.3);
958
+ stroke: rgba(168,139,250,0.15);
790
959
  stroke-width: 1;
791
960
  }
792
961
 
793
962
  /* ============ SCROLLBAR ============ */
794
- ::-webkit-scrollbar { width: 5px; }
963
+ ::-webkit-scrollbar { width: 4px; }
795
964
  ::-webkit-scrollbar-track { background: transparent; }
796
- ::-webkit-scrollbar-thumb { background: var(--bg-active); border-radius: 3px; }
965
+ ::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
797
966
  ::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }
798
967
 
799
- /* ============ TRANSITIONS ============ */
800
- .fade-in {
801
- animation: fadeIn 0.2s ease;
968
+ /* ============ EDIT MODAL ============ */
969
+ .edit-overlay {
970
+ position: fixed;
971
+ inset: 0;
972
+ background: rgba(6,6,12,0.75);
973
+ z-index: 200;
974
+ display: none;
975
+ align-items: center;
976
+ justify-content: center;
977
+ backdrop-filter: blur(4px);
802
978
  }
803
979
 
804
- @keyframes fadeIn {
805
- from { opacity: 0; transform: translateY(4px); }
806
- to { opacity: 1; transform: translateY(0); }
980
+ .edit-overlay.active { display: flex; }
981
+
982
+ .edit-modal {
983
+ width: 640px;
984
+ max-height: 80vh;
985
+ background: var(--bg-card);
986
+ border: 1px solid var(--border);
987
+ border-radius: var(--radius-lg);
988
+ box-shadow: 0 20px 60px rgba(0,0,0,0.6);
989
+ display: flex;
990
+ flex-direction: column;
991
+ overflow: hidden;
807
992
  }
808
993
 
809
- /* Pulse animation for active graph node */
810
- @keyframes pulse {
811
- 0%, 100% { opacity: 1; }
812
- 50% { opacity: 0.6; }
994
+ .edit-header {
995
+ display: flex;
996
+ align-items: center;
997
+ justify-content: space-between;
998
+ padding: 12px 16px;
999
+ border-bottom: 1px solid var(--border-subtle);
1000
+ font-family: var(--font-mono);
1001
+ font-size: 11px;
1002
+ color: var(--text-secondary);
1003
+ }
1004
+
1005
+ .edit-header .edit-path { opacity: 0.6; }
1006
+
1007
+ .edit-actions { display: flex; gap: 8px; }
1008
+
1009
+ .edit-btn {
1010
+ font-family: var(--font-mono);
1011
+ font-size: 10px;
1012
+ padding: 5px 14px;
1013
+ border-radius: var(--radius);
1014
+ border: 1px solid var(--border);
1015
+ cursor: pointer;
1016
+ transition: all 0.15s;
1017
+ letter-spacing: 0.5px;
1018
+ }
1019
+
1020
+ .edit-btn.cancel {
1021
+ background: transparent;
1022
+ color: var(--text-muted);
1023
+ }
1024
+
1025
+ .edit-btn.cancel:hover { color: var(--text-secondary); border-color: var(--text-muted); }
1026
+
1027
+ .edit-btn.save {
1028
+ background: rgba(0,232,223,0.1);
1029
+ color: var(--neon-cyan);
1030
+ border-color: rgba(0,232,223,0.3);
1031
+ }
1032
+
1033
+ .edit-btn.save:hover { background: rgba(0,232,223,0.2); }
1034
+
1035
+ .edit-textarea {
1036
+ flex: 1;
1037
+ min-height: 300px;
1038
+ background: var(--bg-primary);
1039
+ border: none;
1040
+ color: var(--text-primary);
1041
+ font-family: var(--font-mono);
1042
+ font-size: 13px;
1043
+ line-height: 1.7;
1044
+ padding: 16px 20px;
1045
+ resize: none;
1046
+ outline: none;
1047
+ }
1048
+
1049
+ .edit-textarea::placeholder { color: var(--text-muted); }
1050
+
1051
+ .note-edit-btn {
1052
+ background: transparent;
1053
+ border: 1px solid var(--border);
1054
+ color: var(--text-muted);
1055
+ font-family: var(--font-mono);
1056
+ font-size: 10px;
1057
+ padding: 3px 10px;
1058
+ border-radius: var(--radius-sm);
1059
+ cursor: pointer;
1060
+ transition: all 0.15s;
1061
+ float: right;
1062
+ margin-bottom: 12px;
1063
+ }
1064
+
1065
+ .note-edit-btn:hover {
1066
+ border-color: var(--text-muted);
1067
+ color: var(--text-secondary);
1068
+ }
1069
+
1070
+ /* ============ BACKLINK CONTEXT ============ */
1071
+ .rp-item .rp-context {
1072
+ font-size: 10px;
1073
+ color: var(--text-muted);
1074
+ margin-top: 2px;
1075
+ line-height: 1.4;
1076
+ overflow: hidden;
1077
+ text-overflow: ellipsis;
1078
+ white-space: nowrap;
1079
+ }
1080
+
1081
+ .rp-item-col {
1082
+ display: flex;
1083
+ flex-direction: column;
1084
+ padding: 5px 8px;
1085
+ border-radius: var(--radius-sm);
1086
+ cursor: pointer;
1087
+ margin-bottom: 1px;
1088
+ transition: background 0.1s;
1089
+ overflow: hidden;
1090
+ }
1091
+
1092
+ .rp-item-col:hover { background: var(--bg-hover); }
1093
+
1094
+ /* ============ TRANSITIONS ============ */
1095
+ .fade-in { animation: fadeIn 0.15s ease; }
1096
+
1097
+ @keyframes fadeIn {
1098
+ from { opacity: 0; transform: translateY(3px); }
1099
+ to { opacity: 1; transform: translateY(0); }
813
1100
  }
814
1101
  </style>
815
1102
  </head>
@@ -821,7 +1108,7 @@ body.resizing .resize-handle {
821
1108
  <div class="logo">KYP-MEM <span class="logo-sub">know your project</span></div>
822
1109
  <div class="breadcrumb" id="breadcrumb"></div>
823
1110
  <div class="header-actions">
824
- <button class="toggle-btn active" id="graph-toggle" title="Toggle graph view">
1111
+ <button class="header-btn active" id="graph-toggle" title="Toggle graph">
825
1112
  <span class="dot"></span>
826
1113
  <span>GRAPH</span>
827
1114
  </button>
@@ -838,9 +1125,23 @@ body.resizing .resize-handle {
838
1125
  <div class="sidebar">
839
1126
  <div class="sidebar-scroll">
840
1127
  <div class="sidebar-section">
841
- <div class="sidebar-section-title">Explorer</div>
1128
+ <div class="section-label">Explorer</div>
1129
+ <div id="filter-info" class="filter-info" style="display:none;">
1130
+ <span id="filter-count"></span>
1131
+ <span class="clear-btn" id="clear-filters">clear</span>
1132
+ </div>
842
1133
  <div id="file-tree"></div>
843
1134
  </div>
1135
+ <div class="tag-filter-section">
1136
+ <div class="tag-filter-header" id="tag-filter-toggle">
1137
+ <span>Tags</span>
1138
+ <span class="arrow open" id="tag-arrow">&#9654;</span>
1139
+ </div>
1140
+ <div class="tag-filter-body" id="tag-filter-body">
1141
+ <div class="tag-filter-active" id="active-tags"></div>
1142
+ <div class="tag-cloud" id="tag-cloud"></div>
1143
+ </div>
1144
+ </div>
844
1145
  </div>
845
1146
  <div class="stats-bar" id="stats-bar"></div>
846
1147
  </div>
@@ -853,7 +1154,7 @@ body.resizing .resize-handle {
853
1154
  <div class="empty-state">
854
1155
  <div class="es-logo">KYP-MEM</div>
855
1156
  <div class="es-tagline">Know Your Project Memory</div>
856
- <div class="es-hint">Select a note from the sidebar or press <kbd>&#8984;K</kbd> to search</div>
1157
+ <div class="es-hint">Select a note or press <kbd>&#8984;O</kbd> to quick-switch &middot; <kbd>&#8984;K</kbd> to search</div>
857
1158
  </div>
858
1159
  </div>
859
1160
 
@@ -863,9 +1164,13 @@ body.resizing .resize-handle {
863
1164
  <!-- Right panel -->
864
1165
  <div class="right-panel" id="right-panel">
865
1166
  <div id="graph-section">
866
- <div class="rp-section-title">Graph View</div>
1167
+ <div class="rp-section-title">Local Graph</div>
867
1168
  <div id="graph-container"></div>
868
1169
  </div>
1170
+ <div id="rp-outline" class="rp-section" style="display:none;">
1171
+ <div class="rp-section-title">Outline <span class="rp-count" id="outline-count"></span></div>
1172
+ <div id="rp-outline-list"></div>
1173
+ </div>
869
1174
  <div id="rp-backlinks" class="rp-section" style="display:none;">
870
1175
  <div class="rp-section-title">Backlinks <span class="rp-count" id="bl-count"></span></div>
871
1176
  <div id="rp-backlinks-list"></div>
@@ -878,6 +1183,32 @@ body.resizing .resize-handle {
878
1183
  <div class="rp-section-title">Outgoing Links <span class="rp-count" id="out-count"></span></div>
879
1184
  <div id="rp-outlinks-list"></div>
880
1185
  </div>
1186
+ <div id="rp-unlinked" class="rp-section" style="display:none;">
1187
+ <div class="rp-section-title">Unlinked Mentions <span class="rp-count" id="unlinked-count"></span></div>
1188
+ <div id="rp-unlinked-list"></div>
1189
+ </div>
1190
+ </div>
1191
+ </div>
1192
+
1193
+ <!-- Edit Modal -->
1194
+ <div class="edit-overlay" id="edit-overlay">
1195
+ <div class="edit-modal">
1196
+ <div class="edit-header">
1197
+ <span class="edit-path" id="edit-path"></span>
1198
+ <div class="edit-actions">
1199
+ <button class="edit-btn cancel" id="edit-cancel">ESC</button>
1200
+ <button class="edit-btn save" id="edit-save">SAVE</button>
1201
+ </div>
1202
+ </div>
1203
+ <textarea class="edit-textarea" id="edit-textarea" placeholder="Write markdown..."></textarea>
1204
+ </div>
1205
+ </div>
1206
+
1207
+ <!-- Quick Switcher Overlay -->
1208
+ <div class="quick-switcher-overlay" id="qs-overlay">
1209
+ <div class="quick-switcher">
1210
+ <input type="text" id="qs-input" placeholder="Jump to note...">
1211
+ <div class="quick-switcher-results" id="qs-results"></div>
881
1212
  </div>
882
1213
  </div>
883
1214
 
@@ -886,6 +1217,8 @@ let currentPath = null;
886
1217
  let treeData = null;
887
1218
  let allNotes = {};
888
1219
  let graphVisible = true;
1220
+ let activeTagFilters = new Set();
1221
+ let qsSelectedIndex = 0;
889
1222
 
890
1223
  async function fetchJSON(url) {
891
1224
  const r = await fetch(url);
@@ -910,14 +1243,113 @@ document.getElementById('graph-toggle').addEventListener('click', () => {
910
1243
  }
911
1244
  });
912
1245
 
913
- // --- Keyboard shortcut ---
1246
+ // --- Keyboard shortcuts ---
914
1247
  document.addEventListener('keydown', (e) => {
915
1248
  if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
916
1249
  e.preventDefault();
917
1250
  document.getElementById('search-input').focus();
918
1251
  }
1252
+ if ((e.metaKey || e.ctrlKey) && e.key === 'o') {
1253
+ e.preventDefault();
1254
+ openQuickSwitcher();
1255
+ }
1256
+ if (e.key === 'Escape') {
1257
+ closeQuickSwitcher();
1258
+ }
919
1259
  });
920
1260
 
1261
+ // --- Quick Switcher ---
1262
+ function openQuickSwitcher() {
1263
+ const overlay = document.getElementById('qs-overlay');
1264
+ const input = document.getElementById('qs-input');
1265
+ overlay.classList.add('active');
1266
+ input.value = '';
1267
+ input.focus();
1268
+ qsSelectedIndex = 0;
1269
+ renderQsResults('');
1270
+ }
1271
+
1272
+ function closeQuickSwitcher() {
1273
+ document.getElementById('qs-overlay').classList.remove('active');
1274
+ }
1275
+
1276
+ document.getElementById('qs-overlay').addEventListener('click', (e) => {
1277
+ if (e.target === e.currentTarget) closeQuickSwitcher();
1278
+ });
1279
+
1280
+ document.getElementById('qs-input').addEventListener('input', (e) => {
1281
+ qsSelectedIndex = 0;
1282
+ renderQsResults(e.target.value.trim().toLowerCase());
1283
+ });
1284
+
1285
+ document.getElementById('qs-input').addEventListener('keydown', (e) => {
1286
+ const items = document.querySelectorAll('.qs-item');
1287
+ if (e.key === 'ArrowDown') {
1288
+ e.preventDefault();
1289
+ qsSelectedIndex = Math.min(qsSelectedIndex + 1, items.length - 1);
1290
+ updateQsSelection();
1291
+ } else if (e.key === 'ArrowUp') {
1292
+ e.preventDefault();
1293
+ qsSelectedIndex = Math.max(qsSelectedIndex - 1, 0);
1294
+ updateQsSelection();
1295
+ } else if (e.key === 'Enter') {
1296
+ e.preventDefault();
1297
+ const selected = items[qsSelectedIndex];
1298
+ if (selected) {
1299
+ loadNote(selected.dataset.path);
1300
+ closeQuickSwitcher();
1301
+ }
1302
+ }
1303
+ });
1304
+
1305
+ function renderQsResults(query) {
1306
+ const container = document.getElementById('qs-results');
1307
+ const entries = Object.entries(allNotes);
1308
+
1309
+ let filtered = entries;
1310
+ if (query) {
1311
+ filtered = entries.filter(([path, note]) => {
1312
+ const name = note.title.toLowerCase();
1313
+ const p = path.toLowerCase();
1314
+ return name.includes(query) || p.includes(query);
1315
+ });
1316
+ }
1317
+
1318
+ filtered.sort((a, b) => a[1].title.localeCompare(b[1].title));
1319
+ filtered = filtered.slice(0, 15);
1320
+
1321
+ if (filtered.length === 0) {
1322
+ container.innerHTML = '<div class="qs-empty">No notes found</div>';
1323
+ return;
1324
+ }
1325
+
1326
+ container.innerHTML = filtered.map(([path, note], i) => {
1327
+ const folder = path.includes('/') ? path.split('/').slice(0, -1).join('/') : '';
1328
+ return `<div class="qs-item${i === qsSelectedIndex ? ' selected' : ''}" data-path="${path}">
1329
+ <span class="qs-icon">&#9671;</span>
1330
+ <span class="qs-name">${note.title}</span>
1331
+ ${folder ? `<span class="qs-path">${folder}</span>` : ''}
1332
+ </div>`;
1333
+ }).join('');
1334
+
1335
+ container.querySelectorAll('.qs-item').forEach((el, i) => {
1336
+ el.addEventListener('click', () => {
1337
+ loadNote(el.dataset.path);
1338
+ closeQuickSwitcher();
1339
+ });
1340
+ el.addEventListener('mouseenter', () => {
1341
+ qsSelectedIndex = i;
1342
+ updateQsSelection();
1343
+ });
1344
+ });
1345
+ }
1346
+
1347
+ function updateQsSelection() {
1348
+ document.querySelectorAll('.qs-item').forEach((el, i) => {
1349
+ el.classList.toggle('selected', i === qsSelectedIndex);
1350
+ });
1351
+ }
1352
+
921
1353
  // --- File Tree ---
922
1354
  function renderTree(node, container) {
923
1355
  if (node.type === 'folder' && node.name !== 'vault') {
@@ -961,7 +1393,6 @@ async function loadNote(path) {
961
1393
  el.classList.toggle('active', el.dataset.path === path);
962
1394
  });
963
1395
 
964
- // Breadcrumb
965
1396
  const parts = path.replace('.md', '').split('/');
966
1397
  document.getElementById('breadcrumb').innerHTML = parts.map((p, i) =>
967
1398
  i < parts.length - 1
@@ -969,12 +1400,12 @@ async function loadNote(path) {
969
1400
  : `<span class="current">${p}</span>`
970
1401
  ).join('');
971
1402
 
972
- // Content
973
1403
  const contentEl = document.getElementById('content');
974
1404
  let html = '<div class="fade-in">';
975
1405
 
1406
+ html += `<button class="note-edit-btn" onclick="openEditor('${path}')">EDIT</button>`;
976
1407
  html += '<div class="note-properties">';
977
- (note.tags || []).forEach(t => { html += `<span class="tag">#${t}</span>`; });
1408
+ (note.tags || []).forEach(t => { html += `<span class="tag clickable-tag" data-tag="${t}">#${t}</span>`; });
978
1409
  Object.entries(note.properties || {}).forEach(([k, v]) => {
979
1410
  html += `<span class="prop-item"><span class="prop-key">${k}:</span> ${v}</span>`;
980
1411
  });
@@ -1000,7 +1431,15 @@ async function loadNote(path) {
1000
1431
  });
1001
1432
  });
1002
1433
 
1434
+ contentEl.querySelectorAll('.clickable-tag').forEach(el => {
1435
+ el.addEventListener('click', () => {
1436
+ activeTagFilters.add(el.dataset.tag);
1437
+ applyTagFilter();
1438
+ });
1439
+ });
1440
+
1003
1441
  renderRightPanel(note);
1442
+ renderOutline(note);
1004
1443
  if (graphVisible) renderGraph(note);
1005
1444
  }
1006
1445
 
@@ -1013,20 +1452,58 @@ function findNotePath(name) {
1013
1452
  return null;
1014
1453
  }
1015
1454
 
1455
+ // --- Outline ---
1456
+ function renderOutline(note) {
1457
+ const section = document.getElementById('rp-outline');
1458
+ const list = document.getElementById('rp-outline-list');
1459
+ list.innerHTML = '';
1460
+
1461
+ const content = note.content || '';
1462
+ const headings = [];
1463
+ content.split('\n').forEach(line => {
1464
+ const m = line.match(/^(#{1,3})\s+(.+)/);
1465
+ if (m) headings.push({ level: m[1].length, text: m[2].trim() });
1466
+ });
1467
+
1468
+ if (headings.length < 2) {
1469
+ section.style.display = 'none';
1470
+ return;
1471
+ }
1472
+
1473
+ section.style.display = '';
1474
+ document.getElementById('outline-count').textContent = headings.length;
1475
+
1476
+ headings.forEach(h => {
1477
+ const el = document.createElement('div');
1478
+ el.className = `outline-item h${h.level}`;
1479
+ el.textContent = h.text;
1480
+ el.addEventListener('click', () => {
1481
+ const contentEl = document.getElementById('content');
1482
+ const target = Array.from(contentEl.querySelectorAll('h1,h2,h3')).find(
1483
+ el => el.textContent.trim() === h.text
1484
+ );
1485
+ if (target) target.scrollIntoView({ behavior: 'smooth', block: 'start' });
1486
+ });
1487
+ list.appendChild(el);
1488
+ });
1489
+ }
1490
+
1016
1491
  // --- Right Panel ---
1017
1492
  function renderRightPanel(note) {
1018
1493
  const blSection = document.getElementById('rp-backlinks');
1019
1494
  const blList = document.getElementById('rp-backlinks-list');
1020
1495
  blList.innerHTML = '';
1021
- if (note.backlinks && note.backlinks.length) {
1496
+ const backlinks = note.backlinks || [];
1497
+ if (backlinks.length) {
1022
1498
  blSection.style.display = '';
1023
- document.getElementById('bl-count').textContent = note.backlinks.length;
1024
- note.backlinks.forEach(path => {
1025
- const n = allNotes[path];
1499
+ document.getElementById('bl-count').textContent = backlinks.length;
1500
+ backlinks.forEach(bl => {
1026
1501
  const item = document.createElement('div');
1027
- item.className = 'rp-item';
1028
- item.innerHTML = `<span class="rp-title rp-backlink-title">${n ? n.title : path}</span>`;
1029
- item.addEventListener('click', () => loadNote(path));
1502
+ item.className = 'rp-item-col';
1503
+ let html = `<span class="rp-title rp-backlink-title" style="font-size:11px">${bl.title || bl.path || bl}</span>`;
1504
+ if (bl.context) html += `<span class="rp-context">${bl.context}</span>`;
1505
+ item.innerHTML = html;
1506
+ item.addEventListener('click', () => loadNote(bl.path || bl));
1030
1507
  blList.appendChild(item);
1031
1508
  });
1032
1509
  } else {
@@ -1062,14 +1539,86 @@ function renderRightPanel(note) {
1062
1539
  item.className = 'rp-item';
1063
1540
  item.innerHTML = `<span class="rp-title">${link}</span>`;
1064
1541
  if (path) item.addEventListener('click', () => loadNote(path));
1065
- else item.style.opacity = '0.4';
1542
+ else item.style.opacity = '0.3';
1066
1543
  outList.appendChild(item);
1067
1544
  });
1068
1545
  } else {
1069
1546
  outSection.style.display = 'none';
1070
1547
  }
1548
+
1549
+ const ulSection = document.getElementById('rp-unlinked');
1550
+ const ulList = document.getElementById('rp-unlinked-list');
1551
+ ulList.innerHTML = '';
1552
+ const unlinked = note.unlinked || [];
1553
+ if (unlinked.length) {
1554
+ ulSection.style.display = '';
1555
+ document.getElementById('unlinked-count').textContent = unlinked.length;
1556
+ unlinked.forEach(u => {
1557
+ const item = document.createElement('div');
1558
+ item.className = 'rp-item-col';
1559
+ let html = `<span class="rp-title" style="font-size:11px;color:var(--text-secondary)">${u.title}</span>`;
1560
+ if (u.context) html += `<span class="rp-context">${u.context}</span>`;
1561
+ item.innerHTML = html;
1562
+ item.addEventListener('click', () => loadNote(u.path));
1563
+ ulList.appendChild(item);
1564
+ });
1565
+ } else {
1566
+ ulSection.style.display = 'none';
1567
+ }
1568
+ }
1569
+
1570
+ // --- Editor ---
1571
+ let editingPath = null;
1572
+ let editingNote = null;
1573
+
1574
+ async function openEditor(path) {
1575
+ const note = await fetchJSON(`/api/note/${path}`);
1576
+ if (note.error) return;
1577
+ editingPath = path;
1578
+ editingNote = note;
1579
+ document.getElementById('edit-path').textContent = path;
1580
+ document.getElementById('edit-textarea').value = note.content || '';
1581
+ document.getElementById('edit-overlay').classList.add('active');
1582
+ document.getElementById('edit-textarea').focus();
1071
1583
  }
1072
1584
 
1585
+ document.getElementById('edit-cancel').addEventListener('click', closeEditor);
1586
+ document.getElementById('edit-overlay').addEventListener('click', (e) => {
1587
+ if (e.target === e.currentTarget) closeEditor();
1588
+ });
1589
+
1590
+ document.getElementById('edit-save').addEventListener('click', async () => {
1591
+ if (!editingPath) return;
1592
+ const content = document.getElementById('edit-textarea').value;
1593
+ await fetch(`/api/note/${editingPath}`, {
1594
+ method: 'POST',
1595
+ headers: { 'Content-Type': 'application/json' },
1596
+ body: JSON.stringify({
1597
+ content,
1598
+ tags: editingNote.tags || [],
1599
+ properties: editingNote.properties || {},
1600
+ }),
1601
+ });
1602
+ closeEditor();
1603
+ await loadNote(editingPath);
1604
+ });
1605
+
1606
+ function closeEditor() {
1607
+ document.getElementById('edit-overlay').classList.remove('active');
1608
+ editingPath = null;
1609
+ editingNote = null;
1610
+ }
1611
+
1612
+ document.addEventListener('keydown', (e) => {
1613
+ if (e.key === 'Escape' && document.getElementById('edit-overlay').classList.contains('active')) {
1614
+ closeEditor();
1615
+ }
1616
+ if ((e.metaKey || e.ctrlKey) && e.key === 's' && editingPath) {
1617
+ e.preventDefault();
1618
+ document.getElementById('edit-save').click();
1619
+ }
1620
+ });
1621
+
1073
1622
  // --- Graph ---
1074
1623
  function renderGraph(note) {
1075
1624
  const container = document.getElementById('graph-container');
@@ -1115,16 +1664,11 @@ function renderGraph(note) {
1115
1664
  const svg = d3.select(container).append('svg')
1116
1665
  .attr('viewBox', `0 0 ${width} ${height}`);
1117
1666
 
1118
- const defs = svg.append('defs');
1119
- const grad = defs.append('radialGradient').attr('id', 'node-glow');
1120
- grad.append('stop').attr('offset', '0%').attr('stop-color', 'var(--neon-cyan)').attr('stop-opacity', 0.3);
1121
- grad.append('stop').attr('offset', '100%').attr('stop-color', 'var(--neon-cyan)').attr('stop-opacity', 0);
1122
-
1123
1667
  const simulation = d3.forceSimulation(nodeArray)
1124
- .force('link', d3.forceLink(links).id(d => d.id).distance(55))
1125
- .force('charge', d3.forceManyBody().strength(-120))
1668
+ .force('link', d3.forceLink(links).id(d => d.id).distance(50))
1669
+ .force('charge', d3.forceManyBody().strength(-100))
1126
1670
  .force('center', d3.forceCenter(width / 2, height / 2))
1127
- .force('collision', d3.forceCollide().radius(25));
1671
+ .force('collision', d3.forceCollide().radius(22));
1128
1672
 
1129
1673
  const link = svg.selectAll('.graph-link')
1130
1674
  .data(links).enter().append('line')
@@ -1140,9 +1684,8 @@ function renderGraph(note) {
1140
1684
  .on('end', (e, d) => { if (!e.active) simulation.alphaTarget(0); d.fx = null; d.fy = null; })
1141
1685
  );
1142
1686
 
1143
- node.filter(d => d.active).append('circle').attr('r', 14).style('fill', 'url(#node-glow)').style('stroke', 'none');
1144
- node.append('circle').attr('r', d => d.active ? 6 : 4);
1145
- node.append('text').text(d => d.title).attr('dx', 12).attr('dy', 3);
1687
+ node.append('circle').attr('r', d => d.active ? 5 : 3.5);
1688
+ node.append('text').text(d => d.title).attr('dx', 10).attr('dy', 3);
1146
1689
 
1147
1690
  simulation.on('tick', () => {
1148
1691
  link
@@ -1195,14 +1738,113 @@ document.addEventListener('click', (e) => {
1195
1738
  if (!e.target.closest('.search-box')) searchResults.classList.remove('active');
1196
1739
  });
1197
1740
 
1741
+ // --- Tag Filter ---
1742
+ document.getElementById('tag-filter-toggle').addEventListener('click', () => {
1743
+ const body = document.getElementById('tag-filter-body');
1744
+ const arrow = document.getElementById('tag-arrow');
1745
+ body.classList.toggle('collapsed');
1746
+ arrow.classList.toggle('open');
1747
+ });
1748
+
1749
+ document.getElementById('clear-filters').addEventListener('click', () => {
1750
+ activeTagFilters.clear();
1751
+ applyTagFilter();
1752
+ });
1753
+
1754
+ function renderTagCloud(tags) {
1755
+ const cloud = document.getElementById('tag-cloud');
1756
+ cloud.innerHTML = '';
1757
+ const sorted = Object.entries(tags).sort((a, b) => b[1] - a[1]);
1758
+ sorted.forEach(([tag, count]) => {
1759
+ const chip = document.createElement('span');
1760
+ chip.className = 'tag-chip' + (activeTagFilters.has(tag) ? ' selected' : '');
1761
+ chip.innerHTML = `#${tag}<span class="tag-count">${count}</span>`;
1762
+ chip.addEventListener('click', () => {
1763
+ if (activeTagFilters.has(tag)) {
1764
+ activeTagFilters.delete(tag);
1765
+ } else {
1766
+ activeTagFilters.add(tag);
1767
+ }
1768
+ applyTagFilter();
1769
+ });
1770
+ cloud.appendChild(chip);
1771
+ });
1772
+ }
1773
+
1774
+ function applyTagFilter() {
1775
+ const activeEl = document.getElementById('active-tags');
1776
+ const filterInfo = document.getElementById('filter-info');
1777
+ const filterCount = document.getElementById('filter-count');
1778
+
1779
+ activeEl.innerHTML = '';
1780
+ activeTagFilters.forEach(tag => {
1781
+ const el = document.createElement('span');
1782
+ el.className = 'active-tag';
1783
+ el.innerHTML = `#${tag}<span class="remove">&times;</span>`;
1784
+ el.addEventListener('click', () => {
1785
+ activeTagFilters.delete(tag);
1786
+ applyTagFilter();
1787
+ });
1788
+ activeEl.appendChild(el);
1789
+ });
1790
+
1791
+ document.querySelectorAll('.tag-chip').forEach(chip => {
1792
+ const tag = chip.textContent.replace('#', '').replace(/\d+$/, '');
1793
+ chip.classList.toggle('selected', activeTagFilters.has(tag));
1794
+ });
1795
+
1796
+ const treeItems = document.querySelectorAll('.tree-item[data-path]');
1797
+ let visibleCount = 0;
1798
+
1799
+ if (activeTagFilters.size === 0) {
1800
+ treeItems.forEach(el => { el.style.display = ''; });
1801
+ document.querySelectorAll('.tree-children').forEach(el => el.classList.remove('collapsed'));
1802
+ filterInfo.style.display = 'none';
1803
+ renderTagCloud(collectAllTags());
1804
+ return;
1805
+ }
1806
+
1807
+ const matchingPaths = new Set();
1808
+
1809
+ for (const [path, note] of Object.entries(allNotes)) {
1810
+ const noteTags = (note.tags || []).map(t => t.toLowerCase());
1811
+ const matches = [...activeTagFilters].every(f => noteTags.includes(f.toLowerCase()));
1812
+ if (matches) matchingPaths.add(path);
1813
+ }
1814
+
1815
+ treeItems.forEach(el => {
1816
+ const path = el.dataset.path;
1817
+ if (matchingPaths.has(path)) {
1818
+ el.style.display = '';
1819
+ visibleCount++;
1820
+ } else {
1821
+ el.style.display = 'none';
1822
+ }
1823
+ });
1824
+
1825
+ document.querySelectorAll('.tree-children').forEach(el => el.classList.remove('collapsed'));
1826
+
1827
+ filterInfo.style.display = '';
1828
+ filterCount.textContent = `${visibleCount} note${visibleCount !== 1 ? 's' : ''}`;
1829
+ renderTagCloud(collectAllTags());
1830
+ }
1831
+
1832
+ function collectAllTags() {
1833
+ const tags = {};
1834
+ for (const note of Object.values(allNotes)) {
1835
+ (note.tags || []).forEach(t => { tags[t] = (tags[t] || 0) + 1; });
1836
+ }
1837
+ return tags;
1838
+ }
1839
+
1198
1840
  // --- Resizable Panels ---
1199
1841
  function initResize() {
1200
1842
  const layout = document.getElementById('layout');
1201
1843
  const leftHandle = document.getElementById('resize-left');
1202
1844
  const rightHandle = document.getElementById('resize-right');
1203
1845
 
1204
- let sidebarW = parseInt(localStorage.getItem('kyp-sidebar-w')) || 260;
1205
- let rightW = parseInt(localStorage.getItem('kyp-right-w')) || 280;
1846
+ let sidebarW = parseInt(localStorage.getItem('kyp-sidebar-w')) || 256;
1847
+ let rightW = parseInt(localStorage.getItem('kyp-right-w')) || 272;
1206
1848
 
1207
1849
  layout.style.setProperty('--sidebar-w', sidebarW + 'px');
1208
1850
  layout.style.setProperty('--right-w', rightW + 'px');
@@ -1242,7 +1884,7 @@ function initResize() {
1242
1884
  save: () => localStorage.setItem('kyp-sidebar-w', sidebarW),
1243
1885
  invert: false,
1244
1886
  min: 180,
1245
- max: 450,
1887
+ max: 400,
1246
1888
  });
1247
1889
 
1248
1890
  makeDraggable(rightHandle, {
@@ -1251,7 +1893,7 @@ function initResize() {
1251
1893
  save: () => localStorage.setItem('kyp-right-w', rightW),
1252
1894
  invert: true,
1253
1895
  min: 200,
1254
- max: 500,
1896
+ max: 450,
1255
1897
  });
1256
1898
  }
1257
1899
 
@@ -1277,6 +1919,7 @@ async function init() {
1277
1919
  await Promise.all(promises);
1278
1920
 
1279
1921
  renderTree(treeData, document.getElementById('file-tree'));
1922
+ renderTagCloud(collectAllTags());
1280
1923
 
1281
1924
  document.getElementById('stats-bar').innerHTML = `
1282
1925
  <span><span class="stat-val">${stats.notes}</span> notes</span>