-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpreview.html
More file actions
137 lines (134 loc) · 8.39 KB
/
Copy pathpreview.html
File metadata and controls
137 lines (134 loc) · 8.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
<!doctype html>
<!-- Standalone visual preview of the ChromeSidebar component — dev tooling, not a test.
Loads assets/sidebar.{css,js} directly and mounts one instance with a representative DTO
(loose tabs, a plain group, and a project-tree section with folders + leaf projects, across
the dot states). Lets you iterate on the CSS/JS and SEE the result without building curator or
warden.
Fast loop (from a chrome-core checkout):
just preview → open it in your browser
just shot [density] → headless screenshot to preview.png
Or reach it from either app: `just chrome-preview` (in warden / curator).
URL params (compose freely, e.g. ?density=compact&header=1):
?density=compact preview the compact sizing scale (default: comfortable)
?header=1 mount a stand-in in the banner's `header` slot (curator fills this with
its nav pill; warden leaves it empty). Proves the banner is ONE height
either way — the readout in the top-right shows #cc-banner's measured px,
which must match with and without ?header=1 (that's --cc-banner-min doing
its job). The stand-in is a neutral placeholder sized to curator's real
nav-pill row (30px) — the pill's own styling is app-owned (curator's
chrome.css), so it deliberately does NOT live here.
?open=1 mount the pinned "Open" section (warden's `open_tabs_section`): mirror
rows above the main list for every `live` or `detached` tab, which in
this fixture pulls rows out of all three section kinds (loose, a plain
group, and a project tree) while leaving every one of them in place.
The main list below renders de-emphasised while the section is showing —
hover anywhere in it (the empty space under the last row counts) to
bring it back.
Raw headless invocation (what `just shot` wraps):
chrome --headless=new --disable-gpu --hide-scrollbars --force-device-scale-factor=2 \
--window-size=310,900 --default-background-color=00000000 \
--screenshot=preview.png "file://$PWD/preview.html"
(`chrome` = Google Chrome / Chromium — any Chromium-based browser with --screenshot.) -->
<html>
<head>
<meta charset="utf-8" />
<link rel="stylesheet" href="assets/sidebar.css" />
<style>
/* `font-family` must match what the consuming apps set (warden and curator both use
system-ui) — sidebar.css deliberately sets none, inheriting the host page's. Without it
the preview renders in the browser's default serif, so every glyph falls back through a
DIFFERENT face and the preview silently misrepresents the app: text metrics, and above
all the confirm-row glyphs (☠/⏻/↩︎), whose optical corrections are calibrated against
the faces system-ui resolves. Dropping it makes this a measuring tool that lies. */
html, body { margin: 0; background: #0c0f12; font-family: system-ui, sans-serif; }
#sidebar { width: 300px; }
/* Neutral stand-in for a consumer's `header` slot (curator's nav pill). Preview-only — sized
to the real pill row (2px pad + 26px buttons = 30px) so the banner-height parity check is
meaningful; the pill's actual look is curator's concern, not chrome-core's. */
.ph-header { flex: none; display: inline-flex; gap: 2px; background: #2a2a2a; border-radius: 8px; padding: 2px; }
.ph-btn { width: 30px; height: 26px; border-radius: 6px; background: #3a3a3a; }
/* Corner readout: mode + measured banner height, so the loop doubles as a measuring tool. */
#readout {
position: fixed; top: 8px; right: 8px; z-index: 9;
font: 12px ui-monospace, monospace; color: #cdd; background: #1b1f24cc;
border: 1px solid #333; border-radius: 6px; padding: 4px 8px; white-space: pre;
}
</style>
</head>
<body>
<div id="readout"></div>
<aside id="sidebar"></aside>
<script src="assets/sidebar.js"></script>
<script>
const params = new URLSearchParams(location.search);
const density = params.get("density") || "comfortable";
const withHeader = params.get("header") === "1";
// ?open=1 → the pinned "Open" section (warden's `open_tabs_section`); off by default, as it is
// for every app that does not opt in.
const openSection = params.get("open") === "1";
const T = (id, title, group, tree, treePath, extra = {}) => ({
id, title, group, tree, treePath,
live: false, attention: null, presence: null, killable: false, startable: false, warn: false,
...extra,
});
const dto = {
title: "personal",
colour: "#1a9e8f",
density,
windowDrag: false,
openSection,
tabs: [
// Loose tabs (no group) — the flat, un-sectioned rows.
T("/p/dotfiles", "dotfiles", null, false, [], { live: true, presence: "on" }),
T("/p/blog", "blog", null, false, [], { live: true, presence: "off" }),
T("/p/notes", "notes", null, false, [], { presence: "off" }),
T("/p/agent", "agent (crashed)", null, false, [], { presence: "ghost", startable: true }),
T("/p/scratch", "scratch (popped out)", null, false, [], { presence: "off", detached: true }),
// A plain [[window.group]] section (tree:false) — flat rows under a labelled header.
T("/g/api", "api", "backend", false, [], { killable: true, presence: "on", live: true }),
T("/g/workers", "workers", "backend", false, [], { presence: "off" }),
// A project-tree ([[window.root]]) section — tree:true rows nest by treePath.
T("/d/github.com/acme/webapp", "webapp", "Developer", true, ["github.com", "acme"], { presence: "on" }),
T("/d/github.com/acme/design-system", "design-system", "Developer", true, ["github.com", "acme"], { presence: "on" }),
T("/d/github.com/example/x", "x", "Developer", true, ["github.com", "example"]),
T("/d/github.com/lockyc/agentmux", "agentmux", "Developer", true, ["github.com", "lockyc"], { presence: "off" }),
T("/d/github.com/lockyc/chrome-core", "chrome-core", "Developer", true, ["github.com", "lockyc"], { presence: "off" }),
T("/d/github.com/lockyc/curator", "curator", "Developer", true, ["github.com", "lockyc"], { live: true, presence: "on" }),
T("/d/github.com/lockyc/warden", "warden", "Developer", true, ["github.com", "lockyc"], { live: true, presence: "on" }),
T("/d/github.com/spatie/y", "y", "Developer", true, ["github.com", "spatie"]),
],
};
// Optional `header` slot stand-in (curator mounts its nav pill here; warden passes null).
let header = null;
if (withHeader) {
header = document.createElement("div");
header.className = "ph-header";
for (let i = 0; i < 4; i++) header.appendChild(Object.assign(document.createElement("div"), { className: "ph-btn" }));
}
const sb = window.ChromeSidebar.mount(
document.getElementById("sidebar"),
{
// Logged so a click on the detached ("scratch (popped out)") row can be confirmed still
// firing onSelect — the app maps that to "raise the popped-out window".
onSelect(id) { console.log("onSelect", id); },
onUnload() {},
onKill() {},
onKillClose() {},
onStart() {},
onRescan() {},
onResize() {},
// Opt-in pop-out affordance (capability-by-callback-presence) — logged so the click can be
// confirmed firing from the preview. To verify the glyph is ABSENT when unsupplied, comment
// this out and reload: every row's ⤢ disappears.
onPopOut(id) { console.log("onPopOut", id); },
},
{ storageKey: "preview", header, appName: "preview" }
);
sb.update(dto);
// Readout: mode + measured banner height. The height must be identical with/without ?header=1.
const bh = document.getElementById("cc-banner").offsetHeight;
document.getElementById("readout").textContent =
`density: ${density}\nheader: ${withHeader ? "on" : "off"}\nopen: ${openSection ? "on" : "off"}\nbanner: ${bh}px`;
</script>
</body>
</html>