wezard 1.4.2 → 2.0.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/CLAUDE.md +12 -7
- package/README.md +121 -67
- package/dist/daemon/approval.js +9 -3
- package/dist/daemon/approval.js.map +1 -1
- package/dist/daemon/cc-bridge.js.map +1 -1
- package/dist/daemon/chat-name.js +8 -18
- package/dist/daemon/chat-name.js.map +1 -1
- package/dist/daemon/detail.js +53 -12
- package/dist/daemon/detail.js.map +1 -1
- package/dist/daemon/graph.js +5 -7
- package/dist/daemon/graph.js.map +1 -1
- package/dist/daemon/inbound.js +135 -158
- package/dist/daemon/inbound.js.map +1 -1
- package/dist/daemon/index.js +381 -192
- package/dist/daemon/index.js.map +1 -1
- package/dist/daemon/jobs.js +2 -2
- package/dist/daemon/mirror-bridge.js +221 -134
- package/dist/daemon/mirror-bridge.js.map +1 -1
- package/dist/daemon/mirror-store.js.map +1 -1
- package/dist/daemon/model-select.js +74 -0
- package/dist/daemon/model-select.js.map +1 -0
- package/dist/daemon/peers.js +10 -16
- package/dist/daemon/peers.js.map +1 -1
- package/dist/daemon/spawn-tmux.js +27 -4
- package/dist/daemon/spawn-tmux.js.map +1 -1
- package/dist/daemon/task-gate.js +97 -0
- package/dist/daemon/task-gate.js.map +1 -0
- package/dist/daemon/task-registry.js +132 -0
- package/dist/daemon/task-registry.js.map +1 -0
- package/dist/daemon/tasks.js +126 -54
- package/dist/daemon/tasks.js.map +1 -1
- package/dist/daemon/wizard-memory.js +57 -0
- package/dist/daemon/wizard-memory.js.map +1 -0
- package/dist/daemon/wizard.js +84 -38
- package/dist/daemon/wizard.js.map +1 -1
- package/dist/mcp/server.js +138 -76
- package/dist/mcp/server.js.map +1 -1
- package/dist/shared/chat-http.js +185 -108
- package/dist/shared/chat-http.js.map +1 -1
- package/dist/shared/chat-render.js +26 -34
- package/dist/shared/chat-render.js.map +1 -1
- package/dist/shared/chat-view.js +14 -2
- package/dist/shared/chat-view.js.map +1 -1
- package/dist/shared/config.js +23 -4
- package/dist/shared/config.js.map +1 -1
- package/dist/shared/detail-render.js +12 -6
- package/dist/shared/detail-render.js.map +1 -1
- package/dist/shared/detail-store.js.map +1 -1
- package/dist/shared/role-render.js +52 -0
- package/dist/shared/role-render.js.map +1 -0
- package/dist/shared/role-view.js +210 -0
- package/dist/shared/role-view.js.map +1 -0
- package/dist/shared/schedule-spec.js +92 -116
- package/dist/shared/schedule-spec.js.map +1 -1
- package/dist/shared/session-label.js +103 -72
- package/dist/shared/session-label.js.map +1 -1
- package/dist/shared/std.js +3 -0
- package/dist/shared/std.js.map +1 -1
- package/dist/shared/task-file.js +120 -0
- package/dist/shared/task-file.js.map +1 -0
- package/dist/shared/trigger.js +232 -0
- package/dist/shared/trigger.js.map +1 -0
- package/dist/shared/world.js +7 -5
- package/dist/shared/world.js.map +1 -1
- package/dist/svr/index.js +67 -2
- package/dist/svr/index.js.map +1 -1
- package/package.json +1 -1
- package/web/chat.css +407 -212
- package/web/chat.js +932 -321
package/web/chat.css
CHANGED
|
@@ -1,140 +1,293 @@
|
|
|
1
|
-
/*
|
|
2
|
-
由 /chat/app.css 拼在本文件之前 ——
|
|
1
|
+
/* Rolepage 外壳。消息正文 (turn 卡片) 的样式来自 detail-render 的 SHARED_CSS/TURN_CSS,
|
|
2
|
+
由 /chat/app.css 拼在本文件之前 —— 这里管骨架、会话列表、左右气泡与页脚总账。
|
|
3
|
+
视觉只押一处: 「视角」。我说的靠右、染成视角色; 别人说的靠左、带头像; 气泡对面
|
|
4
|
+
那片空白是一道门 —— 点下去就换成对方的视角。其余一律安静。 */
|
|
5
|
+
|
|
6
|
+
:root {
|
|
7
|
+
--paper: #eef1f5; /* 对话底 —— 冷灰, 让白色与视角色的两种气泡都站得住 */
|
|
8
|
+
--card: #fff;
|
|
9
|
+
--ink: #1c2430;
|
|
10
|
+
--mute: #6a7483;
|
|
11
|
+
--faint: #9aa3af;
|
|
12
|
+
--line: #d9dee6;
|
|
13
|
+
--mine: #eef3fd; /* 当前视角说的话 */
|
|
14
|
+
--mine-soft: #e2eafa; /* 它内部还要再沉一档的块 (代码/结果/折叠头) */
|
|
15
|
+
--mine-line: #c9d7f3;
|
|
16
|
+
--accent: #2f55c9; /* 视角色: 名字的点、选中态、自己的气泡描边 */
|
|
17
|
+
--priv: #9a5b10; /* 私聊 */
|
|
18
|
+
--pub: #237a55; /* 公开 */
|
|
19
|
+
}
|
|
3
20
|
|
|
4
21
|
html, body { height: 100% }
|
|
5
22
|
/* overscroll-behavior:none 阻止整页橡皮筋回弹 —— webview 里它会和内层
|
|
6
23
|
.thread 抢滚动手势, 表现为"滚一下卡住/整页在弹"。 */
|
|
7
|
-
body { overflow: hidden; overscroll-behavior: none }
|
|
24
|
+
body { overflow: hidden; overscroll-behavior: none; color: var(--ink) }
|
|
25
|
+
button { font: inherit; color: inherit }
|
|
26
|
+
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px }
|
|
8
27
|
|
|
9
28
|
.app { display: flex; height: 100vh; height: 100dvh }
|
|
29
|
+
@keyframes pulse { 0%, 100% { opacity: 1 } 50% { opacity: .3 } }
|
|
30
|
+
|
|
31
|
+
/* 名字 = 地址。点是地址的一部分, 也是这一页唯一的颜色记号。 */
|
|
32
|
+
.nm { font-weight: 600 }
|
|
33
|
+
.nm::before { content: "."; color: var(--accent); font-weight: 700 }
|
|
34
|
+
.nm.human::before, .nm.task::before, .nm.chat::before { content: none }
|
|
10
35
|
|
|
11
|
-
/* ── 侧栏:
|
|
36
|
+
/* ── 侧栏: 我 + 会话 ─────────────────────────────────────────────── */
|
|
12
37
|
.side {
|
|
13
|
-
width:
|
|
38
|
+
width: 312px; flex: none; background: var(--card); border-right: 1px solid var(--line);
|
|
14
39
|
display: flex; flex-direction: column; min-height: 0;
|
|
15
40
|
}
|
|
16
|
-
.side-head { padding: 13px 16px 11px; border-bottom: 1px solid #eaeef2 }
|
|
17
|
-
.side-head .l1 { display: flex; align-items: baseline; gap: 8px }
|
|
18
|
-
.side-head .t { font-size: 14px; font-weight: 600 }
|
|
19
|
-
.side-head .n {
|
|
20
|
-
margin-left: auto; font-size: 11px; color: #8c959f;
|
|
21
|
-
font-variant-numeric: tabular-nums;
|
|
22
|
-
}
|
|
23
|
-
.side-head .s {
|
|
24
|
-
font-size: 11px; color: #8c959f; font-family: ui-monospace, Menlo, monospace;
|
|
25
|
-
word-break: break-all; margin-top: 3px;
|
|
26
|
-
}
|
|
27
41
|
|
|
28
|
-
|
|
42
|
+
/* ── 左栏顶: 当前 role 的名片 (身份 + 关系/日程入口) ──── */
|
|
43
|
+
.rolebar {
|
|
44
|
+
position: relative; flex: none; padding: 16px 16px 14px; border-bottom: 1px solid var(--line);
|
|
45
|
+
display: flex; flex-direction: column; gap: 8px; background: var(--card);
|
|
46
|
+
}
|
|
47
|
+
.rolebar .conn { position: absolute; top: 12px; right: 14px }
|
|
48
|
+
.rolebar .id { display: flex; gap: 10px; align-items: center; min-width: 0; padding-right: 14px }
|
|
49
|
+
.rolebar .id .av { font-size: 26px; line-height: 1; flex: none }
|
|
50
|
+
.rolebar .id .l { min-width: 0; display: flex; flex-direction: column; gap: 2px }
|
|
51
|
+
.rolebar .id .nm { font-size: 18px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
|
|
52
|
+
.rolebar .id .k { font-size: 11.5px; color: var(--mute) }
|
|
53
|
+
.rolebar .job { margin: 0; font-size: 12.5px; line-height: 1.5; color: var(--ink); opacity: .8 }
|
|
54
|
+
.rolebar .facts { display: flex; gap: 6px 12px; flex-wrap: wrap; font-size: 11.5px; color: var(--mute) }
|
|
55
|
+
.rolebar .facts span { white-space: nowrap }
|
|
56
|
+
.rolebar .facts .go { cursor: pointer; color: var(--accent) }
|
|
57
|
+
.rolebar .facts .go:hover { text-decoration: underline }
|
|
58
|
+
.rolebar .acts { display: flex; gap: 6px; flex-wrap: wrap; align-items: center }
|
|
59
|
+
.rolebar .acts:empty { display: none }
|
|
60
|
+
/* session 切换: 按钮 + 浮层列表, 取代原生 <select>。 */
|
|
61
|
+
.sp { position: relative; flex: 1 1 100%; min-width: 0 }
|
|
62
|
+
.sp-btn {
|
|
63
|
+
width: 100%; display: flex; align-items: center; gap: 8px; cursor: pointer; text-align: left;
|
|
64
|
+
font-size: 12px; background: var(--card); border: 1px solid var(--line); border-radius: 8px; padding: 5px 10px;
|
|
65
|
+
transition: border-color .12s, box-shadow .12s;
|
|
66
|
+
}
|
|
67
|
+
.sp-btn:hover, .sp.open .sp-btn { border-color: var(--accent) }
|
|
68
|
+
.sp.open .sp-btn { box-shadow: 0 0 0 3px #2f55c91f }
|
|
69
|
+
.sp-btn .lb { font-size: 10px; color: var(--faint); text-transform: uppercase; letter-spacing: .4px; flex: none }
|
|
70
|
+
.sp-btn .v { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-variant-numeric: tabular-nums }
|
|
71
|
+
.sp-btn .car {
|
|
72
|
+
flex: none; width: 6px; height: 6px; margin: -3px 2px 0 0; border: solid var(--mute); border-width: 0 1.5px 1.5px 0;
|
|
73
|
+
transform: rotate(45deg); transition: transform .15s;
|
|
74
|
+
}
|
|
75
|
+
.sp.open .sp-btn .car { transform: rotate(-135deg); margin-top: 3px }
|
|
76
|
+
.sp-list {
|
|
77
|
+
position: absolute; z-index: 20; left: 0; right: 0; top: calc(100% + 4px);
|
|
78
|
+
max-height: 280px; overflow-y: auto; overscroll-behavior: contain;
|
|
79
|
+
background: var(--card); border: 1px solid var(--line); border-radius: 10px; padding: 4px;
|
|
80
|
+
box-shadow: 0 8px 24px #1c24301f, 0 2px 6px #1c24300f;
|
|
81
|
+
opacity: 0; transform: translateY(-4px); pointer-events: none; transition: opacity .12s, transform .12s;
|
|
82
|
+
}
|
|
83
|
+
.sp.open .sp-list { opacity: 1; transform: none; pointer-events: auto }
|
|
84
|
+
.sp-it {
|
|
85
|
+
width: 100%; display: grid; grid-template-columns: auto 1fr auto; gap: 10px; align-items: baseline;
|
|
86
|
+
background: none; border: 0; border-radius: 6px; padding: 6px 8px; cursor: pointer; text-align: left; font-size: 12px;
|
|
87
|
+
}
|
|
88
|
+
.sp-it:hover { background: var(--paper) }
|
|
89
|
+
.sp-it.on { background: var(--mine); color: var(--accent) }
|
|
90
|
+
.sp-it .id { font-family: ui-monospace, Menlo, monospace; font-weight: 600 }
|
|
91
|
+
.sp-it .ago { color: var(--mute) }
|
|
92
|
+
.sp-it .n { color: var(--faint); font-variant-numeric: tabular-nums; grid-column: 3 }
|
|
93
|
+
.sp-it.all { border-bottom: 1px solid var(--line); border-radius: 6px 6px 0 0; margin-bottom: 3px }
|
|
94
|
+
.sp-it.all .id { font-family: inherit }
|
|
29
95
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
.
|
|
39
|
-
|
|
40
|
-
width: 3px; border-radius: 2px; background: #0969da;
|
|
41
|
-
}
|
|
96
|
+
/* 左栏底: session 切换 + 用量, 都是轮次的事 —— 与顶上的身份分开, 钉在会话列表下面。 */
|
|
97
|
+
.sidefoot {
|
|
98
|
+
flex: none; border-top: 1px solid var(--line); padding: 10px 12px 12px;
|
|
99
|
+
display: flex; flex-direction: column; gap: 8px; background: var(--paper);
|
|
100
|
+
}
|
|
101
|
+
.sidefoot[hidden] { display: none }
|
|
102
|
+
#rb-sess:empty, #rb-prof:empty { display: none }
|
|
103
|
+
/* 在底部, 浮层往上开。 */
|
|
104
|
+
.sidefoot .sp-list { top: auto; bottom: calc(100% + 4px); transform: translateY(4px) }
|
|
105
|
+
.sidefoot .sp.open .sp-list { transform: none }
|
|
42
106
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
|
|
107
|
+
/* profile: 这个 role 自己跑过的轮次的总账 —— 平铺在左栏底, 不套卡片。 */
|
|
108
|
+
.prof { font-family: ui-monospace, Menlo, monospace }
|
|
109
|
+
.prof .hd { display: flex; align-items: center; gap: 8px; font-size: 11.5px; margin-bottom: 6px }
|
|
110
|
+
.prof .hd .lb { font-size: 10px; color: var(--faint); text-transform: uppercase; letter-spacing: .4px; font-family: system-ui, sans-serif }
|
|
111
|
+
.prof .model {
|
|
112
|
+
margin-left: auto; color: var(--mute);
|
|
113
|
+
max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
114
|
+
}
|
|
115
|
+
.prof .grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px 4px }
|
|
116
|
+
.prof .kv { display: flex; flex-direction: column; align-items: flex-start; min-width: 0 }
|
|
117
|
+
.prof .kv .v { font-size: 13px; font-weight: 700; color: #1f2328; font-variant-numeric: tabular-nums; white-space: nowrap }
|
|
118
|
+
.prof .kv .k { font-size: 9.5px; color: #8c959f; text-transform: uppercase; letter-spacing: .4px }
|
|
119
|
+
.prof .io { margin-top: 8px; display: flex; flex-direction: column; gap: 6px }
|
|
120
|
+
.prof .bar { display: flex; height: 6px; border-radius: 3px; overflow: hidden; background: #eaeef2 }
|
|
121
|
+
.prof .bar .seg { height: 100% }
|
|
122
|
+
.prof .leg { display: flex; gap: 4px 9px; flex-wrap: wrap }
|
|
123
|
+
.prof .lg { display: flex; align-items: center; gap: 4px; font-size: 10.5px; color: #8c959f }
|
|
124
|
+
.prof .lg i { width: 8px; height: 8px; border-radius: 2px; flex: none }
|
|
125
|
+
.prof .lg b { color: #1f2328; font-weight: 700; font-variant-numeric: tabular-nums }
|
|
126
|
+
.conn { display: flex; align-items: center; gap: 5px }
|
|
127
|
+
.conn .d { width: 7px; height: 7px; border-radius: 50%; background: #1a7f37 }
|
|
128
|
+
.conn.off .d { background: #cf222e }
|
|
54
129
|
|
|
55
|
-
|
|
56
|
-
.
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
.
|
|
62
|
-
.
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
/* 每行第三层: 轮数 / 工具数 / token —— 不点进去也能判断哪个会话在真干活。 */
|
|
72
|
-
.tag-meta {
|
|
73
|
-
display: flex; gap: 4px; align-items: center; margin-top: 4px;
|
|
74
|
-
font-size: 10.5px; color: #8c959f; font-family: ui-monospace, Menlo, monospace;
|
|
75
|
-
font-variant-numeric: tabular-nums;
|
|
76
|
-
}
|
|
77
|
-
.tag-meta .sep { opacity: .45 }
|
|
78
|
-
.tag-meta .hot { color: #9a6700 }
|
|
79
|
-
.tags .empty-side { padding: 28px 12px; text-align: center; color: #8c959f; font-size: 12px }
|
|
80
|
-
|
|
81
|
-
/* ── 主区 ───────────────────────────────────────────────────────── */
|
|
82
|
-
/* min-height:0 给纵向 flex (mobile) 用: 缺了它 .main 的 min-height:auto 会被
|
|
83
|
-
内容撑破 100dvh, .thread 不产生内部滚动, 底部被 body overflow:hidden 裁掉。
|
|
84
|
-
横向 (桌面) 下无副作用 —— 高度本来就由 stretch 定死。 */
|
|
85
|
-
.main { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column }
|
|
86
|
-
.topbar {
|
|
87
|
-
flex: none; display: flex; align-items: center; gap: 10px; padding: 11px 20px;
|
|
88
|
-
background: #fff; border-bottom: 1px solid #d0d7de;
|
|
89
|
-
}
|
|
90
|
-
.topbar .em { font-size: 18px }
|
|
91
|
-
.topbar .h { font-size: 15px; font-weight: 600; font-family: ui-monospace, Menlo, monospace }
|
|
92
|
-
.topbar .cwd {
|
|
93
|
-
flex: none; font-size: 11px; color: #57606a; font-family: ui-monospace, Menlo, monospace;
|
|
94
|
-
background: #f6f8fa; border: 1px solid #eaeef2; border-radius: 5px; padding: 1px 6px;
|
|
95
|
-
max-width: 42%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
96
|
-
}
|
|
97
|
-
.topbar .sub {
|
|
98
|
-
font-size: 11px; color: #8c959f; font-family: ui-monospace, Menlo, monospace;
|
|
99
|
-
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
130
|
+
/* 群聊头像 = 参与者头像拼图: 1 格居中, 2 格左右, 3/4 格田字。 */
|
|
131
|
+
.mosaic {
|
|
132
|
+
display: grid !important; width: 34px; height: 34px; border-radius: 10px; overflow: hidden; flex: none;
|
|
133
|
+
background: #eef1f6; border: 1px solid var(--line); gap: 1px; padding: 1px;
|
|
134
|
+
font-size: 13px !important; line-height: 1 !important;
|
|
135
|
+
}
|
|
136
|
+
.mosaic i { font-style: normal; display: grid; place-items: center; background: #fff; min-width: 0; min-height: 0 }
|
|
137
|
+
.mosaic.n1 { grid-template: 1fr / 1fr; font-size: 20px !important }
|
|
138
|
+
.mosaic.n2 { grid-template: 1fr / 1fr 1fr; font-size: 14px !important }
|
|
139
|
+
.mosaic.n3, .mosaic.n4 { grid-template: 1fr 1fr / 1fr 1fr }
|
|
140
|
+
.mosaic.n3 i:first-child { grid-row: span 2 }
|
|
141
|
+
|
|
142
|
+
.convs { flex: 1; min-height: 0; overflow-y: auto; padding: 4px 8px 16px }
|
|
143
|
+
.convs h2 {
|
|
144
|
+
margin: 14px 8px 4px; font-size: 12px; font-weight: 600; color: var(--mute);
|
|
145
|
+
display: flex; align-items: baseline; gap: 6px;
|
|
100
146
|
}
|
|
101
|
-
.
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
.
|
|
112
|
-
.
|
|
113
|
-
.
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
.
|
|
118
|
-
.
|
|
119
|
-
.
|
|
120
|
-
.
|
|
121
|
-
.
|
|
122
|
-
|
|
123
|
-
/*
|
|
124
|
-
.
|
|
147
|
+
.convs h2 span { font-weight: 400; color: var(--faint); font-variant-numeric: tabular-nums }
|
|
148
|
+
.convs .none { padding: 6px 10px; font-size: 12px; color: var(--faint) }
|
|
149
|
+
|
|
150
|
+
.ci {
|
|
151
|
+
display: flex; gap: 10px; align-items: flex-start; width: 100%; text-align: left; overflow: hidden;
|
|
152
|
+
padding: 8px 10px; border: 0; border-radius: 9px; background: transparent; cursor: pointer;
|
|
153
|
+
}
|
|
154
|
+
.ci:hover { background: #f4f6f9 }
|
|
155
|
+
.ci.on { background: #eaf0fc }
|
|
156
|
+
.ci { align-items: center }
|
|
157
|
+
.ci > .av { font-size: 22px; line-height: 1; flex: none; width: 34px; text-align: center }
|
|
158
|
+
.ci .b { min-width: 0; flex: 1; overflow: hidden }
|
|
159
|
+
.ci .pv, .ci .l1 { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
|
|
160
|
+
.ci .l1 { display: flex }
|
|
161
|
+
.ci .l1 { display: flex; align-items: baseline; gap: 6px }
|
|
162
|
+
.ci .t { font-size: 13.5px; font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
|
|
163
|
+
.ci .ts { margin-left: auto; flex: none; font-size: 11px; color: var(--faint); font-variant-numeric: tabular-nums }
|
|
164
|
+
.ci .pv { font-size: 12px; color: var(--mute); overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
|
|
165
|
+
.ci .pv:empty { display: none }
|
|
166
|
+
.ci .tag { font-size: 10.5px; border-radius: 4px; padding: 0 4px; flex: none }
|
|
167
|
+
.ci .tag.priv { color: var(--priv); background: #9a5b1014 }
|
|
168
|
+
|
|
169
|
+
/* 群里的其他 role —— 缩进挂在群下, 点开是「我与它在这个群里」的往来。 */
|
|
170
|
+
.subs { margin: 0 0 6px 34px; border-left: 1px solid var(--line); padding-left: 6px }
|
|
171
|
+
.si {
|
|
172
|
+
display: flex; align-items: center; gap: 7px; width: 100%; text-align: left;
|
|
173
|
+
padding: 4px 8px; border: 0; border-radius: 7px; background: transparent; cursor: pointer;
|
|
174
|
+
font-size: 12.5px; color: var(--ink);
|
|
175
|
+
}
|
|
176
|
+
.si:hover { background: #f4f6f9 }
|
|
177
|
+
.si.on { background: #eaf0fc; color: var(--accent) }
|
|
178
|
+
.si .n { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
|
|
179
|
+
.si .c { margin-left: auto; font-size: 11px; color: var(--faint); font-variant-numeric: tabular-nums }
|
|
180
|
+
.si.quiet { color: var(--faint) }
|
|
181
|
+
|
|
182
|
+
/* ── 右栏头: 这个群聊 / 私聊是什么 ───────────────────────────────── */
|
|
183
|
+
.main { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; background: var(--paper) }
|
|
184
|
+
.chathead {
|
|
185
|
+
flex: none; display: flex; align-items: center; gap: 12px; padding: 10px 20px; min-height: 58px;
|
|
186
|
+
background: var(--card); border-bottom: 1px solid var(--line);
|
|
187
|
+
}
|
|
188
|
+
.chathead .back { display: none; border: 0; background: none; font-size: 22px; color: var(--mute); cursor: pointer; padding: 0 4px }
|
|
189
|
+
.ch-who { display: flex; gap: 11px; align-items: center; min-width: 0; flex: 1 }
|
|
190
|
+
.ch-who > .av:not(.mosaic) { font-size: 26px; line-height: 1; flex: none }
|
|
191
|
+
.ch-who .l { min-width: 0; display: flex; flex-direction: column; gap: 1px }
|
|
192
|
+
.ch-who .t { font-size: 16px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
|
|
193
|
+
.ch-who > .t { flex: none }
|
|
194
|
+
.ch-who .sub { font-size: 11.5px; color: var(--mute); overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
|
|
195
|
+
.ch-acts { display: flex; gap: 8px; align-items: center; flex: none; font-size: 12px; color: var(--mute) }
|
|
196
|
+
.vb {
|
|
197
|
+
font-size: 12.5px; background: var(--card); border: 1px solid var(--line); border-radius: 7px;
|
|
198
|
+
padding: 4px 11px; cursor: pointer; white-space: nowrap;
|
|
199
|
+
}
|
|
200
|
+
.vb:hover { border-color: var(--accent); color: var(--accent) }
|
|
201
|
+
.vb.on { background: var(--accent); border-color: var(--accent); color: #fff }
|
|
202
|
+
.vb b { font-weight: 600; margin-left: 3px; font-variant-numeric: tabular-nums }
|
|
125
203
|
|
|
204
|
+
/* ── 消息 ─────────────────────────────────────────────────────────── */
|
|
126
205
|
.thread {
|
|
127
206
|
flex: 1; min-height: 0; overflow-y: auto; overflow-anchor: none;
|
|
128
|
-
padding: 16px 20px
|
|
129
|
-
overscroll-behavior: contain;
|
|
207
|
+
padding: 16px 20px 28px; -webkit-overflow-scrolling: touch; overscroll-behavior: contain;
|
|
130
208
|
}
|
|
131
|
-
.thread-in { max-width:
|
|
132
|
-
.empty { color:
|
|
209
|
+
.thread-in { max-width: 960px; margin: 0 auto; display: flex; flex-direction: column; gap: 14px }
|
|
210
|
+
.empty { color: var(--faint); text-align: center; padding: 60px 0; font-size: 13px }
|
|
133
211
|
.more-btn {
|
|
134
|
-
align-self: center; background:
|
|
135
|
-
padding: 5px 16px; font-size: 12px; color:
|
|
212
|
+
align-self: center; background: var(--card); border: 1px solid var(--line); border-radius: 16px;
|
|
213
|
+
padding: 5px 16px; font-size: 12px; color: var(--mute); cursor: pointer;
|
|
214
|
+
}
|
|
215
|
+
.more-btn:hover { color: var(--accent); border-color: var(--accent) }
|
|
216
|
+
|
|
217
|
+
.mrow { display: flex; align-items: flex-start; gap: 10px }
|
|
218
|
+
.mrow .av {
|
|
219
|
+
flex: none; width: 34px; height: 34px; border-radius: 50%; border: 1px solid var(--line);
|
|
220
|
+
background: var(--card); font-size: 19px; line-height: 32px; text-align: center; cursor: default; padding: 0;
|
|
221
|
+
}
|
|
222
|
+
.mcol { min-width: 0; max-width: min(78%, 760px); display: flex; flex-direction: column; gap: 4px }
|
|
223
|
+
.mrow.mine { flex-direction: row-reverse }
|
|
224
|
+
.mrow.mine .mcol { align-items: flex-end }
|
|
225
|
+
.mwho { font-size: 11.5px; color: var(--mute); display: flex; gap: 6px; align-items: baseline; flex-wrap: wrap }
|
|
226
|
+
.mwho .to { color: var(--faint) }
|
|
227
|
+
.mwho .ch { font-size: 10.5px; border-radius: 4px; padding: 0 4px }
|
|
228
|
+
.mwho .ch.priv { color: var(--priv); background: #9a5b1014 }
|
|
229
|
+
/* 时刻只此一处 —— 气泡外, 跟着名字走。等宽数字让一列时间对得齐。 */
|
|
230
|
+
.mwho .mt { color: var(--faint); font-family: ui-monospace, Menlo, monospace; font-variant-numeric: tabular-nums }
|
|
231
|
+
.mb { min-width: 0; max-width: 100% }
|
|
232
|
+
/* 卡片里那份时刻是详情页要的, 这里已经写在 .mwho 上了 —— 同一条消息不报两次时间。 */
|
|
233
|
+
.mb .tg-time { display: none }
|
|
234
|
+
|
|
235
|
+
/* 入消息 (问句) 是一颗气泡; 出消息 (回复) 是一张带工具细节的卡片 —— 两者都按视角着色。 */
|
|
236
|
+
.mb > .bubble.mq { border-radius: 14px; border-color: var(--line) }
|
|
237
|
+
.mb .mq .mmeta { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; padding: 8px 14px 0; font-size: 11px; color: var(--faint) }
|
|
238
|
+
.mb .mq .md-body { padding: 10px 14px }
|
|
239
|
+
.mb .mq .mmeta + .md-body { padding-top: 4px }
|
|
240
|
+
.mchip { border-radius: 4px; padding: 0 5px; background: #f1f3f6; color: var(--mute) }
|
|
241
|
+
.mchip.priv { color: var(--priv); background: #9a5b1014 }
|
|
242
|
+
.mchip.pub { color: var(--pub); background: #237a5514 }
|
|
243
|
+
.mchip.graph { color: #6639ba; background: #8250df12 }
|
|
244
|
+
|
|
245
|
+
/* 自己发出的那条: 整块就是视角色。TURN_CSS 里写死的白卡 / 灰底 (嵌套气泡、
|
|
246
|
+
代码块、折叠头) 会在蓝底上显成一张张贴纸 —— 这里把它们收回到气泡自己的
|
|
247
|
+
底色上, 一条消息读起来是一块颜色, 需要再沉一档的才用 --mine-soft。 */
|
|
248
|
+
.mrow.mine .mb > .bubble.mq, .mrow.mine .mb > .turn-group { background: var(--mine); border-color: var(--mine-line) }
|
|
249
|
+
.mrow.mine .mb .bubble, .mrow.mine .mb .typing, .mrow.mine .mb .stats { background: transparent; border-color: var(--mine-line) }
|
|
250
|
+
.mrow.mine .mb .bubble.user, .mrow.mine .mb .bubble.approval,
|
|
251
|
+
.mrow.mine .mb .md-body code, .mrow.mine .mb .md-body pre,
|
|
252
|
+
.mrow.mine .mb .tile, .mrow.mine .mb details > summary,
|
|
253
|
+
.mrow.mine .mb .tool-call > summary:hover { background: var(--mine-soft); border-color: var(--mine-line) }
|
|
254
|
+
.mrow.mine .mb .md-body pre code { background: transparent }
|
|
255
|
+
.mrow.mine .mb .bubble details, .mrow.mine .mb .tg-head { border-color: var(--mine-line) }
|
|
256
|
+
.mrow.mine .mb .tool-body { border-left-color: var(--mine-line) }
|
|
257
|
+
.mrow.mine .mb .io-bar { background: var(--mine-soft) }
|
|
258
|
+
|
|
259
|
+
/* 气泡对面那片空白 = 换视角的门。平时不可见, 悬停才露出要去谁那里。 */
|
|
260
|
+
.flip {
|
|
261
|
+
flex: 1; align-self: stretch; min-width: 40px; border: 0; background: transparent; cursor: pointer;
|
|
262
|
+
display: flex; align-items: center; padding: 0 12px; border-radius: 10px; color: transparent;
|
|
263
|
+
font-size: 12px; transition: background .15s, color .15s;
|
|
264
|
+
}
|
|
265
|
+
.mrow.them .flip { justify-content: flex-start }
|
|
266
|
+
.mrow.mine .flip { justify-content: flex-end }
|
|
267
|
+
/* 气泡可以比视窗还高, 居中的箭头就跑出屏幕了 —— 让它在按钮内 sticky, 上下各留半屏,
|
|
268
|
+
于是只要这一行还在视窗里, 箭头就钉在视窗中线附近。 */
|
|
269
|
+
.flip .fi {
|
|
270
|
+
position: sticky; top: calc(50% - 10px); bottom: calc(50% - 10px);
|
|
271
|
+
display: inline-flex; align-items: center; gap: 4px;
|
|
272
|
+
}
|
|
273
|
+
.mrow.mine .flip .fi { flex-direction: row-reverse }
|
|
274
|
+
.mrow.mine .flip .fc { transform: scaleX(-1) }
|
|
275
|
+
.flip .fc { flex: none }
|
|
276
|
+
.flip:hover, .flip:focus-visible { background: #2f55c90d; color: var(--accent) }
|
|
277
|
+
.flip[disabled] { cursor: default; background: transparent !important; color: transparent !important }
|
|
278
|
+
.mrow .av.go { cursor: pointer }
|
|
279
|
+
.mrow .av.go:hover { border-color: var(--accent) }
|
|
280
|
+
|
|
281
|
+
.mrow.mark { justify-content: center }
|
|
282
|
+
.mrow.mark > * { flex: 1; max-width: 520px }
|
|
283
|
+
|
|
284
|
+
/* 视角切换的那一下: 整列消息淡出再按新视角排回来 —— 这一页唯一的编排动效。 */
|
|
285
|
+
.thread-in.flipping { animation: flip .26s ease }
|
|
286
|
+
@keyframes flip { 0% { opacity: 1 } 45% { opacity: 0; transform: scaleX(.985) } 100% { opacity: 1 } }
|
|
287
|
+
@media (prefers-reduced-motion: reduce) {
|
|
288
|
+
.thread-in.flipping { animation: none }
|
|
289
|
+
.flip { transition: none }
|
|
136
290
|
}
|
|
137
|
-
.more-btn:hover { background: #f6f8fa; color: #0969da; border-color: #0969da55 }
|
|
138
291
|
|
|
139
292
|
/* ── turn 分组 ──────────────────────────────────────────────────── */
|
|
140
293
|
/* section 的默认样式给了白底+边框, 但没有内边距 —— 气泡/工具行会直接贴着卡片
|
|
@@ -167,51 +320,45 @@ body { overflow: hidden; overscroll-behavior: none }
|
|
|
167
320
|
/* graph 派的一轮: 卡片本身也着色, 滚动时不必读归因条就知道这不是人发的。 */
|
|
168
321
|
.turn-group.graph { border-color: #8250df44 }
|
|
169
322
|
|
|
170
|
-
/* ──
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
font-
|
|
177
|
-
}
|
|
178
|
-
.
|
|
179
|
-
.
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
.
|
|
185
|
-
.
|
|
186
|
-
.
|
|
187
|
-
.
|
|
188
|
-
.
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
.
|
|
195
|
-
.sb-io > .k { color: #8c959f; text-transform: uppercase; letter-spacing: .4px; font-size: 10px }
|
|
196
|
-
.sb-bar { display: flex; height: 6px; width: 120px; border-radius: 3px; overflow: hidden; background: #eaeef2 }
|
|
197
|
-
.sb-bar .seg { height: 100% }
|
|
198
|
-
.sb-leg { display: flex; align-items: center; gap: 9px; flex-wrap: wrap }
|
|
199
|
-
.sb-leg .lg { display: flex; align-items: center; gap: 4px; font-size: 10.5px; color: #8c959f }
|
|
200
|
-
.sb-leg .lg i { width: 8px; height: 8px; border-radius: 2px; flex: none }
|
|
201
|
-
.sb-leg .lg b { color: #1f2328; font-weight: 700; font-variant-numeric: tabular-nums }
|
|
202
|
-
.conn { margin-left: auto; display: flex; align-items: center; gap: 5px }
|
|
203
|
-
.conn .d { width: 7px; height: 7px; border-radius: 50%; background: #1a7f37 }
|
|
204
|
-
.conn.off .d { background: #cf222e }
|
|
323
|
+
/* ── 🏓 keepalive 折叠 ──────────────────────────────────────────────
|
|
324
|
+
保温 ping 不是对话, 但它是真花销 —— 所以留在时间轴上, 只是收成一行虚线。 */
|
|
325
|
+
.ping-fold { border: 1px dashed #d8dee4; border-radius: 10px; background: #fbfcfd }
|
|
326
|
+
.ping-fold > .ping-sum {
|
|
327
|
+
display: flex; align-items: center; gap: 8px; padding: 6px 12px;
|
|
328
|
+
cursor: pointer; list-style: none; font-size: 11.5px; color: #8c959f;
|
|
329
|
+
font-family: ui-monospace, Menlo, monospace; font-variant-numeric: tabular-nums;
|
|
330
|
+
}
|
|
331
|
+
.ping-fold > .ping-sum::-webkit-details-marker { display: none }
|
|
332
|
+
.ping-fold > .ping-sum::after {
|
|
333
|
+
content: "›"; margin-left: auto; font-size: 14px; color: #b1bac4;
|
|
334
|
+
transition: transform .12s;
|
|
335
|
+
}
|
|
336
|
+
.ping-fold[open] > .ping-sum::after { transform: rotate(90deg) }
|
|
337
|
+
.ping-fold > .ping-sum:hover { color: #57606a }
|
|
338
|
+
.ping-fold .pb { color: #57606a; font-weight: 700; flex: none }
|
|
339
|
+
.ping-fold .ps { overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
|
|
340
|
+
.ping-fold .pt { flex: none; opacity: .8 }
|
|
341
|
+
.ping-fold .ping-body {
|
|
342
|
+
display: flex; flex-direction: column; gap: 10px; padding: 2px 10px 10px;
|
|
343
|
+
}
|
|
344
|
+
/* 展开后的 ping 轮次压一档: 它们是背景噪声, 不该和真对话卡片一样醒目。 */
|
|
345
|
+
.ping-fold .turn-group { box-shadow: none }
|
|
346
|
+
.ping-fold .mcol { max-width: 100% }
|
|
347
|
+
.ping-fold .flip { display: none }
|
|
205
348
|
|
|
206
349
|
@media (max-width: 760px) {
|
|
207
350
|
.app { flex-direction: column }
|
|
208
|
-
.side { width: auto;
|
|
351
|
+
.side { width: auto; flex: 1; border-right: 0 }
|
|
352
|
+
.main { display: none }
|
|
209
353
|
.app.reading .side { display: none }
|
|
210
|
-
.app.reading .
|
|
354
|
+
.app.reading .main { display: flex }
|
|
355
|
+
.chathead { padding: 8px 12px; gap: 8px }
|
|
356
|
+
.chathead .back { display: block }
|
|
211
357
|
.thread { padding: 12px }
|
|
358
|
+
.mcol { max-width: 86% }
|
|
359
|
+
.flip { min-width: 16px; padding: 0 4px; font-size: 0 }
|
|
212
360
|
.turn-group { padding: 12px }
|
|
213
|
-
.
|
|
214
|
-
.sb-io, .statusbar .model { display: none }
|
|
361
|
+
.thread { padding-bottom: calc(12px + env(safe-area-inset-bottom)) }
|
|
215
362
|
}
|
|
216
363
|
|
|
217
364
|
/* UA 的 [hidden] 规则和 `.gbar{display:flex}` 这类类选择器同权重, 而作者样式
|
|
@@ -219,36 +366,6 @@ body { overflow: hidden; overscroll-behavior: none }
|
|
|
219
366
|
一条 !important 把 hidden 的语义钉死, 三块视图容器的显隐都靠它。 */
|
|
220
367
|
[hidden] { display: none !important }
|
|
221
368
|
|
|
222
|
-
/* ══ 视图切换 ═══════════════════════════════════════════════════════ */
|
|
223
|
-
/* 三栏并列在顶栏右端。会话 key (.sub) 在窄屏下先让位 —— 它是调试信息, 而切换
|
|
224
|
-
视图是主操作。 */
|
|
225
|
-
.topbar .views { margin-left: auto; display: flex; gap: 2px; flex: none }
|
|
226
|
-
.topbar .vb {
|
|
227
|
-
font: inherit; font-size: 12px; color: #57606a; background: transparent;
|
|
228
|
-
border: 1px solid transparent; border-radius: 7px; padding: 3px 11px; cursor: pointer;
|
|
229
|
-
}
|
|
230
|
-
.topbar .vb:hover { background: #f6f8fa; color: #1f2328 }
|
|
231
|
-
.topbar .vb.on { background: #0969da; border-color: #0969da; color: #fff; font-weight: 600 }
|
|
232
|
-
.topbar .sub { min-width: 0 }
|
|
233
|
-
|
|
234
|
-
/* 关系/日程栏不需要那条 288px 的会话列表占着半张桌子 —— 图要横向铺开。 */
|
|
235
|
-
.pane { flex: 1; min-height: 0; display: flex; flex-direction: column; background: #fafbfc }
|
|
236
|
-
.app.wide .side { width: 216px }
|
|
237
|
-
|
|
238
|
-
/* ── 侧栏: wizard 身份 ─────────────────────────────────────────────── */
|
|
239
|
-
/* 名字之外还要有职责与出身, 否则一列 `#tag` 说不出谁是谁。两行都单行省略,
|
|
240
|
-
会话行的高度必须可预期 —— 侧栏是要能一眼扫完的。 */
|
|
241
|
-
.tag-job {
|
|
242
|
-
font-size: 11.5px; color: #0550ae; margin-top: 2px;
|
|
243
|
-
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
244
|
-
}
|
|
245
|
-
.tag-kin { margin-top: 2px }
|
|
246
|
-
.tag-kin .kin {
|
|
247
|
-
font-size: 10.5px; color: #6639ba; background: #8250df12; border-radius: 4px;
|
|
248
|
-
padding: 0 5px; font-family: ui-monospace, Menlo, monospace;
|
|
249
|
-
display: inline-block; max-width: 100%; overflow: hidden;
|
|
250
|
-
text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom;
|
|
251
|
-
}
|
|
252
369
|
|
|
253
370
|
/* ══ 关系图 ═════════════════════════════════════════════════════════ */
|
|
254
371
|
.wtools {
|
|
@@ -275,22 +392,39 @@ body { overflow: hidden; overscroll-behavior: none }
|
|
|
275
392
|
.wtools .warn { color: #9a6700 }
|
|
276
393
|
.wtools .hint { margin-left: 10px; color: #b1bac4 }
|
|
277
394
|
|
|
278
|
-
|
|
395
|
+
/* position 不是装饰: 力导向的画布是 `position:absolute; inset:0`, 没有这一行它
|
|
396
|
+
就贴到更外层的定位祖先上去 —— 坐标原点跑到顶栏, 节点飘到工具条上面, 而
|
|
397
|
+
overflow:hidden 也拦不住一个容器块在自己之外的绝对定位子元素。 */
|
|
398
|
+
.wscroll { position: relative; flex: 1; min-height: 0; overflow: auto; -webkit-overflow-scrolling: touch }
|
|
279
399
|
.wmap { position: relative; padding: 18px 20px 28px; min-width: min-content }
|
|
280
400
|
/* 有关系的节点带一道左侧色条 —— 76 个会话里哪几个真的在协作, 不点开也看得见。 */
|
|
281
401
|
.wnode.rel::before {
|
|
282
402
|
content: ""; position: absolute; left: 1px; top: 8px; bottom: 8px;
|
|
283
403
|
width: 2px; border-radius: 1px; background: #0969da66;
|
|
284
404
|
}
|
|
285
|
-
/* 连线层铺满整张图并且不吃事件 —— 节点的点击/双击必须照常穿过去。
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
405
|
+
/* 连线层铺满整张图并且不吃事件 —— 节点的点击/双击必须照常穿过去。
|
|
406
|
+
z-index 把它抬到卡片之上: 卡片是不透明的, 压在下面时一条跨卡片的边会被中途
|
|
407
|
+
吃掉半截, 读出来像是断的。.wgrid 不设 z-index (保持 auto) 才不会自成一个层叠
|
|
408
|
+
上下文 —— 那样悬停/聚焦的节点就再也抬不过这条线了。 */
|
|
409
|
+
.wedges { position: absolute; inset: 0; pointer-events: none; overflow: visible; z-index: 2 }
|
|
410
|
+
/* 反过来: 正在看的那个节点要压过连线, 否则文字被线划着读。只抬这两种 —— 一直
|
|
411
|
+
抬着某个节点等于把"线被卡片吃掉"这个毛病在它身上留一份。 */
|
|
412
|
+
.wnode:hover, .wnode.sel { z-index: 3 }
|
|
413
|
+
/* 多列流式而不是 grid: 聊天卡片的高度天差地别 (一个群 2 个 wizard, 另一个 20 个),
|
|
414
|
+
grid 的行高按本行最高的那张对齐, 于是矮卡片下面全是空白 —— 图看着比实际稀疏
|
|
415
|
+
一倍。CSS columns 是砌砖式的: 卡片顺着列往下码, 码满了换列, 没有行的概念。
|
|
416
|
+
列宽钉在 320 附近也顺带收住了"两张卡片各占半个屏"的过度拉伸。 */
|
|
417
|
+
.wgrid { position: relative; columns: 320px; column-gap: 16px }
|
|
292
418
|
|
|
293
|
-
.wchat {
|
|
419
|
+
.wchat {
|
|
420
|
+
background: #fff; border: 1px solid #d0d7de; border-radius: 12px; overflow: hidden;
|
|
421
|
+
/* 一张卡片不能被切成两列 —— 断在半截的家谱读不出父子关系。 */
|
|
422
|
+
break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid;
|
|
423
|
+
margin-bottom: 16px;
|
|
424
|
+
}
|
|
425
|
+
/* 卡片头可点 = 进那个群 (见 chat.js 的 openNode)。 */
|
|
426
|
+
.wch.go { cursor: pointer }
|
|
427
|
+
.wch.go:hover .nm { color: #0969da; text-decoration: underline }
|
|
294
428
|
/* 当前聊天是读图的锚点, 给它一道明确的边 —— 其余的群一律等价, 不再分轻重。 */
|
|
295
429
|
.wchat.self { border-color: #0969da66; box-shadow: 0 0 0 3px #0969da10 }
|
|
296
430
|
.wch {
|
|
@@ -324,6 +458,8 @@ body { overflow: hidden; overscroll-behavior: none }
|
|
|
324
458
|
.wnode.sel { background: #eef4fc; border-color: #0969da55 }
|
|
325
459
|
/* 聚焦时无关节点压暗而不是移除 —— 位置不动, 连点几个节点版面也不跳。 */
|
|
326
460
|
.wnode.dim { opacity: .3 }
|
|
461
|
+
/* 双击能走进去的那些 —— 外聊天的节点现在也算 (整页跳过去)。 */
|
|
462
|
+
.wnode.go { cursor: pointer }
|
|
327
463
|
.wnode.cold .wav { filter: grayscale(1); opacity: .55 }
|
|
328
464
|
/* 缩进本身就是家谱; 这道折线只是把"缩给谁看"指实。 */
|
|
329
465
|
.wnode .lin {
|
|
@@ -331,6 +467,8 @@ body { overflow: hidden; overscroll-behavior: none }
|
|
|
331
467
|
border-left: 1.5px solid #d8cdf0; border-bottom: 1.5px solid #d8cdf0;
|
|
332
468
|
border-bottom-left-radius: 6px;
|
|
333
469
|
}
|
|
470
|
+
/* 子 wizard 不是 fork: 折线换成虚线、换色, 与分身一眼分开 (同关系图的 spawn 边)。 */
|
|
471
|
+
.wnode .lin.sp { border-style: dashed; border-color: #f0d2bd }
|
|
334
472
|
.wav {
|
|
335
473
|
position: relative; width: 26px; height: 26px; flex: none; border-radius: 8px;
|
|
336
474
|
background: #f1f3f6; border: 1px solid #eaeef2;
|
|
@@ -371,10 +509,15 @@ body { overflow: hidden; overscroll-behavior: none }
|
|
|
371
509
|
|
|
372
510
|
/* ══ 日程 ═══════════════════════════════════════════════════════════ */
|
|
373
511
|
.plan-in { flex: 1; min-height: 0; overflow-y: auto; padding: 18px 20px 28px }
|
|
374
|
-
.psec {
|
|
512
|
+
.psec {
|
|
513
|
+
max-width: 900px; margin: 0 auto 30px;
|
|
514
|
+
/* 通用 section 规则给了白底+边框却没有内边距 —— 不补这一层, 刻度条/日程行/工单
|
|
515
|
+
行就直接贴着卡片的边。底边留小一点: 末行自己还带 10px 的 margin。 */
|
|
516
|
+
padding: 14px 18px 8px;
|
|
517
|
+
}
|
|
375
518
|
.psec h3 {
|
|
376
|
-
display: flex; align-items: baseline; gap: 8px; font-size: 13px; margin: 0 0
|
|
377
|
-
padding-bottom:
|
|
519
|
+
display: flex; align-items: baseline; gap: 8px; font-size: 13px; margin: 0 0 14px;
|
|
520
|
+
padding-bottom: 8px; border-bottom: 1px solid #d0d7de;
|
|
378
521
|
}
|
|
379
522
|
.psec h3 span {
|
|
380
523
|
font-size: 11px; color: #8c959f; font-weight: 400;
|
|
@@ -385,7 +528,7 @@ body { overflow: hidden; overscroll-behavior: none }
|
|
|
385
528
|
/* 未来 12 小时的刻度条 —— 「今晚还有几枪要响」比一张日期列表更该先看见。 */
|
|
386
529
|
.strip {
|
|
387
530
|
background: #fff; border: 1px solid #d0d7de; border-radius: 10px;
|
|
388
|
-
padding:
|
|
531
|
+
padding: 12px 16px 11px; margin-bottom: 16px;
|
|
389
532
|
}
|
|
390
533
|
.strip .axis {
|
|
391
534
|
position: relative; height: 13px; font-size: 10px; color: #8c959f;
|
|
@@ -403,13 +546,13 @@ body { overflow: hidden; overscroll-behavior: none }
|
|
|
403
546
|
.strip .cap { font-size: 11px; color: #8c959f }
|
|
404
547
|
|
|
405
548
|
.prow {
|
|
406
|
-
display: flex; gap:
|
|
407
|
-
border-radius: 10px; padding:
|
|
549
|
+
display: flex; gap: 16px; background: #fff; border: 1px solid #d0d7de;
|
|
550
|
+
border-radius: 10px; padding: 12px 16px; margin-bottom: 10px;
|
|
408
551
|
}
|
|
409
|
-
.prow .pl { flex: none; width: 152px; border-right: 1px dashed #eaeef2; padding-right:
|
|
552
|
+
.prow .pl { flex: none; width: 152px; border-right: 1px dashed #eaeef2; padding-right: 14px }
|
|
410
553
|
.pwhen { font-size: 11.5px; color: #9a6700; font-weight: 600 }
|
|
411
554
|
.pnext {
|
|
412
|
-
display: flex; align-items: baseline; gap: 6px; margin-top:
|
|
555
|
+
display: flex; align-items: baseline; gap: 6px; margin-top: 5px;
|
|
413
556
|
font-family: ui-monospace, Menlo, monospace;
|
|
414
557
|
}
|
|
415
558
|
.pnext b { font-size: 12.5px; font-variant-numeric: tabular-nums }
|
|
@@ -421,8 +564,8 @@ body { overflow: hidden; overscroll-behavior: none }
|
|
|
421
564
|
margin-left: auto; font-size: 10px; color: #b1bac4;
|
|
422
565
|
font-family: ui-monospace, Menlo, monospace;
|
|
423
566
|
}
|
|
424
|
-
.ptext { font-size: 12px; color: #1f2328; margin-top:
|
|
425
|
-
.pfoot { font-size: 10.5px; color: #8c959f; margin-top:
|
|
567
|
+
.ptext { font-size: 12px; color: #1f2328; margin-top: 6px; line-height: 1.5; word-break: break-word }
|
|
568
|
+
.pfoot { font-size: 10.5px; color: #8c959f; margin-top: 6px }
|
|
426
569
|
|
|
427
570
|
/* wizard 徽标 —— 日程/工单里凡是提到一个 wizard 都用它, 同聊天的可点进线程。 */
|
|
428
571
|
.wchip {
|
|
@@ -433,7 +576,7 @@ body { overflow: hidden; overscroll-behavior: none }
|
|
|
433
576
|
.wchip.go { cursor: pointer; border-color: #0969da33; color: #0550ae }
|
|
434
577
|
.wchip.go:hover { background: #ddf4ff; border-color: #0969da }
|
|
435
578
|
|
|
436
|
-
.jrow { background: #fff; border: 1px solid #d0d7de; border-radius: 10px; padding:
|
|
579
|
+
.jrow { background: #fff; border: 1px solid #d0d7de; border-radius: 10px; padding: 12px 16px; margin-bottom: 10px }
|
|
437
580
|
.jrow.open { border-color: #1a7f3755; box-shadow: 0 0 0 3px #1a7f370d }
|
|
438
581
|
.jh { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap }
|
|
439
582
|
.jid {
|
|
@@ -447,7 +590,7 @@ body { overflow: hidden; overscroll-behavior: none }
|
|
|
447
590
|
margin-left: auto; font-size: 10.5px; color: #8c959f;
|
|
448
591
|
font-family: ui-monospace, Menlo, monospace;
|
|
449
592
|
}
|
|
450
|
-
.jm { display: flex; flex-direction: column; gap:
|
|
593
|
+
.jm { display: flex; flex-direction: column; gap: 5px; margin-top: 9px }
|
|
451
594
|
.jmm { display: flex; align-items: center; gap: 6px; min-width: 0 }
|
|
452
595
|
.jmm em {
|
|
453
596
|
font-style: normal; font-size: 11.5px; color: #656d76; min-width: 0;
|
|
@@ -459,19 +602,17 @@ body { overflow: hidden; overscroll-behavior: none }
|
|
|
459
602
|
}
|
|
460
603
|
.jmm.none { font-size: 11.5px; color: #b1bac4 }
|
|
461
604
|
.jsum {
|
|
462
|
-
font-size: 12px; color: #1f2328; margin-top:
|
|
605
|
+
font-size: 12px; color: #1f2328; margin-top: 10px; padding-top: 10px;
|
|
463
606
|
border-top: 1px dashed #eaeef2; line-height: 1.5; white-space: pre-wrap;
|
|
464
607
|
}
|
|
465
608
|
|
|
466
609
|
@media (max-width: 760px) {
|
|
467
|
-
.
|
|
468
|
-
.topbar .sub { display: none }
|
|
469
|
-
.topbar .vb { padding: 3px 8px }
|
|
610
|
+
.chathead .vb { padding: 3px 8px }
|
|
470
611
|
.wmap { padding: 12px }
|
|
471
|
-
.wgrid {
|
|
612
|
+
.wgrid { columns: 1 }
|
|
472
613
|
.plan-in { padding: 12px }
|
|
473
614
|
.prow { flex-direction: column; gap: 6px }
|
|
474
|
-
.prow .pl { width: auto; border-right: 0; border-bottom: 1px dashed #eaeef2; padding: 0 0
|
|
615
|
+
.prow .pl { width: auto; border-right: 0; border-bottom: 1px dashed #eaeef2; padding: 0 0 8px }
|
|
475
616
|
.pnext { margin-top: 1px }
|
|
476
617
|
}
|
|
477
618
|
|
|
@@ -480,3 +621,57 @@ body { overflow: hidden; overscroll-behavior: none }
|
|
|
480
621
|
padding: 5px 13px 9px; font-size: 10.5px; color: #b1bac4;
|
|
481
622
|
border-top: 1px dashed #eaeef2; margin-top: 2px;
|
|
482
623
|
}
|
|
624
|
+
|
|
625
|
+
/* ══ 关系视图 · 力导向布局 ═════════════════════════════════════════
|
|
626
|
+
卡片布局之外的另一种读法: 节点只画 wizard, 聊天不再是容器而是节点身上的一
|
|
627
|
+
道色条 + 一行群名。见 web/chat.js 的说明。 */
|
|
628
|
+
.wscroll.fx { overflow: hidden }
|
|
629
|
+
.wmap.force { position: absolute; inset: 0; padding: 0; min-width: 0 }
|
|
630
|
+
.fxn {
|
|
631
|
+
position: absolute; left: 0; top: 0; z-index: 2;
|
|
632
|
+
display: flex; align-items: center; gap: 7px; max-width: 210px;
|
|
633
|
+
padding: 5px 10px 5px 7px; border-radius: 10px;
|
|
634
|
+
background: #fff; border: 1px solid #d0d7de; border-left: 3px solid var(--c);
|
|
635
|
+
box-shadow: 0 1px 3px #1b1f2412; cursor: grab; touch-action: none;
|
|
636
|
+
user-select: none; -webkit-user-select: none;
|
|
637
|
+
transition: opacity .15s, box-shadow .12s;
|
|
638
|
+
will-change: transform;
|
|
639
|
+
}
|
|
640
|
+
.fxn .wav { width: 22px; height: 22px; border-radius: 7px; font-size: 12px }
|
|
641
|
+
.fxn .wav .live { width: 8px; height: 8px; right: -2px; bottom: -2px }
|
|
642
|
+
.fxb { min-width: 0; display: flex; flex-direction: column; gap: 0 }
|
|
643
|
+
.fxn .wname { font-size: 12px }
|
|
644
|
+
/* 群名压得比名字轻 —— 它是节点的属性, 不是节点本身。 */
|
|
645
|
+
.fxc {
|
|
646
|
+
font-size: 9.5px; color: var(--c); opacity: .85; overflow: hidden;
|
|
647
|
+
text-overflow: ellipsis; white-space: nowrap;
|
|
648
|
+
}
|
|
649
|
+
.fxn.self { background: #fffbe8 }
|
|
650
|
+
.fxn.cold { opacity: .72 }
|
|
651
|
+
.fxn.cold .wav { filter: grayscale(1); opacity: .55 }
|
|
652
|
+
.fxn.run .wname { color: #1a7f37 }
|
|
653
|
+
.fxn.dim { opacity: .22 }
|
|
654
|
+
.fxn.sel { box-shadow: 0 0 0 3px var(--c), 0 1px 3px #1b1f2412; }
|
|
655
|
+
.fxn.sel .fxc { opacity: 1 }
|
|
656
|
+
.fxn.drag { cursor: grabbing; box-shadow: 0 6px 16px #1b1f2426 }
|
|
657
|
+
/* 钉住 = 这个位置是人摆的, 力不再动它。 */
|
|
658
|
+
.fxn.pin::after {
|
|
659
|
+
content: "📌"; position: absolute; right: -5px; top: -7px; font-size: 9px;
|
|
660
|
+
opacity: .8; pointer-events: none;
|
|
661
|
+
}
|
|
662
|
+
/* 布局开关 —— 两种读法并列, 不是复选。 */
|
|
663
|
+
.wtools .wlay { display: inline-flex; border: 1px solid #d0d7de; border-radius: 7px; overflow: hidden }
|
|
664
|
+
.wtools .lb {
|
|
665
|
+
border: 0; background: #fff; cursor: pointer; padding: 3px 9px;
|
|
666
|
+
font-size: 11.5px; color: #57606a; font-family: inherit;
|
|
667
|
+
}
|
|
668
|
+
.wtools .lb + .lb { border-left: 1px solid #d0d7de }
|
|
669
|
+
.wtools .lb.on { background: #ddf4ff; color: #0550ae; font-weight: 600 }
|
|
670
|
+
|
|
671
|
+
/* ══ 关系 / 日程 ═══════════════════════════════════════════════════ */
|
|
672
|
+
/* 都是当前 role 的另一面, 侧栏 (它的会话) 留着 —— 点一个会话就回到对话。
|
|
673
|
+
会话标题条与页脚总账只属于对话视图。 */
|
|
674
|
+
.pane { flex: 1; min-height: 0; display: flex; flex-direction: column; background: #fafbfc }
|
|
675
|
+
|
|
676
|
+
/* 回复卡片里的工具行是 nowrap 的 —— 不裁一刀会把整列撑出横向滚动。 */
|
|
677
|
+
.mb > .turn-group { overflow: hidden }
|