kyp-mem 0.3.0 → 0.4.1
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/kyp_mem/__init__.py +1 -1
- package/kyp_mem/hooks.py +38 -14
- package/kyp_mem/server.py +179 -1
- package/kyp_mem/static/index.html +1197 -220
- package/kyp_mem/ui.py +111 -0
- package/kyp_mem/vault.py +15 -0
- package/kyp_mem/vector.py +43 -0
- package/package.json +1 -1
- package/pyproject.toml +2 -1
|
@@ -10,40 +10,40 @@
|
|
|
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
|
-
--bg-surface: #
|
|
21
|
-
|
|
22
|
-
--neon-cyan: #
|
|
23
|
-
--neon-green: #
|
|
24
|
-
--neon-magenta: #
|
|
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
25
|
--neon-purple: #a78bfa;
|
|
26
|
-
--neon-orange: #
|
|
27
|
-
--neon-yellow: #
|
|
28
|
-
--neon-blue: #
|
|
29
|
-
--neon-red: #
|
|
26
|
+
--neon-orange: #e8935a;
|
|
27
|
+
--neon-yellow: #d4a853;
|
|
28
|
+
--neon-blue: #7da8d4;
|
|
29
|
+
--neon-red: #d47171;
|
|
30
30
|
|
|
31
|
-
--glow-cyan: 0 0 8px #
|
|
32
|
-
--glow-green: 0 0 8px #
|
|
33
|
-
--glow-magenta: 0 0 8px #
|
|
31
|
+
--glow-cyan: 0 0 8px #D9775730;
|
|
32
|
+
--glow-green: 0 0 8px #5bb98c30;
|
|
33
|
+
--glow-magenta: 0 0 8px #c47ad730;
|
|
34
34
|
|
|
35
|
-
--text-primary: #
|
|
36
|
-
--text-secondary: #
|
|
37
|
-
--text-muted: #
|
|
38
|
-
--border:
|
|
39
|
-
--border-subtle:
|
|
35
|
+
--text-primary: #d8d5cf;
|
|
36
|
+
--text-secondary: #807b73;
|
|
37
|
+
--text-muted: #55514a;
|
|
38
|
+
--border: rgba(255,255,255,0.06);
|
|
39
|
+
--border-subtle: rgba(255,255,255,0.03);
|
|
40
40
|
|
|
41
41
|
--font: 'Inter', -apple-system, sans-serif;
|
|
42
42
|
--font-mono: 'JetBrains Mono', monospace;
|
|
43
43
|
|
|
44
44
|
--radius-sm: 4px;
|
|
45
|
-
--radius:
|
|
46
|
-
--radius-lg:
|
|
45
|
+
--radius: 8px;
|
|
46
|
+
--radius-lg: 12px;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
body {
|
|
52
52
|
font-family: var(--font);
|
|
53
53
|
background: var(--bg-void);
|
|
54
|
+
background-image: radial-gradient(circle at 50% 0%, var(--bg-secondary) 0%, var(--bg-void) 70%);
|
|
54
55
|
color: var(--text-primary);
|
|
55
56
|
height: 100vh;
|
|
56
57
|
overflow: hidden;
|
|
@@ -62,8 +63,8 @@ body::before {
|
|
|
62
63
|
position: fixed;
|
|
63
64
|
inset: 0;
|
|
64
65
|
background-image:
|
|
65
|
-
linear-gradient(rgba(
|
|
66
|
-
linear-gradient(90deg, rgba(
|
|
66
|
+
linear-gradient(rgba(217,119,87,0.012) 1px, transparent 1px),
|
|
67
|
+
linear-gradient(90deg, rgba(217,119,87,0.012) 1px, transparent 1px);
|
|
67
68
|
background-size: 48px 48px;
|
|
68
69
|
pointer-events: none;
|
|
69
70
|
z-index: 0;
|
|
@@ -103,7 +104,7 @@ body::before {
|
|
|
103
104
|
.resize-handle:hover,
|
|
104
105
|
.resize-handle.dragging {
|
|
105
106
|
background: var(--neon-cyan);
|
|
106
|
-
box-shadow: 0 0 12px rgba(
|
|
107
|
+
box-shadow: 0 0 12px rgba(217,119,87,0.2);
|
|
107
108
|
}
|
|
108
109
|
|
|
109
110
|
body.resizing { cursor: col-resize !important; user-select: none !important; }
|
|
@@ -113,7 +114,9 @@ body.resizing .resize-handle { pointer-events: auto !important; }
|
|
|
113
114
|
/* ============ HEADER ============ */
|
|
114
115
|
.header {
|
|
115
116
|
grid-column: 1 / -1;
|
|
116
|
-
background:
|
|
117
|
+
background: rgba(8,8,10,0.6);
|
|
118
|
+
backdrop-filter: blur(12px);
|
|
119
|
+
-webkit-backdrop-filter: blur(12px);
|
|
117
120
|
border-bottom: 1px solid var(--border);
|
|
118
121
|
display: flex;
|
|
119
122
|
align-items: center;
|
|
@@ -191,9 +194,9 @@ body.resizing .resize-handle { pointer-events: auto !important; }
|
|
|
191
194
|
}
|
|
192
195
|
|
|
193
196
|
.header-btn.active {
|
|
194
|
-
border-color: rgba(
|
|
197
|
+
border-color: rgba(217,119,87,0.3);
|
|
195
198
|
color: var(--neon-cyan);
|
|
196
|
-
background: rgba(
|
|
199
|
+
background: rgba(217,119,87,0.05);
|
|
197
200
|
}
|
|
198
201
|
|
|
199
202
|
.header-btn .dot {
|
|
@@ -229,8 +232,8 @@ body.resizing .resize-handle { pointer-events: auto !important; }
|
|
|
229
232
|
.search-box input::placeholder { color: var(--text-muted); }
|
|
230
233
|
|
|
231
234
|
.search-box input:focus {
|
|
232
|
-
border-color: rgba(
|
|
233
|
-
box-shadow: 0 0 16px rgba(
|
|
235
|
+
border-color: rgba(217,119,87,0.3);
|
|
236
|
+
box-shadow: 0 0 16px rgba(217,119,87,0.08);
|
|
234
237
|
width: 260px;
|
|
235
238
|
}
|
|
236
239
|
|
|
@@ -309,24 +312,27 @@ body.resizing .resize-handle { pointer-events: auto !important; }
|
|
|
309
312
|
.quick-switcher-overlay {
|
|
310
313
|
position: fixed;
|
|
311
314
|
inset: 0;
|
|
312
|
-
background: rgba(6,6,12,0.
|
|
315
|
+
background: rgba(6,6,12,0.6);
|
|
313
316
|
z-index: 200;
|
|
314
317
|
display: none;
|
|
315
318
|
align-items: flex-start;
|
|
316
319
|
justify-content: center;
|
|
317
320
|
padding-top: 15vh;
|
|
318
|
-
backdrop-filter: blur(
|
|
321
|
+
backdrop-filter: blur(12px);
|
|
322
|
+
-webkit-backdrop-filter: blur(12px);
|
|
319
323
|
}
|
|
320
324
|
|
|
321
325
|
.quick-switcher-overlay.active { display: flex; }
|
|
322
326
|
|
|
323
327
|
.quick-switcher {
|
|
324
328
|
width: 480px;
|
|
325
|
-
background:
|
|
329
|
+
background: rgba(17,17,22,0.85);
|
|
326
330
|
border: 1px solid var(--border);
|
|
327
331
|
border-radius: var(--radius-lg);
|
|
328
|
-
box-shadow: 0
|
|
332
|
+
box-shadow: 0 24px 64px rgba(0,0,0,0.8), 0 0 0 1px rgba(217,119,87,0.1);
|
|
329
333
|
overflow: hidden;
|
|
334
|
+
backdrop-filter: blur(20px);
|
|
335
|
+
-webkit-backdrop-filter: blur(20px);
|
|
330
336
|
}
|
|
331
337
|
|
|
332
338
|
.quick-switcher input {
|
|
@@ -434,7 +440,7 @@ body.resizing .resize-handle { pointer-events: auto !important; }
|
|
|
434
440
|
.tree-item:hover { background: var(--bg-hover); }
|
|
435
441
|
|
|
436
442
|
.tree-item.active {
|
|
437
|
-
background: rgba(
|
|
443
|
+
background: rgba(217,119,87,0.05);
|
|
438
444
|
}
|
|
439
445
|
|
|
440
446
|
.tree-item.active::before {
|
|
@@ -523,9 +529,9 @@ body.resizing .resize-handle { pointer-events: auto !important; }
|
|
|
523
529
|
font-size: 9px;
|
|
524
530
|
padding: 2px 7px;
|
|
525
531
|
border-radius: var(--radius-sm);
|
|
526
|
-
background: rgba(
|
|
532
|
+
background: rgba(217,119,87,0.08);
|
|
527
533
|
color: var(--neon-cyan);
|
|
528
|
-
border: 1px solid rgba(
|
|
534
|
+
border: 1px solid rgba(217,119,87,0.2);
|
|
529
535
|
cursor: pointer;
|
|
530
536
|
display: flex;
|
|
531
537
|
align-items: center;
|
|
@@ -533,7 +539,7 @@ body.resizing .resize-handle { pointer-events: auto !important; }
|
|
|
533
539
|
transition: all 0.15s;
|
|
534
540
|
}
|
|
535
541
|
|
|
536
|
-
.active-tag:hover { background: rgba(
|
|
542
|
+
.active-tag:hover { background: rgba(217,119,87,0.15); }
|
|
537
543
|
.active-tag .remove { font-size: 11px; opacity: 0.5; }
|
|
538
544
|
.active-tag .remove:hover { opacity: 1; }
|
|
539
545
|
|
|
@@ -566,9 +572,9 @@ body.resizing .resize-handle { pointer-events: auto !important; }
|
|
|
566
572
|
}
|
|
567
573
|
|
|
568
574
|
.tag-chip.selected {
|
|
569
|
-
background: rgba(
|
|
575
|
+
background: rgba(217,119,87,0.08);
|
|
570
576
|
color: var(--neon-cyan);
|
|
571
|
-
border-color: rgba(
|
|
577
|
+
border-color: rgba(217,119,87,0.2);
|
|
572
578
|
}
|
|
573
579
|
|
|
574
580
|
.tag-chip .tag-count {
|
|
@@ -637,9 +643,9 @@ body.resizing .resize-handle { pointer-events: auto !important; }
|
|
|
637
643
|
}
|
|
638
644
|
|
|
639
645
|
.tag.clickable-tag:hover {
|
|
640
|
-
background: rgba(
|
|
646
|
+
background: rgba(217,119,87,0.08);
|
|
641
647
|
color: var(--neon-cyan);
|
|
642
|
-
border-color: rgba(
|
|
648
|
+
border-color: rgba(217,119,87,0.2);
|
|
643
649
|
cursor: pointer;
|
|
644
650
|
}
|
|
645
651
|
|
|
@@ -657,119 +663,132 @@ body.resizing .resize-handle { pointer-events: auto !important; }
|
|
|
657
663
|
|
|
658
664
|
/* ============ MARKDOWN ============ */
|
|
659
665
|
.md-body h1 {
|
|
660
|
-
font-size:
|
|
666
|
+
font-size: 28px;
|
|
661
667
|
font-weight: 700;
|
|
662
|
-
margin: 0 0
|
|
668
|
+
margin: 0 0 28px;
|
|
663
669
|
color: var(--text-primary);
|
|
664
|
-
letter-spacing: -0.
|
|
670
|
+
letter-spacing: -0.5px;
|
|
671
|
+
text-shadow: 0 0 15px rgba(255,255,255,0.05);
|
|
665
672
|
}
|
|
666
673
|
|
|
667
674
|
.md-body h2 {
|
|
668
|
-
font-size:
|
|
675
|
+
font-size: 20px;
|
|
669
676
|
font-weight: 600;
|
|
670
|
-
margin:
|
|
677
|
+
margin: 40px 0 16px;
|
|
671
678
|
color: var(--text-primary);
|
|
672
|
-
padding-bottom:
|
|
673
|
-
border-bottom: 1px solid var(--border
|
|
679
|
+
padding-bottom: 10px;
|
|
680
|
+
border-bottom: 1px solid var(--border);
|
|
674
681
|
}
|
|
675
682
|
|
|
676
683
|
.md-body h3 {
|
|
677
|
-
font-size:
|
|
684
|
+
font-size: 16px;
|
|
678
685
|
font-weight: 600;
|
|
679
|
-
margin:
|
|
686
|
+
margin: 32px 0 12px;
|
|
680
687
|
color: var(--neon-purple);
|
|
688
|
+
text-shadow: 0 0 8px rgba(168,139,250,0.2);
|
|
681
689
|
}
|
|
682
690
|
|
|
683
691
|
.md-body p {
|
|
684
|
-
line-height: 1.
|
|
685
|
-
margin:
|
|
692
|
+
line-height: 1.9;
|
|
693
|
+
margin: 12px 0;
|
|
686
694
|
color: var(--text-secondary);
|
|
687
|
-
font-size:
|
|
695
|
+
font-size: 14px;
|
|
688
696
|
}
|
|
689
697
|
|
|
690
|
-
.md-body ul, .md-body ol { padding-left: 24px; margin:
|
|
698
|
+
.md-body ul, .md-body ol { padding-left: 24px; margin: 12px 0; }
|
|
691
699
|
|
|
692
700
|
.md-body li {
|
|
693
|
-
line-height: 1.
|
|
701
|
+
line-height: 1.9;
|
|
694
702
|
color: var(--text-secondary);
|
|
695
|
-
margin:
|
|
696
|
-
font-size:
|
|
703
|
+
margin: 4px 0;
|
|
704
|
+
font-size: 14px;
|
|
697
705
|
}
|
|
698
706
|
|
|
699
707
|
.md-body li::marker { color: var(--text-muted); }
|
|
700
708
|
|
|
701
|
-
.md-body a { color: var(--neon-blue); text-decoration: none; }
|
|
702
|
-
.md-body a:hover { text-decoration: underline; }
|
|
709
|
+
.md-body a { color: var(--neon-blue); text-decoration: none; transition: color 0.2s; }
|
|
710
|
+
.md-body a:hover { color: var(--neon-cyan); text-decoration: underline; }
|
|
703
711
|
|
|
704
712
|
.md-body strong { color: var(--text-primary); font-weight: 600; }
|
|
705
713
|
|
|
706
714
|
.md-body code {
|
|
707
|
-
background: var(--bg-
|
|
708
|
-
padding:
|
|
709
|
-
border-radius:
|
|
715
|
+
background: var(--bg-hover);
|
|
716
|
+
padding: 3px 6px;
|
|
717
|
+
border-radius: 4px;
|
|
710
718
|
font-family: var(--font-mono);
|
|
711
|
-
font-size:
|
|
719
|
+
font-size: 12.5px;
|
|
712
720
|
color: var(--neon-orange);
|
|
713
|
-
border: 1px solid var(--border
|
|
721
|
+
border: 1px solid var(--border);
|
|
714
722
|
}
|
|
715
723
|
|
|
716
724
|
.md-body pre {
|
|
717
|
-
background:
|
|
725
|
+
background: rgba(8,8,10,0.4);
|
|
718
726
|
border: 1px solid var(--border);
|
|
719
|
-
border-radius: var(--radius);
|
|
720
|
-
padding:
|
|
727
|
+
border-radius: var(--radius-lg);
|
|
728
|
+
padding: 20px;
|
|
721
729
|
overflow-x: auto;
|
|
722
|
-
margin:
|
|
730
|
+
margin: 20px 0;
|
|
731
|
+
box-shadow: inset 0 2px 10px rgba(0,0,0,0.2);
|
|
723
732
|
}
|
|
724
733
|
|
|
725
734
|
.md-body pre code {
|
|
726
735
|
background: none;
|
|
727
736
|
padding: 0;
|
|
728
737
|
border: none;
|
|
729
|
-
color:
|
|
730
|
-
font-size:
|
|
731
|
-
line-height: 1.
|
|
738
|
+
color: #c9c7c2;
|
|
739
|
+
font-size: 12.5px;
|
|
740
|
+
line-height: 1.8;
|
|
732
741
|
}
|
|
733
742
|
|
|
734
743
|
.md-body table {
|
|
735
744
|
width: 100%;
|
|
736
|
-
border-collapse:
|
|
737
|
-
|
|
738
|
-
|
|
745
|
+
border-collapse: separate;
|
|
746
|
+
border-spacing: 0;
|
|
747
|
+
margin: 24px 0;
|
|
748
|
+
font-size: 13px;
|
|
749
|
+
border: 1px solid var(--border);
|
|
750
|
+
border-radius: var(--radius);
|
|
751
|
+
overflow: hidden;
|
|
739
752
|
}
|
|
740
753
|
|
|
741
754
|
.md-body th {
|
|
742
755
|
text-align: left;
|
|
743
|
-
padding:
|
|
756
|
+
padding: 12px 16px;
|
|
744
757
|
border-bottom: 1px solid var(--border);
|
|
745
|
-
|
|
758
|
+
background: rgba(255,255,255,0.02);
|
|
759
|
+
color: var(--text-primary);
|
|
746
760
|
font-family: var(--font-mono);
|
|
747
761
|
font-weight: 600;
|
|
748
|
-
font-size:
|
|
762
|
+
font-size: 11px;
|
|
749
763
|
text-transform: uppercase;
|
|
750
764
|
letter-spacing: 0.5px;
|
|
751
765
|
}
|
|
752
766
|
|
|
753
767
|
.md-body td {
|
|
754
|
-
padding:
|
|
755
|
-
border-bottom: 1px solid var(--border
|
|
768
|
+
padding: 12px 16px;
|
|
769
|
+
border-bottom: 1px solid var(--border);
|
|
756
770
|
color: var(--text-secondary);
|
|
771
|
+
transition: background 0.15s;
|
|
757
772
|
}
|
|
758
773
|
|
|
759
|
-
.md-body tr:
|
|
774
|
+
.md-body tr:last-child td { border-bottom: none; }
|
|
775
|
+
.md-body tr:hover td { background: var(--bg-hover); color: var(--text-primary); }
|
|
760
776
|
|
|
761
777
|
.md-body blockquote {
|
|
762
|
-
border-left:
|
|
763
|
-
padding
|
|
764
|
-
margin:
|
|
765
|
-
color: var(--text-
|
|
778
|
+
border-left: 3px solid var(--neon-purple);
|
|
779
|
+
padding: 12px 20px;
|
|
780
|
+
margin: 20px 0;
|
|
781
|
+
color: var(--text-secondary);
|
|
782
|
+
background: linear-gradient(90deg, rgba(168,139,250,0.05), transparent);
|
|
783
|
+
border-radius: 0 var(--radius) var(--radius) 0;
|
|
784
|
+
font-style: italic;
|
|
766
785
|
}
|
|
767
786
|
|
|
768
787
|
.md-body hr {
|
|
769
788
|
border: none;
|
|
770
789
|
height: 1px;
|
|
771
|
-
background: var(--border);
|
|
772
|
-
margin:
|
|
790
|
+
background: linear-gradient(90deg, transparent, var(--border), transparent);
|
|
791
|
+
margin: 36px 0;
|
|
773
792
|
}
|
|
774
793
|
|
|
775
794
|
.wikilink {
|
|
@@ -783,7 +802,7 @@ body.resizing .resize-handle { pointer-events: auto !important; }
|
|
|
783
802
|
|
|
784
803
|
.wikilink:hover {
|
|
785
804
|
color: var(--neon-cyan);
|
|
786
|
-
border-bottom-color: rgba(
|
|
805
|
+
border-bottom-color: rgba(217,119,87,0.4);
|
|
787
806
|
}
|
|
788
807
|
|
|
789
808
|
/* ============ EMPTY STATE ============ */
|
|
@@ -840,15 +859,40 @@ body.resizing .resize-handle { pointer-events: auto !important; }
|
|
|
840
859
|
|
|
841
860
|
.rp-section-title {
|
|
842
861
|
font-family: var(--font-mono);
|
|
843
|
-
font-size:
|
|
862
|
+
font-size: 10px;
|
|
844
863
|
font-weight: 600;
|
|
845
864
|
text-transform: uppercase;
|
|
846
865
|
letter-spacing: 1.5px;
|
|
847
|
-
color: var(--text-
|
|
866
|
+
color: var(--text-secondary);
|
|
848
867
|
margin-bottom: 8px;
|
|
849
868
|
display: flex;
|
|
850
869
|
align-items: center;
|
|
851
870
|
gap: 6px;
|
|
871
|
+
cursor: pointer;
|
|
872
|
+
padding: 4px 6px;
|
|
873
|
+
border-radius: var(--radius-sm);
|
|
874
|
+
transition: background 0.15s;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
.rp-section-title:hover {
|
|
878
|
+
background: var(--bg-hover);
|
|
879
|
+
color: var(--text-primary);
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
.rp-section-title .arrow {
|
|
883
|
+
margin-left: auto;
|
|
884
|
+
font-size: 8px;
|
|
885
|
+
color: var(--text-muted);
|
|
886
|
+
transition: transform 0.2s;
|
|
887
|
+
transform: rotate(90deg);
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
.rp-section.collapsed .rp-section-title .arrow {
|
|
891
|
+
transform: rotate(0deg);
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
.rp-section.collapsed .rp-section-body {
|
|
895
|
+
display: none;
|
|
852
896
|
}
|
|
853
897
|
|
|
854
898
|
.rp-section-title .rp-count {
|
|
@@ -859,122 +903,582 @@ body.resizing .resize-handle { pointer-events: auto !important; }
|
|
|
859
903
|
border-radius: 8px;
|
|
860
904
|
}
|
|
861
905
|
|
|
862
|
-
.rp-item {
|
|
863
|
-
display: flex;
|
|
906
|
+
.rp-item {
|
|
907
|
+
display: flex;
|
|
908
|
+
align-items: center;
|
|
909
|
+
padding: 5px 8px;
|
|
910
|
+
border-radius: var(--radius-sm);
|
|
911
|
+
cursor: pointer;
|
|
912
|
+
font-size: 11px;
|
|
913
|
+
gap: 8px;
|
|
914
|
+
margin-bottom: 1px;
|
|
915
|
+
transition: background 0.1s;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
.rp-item:hover { background: var(--bg-hover); }
|
|
919
|
+
|
|
920
|
+
.rp-item .rp-score {
|
|
921
|
+
font-family: var(--font-mono);
|
|
922
|
+
font-size: 10px;
|
|
923
|
+
color: var(--neon-green);
|
|
924
|
+
min-width: 30px;
|
|
925
|
+
opacity: 0.8;
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
.rp-item .rp-title {
|
|
929
|
+
overflow: hidden;
|
|
930
|
+
text-overflow: ellipsis;
|
|
931
|
+
white-space: nowrap;
|
|
932
|
+
color: var(--neon-purple);
|
|
933
|
+
font-weight: 500;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
.rp-item .rp-backlink-title { color: var(--neon-cyan); }
|
|
937
|
+
|
|
938
|
+
/* ============ OUTLINE ============ */
|
|
939
|
+
.outline-item {
|
|
940
|
+
display: block;
|
|
941
|
+
padding: 3px 8px;
|
|
942
|
+
border-radius: var(--radius-sm);
|
|
943
|
+
cursor: pointer;
|
|
944
|
+
font-size: 11px;
|
|
945
|
+
color: var(--text-secondary);
|
|
946
|
+
transition: all 0.1s;
|
|
947
|
+
overflow: hidden;
|
|
948
|
+
text-overflow: ellipsis;
|
|
949
|
+
white-space: nowrap;
|
|
950
|
+
margin-bottom: 1px;
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
.outline-item:hover {
|
|
954
|
+
background: var(--bg-hover);
|
|
955
|
+
color: var(--text-primary);
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
.outline-item.h2 { padding-left: 8px; }
|
|
959
|
+
.outline-item.h3 { padding-left: 20px; font-size: 10px; color: var(--text-muted); }
|
|
960
|
+
|
|
961
|
+
/* ============ GRAPH ============ */
|
|
962
|
+
#graph-section { margin-bottom: 12px; transition: all 0.3s; }
|
|
963
|
+
#graph-section.hidden { display: none; }
|
|
964
|
+
|
|
965
|
+
#graph-section.maximized {
|
|
966
|
+
position: fixed;
|
|
967
|
+
inset: 40px;
|
|
968
|
+
z-index: 250;
|
|
969
|
+
background: rgba(17,17,22,0.95);
|
|
970
|
+
border: 1px solid var(--border);
|
|
971
|
+
border-radius: var(--radius-lg);
|
|
972
|
+
padding: 20px;
|
|
973
|
+
display: flex;
|
|
974
|
+
flex-direction: column;
|
|
975
|
+
box-shadow: 0 24px 64px rgba(0,0,0,0.8), 0 0 0 1px rgba(217,119,87,0.3);
|
|
976
|
+
backdrop-filter: blur(20px);
|
|
977
|
+
-webkit-backdrop-filter: blur(20px);
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
#graph-container {
|
|
981
|
+
width: 100%;
|
|
982
|
+
height: 200px;
|
|
983
|
+
border: 1px solid var(--border);
|
|
984
|
+
border-radius: var(--radius);
|
|
985
|
+
overflow: hidden;
|
|
986
|
+
background: transparent;
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
#graph-section.maximized #graph-container {
|
|
990
|
+
flex: 1;
|
|
991
|
+
height: auto !important;
|
|
992
|
+
border: none;
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
#graph-container svg { width: 100%; height: 100%; }
|
|
996
|
+
|
|
997
|
+
.graph-node { cursor: pointer; }
|
|
998
|
+
|
|
999
|
+
.graph-node circle {
|
|
1000
|
+
fill: var(--neon-purple);
|
|
1001
|
+
filter: drop-shadow(0 0 3px rgba(168,139,250,0.5));
|
|
1002
|
+
transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
.graph-node:hover circle {
|
|
1006
|
+
fill: var(--neon-cyan);
|
|
1007
|
+
r: 8;
|
|
1008
|
+
filter: drop-shadow(0 0 8px rgba(217,119,87,0.7));
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
.graph-node.active circle {
|
|
1012
|
+
fill: var(--neon-cyan);
|
|
1013
|
+
filter: drop-shadow(0 0 10px rgba(217,119,87,0.9));
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
.graph-node text {
|
|
1017
|
+
fill: var(--text-muted);
|
|
1018
|
+
font-family: var(--font-mono);
|
|
1019
|
+
font-size: 11px;
|
|
1020
|
+
pointer-events: none;
|
|
1021
|
+
transition: all 0.2s;
|
|
1022
|
+
text-shadow: 0 0 2px var(--bg-primary), 0 0 4px var(--bg-primary);
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
.graph-node:hover text, .graph-node.active text {
|
|
1026
|
+
fill: var(--text-primary);
|
|
1027
|
+
font-size: 13px;
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
.graph-link {
|
|
1031
|
+
stroke: var(--neon-purple);
|
|
1032
|
+
stroke-width: 1.5;
|
|
1033
|
+
transition: opacity 0.3s;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
.graph-size-controls {
|
|
1037
|
+
margin-left: auto;
|
|
1038
|
+
display: flex;
|
|
1039
|
+
gap: 2px;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
.graph-size-btn {
|
|
1043
|
+
background: var(--bg-hover);
|
|
1044
|
+
border: 1px solid var(--border);
|
|
1045
|
+
color: var(--text-muted);
|
|
1046
|
+
font-family: var(--font-mono);
|
|
1047
|
+
font-size: 11px;
|
|
1048
|
+
width: 18px;
|
|
1049
|
+
height: 18px;
|
|
1050
|
+
border-radius: 3px;
|
|
1051
|
+
cursor: pointer;
|
|
1052
|
+
display: flex;
|
|
1053
|
+
align-items: center;
|
|
1054
|
+
justify-content: center;
|
|
1055
|
+
transition: all 0.15s;
|
|
1056
|
+
padding: 0;
|
|
1057
|
+
line-height: 1;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
.graph-size-btn:hover {
|
|
1061
|
+
border-color: var(--neon-cyan);
|
|
1062
|
+
color: var(--neon-cyan);
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
.graph-resize-handle {
|
|
1066
|
+
height: 8px;
|
|
1067
|
+
cursor: ns-resize;
|
|
1068
|
+
position: relative;
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
.graph-resize-handle::after {
|
|
1072
|
+
content: '';
|
|
1073
|
+
position: absolute;
|
|
1074
|
+
bottom: 2px;
|
|
1075
|
+
left: 50%;
|
|
1076
|
+
transform: translateX(-50%);
|
|
1077
|
+
width: 24px;
|
|
1078
|
+
height: 2px;
|
|
1079
|
+
background: var(--border);
|
|
1080
|
+
border-radius: 1px;
|
|
1081
|
+
transition: background 0.2s;
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
.graph-resize-handle:hover::after {
|
|
1085
|
+
background: var(--neon-cyan);
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
/* ============ SESSIONS PILLAR ============ */
|
|
1089
|
+
.pillar-divider {
|
|
1090
|
+
height: 1px;
|
|
1091
|
+
margin: 4px 12px;
|
|
1092
|
+
background: linear-gradient(90deg, transparent, var(--border), transparent);
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
.pillar-label {
|
|
1096
|
+
font-family: var(--font-mono);
|
|
1097
|
+
font-size: 8px;
|
|
1098
|
+
font-weight: 700;
|
|
1099
|
+
text-transform: uppercase;
|
|
1100
|
+
letter-spacing: 2px;
|
|
1101
|
+
color: var(--text-muted);
|
|
1102
|
+
padding: 10px 18px 4px;
|
|
1103
|
+
display: flex;
|
|
1104
|
+
align-items: center;
|
|
1105
|
+
justify-content: space-between;
|
|
1106
|
+
user-select: none;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
.pillar-label .pillar-accent {
|
|
1110
|
+
width: 6px;
|
|
1111
|
+
height: 6px;
|
|
1112
|
+
border-radius: 50%;
|
|
1113
|
+
display: inline-block;
|
|
1114
|
+
margin-right: 6px;
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
.pillar-label .pillar-accent.sessions { background: var(--neon-green); box-shadow: 0 0 6px var(--neon-green); }
|
|
1118
|
+
.pillar-label .pillar-accent.projects { background: var(--neon-cyan); box-shadow: 0 0 6px var(--neon-cyan); }
|
|
1119
|
+
|
|
1120
|
+
.pillar-label .pillar-action {
|
|
1121
|
+
font-size: 9px;
|
|
1122
|
+
font-weight: 500;
|
|
1123
|
+
color: var(--text-muted);
|
|
1124
|
+
cursor: pointer;
|
|
1125
|
+
padding: 1px 6px;
|
|
1126
|
+
border-radius: 3px;
|
|
1127
|
+
border: 1px solid transparent;
|
|
1128
|
+
transition: all 0.15s;
|
|
1129
|
+
letter-spacing: 0.5px;
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
.pillar-label .pillar-action:hover {
|
|
1133
|
+
color: var(--neon-green);
|
|
1134
|
+
border-color: rgba(91,185,140,0.3);
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
.session-search-box {
|
|
1138
|
+
padding: 6px 12px 4px;
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
.session-search-box input {
|
|
1142
|
+
width: 100%;
|
|
1143
|
+
background: rgba(8,8,10,0.4);
|
|
1144
|
+
border: 1px solid var(--border);
|
|
1145
|
+
color: var(--text-primary);
|
|
1146
|
+
font-family: var(--font-mono);
|
|
1147
|
+
font-size: 10px;
|
|
1148
|
+
padding: 5px 10px 5px 24px;
|
|
1149
|
+
border-radius: var(--radius);
|
|
1150
|
+
outline: none;
|
|
1151
|
+
transition: all 0.2s;
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
.session-search-box input::placeholder { color: var(--text-muted); }
|
|
1155
|
+
|
|
1156
|
+
.session-search-box input:focus {
|
|
1157
|
+
border-color: rgba(91,185,140,0.4);
|
|
1158
|
+
box-shadow: 0 0 8px rgba(91,185,140,0.08);
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
.session-search-box {
|
|
1162
|
+
position: relative;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
.session-search-box .ss-icon {
|
|
1166
|
+
position: absolute;
|
|
1167
|
+
left: 20px;
|
|
1168
|
+
top: 50%;
|
|
1169
|
+
transform: translateY(-50%);
|
|
1170
|
+
color: var(--text-muted);
|
|
1171
|
+
font-size: 10px;
|
|
1172
|
+
pointer-events: none;
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
.session-search-results {
|
|
1176
|
+
padding: 0 8px;
|
|
1177
|
+
max-height: 180px;
|
|
1178
|
+
overflow-y: auto;
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
.session-search-results:empty { display: none; }
|
|
1182
|
+
|
|
1183
|
+
.ss-result {
|
|
1184
|
+
padding: 5px 10px;
|
|
1185
|
+
border-radius: var(--radius-sm);
|
|
1186
|
+
cursor: pointer;
|
|
1187
|
+
margin: 1px 0;
|
|
1188
|
+
transition: background 0.1s;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
.ss-result:hover { background: var(--bg-hover); }
|
|
1192
|
+
|
|
1193
|
+
.ss-result .ss-title {
|
|
1194
|
+
font-size: 11px;
|
|
1195
|
+
color: var(--neon-green);
|
|
1196
|
+
font-weight: 500;
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
.ss-result .ss-meta {
|
|
1200
|
+
font-family: var(--font-mono);
|
|
1201
|
+
font-size: 9px;
|
|
1202
|
+
color: var(--text-muted);
|
|
1203
|
+
margin-top: 1px;
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
.ss-result .ss-snippet {
|
|
1207
|
+
font-size: 10px;
|
|
1208
|
+
color: var(--text-secondary);
|
|
1209
|
+
margin-top: 2px;
|
|
1210
|
+
overflow: hidden;
|
|
1211
|
+
text-overflow: ellipsis;
|
|
1212
|
+
white-space: nowrap;
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
.session-project-group {
|
|
1216
|
+
padding: 0 8px;
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
.session-project-header {
|
|
1220
|
+
display: flex;
|
|
1221
|
+
align-items: center;
|
|
1222
|
+
padding: 5px 10px;
|
|
1223
|
+
border-radius: var(--radius-sm);
|
|
1224
|
+
cursor: pointer;
|
|
1225
|
+
gap: 6px;
|
|
1226
|
+
user-select: none;
|
|
1227
|
+
transition: background 0.1s;
|
|
1228
|
+
margin: 1px 0;
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
.session-project-header:hover { background: var(--bg-hover); }
|
|
1232
|
+
|
|
1233
|
+
.session-project-header .sp-arrow {
|
|
1234
|
+
width: 12px;
|
|
1235
|
+
font-size: 8px;
|
|
1236
|
+
color: var(--text-muted);
|
|
1237
|
+
text-align: center;
|
|
1238
|
+
flex-shrink: 0;
|
|
1239
|
+
transition: transform 0.15s;
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
.session-project-header .sp-arrow.open { transform: rotate(90deg); }
|
|
1243
|
+
|
|
1244
|
+
.session-project-header .sp-icon {
|
|
1245
|
+
font-size: 11px;
|
|
1246
|
+
color: var(--neon-green);
|
|
1247
|
+
flex-shrink: 0;
|
|
1248
|
+
opacity: 0.7;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
.session-project-header .sp-name {
|
|
1252
|
+
font-size: 12px;
|
|
1253
|
+
color: var(--text-primary);
|
|
1254
|
+
font-weight: 500;
|
|
1255
|
+
flex: 1;
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
.session-project-header .sp-count {
|
|
1259
|
+
font-family: var(--font-mono);
|
|
1260
|
+
font-size: 9px;
|
|
1261
|
+
color: var(--text-muted);
|
|
1262
|
+
background: rgba(91,185,140,0.06);
|
|
1263
|
+
padding: 1px 5px;
|
|
1264
|
+
border-radius: 3px;
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
.session-project-header .sp-add {
|
|
1268
|
+
background: transparent;
|
|
1269
|
+
border: 1px solid var(--border);
|
|
1270
|
+
color: var(--text-muted);
|
|
1271
|
+
font-family: var(--font-mono);
|
|
1272
|
+
font-size: 11px;
|
|
1273
|
+
width: 16px;
|
|
1274
|
+
height: 16px;
|
|
1275
|
+
border-radius: 3px;
|
|
1276
|
+
cursor: pointer;
|
|
1277
|
+
display: none;
|
|
1278
|
+
align-items: center;
|
|
1279
|
+
justify-content: center;
|
|
1280
|
+
transition: all 0.15s;
|
|
1281
|
+
padding: 0;
|
|
1282
|
+
line-height: 1;
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
.session-project-header:hover .sp-add { display: flex; }
|
|
1286
|
+
.session-project-header .sp-add:hover { border-color: var(--neon-green); color: var(--neon-green); }
|
|
1287
|
+
|
|
1288
|
+
.session-list {
|
|
1289
|
+
padding-left: 12px;
|
|
1290
|
+
overflow: hidden;
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
.session-list.collapsed { display: none; }
|
|
1294
|
+
|
|
1295
|
+
.session-item {
|
|
1296
|
+
display: flex;
|
|
1297
|
+
align-items: center;
|
|
1298
|
+
padding: 3px 10px;
|
|
1299
|
+
border-radius: var(--radius-sm);
|
|
1300
|
+
cursor: pointer;
|
|
1301
|
+
font-size: 11px;
|
|
1302
|
+
gap: 6px;
|
|
1303
|
+
user-select: none;
|
|
1304
|
+
transition: background 0.1s;
|
|
1305
|
+
position: relative;
|
|
1306
|
+
margin: 1px 0;
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
.session-item:hover { background: var(--bg-hover); }
|
|
1310
|
+
|
|
1311
|
+
.session-item.active {
|
|
1312
|
+
background: rgba(91,185,140,0.05);
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
.session-item.active::before {
|
|
1316
|
+
content: '';
|
|
1317
|
+
position: absolute;
|
|
1318
|
+
left: 0;
|
|
1319
|
+
top: 3px;
|
|
1320
|
+
bottom: 3px;
|
|
1321
|
+
width: 2px;
|
|
1322
|
+
background: var(--neon-green);
|
|
1323
|
+
border-radius: 1px;
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
.session-item .si-icon {
|
|
1327
|
+
font-size: 9px;
|
|
1328
|
+
color: var(--neon-green);
|
|
1329
|
+
opacity: 0.5;
|
|
1330
|
+
flex-shrink: 0;
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
.session-item .si-time {
|
|
1334
|
+
font-family: var(--font-mono);
|
|
1335
|
+
font-size: 10px;
|
|
1336
|
+
color: var(--text-secondary);
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
.session-item.active .si-time { color: var(--neon-green); }
|
|
1340
|
+
|
|
1341
|
+
.session-badge {
|
|
1342
|
+
display: inline-flex;
|
|
864
1343
|
align-items: center;
|
|
865
|
-
padding: 5px 8px;
|
|
866
|
-
border-radius: var(--radius-sm);
|
|
867
|
-
cursor: pointer;
|
|
868
|
-
font-size: 11px;
|
|
869
1344
|
gap: 8px;
|
|
870
|
-
|
|
871
|
-
|
|
1345
|
+
font-family: var(--font-mono);
|
|
1346
|
+
font-size: 10px;
|
|
1347
|
+
color: var(--neon-green);
|
|
1348
|
+
background: rgba(91,185,140,0.08);
|
|
1349
|
+
border: 1px solid rgba(91,185,140,0.15);
|
|
1350
|
+
padding: 4px 12px;
|
|
1351
|
+
border-radius: var(--radius);
|
|
1352
|
+
margin-bottom: 16px;
|
|
1353
|
+
letter-spacing: 0.5px;
|
|
872
1354
|
}
|
|
873
1355
|
|
|
874
|
-
.
|
|
875
|
-
|
|
876
|
-
.rp-item .rp-score {
|
|
1356
|
+
.session-empty {
|
|
1357
|
+
padding: 12px 18px;
|
|
877
1358
|
font-family: var(--font-mono);
|
|
878
1359
|
font-size: 10px;
|
|
879
|
-
color: var(--
|
|
880
|
-
|
|
881
|
-
opacity: 0.8;
|
|
1360
|
+
color: var(--text-muted);
|
|
1361
|
+
text-align: center;
|
|
882
1362
|
}
|
|
883
1363
|
|
|
884
|
-
.
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
1364
|
+
.session-create-overlay {
|
|
1365
|
+
position: fixed;
|
|
1366
|
+
inset: 0;
|
|
1367
|
+
background: rgba(6,6,12,0.6);
|
|
1368
|
+
z-index: 200;
|
|
1369
|
+
display: none;
|
|
1370
|
+
align-items: center;
|
|
1371
|
+
justify-content: center;
|
|
1372
|
+
backdrop-filter: blur(12px);
|
|
1373
|
+
-webkit-backdrop-filter: blur(12px);
|
|
890
1374
|
}
|
|
891
1375
|
|
|
892
|
-
.
|
|
1376
|
+
.session-create-overlay.active { display: flex; }
|
|
893
1377
|
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
border-radius: var(--radius-
|
|
899
|
-
|
|
900
|
-
font-size: 11px;
|
|
901
|
-
color: var(--text-secondary);
|
|
902
|
-
transition: all 0.1s;
|
|
1378
|
+
.session-create-modal {
|
|
1379
|
+
width: 420px;
|
|
1380
|
+
background: rgba(17,17,22,0.85);
|
|
1381
|
+
border: 1px solid var(--border);
|
|
1382
|
+
border-radius: var(--radius-lg);
|
|
1383
|
+
box-shadow: 0 24px 64px rgba(0,0,0,0.8), 0 0 0 1px rgba(91,185,140,0.1);
|
|
903
1384
|
overflow: hidden;
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
margin-bottom: 1px;
|
|
1385
|
+
backdrop-filter: blur(20px);
|
|
1386
|
+
-webkit-backdrop-filter: blur(20px);
|
|
907
1387
|
}
|
|
908
1388
|
|
|
909
|
-
.
|
|
910
|
-
|
|
911
|
-
|
|
1389
|
+
.session-create-header {
|
|
1390
|
+
padding: 16px 20px 12px;
|
|
1391
|
+
border-bottom: 1px solid var(--border);
|
|
1392
|
+
font-family: var(--font-mono);
|
|
1393
|
+
font-size: 11px;
|
|
1394
|
+
font-weight: 600;
|
|
1395
|
+
color: var(--text-secondary);
|
|
1396
|
+
letter-spacing: 0.5px;
|
|
912
1397
|
}
|
|
913
1398
|
|
|
914
|
-
.
|
|
915
|
-
|
|
1399
|
+
.session-create-body {
|
|
1400
|
+
padding: 16px 20px;
|
|
1401
|
+
display: flex;
|
|
1402
|
+
flex-direction: column;
|
|
1403
|
+
gap: 12px;
|
|
1404
|
+
}
|
|
916
1405
|
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
1406
|
+
.session-field label {
|
|
1407
|
+
display: block;
|
|
1408
|
+
font-family: var(--font-mono);
|
|
1409
|
+
font-size: 9px;
|
|
1410
|
+
font-weight: 600;
|
|
1411
|
+
text-transform: uppercase;
|
|
1412
|
+
letter-spacing: 1px;
|
|
1413
|
+
color: var(--text-muted);
|
|
1414
|
+
margin-bottom: 4px;
|
|
1415
|
+
}
|
|
920
1416
|
|
|
921
|
-
|
|
1417
|
+
.session-field select,
|
|
1418
|
+
.session-field input,
|
|
1419
|
+
.session-field textarea {
|
|
922
1420
|
width: 100%;
|
|
923
|
-
|
|
924
|
-
border: 1px solid var(--border
|
|
1421
|
+
background: rgba(8,8,10,0.5);
|
|
1422
|
+
border: 1px solid var(--border);
|
|
1423
|
+
color: var(--text-primary);
|
|
1424
|
+
font-family: var(--font-mono);
|
|
1425
|
+
font-size: 12px;
|
|
1426
|
+
padding: 8px 12px;
|
|
925
1427
|
border-radius: var(--radius);
|
|
926
|
-
|
|
927
|
-
|
|
1428
|
+
outline: none;
|
|
1429
|
+
transition: all 0.2s;
|
|
928
1430
|
}
|
|
929
1431
|
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
.
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
filter: drop-shadow(0 0 2px rgba(168,139,250,0.4));
|
|
937
|
-
transition: all 0.2s;
|
|
1432
|
+
.session-field select:focus,
|
|
1433
|
+
.session-field input:focus,
|
|
1434
|
+
.session-field textarea:focus {
|
|
1435
|
+
border-color: rgba(91,185,140,0.4);
|
|
1436
|
+
box-shadow: 0 0 8px rgba(91,185,140,0.1);
|
|
1437
|
+
background: var(--bg-surface);
|
|
938
1438
|
}
|
|
939
1439
|
|
|
940
|
-
.
|
|
941
|
-
|
|
942
|
-
|
|
1440
|
+
.session-field textarea {
|
|
1441
|
+
min-height: 60px;
|
|
1442
|
+
resize: vertical;
|
|
943
1443
|
}
|
|
944
1444
|
|
|
945
|
-
.
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
1445
|
+
.session-create-footer {
|
|
1446
|
+
padding: 12px 20px;
|
|
1447
|
+
border-top: 1px solid var(--border);
|
|
1448
|
+
display: flex;
|
|
1449
|
+
justify-content: flex-end;
|
|
1450
|
+
gap: 8px;
|
|
949
1451
|
}
|
|
950
1452
|
|
|
951
|
-
.
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
1453
|
+
.session-create-footer .edit-btn.create {
|
|
1454
|
+
background: rgba(91,185,140,0.1);
|
|
1455
|
+
color: var(--neon-green);
|
|
1456
|
+
border-color: rgba(91,185,140,0.3);
|
|
955
1457
|
}
|
|
956
1458
|
|
|
957
|
-
.
|
|
958
|
-
|
|
959
|
-
|
|
1459
|
+
.session-create-footer .edit-btn.create:hover {
|
|
1460
|
+
background: rgba(91,185,140,0.2);
|
|
1461
|
+
box-shadow: 0 0 10px rgba(91,185,140,0.15);
|
|
1462
|
+
transform: translateY(-1px);
|
|
960
1463
|
}
|
|
961
1464
|
|
|
962
1465
|
/* ============ SCROLLBAR ============ */
|
|
963
|
-
::-webkit-scrollbar { width:
|
|
1466
|
+
::-webkit-scrollbar { width: 5px; height: 5px; }
|
|
964
1467
|
::-webkit-scrollbar-track { background: transparent; }
|
|
965
|
-
::-webkit-scrollbar-thumb { background:
|
|
966
|
-
::-webkit-scrollbar-thumb:hover { background:
|
|
1468
|
+
::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.08); border-radius: 4px; }
|
|
1469
|
+
::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.15); }
|
|
967
1470
|
|
|
968
1471
|
/* ============ EDIT MODAL ============ */
|
|
969
1472
|
.edit-overlay {
|
|
970
1473
|
position: fixed;
|
|
971
1474
|
inset: 0;
|
|
972
|
-
background: rgba(6,6,12,0.
|
|
1475
|
+
background: rgba(6,6,12,0.6);
|
|
973
1476
|
z-index: 200;
|
|
974
1477
|
display: none;
|
|
975
1478
|
align-items: center;
|
|
976
1479
|
justify-content: center;
|
|
977
|
-
backdrop-filter: blur(
|
|
1480
|
+
backdrop-filter: blur(12px);
|
|
1481
|
+
-webkit-backdrop-filter: blur(12px);
|
|
978
1482
|
}
|
|
979
1483
|
|
|
980
1484
|
.edit-overlay.active { display: flex; }
|
|
@@ -982,13 +1486,15 @@ body.resizing .resize-handle { pointer-events: auto !important; }
|
|
|
982
1486
|
.edit-modal {
|
|
983
1487
|
width: 640px;
|
|
984
1488
|
max-height: 80vh;
|
|
985
|
-
background:
|
|
1489
|
+
background: rgba(17,17,22,0.85);
|
|
986
1490
|
border: 1px solid var(--border);
|
|
987
1491
|
border-radius: var(--radius-lg);
|
|
988
|
-
box-shadow: 0
|
|
1492
|
+
box-shadow: 0 24px 64px rgba(0,0,0,0.8), 0 0 0 1px rgba(217,119,87,0.1);
|
|
989
1493
|
display: flex;
|
|
990
1494
|
flex-direction: column;
|
|
991
1495
|
overflow: hidden;
|
|
1496
|
+
backdrop-filter: blur(20px);
|
|
1497
|
+
-webkit-backdrop-filter: blur(20px);
|
|
992
1498
|
}
|
|
993
1499
|
|
|
994
1500
|
.edit-header {
|
|
@@ -996,7 +1502,7 @@ body.resizing .resize-handle { pointer-events: auto !important; }
|
|
|
996
1502
|
align-items: center;
|
|
997
1503
|
justify-content: space-between;
|
|
998
1504
|
padding: 12px 16px;
|
|
999
|
-
border-bottom: 1px solid var(--border
|
|
1505
|
+
border-bottom: 1px solid var(--border);
|
|
1000
1506
|
font-family: var(--font-mono);
|
|
1001
1507
|
font-size: 11px;
|
|
1002
1508
|
color: var(--text-secondary);
|
|
@@ -1013,7 +1519,7 @@ body.resizing .resize-handle { pointer-events: auto !important; }
|
|
|
1013
1519
|
border-radius: var(--radius);
|
|
1014
1520
|
border: 1px solid var(--border);
|
|
1015
1521
|
cursor: pointer;
|
|
1016
|
-
transition: all 0.
|
|
1522
|
+
transition: all 0.2s ease-out;
|
|
1017
1523
|
letter-spacing: 0.5px;
|
|
1018
1524
|
}
|
|
1019
1525
|
|
|
@@ -1022,25 +1528,25 @@ body.resizing .resize-handle { pointer-events: auto !important; }
|
|
|
1022
1528
|
color: var(--text-muted);
|
|
1023
1529
|
}
|
|
1024
1530
|
|
|
1025
|
-
.edit-btn.cancel:hover { color: var(--text-secondary); border-color: var(--text-muted); }
|
|
1531
|
+
.edit-btn.cancel:hover { color: var(--text-secondary); border-color: var(--text-muted); transform: translateY(-1px); }
|
|
1026
1532
|
|
|
1027
1533
|
.edit-btn.save {
|
|
1028
|
-
background: rgba(
|
|
1534
|
+
background: rgba(217,119,87,0.1);
|
|
1029
1535
|
color: var(--neon-cyan);
|
|
1030
|
-
border-color: rgba(
|
|
1536
|
+
border-color: rgba(217,119,87,0.3);
|
|
1031
1537
|
}
|
|
1032
1538
|
|
|
1033
|
-
.edit-btn.save:hover { background: rgba(
|
|
1539
|
+
.edit-btn.save:hover { background: rgba(217,119,87,0.2); box-shadow: 0 0 10px rgba(217,119,87,0.15); transform: translateY(-1px); }
|
|
1034
1540
|
|
|
1035
1541
|
.edit-textarea {
|
|
1036
1542
|
flex: 1;
|
|
1037
1543
|
min-height: 300px;
|
|
1038
|
-
background:
|
|
1544
|
+
background: rgba(8,8,10,0.3);
|
|
1039
1545
|
border: none;
|
|
1040
1546
|
color: var(--text-primary);
|
|
1041
1547
|
font-family: var(--font-mono);
|
|
1042
1548
|
font-size: 13px;
|
|
1043
|
-
line-height: 1.
|
|
1549
|
+
line-height: 1.8;
|
|
1044
1550
|
padding: 16px 20px;
|
|
1045
1551
|
resize: none;
|
|
1046
1552
|
outline: none;
|
|
@@ -1112,6 +1618,9 @@ body.resizing .resize-handle { pointer-events: auto !important; }
|
|
|
1112
1618
|
<span class="dot"></span>
|
|
1113
1619
|
<span>GRAPH</span>
|
|
1114
1620
|
</button>
|
|
1621
|
+
<button class="header-btn" id="new-project-btn" title="New project">
|
|
1622
|
+
<span>+ PROJECT</span>
|
|
1623
|
+
</button>
|
|
1115
1624
|
<div class="search-box">
|
|
1116
1625
|
<span class="search-icon">⚲</span>
|
|
1117
1626
|
<input type="text" id="search-input" placeholder="Search...">
|
|
@@ -1124,8 +1633,26 @@ body.resizing .resize-handle { pointer-events: auto !important; }
|
|
|
1124
1633
|
<!-- Left sidebar -->
|
|
1125
1634
|
<div class="sidebar">
|
|
1126
1635
|
<div class="sidebar-scroll">
|
|
1636
|
+
<!-- SESSIONS PILLAR (Claude-Mem) -->
|
|
1637
|
+
<div class="pillar-label">
|
|
1638
|
+
<span><span class="pillar-accent sessions"></span>SESSIONS</span>
|
|
1639
|
+
<span class="pillar-action" id="new-session-btn">+ NEW</span>
|
|
1640
|
+
</div>
|
|
1641
|
+
<div class="session-search-box">
|
|
1642
|
+
<span class="ss-icon">⚲</span>
|
|
1643
|
+
<input type="text" id="session-search-input" placeholder="Semantic search sessions...">
|
|
1644
|
+
</div>
|
|
1645
|
+
<div class="session-search-results" id="session-search-results"></div>
|
|
1646
|
+
<div id="session-tree"></div>
|
|
1647
|
+
|
|
1648
|
+
<div class="pillar-divider"></div>
|
|
1649
|
+
|
|
1650
|
+
<!-- PROJECTS PILLAR (Obsidian) -->
|
|
1651
|
+
<div class="pillar-label">
|
|
1652
|
+
<span><span class="pillar-accent projects"></span>PROJECTS</span>
|
|
1653
|
+
<span class="pillar-action" id="new-project-sidebar-btn">+ NEW</span>
|
|
1654
|
+
</div>
|
|
1127
1655
|
<div class="sidebar-section">
|
|
1128
|
-
<div class="section-label">Explorer</div>
|
|
1129
1656
|
<div id="filter-info" class="filter-info" style="display:none;">
|
|
1130
1657
|
<span id="filter-count"></span>
|
|
1131
1658
|
<span class="clear-btn" id="clear-filters">clear</span>
|
|
@@ -1164,28 +1691,29 @@ body.resizing .resize-handle { pointer-events: auto !important; }
|
|
|
1164
1691
|
<!-- Right panel -->
|
|
1165
1692
|
<div class="right-panel" id="right-panel">
|
|
1166
1693
|
<div id="graph-section">
|
|
1167
|
-
<div class="rp-section-title">Local Graph
|
|
1694
|
+
<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><button class="graph-size-btn" id="graph-max" title="Maximize graph">⛶</button></span></div>
|
|
1168
1695
|
<div id="graph-container"></div>
|
|
1696
|
+
<div id="graph-resize-handle" class="graph-resize-handle"></div>
|
|
1169
1697
|
</div>
|
|
1170
1698
|
<div id="rp-outline" class="rp-section" style="display:none;">
|
|
1171
|
-
<div class="rp-section-title">Outline <span class="rp-count" id="outline-count"></span></div>
|
|
1172
|
-
<div id="rp-outline-list"></div>
|
|
1699
|
+
<div class="rp-section-title" onclick="this.parentElement.classList.toggle('collapsed')">Outline <span class="rp-count" id="outline-count"></span><span class="arrow">▶</span></div>
|
|
1700
|
+
<div id="rp-outline-list" class="rp-section-body"></div>
|
|
1173
1701
|
</div>
|
|
1174
1702
|
<div id="rp-backlinks" class="rp-section" style="display:none;">
|
|
1175
|
-
<div class="rp-section-title">Backlinks <span class="rp-count" id="bl-count"></span></div>
|
|
1176
|
-
<div id="rp-backlinks-list"></div>
|
|
1703
|
+
<div class="rp-section-title" onclick="this.parentElement.classList.toggle('collapsed')">Backlinks <span class="rp-count" id="bl-count"></span><span class="arrow">▶</span></div>
|
|
1704
|
+
<div id="rp-backlinks-list" class="rp-section-body"></div>
|
|
1177
1705
|
</div>
|
|
1178
1706
|
<div id="rp-related" class="rp-section" style="display:none;">
|
|
1179
|
-
<div class="rp-section-title">Related <span class="rp-count" id="rel-count"></span></div>
|
|
1180
|
-
<div id="rp-related-list"></div>
|
|
1707
|
+
<div class="rp-section-title" onclick="this.parentElement.classList.toggle('collapsed')">Related <span class="rp-count" id="rel-count"></span><span class="arrow">▶</span></div>
|
|
1708
|
+
<div id="rp-related-list" class="rp-section-body"></div>
|
|
1181
1709
|
</div>
|
|
1182
1710
|
<div id="rp-outlinks" class="rp-section" style="display:none;">
|
|
1183
|
-
<div class="rp-section-title">Outgoing Links <span class="rp-count" id="out-count"></span></div>
|
|
1184
|
-
<div id="rp-outlinks-list"></div>
|
|
1711
|
+
<div class="rp-section-title" onclick="this.parentElement.classList.toggle('collapsed')">Outgoing Links <span class="rp-count" id="out-count"></span><span class="arrow">▶</span></div>
|
|
1712
|
+
<div id="rp-outlinks-list" class="rp-section-body"></div>
|
|
1185
1713
|
</div>
|
|
1186
1714
|
<div id="rp-unlinked" class="rp-section" style="display:none;">
|
|
1187
|
-
<div class="rp-section-title">Unlinked Mentions <span class="rp-count" id="unlinked-count"></span></div>
|
|
1188
|
-
<div id="rp-unlinked-list"></div>
|
|
1715
|
+
<div class="rp-section-title" onclick="this.parentElement.classList.toggle('collapsed')">Unlinked Mentions <span class="rp-count" id="unlinked-count"></span><span class="arrow">▶</span></div>
|
|
1716
|
+
<div id="rp-unlinked-list" class="rp-section-body"></div>
|
|
1189
1717
|
</div>
|
|
1190
1718
|
</div>
|
|
1191
1719
|
</div>
|
|
@@ -1212,11 +1740,55 @@ body.resizing .resize-handle { pointer-events: auto !important; }
|
|
|
1212
1740
|
</div>
|
|
1213
1741
|
</div>
|
|
1214
1742
|
|
|
1743
|
+
<!-- Session Create Modal -->
|
|
1744
|
+
<div class="session-create-overlay" id="session-create-overlay">
|
|
1745
|
+
<div class="session-create-modal">
|
|
1746
|
+
<div class="session-create-header">NEW SESSION</div>
|
|
1747
|
+
<div class="session-create-body">
|
|
1748
|
+
<div class="session-field">
|
|
1749
|
+
<label>Project</label>
|
|
1750
|
+
<input type="text" id="session-project" list="project-list" placeholder="Project name...">
|
|
1751
|
+
<datalist id="project-list"></datalist>
|
|
1752
|
+
</div>
|
|
1753
|
+
<div class="session-field">
|
|
1754
|
+
<label>Summary</label>
|
|
1755
|
+
<textarea id="session-summary" placeholder="What are you working on?"></textarea>
|
|
1756
|
+
</div>
|
|
1757
|
+
</div>
|
|
1758
|
+
<div class="session-create-footer">
|
|
1759
|
+
<button class="edit-btn cancel" id="session-cancel">CANCEL</button>
|
|
1760
|
+
<button class="edit-btn create" id="session-create-btn">CREATE</button>
|
|
1761
|
+
</div>
|
|
1762
|
+
</div>
|
|
1763
|
+
</div>
|
|
1764
|
+
|
|
1765
|
+
<!-- Project Create Modal -->
|
|
1766
|
+
<div class="session-create-overlay" id="project-create-overlay">
|
|
1767
|
+
<div class="session-create-modal">
|
|
1768
|
+
<div class="session-create-header">NEW PROJECT</div>
|
|
1769
|
+
<div class="session-create-body">
|
|
1770
|
+
<div class="session-field">
|
|
1771
|
+
<label>Project Name</label>
|
|
1772
|
+
<input type="text" id="project-name-input" placeholder="My Project...">
|
|
1773
|
+
</div>
|
|
1774
|
+
<div class="session-field">
|
|
1775
|
+
<label>Overview (optional)</label>
|
|
1776
|
+
<textarea id="project-overview-input" placeholder="Brief project description, goals, tech stack..."></textarea>
|
|
1777
|
+
</div>
|
|
1778
|
+
</div>
|
|
1779
|
+
<div class="session-create-footer">
|
|
1780
|
+
<button class="edit-btn cancel" id="project-cancel">CANCEL</button>
|
|
1781
|
+
<button class="edit-btn create" id="project-create-btn">CREATE</button>
|
|
1782
|
+
</div>
|
|
1783
|
+
</div>
|
|
1784
|
+
</div>
|
|
1785
|
+
|
|
1215
1786
|
<script>
|
|
1216
1787
|
let currentPath = null;
|
|
1217
1788
|
let treeData = null;
|
|
1218
1789
|
let allNotes = {};
|
|
1219
1790
|
let graphVisible = true;
|
|
1791
|
+
let currentNote = null;
|
|
1220
1792
|
let activeTagFilters = new Set();
|
|
1221
1793
|
let qsSelectedIndex = 0;
|
|
1222
1794
|
|
|
@@ -1255,6 +1827,8 @@ document.addEventListener('keydown', (e) => {
|
|
|
1255
1827
|
}
|
|
1256
1828
|
if (e.key === 'Escape') {
|
|
1257
1829
|
closeQuickSwitcher();
|
|
1830
|
+
closeSessionCreate();
|
|
1831
|
+
closeProjectCreate();
|
|
1258
1832
|
}
|
|
1259
1833
|
});
|
|
1260
1834
|
|
|
@@ -1350,9 +1924,11 @@ function updateQsSelection() {
|
|
|
1350
1924
|
});
|
|
1351
1925
|
}
|
|
1352
1926
|
|
|
1353
|
-
// --- File Tree ---
|
|
1927
|
+
// --- File Tree (Projects pillar only — no Sessions folders) ---
|
|
1354
1928
|
function renderTree(node, container) {
|
|
1355
1929
|
if (node.type === 'folder' && node.name !== 'vault') {
|
|
1930
|
+
if (node.name === 'Sessions') return;
|
|
1931
|
+
|
|
1356
1932
|
const item = document.createElement('div');
|
|
1357
1933
|
item.className = 'tree-item';
|
|
1358
1934
|
item.innerHTML = `<span class="arrow open">▶</span><span class="icon folder-icon">☰</span><span class="name">${node.name}</span>`;
|
|
@@ -1374,7 +1950,8 @@ function renderTree(node, container) {
|
|
|
1374
1950
|
const item = document.createElement('div');
|
|
1375
1951
|
item.className = 'tree-item';
|
|
1376
1952
|
item.dataset.path = node.path;
|
|
1377
|
-
|
|
1953
|
+
const displayName = node.name.replace('.md', '');
|
|
1954
|
+
item.innerHTML = `<span class="arrow" style="visibility:hidden">▶</span><span class="icon note-icon">◇</span><span class="name">${displayName}</span>`;
|
|
1378
1955
|
item.addEventListener('click', () => loadNote(node.path));
|
|
1379
1956
|
container.appendChild(item);
|
|
1380
1957
|
|
|
@@ -1383,13 +1960,118 @@ function renderTree(node, container) {
|
|
|
1383
1960
|
}
|
|
1384
1961
|
}
|
|
1385
1962
|
|
|
1963
|
+
// --- Session Tree (Sessions pillar — grouped by project with dropdowns) ---
|
|
1964
|
+
function formatSessionTimestamp(filename) {
|
|
1965
|
+
const stem = filename.replace('.md', '');
|
|
1966
|
+
const match = stem.match(/^(\d{4})-(\d{2})-(\d{2})_(\d{2})(\d{2})(\d{2})$/);
|
|
1967
|
+
if (!match) return stem;
|
|
1968
|
+
const [, y, mo, d, h, mi] = match;
|
|
1969
|
+
const hr = parseInt(h);
|
|
1970
|
+
const ampm = hr >= 12 ? 'PM' : 'AM';
|
|
1971
|
+
const hr12 = hr % 12 || 12;
|
|
1972
|
+
const months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
|
|
1973
|
+
return `${months[parseInt(mo)-1]} ${parseInt(d)}, ${hr12}:${mi} ${ampm}`;
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
function renderSessionTree(sessionsData) {
|
|
1977
|
+
const container = document.getElementById('session-tree');
|
|
1978
|
+
container.innerHTML = '';
|
|
1979
|
+
|
|
1980
|
+
if (Object.keys(sessionsData).length === 0) {
|
|
1981
|
+
container.innerHTML = '<div class="session-empty">No sessions yet</div>';
|
|
1982
|
+
return;
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
const sortedProjects = Object.keys(sessionsData).sort();
|
|
1986
|
+
sortedProjects.forEach(project => {
|
|
1987
|
+
const sessions = sessionsData[project];
|
|
1988
|
+
const group = document.createElement('div');
|
|
1989
|
+
group.className = 'session-project-group';
|
|
1990
|
+
|
|
1991
|
+
const header = document.createElement('div');
|
|
1992
|
+
header.className = 'session-project-header';
|
|
1993
|
+
header.innerHTML = `
|
|
1994
|
+
<span class="sp-arrow open">▶</span>
|
|
1995
|
+
<span class="sp-icon">◴</span>
|
|
1996
|
+
<span class="sp-name">${project}</span>
|
|
1997
|
+
<span class="sp-count">${sessions.length}</span>
|
|
1998
|
+
<button class="sp-add" title="New session for ${project}">+</button>
|
|
1999
|
+
`;
|
|
2000
|
+
|
|
2001
|
+
const list = document.createElement('div');
|
|
2002
|
+
list.className = 'session-list';
|
|
2003
|
+
|
|
2004
|
+
sessions.sort((a, b) => b.path.localeCompare(a.path));
|
|
2005
|
+
sessions.forEach(session => {
|
|
2006
|
+
const item = document.createElement('div');
|
|
2007
|
+
item.className = 'session-item';
|
|
2008
|
+
item.dataset.path = session.path;
|
|
2009
|
+
const displayTime = formatSessionTimestamp(session.path.split('/').pop());
|
|
2010
|
+
item.innerHTML = `<span class="si-icon">●</span><span class="si-time">${displayTime}</span>`;
|
|
2011
|
+
item.title = session.title || session.path;
|
|
2012
|
+
item.addEventListener('click', () => loadNote(session.path));
|
|
2013
|
+
list.appendChild(item);
|
|
2014
|
+
});
|
|
2015
|
+
|
|
2016
|
+
header.addEventListener('click', (e) => {
|
|
2017
|
+
if (e.target.classList.contains('sp-add')) {
|
|
2018
|
+
e.stopPropagation();
|
|
2019
|
+
openSessionCreate(project);
|
|
2020
|
+
return;
|
|
2021
|
+
}
|
|
2022
|
+
e.stopPropagation();
|
|
2023
|
+
header.querySelector('.sp-arrow').classList.toggle('open');
|
|
2024
|
+
list.classList.toggle('collapsed');
|
|
2025
|
+
});
|
|
2026
|
+
|
|
2027
|
+
group.appendChild(header);
|
|
2028
|
+
group.appendChild(list);
|
|
2029
|
+
container.appendChild(group);
|
|
2030
|
+
});
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
// --- Session Semantic Search ---
|
|
2034
|
+
let sessionSearchTimeout;
|
|
2035
|
+
const sessionSearchInput = document.getElementById('session-search-input');
|
|
2036
|
+
const sessionSearchResults = document.getElementById('session-search-results');
|
|
2037
|
+
|
|
2038
|
+
sessionSearchInput.addEventListener('input', () => {
|
|
2039
|
+
clearTimeout(sessionSearchTimeout);
|
|
2040
|
+
const q = sessionSearchInput.value.trim();
|
|
2041
|
+
if (!q) { sessionSearchResults.innerHTML = ''; return; }
|
|
2042
|
+
sessionSearchTimeout = setTimeout(async () => {
|
|
2043
|
+
const results = await fetchJSON(`/api/sessions/search?q=${encodeURIComponent(q)}`);
|
|
2044
|
+
sessionSearchResults.innerHTML = '';
|
|
2045
|
+
if (results.length === 0) {
|
|
2046
|
+
sessionSearchResults.innerHTML = '<div class="ss-result"><span class="ss-meta">No matching sessions</span></div>';
|
|
2047
|
+
return;
|
|
2048
|
+
}
|
|
2049
|
+
results.forEach(r => {
|
|
2050
|
+
const div = document.createElement('div');
|
|
2051
|
+
div.className = 'ss-result';
|
|
2052
|
+
const dist = r.distance !== undefined ? ` · dist: ${r.distance.toFixed(2)}` : '';
|
|
2053
|
+
div.innerHTML = `<div class="ss-title">${r.title}</div><div class="ss-meta">${r.path}${dist}</div>${r.snippet ? `<div class="ss-snippet">${r.snippet.substring(0, 120)}</div>` : ''}`;
|
|
2054
|
+
div.addEventListener('click', () => {
|
|
2055
|
+
loadNote(r.path);
|
|
2056
|
+
sessionSearchInput.value = '';
|
|
2057
|
+
sessionSearchResults.innerHTML = '';
|
|
2058
|
+
});
|
|
2059
|
+
sessionSearchResults.appendChild(div);
|
|
2060
|
+
});
|
|
2061
|
+
}, 250);
|
|
2062
|
+
});
|
|
2063
|
+
|
|
1386
2064
|
// --- Note rendering ---
|
|
1387
2065
|
async function loadNote(path) {
|
|
1388
2066
|
currentPath = path;
|
|
1389
2067
|
const note = await fetchJSON(`/api/note/${path}`);
|
|
1390
2068
|
if (note.error) return;
|
|
2069
|
+
currentNote = note;
|
|
1391
2070
|
|
|
1392
|
-
document.querySelectorAll('.tree-item').forEach(el => {
|
|
2071
|
+
document.querySelectorAll('.tree-item[data-path]').forEach(el => {
|
|
2072
|
+
el.classList.toggle('active', el.dataset.path === path);
|
|
2073
|
+
});
|
|
2074
|
+
document.querySelectorAll('.session-item[data-path]').forEach(el => {
|
|
1393
2075
|
el.classList.toggle('active', el.dataset.path === path);
|
|
1394
2076
|
});
|
|
1395
2077
|
|
|
@@ -1404,6 +2086,13 @@ async function loadNote(path) {
|
|
|
1404
2086
|
let html = '<div class="fade-in">';
|
|
1405
2087
|
|
|
1406
2088
|
html += `<button class="note-edit-btn" onclick="openEditor('${path}')">EDIT</button>`;
|
|
2089
|
+
|
|
2090
|
+
const isSession = path.includes('/Sessions/') || path.startsWith('Sessions/');
|
|
2091
|
+
if (isSession) {
|
|
2092
|
+
const sessionProject = path.includes('/Sessions/') ? path.split('/Sessions/')[0] : 'General';
|
|
2093
|
+
html += `<div class="session-badge">◴ SESSION · ${sessionProject}</div>`;
|
|
2094
|
+
}
|
|
2095
|
+
|
|
1407
2096
|
html += '<div class="note-properties">';
|
|
1408
2097
|
(note.tags || []).forEach(t => { html += `<span class="tag clickable-tag" data-tag="${t}">#${t}</span>`; });
|
|
1409
2098
|
Object.entries(note.properties || {}).forEach(([k, v]) => {
|
|
@@ -1619,6 +2308,156 @@ document.addEventListener('keydown', (e) => {
|
|
|
1619
2308
|
}
|
|
1620
2309
|
});
|
|
1621
2310
|
|
|
2311
|
+
// --- Session Management ---
|
|
2312
|
+
function openSessionCreate(defaultProject) {
|
|
2313
|
+
const overlay = document.getElementById('session-create-overlay');
|
|
2314
|
+
const projectInput = document.getElementById('session-project');
|
|
2315
|
+
const datalist = document.getElementById('project-list');
|
|
2316
|
+
const summaryInput = document.getElementById('session-summary');
|
|
2317
|
+
|
|
2318
|
+
const projects = new Set();
|
|
2319
|
+
for (const path of Object.keys(allNotes)) {
|
|
2320
|
+
const parts = path.split('/');
|
|
2321
|
+
if (parts.length > 1) projects.add(parts[0]);
|
|
2322
|
+
}
|
|
2323
|
+
|
|
2324
|
+
datalist.innerHTML = '';
|
|
2325
|
+
for (const p of [...projects].sort()) {
|
|
2326
|
+
const opt = document.createElement('option');
|
|
2327
|
+
opt.value = p;
|
|
2328
|
+
datalist.appendChild(opt);
|
|
2329
|
+
}
|
|
2330
|
+
|
|
2331
|
+
projectInput.value = defaultProject || '';
|
|
2332
|
+
summaryInput.value = '';
|
|
2333
|
+
overlay.classList.add('active');
|
|
2334
|
+
|
|
2335
|
+
if (defaultProject) summaryInput.focus();
|
|
2336
|
+
else projectInput.focus();
|
|
2337
|
+
}
|
|
2338
|
+
|
|
2339
|
+
function closeSessionCreate() {
|
|
2340
|
+
document.getElementById('session-create-overlay').classList.remove('active');
|
|
2341
|
+
}
|
|
2342
|
+
|
|
2343
|
+
document.getElementById('session-cancel').addEventListener('click', closeSessionCreate);
|
|
2344
|
+
document.getElementById('session-create-overlay').addEventListener('click', (e) => {
|
|
2345
|
+
if (e.target === e.currentTarget) closeSessionCreate();
|
|
2346
|
+
});
|
|
2347
|
+
|
|
2348
|
+
document.getElementById('session-create-btn').addEventListener('click', async () => {
|
|
2349
|
+
const project = document.getElementById('session-project').value.trim();
|
|
2350
|
+
const summary = document.getElementById('session-summary').value.trim();
|
|
2351
|
+
|
|
2352
|
+
if (!project) {
|
|
2353
|
+
document.getElementById('session-project').focus();
|
|
2354
|
+
return;
|
|
2355
|
+
}
|
|
2356
|
+
|
|
2357
|
+
const resp = await fetch('/api/sessions/create', {
|
|
2358
|
+
method: 'POST',
|
|
2359
|
+
headers: { 'Content-Type': 'application/json' },
|
|
2360
|
+
body: JSON.stringify({ project, summary }),
|
|
2361
|
+
});
|
|
2362
|
+
|
|
2363
|
+
const result = await resp.json();
|
|
2364
|
+
if (result.ok) {
|
|
2365
|
+
closeSessionCreate();
|
|
2366
|
+
await refreshTree();
|
|
2367
|
+
loadNote(result.path);
|
|
2368
|
+
}
|
|
2369
|
+
});
|
|
2370
|
+
|
|
2371
|
+
// --- Sidebar pillar buttons ---
|
|
2372
|
+
document.getElementById('new-session-btn').addEventListener('click', () => openSessionCreate(''));
|
|
2373
|
+
|
|
2374
|
+
document.getElementById('new-project-sidebar-btn').addEventListener('click', () => {
|
|
2375
|
+
document.getElementById('project-create-overlay').classList.add('active');
|
|
2376
|
+
document.getElementById('project-name-input').value = '';
|
|
2377
|
+
document.getElementById('project-overview-input').value = '';
|
|
2378
|
+
document.getElementById('project-name-input').focus();
|
|
2379
|
+
});
|
|
2380
|
+
|
|
2381
|
+
// --- Project Management ---
|
|
2382
|
+
function closeProjectCreate() {
|
|
2383
|
+
document.getElementById('project-create-overlay').classList.remove('active');
|
|
2384
|
+
}
|
|
2385
|
+
|
|
2386
|
+
document.getElementById('new-project-btn').addEventListener('click', () => {
|
|
2387
|
+
document.getElementById('project-create-overlay').classList.add('active');
|
|
2388
|
+
document.getElementById('project-name-input').value = '';
|
|
2389
|
+
document.getElementById('project-overview-input').value = '';
|
|
2390
|
+
document.getElementById('project-name-input').focus();
|
|
2391
|
+
});
|
|
2392
|
+
|
|
2393
|
+
document.getElementById('project-cancel').addEventListener('click', closeProjectCreate);
|
|
2394
|
+
document.getElementById('project-create-overlay').addEventListener('click', (e) => {
|
|
2395
|
+
if (e.target === e.currentTarget) closeProjectCreate();
|
|
2396
|
+
});
|
|
2397
|
+
|
|
2398
|
+
document.getElementById('project-create-btn').addEventListener('click', async () => {
|
|
2399
|
+
const name = document.getElementById('project-name-input').value.trim();
|
|
2400
|
+
const overview = document.getElementById('project-overview-input').value.trim();
|
|
2401
|
+
if (!name) {
|
|
2402
|
+
document.getElementById('project-name-input').focus();
|
|
2403
|
+
return;
|
|
2404
|
+
}
|
|
2405
|
+
const resp = await fetch('/api/projects/create', {
|
|
2406
|
+
method: 'POST',
|
|
2407
|
+
headers: { 'Content-Type': 'application/json' },
|
|
2408
|
+
body: JSON.stringify({ name, overview }),
|
|
2409
|
+
});
|
|
2410
|
+
const result = await resp.json();
|
|
2411
|
+
if (result.ok) {
|
|
2412
|
+
closeProjectCreate();
|
|
2413
|
+
await refreshTree();
|
|
2414
|
+
loadNote(result.path);
|
|
2415
|
+
}
|
|
2416
|
+
});
|
|
2417
|
+
|
|
2418
|
+
async function refreshTree() {
|
|
2419
|
+
const [rawTreeData, sessionsData, stats] = await Promise.all([
|
|
2420
|
+
fetchJSON('/api/tree'),
|
|
2421
|
+
fetchJSON('/api/sessions'),
|
|
2422
|
+
fetchJSON('/api/stats'),
|
|
2423
|
+
]);
|
|
2424
|
+
|
|
2425
|
+
allNotes = {};
|
|
2426
|
+
function walk(node) {
|
|
2427
|
+
if (node.type === 'note') {
|
|
2428
|
+
allNotes[node.path] = { title: node.name.replace('.md', ''), tags: node.tags || [] };
|
|
2429
|
+
}
|
|
2430
|
+
(node.children || []).forEach(walk);
|
|
2431
|
+
}
|
|
2432
|
+
walk(rawTreeData);
|
|
2433
|
+
|
|
2434
|
+
const treeEl = document.getElementById('file-tree');
|
|
2435
|
+
treeEl.innerHTML = '';
|
|
2436
|
+
renderTree(rawTreeData, treeEl);
|
|
2437
|
+
|
|
2438
|
+
renderSessionTree(sessionsData);
|
|
2439
|
+
renderTagCloud(collectAllTags());
|
|
2440
|
+
|
|
2441
|
+
document.getElementById('stats-bar').innerHTML = `
|
|
2442
|
+
<span><span class="stat-val">${stats.notes}</span> notes</span>
|
|
2443
|
+
<span><span class="stat-val">${stats.folders}</span> folders</span>
|
|
2444
|
+
<span><span class="stat-val">${stats.tags}</span> tags</span>
|
|
2445
|
+
<span><span class="stat-val">${stats.links}</span> links</span>
|
|
2446
|
+
`;
|
|
2447
|
+
|
|
2448
|
+
markActiveItems();
|
|
2449
|
+
}
|
|
2450
|
+
|
|
2451
|
+
function markActiveItems() {
|
|
2452
|
+
if (!currentPath) return;
|
|
2453
|
+
document.querySelectorAll('.tree-item[data-path]').forEach(el => {
|
|
2454
|
+
el.classList.toggle('active', el.dataset.path === currentPath);
|
|
2455
|
+
});
|
|
2456
|
+
document.querySelectorAll('.session-item[data-path]').forEach(el => {
|
|
2457
|
+
el.classList.toggle('active', el.dataset.path === currentPath);
|
|
2458
|
+
});
|
|
2459
|
+
}
|
|
2460
|
+
|
|
1622
2461
|
// --- Graph ---
|
|
1623
2462
|
function renderGraph(note) {
|
|
1624
2463
|
const container = document.getElementById('graph-container');
|
|
@@ -1627,71 +2466,202 @@ function renderGraph(note) {
|
|
|
1627
2466
|
const nodes = new Map();
|
|
1628
2467
|
const links = [];
|
|
1629
2468
|
|
|
1630
|
-
nodes.set(note.path, { id: note.path, title: note.title, active: true });
|
|
2469
|
+
nodes.set(note.path, { id: note.path, title: note.title, active: true, tags: note.tags || [] });
|
|
2470
|
+
|
|
2471
|
+
const projectPrefix = note.path.includes('/') ? note.path.split('/')[0] + '/' : '';
|
|
2472
|
+
const inSameProject = (p) => !projectPrefix ? !p.includes('/') : p.startsWith(projectPrefix);
|
|
1631
2473
|
|
|
1632
2474
|
(note.links || []).forEach(link => {
|
|
1633
2475
|
const path = findNotePath(link);
|
|
1634
|
-
if (path &&
|
|
1635
|
-
|
|
1636
|
-
|
|
2476
|
+
if (path && inSameProject(path)) {
|
|
2477
|
+
if (!nodes.has(path)) {
|
|
2478
|
+
const n = allNotes[path];
|
|
2479
|
+
nodes.set(path, { id: path, title: n ? n.title : link, active: false, tags: n ? n.tags : [] });
|
|
2480
|
+
}
|
|
2481
|
+
links.push({ source: note.path, target: path });
|
|
1637
2482
|
}
|
|
1638
|
-
if (path) links.push({ source: note.path, target: path });
|
|
1639
2483
|
});
|
|
1640
2484
|
|
|
1641
|
-
(note.backlinks || []).forEach(
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
2485
|
+
(note.backlinks || []).forEach(bl => {
|
|
2486
|
+
const blPath = typeof bl === 'string' ? bl : (bl && bl.path);
|
|
2487
|
+
if (!blPath) return;
|
|
2488
|
+
if (inSameProject(blPath)) {
|
|
2489
|
+
if (!nodes.has(blPath)) {
|
|
2490
|
+
const n = allNotes[blPath];
|
|
2491
|
+
const title = (bl && typeof bl === 'object' && bl.title) ? bl.title : (n ? n.title : blPath);
|
|
2492
|
+
nodes.set(blPath, { id: blPath, title, active: false, tags: n ? n.tags : [] });
|
|
2493
|
+
}
|
|
2494
|
+
links.push({ source: blPath, target: note.path });
|
|
1645
2495
|
}
|
|
1646
|
-
links.push({ source: path, target: note.path });
|
|
1647
2496
|
});
|
|
1648
2497
|
|
|
1649
2498
|
(note.related || []).forEach(r => {
|
|
1650
|
-
if (
|
|
1651
|
-
nodes.
|
|
2499
|
+
if (r.path && inSameProject(r.path)) {
|
|
2500
|
+
if (!nodes.has(r.path)) {
|
|
2501
|
+
const n = allNotes[r.path];
|
|
2502
|
+
nodes.set(r.path, { id: r.path, title: r.title, active: false, tags: n ? n.tags : [] });
|
|
2503
|
+
}
|
|
2504
|
+
links.push({ source: note.path, target: r.path, dashed: true });
|
|
1652
2505
|
}
|
|
1653
2506
|
});
|
|
1654
2507
|
|
|
1655
2508
|
const nodeArray = Array.from(nodes.values());
|
|
2509
|
+
nodeArray.forEach(n => n.degree = 0);
|
|
2510
|
+
links.forEach(l => {
|
|
2511
|
+
const s = nodes.get(l.source);
|
|
2512
|
+
const t = nodes.get(l.target);
|
|
2513
|
+
if (s) s.degree++;
|
|
2514
|
+
if (t) t.degree++;
|
|
2515
|
+
});
|
|
2516
|
+
|
|
1656
2517
|
if (nodeArray.length < 2) {
|
|
1657
|
-
container.innerHTML = '<
|
|
2518
|
+
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>';
|
|
1658
2519
|
return;
|
|
1659
2520
|
}
|
|
1660
2521
|
|
|
1661
|
-
const
|
|
1662
|
-
const
|
|
2522
|
+
const isMaximized = document.getElementById('graph-section').classList.contains('maximized');
|
|
2523
|
+
const width = container.clientWidth || 248;
|
|
2524
|
+
const height = container.clientHeight || 200;
|
|
2525
|
+
const margin = isMaximized ? 60 : 24;
|
|
1663
2526
|
|
|
1664
2527
|
const svg = d3.select(container).append('svg')
|
|
1665
2528
|
.attr('viewBox', `0 0 ${width} ${height}`);
|
|
1666
2529
|
|
|
2530
|
+
const g = svg.append('g');
|
|
2531
|
+
|
|
2532
|
+
svg.call(d3.zoom()
|
|
2533
|
+
.scaleExtent([0.2, 4])
|
|
2534
|
+
.on('zoom', (event) => g.attr('transform', event.transform))
|
|
2535
|
+
);
|
|
2536
|
+
|
|
1667
2537
|
const simulation = d3.forceSimulation(nodeArray)
|
|
1668
|
-
.force('link', d3.forceLink(links).id(d => d.id).distance(
|
|
1669
|
-
.force('charge', d3.forceManyBody().strength(-100))
|
|
2538
|
+
.force('link', d3.forceLink(links).id(d => d.id).distance(isMaximized ? 150 : 80))
|
|
2539
|
+
.force('charge', d3.forceManyBody().strength(d => isMaximized ? -300 - (d.degree * 40) : -100 - (d.degree * 20)))
|
|
1670
2540
|
.force('center', d3.forceCenter(width / 2, height / 2))
|
|
1671
|
-
.force('collision', d3.forceCollide().radius(
|
|
2541
|
+
.force('collision', d3.forceCollide().radius(d => {
|
|
2542
|
+
const textWidth = d.title.length * (isMaximized ? 6 : 4.5);
|
|
2543
|
+
return (isMaximized ? textWidth + 10 : 12) + (d.degree * 2);
|
|
2544
|
+
}));
|
|
1672
2545
|
|
|
1673
|
-
const
|
|
2546
|
+
const linkEl = g.selectAll('.graph-link')
|
|
1674
2547
|
.data(links).enter().append('line')
|
|
1675
|
-
.attr('class', 'graph-link')
|
|
2548
|
+
.attr('class', 'graph-link')
|
|
2549
|
+
.attr('stroke-dasharray', d => d.dashed ? '3,3' : null)
|
|
2550
|
+
.style('opacity', d => d.dashed ? 0.3 : 0.6);
|
|
1676
2551
|
|
|
1677
|
-
const node =
|
|
2552
|
+
const node = g.selectAll('.graph-node')
|
|
1678
2553
|
.data(nodeArray).enter().append('g')
|
|
1679
2554
|
.attr('class', d => 'graph-node' + (d.active ? ' active' : ''))
|
|
1680
|
-
.on('click', (e, d) =>
|
|
2555
|
+
.on('click', (e, d) => {
|
|
2556
|
+
e.stopPropagation();
|
|
2557
|
+
loadNote(d.id);
|
|
2558
|
+
if (isMaximized) {
|
|
2559
|
+
document.getElementById('graph-section').classList.remove('maximized');
|
|
2560
|
+
isGraphMaximized = false;
|
|
2561
|
+
renderGraph(currentNote);
|
|
2562
|
+
}
|
|
2563
|
+
})
|
|
1681
2564
|
.call(d3.drag()
|
|
1682
2565
|
.on('start', (e, d) => { if (!e.active) simulation.alphaTarget(0.3).restart(); d.fx = d.x; d.fy = d.y; })
|
|
1683
2566
|
.on('drag', (e, d) => { d.fx = e.x; d.fy = e.y; })
|
|
1684
2567
|
.on('end', (e, d) => { if (!e.active) simulation.alphaTarget(0); d.fx = null; d.fy = null; })
|
|
1685
2568
|
);
|
|
1686
2569
|
|
|
1687
|
-
node.append('circle').attr('r', d => d.active ?
|
|
1688
|
-
node.append('text').text(d => d.title).attr('dx',
|
|
2570
|
+
node.append('circle').attr('r', d => d.active ? 8 : Math.min(12, 3 + (d.degree * 1.2)));
|
|
2571
|
+
node.append('text').text(d => d.title).attr('dx', d => (d.active ? 8 : Math.min(12, 3 + (d.degree * 1.2))) + 6).attr('dy', 3);
|
|
2572
|
+
|
|
2573
|
+
if (isMaximized) {
|
|
2574
|
+
node.append('text')
|
|
2575
|
+
.text(d => {
|
|
2576
|
+
let hash = 0;
|
|
2577
|
+
for (let i = 0; i < d.id.length; i++) hash = Math.imul(31, hash) + d.id.charCodeAt(i) | 0;
|
|
2578
|
+
const v1 = ((Math.abs(hash) % 1000) / 1000).toFixed(3);
|
|
2579
|
+
const v2 = ((Math.abs(hash * 13) % 1000) / 1000).toFixed(3);
|
|
2580
|
+
const v3 = ((Math.abs(hash * 17) % 1000) / 1000).toFixed(3);
|
|
2581
|
+
return `[${v1}, ${v2}, ${v3}, ...]`;
|
|
2582
|
+
})
|
|
2583
|
+
.attr('dx', d => (d.active ? 8 : Math.min(12, 3 + (d.degree * 1.2))) + 6)
|
|
2584
|
+
.attr('dy', 16)
|
|
2585
|
+
.style('fill', 'var(--neon-purple)')
|
|
2586
|
+
.style('font-size', '8px')
|
|
2587
|
+
.style('opacity', '0.8')
|
|
2588
|
+
.style('pointer-events', 'none')
|
|
2589
|
+
.style('font-family', 'var(--font-mono)');
|
|
2590
|
+
|
|
2591
|
+
node.append('text')
|
|
2592
|
+
.text(d => d.id ? d.id.split('/').slice(0, -1).join('/') : '')
|
|
2593
|
+
.attr('dx', d => (d.active ? 8 : Math.min(12, 3 + (d.degree * 1.2))) + 6)
|
|
2594
|
+
.attr('dy', 26)
|
|
2595
|
+
.style('fill', 'var(--text-muted)')
|
|
2596
|
+
.style('font-size', '8px')
|
|
2597
|
+
.style('pointer-events', 'none');
|
|
2598
|
+
}
|
|
1689
2599
|
|
|
1690
2600
|
simulation.on('tick', () => {
|
|
1691
|
-
|
|
2601
|
+
linkEl
|
|
1692
2602
|
.attr('x1', d => d.source.x).attr('y1', d => d.source.y)
|
|
1693
2603
|
.attr('x2', d => d.target.x).attr('y2', d => d.target.y);
|
|
1694
|
-
node.attr('transform', d =>
|
|
2604
|
+
node.attr('transform', d => {
|
|
2605
|
+
d.x = Math.max(margin, Math.min(width - margin, d.x));
|
|
2606
|
+
d.y = Math.max(margin, Math.min(height - margin, d.y));
|
|
2607
|
+
return `translate(${d.x},${d.y})`;
|
|
2608
|
+
});
|
|
2609
|
+
});
|
|
2610
|
+
}
|
|
2611
|
+
|
|
2612
|
+
// --- Graph Resize ---
|
|
2613
|
+
let graphHeight = parseInt(localStorage.getItem('kyp-graph-h')) || 200;
|
|
2614
|
+
let isGraphMaximized = false;
|
|
2615
|
+
|
|
2616
|
+
function initGraphResize() {
|
|
2617
|
+
const container = document.getElementById('graph-container');
|
|
2618
|
+
const section = document.getElementById('graph-section');
|
|
2619
|
+
container.style.height = graphHeight + 'px';
|
|
2620
|
+
|
|
2621
|
+
document.getElementById('graph-max').addEventListener('click', () => {
|
|
2622
|
+
isGraphMaximized = !isGraphMaximized;
|
|
2623
|
+
section.classList.toggle('maximized', isGraphMaximized);
|
|
2624
|
+
if (graphVisible && currentNote) renderGraph(currentNote);
|
|
2625
|
+
});
|
|
2626
|
+
|
|
2627
|
+
document.getElementById('graph-shrink').addEventListener('click', () => {
|
|
2628
|
+
graphHeight = Math.max(100, graphHeight - 50);
|
|
2629
|
+
container.style.height = graphHeight + 'px';
|
|
2630
|
+
localStorage.setItem('kyp-graph-h', graphHeight);
|
|
2631
|
+
if (graphVisible && currentNote) renderGraph(currentNote);
|
|
2632
|
+
});
|
|
2633
|
+
|
|
2634
|
+
document.getElementById('graph-grow').addEventListener('click', () => {
|
|
2635
|
+
graphHeight = Math.min(600, graphHeight + 50);
|
|
2636
|
+
container.style.height = graphHeight + 'px';
|
|
2637
|
+
localStorage.setItem('kyp-graph-h', graphHeight);
|
|
2638
|
+
if (graphVisible && currentNote) renderGraph(currentNote);
|
|
2639
|
+
});
|
|
2640
|
+
|
|
2641
|
+
const handle = document.getElementById('graph-resize-handle');
|
|
2642
|
+
handle.addEventListener('mousedown', (e) => {
|
|
2643
|
+
e.preventDefault();
|
|
2644
|
+
const startY = e.clientY;
|
|
2645
|
+
const startH = graphHeight;
|
|
2646
|
+
document.body.style.cursor = 'ns-resize';
|
|
2647
|
+
document.body.style.userSelect = 'none';
|
|
2648
|
+
|
|
2649
|
+
function onMove(ev) {
|
|
2650
|
+
graphHeight = Math.max(100, Math.min(600, startH + (ev.clientY - startY)));
|
|
2651
|
+
container.style.height = graphHeight + 'px';
|
|
2652
|
+
}
|
|
2653
|
+
|
|
2654
|
+
function onUp() {
|
|
2655
|
+
document.body.style.cursor = '';
|
|
2656
|
+
document.body.style.userSelect = '';
|
|
2657
|
+
localStorage.setItem('kyp-graph-h', graphHeight);
|
|
2658
|
+
if (graphVisible && currentNote) renderGraph(currentNote);
|
|
2659
|
+
document.removeEventListener('mousemove', onMove);
|
|
2660
|
+
document.removeEventListener('mouseup', onUp);
|
|
2661
|
+
}
|
|
2662
|
+
|
|
2663
|
+
document.addEventListener('mousemove', onMove);
|
|
2664
|
+
document.addEventListener('mouseup', onUp);
|
|
1695
2665
|
});
|
|
1696
2666
|
}
|
|
1697
2667
|
|
|
@@ -1899,8 +2869,13 @@ function initResize() {
|
|
|
1899
2869
|
|
|
1900
2870
|
// --- Init ---
|
|
1901
2871
|
async function init() {
|
|
1902
|
-
|
|
1903
|
-
|
|
2872
|
+
const [rawTreeData, sessionsData, stats] = await Promise.all([
|
|
2873
|
+
fetchJSON('/api/tree'),
|
|
2874
|
+
fetchJSON('/api/sessions'),
|
|
2875
|
+
fetchJSON('/api/stats'),
|
|
2876
|
+
]);
|
|
2877
|
+
|
|
2878
|
+
treeData = rawTreeData;
|
|
1904
2879
|
|
|
1905
2880
|
function walk(node) {
|
|
1906
2881
|
if (node.type === 'note') {
|
|
@@ -1919,6 +2894,7 @@ async function init() {
|
|
|
1919
2894
|
await Promise.all(promises);
|
|
1920
2895
|
|
|
1921
2896
|
renderTree(treeData, document.getElementById('file-tree'));
|
|
2897
|
+
renderSessionTree(sessionsData);
|
|
1922
2898
|
renderTagCloud(collectAllTags());
|
|
1923
2899
|
|
|
1924
2900
|
document.getElementById('stats-bar').innerHTML = `
|
|
@@ -1930,6 +2906,7 @@ async function init() {
|
|
|
1930
2906
|
}
|
|
1931
2907
|
|
|
1932
2908
|
initResize();
|
|
2909
|
+
initGraphResize();
|
|
1933
2910
|
init();
|
|
1934
2911
|
</script>
|
|
1935
2912
|
</body>
|