@parley-im/parley 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +134 -2
- package/bin/parley +15 -0
- package/dist/account.js +79 -0
- package/dist/agents/claude.js +134 -0
- package/dist/agents/codex.js +128 -0
- package/dist/agents/process.js +47 -0
- package/dist/agents/types.js +1 -0
- package/dist/api.js +180 -0
- package/dist/charter.js +57 -0
- package/dist/cli.js +272 -0
- package/dist/config.js +97 -0
- package/dist/control.js +72 -0
- package/dist/daemon.js +42 -0
- package/dist/db.js +243 -0
- package/dist/mcp.js +153 -0
- package/dist/models.js +10 -0
- package/dist/relay.js +304 -0
- package/dist/runner.js +198 -0
- package/dist/seal.js +51 -0
- package/dist/server.js +308 -0
- package/dist/state.js +41 -0
- package/dist/transcript.js +53 -0
- package/package.json +46 -4
- package/web/app.css +404 -0
- package/web/chat.html +81 -0
- package/web/chat.js +901 -0
- package/web/ended.html +20 -0
- package/web/home.js +552 -0
- package/web/icon-180.png +0 -0
- package/web/icon.png +0 -0
- package/web/icon.svg +1 -0
- package/web/markdown.js +87 -0
- package/web/missing.html +20 -0
- package/web/panel.html +76 -0
- package/web/panel.js +224 -0
- package/web/seal.js +44 -0
package/web/app.css
ADDED
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
/* parley: one stylesheet for the tester chat, your session view and your
|
|
2
|
+
control panel. Neutral surfaces, one accent, and a monospace face only where
|
|
3
|
+
it means something (code, paths, the agent's activity, numbers). */
|
|
4
|
+
|
|
5
|
+
:root {
|
|
6
|
+
--bg: #fafaf9;
|
|
7
|
+
--panel: #ffffff;
|
|
8
|
+
--subtle: #f3f3f1;
|
|
9
|
+
--hover: #ececea;
|
|
10
|
+
--line: #e4e4e1;
|
|
11
|
+
--line-strong: #d2d2ce;
|
|
12
|
+
--text: #19191a;
|
|
13
|
+
--muted: #66666c;
|
|
14
|
+
--faint: #9c9ca3;
|
|
15
|
+
--accent: #5b4cdb;
|
|
16
|
+
--accent-soft: #eeecfd;
|
|
17
|
+
--accent-ink: #ffffff;
|
|
18
|
+
--ok: #1f9d55;
|
|
19
|
+
--warn: #b7791f;
|
|
20
|
+
--danger: #c4302b;
|
|
21
|
+
--shadow: 0 1px 2px rgba(0, 0, 0, 0.04), 0 8px 24px -12px rgba(0, 0, 0, 0.12);
|
|
22
|
+
--sans: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
23
|
+
--mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
|
|
24
|
+
color-scheme: light;
|
|
25
|
+
}
|
|
26
|
+
@media (prefers-color-scheme: dark) {
|
|
27
|
+
:root:not([data-theme="light"]) {
|
|
28
|
+
--bg: #0c0c0d;
|
|
29
|
+
--panel: #131315;
|
|
30
|
+
--subtle: #19191c;
|
|
31
|
+
--hover: #212125;
|
|
32
|
+
--line: #26262b;
|
|
33
|
+
--line-strong: #36363c;
|
|
34
|
+
--text: #ececef;
|
|
35
|
+
--muted: #9b9ba4;
|
|
36
|
+
--faint: #66666f;
|
|
37
|
+
--accent: #9d92ff;
|
|
38
|
+
--accent-soft: #221f3d;
|
|
39
|
+
--accent-ink: #0c0c0d;
|
|
40
|
+
--ok: #3ccf7a;
|
|
41
|
+
--warn: #e3a948;
|
|
42
|
+
--danger: #ff6b63;
|
|
43
|
+
--shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 8px 24px -12px rgba(0, 0, 0, 0.6);
|
|
44
|
+
color-scheme: dark;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
* { box-sizing: border-box; }
|
|
49
|
+
[hidden] { display: none !important; }
|
|
50
|
+
html, body { height: 100%; }
|
|
51
|
+
body {
|
|
52
|
+
margin: 0;
|
|
53
|
+
background: var(--bg);
|
|
54
|
+
color: var(--text);
|
|
55
|
+
font: 15px/1.55 var(--sans);
|
|
56
|
+
-webkit-font-smoothing: antialiased;
|
|
57
|
+
-webkit-tap-highlight-color: transparent;
|
|
58
|
+
}
|
|
59
|
+
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
|
|
60
|
+
.mono { font-family: var(--mono); font-size: 0.86em; }
|
|
61
|
+
a { color: inherit; }
|
|
62
|
+
button, input, textarea, select { font: inherit; color: inherit; }
|
|
63
|
+
|
|
64
|
+
/* ---------- shared pieces ---------- */
|
|
65
|
+
|
|
66
|
+
.mark { display: inline-grid; place-items: center; width: 22px; height: 22px; border-radius: 6px; background: var(--accent); color: var(--accent-ink); flex: none; }
|
|
67
|
+
.mark svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
|
|
68
|
+
|
|
69
|
+
.topbar {
|
|
70
|
+
display: flex; align-items: center; gap: 10px; min-height: 52px;
|
|
71
|
+
padding: calc(8px + env(safe-area-inset-top)) 16px 8px;
|
|
72
|
+
border-bottom: 1px solid var(--line); background: var(--bg);
|
|
73
|
+
}
|
|
74
|
+
.crumbs { display: flex; align-items: baseline; gap: 8px; min-width: 0; flex: 1; }
|
|
75
|
+
.crumbs .product { color: var(--muted); font-weight: 500; }
|
|
76
|
+
.crumbs .slash { color: var(--faint); }
|
|
77
|
+
.crumbs .here { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
78
|
+
.crumbs a { text-decoration: none; }
|
|
79
|
+
.crumbs a:hover { text-decoration: underline; }
|
|
80
|
+
|
|
81
|
+
.status { display: inline-flex; align-items: center; gap: 7px; font-size: 13px; color: var(--muted); white-space: nowrap; }
|
|
82
|
+
.dot { width: 7px; height: 7px; border-radius: 50%; background: var(--faint); flex: none; }
|
|
83
|
+
.dot.on { background: var(--ok); box-shadow: 0 0 0 3px color-mix(in srgb, var(--ok) 18%, transparent); }
|
|
84
|
+
.dot.busy { background: var(--accent); animation: pulse 1.4s infinite ease-in-out; }
|
|
85
|
+
.dot.warn { background: var(--warn); }
|
|
86
|
+
.dot.off { background: var(--danger); }
|
|
87
|
+
@keyframes pulse { 50% { opacity: 0.35; } }
|
|
88
|
+
|
|
89
|
+
.btn {
|
|
90
|
+
display: inline-flex; align-items: center; justify-content: center; gap: 6px;
|
|
91
|
+
height: 32px; padding: 0 12px; border-radius: 8px; border: 1px solid var(--line-strong);
|
|
92
|
+
background: var(--panel); font-size: 13px; font-weight: 500; cursor: pointer; text-decoration: none; white-space: nowrap;
|
|
93
|
+
touch-action: manipulation;
|
|
94
|
+
}
|
|
95
|
+
.btn:hover { background: var(--subtle); }
|
|
96
|
+
.btn:disabled { opacity: 0.5; cursor: default; }
|
|
97
|
+
.btn.primary { background: var(--text); color: var(--bg); border-color: var(--text); }
|
|
98
|
+
.btn.primary:hover { opacity: 0.88; }
|
|
99
|
+
.btn.danger { color: var(--danger); }
|
|
100
|
+
.btn.confirm { background: var(--danger); color: #fff; border-color: var(--danger); }
|
|
101
|
+
.btn.ghost { border-color: transparent; background: transparent; color: var(--muted); }
|
|
102
|
+
.btn.ghost:hover { background: var(--subtle); color: var(--text); }
|
|
103
|
+
.btn svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
|
|
104
|
+
|
|
105
|
+
.chip {
|
|
106
|
+
font-family: var(--mono); font-size: 12px; color: var(--muted); white-space: nowrap;
|
|
107
|
+
padding: 2px 8px; border: 1px solid var(--line); border-radius: 99px; background: var(--subtle);
|
|
108
|
+
}
|
|
109
|
+
.chip.low { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 40%, var(--line)); }
|
|
110
|
+
.info-btn { width: 34px; height: 34px; margin-right: -6px; }
|
|
111
|
+
|
|
112
|
+
.sheet-back { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.35); z-index: 40; }
|
|
113
|
+
.sheet {
|
|
114
|
+
position: fixed; z-index: 41; left: 50%; top: 50%; transform: translate(-50%, -50%);
|
|
115
|
+
width: min(440px, calc(100% - 32px)); max-height: calc(100% - 48px); overflow-y: auto;
|
|
116
|
+
background: var(--panel); border: 1px solid var(--line); border-radius: 14px; box-shadow: var(--shadow);
|
|
117
|
+
}
|
|
118
|
+
.sheet header { display: flex; align-items: center; justify-content: space-between; padding: 12px 12px 4px 16px; }
|
|
119
|
+
.sheet h2 { font-size: 16px; margin: 0; }
|
|
120
|
+
.sheet-body { padding: 4px 16px 16px; font-size: 14px; }
|
|
121
|
+
.sheet-body p { margin: 0 0 10px; color: var(--muted); }
|
|
122
|
+
.sheet-body p strong { color: var(--text); font-weight: 600; }
|
|
123
|
+
.sheet-body .kv { margin: 6px 0 14px; padding: 10px 12px; background: var(--subtle); border: 1px solid var(--line); border-radius: 10px; }
|
|
124
|
+
@media (max-width: 560px) {
|
|
125
|
+
.sheet { left: 0; right: 0; top: auto; bottom: 0; transform: none; width: auto; border-radius: 16px 16px 0 0; padding-bottom: env(safe-area-inset-bottom); }
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.notice {
|
|
129
|
+
margin: 10px 16px 0; padding: 9px 12px; border-radius: 8px; font-size: 14px;
|
|
130
|
+
background: var(--subtle); border-left: 3px solid var(--warn); color: var(--text);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.label { font-size: 11px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--faint); }
|
|
134
|
+
|
|
135
|
+
/* ---------- chat ---------- */
|
|
136
|
+
|
|
137
|
+
.app { display: flex; flex-direction: column; height: 100dvh; overflow: hidden; }
|
|
138
|
+
.layout { flex: 1; min-height: 0; display: flex; }
|
|
139
|
+
.chat { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; }
|
|
140
|
+
.chat-inner { width: 100%; max-width: 760px; margin: 0 auto; }
|
|
141
|
+
|
|
142
|
+
.scroll { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; overflow-anchor: none; }
|
|
143
|
+
.scroll .chat-inner { padding: 20px 16px 12px; }
|
|
144
|
+
|
|
145
|
+
.intro {
|
|
146
|
+
margin-bottom: 20px; padding: 10px 12px; border: 1px solid var(--line); border-radius: 10px;
|
|
147
|
+
background: var(--panel); color: var(--muted); font-size: 13.5px; line-height: 1.5;
|
|
148
|
+
}
|
|
149
|
+
.intro button { border: 0; background: none; padding: 0; color: var(--accent); cursor: pointer; font-size: inherit; }
|
|
150
|
+
.intro strong { color: var(--text); font-weight: 600; }
|
|
151
|
+
|
|
152
|
+
.older { display: flex; justify-content: center; margin: 0 0 18px; }
|
|
153
|
+
|
|
154
|
+
.messages { list-style: none; margin: 0; padding: 0; }
|
|
155
|
+
.msg { position: relative; padding-left: 22px; margin: 0 0 18px; }
|
|
156
|
+
.msg::before {
|
|
157
|
+
position: absolute; left: 0; top: 0; width: 14px; text-align: center;
|
|
158
|
+
font-family: var(--mono); font-size: 14px; line-height: 1.55;
|
|
159
|
+
}
|
|
160
|
+
.msg.agent::before { content: "●"; color: var(--accent); font-size: 10px; line-height: 23px; }
|
|
161
|
+
.msg.tester::before { content: "›"; color: var(--muted); font-weight: 600; top: 10px; }
|
|
162
|
+
.msg.error::before { content: "!"; color: var(--danger); font-weight: 700; }
|
|
163
|
+
.meta { font-size: 12px; color: var(--faint); margin-bottom: 2px; }
|
|
164
|
+
.meta .who { color: var(--muted); font-weight: 600; }
|
|
165
|
+
.msg.tester .bubble { background: var(--subtle); border: 1px solid var(--line); border-radius: 10px; padding: 9px 12px; }
|
|
166
|
+
.msg.tester .meta { display: none; }
|
|
167
|
+
/* Testers get just the conversation: no names or times on every message. */
|
|
168
|
+
.tester-view .msg .meta, .tester-view .msg .stamp { display: none; }
|
|
169
|
+
.tester-view .msg { margin-bottom: 16px; }
|
|
170
|
+
.tester-view .msg.tester::before { top: 9px; }
|
|
171
|
+
.msg.tester .stamp { font-size: 12px; color: var(--faint); margin-top: 4px; }
|
|
172
|
+
.msg.error .body { color: var(--danger); font-size: 14px; }
|
|
173
|
+
.msg .body { overflow-wrap: anywhere; }
|
|
174
|
+
|
|
175
|
+
.shots { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
|
|
176
|
+
.shots img {
|
|
177
|
+
max-width: min(240px, 60vw); max-height: 200px; border-radius: 8px; border: 1px solid var(--line);
|
|
178
|
+
display: block; cursor: zoom-in; background: var(--subtle);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.trail { margin-top: 6px; font-size: 12px; color: var(--faint); }
|
|
182
|
+
.trail summary { cursor: pointer; list-style: none; font-family: var(--mono); }
|
|
183
|
+
.trail summary::-webkit-details-marker { display: none; }
|
|
184
|
+
.trail summary::before { content: "▸ "; }
|
|
185
|
+
.trail[open] summary::before { content: "▾ "; }
|
|
186
|
+
.trail ul { margin: 4px 0 0; padding: 0; list-style: none; }
|
|
187
|
+
|
|
188
|
+
.steps { margin-top: 4px; font-family: var(--mono); font-size: 12.5px; color: var(--muted); }
|
|
189
|
+
.steps li, .trail li { padding-left: 18px; position: relative; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
190
|
+
.steps li::before, .trail li::before { content: "⎿"; position: absolute; left: 2px; color: var(--faint); }
|
|
191
|
+
.steps .now { color: var(--text); }
|
|
192
|
+
|
|
193
|
+
.body p { margin: 0 0 0.65em; }
|
|
194
|
+
.body p:last-child, .body ul:last-child, .body ol:last-child, .body pre:last-child { margin-bottom: 0; }
|
|
195
|
+
.body ul, .body ol { margin: 0 0 0.65em; padding-left: 1.25em; }
|
|
196
|
+
.body li { margin: 0.15em 0; }
|
|
197
|
+
.body h4 { margin: 0.8em 0 0.3em; font-size: 1em; }
|
|
198
|
+
.body code { font-family: var(--mono); font-size: 0.86em; background: var(--subtle); border: 1px solid var(--line); padding: 0.05em 0.35em; border-radius: 5px; }
|
|
199
|
+
.msg.tester .body code { background: var(--panel); }
|
|
200
|
+
.body pre { background: var(--subtle); border: 1px solid var(--line); padding: 10px 12px; border-radius: 8px; overflow-x: auto; margin: 0 0 0.65em; font-size: 13px; }
|
|
201
|
+
.body pre code { background: none; border: 0; padding: 0; font-size: inherit; }
|
|
202
|
+
.body a { color: var(--accent); }
|
|
203
|
+
.body blockquote { margin: 0 0 0.65em; padding: 2px 0 2px 12px; border-left: 3px solid var(--line-strong); color: var(--muted); }
|
|
204
|
+
.table-wrap { overflow-x: auto; margin: 0 0 0.65em; border: 1px solid var(--line); border-radius: 8px; }
|
|
205
|
+
.body table { border-collapse: collapse; font-size: 14px; width: 100%; }
|
|
206
|
+
.body th, .body td { overflow-wrap: break-word; padding: 6px 10px; border-bottom: 1px solid var(--line); text-align: left; vertical-align: top; }
|
|
207
|
+
.body th { background: var(--subtle); font-weight: 600; white-space: nowrap; }
|
|
208
|
+
.body tr:last-child td { border-bottom: 0; }
|
|
209
|
+
|
|
210
|
+
.thinking { display: inline-flex; gap: 4px; padding: 8px 0 4px; }
|
|
211
|
+
.thinking span { width: 5px; height: 5px; border-radius: 50%; background: var(--faint); animation: blink 1.2s infinite ease-in-out both; }
|
|
212
|
+
.thinking span:nth-child(2) { animation-delay: 0.15s; }
|
|
213
|
+
.thinking span:nth-child(3) { animation-delay: 0.3s; }
|
|
214
|
+
@keyframes blink { 0%, 80%, 100% { opacity: 0.25; } 40% { opacity: 1; } }
|
|
215
|
+
.cursor::after { content: ""; display: inline-block; width: 7px; height: 1.05em; background: var(--accent); margin-left: 3px; vertical-align: -3px; animation: blink 1s infinite; }
|
|
216
|
+
|
|
217
|
+
.dock { border-top: 1px solid var(--line); background: var(--bg); }
|
|
218
|
+
.dock .chat-inner { padding: 8px 16px calc(8px + env(safe-area-inset-bottom)); }
|
|
219
|
+
.composer { border: 1px solid var(--line-strong); border-radius: 12px; background: var(--panel); box-shadow: var(--shadow); }
|
|
220
|
+
.composer:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
|
|
221
|
+
.composer .row { display: flex; align-items: flex-end; gap: 2px; padding: 4px 4px 4px 12px; }
|
|
222
|
+
.prompt { font-family: var(--mono); color: var(--accent); font-weight: 600; padding: 9px 4px 9px 0; line-height: 1.55; }
|
|
223
|
+
textarea {
|
|
224
|
+
flex: 1; resize: none; border: 0; outline: 0; background: transparent;
|
|
225
|
+
padding: 8px 4px; min-height: 40px; line-height: 1.55; font-size: 16px;
|
|
226
|
+
/* The browser sizes it to its text, so dictation doesn't make it jump. */
|
|
227
|
+
field-sizing: content;
|
|
228
|
+
max-height: calc(1.55em * 8 + 16px);
|
|
229
|
+
}
|
|
230
|
+
/* On phones it stops at three lines and scrolls inside, so the conversation
|
|
231
|
+
keeps the room. */
|
|
232
|
+
@media (pointer: coarse) {
|
|
233
|
+
textarea { max-height: calc(1.55em * 3 + 16px); }
|
|
234
|
+
}
|
|
235
|
+
textarea::placeholder { color: var(--faint); }
|
|
236
|
+
.icon-btn {
|
|
237
|
+
flex: none; width: 40px; height: 40px; border-radius: 9px; border: 0; background: transparent; color: var(--muted);
|
|
238
|
+
display: grid; place-items: center; cursor: pointer; touch-action: manipulation;
|
|
239
|
+
}
|
|
240
|
+
.icon-btn:hover { background: var(--subtle); color: var(--text); }
|
|
241
|
+
.icon-btn svg { width: 19px; height: 19px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
|
|
242
|
+
.send { background: var(--accent); color: var(--accent-ink); }
|
|
243
|
+
.send:hover { background: var(--accent); color: var(--accent-ink); opacity: 0.9; }
|
|
244
|
+
.send:disabled { background: var(--subtle); color: var(--faint); cursor: default; opacity: 1; }
|
|
245
|
+
.attachments { display: flex; gap: 8px; padding: 10px 10px 0; flex-wrap: wrap; }
|
|
246
|
+
.thumb { position: relative; }
|
|
247
|
+
.thumb img { width: 56px; height: 56px; object-fit: cover; border-radius: 8px; display: block; border: 1px solid var(--line); }
|
|
248
|
+
.thumb.loading img { opacity: 0.4; }
|
|
249
|
+
.thumb button {
|
|
250
|
+
position: absolute; top: -6px; right: -6px; width: 20px; height: 20px; border-radius: 50%; padding: 0;
|
|
251
|
+
border: 1px solid var(--line); background: var(--panel); color: var(--text); font-size: 13px; line-height: 18px; cursor: pointer;
|
|
252
|
+
}
|
|
253
|
+
.hints { display: flex; justify-content: space-between; gap: 12px; margin: 6px 2px 0; font-size: 12px; color: var(--faint); }
|
|
254
|
+
.hints .warn { color: var(--warn); }
|
|
255
|
+
.hints .over { color: var(--danger); font-weight: 600; }
|
|
256
|
+
.paused { padding: 12px 14px; border: 1px dashed var(--line-strong); border-radius: 10px; color: var(--muted); font-size: 14px; text-align: center; }
|
|
257
|
+
|
|
258
|
+
.drop {
|
|
259
|
+
position: fixed; inset: 0; display: grid; place-items: center; z-index: 10;
|
|
260
|
+
background: color-mix(in srgb, var(--bg) 82%, transparent); backdrop-filter: blur(3px);
|
|
261
|
+
}
|
|
262
|
+
.drop div { border: 1.5px dashed var(--accent); padding: 28px 36px; border-radius: 14px; font-weight: 600; background: var(--panel); }
|
|
263
|
+
.lightbox { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.86); display: grid; place-items: center; z-index: 20; cursor: zoom-out; padding: 16px; }
|
|
264
|
+
.lightbox img { max-width: 100%; max-height: 100%; border-radius: 6px; }
|
|
265
|
+
|
|
266
|
+
/* Your session view: the conversation plus a side panel of controls. */
|
|
267
|
+
.side {
|
|
268
|
+
width: 320px; flex: none; border-left: 1px solid var(--line); background: var(--panel);
|
|
269
|
+
overflow-y: auto; padding: 16px;
|
|
270
|
+
}
|
|
271
|
+
.side h2 { font-size: 15px; margin: 0 0 2px; }
|
|
272
|
+
.side .sub { color: var(--muted); font-size: 13px; margin-bottom: 14px; }
|
|
273
|
+
.side section { padding: 14px 0; border-top: 1px solid var(--line); }
|
|
274
|
+
.side section:first-of-type { border-top: 0; padding-top: 0; }
|
|
275
|
+
.kv { display: grid; grid-template-columns: auto 1fr; gap: 6px 14px; font-size: 13px; }
|
|
276
|
+
.kv dt { color: var(--muted); }
|
|
277
|
+
.kv dd { margin: 0; text-align: right; overflow-wrap: anywhere; }
|
|
278
|
+
.actions { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 10px; }
|
|
279
|
+
.meter { height: 6px; border-radius: 3px; background: var(--subtle); overflow: hidden; margin: 8px 0 4px; }
|
|
280
|
+
.meter span { display: block; height: 100%; background: var(--accent); border-radius: 3px; }
|
|
281
|
+
.meter.full span { background: var(--warn); }
|
|
282
|
+
.brief-text { font-size: 13px; color: var(--muted); white-space: pre-wrap; max-height: 260px; overflow: auto; }
|
|
283
|
+
.linkbox { display: flex; gap: 6px; }
|
|
284
|
+
.linkbox input { flex: 1; min-width: 0; height: 32px; border: 1px solid var(--line-strong); border-radius: 8px; padding: 0 8px; background: var(--subtle); font-family: var(--mono); font-size: 12px; }
|
|
285
|
+
|
|
286
|
+
@media (max-width: 900px) {
|
|
287
|
+
.layout { flex-direction: column; }
|
|
288
|
+
.side { width: auto; border-left: 0; border-bottom: 1px solid var(--line); max-height: 45vh; order: -1; }
|
|
289
|
+
}
|
|
290
|
+
@media (max-width: 560px) {
|
|
291
|
+
.topbar { min-height: 46px; gap: 8px; padding: calc(6px + env(safe-area-inset-top)) 12px 6px; }
|
|
292
|
+
.topbar .status #status-text { max-width: 30vw; overflow: hidden; text-overflow: ellipsis; }
|
|
293
|
+
.crumbs .product, .crumbs .slash { display: none; }
|
|
294
|
+
.scroll .chat-inner { padding: 14px 12px 8px; }
|
|
295
|
+
.dock .chat-inner { padding-left: 10px; padding-right: 10px; }
|
|
296
|
+
.msg { padding-left: 18px; }
|
|
297
|
+
.hints .keys { display: none; }
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/* ---------- control panel ---------- */
|
|
301
|
+
|
|
302
|
+
.page { max-width: 1180px; margin: 0 auto; padding: 0 16px 60px; }
|
|
303
|
+
body.panel { overflow: auto; }
|
|
304
|
+
.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin: 20px 0; }
|
|
305
|
+
.stat { background: var(--panel); border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px; }
|
|
306
|
+
.stat .value { font-family: var(--mono); font-size: 22px; font-weight: 600; margin-top: 4px; letter-spacing: -0.02em; }
|
|
307
|
+
.stat .note { font-size: 12px; color: var(--muted); margin-top: 2px; }
|
|
308
|
+
.toolbar { display: flex; align-items: center; gap: 10px; margin: 6px 0 10px; flex-wrap: wrap; }
|
|
309
|
+
.tabs { display: inline-flex; background: var(--subtle); border: 1px solid var(--line); border-radius: 9px; padding: 2px; }
|
|
310
|
+
.tabs button { border: 0; background: transparent; padding: 5px 12px; border-radius: 7px; font-size: 13px; color: var(--muted); cursor: pointer; }
|
|
311
|
+
.tabs button.on { background: var(--panel); color: var(--text); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08); }
|
|
312
|
+
.search { flex: 1; min-width: 160px; height: 32px; border: 1px solid var(--line-strong); border-radius: 8px; padding: 0 10px; background: var(--panel); }
|
|
313
|
+
.table { background: var(--panel); border: 1px solid var(--line); border-radius: 10px; overflow: hidden; }
|
|
314
|
+
.thead, .trow { display: grid; grid-template-columns: minmax(170px, 2fr) 1.3fr 0.7fr 1.1fr 0.7fr 290px; gap: 14px; align-items: center; padding: 10px 14px; }
|
|
315
|
+
.thead { border-bottom: 1px solid var(--line); background: var(--subtle); }
|
|
316
|
+
.trow { border-bottom: 1px solid var(--line); font-size: 14px; }
|
|
317
|
+
.trow:last-child { border-bottom: 0; }
|
|
318
|
+
.trow:hover { background: color-mix(in srgb, var(--subtle) 60%, var(--panel)); }
|
|
319
|
+
.trow.ended { color: var(--muted); }
|
|
320
|
+
.who-cell .name { font-weight: 600; display: flex; align-items: center; gap: 8px; }
|
|
321
|
+
.who-cell .where { font-size: 12px; color: var(--muted); font-family: var(--mono); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
322
|
+
.badge { display: inline-block; padding: 0 7px; border-radius: 99px; font-size: 11px; font-weight: 600; line-height: 18px; background: var(--accent); color: var(--accent-ink); }
|
|
323
|
+
.badge.soft { background: var(--subtle); color: var(--muted); border: 1px solid var(--line); }
|
|
324
|
+
.cell-muted { font-size: 13px; color: var(--muted); }
|
|
325
|
+
.num { font-family: var(--mono); font-size: 13px; }
|
|
326
|
+
.row-actions { display: flex; gap: 6px; justify-content: flex-end; }
|
|
327
|
+
.empty { padding: 36px 16px; text-align: center; color: var(--muted); }
|
|
328
|
+
.empty code { font-family: var(--mono); font-size: 13px; }
|
|
329
|
+
|
|
330
|
+
.drawer-back { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.32); z-index: 30; }
|
|
331
|
+
.drawer {
|
|
332
|
+
position: fixed; top: 0; right: 0; bottom: 0; width: min(520px, 100%); z-index: 31; background: var(--panel);
|
|
333
|
+
border-left: 1px solid var(--line); box-shadow: var(--shadow); display: flex; flex-direction: column;
|
|
334
|
+
}
|
|
335
|
+
.drawer header { display: flex; align-items: center; justify-content: space-between; padding: 14px 16px; border-bottom: 1px solid var(--line); }
|
|
336
|
+
.drawer header h2 { font-size: 16px; margin: 0; }
|
|
337
|
+
.drawer form { padding: 16px; overflow-y: auto; display: grid; gap: 14px; }
|
|
338
|
+
.field { display: grid; gap: 5px; }
|
|
339
|
+
.field label { font-size: 13px; font-weight: 600; }
|
|
340
|
+
.field .help { font-size: 12px; color: var(--muted); }
|
|
341
|
+
.field input, .field textarea, .field select {
|
|
342
|
+
border: 1px solid var(--line-strong); border-radius: 8px; padding: 8px 10px; background: var(--bg); font-size: 14px; min-height: 36px;
|
|
343
|
+
}
|
|
344
|
+
.field textarea { min-height: 140px; resize: vertical; font-size: 14px; }
|
|
345
|
+
.field input:focus, .field textarea:focus { outline: 2px solid var(--accent-soft); border-color: var(--accent); }
|
|
346
|
+
.segmented { display: inline-flex; border: 1px solid var(--line-strong); border-radius: 8px; overflow: hidden; width: fit-content; }
|
|
347
|
+
.segmented label { padding: 6px 14px; font-size: 13px; cursor: pointer; }
|
|
348
|
+
.segmented input { display: none; }
|
|
349
|
+
.segmented label:has(input:checked) { background: var(--text); color: var(--bg); }
|
|
350
|
+
.form-error { color: var(--danger); font-size: 13px; }
|
|
351
|
+
.made { padding: 12px; border: 1px solid var(--line); border-radius: 10px; background: var(--subtle); display: grid; gap: 8px; }
|
|
352
|
+
|
|
353
|
+
@media (max-width: 900px) {
|
|
354
|
+
.stats { grid-template-columns: repeat(2, 1fr); }
|
|
355
|
+
.thead { display: none; }
|
|
356
|
+
.trow { grid-template-columns: 1fr auto; gap: 6px 12px; }
|
|
357
|
+
.trow > .c-activity, .trow > .c-messages, .trow > .c-replies, .trow > .c-spend { grid-column: 1; }
|
|
358
|
+
.trow > .row-actions { grid-column: 2; grid-row: 1 / span 3; flex-direction: column; align-items: stretch; }
|
|
359
|
+
.trow > .c-spend { display: none; }
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/* ---------- standalone notes (ended, not found) ---------- */
|
|
363
|
+
|
|
364
|
+
.lost { min-height: 100dvh; display: grid; place-items: center; padding: 16px; text-align: center; }
|
|
365
|
+
.lost.inline { min-height: 100%; }
|
|
366
|
+
.lost .mark { width: 36px; height: 36px; border-radius: 9px; margin: 0 auto 16px; }
|
|
367
|
+
.lost .mark svg { width: 20px; height: 20px; }
|
|
368
|
+
.lost h1 { font-size: 20px; margin: 0 0 6px; letter-spacing: -0.01em; }
|
|
369
|
+
.lost p { color: var(--muted); margin: 0 auto; max-width: 34ch; }
|
|
370
|
+
|
|
371
|
+
/* ---------- parley.im's own pages ---------- */
|
|
372
|
+
|
|
373
|
+
.site { max-width: 760px; }
|
|
374
|
+
.hero { padding: 36px 0 8px; }
|
|
375
|
+
.hero h1 { font-size: 26px; line-height: 1.25; letter-spacing: -0.02em; margin: 0 0 12px; }
|
|
376
|
+
.hero p { color: var(--muted); margin: 0 0 12px; max-width: 62ch; }
|
|
377
|
+
.steps-list { margin: 22px 0 48px; }
|
|
378
|
+
.steps-list ol { padding-left: 1.2em; margin: 10px 0 20px; }
|
|
379
|
+
.steps-list li { margin: 6px 0; }
|
|
380
|
+
.site code { font-family: var(--mono); font-size: 0.88em; background: var(--subtle); border: 1px solid var(--line); padding: 0.05em 0.35em; border-radius: 5px; }
|
|
381
|
+
.site h3 { margin: 32px 0 8px; }
|
|
382
|
+
.stack { display: grid; gap: 10px; max-width: 360px; margin-top: 16px; }
|
|
383
|
+
.docs { padding-bottom: 40px; }
|
|
384
|
+
.docs h2 { font-size: 17px; letter-spacing: -0.01em; margin: 36px 0 10px; }
|
|
385
|
+
.docs p, .docs li { max-width: 66ch; }
|
|
386
|
+
.docs ul { padding-left: 1.2em; }
|
|
387
|
+
.docs li { margin: 6px 0; }
|
|
388
|
+
.docs pre { background: var(--subtle); border: 1px solid var(--line); border-radius: 8px; padding: 12px 14px; overflow-x: auto; font-size: 13px; line-height: 1.6; }
|
|
389
|
+
.docs pre code { background: none; border: 0; padding: 0; font-size: inherit; }
|
|
390
|
+
.docs blockquote { margin: 10px 0; padding: 8px 14px; border-left: 3px solid var(--accent); background: var(--accent-soft); border-radius: 0 8px 8px 0; color: var(--text); }
|
|
391
|
+
.trow.site-row { grid-template-columns: 1fr auto; }
|
|
392
|
+
|
|
393
|
+
/* parley.im's front page: no words, just home.js drawing on a faint grid. */
|
|
394
|
+
body.home { overflow: hidden; }
|
|
395
|
+
.home .topbar { position: relative; z-index: 1; background: transparent; border-bottom-color: transparent; }
|
|
396
|
+
.stage { position: fixed; inset: 0; }
|
|
397
|
+
.stage::before {
|
|
398
|
+
content: ""; position: absolute; inset: 0;
|
|
399
|
+
background-image: radial-gradient(circle, var(--line-strong) 0.9px, transparent 1.4px);
|
|
400
|
+
background-size: 22px 22px; background-position: center;
|
|
401
|
+
-webkit-mask-image: radial-gradient(ellipse at center, #000 15%, transparent 72%);
|
|
402
|
+
mask-image: radial-gradient(ellipse at center, #000 15%, transparent 72%);
|
|
403
|
+
}
|
|
404
|
+
.stage canvas { position: absolute; inset: 0; display: block; }
|
package/web/chat.html
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover, interactive-widget=resizes-content">
|
|
6
|
+
<meta name="robots" content="noindex, nofollow">
|
|
7
|
+
<meta name="referrer" content="no-referrer">
|
|
8
|
+
<meta name="theme-color" content="#0c0c0d" media="(prefers-color-scheme: dark)">
|
|
9
|
+
<meta name="theme-color" content="#fafaf9" media="(prefers-color-scheme: light)">
|
|
10
|
+
<meta property="og:title" content="{{PREVIEW_TITLE}}">
|
|
11
|
+
<meta property="og:description" content="{{PREVIEW_TEXT}}">
|
|
12
|
+
<meta property="og:site_name" content="parley">
|
|
13
|
+
<title>{{TITLE}}</title>
|
|
14
|
+
<link rel="icon" href="/static/icon.svg">
|
|
15
|
+
<link rel="stylesheet" href="/static/app.css">
|
|
16
|
+
</head>
|
|
17
|
+
<body>
|
|
18
|
+
<div class="app">
|
|
19
|
+
<header class="topbar">
|
|
20
|
+
<span class="mark" aria-hidden="true"><svg viewBox="4 4 24 24"><g fill="currentColor" stroke="none"><circle cx="8" cy="10" r="2.2"/><rect x="12" y="8" width="12" height="4" rx="2"/><rect x="6" y="14" width="20" height="4" rx="2" opacity=".7"/><rect x="6" y="20" width="13" height="4" rx="2" opacity=".7"/></g></svg></span>
|
|
21
|
+
<nav class="crumbs" id="crumbs">
|
|
22
|
+
<span class="product">parley</span><span class="slash">/</span><span class="here" id="project"> </span>
|
|
23
|
+
</nav>
|
|
24
|
+
<span class="status" id="status" hidden><span class="dot" id="status-dot"></span><span id="status-text"></span></span>
|
|
25
|
+
<span class="chip" id="chip" hidden></span>
|
|
26
|
+
<button class="icon-btn info-btn" id="info-btn" type="button" title="About this chat" hidden>
|
|
27
|
+
<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="8.5"/><path d="M12 11v5"/><path d="M12 7.6v.1"/></svg>
|
|
28
|
+
<span class="sr">About this chat</span>
|
|
29
|
+
</button>
|
|
30
|
+
</header>
|
|
31
|
+
|
|
32
|
+
<div class="notice" id="banner" hidden></div>
|
|
33
|
+
|
|
34
|
+
<div class="layout" id="layout">
|
|
35
|
+
<div class="chat">
|
|
36
|
+
<main class="scroll" id="scroll">
|
|
37
|
+
<div class="chat-inner" id="content">
|
|
38
|
+
<div class="intro" id="intro" hidden></div>
|
|
39
|
+
<div class="older" id="older" hidden><button class="btn ghost" id="older-btn" type="button">Show earlier messages</button></div>
|
|
40
|
+
<ol class="messages" id="messages" aria-live="polite"></ol>
|
|
41
|
+
</div>
|
|
42
|
+
</main>
|
|
43
|
+
|
|
44
|
+
<footer class="dock" id="dock" hidden>
|
|
45
|
+
<div class="chat-inner">
|
|
46
|
+
<div class="composer" id="composer">
|
|
47
|
+
<div class="attachments" id="attachments" hidden></div>
|
|
48
|
+
<div class="row">
|
|
49
|
+
<span class="prompt" aria-hidden="true">›</span>
|
|
50
|
+
<textarea id="input" rows="1" placeholder="Say anything. Ramble away." autocomplete="off" autocorrect="on" spellcheck="true" aria-label="Message"></textarea>
|
|
51
|
+
<label class="icon-btn" title="Add a screenshot">
|
|
52
|
+
<input type="file" id="file" accept="image/png,image/jpeg,image/gif,image/webp" multiple hidden>
|
|
53
|
+
<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3.5" y="5" width="17" height="14" rx="2.5"/><path d="m4 16 4.5-4.5a1.5 1.5 0 0 1 2.1 0L15 16"/><path d="m13.5 14.5 1.7-1.7a1.5 1.5 0 0 1 2.1 0l2.7 2.7"/><circle cx="15.5" cy="9.5" r="1.2"/></svg>
|
|
54
|
+
<span class="sr">Add a screenshot</span>
|
|
55
|
+
</label>
|
|
56
|
+
<button class="icon-btn send" id="send" type="button" disabled title="Send">
|
|
57
|
+
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 19V5"/><path d="m6 11 6-6 6 6"/></svg>
|
|
58
|
+
<span class="sr">Send</span>
|
|
59
|
+
</button>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
<div class="paused" id="paused" hidden></div>
|
|
63
|
+
<div class="hints" id="hints" hidden><span id="hint-left"></span><span id="hint-right"></span></div>
|
|
64
|
+
</div>
|
|
65
|
+
</footer>
|
|
66
|
+
</div>
|
|
67
|
+
<aside class="side" id="side" hidden></aside>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
<div class="sheet-back" id="sheet-back" hidden></div>
|
|
71
|
+
<section class="sheet" id="sheet" hidden aria-label="About this chat">
|
|
72
|
+
<header><h2>About this chat</h2><button class="btn ghost" id="sheet-close" type="button">Done</button></header>
|
|
73
|
+
<div class="sheet-body" id="sheet-body"></div>
|
|
74
|
+
</section>
|
|
75
|
+
<div class="drop" id="drop" hidden><div>Drop screenshots to add them</div></div>
|
|
76
|
+
<script>window.PARLEY = {{CONFIG}};</script>
|
|
77
|
+
<script src="/static/markdown.js"></script>
|
|
78
|
+
<script src="/static/seal.js"></script>
|
|
79
|
+
<script src="/static/chat.js"></script>
|
|
80
|
+
</body>
|
|
81
|
+
</html>
|