dsh-biocore 0.1.8 → 0.2.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/package.json +1 -1
- package/ui/panel-layout.js +5 -3
- package/ui/panel.css +276 -1
- package/ui/panel.html +120 -8
- package/ui/panel.js +223 -26
package/package.json
CHANGED
package/ui/panel-layout.js
CHANGED
|
@@ -10,15 +10,17 @@
|
|
|
10
10
|
var STORAGE_KEY = 'biocore-panel-layout-v2'
|
|
11
11
|
var DEFAULT_ORDER = [
|
|
12
12
|
'mood', 'tension', 'warmth', 'heaviness', 'clarity', 'chart',
|
|
13
|
-
'memory', 'memory-summary', 'metrics',
|
|
13
|
+
'memory', 'memory-summary', 'metrics',
|
|
14
14
|
'persona', 'model', 'switches', 'expression', 'advanced',
|
|
15
|
+
'runtime', 'trace',
|
|
15
16
|
]
|
|
16
|
-
var TAB_ORDER = ['dashboard', 'memory', 'settings', '
|
|
17
|
+
var TAB_ORDER = ['dashboard', 'memory', 'relation', 'settings', 'tools']
|
|
17
18
|
var TAB_GROUPS = Object.freeze({
|
|
18
19
|
dashboard: ['mood', 'tension', 'warmth', 'heaviness', 'clarity', 'chart'],
|
|
19
20
|
memory: ['memory', 'memory-summary'],
|
|
21
|
+
relation: ['metrics'],
|
|
20
22
|
settings: ['persona', 'model', 'switches', 'expression', 'advanced'],
|
|
21
|
-
|
|
23
|
+
tools: ['runtime', 'trace'],
|
|
22
24
|
})
|
|
23
25
|
|
|
24
26
|
function defaultLayout() {
|
package/ui/panel.css
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* BioCore instrument panel — FlClash mobile spec. | layout
|
|
1
|
+
/* BioCore instrument panel — FlClash mobile spec. | layout v27
|
|
2
2
|
1) tokens 2) base 3) topbar 4) cards 5) figures 6) lists 7) forms
|
|
3
3
|
8) switches 9) nav 10) edit mode 11) desktop.
|
|
4
4
|
Rule: one component rule per selector, px values from docs/DSH-PANEL-FLCLASH-SPEC.md. */
|
|
@@ -499,6 +499,9 @@ canvas#moodChart { display: block; width: 100%; height: 150px; }
|
|
|
499
499
|
.expression-fields { grid-template-columns: 1fr; }
|
|
500
500
|
}
|
|
501
501
|
|
|
502
|
+
/* bug fix: whole channels block (title included) leaves non-dashboard tabs */
|
|
503
|
+
.panel:not(.tab-dashboard):not(.layout-editing) .channels-wrap { display: none; }
|
|
504
|
+
|
|
502
505
|
/* ---------- 13. layout guards (防止旧版/串版样式压扁版面) ---------- */
|
|
503
506
|
html, body { overflow-x: clip; }
|
|
504
507
|
body { max-width: 100%; }
|
|
@@ -556,3 +559,275 @@ body { max-width: 100%; }
|
|
|
556
559
|
.model-card .model-section-title:first-of-type { margin-top: 0; }
|
|
557
560
|
.rerank-toggle { margin: 0 0 10px; }
|
|
558
561
|
.rerank-grid[hidden] { display: none !important; }
|
|
562
|
+
|
|
563
|
+
/* ---------- 15. desktop (>=1024): left rail + 12-col dashboard ---------- */
|
|
564
|
+
.rail, .desk { display: none; }
|
|
565
|
+
|
|
566
|
+
@media (min-width: 1024px) {
|
|
567
|
+
:root {
|
|
568
|
+
--rail-w: 220px;
|
|
569
|
+
--radius-card: 32px;
|
|
570
|
+
--pad-card: 20px;
|
|
571
|
+
--gap-card: 12px;
|
|
572
|
+
}
|
|
573
|
+
body { padding: 0; }
|
|
574
|
+
body.rail-collapsed { --rail-w: 64px; }
|
|
575
|
+
|
|
576
|
+
.panel {
|
|
577
|
+
width: auto;
|
|
578
|
+
max-width: none;
|
|
579
|
+
min-height: 100vh;
|
|
580
|
+
margin: 0 0 0 var(--rail-w);
|
|
581
|
+
padding: 16px 24px 24px 16px;
|
|
582
|
+
display: grid;
|
|
583
|
+
grid-template-columns: repeat(12, minmax(0, 1fr));
|
|
584
|
+
gap: 12px;
|
|
585
|
+
align-content: start;
|
|
586
|
+
transition: margin-left 160ms ease;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/* --- left rail --- */
|
|
590
|
+
.rail {
|
|
591
|
+
position: fixed;
|
|
592
|
+
inset: 0 auto 0 0;
|
|
593
|
+
z-index: 40;
|
|
594
|
+
width: var(--rail-w);
|
|
595
|
+
display: flex;
|
|
596
|
+
flex-direction: column;
|
|
597
|
+
gap: 6px;
|
|
598
|
+
padding: 12px 10px;
|
|
599
|
+
background: var(--page);
|
|
600
|
+
border-right: 1px solid var(--line);
|
|
601
|
+
overflow: hidden;
|
|
602
|
+
transition: width 160ms ease, padding 160ms ease;
|
|
603
|
+
}
|
|
604
|
+
.rail-toggle {
|
|
605
|
+
display: grid;
|
|
606
|
+
place-items: center;
|
|
607
|
+
width: 40px;
|
|
608
|
+
height: 40px;
|
|
609
|
+
margin: 0 0 8px 2px;
|
|
610
|
+
padding: 0;
|
|
611
|
+
border: 0;
|
|
612
|
+
border-radius: 10px;
|
|
613
|
+
background: transparent;
|
|
614
|
+
color: var(--text-2);
|
|
615
|
+
cursor: pointer;
|
|
616
|
+
transition: background 160ms ease, color 160ms ease;
|
|
617
|
+
}
|
|
618
|
+
.rail-toggle:hover { background: rgba(255, 255, 255, 0.04); color: var(--text); }
|
|
619
|
+
.rail-toggle svg { width: 20px; height: 20px; }
|
|
620
|
+
.rail-nav { display: flex; flex-direction: column; gap: 2px; }
|
|
621
|
+
.rail-item {
|
|
622
|
+
position: relative;
|
|
623
|
+
display: flex;
|
|
624
|
+
align-items: center;
|
|
625
|
+
gap: 10px;
|
|
626
|
+
height: 40px;
|
|
627
|
+
padding: 0 12px;
|
|
628
|
+
border: 0;
|
|
629
|
+
border-radius: 8px;
|
|
630
|
+
background: transparent;
|
|
631
|
+
color: var(--text-2);
|
|
632
|
+
font: inherit;
|
|
633
|
+
font-size: 14px;
|
|
634
|
+
line-height: 20px;
|
|
635
|
+
text-align: left;
|
|
636
|
+
white-space: nowrap;
|
|
637
|
+
overflow: hidden;
|
|
638
|
+
cursor: pointer;
|
|
639
|
+
transition: background 160ms ease, color 160ms ease;
|
|
640
|
+
}
|
|
641
|
+
.rail-item svg { flex: 0 0 20px; width: 20px; height: 20px; }
|
|
642
|
+
.rail-item:hover { background: rgba(255, 255, 255, 0.04); color: var(--text); }
|
|
643
|
+
.rail-item.active { background: rgba(255, 255, 255, 0.06); color: var(--text); }
|
|
644
|
+
.rail-item.active::before {
|
|
645
|
+
content: '';
|
|
646
|
+
position: absolute;
|
|
647
|
+
left: 0;
|
|
648
|
+
top: 8px;
|
|
649
|
+
bottom: 8px;
|
|
650
|
+
width: 2px;
|
|
651
|
+
border-radius: 2px;
|
|
652
|
+
background: var(--accent);
|
|
653
|
+
}
|
|
654
|
+
body.rail-collapsed .rail-item { justify-content: center; padding: 0; }
|
|
655
|
+
body.rail-collapsed .rail-item span { display: none; }
|
|
656
|
+
|
|
657
|
+
/* --- header --- */
|
|
658
|
+
.topbar { position: static; height: 56px; padding: 0; grid-column: 1 / -1; }
|
|
659
|
+
.topbar h1 { font-size: 22px; line-height: 28px; }
|
|
660
|
+
.masthead { display: none; }
|
|
661
|
+
.tabbar { display: none; }
|
|
662
|
+
.footer { grid-column: 1 / -1; padding: 0 4px; }
|
|
663
|
+
|
|
664
|
+
/* --- desktop dashboard: 12 col x 5 rows --- */
|
|
665
|
+
.desk {
|
|
666
|
+
display: grid;
|
|
667
|
+
grid-column: 1 / -1;
|
|
668
|
+
grid-template-columns: repeat(12, minmax(0, 1fr));
|
|
669
|
+
grid-template-rows: 208px 64px 176px minmax(200px, auto) minmax(120px, auto);
|
|
670
|
+
gap: 12px;
|
|
671
|
+
}
|
|
672
|
+
.desk-card {
|
|
673
|
+
position: relative;
|
|
674
|
+
min-width: 0;
|
|
675
|
+
padding: 20px;
|
|
676
|
+
border-radius: 32px;
|
|
677
|
+
overflow: hidden;
|
|
678
|
+
}
|
|
679
|
+
.desk-card-head {
|
|
680
|
+
display: flex;
|
|
681
|
+
align-items: baseline;
|
|
682
|
+
justify-content: space-between;
|
|
683
|
+
gap: 8px;
|
|
684
|
+
margin-bottom: 10px;
|
|
685
|
+
}
|
|
686
|
+
.desk-card-head h2 { margin: 0; font-size: 15px; line-height: 24px; font-weight: 600; }
|
|
687
|
+
.desk-status, .desk-seg, .desk-memory, .desk-chart { grid-column: span 6; }
|
|
688
|
+
.desk-metric, .desk-switch, .desk-tile { grid-column: span 3; }
|
|
689
|
+
.desk-stat { grid-column: span 4; }
|
|
690
|
+
|
|
691
|
+
.desk-status { display: flex; align-items: center; gap: 20px; }
|
|
692
|
+
.desk-orb { width: 88px; height: 88px; flex: 0 0 88px; display: grid; place-items: center; }
|
|
693
|
+
.desk-status-body { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
|
|
694
|
+
.desk-status-body h2 { margin: 0; font-size: 22px; line-height: 28px; font-weight: 600; }
|
|
695
|
+
.desk-status-body .motivation { margin: 0; color: var(--text-2); font-size: 15px; line-height: 22px; }
|
|
696
|
+
|
|
697
|
+
.desk-metric { display: flex; flex-direction: column; justify-content: center; gap: 10px; }
|
|
698
|
+
.desk-metric-head {
|
|
699
|
+
display: flex;
|
|
700
|
+
align-items: baseline;
|
|
701
|
+
justify-content: space-between;
|
|
702
|
+
gap: 8px;
|
|
703
|
+
color: var(--text-2);
|
|
704
|
+
font-size: 13px;
|
|
705
|
+
line-height: 18px;
|
|
706
|
+
}
|
|
707
|
+
.desk-metric-value { display: flex; align-items: baseline; gap: 10px; }
|
|
708
|
+
.desk-metric-value strong {
|
|
709
|
+
font-size: 40px;
|
|
710
|
+
line-height: 44px;
|
|
711
|
+
font-weight: 700;
|
|
712
|
+
letter-spacing: -0.02em;
|
|
713
|
+
font-variant-numeric: tabular-nums;
|
|
714
|
+
}
|
|
715
|
+
.desk-metric-value .sub-status { margin-left: auto; color: var(--text-2); font-size: 13px; }
|
|
716
|
+
|
|
717
|
+
.desk-seg { display: flex; align-items: center; gap: 6px; padding: 6px; border-radius: 32px; background: var(--tone); box-shadow: none; }
|
|
718
|
+
.seg-item {
|
|
719
|
+
flex: 1 1 0;
|
|
720
|
+
height: 52px;
|
|
721
|
+
border: 0;
|
|
722
|
+
border-radius: 16px;
|
|
723
|
+
background: transparent;
|
|
724
|
+
color: var(--text-2);
|
|
725
|
+
font: inherit;
|
|
726
|
+
font-size: 14px;
|
|
727
|
+
cursor: pointer;
|
|
728
|
+
transition: background 160ms ease, color 160ms ease;
|
|
729
|
+
}
|
|
730
|
+
.seg-item:hover { background: rgba(255, 255, 255, 0.04); color: var(--text); }
|
|
731
|
+
.seg-item.active { background: var(--accent); color: #ffffff; }
|
|
732
|
+
|
|
733
|
+
.desk-switch { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
|
|
734
|
+
.desk-switch-label { font-size: 15px; line-height: 24px; font-weight: 600; }
|
|
735
|
+
.desk-switch-control { display: flex; align-items: center; gap: 8px; }
|
|
736
|
+
.desk-switch-control input { width: 22px; height: 22px; accent-color: var(--accent); }
|
|
737
|
+
.desk-switch-state { color: var(--text-3); font-size: 12px; line-height: 16px; }
|
|
738
|
+
|
|
739
|
+
.desk-tile { display: flex; flex-direction: column; justify-content: center; gap: 8px; }
|
|
740
|
+
.desk-tile-head {
|
|
741
|
+
display: flex;
|
|
742
|
+
align-items: center;
|
|
743
|
+
justify-content: space-between;
|
|
744
|
+
gap: 8px;
|
|
745
|
+
color: var(--text-2);
|
|
746
|
+
font-size: 12px;
|
|
747
|
+
line-height: 16px;
|
|
748
|
+
}
|
|
749
|
+
.desk-tile strong {
|
|
750
|
+
font-size: 22px;
|
|
751
|
+
line-height: 28px;
|
|
752
|
+
font-weight: 600;
|
|
753
|
+
letter-spacing: -0.01em;
|
|
754
|
+
overflow: hidden;
|
|
755
|
+
text-overflow: ellipsis;
|
|
756
|
+
white-space: nowrap;
|
|
757
|
+
}
|
|
758
|
+
.desk-tile-note { color: var(--text-3); font-size: 12px; line-height: 16px; }
|
|
759
|
+
.desk-tile-row { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; color: var(--text-2); font-size: 13px; line-height: 18px; }
|
|
760
|
+
.desk-tile-row b { color: var(--text); font-size: 15px; font-weight: 600; font-variant-numeric: tabular-nums; }
|
|
761
|
+
.desk-chevron { color: var(--text-3); font-size: 14px; }
|
|
762
|
+
.desk-copy {
|
|
763
|
+
height: 24px;
|
|
764
|
+
padding: 0 10px;
|
|
765
|
+
border: 0;
|
|
766
|
+
border-radius: 8px;
|
|
767
|
+
background: var(--block);
|
|
768
|
+
color: var(--text-2);
|
|
769
|
+
font: inherit;
|
|
770
|
+
font-size: 12px;
|
|
771
|
+
cursor: pointer;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
.desk-memory { display: flex; flex-direction: column; }
|
|
775
|
+
.desk-memory .memory-list { max-height: none; }
|
|
776
|
+
.desk-chart { display: flex; flex-direction: column; }
|
|
777
|
+
#deskChart { width: 100%; height: 100%; min-height: 110px; display: block; }
|
|
778
|
+
|
|
779
|
+
.desk-stat { display: flex; flex-direction: column; justify-content: center; gap: 6px; }
|
|
780
|
+
.desk-stat-row {
|
|
781
|
+
display: flex;
|
|
782
|
+
align-items: baseline;
|
|
783
|
+
justify-content: space-between;
|
|
784
|
+
gap: 8px;
|
|
785
|
+
color: var(--text-2);
|
|
786
|
+
font-size: 13px;
|
|
787
|
+
line-height: 18px;
|
|
788
|
+
}
|
|
789
|
+
.desk-stat-row b { color: var(--text); font-size: 15px; font-weight: 600; font-variant-numeric: tabular-nums; }
|
|
790
|
+
|
|
791
|
+
/* --- tab switching on desktop --- */
|
|
792
|
+
.panel.tab-dashboard #cards { display: none; }
|
|
793
|
+
.panel:not(.tab-dashboard) .desk { display: none; }
|
|
794
|
+
.panel:not(.tab-dashboard) #cards {
|
|
795
|
+
display: grid;
|
|
796
|
+
grid-column: 1 / -1;
|
|
797
|
+
grid-template-columns: repeat(12, minmax(0, 1fr));
|
|
798
|
+
gap: 12px;
|
|
799
|
+
}
|
|
800
|
+
.panel:not(.tab-dashboard) #cards { align-content: start; }
|
|
801
|
+
.panel:not(.tab-dashboard) #cards > * { grid-column: span 6; }
|
|
802
|
+
.panel:not(.tab-dashboard) #cards > [data-card-id="metrics"] { grid-column: span 8; }
|
|
803
|
+
.panel:not(.tab-dashboard) #cards > [data-card-id="trace"] { grid-column: span 8; }
|
|
804
|
+
.panel:not(.tab-dashboard) #cards > [data-card-id="runtime"] { grid-column: span 4; }
|
|
805
|
+
.panel:not(.tab-dashboard) #cards > [data-card-id="model"] { grid-column: span 12; }
|
|
806
|
+
.panel:not(.tab-dashboard) #cards > .channels-wrap { grid-column: span 12; }
|
|
807
|
+
.panel:not(.tab-dashboard) .channels-wrap .channel-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
|
|
808
|
+
.panel:not(.tab-dashboard) .add-cards { grid-column: 1 / -1; }
|
|
809
|
+
.layout-editing #cards { display: grid; grid-column: 1 / -1; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 12px; }
|
|
810
|
+
.layout-editing #cards > * { grid-column: span 6; }
|
|
811
|
+
|
|
812
|
+
/* --- desktop edit mode (hide chips on desk cards) --- */
|
|
813
|
+
.desk-hide {
|
|
814
|
+
display: none;
|
|
815
|
+
position: absolute;
|
|
816
|
+
top: -8px;
|
|
817
|
+
right: -8px;
|
|
818
|
+
z-index: 3;
|
|
819
|
+
place-items: center;
|
|
820
|
+
width: 28px;
|
|
821
|
+
height: 28px;
|
|
822
|
+
padding: 0;
|
|
823
|
+
border: 0;
|
|
824
|
+
border-radius: 50%;
|
|
825
|
+
background: var(--danger);
|
|
826
|
+
color: #ffffff;
|
|
827
|
+
font-size: 18px;
|
|
828
|
+
line-height: 1;
|
|
829
|
+
cursor: pointer;
|
|
830
|
+
}
|
|
831
|
+
.layout-editing .desk-hide { display: grid; }
|
|
832
|
+
.desk-card.is-desk-hidden { display: none !important; }
|
|
833
|
+
}
|
package/ui/panel.html
CHANGED
|
@@ -1,13 +1,25 @@
|
|
|
1
1
|
<!doctype html>
|
|
2
|
-
<!-- BioCore panel layout
|
|
2
|
+
<!-- BioCore panel layout v27: mobile = FlClash phone (masthead/channels 2x2/pill tabbar); desktop >=1024 = left rail + 12-col 5-row dashboard -->
|
|
3
3
|
<html lang="zh-CN">
|
|
4
4
|
<head>
|
|
5
5
|
<meta charset="utf-8">
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
7
7
|
<title>生物核 · 仪器面板</title>
|
|
8
|
-
<link rel="stylesheet" href="panel.css?v=
|
|
8
|
+
<link rel="stylesheet" href="panel.css?v=27">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
|
+
<aside class="rail" id="rail" aria-label="主导航">
|
|
12
|
+
<button class="rail-toggle" id="railToggle" type="button" aria-label="收起导航" aria-expanded="true" title="收起导航">
|
|
13
|
+
<svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2.5" y="3.5" width="15" height="13" rx="2.5"/><path d="M7.5 3.5v13M12.5 8l-2 2 2 2"/></svg>
|
|
14
|
+
</button>
|
|
15
|
+
<nav class="rail-nav" aria-label="页面导航">
|
|
16
|
+
<button class="rail-item active" type="button" data-tab="dashboard" title="仪表盘" aria-selected="true"><svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="3" width="6" height="6" rx="1.5"/><rect x="11" y="3" width="6" height="6" rx="1.5"/><rect x="3" y="11" width="6" height="6" rx="1.5"/><rect x="11" y="11" width="6" height="6" rx="1.5"/></svg><span>仪表盘</span></button>
|
|
17
|
+
<button class="rail-item" type="button" data-tab="memory" title="记忆" aria-selected="false"><svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 3.5h10v13l-5-3-5 3z"/></svg><span>记忆</span></button>
|
|
18
|
+
<button class="rail-item" type="button" data-tab="relation" title="关系" aria-selected="false"><svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 16.2s-5.4-3.4-5.4-7a2.9 2.9 0 015.4-1.7 2.9 2.9 0 015.4 1.7c0 3.6-5.4 7-5.4 7z"/></svg><span>关系</span></button>
|
|
19
|
+
<button class="rail-item" type="button" data-tab="settings" title="配置" aria-selected="false"><svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="10" cy="10" r="2.6"/><path d="M10 3.2v2M10 14.8v2M3.2 10h2M14.8 10h2M5.2 5.2l1.4 1.4M13.4 13.4l1.4 1.4M14.8 5.2l-1.4 1.4M6.6 13.4l-1.4 1.4"/></svg><span>配置</span></button>
|
|
20
|
+
<button class="rail-item" type="button" data-tab="tools" title="工具" aria-selected="false"><svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M11.6 4.4a3.2 3.2 0 00-4 4l-4.1 4.1 2 2 4.1-4.1a3.2 3.2 0 004-4l-2 2-1.6-1.6 1.6-2.4z"/></svg><span>工具</span></button>
|
|
21
|
+
</nav>
|
|
22
|
+
</aside>
|
|
11
23
|
<main class="panel" id="panel">
|
|
12
24
|
<header class="topbar" id="topBar">
|
|
13
25
|
<div class="topbar-title">
|
|
@@ -22,6 +34,102 @@
|
|
|
22
34
|
</button>
|
|
23
35
|
</header>
|
|
24
36
|
|
|
37
|
+
<section class="desk" id="deskGrid" aria-label="桌面仪表盘">
|
|
38
|
+
<header class="card desk-card desk-status">
|
|
39
|
+
<div class="orb-wrap desk-orb" aria-hidden="true"><div class="orb"><span class="orb-ring"></span></div></div>
|
|
40
|
+
<div class="desk-status-body">
|
|
41
|
+
<h2>她现在的样子</h2>
|
|
42
|
+
<p class="motivation" id="deskMotivation">正在读取…</p>
|
|
43
|
+
<div class="status" id="deskStatus"><i class="dot"></i><span id="deskStatusText">未连接</span></div>
|
|
44
|
+
</div>
|
|
45
|
+
</header>
|
|
46
|
+
|
|
47
|
+
<section class="card desk-card desk-metric" id="deskMoodCard" data-card-label="心情">
|
|
48
|
+
<div class="desk-metric-head"><span>心情</span><span class="sub-trend"><b id="deskArrowV">→</b><span class="delta" id="deskDeltaV">—</span></span></div>
|
|
49
|
+
<div class="desk-metric-value"><strong id="deskNumV">–</strong><span class="sub-status" id="deskWordV">—</span></div>
|
|
50
|
+
<div class="bar"><i id="deskBarV"></i></div>
|
|
51
|
+
</section>
|
|
52
|
+
|
|
53
|
+
<section class="card desk-card desk-metric" id="deskTensionCard" data-card-label="张力">
|
|
54
|
+
<div class="desk-metric-head"><span>张力</span><span class="sub-trend"><b id="deskArrowTension">→</b><span class="delta" id="deskDeltaTension">—</span></span></div>
|
|
55
|
+
<div class="desk-metric-value"><strong id="deskNumTension">–</strong><span class="sub-status" id="deskWordTension">—</span></div>
|
|
56
|
+
<div class="bar"><i id="deskBarTension"></i></div>
|
|
57
|
+
</section>
|
|
58
|
+
|
|
59
|
+
<nav class="card desk-card desk-seg" id="segTabs" aria-label="分组导航">
|
|
60
|
+
<button class="seg-item active" type="button" data-tab="dashboard" aria-selected="true">仪表盘</button>
|
|
61
|
+
<button class="seg-item" type="button" data-tab="memory" aria-selected="false">记忆</button>
|
|
62
|
+
<button class="seg-item" type="button" data-tab="relation" aria-selected="false">关系</button>
|
|
63
|
+
<button class="seg-item" type="button" data-tab="settings" aria-selected="false">配置</button>
|
|
64
|
+
<button class="seg-item" type="button" data-tab="tools" aria-selected="false">工具</button>
|
|
65
|
+
</nav>
|
|
66
|
+
|
|
67
|
+
<section class="card desk-card desk-switch" aria-label="安全闸">
|
|
68
|
+
<span class="desk-switch-label">安全闸</span>
|
|
69
|
+
<label class="desk-switch-control"><input type="checkbox" data-switch="safety_enabled" aria-label="安全闸"><span class="desk-switch-state" data-switch-state="safety_enabled">当前:关</span></label>
|
|
70
|
+
</section>
|
|
71
|
+
|
|
72
|
+
<section class="card desk-card desk-switch" aria-label="主动回复">
|
|
73
|
+
<span class="desk-switch-label">主动回复</span>
|
|
74
|
+
<label class="desk-switch-control"><input type="checkbox" data-switch="proactive_send" aria-label="主动回复"><span class="desk-switch-state" data-switch-state="proactive_send">当前:关</span></label>
|
|
75
|
+
</section>
|
|
76
|
+
|
|
77
|
+
<section class="card desk-card desk-tile">
|
|
78
|
+
<div class="desk-tile-head"><span>数据目录</span><button class="desk-copy" id="deskCopyDataDir" type="button">复制</button></div>
|
|
79
|
+
<strong id="deskDataDir">宿主托管</strong>
|
|
80
|
+
</section>
|
|
81
|
+
|
|
82
|
+
<section class="card desk-card desk-tile">
|
|
83
|
+
<div class="desk-tile-head"><span>人设</span><span class="desk-chevron" aria-hidden="true">›</span></div>
|
|
84
|
+
<strong id="deskPersona">未载入</strong>
|
|
85
|
+
<span class="desk-tile-note" id="deskPersonaNote">—</span>
|
|
86
|
+
</section>
|
|
87
|
+
|
|
88
|
+
<section class="card desk-card desk-tile">
|
|
89
|
+
<div class="desk-tile-head"><span>运行时</span><span class="desk-chevron" aria-hidden="true">›</span></div>
|
|
90
|
+
<div class="desk-tile-row"><span>运行时长</span><b id="deskUptime">—</b></div>
|
|
91
|
+
<div class="desk-tile-row"><span>轮次</span><b id="deskTurns">—</b></div>
|
|
92
|
+
<div class="desk-tile-row"><span>向量模式</span><b id="deskVector">—</b></div>
|
|
93
|
+
</section>
|
|
94
|
+
|
|
95
|
+
<section class="card desk-card desk-tile">
|
|
96
|
+
<div class="desk-tile-head"><span>记忆容量</span><span class="desk-tile-note" id="deskCapText">0 / 200</span></div>
|
|
97
|
+
<div class="bar"><i id="deskCapFill"></i></div>
|
|
98
|
+
</section>
|
|
99
|
+
|
|
100
|
+
<section class="card desk-card desk-memory">
|
|
101
|
+
<div class="desk-card-head"><h2>最近记忆</h2><span class="card-aside" id="deskMemoryHint">—</span></div>
|
|
102
|
+
<ul class="memory-list" id="deskMemoryList"><li class="empty">还没有记忆,聊几句就会记住</li></ul>
|
|
103
|
+
</section>
|
|
104
|
+
|
|
105
|
+
<section class="card desk-card desk-chart">
|
|
106
|
+
<div class="desk-card-head"><h2>心情 · 24 小时</h2><span class="card-aside" id="deskChartHint">单线 + 事件点</span></div>
|
|
107
|
+
<canvas id="deskChart" height="170"></canvas>
|
|
108
|
+
</section>
|
|
109
|
+
|
|
110
|
+
<section class="card desk-card desk-stat">
|
|
111
|
+
<div class="desk-card-head"><h2>四通道均值</h2></div>
|
|
112
|
+
<div class="desk-stat-row"><span>绷紧</span><b id="deskAvgTension">—</b></div>
|
|
113
|
+
<div class="desk-stat-row"><span>暖</span><b id="deskAvgWarmth">—</b></div>
|
|
114
|
+
<div class="desk-stat-row"><span>沉</span><b id="deskAvgHeaviness">—</b></div>
|
|
115
|
+
<div class="desk-stat-row"><span>清</span><b id="deskAvgClarity">—</b></div>
|
|
116
|
+
</section>
|
|
117
|
+
|
|
118
|
+
<section class="card desk-card desk-stat">
|
|
119
|
+
<div class="desk-card-head"><h2>关系</h2></div>
|
|
120
|
+
<div class="desk-stat-row"><span>亲近</span><b id="deskRelCloseness">—</b></div>
|
|
121
|
+
<div class="desk-stat-row"><span>信任</span><b id="deskRelTrust">—</b></div>
|
|
122
|
+
<div class="desk-stat-row"><span>冲突</span><b id="deskRelConflict">—</b></div>
|
|
123
|
+
</section>
|
|
124
|
+
|
|
125
|
+
<section class="card desk-card desk-stat">
|
|
126
|
+
<div class="desk-card-head"><h2>今日</h2></div>
|
|
127
|
+
<div class="desk-stat-row"><span>新增记忆</span><b id="deskTodayMem">—</b></div>
|
|
128
|
+
<div class="desk-stat-row"><span>轮次</span><b id="deskTodayTurns">—</b></div>
|
|
129
|
+
<div class="desk-stat-row"><span>主动发送</span><b id="deskTodayProactive">—</b></div>
|
|
130
|
+
</section>
|
|
131
|
+
</section>
|
|
132
|
+
|
|
25
133
|
<header class="masthead" id="masthead">
|
|
26
134
|
<div class="orb-wrap" aria-hidden="true">
|
|
27
135
|
<div class="orb"><span class="orb-ring"></span></div>
|
|
@@ -270,15 +378,19 @@
|
|
|
270
378
|
<svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 3.5h10v13l-5-3-5 3z"/></svg>
|
|
271
379
|
<span>记忆</span>
|
|
272
380
|
</button>
|
|
381
|
+
<button class="tab-item" type="button" data-tab="relation" aria-selected="false">
|
|
382
|
+
<svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 16.2s-5.4-3.4-5.4-7a2.9 2.9 0 015.4-1.7 2.9 2.9 0 015.4 1.7c0 3.6-5.4 7-5.4 7z"/></svg>
|
|
383
|
+
<span>关系</span>
|
|
384
|
+
</button>
|
|
273
385
|
<button class="tab-item" type="button" data-tab="settings" aria-selected="false">
|
|
274
386
|
<svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="10" cy="10" r="2.6"/><path d="M10 3.2v2M10 14.8v2M3.2 10h2M14.8 10h2M5.2 5.2l1.4 1.4M13.4 13.4l1.4 1.4M14.8 5.2l-1.4 1.4M6.6 13.4l-1.4 1.4"/></svg>
|
|
275
|
-
<span
|
|
387
|
+
<span>配置</span>
|
|
276
388
|
</button>
|
|
277
|
-
<button class="tab-item" type="button" data-tab="
|
|
278
|
-
<svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="
|
|
279
|
-
<span
|
|
389
|
+
<button class="tab-item" type="button" data-tab="tools" aria-selected="false">
|
|
390
|
+
<svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M11.6 4.4a3.2 3.2 0 00-4 4l-4.1 4.1 2 2 4.1-4.1a3.2 3.2 0 004-4l-2 2-1.6-1.6 1.6-2.4z"/></svg>
|
|
391
|
+
<span>工具</span>
|
|
280
392
|
</button>
|
|
281
|
-
|
|
393
|
+
</nav>
|
|
282
394
|
|
|
283
395
|
<div class="layout-toast" id="layoutToast" role="status" hidden></div>
|
|
284
396
|
|
|
@@ -289,6 +401,6 @@
|
|
|
289
401
|
</main>
|
|
290
402
|
<script src="panel-layout.js?v=5"></script>
|
|
291
403
|
<script src="trace-view.js?v=5"></script>
|
|
292
|
-
<script src="panel.js?v=
|
|
404
|
+
<script src="panel.js?v=6"></script>
|
|
293
405
|
</body>
|
|
294
406
|
</html>
|
package/ui/panel.js
CHANGED
|
@@ -442,8 +442,7 @@
|
|
|
442
442
|
return localPoints.slice()
|
|
443
443
|
}
|
|
444
444
|
|
|
445
|
-
function
|
|
446
|
-
var canvas = $('moodChart')
|
|
445
|
+
function drawChartInto(canvas, data) {
|
|
447
446
|
if (!canvas) return
|
|
448
447
|
var points = mergePoints(data)
|
|
449
448
|
var wrapWidth = canvas.clientWidth || canvas.parentElement.clientWidth || 600
|
|
@@ -523,7 +522,7 @@
|
|
|
523
522
|
ctx.arc(toX(eventTs), eventY, 2.6, 0, Math.PI * 2)
|
|
524
523
|
ctx.fill()
|
|
525
524
|
}
|
|
526
|
-
setText('chartHint', '单线 + ' + events.length + ' 个事件点')
|
|
525
|
+
setText(canvas.id === 'deskChart' ? 'deskChartHint' : 'chartHint', '单线 + ' + events.length + ' 个事件点')
|
|
527
526
|
} else {
|
|
528
527
|
ctx.strokeStyle = lineColor
|
|
529
528
|
ctx.lineWidth = 2
|
|
@@ -538,12 +537,183 @@
|
|
|
538
537
|
ctx.arc(padL + plotW - 3, padT + ((1 - Math.max(-1, Math.min(1, points[0].v))) / 2) * plotH, 3, 0, Math.PI * 2)
|
|
539
538
|
ctx.fill()
|
|
540
539
|
}
|
|
541
|
-
setText('chartHint', '积累中 · 单点')
|
|
540
|
+
setText(canvas.id === 'deskChart' ? 'deskChartHint' : 'chartHint', '积累中 · 单点')
|
|
542
541
|
}
|
|
543
542
|
ctx.fillStyle = mutedColor
|
|
544
543
|
ctx.fillText('24 小时', padL, wrapHeight - 5)
|
|
545
544
|
}
|
|
546
545
|
|
|
546
|
+
function renderChart(data) {
|
|
547
|
+
drawChartInto($('moodChart'), data)
|
|
548
|
+
drawChartInto($('deskChart'), data)
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
var DESK_HIDDEN_KEY = 'biocore-desk-hidden'
|
|
552
|
+
var RAIL_KEY = 'biocore-rail-collapsed'
|
|
553
|
+
|
|
554
|
+
function copyText(fromId, toId) {
|
|
555
|
+
var from = $(fromId)
|
|
556
|
+
var to = $(toId)
|
|
557
|
+
if (from && to) to.textContent = from.textContent
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
function copyBar(fromId, toId) {
|
|
561
|
+
var from = $(fromId)
|
|
562
|
+
var to = $(toId)
|
|
563
|
+
if (from && to) to.style.width = from.style.width
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/** Desktop grid mirrors the mobile DOM (single data source, no duplicate state). */
|
|
567
|
+
function deskSync(data) {
|
|
568
|
+
copyText('motivation', 'deskMotivation')
|
|
569
|
+
copyText('statusText', 'deskStatusText')
|
|
570
|
+
var mobileStatus = $('status')
|
|
571
|
+
var deskStatus = $('deskStatus')
|
|
572
|
+
if (mobileStatus && deskStatus) {
|
|
573
|
+
deskStatus.className = 'status' + (mobileStatus.classList.contains('on') ? ' on' : (mobileStatus.classList.contains('off') ? ' off' : ''))
|
|
574
|
+
}
|
|
575
|
+
copyText('num-v', 'deskNumV')
|
|
576
|
+
copyText('moodNote', 'deskWordV')
|
|
577
|
+
copyText('arrow-v', 'deskArrowV')
|
|
578
|
+
copyText('delta-v', 'deskDeltaV')
|
|
579
|
+
copyBar('bar-v', 'deskBarV')
|
|
580
|
+
copyText('num-emotion-tension', 'deskNumTension')
|
|
581
|
+
copyText('status-tension', 'deskWordTension')
|
|
582
|
+
copyText('arrow-emotion-tension', 'deskArrowTension')
|
|
583
|
+
copyText('delta-emotion-tension', 'deskDeltaTension')
|
|
584
|
+
copyBar('bar-emotion-tension', 'deskBarTension')
|
|
585
|
+
copyText('runtimeUptime', 'deskUptime')
|
|
586
|
+
copyText('runtimeTurns', 'deskTurns')
|
|
587
|
+
copyText('runtimeVector', 'deskVector')
|
|
588
|
+
copyText('capText', 'deskCapText')
|
|
589
|
+
copyBar('capFill', 'deskCapFill')
|
|
590
|
+
copyText('dataDirText', 'deskDataDir')
|
|
591
|
+
copyText('memTotal', 'deskTodayMem')
|
|
592
|
+
copyText('runtimeTurns', 'deskTodayTurns')
|
|
593
|
+
copyText('memoryHint', 'deskMemoryHint')
|
|
594
|
+
var memoryFrom = $('memoryList')
|
|
595
|
+
var memoryTo = $('deskMemoryList')
|
|
596
|
+
if (memoryFrom && memoryTo) memoryTo.innerHTML = memoryFrom.innerHTML
|
|
597
|
+
var available = data && data.available !== false
|
|
598
|
+
var intero = (available && data.intero) || {}
|
|
599
|
+
var channels = [['tension', 'deskAvgTension'], ['warmth', 'deskAvgWarmth'], ['heaviness', 'deskAvgHeaviness'], ['clarity', 'deskAvgClarity']]
|
|
600
|
+
for (var i = 0; i < channels.length; i += 1) {
|
|
601
|
+
var value = Number(intero[channels[i][0]])
|
|
602
|
+
setText(channels[i][1], Number.isFinite(value) ? fmt(value) : '—')
|
|
603
|
+
}
|
|
604
|
+
var rel = (available && data.relationship_metrics) || {}
|
|
605
|
+
setText('deskRelCloseness', available && Number.isFinite(Number(rel.closeness)) ? fmt(rel.closeness) : '—')
|
|
606
|
+
setText('deskRelTrust', available && Number.isFinite(Number(rel.trust)) ? fmt(rel.trust) : '—')
|
|
607
|
+
setText('deskRelConflict', available && Number.isFinite(Number(rel.conflict)) ? fmt(rel.conflict) : '—')
|
|
608
|
+
setText('deskTodayProactive', '—')
|
|
609
|
+
var personaBox = $('personaText')
|
|
610
|
+
var personaChars = personaBox ? String(personaBox.value || '').replace(/s+/g, '').length : 0
|
|
611
|
+
setText('deskPersona', personaChars ? '已载入' : '未载入')
|
|
612
|
+
setText('deskPersonaNote', personaChars ? (personaChars + ' 字 · 编译后只改倾向') : '还没有写人设')
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
function deskCards() {
|
|
616
|
+
return Array.prototype.slice.call(document.querySelectorAll('#deskGrid .desk-card'))
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
function deskCardId(card, index) {
|
|
620
|
+
if (!card.id) card.id = 'desk-card-' + index
|
|
621
|
+
return card.id
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
function readDeskHidden() {
|
|
625
|
+
try {
|
|
626
|
+
var raw = window.localStorage.getItem(DESK_HIDDEN_KEY)
|
|
627
|
+
var list = raw ? JSON.parse(raw) : []
|
|
628
|
+
return Array.isArray(list) ? list : []
|
|
629
|
+
} catch (e) { return [] }
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
function writeDeskHidden(list) {
|
|
633
|
+
try { window.localStorage.setItem(DESK_HIDDEN_KEY, JSON.stringify(list)) } catch (e) { /* ignore */ }
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
function applyDeskHidden() {
|
|
637
|
+
var hidden = readDeskHidden()
|
|
638
|
+
deskCards().forEach(function (card, index) {
|
|
639
|
+
card.classList.toggle('is-desk-hidden', hidden.indexOf(deskCardId(card, index)) >= 0)
|
|
640
|
+
})
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
function ensureDeskHides() {
|
|
644
|
+
deskCards().forEach(function (card, index) {
|
|
645
|
+
deskCardId(card, index)
|
|
646
|
+
if (card.querySelector('[data-desk-hide]')) return
|
|
647
|
+
var button = document.createElement('button')
|
|
648
|
+
button.type = 'button'
|
|
649
|
+
button.className = 'desk-hide'
|
|
650
|
+
button.setAttribute('data-desk-hide', '')
|
|
651
|
+
button.setAttribute('aria-label', '隐藏这张卡片')
|
|
652
|
+
button.textContent = '−'
|
|
653
|
+
card.appendChild(button)
|
|
654
|
+
})
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
function deskLabel(card) {
|
|
658
|
+
var named = card.getAttribute('data-card-label')
|
|
659
|
+
if (named) return named
|
|
660
|
+
var title = card.querySelector('h2')
|
|
661
|
+
return title ? title.textContent.trim() : card.id
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
function restoreDeskCard(id) {
|
|
665
|
+
writeDeskHidden(readDeskHidden().filter(function (item) { return item !== id }))
|
|
666
|
+
applyDeskHidden()
|
|
667
|
+
renderAddCards()
|
|
668
|
+
layoutToast('已恢复卡片')
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
function onDeskEditClick(event) {
|
|
672
|
+
var target = event.target
|
|
673
|
+
var add = target && target.closest ? target.closest('[data-desk-add]') : null
|
|
674
|
+
if (add) {
|
|
675
|
+
event.preventDefault()
|
|
676
|
+
restoreDeskCard(add.getAttribute('data-desk-add'))
|
|
677
|
+
return
|
|
678
|
+
}
|
|
679
|
+
var hide = target && target.closest ? target.closest('[data-desk-hide]') : null
|
|
680
|
+
if (!hide) return
|
|
681
|
+
event.preventDefault()
|
|
682
|
+
var card = hide.closest('.desk-card')
|
|
683
|
+
if (!card) return
|
|
684
|
+
var hidden = readDeskHidden()
|
|
685
|
+
var id = card.id
|
|
686
|
+
if (hidden.indexOf(id) < 0) hidden.push(id)
|
|
687
|
+
writeDeskHidden(hidden)
|
|
688
|
+
applyDeskHidden()
|
|
689
|
+
renderAddCards()
|
|
690
|
+
layoutToast('已隐藏「' + deskLabel(card) + '」')
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
function railApply(collapsed) {
|
|
694
|
+
document.body.classList.toggle('rail-collapsed', !!collapsed)
|
|
695
|
+
var button = $('railToggle')
|
|
696
|
+
if (!button) return
|
|
697
|
+
var label = collapsed ? '展开导航' : '收起导航'
|
|
698
|
+
button.setAttribute('aria-expanded', String(!collapsed))
|
|
699
|
+
button.setAttribute('aria-label', label)
|
|
700
|
+
button.setAttribute('title', label)
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
function railInit() {
|
|
704
|
+
var storage = layoutStorage()
|
|
705
|
+
var collapsed = false
|
|
706
|
+
try { collapsed = !!storage && storage.getItem(RAIL_KEY) === '1' } catch (e) { collapsed = false }
|
|
707
|
+
railApply(collapsed)
|
|
708
|
+
var button = $('railToggle')
|
|
709
|
+
if (!button) return
|
|
710
|
+
button.addEventListener('click', function () {
|
|
711
|
+
var next = !document.body.classList.contains('rail-collapsed')
|
|
712
|
+
railApply(next)
|
|
713
|
+
try { if (storage) storage.setItem(RAIL_KEY, next ? '1' : '0') } catch (e) { /* ignore */ }
|
|
714
|
+
})
|
|
715
|
+
}
|
|
716
|
+
|
|
547
717
|
function updateFooter(data) {
|
|
548
718
|
var memory = data && data.available !== false && typeof data.memory_count === 'number'
|
|
549
719
|
? data.memory_count : '-'
|
|
@@ -560,6 +730,8 @@
|
|
|
560
730
|
renderRuntime(data)
|
|
561
731
|
renderChart(data)
|
|
562
732
|
updateFooter(data)
|
|
733
|
+
deskSync(data)
|
|
734
|
+
deskSync(data)
|
|
563
735
|
if (!data) renderEmpty('request_failed')
|
|
564
736
|
else if (data.available === false) renderEmpty(String(data.reason || 'request_failed'))
|
|
565
737
|
else clearEmpty()
|
|
@@ -611,16 +783,20 @@
|
|
|
611
783
|
}
|
|
612
784
|
|
|
613
785
|
function paintSwitchState(key, checked) {
|
|
614
|
-
var
|
|
615
|
-
|
|
786
|
+
var states = document.querySelectorAll('[data-switch-state="' + key + '"]')
|
|
787
|
+
for (var i = 0; i < states.length; i += 1) states[i].textContent = '当前:' + (checked ? '开' : '关')
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
function setSwitchInputs(key, checked) {
|
|
791
|
+
var inputs = document.querySelectorAll('input[data-switch="' + key + '"]')
|
|
792
|
+
for (var i = 0; i < inputs.length; i += 1) inputs[i].checked = !!checked
|
|
793
|
+
paintSwitchState(key, checked)
|
|
616
794
|
}
|
|
617
795
|
|
|
618
796
|
function applySwitchValues(values) {
|
|
619
797
|
for (var i = 0; i < SWITCHES.length; i += 1) {
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
input.checked = values[SWITCHES[i].key]
|
|
623
|
-
paintSwitchState(SWITCHES[i].key, input.checked)
|
|
798
|
+
if (values && typeof values[SWITCHES[i].key] === 'boolean') {
|
|
799
|
+
setSwitchInputs(SWITCHES[i].key, values[SWITCHES[i].key])
|
|
624
800
|
}
|
|
625
801
|
}
|
|
626
802
|
}
|
|
@@ -673,14 +849,12 @@
|
|
|
673
849
|
applySwitchValues(body.switches)
|
|
674
850
|
setText('switchHint', '已写入宿主设置')
|
|
675
851
|
} else {
|
|
676
|
-
|
|
677
|
-
paintSwitchState(key, input.checked)
|
|
852
|
+
setSwitchInputs(key, !next)
|
|
678
853
|
setText('switchHint', '写入失败:' + ((body && body.reason) || 'unknown'))
|
|
679
854
|
}
|
|
680
855
|
})
|
|
681
856
|
.catch(function () {
|
|
682
|
-
|
|
683
|
-
paintSwitchState(key, input.checked)
|
|
857
|
+
setSwitchInputs(key, !next)
|
|
684
858
|
setText('switchHint', '写入失败:未连接')
|
|
685
859
|
})
|
|
686
860
|
.then(function () {
|
|
@@ -1270,15 +1444,18 @@
|
|
|
1270
1444
|
if (!layoutApi) return
|
|
1271
1445
|
var group = layoutEditing ? null : (layoutApi.TAB_GROUPS[activeTab] || [])
|
|
1272
1446
|
var panel = $('panel')
|
|
1273
|
-
if (panel)
|
|
1447
|
+
if (panel) {
|
|
1448
|
+
var tabsKnown = ['dashboard', 'memory', 'relation', 'settings', 'tools']
|
|
1449
|
+
for (var t = 0; t < tabsKnown.length; t += 1) {
|
|
1450
|
+
panel.classList.toggle('tab-' + tabsKnown[t], activeTab === tabsKnown[t])
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1274
1453
|
var cards = layoutCards()
|
|
1275
1454
|
for (var i = 0; i < cards.length; i += 1) {
|
|
1276
1455
|
var id = cards[i].getAttribute('data-card-id')
|
|
1277
1456
|
cards[i].classList.toggle('tab-hidden', !!group && group.indexOf(id) < 0)
|
|
1278
1457
|
}
|
|
1279
|
-
var
|
|
1280
|
-
if (!bar) return
|
|
1281
|
-
var items = bar.querySelectorAll('[data-tab]')
|
|
1458
|
+
var items = document.querySelectorAll('[data-tab]')
|
|
1282
1459
|
for (var j = 0; j < items.length; j += 1) {
|
|
1283
1460
|
var on = items[j].getAttribute('data-tab') === activeTab
|
|
1284
1461
|
items[j].classList.toggle('active', on)
|
|
@@ -1286,17 +1463,19 @@
|
|
|
1286
1463
|
}
|
|
1287
1464
|
}
|
|
1288
1465
|
|
|
1466
|
+
function setActiveTab(tab) {
|
|
1467
|
+
if (!layoutApi || !layoutApi.TAB_GROUPS[tab]) return
|
|
1468
|
+
activeTab = tab
|
|
1469
|
+
applyTabGroup()
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1289
1472
|
function bindTabBar() {
|
|
1290
|
-
|
|
1291
|
-
if (!bar) return
|
|
1292
|
-
bar.addEventListener('click', function (event) {
|
|
1473
|
+
document.addEventListener('click', function (event) {
|
|
1293
1474
|
var target = event.target
|
|
1294
1475
|
var button = target && target.closest ? target.closest('[data-tab]') : null
|
|
1295
1476
|
if (!button) return
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
activeTab = tab
|
|
1299
|
-
applyTabGroup()
|
|
1477
|
+
event.preventDefault()
|
|
1478
|
+
setActiveTab(button.getAttribute('data-tab'))
|
|
1300
1479
|
})
|
|
1301
1480
|
applyTabGroup()
|
|
1302
1481
|
}
|
|
@@ -1354,6 +1533,8 @@
|
|
|
1354
1533
|
if (reset) reset.hidden = !layoutEditing
|
|
1355
1534
|
var cards = layoutCards()
|
|
1356
1535
|
for (var i = 0; i < cards.length; i += 1) ensureHideButton(cards[i])
|
|
1536
|
+
ensureDeskHides()
|
|
1537
|
+
applyDeskHidden()
|
|
1357
1538
|
renderAddCards()
|
|
1358
1539
|
applyTabGroup()
|
|
1359
1540
|
if (!layoutEditing) persistDomOrder()
|
|
@@ -1396,7 +1577,11 @@
|
|
|
1396
1577
|
return
|
|
1397
1578
|
}
|
|
1398
1579
|
var hidden = hiddenCards()
|
|
1399
|
-
|
|
1580
|
+
var deskHidden = readDeskHidden()
|
|
1581
|
+
var deskHiddenCards = deskCards().filter(function (card, index) {
|
|
1582
|
+
return deskHidden.indexOf(deskCardId(card, index)) >= 0
|
|
1583
|
+
})
|
|
1584
|
+
if (!hidden.length && !deskHiddenCards.length) {
|
|
1400
1585
|
section.hidden = true
|
|
1401
1586
|
list.textContent = ''
|
|
1402
1587
|
return
|
|
@@ -1411,6 +1596,14 @@
|
|
|
1411
1596
|
chip.textContent = '+ ' + hidden[i].label
|
|
1412
1597
|
list.appendChild(chip)
|
|
1413
1598
|
}
|
|
1599
|
+
for (var d = 0; d < deskHiddenCards.length; d += 1) {
|
|
1600
|
+
var deskChip = document.createElement('button')
|
|
1601
|
+
deskChip.type = 'button'
|
|
1602
|
+
deskChip.className = 'add-chip'
|
|
1603
|
+
deskChip.setAttribute('data-desk-add', deskCardId(deskHiddenCards[d], 0))
|
|
1604
|
+
deskChip.textContent = '+ ' + deskLabel(deskHiddenCards[d])
|
|
1605
|
+
list.appendChild(deskChip)
|
|
1606
|
+
}
|
|
1414
1607
|
}
|
|
1415
1608
|
|
|
1416
1609
|
function showHiddenCard(id) {
|
|
@@ -1583,9 +1776,13 @@
|
|
|
1583
1776
|
document.addEventListener('pointermove', onCardsPointerMove, { passive: false })
|
|
1584
1777
|
document.addEventListener('pointerup', onCardsPointerUp)
|
|
1585
1778
|
document.addEventListener('pointercancel', onCardsPointerUp)
|
|
1779
|
+
ensureDeskHides()
|
|
1780
|
+
applyDeskHidden()
|
|
1781
|
+
document.addEventListener('click', onDeskEditClick)
|
|
1586
1782
|
}
|
|
1587
1783
|
|
|
1588
1784
|
function boot() {
|
|
1785
|
+
railInit()
|
|
1589
1786
|
initLayout()
|
|
1590
1787
|
bindAdvanced()
|
|
1591
1788
|
bindPersona()
|