kyp-mem 0.2.2 → 0.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/README.md +53 -54
- package/bin/cli.mjs +56 -1
- package/kyp_mem/__init__.py +1 -1
- package/kyp_mem/cli.py +101 -0
- package/kyp_mem/hooks.py +150 -0
- package/kyp_mem/server.py +140 -9
- package/kyp_mem/static/index.html +1438 -324
- package/kyp_mem/ui.py +135 -2
- package/package.json +2 -2
- package/pyproject.toml +2 -2
|
@@ -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
|
|
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: #
|
|
14
|
-
--bg-primary: #
|
|
15
|
-
--bg-secondary: #
|
|
16
|
-
--bg-tertiary: #
|
|
17
|
-
--bg-hover: #
|
|
18
|
-
--bg-active: #
|
|
19
|
-
--bg-card: #
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
--neon-
|
|
23
|
-
--neon-
|
|
24
|
-
--neon-
|
|
25
|
-
--neon-
|
|
26
|
-
--neon-
|
|
27
|
-
--neon-
|
|
28
|
-
--neon-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
--glow-
|
|
32
|
-
--glow-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
--text-
|
|
36
|
-
--text-
|
|
37
|
-
--
|
|
38
|
-
--border
|
|
13
|
+
--bg-void: #09090b;
|
|
14
|
+
--bg-primary: #0d0d10;
|
|
15
|
+
--bg-secondary: #0f0f12;
|
|
16
|
+
--bg-tertiary: #08080a;
|
|
17
|
+
--bg-hover: #15151c;
|
|
18
|
+
--bg-active: #1c1c26;
|
|
19
|
+
--bg-card: #111116;
|
|
20
|
+
--bg-surface: #0b0b0e;
|
|
21
|
+
|
|
22
|
+
--neon-cyan: #D97757;
|
|
23
|
+
--neon-green: #5bb98c;
|
|
24
|
+
--neon-magenta: #c47ad7;
|
|
25
|
+
--neon-purple: #a78bfa;
|
|
26
|
+
--neon-orange: #e8935a;
|
|
27
|
+
--neon-yellow: #d4a853;
|
|
28
|
+
--neon-blue: #7da8d4;
|
|
29
|
+
--neon-red: #d47171;
|
|
30
|
+
|
|
31
|
+
--glow-cyan: 0 0 8px #D9775730;
|
|
32
|
+
--glow-green: 0 0 8px #5bb98c30;
|
|
33
|
+
--glow-magenta: 0 0 8px #c47ad730;
|
|
34
|
+
|
|
35
|
+
--text-primary: #d8d5cf;
|
|
36
|
+
--text-secondary: #807b73;
|
|
37
|
+
--text-muted: #44413a;
|
|
38
|
+
--border: #1c1a17;
|
|
39
|
+
--border-subtle: #16150f;
|
|
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(
|
|
61
|
-
linear-gradient(90deg, rgba(
|
|
62
|
-
background-size:
|
|
65
|
+
linear-gradient(rgba(217,119,87,0.015) 1px, transparent 1px),
|
|
66
|
+
linear-gradient(90deg, rgba(217,119,87,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,
|
|
70
|
-
grid-template-rows:
|
|
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,
|
|
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:
|
|
89
|
+
background: var(--border-subtle);
|
|
85
90
|
cursor: col-resize;
|
|
86
91
|
position: relative;
|
|
87
92
|
z-index: 10;
|
|
88
|
-
transition: background 0.
|
|
93
|
+
transition: background 0.3s;
|
|
89
94
|
}
|
|
90
95
|
|
|
91
96
|
.resize-handle::before {
|
|
92
97
|
content: '';
|
|
93
98
|
position: absolute;
|
|
94
|
-
inset: 0 -
|
|
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:
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
body.resizing {
|
|
125
|
-
cursor: col-resize !important;
|
|
126
|
-
user-select: none !important;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
body.resizing * {
|
|
130
|
-
cursor: col-resize !important;
|
|
131
|
-
pointer-events: none !important;
|
|
105
|
+
background: var(--neon-cyan);
|
|
106
|
+
box-shadow: 0 0 12px rgba(217,119,87,0.2);
|
|
132
107
|
}
|
|
133
108
|
|
|
134
|
-
body.resizing
|
|
135
|
-
|
|
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:
|
|
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),
|
|
158
|
-
opacity: 0.
|
|
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:
|
|
139
|
+
font-size: 13px;
|
|
165
140
|
color: var(--neon-cyan);
|
|
166
|
-
|
|
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:
|
|
150
|
+
margin-left: 10px;
|
|
178
151
|
}
|
|
179
152
|
|
|
180
153
|
.breadcrumb {
|
|
181
154
|
font-family: var(--font-mono);
|
|
182
|
-
font-size:
|
|
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
|
|
190
|
-
.breadcrumb .current { color: var(--neon-cyan); font-weight:
|
|
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:
|
|
169
|
+
gap: 8px;
|
|
197
170
|
}
|
|
198
171
|
|
|
199
|
-
.
|
|
200
|
-
background:
|
|
172
|
+
.header-btn {
|
|
173
|
+
background: transparent;
|
|
201
174
|
border: 1px solid var(--border);
|
|
202
|
-
color: var(--text-
|
|
175
|
+
color: var(--text-muted);
|
|
203
176
|
font-family: var(--font-mono);
|
|
204
|
-
font-size:
|
|
177
|
+
font-size: 10px;
|
|
205
178
|
padding: 5px 10px;
|
|
206
|
-
border-radius:
|
|
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
|
-
.
|
|
215
|
-
border-color: var(--
|
|
216
|
-
color: var(--
|
|
188
|
+
.header-btn:hover {
|
|
189
|
+
border-color: var(--text-muted);
|
|
190
|
+
color: var(--text-secondary);
|
|
217
191
|
}
|
|
218
192
|
|
|
219
|
-
.
|
|
220
|
-
border-color:
|
|
193
|
+
.header-btn.active {
|
|
194
|
+
border-color: rgba(217,119,87,0.3);
|
|
221
195
|
color: var(--neon-cyan);
|
|
222
|
-
background: rgba(
|
|
223
|
-
box-shadow: 0 0 8px rgba(0, 255, 245, 0.15);
|
|
196
|
+
background: rgba(217,119,87,0.05);
|
|
224
197
|
}
|
|
225
198
|
|
|
226
|
-
.
|
|
227
|
-
width:
|
|
228
|
-
height:
|
|
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
|
-
.
|
|
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-
|
|
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:
|
|
250
|
-
font-size:
|
|
251
|
-
width:
|
|
222
|
+
border-radius: var(--radius);
|
|
223
|
+
font-size: 11px;
|
|
224
|
+
width: 200px;
|
|
252
225
|
outline: none;
|
|
253
|
-
transition: all 0.
|
|
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:
|
|
260
|
-
box-shadow: 0 0
|
|
261
|
-
width:
|
|
232
|
+
border-color: rgba(217,119,87,0.3);
|
|
233
|
+
box-shadow: 0 0 16px rgba(217,119,87,0.08);
|
|
234
|
+
width: 260px;
|
|
262
235
|
}
|
|
263
236
|
|
|
264
237
|
.search-box .search-icon {
|
|
265
238
|
position: absolute;
|
|
266
|
-
left:
|
|
239
|
+
left: 10px;
|
|
267
240
|
top: 50%;
|
|
268
241
|
transform: translateY(-50%);
|
|
269
242
|
color: var(--text-muted);
|
|
270
|
-
font-size:
|
|
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:
|
|
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% +
|
|
263
|
+
top: calc(100% + 8px);
|
|
290
264
|
right: 0;
|
|
291
|
-
width:
|
|
292
|
-
max-height:
|
|
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:
|
|
270
|
+
border-radius: var(--radius-lg);
|
|
297
271
|
z-index: 100;
|
|
298
272
|
display: none;
|
|
299
|
-
|
|
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:
|
|
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:
|
|
317
|
-
font-weight:
|
|
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:
|
|
298
|
+
margin-top: 2px;
|
|
326
299
|
}
|
|
327
300
|
|
|
328
301
|
.search-result .sr-snippet {
|
|
329
|
-
font-size:
|
|
302
|
+
font-size: 11px;
|
|
330
303
|
color: var(--text-secondary);
|
|
331
304
|
margin-top: 4px;
|
|
332
|
-
line-height: 1.
|
|
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:
|
|
402
|
+
padding: 6px 0;
|
|
348
403
|
}
|
|
349
404
|
|
|
350
|
-
.sidebar-section { padding: 0
|
|
405
|
+
.sidebar-section { padding: 0 8px; }
|
|
351
406
|
|
|
352
|
-
.
|
|
407
|
+
.section-label {
|
|
353
408
|
font-family: var(--font-mono);
|
|
354
|
-
font-size:
|
|
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
|
|
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:
|
|
366
|
-
border-radius:
|
|
423
|
+
padding: 4px 10px;
|
|
424
|
+
border-radius: var(--radius-sm);
|
|
367
425
|
cursor: pointer;
|
|
368
|
-
font-size:
|
|
426
|
+
font-size: 12px;
|
|
369
427
|
gap: 6px;
|
|
370
428
|
user-select: none;
|
|
371
|
-
transition:
|
|
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(
|
|
437
|
+
background: rgba(217,119,87,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:
|
|
395
|
-
font-size:
|
|
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:
|
|
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:
|
|
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
|
-
|
|
424
|
-
|
|
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
|
-
.
|
|
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(217,119,87,0.08);
|
|
527
|
+
color: var(--neon-cyan);
|
|
528
|
+
border: 1px solid rgba(217,119,87,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(217,119,87,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(217,119,87,0.08);
|
|
570
|
+
color: var(--neon-cyan);
|
|
571
|
+
border-color: rgba(217,119,87,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:
|
|
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:
|
|
602
|
+
font-size: 9px;
|
|
434
603
|
color: var(--text-muted);
|
|
435
604
|
display: flex;
|
|
436
|
-
gap:
|
|
605
|
+
gap: 12px;
|
|
437
606
|
flex-wrap: wrap;
|
|
438
607
|
}
|
|
439
608
|
|
|
440
|
-
.stat-val { color: var(--neon-green); font-weight:
|
|
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:
|
|
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:
|
|
453
|
-
margin-bottom:
|
|
454
|
-
padding-bottom:
|
|
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:
|
|
629
|
+
font-size: 10px;
|
|
461
630
|
font-weight: 500;
|
|
462
|
-
padding:
|
|
463
|
-
border-radius:
|
|
464
|
-
background: rgba(
|
|
465
|
-
color: var(--neon-
|
|
466
|
-
border: 1px solid rgba(
|
|
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(217,119,87,0.08);
|
|
641
|
+
color: var(--neon-cyan);
|
|
642
|
+
border-color: rgba(217,119,87,0.2);
|
|
643
|
+
cursor: pointer;
|
|
467
644
|
}
|
|
468
645
|
|
|
469
646
|
.prop-item {
|
|
470
647
|
font-family: var(--font-mono);
|
|
471
|
-
font-size:
|
|
472
|
-
padding:
|
|
473
|
-
border-radius:
|
|
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:
|
|
660
|
+
font-size: 26px;
|
|
484
661
|
font-weight: 700;
|
|
485
|
-
margin: 0 0
|
|
486
|
-
color: var(--
|
|
487
|
-
|
|
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:
|
|
668
|
+
font-size: 18px;
|
|
492
669
|
font-weight: 600;
|
|
493
|
-
margin:
|
|
494
|
-
color: var(--
|
|
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:
|
|
677
|
+
font-size: 15px;
|
|
501
678
|
font-weight: 600;
|
|
502
|
-
margin:
|
|
679
|
+
margin: 28px 0 8px;
|
|
503
680
|
color: var(--neon-purple);
|
|
504
681
|
}
|
|
505
682
|
|
|
506
683
|
.md-body p {
|
|
507
|
-
line-height: 1.
|
|
508
|
-
margin:
|
|
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.
|
|
693
|
+
line-height: 1.8;
|
|
516
694
|
color: var(--text-secondary);
|
|
517
|
-
margin:
|
|
695
|
+
margin: 2px 0;
|
|
696
|
+
font-size: 13.5px;
|
|
518
697
|
}
|
|
519
698
|
|
|
520
|
-
.md-body li::marker { color: var(--
|
|
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;
|
|
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:
|
|
530
|
-
border-radius:
|
|
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:
|
|
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:
|
|
564
|
-
line-height: 1.
|
|
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:
|
|
738
|
+
font-size: 12.5px;
|
|
572
739
|
}
|
|
573
740
|
|
|
574
741
|
.md-body th {
|
|
575
742
|
text-align: left;
|
|
576
|
-
padding:
|
|
577
|
-
border-bottom:
|
|
578
|
-
color: var(--
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
606
|
-
margin:
|
|
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(
|
|
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-
|
|
620
|
-
|
|
621
|
-
border-bottom-color: var(--neon-magenta);
|
|
785
|
+
color: var(--neon-cyan);
|
|
786
|
+
border-bottom-color: rgba(217,119,87,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:
|
|
796
|
+
gap: 12px;
|
|
632
797
|
}
|
|
633
798
|
|
|
634
799
|
.empty-state .es-logo {
|
|
635
800
|
font-family: var(--font-mono);
|
|
636
|
-
font-size:
|
|
801
|
+
font-size: 28px;
|
|
637
802
|
font-weight: 700;
|
|
638
803
|
color: var(--neon-cyan);
|
|
639
|
-
|
|
640
|
-
|
|
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:
|
|
810
|
+
font-size: 11px;
|
|
646
811
|
color: var(--text-muted);
|
|
647
|
-
letter-spacing:
|
|
812
|
+
letter-spacing: 3px;
|
|
648
813
|
text-transform: uppercase;
|
|
649
814
|
}
|
|
650
815
|
|
|
651
816
|
.empty-state .es-hint {
|
|
652
|
-
font-size:
|
|
817
|
+
font-size: 12px;
|
|
653
818
|
color: var(--text-muted);
|
|
654
|
-
margin-top:
|
|
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:
|
|
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:
|
|
836
|
+
padding: 12px;
|
|
673
837
|
}
|
|
674
838
|
|
|
675
|
-
.rp-section { margin-bottom:
|
|
839
|
+
.rp-section { margin-bottom: 20px; }
|
|
676
840
|
|
|
677
841
|
.rp-section-title {
|
|
678
842
|
font-family: var(--font-mono);
|
|
679
|
-
font-size:
|
|
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:
|
|
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:
|
|
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:
|
|
702
|
-
border-radius:
|
|
865
|
+
padding: 5px 8px;
|
|
866
|
+
border-radius: var(--radius-sm);
|
|
703
867
|
cursor: pointer;
|
|
704
|
-
font-size:
|
|
868
|
+
font-size: 11px;
|
|
705
869
|
gap: 8px;
|
|
706
|
-
margin-bottom:
|
|
707
|
-
transition:
|
|
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:
|
|
878
|
+
font-size: 10px;
|
|
717
879
|
color: var(--neon-green);
|
|
718
|
-
min-width:
|
|
719
|
-
|
|
880
|
+
min-width: 30px;
|
|
881
|
+
opacity: 0.8;
|
|
720
882
|
}
|
|
721
883
|
|
|
722
884
|
.rp-item .rp-title {
|
|
@@ -727,89 +889,404 @@ body.resizing .resize-handle {
|
|
|
727
889
|
font-weight: 500;
|
|
728
890
|
}
|
|
729
891
|
|
|
730
|
-
.rp-item .rp-backlink-title {
|
|
731
|
-
|
|
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
|
-
|
|
735
|
-
|
|
736
|
-
|
|
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:
|
|
744
|
-
border: 1px solid var(--border);
|
|
745
|
-
border-radius:
|
|
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%;
|
|
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
|
|
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
|
|
942
|
+
filter: drop-shadow(0 0 4px rgba(217,119,87,0.5));
|
|
774
943
|
}
|
|
775
944
|
|
|
776
945
|
.graph-node.active circle {
|
|
777
946
|
fill: var(--neon-cyan);
|
|
778
|
-
r:
|
|
779
|
-
filter: drop-shadow(0 0
|
|
947
|
+
r: 6;
|
|
948
|
+
filter: drop-shadow(0 0 6px rgba(217,119,87,0.5));
|
|
780
949
|
}
|
|
781
950
|
|
|
782
951
|
.graph-node text {
|
|
783
|
-
fill: var(--text-
|
|
952
|
+
fill: var(--text-muted);
|
|
784
953
|
font-family: var(--font-mono);
|
|
785
|
-
font-size:
|
|
954
|
+
font-size: 8px;
|
|
786
955
|
}
|
|
787
956
|
|
|
788
957
|
.graph-link {
|
|
789
|
-
stroke: rgba(
|
|
958
|
+
stroke: rgba(168,139,250,0.15);
|
|
790
959
|
stroke-width: 1;
|
|
791
960
|
}
|
|
792
961
|
|
|
962
|
+
.graph-size-controls {
|
|
963
|
+
margin-left: auto;
|
|
964
|
+
display: flex;
|
|
965
|
+
gap: 2px;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
.graph-size-btn {
|
|
969
|
+
background: var(--bg-hover);
|
|
970
|
+
border: 1px solid var(--border);
|
|
971
|
+
color: var(--text-muted);
|
|
972
|
+
font-family: var(--font-mono);
|
|
973
|
+
font-size: 11px;
|
|
974
|
+
width: 18px;
|
|
975
|
+
height: 18px;
|
|
976
|
+
border-radius: 3px;
|
|
977
|
+
cursor: pointer;
|
|
978
|
+
display: flex;
|
|
979
|
+
align-items: center;
|
|
980
|
+
justify-content: center;
|
|
981
|
+
transition: all 0.15s;
|
|
982
|
+
padding: 0;
|
|
983
|
+
line-height: 1;
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
.graph-size-btn:hover {
|
|
987
|
+
border-color: var(--neon-cyan);
|
|
988
|
+
color: var(--neon-cyan);
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
.graph-resize-handle {
|
|
992
|
+
height: 8px;
|
|
993
|
+
cursor: ns-resize;
|
|
994
|
+
position: relative;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
.graph-resize-handle::after {
|
|
998
|
+
content: '';
|
|
999
|
+
position: absolute;
|
|
1000
|
+
bottom: 2px;
|
|
1001
|
+
left: 50%;
|
|
1002
|
+
transform: translateX(-50%);
|
|
1003
|
+
width: 24px;
|
|
1004
|
+
height: 2px;
|
|
1005
|
+
background: var(--border);
|
|
1006
|
+
border-radius: 1px;
|
|
1007
|
+
transition: background 0.2s;
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
.graph-resize-handle:hover::after {
|
|
1011
|
+
background: var(--neon-cyan);
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
/* ============ SESSIONS ============ */
|
|
1015
|
+
.session-folder-icon { color: var(--neon-green) !important; }
|
|
1016
|
+
|
|
1017
|
+
.session-add-btn {
|
|
1018
|
+
background: transparent;
|
|
1019
|
+
border: 1px solid var(--border);
|
|
1020
|
+
color: var(--text-muted);
|
|
1021
|
+
font-family: var(--font-mono);
|
|
1022
|
+
font-size: 11px;
|
|
1023
|
+
width: 16px;
|
|
1024
|
+
height: 16px;
|
|
1025
|
+
border-radius: 3px;
|
|
1026
|
+
cursor: pointer;
|
|
1027
|
+
margin-left: auto;
|
|
1028
|
+
display: none;
|
|
1029
|
+
align-items: center;
|
|
1030
|
+
justify-content: center;
|
|
1031
|
+
transition: all 0.15s;
|
|
1032
|
+
padding: 0;
|
|
1033
|
+
line-height: 1;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
.tree-item:hover .session-add-btn { display: flex; }
|
|
1037
|
+
|
|
1038
|
+
.session-add-btn:hover {
|
|
1039
|
+
border-color: var(--neon-green);
|
|
1040
|
+
color: var(--neon-green);
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
.session-badge {
|
|
1044
|
+
display: inline-flex;
|
|
1045
|
+
align-items: center;
|
|
1046
|
+
gap: 8px;
|
|
1047
|
+
font-family: var(--font-mono);
|
|
1048
|
+
font-size: 10px;
|
|
1049
|
+
color: var(--neon-green);
|
|
1050
|
+
background: rgba(91,185,140,0.08);
|
|
1051
|
+
border: 1px solid rgba(91,185,140,0.15);
|
|
1052
|
+
padding: 4px 12px;
|
|
1053
|
+
border-radius: var(--radius);
|
|
1054
|
+
margin-bottom: 16px;
|
|
1055
|
+
letter-spacing: 0.5px;
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
.session-create-overlay {
|
|
1059
|
+
position: fixed;
|
|
1060
|
+
inset: 0;
|
|
1061
|
+
background: rgba(6,6,12,0.75);
|
|
1062
|
+
z-index: 200;
|
|
1063
|
+
display: none;
|
|
1064
|
+
align-items: center;
|
|
1065
|
+
justify-content: center;
|
|
1066
|
+
backdrop-filter: blur(4px);
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
.session-create-overlay.active { display: flex; }
|
|
1070
|
+
|
|
1071
|
+
.session-create-modal {
|
|
1072
|
+
width: 420px;
|
|
1073
|
+
background: var(--bg-card);
|
|
1074
|
+
border: 1px solid var(--border);
|
|
1075
|
+
border-radius: var(--radius-lg);
|
|
1076
|
+
box-shadow: 0 20px 60px rgba(0,0,0,0.6);
|
|
1077
|
+
overflow: hidden;
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
.session-create-header {
|
|
1081
|
+
padding: 16px 20px 12px;
|
|
1082
|
+
border-bottom: 1px solid var(--border-subtle);
|
|
1083
|
+
font-family: var(--font-mono);
|
|
1084
|
+
font-size: 11px;
|
|
1085
|
+
font-weight: 600;
|
|
1086
|
+
color: var(--text-secondary);
|
|
1087
|
+
letter-spacing: 0.5px;
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
.session-create-body {
|
|
1091
|
+
padding: 16px 20px;
|
|
1092
|
+
display: flex;
|
|
1093
|
+
flex-direction: column;
|
|
1094
|
+
gap: 12px;
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
.session-field label {
|
|
1098
|
+
display: block;
|
|
1099
|
+
font-family: var(--font-mono);
|
|
1100
|
+
font-size: 9px;
|
|
1101
|
+
font-weight: 600;
|
|
1102
|
+
text-transform: uppercase;
|
|
1103
|
+
letter-spacing: 1px;
|
|
1104
|
+
color: var(--text-muted);
|
|
1105
|
+
margin-bottom: 4px;
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
.session-field select,
|
|
1109
|
+
.session-field input,
|
|
1110
|
+
.session-field textarea {
|
|
1111
|
+
width: 100%;
|
|
1112
|
+
background: var(--bg-surface);
|
|
1113
|
+
border: 1px solid var(--border);
|
|
1114
|
+
color: var(--text-primary);
|
|
1115
|
+
font-family: var(--font-mono);
|
|
1116
|
+
font-size: 12px;
|
|
1117
|
+
padding: 8px 12px;
|
|
1118
|
+
border-radius: var(--radius);
|
|
1119
|
+
outline: none;
|
|
1120
|
+
transition: border-color 0.2s;
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
.session-field select:focus,
|
|
1124
|
+
.session-field input:focus,
|
|
1125
|
+
.session-field textarea:focus {
|
|
1126
|
+
border-color: rgba(217,119,87,0.3);
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
.session-field textarea {
|
|
1130
|
+
min-height: 60px;
|
|
1131
|
+
resize: vertical;
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
.session-create-footer {
|
|
1135
|
+
padding: 12px 20px;
|
|
1136
|
+
border-top: 1px solid var(--border-subtle);
|
|
1137
|
+
display: flex;
|
|
1138
|
+
justify-content: flex-end;
|
|
1139
|
+
gap: 8px;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
.session-create-footer .edit-btn.create {
|
|
1143
|
+
background: rgba(91,185,140,0.1);
|
|
1144
|
+
color: var(--neon-green);
|
|
1145
|
+
border-color: rgba(91,185,140,0.3);
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
.session-create-footer .edit-btn.create:hover {
|
|
1149
|
+
background: rgba(91,185,140,0.2);
|
|
1150
|
+
}
|
|
1151
|
+
|
|
793
1152
|
/* ============ SCROLLBAR ============ */
|
|
794
|
-
::-webkit-scrollbar { width:
|
|
1153
|
+
::-webkit-scrollbar { width: 4px; }
|
|
795
1154
|
::-webkit-scrollbar-track { background: transparent; }
|
|
796
|
-
::-webkit-scrollbar-thumb { background: var(--
|
|
1155
|
+
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
|
|
797
1156
|
::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }
|
|
798
1157
|
|
|
799
|
-
/* ============
|
|
800
|
-
.
|
|
801
|
-
|
|
1158
|
+
/* ============ EDIT MODAL ============ */
|
|
1159
|
+
.edit-overlay {
|
|
1160
|
+
position: fixed;
|
|
1161
|
+
inset: 0;
|
|
1162
|
+
background: rgba(6,6,12,0.75);
|
|
1163
|
+
z-index: 200;
|
|
1164
|
+
display: none;
|
|
1165
|
+
align-items: center;
|
|
1166
|
+
justify-content: center;
|
|
1167
|
+
backdrop-filter: blur(4px);
|
|
802
1168
|
}
|
|
803
1169
|
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
1170
|
+
.edit-overlay.active { display: flex; }
|
|
1171
|
+
|
|
1172
|
+
.edit-modal {
|
|
1173
|
+
width: 640px;
|
|
1174
|
+
max-height: 80vh;
|
|
1175
|
+
background: var(--bg-card);
|
|
1176
|
+
border: 1px solid var(--border);
|
|
1177
|
+
border-radius: var(--radius-lg);
|
|
1178
|
+
box-shadow: 0 20px 60px rgba(0,0,0,0.6);
|
|
1179
|
+
display: flex;
|
|
1180
|
+
flex-direction: column;
|
|
1181
|
+
overflow: hidden;
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
.edit-header {
|
|
1185
|
+
display: flex;
|
|
1186
|
+
align-items: center;
|
|
1187
|
+
justify-content: space-between;
|
|
1188
|
+
padding: 12px 16px;
|
|
1189
|
+
border-bottom: 1px solid var(--border-subtle);
|
|
1190
|
+
font-family: var(--font-mono);
|
|
1191
|
+
font-size: 11px;
|
|
1192
|
+
color: var(--text-secondary);
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
.edit-header .edit-path { opacity: 0.6; }
|
|
1196
|
+
|
|
1197
|
+
.edit-actions { display: flex; gap: 8px; }
|
|
1198
|
+
|
|
1199
|
+
.edit-btn {
|
|
1200
|
+
font-family: var(--font-mono);
|
|
1201
|
+
font-size: 10px;
|
|
1202
|
+
padding: 5px 14px;
|
|
1203
|
+
border-radius: var(--radius);
|
|
1204
|
+
border: 1px solid var(--border);
|
|
1205
|
+
cursor: pointer;
|
|
1206
|
+
transition: all 0.15s;
|
|
1207
|
+
letter-spacing: 0.5px;
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
.edit-btn.cancel {
|
|
1211
|
+
background: transparent;
|
|
1212
|
+
color: var(--text-muted);
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
.edit-btn.cancel:hover { color: var(--text-secondary); border-color: var(--text-muted); }
|
|
1216
|
+
|
|
1217
|
+
.edit-btn.save {
|
|
1218
|
+
background: rgba(217,119,87,0.1);
|
|
1219
|
+
color: var(--neon-cyan);
|
|
1220
|
+
border-color: rgba(217,119,87,0.3);
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
.edit-btn.save:hover { background: rgba(217,119,87,0.2); }
|
|
1224
|
+
|
|
1225
|
+
.edit-textarea {
|
|
1226
|
+
flex: 1;
|
|
1227
|
+
min-height: 300px;
|
|
1228
|
+
background: var(--bg-primary);
|
|
1229
|
+
border: none;
|
|
1230
|
+
color: var(--text-primary);
|
|
1231
|
+
font-family: var(--font-mono);
|
|
1232
|
+
font-size: 13px;
|
|
1233
|
+
line-height: 1.7;
|
|
1234
|
+
padding: 16px 20px;
|
|
1235
|
+
resize: none;
|
|
1236
|
+
outline: none;
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
.edit-textarea::placeholder { color: var(--text-muted); }
|
|
1240
|
+
|
|
1241
|
+
.note-edit-btn {
|
|
1242
|
+
background: transparent;
|
|
1243
|
+
border: 1px solid var(--border);
|
|
1244
|
+
color: var(--text-muted);
|
|
1245
|
+
font-family: var(--font-mono);
|
|
1246
|
+
font-size: 10px;
|
|
1247
|
+
padding: 3px 10px;
|
|
1248
|
+
border-radius: var(--radius-sm);
|
|
1249
|
+
cursor: pointer;
|
|
1250
|
+
transition: all 0.15s;
|
|
1251
|
+
float: right;
|
|
1252
|
+
margin-bottom: 12px;
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
.note-edit-btn:hover {
|
|
1256
|
+
border-color: var(--text-muted);
|
|
1257
|
+
color: var(--text-secondary);
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
/* ============ BACKLINK CONTEXT ============ */
|
|
1261
|
+
.rp-item .rp-context {
|
|
1262
|
+
font-size: 10px;
|
|
1263
|
+
color: var(--text-muted);
|
|
1264
|
+
margin-top: 2px;
|
|
1265
|
+
line-height: 1.4;
|
|
1266
|
+
overflow: hidden;
|
|
1267
|
+
text-overflow: ellipsis;
|
|
1268
|
+
white-space: nowrap;
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
.rp-item-col {
|
|
1272
|
+
display: flex;
|
|
1273
|
+
flex-direction: column;
|
|
1274
|
+
padding: 5px 8px;
|
|
1275
|
+
border-radius: var(--radius-sm);
|
|
1276
|
+
cursor: pointer;
|
|
1277
|
+
margin-bottom: 1px;
|
|
1278
|
+
transition: background 0.1s;
|
|
1279
|
+
overflow: hidden;
|
|
807
1280
|
}
|
|
808
1281
|
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
1282
|
+
.rp-item-col:hover { background: var(--bg-hover); }
|
|
1283
|
+
|
|
1284
|
+
/* ============ TRANSITIONS ============ */
|
|
1285
|
+
.fade-in { animation: fadeIn 0.15s ease; }
|
|
1286
|
+
|
|
1287
|
+
@keyframes fadeIn {
|
|
1288
|
+
from { opacity: 0; transform: translateY(3px); }
|
|
1289
|
+
to { opacity: 1; transform: translateY(0); }
|
|
813
1290
|
}
|
|
814
1291
|
</style>
|
|
815
1292
|
</head>
|
|
@@ -821,10 +1298,13 @@ body.resizing .resize-handle {
|
|
|
821
1298
|
<div class="logo">KYP-MEM <span class="logo-sub">know your project</span></div>
|
|
822
1299
|
<div class="breadcrumb" id="breadcrumb"></div>
|
|
823
1300
|
<div class="header-actions">
|
|
824
|
-
<button class="
|
|
1301
|
+
<button class="header-btn active" id="graph-toggle" title="Toggle graph">
|
|
825
1302
|
<span class="dot"></span>
|
|
826
1303
|
<span>GRAPH</span>
|
|
827
1304
|
</button>
|
|
1305
|
+
<button class="header-btn" id="new-project-btn" title="New project">
|
|
1306
|
+
<span>+ PROJECT</span>
|
|
1307
|
+
</button>
|
|
828
1308
|
<div class="search-box">
|
|
829
1309
|
<span class="search-icon">⚲</span>
|
|
830
1310
|
<input type="text" id="search-input" placeholder="Search...">
|
|
@@ -838,9 +1318,23 @@ body.resizing .resize-handle {
|
|
|
838
1318
|
<div class="sidebar">
|
|
839
1319
|
<div class="sidebar-scroll">
|
|
840
1320
|
<div class="sidebar-section">
|
|
841
|
-
<div class="
|
|
1321
|
+
<div class="section-label">Explorer</div>
|
|
1322
|
+
<div id="filter-info" class="filter-info" style="display:none;">
|
|
1323
|
+
<span id="filter-count"></span>
|
|
1324
|
+
<span class="clear-btn" id="clear-filters">clear</span>
|
|
1325
|
+
</div>
|
|
842
1326
|
<div id="file-tree"></div>
|
|
843
1327
|
</div>
|
|
1328
|
+
<div class="tag-filter-section">
|
|
1329
|
+
<div class="tag-filter-header" id="tag-filter-toggle">
|
|
1330
|
+
<span>Tags</span>
|
|
1331
|
+
<span class="arrow open" id="tag-arrow">▶</span>
|
|
1332
|
+
</div>
|
|
1333
|
+
<div class="tag-filter-body" id="tag-filter-body">
|
|
1334
|
+
<div class="tag-filter-active" id="active-tags"></div>
|
|
1335
|
+
<div class="tag-cloud" id="tag-cloud"></div>
|
|
1336
|
+
</div>
|
|
1337
|
+
</div>
|
|
844
1338
|
</div>
|
|
845
1339
|
<div class="stats-bar" id="stats-bar"></div>
|
|
846
1340
|
</div>
|
|
@@ -853,7 +1347,7 @@ body.resizing .resize-handle {
|
|
|
853
1347
|
<div class="empty-state">
|
|
854
1348
|
<div class="es-logo">KYP-MEM</div>
|
|
855
1349
|
<div class="es-tagline">Know Your Project Memory</div>
|
|
856
|
-
<div class="es-hint">Select a note
|
|
1350
|
+
<div class="es-hint">Select a note or press <kbd>⌘O</kbd> to quick-switch · <kbd>⌘K</kbd> to search</div>
|
|
857
1351
|
</div>
|
|
858
1352
|
</div>
|
|
859
1353
|
|
|
@@ -863,8 +1357,13 @@ body.resizing .resize-handle {
|
|
|
863
1357
|
<!-- Right panel -->
|
|
864
1358
|
<div class="right-panel" id="right-panel">
|
|
865
1359
|
<div id="graph-section">
|
|
866
|
-
<div class="rp-section-title">Graph
|
|
1360
|
+
<div class="rp-section-title">Local Graph <span class="graph-size-controls"><button class="graph-size-btn" id="graph-shrink" title="Shrink graph">−</button><button class="graph-size-btn" id="graph-grow" title="Grow graph">+</button></span></div>
|
|
867
1361
|
<div id="graph-container"></div>
|
|
1362
|
+
<div id="graph-resize-handle" class="graph-resize-handle"></div>
|
|
1363
|
+
</div>
|
|
1364
|
+
<div id="rp-outline" class="rp-section" style="display:none;">
|
|
1365
|
+
<div class="rp-section-title">Outline <span class="rp-count" id="outline-count"></span></div>
|
|
1366
|
+
<div id="rp-outline-list"></div>
|
|
868
1367
|
</div>
|
|
869
1368
|
<div id="rp-backlinks" class="rp-section" style="display:none;">
|
|
870
1369
|
<div class="rp-section-title">Backlinks <span class="rp-count" id="bl-count"></span></div>
|
|
@@ -878,6 +1377,75 @@ body.resizing .resize-handle {
|
|
|
878
1377
|
<div class="rp-section-title">Outgoing Links <span class="rp-count" id="out-count"></span></div>
|
|
879
1378
|
<div id="rp-outlinks-list"></div>
|
|
880
1379
|
</div>
|
|
1380
|
+
<div id="rp-unlinked" class="rp-section" style="display:none;">
|
|
1381
|
+
<div class="rp-section-title">Unlinked Mentions <span class="rp-count" id="unlinked-count"></span></div>
|
|
1382
|
+
<div id="rp-unlinked-list"></div>
|
|
1383
|
+
</div>
|
|
1384
|
+
</div>
|
|
1385
|
+
</div>
|
|
1386
|
+
|
|
1387
|
+
<!-- Edit Modal -->
|
|
1388
|
+
<div class="edit-overlay" id="edit-overlay">
|
|
1389
|
+
<div class="edit-modal">
|
|
1390
|
+
<div class="edit-header">
|
|
1391
|
+
<span class="edit-path" id="edit-path"></span>
|
|
1392
|
+
<div class="edit-actions">
|
|
1393
|
+
<button class="edit-btn cancel" id="edit-cancel">ESC</button>
|
|
1394
|
+
<button class="edit-btn save" id="edit-save">SAVE</button>
|
|
1395
|
+
</div>
|
|
1396
|
+
</div>
|
|
1397
|
+
<textarea class="edit-textarea" id="edit-textarea" placeholder="Write markdown..."></textarea>
|
|
1398
|
+
</div>
|
|
1399
|
+
</div>
|
|
1400
|
+
|
|
1401
|
+
<!-- Quick Switcher Overlay -->
|
|
1402
|
+
<div class="quick-switcher-overlay" id="qs-overlay">
|
|
1403
|
+
<div class="quick-switcher">
|
|
1404
|
+
<input type="text" id="qs-input" placeholder="Jump to note...">
|
|
1405
|
+
<div class="quick-switcher-results" id="qs-results"></div>
|
|
1406
|
+
</div>
|
|
1407
|
+
</div>
|
|
1408
|
+
|
|
1409
|
+
<!-- Session Create Modal -->
|
|
1410
|
+
<div class="session-create-overlay" id="session-create-overlay">
|
|
1411
|
+
<div class="session-create-modal">
|
|
1412
|
+
<div class="session-create-header">NEW SESSION</div>
|
|
1413
|
+
<div class="session-create-body">
|
|
1414
|
+
<div class="session-field">
|
|
1415
|
+
<label>Project</label>
|
|
1416
|
+
<input type="text" id="session-project" list="project-list" placeholder="Project name...">
|
|
1417
|
+
<datalist id="project-list"></datalist>
|
|
1418
|
+
</div>
|
|
1419
|
+
<div class="session-field">
|
|
1420
|
+
<label>Summary</label>
|
|
1421
|
+
<textarea id="session-summary" placeholder="What are you working on?"></textarea>
|
|
1422
|
+
</div>
|
|
1423
|
+
</div>
|
|
1424
|
+
<div class="session-create-footer">
|
|
1425
|
+
<button class="edit-btn cancel" id="session-cancel">CANCEL</button>
|
|
1426
|
+
<button class="edit-btn create" id="session-create-btn">CREATE</button>
|
|
1427
|
+
</div>
|
|
1428
|
+
</div>
|
|
1429
|
+
</div>
|
|
1430
|
+
|
|
1431
|
+
<!-- Project Create Modal -->
|
|
1432
|
+
<div class="session-create-overlay" id="project-create-overlay">
|
|
1433
|
+
<div class="session-create-modal">
|
|
1434
|
+
<div class="session-create-header">NEW PROJECT</div>
|
|
1435
|
+
<div class="session-create-body">
|
|
1436
|
+
<div class="session-field">
|
|
1437
|
+
<label>Project Name</label>
|
|
1438
|
+
<input type="text" id="project-name-input" placeholder="My Project...">
|
|
1439
|
+
</div>
|
|
1440
|
+
<div class="session-field">
|
|
1441
|
+
<label>Overview (optional)</label>
|
|
1442
|
+
<textarea id="project-overview-input" placeholder="Brief project description, goals, tech stack..."></textarea>
|
|
1443
|
+
</div>
|
|
1444
|
+
</div>
|
|
1445
|
+
<div class="session-create-footer">
|
|
1446
|
+
<button class="edit-btn cancel" id="project-cancel">CANCEL</button>
|
|
1447
|
+
<button class="edit-btn create" id="project-create-btn">CREATE</button>
|
|
1448
|
+
</div>
|
|
881
1449
|
</div>
|
|
882
1450
|
</div>
|
|
883
1451
|
|
|
@@ -886,6 +1454,9 @@ let currentPath = null;
|
|
|
886
1454
|
let treeData = null;
|
|
887
1455
|
let allNotes = {};
|
|
888
1456
|
let graphVisible = true;
|
|
1457
|
+
let currentNote = null;
|
|
1458
|
+
let activeTagFilters = new Set();
|
|
1459
|
+
let qsSelectedIndex = 0;
|
|
889
1460
|
|
|
890
1461
|
async function fetchJSON(url) {
|
|
891
1462
|
const r = await fetch(url);
|
|
@@ -910,25 +1481,137 @@ document.getElementById('graph-toggle').addEventListener('click', () => {
|
|
|
910
1481
|
}
|
|
911
1482
|
});
|
|
912
1483
|
|
|
913
|
-
// --- Keyboard
|
|
1484
|
+
// --- Keyboard shortcuts ---
|
|
914
1485
|
document.addEventListener('keydown', (e) => {
|
|
915
1486
|
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
|
|
916
1487
|
e.preventDefault();
|
|
917
1488
|
document.getElementById('search-input').focus();
|
|
918
1489
|
}
|
|
1490
|
+
if ((e.metaKey || e.ctrlKey) && e.key === 'o') {
|
|
1491
|
+
e.preventDefault();
|
|
1492
|
+
openQuickSwitcher();
|
|
1493
|
+
}
|
|
1494
|
+
if (e.key === 'Escape') {
|
|
1495
|
+
closeQuickSwitcher();
|
|
1496
|
+
closeSessionCreate();
|
|
1497
|
+
closeProjectCreate();
|
|
1498
|
+
}
|
|
919
1499
|
});
|
|
920
1500
|
|
|
1501
|
+
// --- Quick Switcher ---
|
|
1502
|
+
function openQuickSwitcher() {
|
|
1503
|
+
const overlay = document.getElementById('qs-overlay');
|
|
1504
|
+
const input = document.getElementById('qs-input');
|
|
1505
|
+
overlay.classList.add('active');
|
|
1506
|
+
input.value = '';
|
|
1507
|
+
input.focus();
|
|
1508
|
+
qsSelectedIndex = 0;
|
|
1509
|
+
renderQsResults('');
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
function closeQuickSwitcher() {
|
|
1513
|
+
document.getElementById('qs-overlay').classList.remove('active');
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
document.getElementById('qs-overlay').addEventListener('click', (e) => {
|
|
1517
|
+
if (e.target === e.currentTarget) closeQuickSwitcher();
|
|
1518
|
+
});
|
|
1519
|
+
|
|
1520
|
+
document.getElementById('qs-input').addEventListener('input', (e) => {
|
|
1521
|
+
qsSelectedIndex = 0;
|
|
1522
|
+
renderQsResults(e.target.value.trim().toLowerCase());
|
|
1523
|
+
});
|
|
1524
|
+
|
|
1525
|
+
document.getElementById('qs-input').addEventListener('keydown', (e) => {
|
|
1526
|
+
const items = document.querySelectorAll('.qs-item');
|
|
1527
|
+
if (e.key === 'ArrowDown') {
|
|
1528
|
+
e.preventDefault();
|
|
1529
|
+
qsSelectedIndex = Math.min(qsSelectedIndex + 1, items.length - 1);
|
|
1530
|
+
updateQsSelection();
|
|
1531
|
+
} else if (e.key === 'ArrowUp') {
|
|
1532
|
+
e.preventDefault();
|
|
1533
|
+
qsSelectedIndex = Math.max(qsSelectedIndex - 1, 0);
|
|
1534
|
+
updateQsSelection();
|
|
1535
|
+
} else if (e.key === 'Enter') {
|
|
1536
|
+
e.preventDefault();
|
|
1537
|
+
const selected = items[qsSelectedIndex];
|
|
1538
|
+
if (selected) {
|
|
1539
|
+
loadNote(selected.dataset.path);
|
|
1540
|
+
closeQuickSwitcher();
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
});
|
|
1544
|
+
|
|
1545
|
+
function renderQsResults(query) {
|
|
1546
|
+
const container = document.getElementById('qs-results');
|
|
1547
|
+
const entries = Object.entries(allNotes);
|
|
1548
|
+
|
|
1549
|
+
let filtered = entries;
|
|
1550
|
+
if (query) {
|
|
1551
|
+
filtered = entries.filter(([path, note]) => {
|
|
1552
|
+
const name = note.title.toLowerCase();
|
|
1553
|
+
const p = path.toLowerCase();
|
|
1554
|
+
return name.includes(query) || p.includes(query);
|
|
1555
|
+
});
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1558
|
+
filtered.sort((a, b) => a[1].title.localeCompare(b[1].title));
|
|
1559
|
+
filtered = filtered.slice(0, 15);
|
|
1560
|
+
|
|
1561
|
+
if (filtered.length === 0) {
|
|
1562
|
+
container.innerHTML = '<div class="qs-empty">No notes found</div>';
|
|
1563
|
+
return;
|
|
1564
|
+
}
|
|
1565
|
+
|
|
1566
|
+
container.innerHTML = filtered.map(([path, note], i) => {
|
|
1567
|
+
const folder = path.includes('/') ? path.split('/').slice(0, -1).join('/') : '';
|
|
1568
|
+
return `<div class="qs-item${i === qsSelectedIndex ? ' selected' : ''}" data-path="${path}">
|
|
1569
|
+
<span class="qs-icon">◇</span>
|
|
1570
|
+
<span class="qs-name">${note.title}</span>
|
|
1571
|
+
${folder ? `<span class="qs-path">${folder}</span>` : ''}
|
|
1572
|
+
</div>`;
|
|
1573
|
+
}).join('');
|
|
1574
|
+
|
|
1575
|
+
container.querySelectorAll('.qs-item').forEach((el, i) => {
|
|
1576
|
+
el.addEventListener('click', () => {
|
|
1577
|
+
loadNote(el.dataset.path);
|
|
1578
|
+
closeQuickSwitcher();
|
|
1579
|
+
});
|
|
1580
|
+
el.addEventListener('mouseenter', () => {
|
|
1581
|
+
qsSelectedIndex = i;
|
|
1582
|
+
updateQsSelection();
|
|
1583
|
+
});
|
|
1584
|
+
});
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
function updateQsSelection() {
|
|
1588
|
+
document.querySelectorAll('.qs-item').forEach((el, i) => {
|
|
1589
|
+
el.classList.toggle('selected', i === qsSelectedIndex);
|
|
1590
|
+
});
|
|
1591
|
+
}
|
|
1592
|
+
|
|
921
1593
|
// --- File Tree ---
|
|
922
|
-
function renderTree(node, container) {
|
|
1594
|
+
function renderTree(node, container, parentFolder) {
|
|
923
1595
|
if (node.type === 'folder' && node.name !== 'vault') {
|
|
1596
|
+
const isSessionsFolder = node.name === 'Sessions';
|
|
924
1597
|
const item = document.createElement('div');
|
|
925
1598
|
item.className = 'tree-item';
|
|
926
|
-
|
|
1599
|
+
|
|
1600
|
+
if (isSessionsFolder) {
|
|
1601
|
+
item.innerHTML = `<span class="arrow open">▶</span><span class="icon session-folder-icon">◴</span><span class="name">Sessions</span><button class="session-add-btn" data-project="${parentFolder || ''}" title="New session">+</button>`;
|
|
1602
|
+
} else {
|
|
1603
|
+
item.innerHTML = `<span class="arrow open">▶</span><span class="icon folder-icon">☰</span><span class="name">${node.name}</span>`;
|
|
1604
|
+
}
|
|
927
1605
|
|
|
928
1606
|
const children = document.createElement('div');
|
|
929
1607
|
children.className = 'tree-children';
|
|
930
1608
|
|
|
931
1609
|
item.addEventListener('click', (e) => {
|
|
1610
|
+
if (e.target.classList.contains('session-add-btn')) {
|
|
1611
|
+
e.stopPropagation();
|
|
1612
|
+
openSessionCreate(e.target.dataset.project);
|
|
1613
|
+
return;
|
|
1614
|
+
}
|
|
932
1615
|
e.stopPropagation();
|
|
933
1616
|
item.querySelector('.arrow').classList.toggle('open');
|
|
934
1617
|
children.classList.toggle('collapsed');
|
|
@@ -936,13 +1619,30 @@ function renderTree(node, container) {
|
|
|
936
1619
|
|
|
937
1620
|
container.appendChild(item);
|
|
938
1621
|
container.appendChild(children);
|
|
939
|
-
(node.children || []).forEach(c => renderTree(c, children));
|
|
1622
|
+
(node.children || []).forEach(c => renderTree(c, children, node.name));
|
|
940
1623
|
|
|
941
1624
|
} else if (node.type === 'note') {
|
|
942
1625
|
const item = document.createElement('div');
|
|
943
1626
|
item.className = 'tree-item';
|
|
944
1627
|
item.dataset.path = node.path;
|
|
945
|
-
|
|
1628
|
+
|
|
1629
|
+
const isSessionNote = node.path.includes('/Sessions/') || node.path.startsWith('Sessions/');
|
|
1630
|
+
let displayName = node.name.replace('.md', '');
|
|
1631
|
+
|
|
1632
|
+
if (isSessionNote) {
|
|
1633
|
+
const match = displayName.match(/^(\d{4})-(\d{2})-(\d{2})_(\d{2})(\d{2})(\d{2})$/);
|
|
1634
|
+
if (match) {
|
|
1635
|
+
const [, y, mo, d, h, mi] = match;
|
|
1636
|
+
const hr = parseInt(h);
|
|
1637
|
+
const ampm = hr >= 12 ? 'PM' : 'AM';
|
|
1638
|
+
const hr12 = hr % 12 || 12;
|
|
1639
|
+
const months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
|
|
1640
|
+
displayName = `${months[parseInt(mo)-1]} ${parseInt(d)}, ${hr12}:${mi} ${ampm}`;
|
|
1641
|
+
item.title = node.name.replace('.md', '');
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
item.innerHTML = `<span class="arrow" style="visibility:hidden">▶</span><span class="icon note-icon">◇</span><span class="name">${displayName}</span>`;
|
|
946
1646
|
item.addEventListener('click', () => loadNote(node.path));
|
|
947
1647
|
container.appendChild(item);
|
|
948
1648
|
|
|
@@ -956,12 +1656,12 @@ async function loadNote(path) {
|
|
|
956
1656
|
currentPath = path;
|
|
957
1657
|
const note = await fetchJSON(`/api/note/${path}`);
|
|
958
1658
|
if (note.error) return;
|
|
1659
|
+
currentNote = note;
|
|
959
1660
|
|
|
960
1661
|
document.querySelectorAll('.tree-item').forEach(el => {
|
|
961
1662
|
el.classList.toggle('active', el.dataset.path === path);
|
|
962
1663
|
});
|
|
963
1664
|
|
|
964
|
-
// Breadcrumb
|
|
965
1665
|
const parts = path.replace('.md', '').split('/');
|
|
966
1666
|
document.getElementById('breadcrumb').innerHTML = parts.map((p, i) =>
|
|
967
1667
|
i < parts.length - 1
|
|
@@ -969,12 +1669,19 @@ async function loadNote(path) {
|
|
|
969
1669
|
: `<span class="current">${p}</span>`
|
|
970
1670
|
).join('');
|
|
971
1671
|
|
|
972
|
-
// Content
|
|
973
1672
|
const contentEl = document.getElementById('content');
|
|
974
1673
|
let html = '<div class="fade-in">';
|
|
975
1674
|
|
|
1675
|
+
html += `<button class="note-edit-btn" onclick="openEditor('${path}')">EDIT</button>`;
|
|
1676
|
+
|
|
1677
|
+
const isSession = path.includes('/Sessions/') || path.startsWith('Sessions/');
|
|
1678
|
+
if (isSession) {
|
|
1679
|
+
const sessionProject = path.includes('/Sessions/') ? path.split('/Sessions/')[0] : 'General';
|
|
1680
|
+
html += `<div class="session-badge">◴ SESSION · ${sessionProject}</div>`;
|
|
1681
|
+
}
|
|
1682
|
+
|
|
976
1683
|
html += '<div class="note-properties">';
|
|
977
|
-
(note.tags || []).forEach(t => { html += `<span class="tag">#${t}</span>`; });
|
|
1684
|
+
(note.tags || []).forEach(t => { html += `<span class="tag clickable-tag" data-tag="${t}">#${t}</span>`; });
|
|
978
1685
|
Object.entries(note.properties || {}).forEach(([k, v]) => {
|
|
979
1686
|
html += `<span class="prop-item"><span class="prop-key">${k}:</span> ${v}</span>`;
|
|
980
1687
|
});
|
|
@@ -1000,7 +1707,15 @@ async function loadNote(path) {
|
|
|
1000
1707
|
});
|
|
1001
1708
|
});
|
|
1002
1709
|
|
|
1710
|
+
contentEl.querySelectorAll('.clickable-tag').forEach(el => {
|
|
1711
|
+
el.addEventListener('click', () => {
|
|
1712
|
+
activeTagFilters.add(el.dataset.tag);
|
|
1713
|
+
applyTagFilter();
|
|
1714
|
+
});
|
|
1715
|
+
});
|
|
1716
|
+
|
|
1003
1717
|
renderRightPanel(note);
|
|
1718
|
+
renderOutline(note);
|
|
1004
1719
|
if (graphVisible) renderGraph(note);
|
|
1005
1720
|
}
|
|
1006
1721
|
|
|
@@ -1013,20 +1728,58 @@ function findNotePath(name) {
|
|
|
1013
1728
|
return null;
|
|
1014
1729
|
}
|
|
1015
1730
|
|
|
1731
|
+
// --- Outline ---
|
|
1732
|
+
function renderOutline(note) {
|
|
1733
|
+
const section = document.getElementById('rp-outline');
|
|
1734
|
+
const list = document.getElementById('rp-outline-list');
|
|
1735
|
+
list.innerHTML = '';
|
|
1736
|
+
|
|
1737
|
+
const content = note.content || '';
|
|
1738
|
+
const headings = [];
|
|
1739
|
+
content.split('\n').forEach(line => {
|
|
1740
|
+
const m = line.match(/^(#{1,3})\s+(.+)/);
|
|
1741
|
+
if (m) headings.push({ level: m[1].length, text: m[2].trim() });
|
|
1742
|
+
});
|
|
1743
|
+
|
|
1744
|
+
if (headings.length < 2) {
|
|
1745
|
+
section.style.display = 'none';
|
|
1746
|
+
return;
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
section.style.display = '';
|
|
1750
|
+
document.getElementById('outline-count').textContent = headings.length;
|
|
1751
|
+
|
|
1752
|
+
headings.forEach(h => {
|
|
1753
|
+
const el = document.createElement('div');
|
|
1754
|
+
el.className = `outline-item h${h.level}`;
|
|
1755
|
+
el.textContent = h.text;
|
|
1756
|
+
el.addEventListener('click', () => {
|
|
1757
|
+
const contentEl = document.getElementById('content');
|
|
1758
|
+
const target = Array.from(contentEl.querySelectorAll('h1,h2,h3')).find(
|
|
1759
|
+
el => el.textContent.trim() === h.text
|
|
1760
|
+
);
|
|
1761
|
+
if (target) target.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
1762
|
+
});
|
|
1763
|
+
list.appendChild(el);
|
|
1764
|
+
});
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1016
1767
|
// --- Right Panel ---
|
|
1017
1768
|
function renderRightPanel(note) {
|
|
1018
1769
|
const blSection = document.getElementById('rp-backlinks');
|
|
1019
1770
|
const blList = document.getElementById('rp-backlinks-list');
|
|
1020
1771
|
blList.innerHTML = '';
|
|
1021
|
-
|
|
1772
|
+
const backlinks = note.backlinks || [];
|
|
1773
|
+
if (backlinks.length) {
|
|
1022
1774
|
blSection.style.display = '';
|
|
1023
|
-
document.getElementById('bl-count').textContent =
|
|
1024
|
-
|
|
1025
|
-
const n = allNotes[path];
|
|
1775
|
+
document.getElementById('bl-count').textContent = backlinks.length;
|
|
1776
|
+
backlinks.forEach(bl => {
|
|
1026
1777
|
const item = document.createElement('div');
|
|
1027
|
-
item.className = 'rp-item';
|
|
1028
|
-
|
|
1029
|
-
|
|
1778
|
+
item.className = 'rp-item-col';
|
|
1779
|
+
let html = `<span class="rp-title rp-backlink-title" style="font-size:11px">${bl.title || bl.path || bl}</span>`;
|
|
1780
|
+
if (bl.context) html += `<span class="rp-context">${bl.context}</span>`;
|
|
1781
|
+
item.innerHTML = html;
|
|
1782
|
+
item.addEventListener('click', () => loadNote(bl.path || bl));
|
|
1030
1783
|
blList.appendChild(item);
|
|
1031
1784
|
});
|
|
1032
1785
|
} else {
|
|
@@ -1062,12 +1815,212 @@ function renderRightPanel(note) {
|
|
|
1062
1815
|
item.className = 'rp-item';
|
|
1063
1816
|
item.innerHTML = `<span class="rp-title">${link}</span>`;
|
|
1064
1817
|
if (path) item.addEventListener('click', () => loadNote(path));
|
|
1065
|
-
else item.style.opacity = '0.
|
|
1818
|
+
else item.style.opacity = '0.3';
|
|
1066
1819
|
outList.appendChild(item);
|
|
1067
1820
|
});
|
|
1068
1821
|
} else {
|
|
1069
1822
|
outSection.style.display = 'none';
|
|
1070
1823
|
}
|
|
1824
|
+
|
|
1825
|
+
const ulSection = document.getElementById('rp-unlinked');
|
|
1826
|
+
const ulList = document.getElementById('rp-unlinked-list');
|
|
1827
|
+
ulList.innerHTML = '';
|
|
1828
|
+
const unlinked = note.unlinked || [];
|
|
1829
|
+
if (unlinked.length) {
|
|
1830
|
+
ulSection.style.display = '';
|
|
1831
|
+
document.getElementById('unlinked-count').textContent = unlinked.length;
|
|
1832
|
+
unlinked.forEach(u => {
|
|
1833
|
+
const item = document.createElement('div');
|
|
1834
|
+
item.className = 'rp-item-col';
|
|
1835
|
+
let html = `<span class="rp-title" style="font-size:11px;color:var(--text-secondary)">${u.title}</span>`;
|
|
1836
|
+
if (u.context) html += `<span class="rp-context">${u.context}</span>`;
|
|
1837
|
+
item.innerHTML = html;
|
|
1838
|
+
item.addEventListener('click', () => loadNote(u.path));
|
|
1839
|
+
ulList.appendChild(item);
|
|
1840
|
+
});
|
|
1841
|
+
} else {
|
|
1842
|
+
ulSection.style.display = 'none';
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
|
|
1846
|
+
// --- Editor ---
|
|
1847
|
+
let editingPath = null;
|
|
1848
|
+
let editingNote = null;
|
|
1849
|
+
|
|
1850
|
+
async function openEditor(path) {
|
|
1851
|
+
const note = await fetchJSON(`/api/note/${path}`);
|
|
1852
|
+
if (note.error) return;
|
|
1853
|
+
editingPath = path;
|
|
1854
|
+
editingNote = note;
|
|
1855
|
+
document.getElementById('edit-path').textContent = path;
|
|
1856
|
+
document.getElementById('edit-textarea').value = note.content || '';
|
|
1857
|
+
document.getElementById('edit-overlay').classList.add('active');
|
|
1858
|
+
document.getElementById('edit-textarea').focus();
|
|
1859
|
+
}
|
|
1860
|
+
|
|
1861
|
+
document.getElementById('edit-cancel').addEventListener('click', closeEditor);
|
|
1862
|
+
document.getElementById('edit-overlay').addEventListener('click', (e) => {
|
|
1863
|
+
if (e.target === e.currentTarget) closeEditor();
|
|
1864
|
+
});
|
|
1865
|
+
|
|
1866
|
+
document.getElementById('edit-save').addEventListener('click', async () => {
|
|
1867
|
+
if (!editingPath) return;
|
|
1868
|
+
const content = document.getElementById('edit-textarea').value;
|
|
1869
|
+
await fetch(`/api/note/${editingPath}`, {
|
|
1870
|
+
method: 'POST',
|
|
1871
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1872
|
+
body: JSON.stringify({
|
|
1873
|
+
content,
|
|
1874
|
+
tags: editingNote.tags || [],
|
|
1875
|
+
properties: editingNote.properties || {},
|
|
1876
|
+
}),
|
|
1877
|
+
});
|
|
1878
|
+
closeEditor();
|
|
1879
|
+
await loadNote(editingPath);
|
|
1880
|
+
});
|
|
1881
|
+
|
|
1882
|
+
function closeEditor() {
|
|
1883
|
+
document.getElementById('edit-overlay').classList.remove('active');
|
|
1884
|
+
editingPath = null;
|
|
1885
|
+
editingNote = null;
|
|
1886
|
+
}
|
|
1887
|
+
|
|
1888
|
+
document.addEventListener('keydown', (e) => {
|
|
1889
|
+
if (e.key === 'Escape' && document.getElementById('edit-overlay').classList.contains('active')) {
|
|
1890
|
+
closeEditor();
|
|
1891
|
+
}
|
|
1892
|
+
if ((e.metaKey || e.ctrlKey) && e.key === 's' && editingPath) {
|
|
1893
|
+
e.preventDefault();
|
|
1894
|
+
document.getElementById('edit-save').click();
|
|
1895
|
+
}
|
|
1896
|
+
});
|
|
1897
|
+
|
|
1898
|
+
// --- Session Management ---
|
|
1899
|
+
function openSessionCreate(defaultProject) {
|
|
1900
|
+
const overlay = document.getElementById('session-create-overlay');
|
|
1901
|
+
const projectInput = document.getElementById('session-project');
|
|
1902
|
+
const datalist = document.getElementById('project-list');
|
|
1903
|
+
const summaryInput = document.getElementById('session-summary');
|
|
1904
|
+
|
|
1905
|
+
const projects = new Set();
|
|
1906
|
+
for (const path of Object.keys(allNotes)) {
|
|
1907
|
+
const parts = path.split('/');
|
|
1908
|
+
if (parts.length > 1) projects.add(parts[0]);
|
|
1909
|
+
}
|
|
1910
|
+
|
|
1911
|
+
datalist.innerHTML = '';
|
|
1912
|
+
for (const p of [...projects].sort()) {
|
|
1913
|
+
const opt = document.createElement('option');
|
|
1914
|
+
opt.value = p;
|
|
1915
|
+
datalist.appendChild(opt);
|
|
1916
|
+
}
|
|
1917
|
+
|
|
1918
|
+
projectInput.value = defaultProject || '';
|
|
1919
|
+
summaryInput.value = '';
|
|
1920
|
+
overlay.classList.add('active');
|
|
1921
|
+
|
|
1922
|
+
if (defaultProject) summaryInput.focus();
|
|
1923
|
+
else projectInput.focus();
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
function closeSessionCreate() {
|
|
1927
|
+
document.getElementById('session-create-overlay').classList.remove('active');
|
|
1928
|
+
}
|
|
1929
|
+
|
|
1930
|
+
document.getElementById('session-cancel').addEventListener('click', closeSessionCreate);
|
|
1931
|
+
document.getElementById('session-create-overlay').addEventListener('click', (e) => {
|
|
1932
|
+
if (e.target === e.currentTarget) closeSessionCreate();
|
|
1933
|
+
});
|
|
1934
|
+
|
|
1935
|
+
document.getElementById('session-create-btn').addEventListener('click', async () => {
|
|
1936
|
+
const project = document.getElementById('session-project').value.trim();
|
|
1937
|
+
const summary = document.getElementById('session-summary').value.trim();
|
|
1938
|
+
|
|
1939
|
+
if (!project) {
|
|
1940
|
+
document.getElementById('session-project').focus();
|
|
1941
|
+
return;
|
|
1942
|
+
}
|
|
1943
|
+
|
|
1944
|
+
const resp = await fetch('/api/sessions/create', {
|
|
1945
|
+
method: 'POST',
|
|
1946
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1947
|
+
body: JSON.stringify({ project, summary }),
|
|
1948
|
+
});
|
|
1949
|
+
|
|
1950
|
+
const result = await resp.json();
|
|
1951
|
+
if (result.ok) {
|
|
1952
|
+
closeSessionCreate();
|
|
1953
|
+
await refreshTree();
|
|
1954
|
+
loadNote(result.path);
|
|
1955
|
+
}
|
|
1956
|
+
});
|
|
1957
|
+
|
|
1958
|
+
// --- Project Management ---
|
|
1959
|
+
function closeProjectCreate() {
|
|
1960
|
+
document.getElementById('project-create-overlay').classList.remove('active');
|
|
1961
|
+
}
|
|
1962
|
+
|
|
1963
|
+
document.getElementById('new-project-btn').addEventListener('click', () => {
|
|
1964
|
+
document.getElementById('project-create-overlay').classList.add('active');
|
|
1965
|
+
document.getElementById('project-name-input').value = '';
|
|
1966
|
+
document.getElementById('project-overview-input').value = '';
|
|
1967
|
+
document.getElementById('project-name-input').focus();
|
|
1968
|
+
});
|
|
1969
|
+
|
|
1970
|
+
document.getElementById('project-cancel').addEventListener('click', closeProjectCreate);
|
|
1971
|
+
document.getElementById('project-create-overlay').addEventListener('click', (e) => {
|
|
1972
|
+
if (e.target === e.currentTarget) closeProjectCreate();
|
|
1973
|
+
});
|
|
1974
|
+
|
|
1975
|
+
document.getElementById('project-create-btn').addEventListener('click', async () => {
|
|
1976
|
+
const name = document.getElementById('project-name-input').value.trim();
|
|
1977
|
+
const overview = document.getElementById('project-overview-input').value.trim();
|
|
1978
|
+
if (!name) {
|
|
1979
|
+
document.getElementById('project-name-input').focus();
|
|
1980
|
+
return;
|
|
1981
|
+
}
|
|
1982
|
+
const resp = await fetch('/api/projects/create', {
|
|
1983
|
+
method: 'POST',
|
|
1984
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1985
|
+
body: JSON.stringify({ name, overview }),
|
|
1986
|
+
});
|
|
1987
|
+
const result = await resp.json();
|
|
1988
|
+
if (result.ok) {
|
|
1989
|
+
closeProjectCreate();
|
|
1990
|
+
await refreshTree();
|
|
1991
|
+
loadNote(result.path);
|
|
1992
|
+
}
|
|
1993
|
+
});
|
|
1994
|
+
|
|
1995
|
+
async function refreshTree() {
|
|
1996
|
+
treeData = await fetchJSON('/api/tree');
|
|
1997
|
+
allNotes = {};
|
|
1998
|
+
function walk(node) {
|
|
1999
|
+
if (node.type === 'note') {
|
|
2000
|
+
allNotes[node.path] = { title: node.name.replace('.md', ''), tags: node.tags || [] };
|
|
2001
|
+
}
|
|
2002
|
+
(node.children || []).forEach(walk);
|
|
2003
|
+
}
|
|
2004
|
+
walk(treeData);
|
|
2005
|
+
|
|
2006
|
+
const treeEl = document.getElementById('file-tree');
|
|
2007
|
+
treeEl.innerHTML = '';
|
|
2008
|
+
renderTree(treeData, treeEl);
|
|
2009
|
+
renderTagCloud(collectAllTags());
|
|
2010
|
+
|
|
2011
|
+
const stats = await fetchJSON('/api/stats');
|
|
2012
|
+
document.getElementById('stats-bar').innerHTML = `
|
|
2013
|
+
<span><span class="stat-val">${stats.notes}</span> notes</span>
|
|
2014
|
+
<span><span class="stat-val">${stats.folders}</span> folders</span>
|
|
2015
|
+
<span><span class="stat-val">${stats.tags}</span> tags</span>
|
|
2016
|
+
<span><span class="stat-val">${stats.links}</span> links</span>
|
|
2017
|
+
`;
|
|
2018
|
+
|
|
2019
|
+
if (currentPath) {
|
|
2020
|
+
document.querySelectorAll('.tree-item').forEach(el => {
|
|
2021
|
+
el.classList.toggle('active', el.dataset.path === currentPath);
|
|
2022
|
+
});
|
|
2023
|
+
}
|
|
1071
2024
|
}
|
|
1072
2025
|
|
|
1073
2026
|
// --- Graph ---
|
|
@@ -1089,66 +2042,126 @@ function renderGraph(note) {
|
|
|
1089
2042
|
if (path) links.push({ source: note.path, target: path });
|
|
1090
2043
|
});
|
|
1091
2044
|
|
|
1092
|
-
(note.backlinks || []).forEach(
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
2045
|
+
(note.backlinks || []).forEach(bl => {
|
|
2046
|
+
const blPath = typeof bl === 'string' ? bl : (bl && bl.path);
|
|
2047
|
+
if (!blPath) return;
|
|
2048
|
+
if (!nodes.has(blPath)) {
|
|
2049
|
+
const n = allNotes[blPath];
|
|
2050
|
+
const title = (bl && typeof bl === 'object' && bl.title) ? bl.title : (n ? n.title : blPath);
|
|
2051
|
+
nodes.set(blPath, { id: blPath, title, active: false });
|
|
1096
2052
|
}
|
|
1097
|
-
links.push({ source:
|
|
2053
|
+
links.push({ source: blPath, target: note.path });
|
|
1098
2054
|
});
|
|
1099
2055
|
|
|
1100
2056
|
(note.related || []).forEach(r => {
|
|
1101
2057
|
if (!nodes.has(r.path)) {
|
|
1102
2058
|
nodes.set(r.path, { id: r.path, title: r.title, active: false });
|
|
1103
2059
|
}
|
|
2060
|
+
links.push({ source: note.path, target: r.path, dashed: true });
|
|
1104
2061
|
});
|
|
1105
2062
|
|
|
1106
2063
|
const nodeArray = Array.from(nodes.values());
|
|
1107
2064
|
if (nodeArray.length < 2) {
|
|
1108
|
-
container.innerHTML = '<
|
|
2065
|
+
container.innerHTML = '<div style="display:flex;align-items:center;justify-content:center;height:100%;color:var(--text-muted);font-size:10px;font-family:var(--font-mono)">No connections</div>';
|
|
1109
2066
|
return;
|
|
1110
2067
|
}
|
|
1111
2068
|
|
|
1112
|
-
const width = container.clientWidth;
|
|
1113
|
-
const height = container.clientHeight;
|
|
2069
|
+
const width = container.clientWidth || 248;
|
|
2070
|
+
const height = container.clientHeight || 200;
|
|
2071
|
+
const margin = 24;
|
|
1114
2072
|
|
|
1115
2073
|
const svg = d3.select(container).append('svg')
|
|
1116
2074
|
.attr('viewBox', `0 0 ${width} ${height}`);
|
|
1117
2075
|
|
|
1118
|
-
const
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
2076
|
+
const g = svg.append('g');
|
|
2077
|
+
|
|
2078
|
+
svg.call(d3.zoom()
|
|
2079
|
+
.scaleExtent([0.3, 3])
|
|
2080
|
+
.on('zoom', (event) => g.attr('transform', event.transform))
|
|
2081
|
+
);
|
|
1122
2082
|
|
|
1123
2083
|
const simulation = d3.forceSimulation(nodeArray)
|
|
1124
|
-
.force('link', d3.forceLink(links).id(d => d.id).distance(
|
|
2084
|
+
.force('link', d3.forceLink(links).id(d => d.id).distance(60))
|
|
1125
2085
|
.force('charge', d3.forceManyBody().strength(-120))
|
|
1126
2086
|
.force('center', d3.forceCenter(width / 2, height / 2))
|
|
1127
2087
|
.force('collision', d3.forceCollide().radius(25));
|
|
1128
2088
|
|
|
1129
|
-
const
|
|
2089
|
+
const linkEl = g.selectAll('.graph-link')
|
|
1130
2090
|
.data(links).enter().append('line')
|
|
1131
|
-
.attr('class', 'graph-link')
|
|
2091
|
+
.attr('class', 'graph-link')
|
|
2092
|
+
.attr('stroke-dasharray', d => d.dashed ? '3,3' : null)
|
|
2093
|
+
.style('opacity', d => d.dashed ? 0.5 : 1);
|
|
1132
2094
|
|
|
1133
|
-
const node =
|
|
2095
|
+
const node = g.selectAll('.graph-node')
|
|
1134
2096
|
.data(nodeArray).enter().append('g')
|
|
1135
2097
|
.attr('class', d => 'graph-node' + (d.active ? ' active' : ''))
|
|
1136
|
-
.on('click', (e, d) => loadNote(d.id))
|
|
2098
|
+
.on('click', (e, d) => { e.stopPropagation(); loadNote(d.id); })
|
|
1137
2099
|
.call(d3.drag()
|
|
1138
2100
|
.on('start', (e, d) => { if (!e.active) simulation.alphaTarget(0.3).restart(); d.fx = d.x; d.fy = d.y; })
|
|
1139
2101
|
.on('drag', (e, d) => { d.fx = e.x; d.fy = e.y; })
|
|
1140
2102
|
.on('end', (e, d) => { if (!e.active) simulation.alphaTarget(0); d.fx = null; d.fy = null; })
|
|
1141
2103
|
);
|
|
1142
2104
|
|
|
1143
|
-
node.filter(d => d.active).append('circle').attr('r', 14).style('fill', 'url(#node-glow)').style('stroke', 'none');
|
|
1144
2105
|
node.append('circle').attr('r', d => d.active ? 6 : 4);
|
|
1145
|
-
node.append('text').text(d => d.title).attr('dx',
|
|
2106
|
+
node.append('text').text(d => d.title).attr('dx', 10).attr('dy', 3);
|
|
1146
2107
|
|
|
1147
2108
|
simulation.on('tick', () => {
|
|
1148
|
-
|
|
2109
|
+
linkEl
|
|
1149
2110
|
.attr('x1', d => d.source.x).attr('y1', d => d.source.y)
|
|
1150
2111
|
.attr('x2', d => d.target.x).attr('y2', d => d.target.y);
|
|
1151
|
-
node.attr('transform', d =>
|
|
2112
|
+
node.attr('transform', d => {
|
|
2113
|
+
d.x = Math.max(margin, Math.min(width - margin, d.x));
|
|
2114
|
+
d.y = Math.max(margin, Math.min(height - margin, d.y));
|
|
2115
|
+
return `translate(${d.x},${d.y})`;
|
|
2116
|
+
});
|
|
2117
|
+
});
|
|
2118
|
+
}
|
|
2119
|
+
|
|
2120
|
+
// --- Graph Resize ---
|
|
2121
|
+
let graphHeight = parseInt(localStorage.getItem('kyp-graph-h')) || 200;
|
|
2122
|
+
|
|
2123
|
+
function initGraphResize() {
|
|
2124
|
+
const container = document.getElementById('graph-container');
|
|
2125
|
+
container.style.height = graphHeight + 'px';
|
|
2126
|
+
|
|
2127
|
+
document.getElementById('graph-shrink').addEventListener('click', () => {
|
|
2128
|
+
graphHeight = Math.max(100, graphHeight - 50);
|
|
2129
|
+
container.style.height = graphHeight + 'px';
|
|
2130
|
+
localStorage.setItem('kyp-graph-h', graphHeight);
|
|
2131
|
+
if (graphVisible && currentNote) renderGraph(currentNote);
|
|
2132
|
+
});
|
|
2133
|
+
|
|
2134
|
+
document.getElementById('graph-grow').addEventListener('click', () => {
|
|
2135
|
+
graphHeight = Math.min(600, graphHeight + 50);
|
|
2136
|
+
container.style.height = graphHeight + 'px';
|
|
2137
|
+
localStorage.setItem('kyp-graph-h', graphHeight);
|
|
2138
|
+
if (graphVisible && currentNote) renderGraph(currentNote);
|
|
2139
|
+
});
|
|
2140
|
+
|
|
2141
|
+
const handle = document.getElementById('graph-resize-handle');
|
|
2142
|
+
handle.addEventListener('mousedown', (e) => {
|
|
2143
|
+
e.preventDefault();
|
|
2144
|
+
const startY = e.clientY;
|
|
2145
|
+
const startH = graphHeight;
|
|
2146
|
+
document.body.style.cursor = 'ns-resize';
|
|
2147
|
+
document.body.style.userSelect = 'none';
|
|
2148
|
+
|
|
2149
|
+
function onMove(ev) {
|
|
2150
|
+
graphHeight = Math.max(100, Math.min(600, startH + (ev.clientY - startY)));
|
|
2151
|
+
container.style.height = graphHeight + 'px';
|
|
2152
|
+
}
|
|
2153
|
+
|
|
2154
|
+
function onUp() {
|
|
2155
|
+
document.body.style.cursor = '';
|
|
2156
|
+
document.body.style.userSelect = '';
|
|
2157
|
+
localStorage.setItem('kyp-graph-h', graphHeight);
|
|
2158
|
+
if (graphVisible && currentNote) renderGraph(currentNote);
|
|
2159
|
+
document.removeEventListener('mousemove', onMove);
|
|
2160
|
+
document.removeEventListener('mouseup', onUp);
|
|
2161
|
+
}
|
|
2162
|
+
|
|
2163
|
+
document.addEventListener('mousemove', onMove);
|
|
2164
|
+
document.addEventListener('mouseup', onUp);
|
|
1152
2165
|
});
|
|
1153
2166
|
}
|
|
1154
2167
|
|
|
@@ -1195,14 +2208,113 @@ document.addEventListener('click', (e) => {
|
|
|
1195
2208
|
if (!e.target.closest('.search-box')) searchResults.classList.remove('active');
|
|
1196
2209
|
});
|
|
1197
2210
|
|
|
2211
|
+
// --- Tag Filter ---
|
|
2212
|
+
document.getElementById('tag-filter-toggle').addEventListener('click', () => {
|
|
2213
|
+
const body = document.getElementById('tag-filter-body');
|
|
2214
|
+
const arrow = document.getElementById('tag-arrow');
|
|
2215
|
+
body.classList.toggle('collapsed');
|
|
2216
|
+
arrow.classList.toggle('open');
|
|
2217
|
+
});
|
|
2218
|
+
|
|
2219
|
+
document.getElementById('clear-filters').addEventListener('click', () => {
|
|
2220
|
+
activeTagFilters.clear();
|
|
2221
|
+
applyTagFilter();
|
|
2222
|
+
});
|
|
2223
|
+
|
|
2224
|
+
function renderTagCloud(tags) {
|
|
2225
|
+
const cloud = document.getElementById('tag-cloud');
|
|
2226
|
+
cloud.innerHTML = '';
|
|
2227
|
+
const sorted = Object.entries(tags).sort((a, b) => b[1] - a[1]);
|
|
2228
|
+
sorted.forEach(([tag, count]) => {
|
|
2229
|
+
const chip = document.createElement('span');
|
|
2230
|
+
chip.className = 'tag-chip' + (activeTagFilters.has(tag) ? ' selected' : '');
|
|
2231
|
+
chip.innerHTML = `#${tag}<span class="tag-count">${count}</span>`;
|
|
2232
|
+
chip.addEventListener('click', () => {
|
|
2233
|
+
if (activeTagFilters.has(tag)) {
|
|
2234
|
+
activeTagFilters.delete(tag);
|
|
2235
|
+
} else {
|
|
2236
|
+
activeTagFilters.add(tag);
|
|
2237
|
+
}
|
|
2238
|
+
applyTagFilter();
|
|
2239
|
+
});
|
|
2240
|
+
cloud.appendChild(chip);
|
|
2241
|
+
});
|
|
2242
|
+
}
|
|
2243
|
+
|
|
2244
|
+
function applyTagFilter() {
|
|
2245
|
+
const activeEl = document.getElementById('active-tags');
|
|
2246
|
+
const filterInfo = document.getElementById('filter-info');
|
|
2247
|
+
const filterCount = document.getElementById('filter-count');
|
|
2248
|
+
|
|
2249
|
+
activeEl.innerHTML = '';
|
|
2250
|
+
activeTagFilters.forEach(tag => {
|
|
2251
|
+
const el = document.createElement('span');
|
|
2252
|
+
el.className = 'active-tag';
|
|
2253
|
+
el.innerHTML = `#${tag}<span class="remove">×</span>`;
|
|
2254
|
+
el.addEventListener('click', () => {
|
|
2255
|
+
activeTagFilters.delete(tag);
|
|
2256
|
+
applyTagFilter();
|
|
2257
|
+
});
|
|
2258
|
+
activeEl.appendChild(el);
|
|
2259
|
+
});
|
|
2260
|
+
|
|
2261
|
+
document.querySelectorAll('.tag-chip').forEach(chip => {
|
|
2262
|
+
const tag = chip.textContent.replace('#', '').replace(/\d+$/, '');
|
|
2263
|
+
chip.classList.toggle('selected', activeTagFilters.has(tag));
|
|
2264
|
+
});
|
|
2265
|
+
|
|
2266
|
+
const treeItems = document.querySelectorAll('.tree-item[data-path]');
|
|
2267
|
+
let visibleCount = 0;
|
|
2268
|
+
|
|
2269
|
+
if (activeTagFilters.size === 0) {
|
|
2270
|
+
treeItems.forEach(el => { el.style.display = ''; });
|
|
2271
|
+
document.querySelectorAll('.tree-children').forEach(el => el.classList.remove('collapsed'));
|
|
2272
|
+
filterInfo.style.display = 'none';
|
|
2273
|
+
renderTagCloud(collectAllTags());
|
|
2274
|
+
return;
|
|
2275
|
+
}
|
|
2276
|
+
|
|
2277
|
+
const matchingPaths = new Set();
|
|
2278
|
+
|
|
2279
|
+
for (const [path, note] of Object.entries(allNotes)) {
|
|
2280
|
+
const noteTags = (note.tags || []).map(t => t.toLowerCase());
|
|
2281
|
+
const matches = [...activeTagFilters].every(f => noteTags.includes(f.toLowerCase()));
|
|
2282
|
+
if (matches) matchingPaths.add(path);
|
|
2283
|
+
}
|
|
2284
|
+
|
|
2285
|
+
treeItems.forEach(el => {
|
|
2286
|
+
const path = el.dataset.path;
|
|
2287
|
+
if (matchingPaths.has(path)) {
|
|
2288
|
+
el.style.display = '';
|
|
2289
|
+
visibleCount++;
|
|
2290
|
+
} else {
|
|
2291
|
+
el.style.display = 'none';
|
|
2292
|
+
}
|
|
2293
|
+
});
|
|
2294
|
+
|
|
2295
|
+
document.querySelectorAll('.tree-children').forEach(el => el.classList.remove('collapsed'));
|
|
2296
|
+
|
|
2297
|
+
filterInfo.style.display = '';
|
|
2298
|
+
filterCount.textContent = `${visibleCount} note${visibleCount !== 1 ? 's' : ''}`;
|
|
2299
|
+
renderTagCloud(collectAllTags());
|
|
2300
|
+
}
|
|
2301
|
+
|
|
2302
|
+
function collectAllTags() {
|
|
2303
|
+
const tags = {};
|
|
2304
|
+
for (const note of Object.values(allNotes)) {
|
|
2305
|
+
(note.tags || []).forEach(t => { tags[t] = (tags[t] || 0) + 1; });
|
|
2306
|
+
}
|
|
2307
|
+
return tags;
|
|
2308
|
+
}
|
|
2309
|
+
|
|
1198
2310
|
// --- Resizable Panels ---
|
|
1199
2311
|
function initResize() {
|
|
1200
2312
|
const layout = document.getElementById('layout');
|
|
1201
2313
|
const leftHandle = document.getElementById('resize-left');
|
|
1202
2314
|
const rightHandle = document.getElementById('resize-right');
|
|
1203
2315
|
|
|
1204
|
-
let sidebarW = parseInt(localStorage.getItem('kyp-sidebar-w')) ||
|
|
1205
|
-
let rightW = parseInt(localStorage.getItem('kyp-right-w')) ||
|
|
2316
|
+
let sidebarW = parseInt(localStorage.getItem('kyp-sidebar-w')) || 256;
|
|
2317
|
+
let rightW = parseInt(localStorage.getItem('kyp-right-w')) || 272;
|
|
1206
2318
|
|
|
1207
2319
|
layout.style.setProperty('--sidebar-w', sidebarW + 'px');
|
|
1208
2320
|
layout.style.setProperty('--right-w', rightW + 'px');
|
|
@@ -1242,7 +2354,7 @@ function initResize() {
|
|
|
1242
2354
|
save: () => localStorage.setItem('kyp-sidebar-w', sidebarW),
|
|
1243
2355
|
invert: false,
|
|
1244
2356
|
min: 180,
|
|
1245
|
-
max:
|
|
2357
|
+
max: 400,
|
|
1246
2358
|
});
|
|
1247
2359
|
|
|
1248
2360
|
makeDraggable(rightHandle, {
|
|
@@ -1251,7 +2363,7 @@ function initResize() {
|
|
|
1251
2363
|
save: () => localStorage.setItem('kyp-right-w', rightW),
|
|
1252
2364
|
invert: true,
|
|
1253
2365
|
min: 200,
|
|
1254
|
-
max:
|
|
2366
|
+
max: 450,
|
|
1255
2367
|
});
|
|
1256
2368
|
}
|
|
1257
2369
|
|
|
@@ -1277,6 +2389,7 @@ async function init() {
|
|
|
1277
2389
|
await Promise.all(promises);
|
|
1278
2390
|
|
|
1279
2391
|
renderTree(treeData, document.getElementById('file-tree'));
|
|
2392
|
+
renderTagCloud(collectAllTags());
|
|
1280
2393
|
|
|
1281
2394
|
document.getElementById('stats-bar').innerHTML = `
|
|
1282
2395
|
<span><span class="stat-val">${stats.notes}</span> notes</span>
|
|
@@ -1287,6 +2400,7 @@ async function init() {
|
|
|
1287
2400
|
}
|
|
1288
2401
|
|
|
1289
2402
|
initResize();
|
|
2403
|
+
initGraphResize();
|
|
1290
2404
|
init();
|
|
1291
2405
|
</script>
|
|
1292
2406
|
</body>
|