yoyo-pi 0.1.4

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.
@@ -0,0 +1,481 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en"><head>
3
+ <meta charset="utf-8">
4
+ <title>pi-TUI · status bar variations</title>
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <!-- Standalone preview: no bundler wrapper, so GitHub HTML previewers can render it reliably. -->
7
+ <style>
8
+ /* ── page chrome ────────────────────────────────────────────────────── */
9
+ html, body { margin: 0; padding: 0; }
10
+ body {
11
+ font-family: 'Inter', system-ui, sans-serif;
12
+ background: #1a1916;
13
+ color: #E8E3D9;
14
+ min-height: 100vh;
15
+ padding: 56px 40px 80px;
16
+ -webkit-font-smoothing: antialiased;
17
+ }
18
+ .page-h {
19
+ max-width: 980px;
20
+ margin: 0 auto 48px;
21
+ }
22
+ .page-h h1 {
23
+ font-family: 'Fraunces', serif;
24
+ font-weight: 600;
25
+ font-size: 40px;
26
+ letter-spacing: -0.01em;
27
+ margin: 0 0 8px;
28
+ color: #ECE7DC;
29
+ }
30
+ .page-h .sub {
31
+ color: #9A9385;
32
+ font-size: 15px;
33
+ max-width: 60ch;
34
+ text-wrap: pretty;
35
+ }
36
+
37
+ .theme-switch {
38
+ max-width: 980px;
39
+ margin: 0 auto 28px;
40
+ display: flex;
41
+ gap: 8px;
42
+ align-items: center;
43
+ font-size: 13px;
44
+ color: #9A9385;
45
+ }
46
+ .theme-switch button {
47
+ font: inherit;
48
+ background: transparent;
49
+ color: #B0A99A;
50
+ border: 1px solid rgba(236,231,220,0.18);
51
+ border-radius: 6px;
52
+ padding: 5px 12px;
53
+ cursor: pointer;
54
+ transition: background 200ms, color 200ms, border-color 200ms;
55
+ }
56
+ .theme-switch button:hover { background: rgba(236,231,220,0.06); color: #ECE7DC; }
57
+ .theme-switch button[aria-pressed="true"] {
58
+ background: rgba(216,155,126,0.15);
59
+ color: #D89B7E;
60
+ border-color: rgba(216,155,126,0.4);
61
+ }
62
+
63
+ .grid {
64
+ max-width: 980px;
65
+ margin: 0 auto;
66
+ display: grid;
67
+ grid-template-columns: 1fr;
68
+ gap: 36px;
69
+ }
70
+ .card {
71
+ display: flex;
72
+ flex-direction: column;
73
+ gap: 12px;
74
+ }
75
+ .card .label {
76
+ display: flex;
77
+ align-items: baseline;
78
+ gap: 10px;
79
+ color: #9A9385;
80
+ font-size: 13px;
81
+ }
82
+ .card .label .n {
83
+ font-family: 'JetBrains Mono', monospace;
84
+ color: #D89B7E;
85
+ font-weight: 500;
86
+ }
87
+ .card .label .name {
88
+ color: #ECE7DC;
89
+ font-weight: 500;
90
+ }
91
+ .card .label .note {
92
+ color: #777768;
93
+ font-size: 12px;
94
+ }
95
+
96
+ /* ── tui surface ────────────────────────────────────────────────────── */
97
+ .tui-screen {
98
+ /* paper (default) */
99
+ --tui-bg: #EFE7D4;
100
+ --tui-bg-edge: #E5DBC2;
101
+ --tui-ink: #1D1916;
102
+ --tui-ink-2: #5B524A;
103
+ --tui-ink-3: #8C8175;
104
+ --tui-rule: rgba(29,25,22,0.18);
105
+ --tui-red: #8C2A1F;
106
+ --tui-red-bg: rgba(140,42,31,0.10);
107
+ --tui-yellow: #8A6A1F;
108
+ --tui-yellow-bg: rgba(138,106,31,0.12);
109
+ --tui-green: #3F5C45;
110
+ --tui-green-bg: rgba(63,92,69,0.12);
111
+ --tui-blue: #2F5A78;
112
+ --tui-blue-bg: rgba(47,90,120,0.10);
113
+ --tui-purple: #6E4A78;
114
+ --tui-cursor: #8C2A1F;
115
+ --tui-selection: rgba(140,42,31,0.18);
116
+ --tui-paper-tex: 0.6;
117
+
118
+ background: var(--tui-bg);
119
+ color: var(--tui-ink);
120
+ font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
121
+ font-size: 13px;
122
+ line-height: 1.55;
123
+ border-radius: 4px;
124
+ padding: 22px 24px;
125
+ white-space: pre;
126
+ overflow: hidden;
127
+ position: relative;
128
+ isolation: isolate;
129
+ box-shadow:
130
+ 0 1px 0 rgba(0,0,0,0.4),
131
+ 0 12px 28px rgba(0,0,0,0.35);
132
+ }
133
+ .tui-screen::before {
134
+ content: '';
135
+ position: absolute; inset: 0;
136
+ pointer-events: none;
137
+ z-index: 0;
138
+ background-image:
139
+ radial-gradient(circle at 17% 23%, rgba(0,0,0,0.030) 0.5px, transparent 1px),
140
+ radial-gradient(circle at 71% 41%, rgba(0,0,0,0.022) 0.5px, transparent 1px),
141
+ radial-gradient(circle at 41% 73%, rgba(0,0,0,0.020) 0.5px, transparent 1px),
142
+ radial-gradient(circle at 89% 89%, rgba(0,0,0,0.025) 0.5px, transparent 1px);
143
+ background-size: 7px 7px, 11px 11px, 13px 13px, 19px 19px;
144
+ opacity: var(--tui-paper-tex);
145
+ }
146
+ .tui-screen::after {
147
+ content: '';
148
+ position: absolute; inset: 0;
149
+ pointer-events: none;
150
+ z-index: 0;
151
+ box-shadow:
152
+ inset 0 0 80px rgba(29,25,22,0.06),
153
+ inset 0 0 0 1px rgba(29,25,22,0.05);
154
+ }
155
+ .tui-screen > * { position: relative; z-index: 1; }
156
+
157
+ body[data-theme="dark"] .tui-screen {
158
+ --tui-bg: #2E322E;
159
+ --tui-bg-edge: #272A27;
160
+ --tui-ink: #ECE7DC;
161
+ --tui-ink-2: #B0B0A5;
162
+ --tui-ink-3: #777768;
163
+ --tui-rule: rgba(236,231,220,0.18);
164
+ --tui-red: #D89B7E;
165
+ --tui-red-bg: rgba(216,155,126,0.14);
166
+ --tui-yellow: #D9B670;
167
+ --tui-yellow-bg: rgba(217,182,112,0.16);
168
+ --tui-green: #ADC79A;
169
+ --tui-green-bg: rgba(173,199,154,0.14);
170
+ --tui-blue: #8FB4CE;
171
+ --tui-blue-bg: rgba(143,180,206,0.12);
172
+ --tui-purple: #BCA0C5;
173
+ --tui-cursor: #D89B7E;
174
+ --tui-selection: rgba(216,155,126,0.20);
175
+ --tui-paper-tex: 0;
176
+ }
177
+ body[data-theme="dark"] .tui-screen::before { display: none; }
178
+
179
+ body[data-theme="light"] .tui-screen {
180
+ --tui-bg: #F5F1EA;
181
+ --tui-bg-edge: #ECE7DC;
182
+ --tui-ink: #2A2D28;
183
+ --tui-ink-2: #6B6B60;
184
+ --tui-ink-3: #9A9A8E;
185
+ --tui-rule: rgba(42,45,40,0.14);
186
+ --tui-red: #A8734F;
187
+ --tui-yellow: #A88A50;
188
+ --tui-green: #6F8A68;
189
+ --tui-blue: #5F8880;
190
+ --tui-purple: #8A6E9C;
191
+ --tui-cursor: #A8734F;
192
+ --tui-selection: rgba(168,115,79,0.16);
193
+ --tui-paper-tex: 0;
194
+ }
195
+ body[data-theme="light"] .tui-screen::before { display: none; }
196
+
197
+ .tui-line { display: block; white-space: pre; font-feature-settings: 'liga' 0, 'calt' 0; }
198
+
199
+ .tui-red { color: var(--tui-red); }
200
+ .tui-yel { color: var(--tui-yellow); }
201
+ .tui-grn { color: var(--tui-green); }
202
+ .tui-blu { color: var(--tui-blue); }
203
+ .tui-pur { color: var(--tui-purple); }
204
+ .tui-dim { color: var(--tui-ink-2); }
205
+ .tui-faint { color: var(--tui-ink-3); }
206
+ .tui-bold { font-weight: 700; }
207
+ .tui-italic { font-style: italic; }
208
+
209
+ .tui-fill-red { background: var(--tui-red-bg); color: var(--tui-red); }
210
+ .tui-fill-yel { background: var(--tui-yellow-bg); color: var(--tui-yellow); }
211
+ .tui-fill-grn { background: var(--tui-green-bg); color: var(--tui-green); }
212
+ .tui-fill-blu { background: var(--tui-blue-bg); color: var(--tui-blue); }
213
+ .tui-fill-dim { background: rgba(0,0,0,0.05); }
214
+
215
+ .tui-cursor {
216
+ display: inline-block;
217
+ width: 1ch;
218
+ background: var(--tui-cursor);
219
+ color: var(--tui-cursor);
220
+ animation: tui-blink 1.0s steps(2) infinite;
221
+ }
222
+ .tui-cursor::before { content: '█'; }
223
+ @keyframes tui-blink {
224
+ 0%, 49% { opacity: 1; }
225
+ 50%, 100% { opacity: 0.18; }
226
+ }
227
+ </style>
228
+ </head>
229
+
230
+ <body data-theme="dark">
231
+
232
+ <div class="page-h">
233
+ <h1>Status bar &amp; input — variations</h1>
234
+ <p class="sub">Eight takes on the bottom strip of pi-TUI. Each shows the current path, the active model and its reasoning strength, and (when in a git repo) the branch with change counts.</p>
235
+ </div>
236
+
237
+ <div class="theme-switch">
238
+ <span>theme&nbsp;·&nbsp;</span>
239
+ <button data-theme-btn="paper">paper</button>
240
+ <button data-theme-btn="dark" aria-pressed="true">dark</button>
241
+ <button data-theme-btn="light">light</button>
242
+ </div>
243
+
244
+ <div class="grid" id="grid"></div>
245
+
246
+ <script>
247
+ // ── parser ─────────────────────────────────────────────────────────────
248
+ // Same «cls»…«/» marker convention as the main project.
249
+ function tuiRender(line) {
250
+ const out = [];
251
+ const stack = [];
252
+ let buf = '';
253
+ let i = 0;
254
+ const flush = () => {
255
+ if (!buf) return;
256
+ const text = escapeHtml(buf);
257
+ if (stack.length) {
258
+ const cls = stack.map(mapClass).join(' ');
259
+ out.push(`<span class="${cls}">${text}</span>`);
260
+ } else {
261
+ out.push(text);
262
+ }
263
+ buf = '';
264
+ };
265
+ while (i < line.length) {
266
+ if (line[i] === '«' && line.charAt(i + 1) === '/' && line.charAt(i + 2) === '»') {
267
+ flush();
268
+ stack.pop();
269
+ i += 3;
270
+ } else if (line[i] === '«') {
271
+ const close = line.indexOf('»', i + 1);
272
+ if (close === -1) { buf += line[i]; i++; continue; }
273
+ flush();
274
+ const tok = line.slice(i + 1, close);
275
+ if (tok === 'cur') {
276
+ out.push('<span class="tui-cursor"></span>');
277
+ } else {
278
+ stack.push(tok);
279
+ }
280
+ i = close + 1;
281
+ } else {
282
+ buf += line[i];
283
+ i++;
284
+ }
285
+ }
286
+ flush();
287
+ return out.join('');
288
+ }
289
+ function escapeHtml(s) {
290
+ return s.replace(/[&<>]/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;'}[c]));
291
+ }
292
+ function mapClass(k) {
293
+ return ({
294
+ red:'tui-red', yel:'tui-yel', grn:'tui-grn', blu:'tui-blu', pur:'tui-pur',
295
+ dim:'tui-dim', faint:'tui-faint', b:'tui-bold', it:'tui-italic',
296
+ fred:'tui-fill-red', fyel:'tui-fill-yel', fgrn:'tui-fill-grn',
297
+ fblu:'tui-fill-blu', fdim:'tui-fill-dim',
298
+ }[k] || k);
299
+ }
300
+ function tuiLen(line) {
301
+ return line.replace(/«cur»/g, ' ').replace(/«[^»]*»/g, '').length;
302
+ }
303
+ function tuiPad(line, width, fill = ' ') {
304
+ const n = tuiLen(line);
305
+ if (n >= width) return line;
306
+ return line + fill.repeat(width - n);
307
+ }
308
+ function lr(left, right, W, fill = ' ') {
309
+ const gap = W - tuiLen(left) - tuiLen(right);
310
+ return left + fill.repeat(Math.max(1, gap)) + right;
311
+ }
312
+
313
+ // ── shared data ────────────────────────────────────────────────────────
314
+ const PATH = '~/projects/sage-app';
315
+ const PATH_LONG = '…/sage-app/src/components';
316
+ const MODEL = 'gpt-5.5';
317
+ const STRENGTH = 'xhigh';
318
+ const BRANCH = 'feat/picker-ctx';
319
+ const GIT_MOD = 3;
320
+ const GIT_UNT = 1;
321
+ const PROMPT = '«red b»›«/»';
322
+ const HINT = '«faint it»message pi…«/»';
323
+ const CUR = '«cur»';
324
+ const HINTS = '«dim»[/]«/»«faint» cmds «/»«faint»·«/»«dim» [@]«/»«faint» files «/»«faint»·«/»«dim» [⏎]«/»«faint» send«/»';
325
+
326
+ // ── variants ───────────────────────────────────────────────────────────
327
+
328
+ function v1_hairline() {
329
+ const W = 92, L = [];
330
+ L.push('«faint»' + '─'.repeat(W) + '«/»');
331
+ L.push(' ' + PROMPT + ' ' + tuiPad('refactor the file picker to use a provider context' + CUR, W - 4));
332
+ L.push('«faint»' + '─'.repeat(W) + '«/»');
333
+ L.push('');
334
+ const left = `«dim»${PATH}«/» «faint»·«/» «grn»⎇«/» «b»${BRANCH}«/» «yel»✚${GIT_MOD}«/» «red»?${GIT_UNT}«/»`;
335
+ const right = `«faint»model«/» «b»${MODEL}«/» «faint»·«/» «yel»${STRENGTH}«/»`;
336
+ L.push(' ' + lr(left, right + ' ', W - 1));
337
+ return L;
338
+ }
339
+
340
+ function v2_chips() {
341
+ const W = 92, L = [];
342
+ L.push('╭' + '─'.repeat(W - 2) + '╮');
343
+ L.push('│ ' + PROMPT + ' ' + tuiPad(HINT + CUR, W - 6) + ' │');
344
+ L.push('│' + ' '.repeat(W - 2) + '│');
345
+ const seg1 = ` «dim»${PATH}«/» `;
346
+ const seg2 = ` «grn»⎇«/» «b»${BRANCH}«/» «red»?${GIT_UNT}«/» «yel»✚${GIT_MOD}«/» `;
347
+ const seg3 = ` «b»${MODEL}«/» «faint»·«/» «yel»${STRENGTH}«/» `;
348
+ const inner = '─' + seg1 + '─' + seg2 + '─';
349
+ const tail = '─' + seg3 + '─';
350
+ const fill = W - 2 - tuiLen(inner) - tuiLen(tail);
351
+ L.push('╰' + inner + '─'.repeat(Math.max(1, fill)) + tail + '╯');
352
+ return L;
353
+ }
354
+
355
+ function v3_status_above() {
356
+ const W = 92, L = [];
357
+ const left = `«faint»in«/» «dim»${PATH}«/» «grn»⎇«/» «b»${BRANCH}«/» «yel»✚${GIT_MOD}«/» «red»?${GIT_UNT}«/»`;
358
+ const right = `«faint»using«/» «b»${MODEL}«/» «faint»·«/» «yel»${STRENGTH}«/»`;
359
+ L.push(' ' + lr(left, right + ' ', W - 2));
360
+ L.push('');
361
+ L.push(' ╭' + '─'.repeat(W - 6) + '╮');
362
+ L.push(' │ ' + PROMPT + ' ' + tuiPad('refactor the file picker' + CUR, W - 10) + ' │');
363
+ L.push(' ╰' + '─'.repeat(W - 6) + '╯');
364
+ L.push(' ' + tuiPad('', W - 2 - tuiLen(HINTS)) + HINTS);
365
+ return L;
366
+ }
367
+
368
+ function v4_pills() {
369
+ const W = 92, L = [];
370
+ L.push('«faint»' + '╴ '.repeat(Math.floor(W / 2)) + '«/»');
371
+ L.push(' ' + PROMPT + ' ' + tuiPad(HINT + CUR, W - 4));
372
+ L.push('«faint»' + '╴ '.repeat(Math.floor(W / 2)) + '«/»');
373
+ L.push('');
374
+ const p1 = `«fdim» ${PATH} «/»`;
375
+ const p2 = `«fgrn» ⎇ ${BRANCH} «/»` + ` «fyel» ✚${GIT_MOD} «/»` + ` «fred» ?${GIT_UNT} «/»`;
376
+ const p3 = `«fred» ${MODEL} «/»` + ` «fdim» ${STRENGTH} «/»`;
377
+ L.push(' ' + lr(p1 + ' ' + p2, p3 + ' ', W - 1));
378
+ return L;
379
+ }
380
+
381
+ function v5_corner_tabs() {
382
+ const W = 92, L = [];
383
+ const leftTab = '─ «faint»chat«/» ';
384
+ const rightTab = ` «b»${MODEL}«/» «faint»·«/» «yel»${STRENGTH}«/» ─`;
385
+ const topMid = W - 2 - tuiLen(leftTab) - tuiLen(rightTab);
386
+ L.push('╭' + leftTab + '─'.repeat(topMid) + rightTab + '╮');
387
+ L.push('│' + ' '.repeat(W - 2) + '│');
388
+ L.push('│ ' + PROMPT + ' ' + tuiPad('refactor the file picker' + CUR, W - 8) + ' │');
389
+ L.push('│' + ' '.repeat(W - 2) + '│');
390
+ const lTab = `─ «dim»${PATH}«/» `;
391
+ const rTab = ` «grn»⎇«/» «b»${BRANCH}«/» «yel»✚${GIT_MOD}«/» «red»?${GIT_UNT}«/» ─`;
392
+ const botMid = W - 2 - tuiLen(lTab) - tuiLen(rTab);
393
+ L.push('╰' + lTab + '─'.repeat(botMid) + rTab + '╯');
394
+ return L;
395
+ }
396
+
397
+ function v6_margin() {
398
+ const W = 92, L = [];
399
+ const MARGIN = 22;
400
+ const FIELD = W - MARGIN;
401
+ const m = s => tuiPad(s, MARGIN);
402
+ L.push(m('«faint»path«/»') + '«faint»╴«/» ' + tuiPad(HINT + CUR, FIELD - 4));
403
+ L.push(m(`«dim»${PATH}«/»`) + '«faint»' + '─'.repeat(FIELD) + '«/»');
404
+ L.push('');
405
+ L.push(m('«faint»branch«/»') + ' ');
406
+ L.push(m(`«grn»⎇«/» «b»${BRANCH}«/» «yel»✚${GIT_MOD}«/» «red»?${GIT_UNT}«/»`) + ' ');
407
+ L.push('');
408
+ L.push(m('«faint»model«/»') + tuiPad('', FIELD - tuiLen(HINTS) - 2) + HINTS);
409
+ L.push(m(`«b»${MODEL}«/» «faint»·«/» «yel»${STRENGTH}«/»`) + ' ');
410
+ return L;
411
+ }
412
+
413
+ function v7_dense() {
414
+ const W = 92, L = [];
415
+ const left = `«dim»${PATH_LONG}«/» «faint»│«/» «grn»⎇«/» «b»${BRANCH}«/» «yel»✚${GIT_MOD}«/» «red»?${GIT_UNT}«/»`;
416
+ const right = `«b»${MODEL}«/» «faint»·«/» «yel»${STRENGTH}«/»`;
417
+ L.push(' ' + lr(left, right + ' ', W - 1));
418
+ L.push('«faint»' + '─'.repeat(W) + '«/»');
419
+ L.push(' ' + PROMPT + ' ' + tuiPad(HINT + CUR, W - 4));
420
+ L.push(' ' + tuiPad('', W - 3 - tuiLen(HINTS)) + HINTS + ' ');
421
+ return L;
422
+ }
423
+
424
+ function v8_badges() {
425
+ const W = 92, L = [];
426
+ L.push(' ╭' + '─'.repeat(W - 6) + '╮');
427
+ L.push(' │ ' + PROMPT + ' ' + tuiPad('how should I commit this?' + CUR, W - 10) + ' │');
428
+ L.push(' ╰' + '─'.repeat(W - 6) + '╯');
429
+ L.push('');
430
+ const b1 = `«faint»❯«/» «dim»${PATH}«/»`;
431
+ const b2 = `«grn»⎇«/» «b»${BRANCH}«/»`;
432
+ const b3 = `«yel»✚«/»${GIT_MOD} «red»?«/»${GIT_UNT}`;
433
+ const b4 = `«faint»◆«/» «b»${MODEL}«/» «faint»/«/» «yel»${STRENGTH}«/»`;
434
+ const left = `${b1} «faint»·«/» ${b2} «faint»·«/» ${b3}`;
435
+ const right = `${b4}`;
436
+ L.push(' ' + lr(left, right + ' ', W - 2));
437
+ return L;
438
+ }
439
+
440
+ const VARIANTS = [
441
+ { n: 'V1', name: 'hairline rules', note: 'closest to your current design, refined', build: v1_hairline },
442
+ { n: 'V2', name: 'rule-embedded chips', note: 'status baked into the bottom rule', build: v2_chips },
443
+ { n: 'V3', name: 'status above input', note: 'info row first, soft-boxed input below', build: v3_status_above },
444
+ { n: 'V4', name: 'label pills', note: 'tinted blocks · vintage label strip', build: v4_pills },
445
+ { n: 'V5', name: 'corner tabs', note: 'index-card style with top + bottom tabs', build: v5_corner_tabs },
446
+ { n: 'V6', name: 'margin labels', note: 'editorial type-set, status in left margin',build: v6_margin },
447
+ { n: 'V7', name: 'single-line dense', note: 'truncated path · single status row', build: v7_dense },
448
+ { n: 'V8', name: 'badges row', note: 'boxed input + horizontal icon badges', build: v8_badges },
449
+ ];
450
+
451
+ // ── mount ──────────────────────────────────────────────────────────────
452
+ const grid = document.getElementById('grid');
453
+ for (const v of VARIANTS) {
454
+ const card = document.createElement('div');
455
+ card.className = 'card';
456
+ card.innerHTML = `
457
+ <div class="label">
458
+ <span class="n">${v.n}</span>
459
+ <span class="name">${v.name}</span>
460
+ <span class="note">${v.note}</span>
461
+ </div>
462
+ <div class="tui-screen">${v.build().map(l => `<span class="tui-line">${tuiRender(l) || '&nbsp;'}</span>`).join('')}</div>
463
+ `;
464
+ grid.appendChild(card);
465
+ }
466
+
467
+ // theme switch
468
+ document.querySelectorAll('[data-theme-btn]').forEach(btn => {
469
+ btn.addEventListener('click', () => {
470
+ const theme = btn.dataset.themeBtn;
471
+ document.body.dataset.theme = theme;
472
+ document.querySelectorAll('[data-theme-btn]').forEach(b => {
473
+ b.setAttribute('aria-pressed', b === btn ? 'true' : 'false');
474
+ });
475
+ });
476
+ });
477
+ </script>
478
+
479
+
480
+
481
+ </body></html>
Binary file
Binary file
Binary file