@leftoff/cli 0.8.8 → 0.9.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/CHANGELOG.md +31 -1
- package/assets/sample-transcript.jsonl +12 -12
- package/bin/leftoff.js +377 -371
- package/mod/.claude-plugin/plugin.json +1 -1
- package/mod/hooks/core.js +2 -1
- package/mod/hooks/register.js +14 -4
- package/package.json +1 -1
- package/ui/app.css +138 -16
- package/ui/app.js +348 -56
- package/ui/changelog-md.js +6 -2
- package/ui/handoffs.js +62 -5
- package/ui/icons.js +4 -0
- package/ui/picker.js +38 -1
- package/ui/prs.js +134 -43
- package/ui/repos.js +23 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "leftoff",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Leftoff (formerly Checkpoints): WTF was I working on? Tracks every Claude Code session on this machine, writes a 3-line checkpoint when one goes quiet, and adds /cp (checkpoint now), /cp-name and a /leftoff pane. Talks to the local Leftoff daemon on 127.0.0.1:7429 and falls back to writing markdown in ~/checkpoints.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Joel"
|
package/mod/hooks/core.js
CHANGED
|
@@ -537,7 +537,7 @@ const SESSION_ORDER = ['id', 'title', 'title_source', 'machine', 'cwd', 'repo',
|
|
|
537
537
|
export const SESSION_EXTRA = ['inTurn', 'needsInput', 'backgroundTasks', 'turnsSinceCheckpoint', 'dormantStretch',
|
|
538
538
|
'finalCheckpointDone', 'firstPrompt', 'lastPreview', 'lastNotification', 'lastEventAt', 'statusChanges', 'folder',
|
|
539
539
|
'pid', 'tty', 'pidStartedAt', 'pidSource', 'term', 'closedAt', 'answers', 'lastNotificationMessage', 'needsInputAt', 'question', 'questionAt',
|
|
540
|
-
'startSource', 'historyTurns', 'healedAt', 'healedVia', 'archivedReason', 'backend', 'prLinks', 'prUnlinked', 'todos', 'files', 'startRepo', 'editedRepos', 'parked', 'nonInteractive']
|
|
540
|
+
'startSource', 'historyTurns', 'healedAt', 'healedVia', 'archivedReason', 'backend', 'prLinks', 'prUnlinked', 'todos', 'files', 'startRepo', 'editedRepos', 'parked', 'nonInteractive', 'transcriptCwd', 'doubtedCheckpoints']
|
|
541
541
|
|
|
542
542
|
export const SESSION_FIELDS = ['id', 'title', 'titleSource', 'machine', 'cwd', 'repo', 'transcriptPath', 'model', 'surface', 'capture',
|
|
543
543
|
'status', 'startedAt', 'lastActivityAt', 'lastHeartbeatAt', 'endedAt', 'endReason', 'turns', 'lastCheckpointId',
|
|
@@ -1222,6 +1222,7 @@ const CHECKPOINT_BASE = [
|
|
|
1222
1222
|
'Stopped at: <the exact state when it went quiet: what passed, what failed, what is half-done>',
|
|
1223
1223
|
'Next: <the single next action a human or the agent should take>',
|
|
1224
1224
|
'If the session is blocked on the human (a question, a permission, a decision), start Next with "YOU:".',
|
|
1225
|
+
'Describe only what the transcript shows; the lines above it (repo, branch, title, previous checkpoint) are background and may be out of date.',
|
|
1225
1226
|
]
|
|
1226
1227
|
const INFORMATIVE_SECTIONS = [
|
|
1227
1228
|
'Then these sections, each a heading line followed by "- " bullets (write "- none" when there is nothing; never invent):',
|
package/mod/hooks/register.js
CHANGED
|
@@ -28,7 +28,7 @@ const END_TIMEOUT_MS = 1000
|
|
|
28
28
|
const MODEL_TIMEOUT_MS = 20000
|
|
29
29
|
|
|
30
30
|
// Module state. $.state is not used: the pane redraws with $.ui.invalidate.
|
|
31
|
-
const MOD_VERSION = '0.
|
|
31
|
+
const MOD_VERSION = '0.9.0' // keep in step with .claude-plugin/plugin.json
|
|
32
32
|
|
|
33
33
|
const st = {
|
|
34
34
|
internal: false,
|
|
@@ -197,7 +197,7 @@ async function heartbeat($) {
|
|
|
197
197
|
// release takes a name. -> st.commands: [{ key, want, name, ok, error }]
|
|
198
198
|
const COMMANDS = [
|
|
199
199
|
{ key: 'checkpoint', names: ['cp', 'cp-save'], description: 'Leftoff: save a checkpoint of this session now (--short / --long for this one)', argumentHint: '[--short|--long] [note]', immediate: true },
|
|
200
|
-
{ key: 'name', names: ['cp-name'], description: 'Leftoff: name this session (runs /rename, tells the board)', argumentHint: '<title>', immediate: false },
|
|
200
|
+
{ key: 'name', names: ['cp-name'], description: 'Leftoff: name this session (runs /rename, tells the board); --auto names it from the latest messages', argumentHint: '<title> | --auto', immediate: false },
|
|
201
201
|
{ key: 'pane', names: ['leftoff'], description: 'Leftoff: every open session and its status (/leftoff open: the board)', argumentHint: '[open]', immediate: true },
|
|
202
202
|
// The pane's pre-0.4.5 name, kept so the habit keeps working.
|
|
203
203
|
{ key: 'pane-old', names: ['checkpoints'], description: 'Leftoff (old name): same as /leftoff', argumentHint: '[open]', immediate: true },
|
|
@@ -684,8 +684,18 @@ function afterCheckpoint($, cp, trigger) {
|
|
|
684
684
|
}
|
|
685
685
|
|
|
686
686
|
async function nameSession($, args) {
|
|
687
|
-
|
|
688
|
-
if (!title) { $.ui.toast('Usage: /' + st.nameCommand + ' <title>'); return {} }
|
|
687
|
+
let title = String(args || '').trim()
|
|
688
|
+
if (!title) { $.ui.toast('Usage: /' + st.nameCommand + ' <title> (or --auto: a new title from the latest messages)'); return {} }
|
|
689
|
+
// 0.9.0: --auto (also auto, -a): the daemon writes a title from the most recent messages
|
|
690
|
+
if (/^(--auto|auto|-a)$/i.test(title)) {
|
|
691
|
+
const r = st.sessionId ? await api($, 'POST', '/v1/sessions/' + encodeURIComponent(st.sessionId) + '/title/auto', {}, 30000) : null
|
|
692
|
+
if (!(r && r.ok && r.json && r.json.title)) { $.ui.toast('Couldn’t make a title: ' + ((r && r.json && r.json.error && r.json.error.message) || 'the Leftoff daemon isn’t answering')); return {} }
|
|
693
|
+
title = r.json.title
|
|
694
|
+
if (tabTitleOn()) { if (!st.record) st.record = {}; st.record.title = title; await applyTabTitle($, title, { force: true }) }
|
|
695
|
+
else { try { await $.command.run({ command: 'rename', args: title }) } catch {} }
|
|
696
|
+
$.ui.toast('Named this session “' + clip(title, 60) + '” (from the latest messages)')
|
|
697
|
+
return {}
|
|
698
|
+
}
|
|
689
699
|
if (tabTitleOn()) {
|
|
690
700
|
if (!st.record) st.record = {}
|
|
691
701
|
st.record.title = title
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leftoff/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Leftoff: WTF was I working on? Tracks every Claude Code session, writes a 3-line checkpoint when one goes quiet, and gives you a daily digest and a board, on your Mac and (optionally) your phone.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude",
|
package/ui/app.css
CHANGED
|
@@ -110,6 +110,14 @@ h2 .count { color: var(--faint); font-weight: 500; }
|
|
|
110
110
|
.card .row1 { display: flex; align-items: flex-start; gap: 10px; }
|
|
111
111
|
.card .title { font-size: 15px; font-weight: 600; line-height: 1.35; flex: 1; }
|
|
112
112
|
.card .title a:hover { text-decoration: underline; text-decoration-color: var(--faint); }
|
|
113
|
+
.s-title { display: flex; align-items: center; gap: 6px; min-width: 0; }
|
|
114
|
+
.s-title h1 { min-width: 0; }
|
|
115
|
+
.s-title-text { cursor: text; border-radius: 6px; outline-offset: 2px; }
|
|
116
|
+
.s-title-text:hover { background: var(--subtle); box-shadow: 0 0 0 4px var(--subtle); }
|
|
117
|
+
.s-title .rename-pen { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border-radius: 8px; border: 1px solid transparent; background: none; color: var(--muted); cursor: pointer; }
|
|
118
|
+
.s-title .rename-pen:hover, .s-title .rename-pen:focus-visible { color: var(--accent); border-color: var(--line); background: var(--bg2); }
|
|
119
|
+
.s-title .rename-pen svg { width: 16px; height: 16px; }
|
|
120
|
+
.s-title input { flex: 1 1 auto; width: min(560px, calc(100vw - 80px)); min-width: 0; font-family: inherit; font-weight: 700; font-size: 22px; line-height: 1.25; color: var(--text); background: var(--field); border: 1px solid var(--accent); border-radius: 8px; padding: 4px 8px; margin: 6px 0; }
|
|
113
121
|
.card .title input { width: 100%; background: var(--bg); border: 1px solid var(--accent); border-radius: 6px; color: var(--text); padding: 3px 6px; font: inherit; }
|
|
114
122
|
.mt { margin-top: 20px; }
|
|
115
123
|
.icon { background: none; border: 0; color: var(--faint); cursor: pointer; padding: 0 4px; margin-left: 4px; font-size: 13px; opacity: 0; transition: opacity .15s; }
|
|
@@ -1432,6 +1440,17 @@ a.cpr:hover { border-color: var(--line-strong); }
|
|
|
1432
1440
|
.prs-q { width: 100%; max-width: 480px; font-size: 16px; padding: 8px 12px; border-radius: 10px; border: 1px solid var(--line); background: var(--card); color: var(--text); }
|
|
1433
1441
|
.prs-chips { margin-top: 8px; }
|
|
1434
1442
|
.prs-chips .rchip.ck .rl::before { content: '◇ '; color: var(--faint); }
|
|
1443
|
+
/* 0.8.9: the buckets, each with its color dot (chips) and heading color (groups) */
|
|
1444
|
+
.prs-buckets .rchip .rl::before { content: ''; display: inline-block; width: 7px; height: 7px; border-radius: 50%; margin-right: 6px; vertical-align: 1px; background: var(--b, var(--gray)); }
|
|
1445
|
+
.prs-buckets .rchip { font-family: inherit; }
|
|
1446
|
+
.rchip.b-review, .prgroup.b-review { --b: var(--accent); }
|
|
1447
|
+
.rchip.b-fix, .prgroup.b-fix { --b: var(--red); }
|
|
1448
|
+
.rchip.b-ready, .prgroup.b-ready { --b: var(--green); }
|
|
1449
|
+
.rchip.b-waiting, .prgroup.b-waiting { --b: var(--yellow); }
|
|
1450
|
+
.rchip.b-merged, .prgroup.b-merged { --b: var(--machine); }
|
|
1451
|
+
.rchip.b-closed, .prgroup.b-closed { --b: var(--gray); }
|
|
1452
|
+
.prgroup[class*="b-"] > h2 { color: var(--b); }
|
|
1453
|
+
.prgroup[class*="b-"] > h2::before { content: ''; display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 7px; vertical-align: 1px; background: var(--b); }
|
|
1435
1454
|
.pr-why { color: var(--muted); }
|
|
1436
1455
|
.prrow { cursor: pointer; }
|
|
1437
1456
|
.prrow.open { border-color: var(--line-strong); }
|
|
@@ -1556,30 +1575,97 @@ ul.files-list li + li { border-top: 1px solid var(--line); }
|
|
|
1556
1575
|
.doc-viewer { position: fixed; inset: 0; z-index: 60; background: rgba(0,0,0,.55); display: flex; align-items: stretch; justify-content: center; padding: max(16px, env(safe-area-inset-top)) 12px 12px; }
|
|
1557
1576
|
.doc-viewer[hidden] { display: none; }
|
|
1558
1577
|
html.dv-open, html.dv-open body { overflow: hidden; }
|
|
1559
|
-
.dv-sheet { width:
|
|
1560
|
-
.dv-head { display: flex; align-items: center; gap:
|
|
1578
|
+
.dv-sheet { width: min(1100px, 92vw); max-width: 100%; background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius); display: flex; flex-direction: column; overflow: hidden; box-shadow: var(--toast-shadow); }
|
|
1579
|
+
.dv-head { display: flex; align-items: center; gap: 8px; padding: 10px 12px 10px 16px; border-bottom: 1px solid var(--line); }
|
|
1561
1580
|
.dv-title { flex: 1; min-width: 0; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1562
1581
|
.dv-x { flex: none; width: 36px; height: 36px; border-radius: 10px; border: 1px solid var(--line); background: var(--bg2); color: var(--text); font-size: 20px; line-height: 1; cursor: pointer; }
|
|
1563
|
-
.dv-
|
|
1564
|
-
.dv-
|
|
1565
|
-
.
|
|
1566
|
-
.
|
|
1567
|
-
.
|
|
1568
|
-
.
|
|
1569
|
-
.
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
.doc-
|
|
1582
|
+
.dv-dl { flex: none; display: inline-flex; align-items: center; gap: 6px; }
|
|
1583
|
+
.dv-dl svg { width: 15px; height: 15px; }
|
|
1584
|
+
.dv-dl .chev { font-size: 10px; opacity: .7; margin-left: 1px; }
|
|
1585
|
+
.dv-dl.copied { color: var(--green); border-color: var(--green); }
|
|
1586
|
+
.dv-ptitle { display: none; }
|
|
1587
|
+
.dv-sub { padding: 6px 16px 0; font-size: 12px; }
|
|
1588
|
+
.dv-body { flex: 1; overflow: auto; padding: 10px 24px 32px; -webkit-overflow-scrolling: touch; }
|
|
1589
|
+
/* 0.8.9: a phone gets the whole screen (a sheet), not a card with margins */
|
|
1590
|
+
@media (max-width: 599.98px) {
|
|
1591
|
+
.doc-viewer { padding: 0; }
|
|
1592
|
+
.dv-sheet { width: 100%; border: 0; border-radius: 0; box-shadow: none; padding-top: env(safe-area-inset-top); }
|
|
1593
|
+
.dv-head { padding: 8px 8px 8px 14px; }
|
|
1594
|
+
.dv-body { padding: 8px 16px calc(28px + env(safe-area-inset-bottom)); }
|
|
1595
|
+
.dv-sub { padding: 6px 14px 0; }
|
|
1596
|
+
.dv-dl .dl-word { display: none; }
|
|
1597
|
+
}
|
|
1598
|
+
html.dv-open .lo-backdrop { z-index: 61; }
|
|
1599
|
+
html.dv-open .lo-menu { z-index: 62; }
|
|
1600
|
+
|
|
1601
|
+
/* The rendered markdown (0.8.9: colors). Prose keeps a reading measure (~80
|
|
1602
|
+
characters); tables and code blocks may use the whole width. */
|
|
1603
|
+
.doc-md { font-size: 15px; line-height: 1.6; color: var(--text2); overflow-wrap: anywhere; }
|
|
1604
|
+
.doc-md > p, .doc-md > ul, .doc-md > ol, .doc-md > blockquote, .doc-md > h2, .doc-md > h3, .doc-md > h4, .doc-md > h5, .doc-md > h6 { max-width: 80ch; }
|
|
1605
|
+
.doc-md p { margin: 0 0 12px; }
|
|
1606
|
+
.doc-md h2, .doc-md h3, .doc-md h4, .doc-md h5, .doc-md h6 { text-transform: none; letter-spacing: normal; line-height: 1.3; }
|
|
1607
|
+
.doc-md h2 { font-size: 24px; font-weight: 700; color: var(--text); margin: 22px 0 12px; padding-bottom: 8px; border-bottom: 2px solid color-mix(in srgb, var(--accent) 45%, var(--line)); }
|
|
1608
|
+
.doc-md h2:first-child { margin-top: 6px; }
|
|
1609
|
+
.doc-md h3 { font-size: 19px; font-weight: 650; color: var(--accent); margin: 22px 0 8px; }
|
|
1610
|
+
.doc-md h4 { font-size: 16px; font-weight: 650; color: var(--cyan); margin: 18px 0 6px; }
|
|
1611
|
+
.doc-md h5, .doc-md h6 { font-size: 13px; font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: .05em; margin: 16px 0 6px; }
|
|
1612
|
+
.doc-md b, .doc-md strong { color: var(--text); font-weight: 650; }
|
|
1613
|
+
.doc-md em { font-style: italic; }
|
|
1614
|
+
.doc-md del { color: var(--muted); }
|
|
1615
|
+
.doc-md a { color: var(--accent); text-decoration: underline; text-decoration-color: color-mix(in srgb, var(--accent) 40%, transparent); text-underline-offset: 2px; }
|
|
1616
|
+
.doc-md a:hover { text-decoration-color: var(--accent); }
|
|
1617
|
+
.doc-md code { font-family: var(--mono); font-size: .87em; color: var(--you); background: var(--tint-red); border-radius: 5px; padding: 1px 5px; }
|
|
1618
|
+
.doc-md pre.doc-code, .doc-pre { background: var(--card2); border: 1px solid var(--line); border-left: 3px solid color-mix(in srgb, var(--accent) 55%, var(--line)); border-radius: 10px; padding: 12px 14px; margin: 0 0 14px; overflow: auto; font-family: var(--mono); font-size: 12.5px; line-height: 1.5; white-space: pre; color: var(--text); }
|
|
1619
|
+
.doc-md pre.doc-code code { background: none; padding: 0; color: inherit; font-size: inherit; }
|
|
1620
|
+
.doc-md .tk-c { color: var(--faint); font-style: italic; }
|
|
1621
|
+
.doc-md .tk-s { color: var(--green); }
|
|
1622
|
+
.doc-md .tk-n { color: var(--yellow); }
|
|
1623
|
+
.doc-md .tk-k { color: var(--accent); font-weight: 600; }
|
|
1624
|
+
.doc-md .tk-add { color: var(--green); background: var(--tint-green); display: inline-block; min-width: 100%; }
|
|
1625
|
+
.doc-md .tk-del { color: var(--red); background: var(--tint-red); display: inline-block; min-width: 100%; }
|
|
1626
|
+
.doc-md blockquote { margin: 12px 0; padding: 8px 14px; border-left: 3px solid var(--accent); background: var(--tint-accent); border-radius: 0 8px 8px 0; color: var(--text2); }
|
|
1627
|
+
.doc-md blockquote > :last-child { margin-bottom: 0; }
|
|
1628
|
+
.doc-md ul, .doc-md ol { margin: 0 0 12px; padding-left: 22px; }
|
|
1629
|
+
.doc-md li { margin: 3px 0; }
|
|
1630
|
+
.doc-md li::marker { color: var(--accent); }
|
|
1631
|
+
.doc-md ol > li::marker { font-weight: 600; }
|
|
1573
1632
|
.doc-md li.sub { margin-left: 18px; }
|
|
1574
1633
|
.doc-md li.task { list-style: none; margin-left: -18px; }
|
|
1575
1634
|
.doc-page { max-width: 760px; padding-bottom: 32px; } /* 0.8.1: #/docs/<name> */
|
|
1576
|
-
.doc-md .tbox { display: inline-
|
|
1635
|
+
.doc-md .tbox { display: inline-flex; align-items: center; justify-content: center; width: 15px; height: 15px; border: 1.5px solid var(--line-strong); border-radius: 4px; margin-right: 8px; vertical-align: -2px; background: var(--field); }
|
|
1577
1636
|
.doc-md .tbox.on { background: var(--green); border-color: var(--green); }
|
|
1578
|
-
.doc-
|
|
1579
|
-
.doc-md
|
|
1637
|
+
.doc-md .tbox.on::after { content: ''; width: 4px; height: 8px; border: solid var(--on-accent); border-width: 0 2px 2px 0; transform: translateY(-1px) rotate(45deg); }
|
|
1638
|
+
.doc-md li.task:has(.tbox.on) { color: var(--muted); }
|
|
1639
|
+
.doc-md hr { border: 0; height: 2px; margin: 22px 0; background: linear-gradient(90deg, var(--accent), color-mix(in srgb, var(--accent) 10%, transparent)); opacity: .55; }
|
|
1640
|
+
.doc-table { overflow-x: auto; margin: 0 0 14px; border: 1px solid var(--line); border-radius: 10px; }
|
|
1641
|
+
.doc-md table { border-collapse: collapse; font-size: 13.5px; width: max-content; min-width: 100%; }
|
|
1580
1642
|
.doc-md table { overflow-wrap: normal; word-break: normal; }
|
|
1581
1643
|
.doc-md th { white-space: nowrap; }
|
|
1582
|
-
.doc-md th, .doc-md td { border: 1px solid var(--line); padding:
|
|
1644
|
+
.doc-md th, .doc-md td { border-bottom: 1px solid var(--line); padding: 7px 12px; text-align: left; vertical-align: top; }
|
|
1645
|
+
.doc-md th + th, .doc-md td + td { border-left: 1px solid var(--line); }
|
|
1646
|
+
.doc-md thead th { background: var(--tint-accent); color: var(--text); font-weight: 650; border-bottom: 2px solid color-mix(in srgb, var(--accent) 40%, var(--line)); }
|
|
1647
|
+
.doc-md tbody tr:nth-child(even) td { background: var(--bg2); }
|
|
1648
|
+
.doc-md tbody tr:last-child td { border-bottom: 0; }
|
|
1649
|
+
|
|
1650
|
+
/* 0.8.9: Download as PDF prints just the file (the browser's "Save as PDF"):
|
|
1651
|
+
white paper, the light theme's colors, no modal around it. */
|
|
1652
|
+
@media print {
|
|
1653
|
+
html.dv-printing body > *:not(#docViewer) { display: none !important; }
|
|
1654
|
+
html.dv-printing, html.dv-printing body { overflow: visible !important; height: auto !important; background: #fff !important; }
|
|
1655
|
+
html.dv-printing #docViewer { position: static !important; display: block !important; background: none !important; padding: 0 !important; }
|
|
1656
|
+
html.dv-printing .dv-sheet { display: block; width: auto; max-width: none; border: 0; border-radius: 0; box-shadow: none; background: #fff; overflow: visible; }
|
|
1657
|
+
html.dv-printing .dv-head, html.dv-printing .dv-sub, html.dv-printing .lo-menu, html.dv-printing .lo-backdrop { display: none !important; }
|
|
1658
|
+
html.dv-printing .dv-ptitle { display: block; font: 600 12px/1.4 var(--mono); color: #687185; border-bottom: 1px solid #e1e5ed; padding-bottom: 6px; margin-bottom: 14px; }
|
|
1659
|
+
html.dv-printing .dv-body { overflow: visible; padding: 0; }
|
|
1660
|
+
html.dv-printing .doc-md { font-size: 11.5pt; }
|
|
1661
|
+
html.dv-printing .doc-md > * { max-width: none; }
|
|
1662
|
+
html.dv-printing .doc-md pre.doc-code, html.dv-printing .doc-pre { white-space: pre-wrap; overflow: visible; break-inside: avoid; }
|
|
1663
|
+
html.dv-printing .doc-table { overflow: visible; }
|
|
1664
|
+
html.dv-printing .doc-md table { width: 100%; }
|
|
1665
|
+
html.dv-printing .doc-md tr, html.dv-printing .doc-md blockquote { break-inside: avoid; }
|
|
1666
|
+
html.dv-printing .doc-md h2, html.dv-printing .doc-md h3, html.dv-printing .doc-md h4 { break-after: avoid; }
|
|
1667
|
+
html.dv-printing * { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
1668
|
+
}
|
|
1583
1669
|
.doc-img { text-align: center; padding-top: 10px; }
|
|
1584
1670
|
.doc-img img { max-width: 100%; height: auto; border-radius: 8px; background: #fff; }
|
|
1585
1671
|
|
|
@@ -1653,3 +1739,39 @@ html.dv-open, html.dv-open body { overflow: hidden; }
|
|
|
1653
1739
|
.lo-menu.sheet.lo-actmenu { max-width: none; }
|
|
1654
1740
|
.lo-menu.sheet .lo-act { padding: 14px 10px; font-size: 16px; }
|
|
1655
1741
|
@media (pointer: coarse) { .btn.icon-btn { width: 36px; height: 34px; } }
|
|
1742
|
+
|
|
1743
|
+
/* 0.9.0: projects. The chip next to the repo, the filter chips, the name form. */
|
|
1744
|
+
.chip.proj { display: inline-flex; align-items: center; gap: 4px; color: var(--text2); font-weight: 600; border-color: color-mix(in srgb, var(--accent) 45%, transparent); background: color-mix(in srgb, var(--accent) 9%, transparent); max-width: 12em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; cursor: pointer; font-family: inherit; }
|
|
1745
|
+
.chip.proj:hover { color: var(--text); border-color: var(--accent); }
|
|
1746
|
+
.chip.proj .pe, .rchip .pe { font-size: 1.05em; line-height: 1; }
|
|
1747
|
+
.chip.proj-add { cursor: pointer; font-family: inherit; color: var(--muted); border-style: dashed; background: none; }
|
|
1748
|
+
.chip.proj-add:hover { color: var(--text); border-color: var(--line-strong); }
|
|
1749
|
+
.repos.projects .rchip, .rchip.pchip { font-family: inherit; font-weight: 600; }
|
|
1750
|
+
.repos.projects .rchip .rl { display: inline-flex; align-items: center; gap: 5px; }
|
|
1751
|
+
.repos.projects .proj-more { flex: none; width: 30px; height: 30px; padding: 0; border-radius: 999px; }
|
|
1752
|
+
.lo-namesheet { padding: 10px; min-width: 260px; }
|
|
1753
|
+
.lo-namesheet .lo-sheet-head { padding: 2px 4px 8px; }
|
|
1754
|
+
.lo-nameform { display: flex; gap: 8px; align-items: center; }
|
|
1755
|
+
.lo-nameform .lo-name { flex: 1; min-width: 0; font: inherit; font-size: 14px; padding: 8px 10px; border: 1px solid var(--line-strong); border-radius: 8px; background: var(--card); color: var(--text); }
|
|
1756
|
+
.lo-nameform .lo-name:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--tint-accent); }
|
|
1757
|
+
.lo-name-err { color: var(--red, #d64545); font-size: 12.5px; padding: 6px 2px 0; }
|
|
1758
|
+
.lo-act.on { color: var(--text); font-weight: 600; }
|
|
1759
|
+
.lo-act.danger { color: var(--red, #d64545); }
|
|
1760
|
+
@media (pointer: coarse), (max-width: 600px) { .lo-nameform .lo-name { font-size: 16px; } }
|
|
1761
|
+
|
|
1762
|
+
/* 0.9.0: checkpoints written with another session's branch, folded away */
|
|
1763
|
+
.tl-doubt { margin: 10px 0 0; color: var(--muted); font-size: 13px; }
|
|
1764
|
+
.tl-doubt > summary { cursor: pointer; padding: 6px 0; }
|
|
1765
|
+
.tl-doubt .timeline { opacity: .6; margin-top: 6px; }
|
|
1766
|
+
|
|
1767
|
+
/* 0.9.0: Merged and Closed fold to one row each */
|
|
1768
|
+
.prgroup.done > summary { list-style: none; cursor: pointer; border: 1px solid var(--line); border-radius: 10px; padding: 0 12px; min-height: 44px; display: flex; align-items: center; }
|
|
1769
|
+
.prgroup.done > summary::-webkit-details-marker { display: none; }
|
|
1770
|
+
.prgroup.done > summary h2 { margin: 0; flex: 1; display: flex; align-items: center; gap: 6px; color: var(--b); }
|
|
1771
|
+
.prgroup.done > summary h2::before { content: ''; display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 1px; background: var(--b); }
|
|
1772
|
+
.prgroup.done > summary .chev { margin-left: auto; color: var(--muted); font-size: 18px; transition: transform .15s; }
|
|
1773
|
+
.prgroup.done[open] > summary { margin-bottom: 8px; }
|
|
1774
|
+
.prgroup.done[open] > summary .chev { transform: rotate(90deg); }
|
|
1775
|
+
.pr-more-sess > summary { list-style: none; cursor: pointer; display: inline; }
|
|
1776
|
+
.pr-more-sess > summary::-webkit-details-marker { display: none; }
|
|
1777
|
+
.pr-more-sess[open] > summary { display: none; }
|