@commentray/render 0.0.5 → 0.0.8
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/dist/browse-page-slug.d.ts +6 -0
- package/dist/browse-page-slug.d.ts.map +1 -0
- package/dist/browse-page-slug.js +9 -0
- package/dist/browse-page-slug.js.map +1 -0
- package/dist/build-commentray-nav-search.d.ts +11 -5
- package/dist/build-commentray-nav-search.d.ts.map +1 -1
- package/dist/build-commentray-nav-search.js +11 -11
- package/dist/build-commentray-nav-search.js.map +1 -1
- package/dist/code-browser-block-rays.d.ts +48 -0
- package/dist/code-browser-block-rays.d.ts.map +1 -0
- package/dist/code-browser-block-rays.js +95 -0
- package/dist/code-browser-block-rays.js.map +1 -0
- package/dist/code-browser-client.bundle.js +12 -12
- package/dist/code-browser-client.js +1106 -145
- package/dist/code-browser-client.js.map +1 -1
- package/dist/code-browser-color-theme.d.ts +15 -0
- package/dist/code-browser-color-theme.d.ts.map +1 -0
- package/dist/code-browser-color-theme.js +73 -0
- package/dist/code-browser-color-theme.js.map +1 -0
- package/dist/code-browser-pair-nav.d.ts +31 -0
- package/dist/code-browser-pair-nav.d.ts.map +1 -0
- package/dist/code-browser-pair-nav.js +77 -0
- package/dist/code-browser-pair-nav.js.map +1 -0
- package/dist/code-browser-scroll-sync.js +1 -1
- package/dist/code-browser-scroll-sync.js.map +1 -1
- package/dist/code-browser-search.d.ts +45 -0
- package/dist/code-browser-search.d.ts.map +1 -1
- package/dist/code-browser-search.js +89 -0
- package/dist/code-browser-search.js.map +1 -1
- package/dist/code-browser.d.ts +24 -3
- package/dist/code-browser.d.ts.map +1 -1
- package/dist/code-browser.js +1202 -288
- package/dist/code-browser.js.map +1 -1
- package/dist/hljs-stylesheet-themes.d.ts +13 -0
- package/dist/hljs-stylesheet-themes.d.ts.map +1 -0
- package/dist/hljs-stylesheet-themes.js +19 -0
- package/dist/hljs-stylesheet-themes.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/inline-favicon.d.ts +2 -0
- package/dist/inline-favicon.d.ts.map +1 -0
- package/dist/inline-favicon.js +25 -0
- package/dist/inline-favicon.js.map +1 -0
- package/dist/markdown-pipeline.d.ts.map +1 -1
- package/dist/markdown-pipeline.js +38 -2
- package/dist/markdown-pipeline.js.map +1 -1
- package/dist/mermaid-runtime-html.d.ts.map +1 -1
- package/dist/mermaid-runtime-html.js +13 -3
- package/dist/mermaid-runtime-html.js.map +1 -1
- package/dist/package-version.d.ts.map +1 -1
- package/dist/package-version.js +4 -4
- package/dist/package-version.js.map +1 -1
- package/dist/side-by-side-layout.css +58 -0
- package/dist/side-by-side.d.ts.map +1 -1
- package/dist/side-by-side.js +10 -12
- package/dist/side-by-side.js.map +1 -1
- package/package.json +2 -2
package/dist/code-browser.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { MARKER_ID_BODY, buildBlockScrollLinks, } from "@commentray/core";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { MARKER_ID_BODY, buildBlockScrollLinks, findMonorepoPackagesDir, monorepoLayoutStartDir, } from "@commentray/core";
|
|
5
4
|
import { tryBuildBlockStretchTableHtml } from "./block-stretch-layout.js";
|
|
6
5
|
import { formatCommentrayBuiltAtLocal } from "./build-stamp.js";
|
|
7
6
|
import { escapeHtml } from "./html-utils.js";
|
|
7
|
+
import { commentrayColorThemeHeadBoot } from "./code-browser-color-theme.js";
|
|
8
|
+
import { hljsStylesheetThemes } from "./hljs-stylesheet-themes.js";
|
|
8
9
|
import { renderHighlightedCodeLineRows } from "./highlighted-code-lines.js";
|
|
10
|
+
import { COMMENTRAY_FAVICON_LINK_HTML } from "./inline-favicon.js";
|
|
9
11
|
import { mermaidRuntimeScriptHtml } from "./mermaid-runtime-html.js";
|
|
10
12
|
import { renderMarkdownToHtml } from "./markdown-pipeline.js";
|
|
11
13
|
import { commentrayRenderVersion } from "./package-version.js";
|
|
@@ -15,10 +17,29 @@ function renderGeneratorMetaHtml(label) {
|
|
|
15
17
|
return "";
|
|
16
18
|
return `<meta name="generator" content="${escapeHtml(t)}" />\n `;
|
|
17
19
|
}
|
|
20
|
+
const META_DESCRIPTION_MAX_LEN = 320;
|
|
21
|
+
function codeBrowserMetaDescription(opts, title) {
|
|
22
|
+
const custom = opts.metaDescription?.trim();
|
|
23
|
+
if (custom)
|
|
24
|
+
return custom.slice(0, META_DESCRIPTION_MAX_LEN);
|
|
25
|
+
const fallback = `${title} — Side-by-side source and commentray documentation.`;
|
|
26
|
+
return fallback.slice(0, META_DESCRIPTION_MAX_LEN);
|
|
27
|
+
}
|
|
28
|
+
function renderMetaDescriptionHtml(opts, title) {
|
|
29
|
+
const content = codeBrowserMetaDescription(opts, title);
|
|
30
|
+
return `<meta name="description" content="${escapeHtml(content)}" />\n `;
|
|
31
|
+
}
|
|
18
32
|
/** Single capture: marker id (avoid a wrapping group around the whole comment — that shifted indices). */
|
|
19
33
|
const BLOCK_MARKER_HTML_LINE = new RegExp(`^<!--\\s*commentray:block\\s+id=(${MARKER_ID_BODY})\\s*-->$`, "i");
|
|
20
34
|
function trimEndSpacesTabs(s) {
|
|
21
|
-
|
|
35
|
+
let end = s.length;
|
|
36
|
+
while (end > 0) {
|
|
37
|
+
const c = s[end - 1];
|
|
38
|
+
if (c !== " " && c !== "\t")
|
|
39
|
+
break;
|
|
40
|
+
end--;
|
|
41
|
+
}
|
|
42
|
+
return s.slice(0, end);
|
|
22
43
|
}
|
|
23
44
|
function isSetextUnderlineLine(line) {
|
|
24
45
|
const t = trimEndSpacesTabs(line);
|
|
@@ -111,6 +132,33 @@ function injectCommentrayDocAnchors(markdown, links) {
|
|
|
111
132
|
const GITHUB_MARK_SVG = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="20" height="20" fill="currentColor" aria-hidden="true">' +
|
|
112
133
|
'<path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/>' +
|
|
113
134
|
"</svg>";
|
|
135
|
+
/** Simple home glyph for same-site hub link (matches Octocat control size). */
|
|
136
|
+
const SITE_HOME_SVG = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="currentColor" aria-hidden="true">' +
|
|
137
|
+
'<path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/>' +
|
|
138
|
+
"</svg>";
|
|
139
|
+
/** Folder-with-list glyph (file tree / documented pairs hub). */
|
|
140
|
+
const TOOLBAR_ICON_TREE_SVG = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">' +
|
|
141
|
+
'<path d="M4 20h16a1 1 0 0 0 1-1V9a2 2 0 0 0-2-2h-5.5a2 2 0 0 1-1.6-.8L10.5 4.5a2 2 0 0 0-1.6-.8H5a2 2 0 0 0-2 2v14a1 1 0 0 0 1 1Z"/>' +
|
|
142
|
+
'<path d="M8 12h8M8 16h6M8 20h4"/>' +
|
|
143
|
+
"</svg>";
|
|
144
|
+
/**
|
|
145
|
+
* Line wrap — Material "wrap_text" glyph (Apache-2.0), same visual family as
|
|
146
|
+
* https://www.svgrepo.com/svg/376703/text-wrap-line (filled 24dp path scaled to 18px).
|
|
147
|
+
*/
|
|
148
|
+
const TOOLBAR_ICON_WRAP_SVG = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="18" height="18" fill="currentColor" aria-hidden="true">' +
|
|
149
|
+
'<path d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3 3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"/>' +
|
|
150
|
+
"</svg>";
|
|
151
|
+
const CHROME_ICON_SEARCH_SVG = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">' +
|
|
152
|
+
'<circle cx="11" cy="11" r="7"/>' +
|
|
153
|
+
'<path d="m21 21-4.3-4.3"/>' +
|
|
154
|
+
"</svg>";
|
|
155
|
+
/** Swap / flip: circle split by a diameter, one arrow per half (narrow viewports). */
|
|
156
|
+
const TOOLBAR_ICON_FLIP_PANES_SVG = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">' +
|
|
157
|
+
'<circle cx="12" cy="12" r="9"/>' +
|
|
158
|
+
'<path d="M12 4v16"/>' +
|
|
159
|
+
'<path d="M10.5 12H6l2.5-2.5M6 12l2.5 2.5"/>' +
|
|
160
|
+
'<path d="M13.5 12H18l-2.5-2.5M18 12l-2.5 2.5"/>' +
|
|
161
|
+
"</svg>";
|
|
114
162
|
function safeExternalHttpUrl(url) {
|
|
115
163
|
const t = url?.trim();
|
|
116
164
|
if (!t)
|
|
@@ -119,26 +167,48 @@ function safeExternalHttpUrl(url) {
|
|
|
119
167
|
return null;
|
|
120
168
|
return t;
|
|
121
169
|
}
|
|
122
|
-
|
|
170
|
+
/** Allows relative static browse links (`./browse/…`) and `http(s):` URLs; rejects `javascript:` / `data:`. */
|
|
171
|
+
function safeToolbarNavigationHref(url) {
|
|
172
|
+
const t = url?.trim();
|
|
173
|
+
if (!t)
|
|
174
|
+
return null;
|
|
175
|
+
if (/^(javascript|data):/i.test(t))
|
|
176
|
+
return null;
|
|
177
|
+
return t;
|
|
178
|
+
}
|
|
179
|
+
function buildToolbarSiteHubHtml(siteHubUrl) {
|
|
180
|
+
const site = safeToolbarNavigationHref(siteHubUrl);
|
|
181
|
+
if (!site)
|
|
182
|
+
return "";
|
|
183
|
+
const se = escapeHtml(site);
|
|
184
|
+
return `<a class="toolbar-github" href="${se}" aria-label="Documentation home" title="Back to this site (hub)">${SITE_HOME_SVG}</a>`;
|
|
185
|
+
}
|
|
186
|
+
/** GitHub Octocat in the toolbar when a repo URL is set and the hub link does not replace it. */
|
|
187
|
+
function buildToolbarEndHtml(githubRepoUrl, siteHubUrl) {
|
|
188
|
+
const site = safeToolbarNavigationHref(siteHubUrl);
|
|
123
189
|
const gh = safeExternalHttpUrl(githubRepoUrl);
|
|
124
|
-
|
|
125
|
-
const bits = [];
|
|
126
|
-
if (gh) {
|
|
190
|
+
if (!site && gh) {
|
|
127
191
|
const he = escapeHtml(gh);
|
|
128
|
-
|
|
192
|
+
return `<div class="toolbar__end"><a class="toolbar-github" href="${he}" target="_blank" rel="noopener noreferrer" aria-label="View repository on GitHub" title="View repository on GitHub">${GITHUB_MARK_SVG}</a></div>`;
|
|
129
193
|
}
|
|
194
|
+
return "";
|
|
195
|
+
}
|
|
196
|
+
function renderPageFooterHtml(input) {
|
|
197
|
+
const { builtAt, toolHomeUrl, commentrayRenderSemver } = input;
|
|
198
|
+
const iso = builtAt.toISOString();
|
|
199
|
+
const human = formatCommentrayBuiltAtLocal(builtAt);
|
|
200
|
+
const tool = safeExternalHttpUrl(toolHomeUrl);
|
|
130
201
|
if (tool) {
|
|
131
202
|
const te = escapeHtml(tool);
|
|
132
203
|
const ver = escapeHtml(commentrayRenderSemver);
|
|
133
|
-
|
|
204
|
+
return (`<footer class="app__footer" role="contentinfo">` +
|
|
205
|
+
`<p class="app__footer-line app__footer-attribution" role="note">` +
|
|
206
|
+
`Rendered with <a href="${te}" target="_blank" rel="noopener noreferrer">Commentray</a> ` +
|
|
207
|
+
`<span class="app__footer-attribution__version" translate="no">v${ver}</span>: ` +
|
|
208
|
+
`<time datetime="${escapeHtml(iso)}">${escapeHtml(human)}</time>` +
|
|
209
|
+
`</p>` +
|
|
210
|
+
`</footer>`);
|
|
134
211
|
}
|
|
135
|
-
if (bits.length === 0)
|
|
136
|
-
return "";
|
|
137
|
-
return `<div class="toolbar__end">${bits.join("")}</div>`;
|
|
138
|
-
}
|
|
139
|
-
function renderPageFooterHtml(builtAt) {
|
|
140
|
-
const iso = builtAt.toISOString();
|
|
141
|
-
const human = formatCommentrayBuiltAtLocal(builtAt);
|
|
142
212
|
return (`<footer class="app__footer" role="contentinfo">` +
|
|
143
213
|
`<p class="app__footer-line">HTML generated <time datetime="${escapeHtml(iso)}">${escapeHtml(human)}</time></p>` +
|
|
144
214
|
`</footer>`);
|
|
@@ -160,49 +230,61 @@ function renderToolbarDocHubHtml(opts) {
|
|
|
160
230
|
const navAttr = escapeHtml(nav ?? "");
|
|
161
231
|
const navRailDocumentedHtml = showDocumentedTree
|
|
162
232
|
? `<details class="nav-rail__doc-hub" id="documented-files-hub" data-nav-json-url="${navAttr}">
|
|
163
|
-
<summary class="nav-rail__doc-hub-summary">
|
|
233
|
+
<summary class="nav-rail__doc-hub-summary" title="Comment-rayed files" aria-label="Comment-rayed files"><span class="nav-rail__doc-hub-summary__caption">Comment-rayed files</span><span class="nav-rail__doc-hub-summary__glyph" aria-hidden="true">${TOOLBAR_ICON_TREE_SVG}</span></summary>
|
|
164
234
|
<div class="nav-rail__doc-hub-inner">
|
|
235
|
+
<div class="nav-rail__doc-hub-filter-row">
|
|
236
|
+
<label class="nav-rail__doc-hub-filter-label" for="documented-files-filter">Filter</label>
|
|
237
|
+
<input type="search" id="documented-files-filter" class="nav-rail__doc-hub-filter" placeholder="Filter by path…" autocomplete="off" spellcheck="false" />
|
|
238
|
+
</div>
|
|
165
239
|
<div id="documented-files-tree" class="documented-files-tree" role="tree"></div>
|
|
166
240
|
</div>
|
|
167
241
|
</details>`
|
|
168
242
|
: "";
|
|
169
243
|
return { toolbarDocHubHtml, navRailDocumentedHtml };
|
|
170
244
|
}
|
|
171
|
-
function
|
|
245
|
+
function dualPanePanesInnerHtml(codeHtml, commentrayHtml) {
|
|
246
|
+
return (` <section class="pane--code" id="code-pane" aria-label="Source code">` +
|
|
247
|
+
` ${codeHtml}\n` +
|
|
248
|
+
` </section>\n` +
|
|
249
|
+
` <div class="gutter" id="gutter" role="separator" aria-orientation="vertical" aria-label="Resize panes"></div>\n` +
|
|
250
|
+
` <section class="pane--doc commentray" id="doc-pane" aria-label="Commentray">\n` +
|
|
251
|
+
` <div id="doc-pane-body" class="doc-pane-body">\n` +
|
|
252
|
+
` ${commentrayHtml}\n` +
|
|
253
|
+
` </div>\n` +
|
|
254
|
+
` </section>\n`);
|
|
255
|
+
}
|
|
256
|
+
/** Plain-text Src/Doc labels above the panes; column widths track the resizable split via `--split-pct`. */
|
|
257
|
+
function renderShellPairContextHtml(filePath, commentrayPath) {
|
|
172
258
|
const fpRaw = (filePath ?? "").trim();
|
|
173
259
|
const crRaw = (commentrayPath ?? "").trim();
|
|
174
|
-
|
|
175
|
-
const crUrl = safeExternalHttpUrl(opts?.commentrayOnGithubUrl);
|
|
176
|
-
if (fpRaw.length === 0 && crRaw.length === 0 && srcUrl === null && crUrl === null) {
|
|
260
|
+
if (fpRaw.length === 0 && crRaw.length === 0)
|
|
177
261
|
return "";
|
|
178
|
-
}
|
|
179
262
|
const fp = escapeHtml(fpRaw);
|
|
180
263
|
const cr = escapeHtml(crRaw);
|
|
181
264
|
const fpDisp = fpRaw.length > 0 ? fp : "—";
|
|
182
265
|
const crDisp = crRaw.length > 0 ? cr : "—";
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
<span class="nav-
|
|
192
|
-
|
|
193
|
-
</span>
|
|
194
|
-
<span class="nav-rail__pair-sep" aria-hidden="true">·</span>
|
|
195
|
-
<span class="nav-rail__pair">
|
|
196
|
-
<span class="nav-rail__pair-lab">Doc</span>
|
|
197
|
-
<span class="nav-rail__pair-path nav-rail__pair-path--secondary" title="${cr}">${crDisp}</span>${crGh}
|
|
198
|
-
</span>
|
|
266
|
+
return `<div class="shell__pair-context" aria-label="Current documentation pair">
|
|
267
|
+
<div class="shell__pair-cell shell__pair-cell--src">
|
|
268
|
+
<span class="shell__pair-lab">Src</span>
|
|
269
|
+
<span class="shell__pair-path" title="${fp}">${fpDisp}</span>
|
|
270
|
+
</div>
|
|
271
|
+
<div class="shell__pair-gutter-spacer" aria-hidden="true"></div>
|
|
272
|
+
<div class="shell__pair-cell shell__pair-cell--doc">
|
|
273
|
+
<span class="shell__pair-lab">Doc</span>
|
|
274
|
+
<span class="shell__pair-path shell__pair-path--secondary" id="nav-rail-doc-path" title="${cr}">${crDisp}</span>
|
|
275
|
+
</div>
|
|
199
276
|
</div>`;
|
|
200
277
|
}
|
|
278
|
+
function wrapDualShellInner(pairContextHtml, panesHtml) {
|
|
279
|
+
const row = pairContextHtml.trim().length > 0 ? ` ${pairContextHtml.trim()}\n` : "";
|
|
280
|
+
return `${row} <div class="shell__panes">\n${panesHtml} </div>\n`;
|
|
281
|
+
}
|
|
201
282
|
/** IIFE produced by `npm run build -w @commentray/render` (esbuild of `code-browser-client.ts`). */
|
|
202
283
|
function loadCodeBrowserClientBundle() {
|
|
203
|
-
const
|
|
204
|
-
const
|
|
205
|
-
const
|
|
284
|
+
const packagesDir = findMonorepoPackagesDir(monorepoLayoutStartDir(import.meta.url));
|
|
285
|
+
const renderDistDir = join(packagesDir, "render", "dist");
|
|
286
|
+
const inDist = join(renderDistDir, "code-browser-client.bundle.js");
|
|
287
|
+
const fromSrc = join(packagesDir, "render", "code-browser-client.bundle.js");
|
|
206
288
|
for (const p of [inDist, fromSrc]) {
|
|
207
289
|
if (existsSync(p)) {
|
|
208
290
|
return readFileSync(p, "utf8");
|
|
@@ -210,10 +292,94 @@ function loadCodeBrowserClientBundle() {
|
|
|
210
292
|
}
|
|
211
293
|
throw new Error("Missing code-browser-client.bundle.js. Run `npm run build -w @commentray/render` to bundle the browser client.");
|
|
212
294
|
}
|
|
295
|
+
/**
|
|
296
|
+
* Compact theme control: primary click opens a menu (readme.io–style), secondary click cycles
|
|
297
|
+
* system → light → dark. Paired with {@link ./code-browser-color-theme.ts} and the client bundle.
|
|
298
|
+
*/
|
|
299
|
+
const TOOLBAR_COLOR_THEME_HTML = ` <div class="toolbar-theme">
|
|
300
|
+
<button type="button" id="commentray-theme-trigger" class="toolbar-theme__trigger" data-commentray-trigger-mode="system" aria-haspopup="menu" aria-expanded="false" aria-label="Color theme" title="Appearance: left-click opens the theme menu. Right-click cycles System, Light, and Dark.">
|
|
301
|
+
<span class="toolbar-theme__icon toolbar-theme__icon--system" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8m-4-4v4"/></svg></span>
|
|
302
|
+
<span class="toolbar-theme__icon toolbar-theme__icon--light" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M4.93 4.93l1.41 1.41m11.32 11.32l1.41 1.41M2 12h2m16 0h2M6.34 6.34L4.93 4.93m12.02 12.02l1.41 1.41M17.66 6.34l1.41-1.41M6.34 17.66l-1.41 1.41"/></svg></span>
|
|
303
|
+
<span class="toolbar-theme__icon toolbar-theme__icon--dark" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="18" height="18" fill="currentColor"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg></span>
|
|
304
|
+
</button>
|
|
305
|
+
<div id="commentray-theme-menu" class="toolbar-theme__menu" role="menu" hidden aria-labelledby="commentray-theme-trigger">
|
|
306
|
+
<button type="button" role="menuitemradio" class="toolbar-theme__menuitem" data-commentray-theme-value="system" aria-checked="true">System</button>
|
|
307
|
+
<button type="button" role="menuitemradio" class="toolbar-theme__menuitem" data-commentray-theme-value="light" aria-checked="false">Light</button>
|
|
308
|
+
<button type="button" role="menuitemradio" class="toolbar-theme__menuitem" data-commentray-theme-value="dark" aria-checked="false">Dark</button>
|
|
309
|
+
</div>
|
|
310
|
+
</div>
|
|
311
|
+
`;
|
|
213
312
|
const CODE_BROWSER_STYLES = `
|
|
214
|
-
:root {
|
|
313
|
+
:root {
|
|
314
|
+
--cr-control-h: 32px;
|
|
315
|
+
--cr-control-radius: 8px;
|
|
316
|
+
--cr-icon-inner: 18px;
|
|
317
|
+
--cr-label-caps-fs: 10px;
|
|
318
|
+
--cr-label-caps-track: 0.06em;
|
|
319
|
+
--cr-ui-fs: 12px;
|
|
320
|
+
/** Matches code/doc pane horizontal padding so pair-context rows line up with pane content (e.g. line nums). */
|
|
321
|
+
--cr-pane-inline-pad: 12px;
|
|
322
|
+
}
|
|
323
|
+
:root:is(:not([data-commentray-theme]), [data-commentray-theme="system"]) {
|
|
324
|
+
color-scheme: light dark;
|
|
325
|
+
}
|
|
326
|
+
:root[data-commentray-theme="light"] {
|
|
327
|
+
color-scheme: light;
|
|
328
|
+
}
|
|
329
|
+
:root[data-commentray-theme="dark"] {
|
|
330
|
+
color-scheme: dark;
|
|
331
|
+
}
|
|
215
332
|
* { box-sizing: border-box; }
|
|
216
|
-
|
|
333
|
+
html { background: Canvas; color: CanvasText; }
|
|
334
|
+
body {
|
|
335
|
+
margin: 0;
|
|
336
|
+
font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
|
|
337
|
+
background: Canvas;
|
|
338
|
+
color: CanvasText;
|
|
339
|
+
}
|
|
340
|
+
.skip-link {
|
|
341
|
+
position: absolute;
|
|
342
|
+
left: -9999px;
|
|
343
|
+
top: 0;
|
|
344
|
+
z-index: 10000;
|
|
345
|
+
padding: 8px 16px;
|
|
346
|
+
margin: 0;
|
|
347
|
+
font: inherit;
|
|
348
|
+
font-size: 14px;
|
|
349
|
+
text-decoration: none;
|
|
350
|
+
border-radius: 8px;
|
|
351
|
+
border: 1px solid color-mix(in oklab, CanvasText 25%, Canvas);
|
|
352
|
+
background: Canvas;
|
|
353
|
+
color: CanvasText;
|
|
354
|
+
}
|
|
355
|
+
.skip-link:focus {
|
|
356
|
+
left: 12px;
|
|
357
|
+
top: 8px;
|
|
358
|
+
outline: 2px solid color-mix(in oklab, CanvasText 45%, Canvas);
|
|
359
|
+
outline-offset: 2px;
|
|
360
|
+
}
|
|
361
|
+
.skip-link:focus:not(:focus-visible) {
|
|
362
|
+
left: -9999px;
|
|
363
|
+
top: 0;
|
|
364
|
+
outline: none;
|
|
365
|
+
}
|
|
366
|
+
.skip-link:focus-visible {
|
|
367
|
+
left: 12px;
|
|
368
|
+
top: 8px;
|
|
369
|
+
outline: 2px solid color-mix(in oklab, CanvasText 45%, Canvas);
|
|
370
|
+
outline-offset: 2px;
|
|
371
|
+
}
|
|
372
|
+
.sr-only {
|
|
373
|
+
position: absolute;
|
|
374
|
+
width: 1px;
|
|
375
|
+
height: 1px;
|
|
376
|
+
padding: 0;
|
|
377
|
+
margin: -1px;
|
|
378
|
+
overflow: hidden;
|
|
379
|
+
clip: rect(0, 0, 0, 0);
|
|
380
|
+
white-space: nowrap;
|
|
381
|
+
border: 0;
|
|
382
|
+
}
|
|
217
383
|
.app {
|
|
218
384
|
display: flex;
|
|
219
385
|
flex-direction: column;
|
|
@@ -244,148 +410,101 @@ const CODE_BROWSER_STYLES = `
|
|
|
244
410
|
.chrome__search-row input[type="search"] {
|
|
245
411
|
flex: 1 1 auto;
|
|
246
412
|
min-width: 140px;
|
|
247
|
-
|
|
413
|
+
min-height: var(--cr-control-h);
|
|
414
|
+
padding: 0 12px;
|
|
248
415
|
font: inherit;
|
|
249
|
-
font-size:
|
|
250
|
-
|
|
416
|
+
font-size: var(--cr-ui-fs);
|
|
417
|
+
line-height: 1.25;
|
|
418
|
+
border-radius: var(--cr-control-radius);
|
|
251
419
|
border: 1px solid color-mix(in oklab, CanvasText 25%, Canvas);
|
|
252
420
|
background: Canvas;
|
|
253
421
|
color: CanvasText;
|
|
254
422
|
}
|
|
255
423
|
.chrome__search-row #search-clear {
|
|
256
424
|
flex: 0 0 auto;
|
|
425
|
+
display: inline-flex;
|
|
426
|
+
align-items: center;
|
|
427
|
+
justify-content: center;
|
|
428
|
+
min-height: var(--cr-control-h);
|
|
429
|
+
padding: 0 12px;
|
|
257
430
|
font: inherit;
|
|
258
|
-
|
|
259
|
-
|
|
431
|
+
font-size: var(--cr-ui-fs);
|
|
432
|
+
font-weight: 500;
|
|
433
|
+
border-radius: var(--cr-control-radius);
|
|
260
434
|
cursor: pointer;
|
|
261
435
|
border: 1px solid color-mix(in oklab, CanvasText 25%, Canvas);
|
|
262
436
|
background: color-mix(in oklab, CanvasText 6%, Canvas);
|
|
263
437
|
color: CanvasText;
|
|
264
|
-
}
|
|
265
|
-
.chrome__search-label {
|
|
266
|
-
flex: 0 0 auto;
|
|
267
438
|
white-space: nowrap;
|
|
268
439
|
}
|
|
269
|
-
.
|
|
270
|
-
|
|
271
|
-
flex-direction: row;
|
|
272
|
-
flex-wrap: wrap;
|
|
273
|
-
align-items: center;
|
|
274
|
-
gap: 6px 10px;
|
|
275
|
-
padding: 5px 10px;
|
|
276
|
-
border-radius: 8px;
|
|
277
|
-
border: 1px solid color-mix(in oklab, CanvasText 14%, Canvas);
|
|
278
|
-
background: Canvas;
|
|
279
|
-
font-size: 12px;
|
|
280
|
-
line-height: 1.3;
|
|
440
|
+
.chrome__search-row #search-clear:hover {
|
|
441
|
+
background: color-mix(in oklab, CanvasText 11%, Canvas);
|
|
281
442
|
}
|
|
282
|
-
.
|
|
443
|
+
.chrome__search-row input[type="search"]:focus-visible,
|
|
444
|
+
.chrome__search-row #search-clear:focus-visible {
|
|
445
|
+
outline: 2px solid color-mix(in oklab, CanvasText 45%, Canvas);
|
|
446
|
+
outline-offset: 2px;
|
|
447
|
+
}
|
|
448
|
+
.chrome__search-label {
|
|
449
|
+
flex: 0 0 auto;
|
|
283
450
|
display: inline-flex;
|
|
284
451
|
flex-direction: row;
|
|
285
452
|
align-items: center;
|
|
286
453
|
gap: 6px;
|
|
287
|
-
min-width: 0;
|
|
288
|
-
flex: 1 1 140px;
|
|
289
|
-
max-width: min(48%, 100%);
|
|
290
|
-
}
|
|
291
|
-
.nav-rail__pair-lab {
|
|
292
|
-
flex: 0 0 auto;
|
|
293
|
-
font-size: 9px;
|
|
294
|
-
font-weight: 700;
|
|
295
|
-
letter-spacing: 0.06em;
|
|
296
|
-
text-transform: uppercase;
|
|
297
|
-
opacity: 0.72;
|
|
298
|
-
}
|
|
299
|
-
.nav-rail__pair-path {
|
|
300
|
-
flex: 1 1 auto;
|
|
301
|
-
min-width: 0;
|
|
302
|
-
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
|
|
303
|
-
font-size: 11px;
|
|
304
|
-
color: CanvasText;
|
|
305
|
-
overflow: hidden;
|
|
306
|
-
text-overflow: ellipsis;
|
|
307
454
|
white-space: nowrap;
|
|
308
|
-
|
|
309
|
-
.nav-rail__pair-path--secondary { opacity: 0.88; }
|
|
310
|
-
.nav-rail__pair-sep {
|
|
311
|
-
flex: 0 0 auto;
|
|
312
|
-
opacity: 0.45;
|
|
455
|
+
cursor: default;
|
|
313
456
|
user-select: none;
|
|
314
|
-
padding: 0 2px;
|
|
315
457
|
}
|
|
316
|
-
.
|
|
317
|
-
|
|
318
|
-
display:
|
|
319
|
-
align-items: center;
|
|
320
|
-
justify-content: center;
|
|
321
|
-
width: 26px;
|
|
322
|
-
height: 26px;
|
|
323
|
-
border-radius: 6px;
|
|
324
|
-
border: 1px solid color-mix(in oklab, CanvasText 20%, Canvas);
|
|
325
|
-
background: color-mix(in oklab, CanvasText 5%, Canvas);
|
|
326
|
-
color: CanvasText;
|
|
327
|
-
}
|
|
328
|
-
.nav-rail__pair-gh:hover {
|
|
329
|
-
background: color-mix(in oklab, CanvasText 10%, Canvas);
|
|
330
|
-
}
|
|
331
|
-
.nav-rail__pair-gh:focus-visible {
|
|
332
|
-
outline: 2px solid color-mix(in oklab, CanvasText 45%, Canvas);
|
|
333
|
-
outline-offset: 2px;
|
|
334
|
-
}
|
|
335
|
-
.nav-rail__pair-gh svg {
|
|
336
|
-
width: 14px;
|
|
337
|
-
height: 14px;
|
|
338
|
-
display: block;
|
|
339
|
-
}
|
|
340
|
-
.toolbar .nav-rail__context--compact {
|
|
341
|
-
border: 0;
|
|
342
|
-
background: transparent;
|
|
343
|
-
padding: 0;
|
|
344
|
-
flex: 1 1 200px;
|
|
345
|
-
min-width: 0;
|
|
346
|
-
max-width: none;
|
|
347
|
-
gap: 6px 10px;
|
|
348
|
-
}
|
|
349
|
-
.toolbar .nav-rail__pair {
|
|
350
|
-
flex: 1 1 auto;
|
|
351
|
-
min-width: 0;
|
|
352
|
-
max-width: min(44vw, 420px);
|
|
458
|
+
/* Wide viewports: same legible caps word as historic Pages shell (icon hidden). */
|
|
459
|
+
.chrome__search-label__glyph {
|
|
460
|
+
display: none;
|
|
353
461
|
}
|
|
354
462
|
.nav-rail__search-label {
|
|
355
|
-
font-size:
|
|
463
|
+
font-size: var(--cr-label-caps-fs);
|
|
356
464
|
font-weight: 700;
|
|
357
|
-
letter-spacing:
|
|
465
|
+
letter-spacing: var(--cr-label-caps-track);
|
|
358
466
|
text-transform: uppercase;
|
|
359
|
-
opacity: 0.8;
|
|
360
|
-
}
|
|
361
|
-
.nav-rail__search-hint {
|
|
362
|
-
margin: 0;
|
|
363
|
-
font-size: 11px;
|
|
364
|
-
line-height: 1.35;
|
|
365
467
|
opacity: 0.78;
|
|
366
468
|
}
|
|
367
|
-
.nav-rail__code {
|
|
368
|
-
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
|
|
369
|
-
font-size: 10px;
|
|
370
|
-
}
|
|
371
469
|
.nav-rail__doc-hub {
|
|
372
470
|
position: relative;
|
|
373
471
|
flex: 0 0 auto;
|
|
374
472
|
align-self: center;
|
|
375
473
|
display: block;
|
|
376
474
|
border: 1px solid color-mix(in oklab, CanvasText 16%, Canvas);
|
|
377
|
-
border-radius:
|
|
475
|
+
border-radius: var(--cr-control-radius);
|
|
378
476
|
background: Canvas;
|
|
379
477
|
overflow: visible;
|
|
380
478
|
}
|
|
381
479
|
.nav-rail__doc-hub-summary {
|
|
382
480
|
cursor: pointer;
|
|
383
|
-
font-size:
|
|
384
|
-
font-weight:
|
|
385
|
-
|
|
481
|
+
font-size: var(--cr-ui-fs);
|
|
482
|
+
font-weight: 500;
|
|
483
|
+
color: color-mix(in oklab, CanvasText 88%, Canvas);
|
|
484
|
+
padding: 0 12px;
|
|
485
|
+
min-height: var(--cr-control-h);
|
|
486
|
+
display: inline-flex;
|
|
487
|
+
flex-direction: row;
|
|
488
|
+
align-items: center;
|
|
489
|
+
justify-content: flex-start;
|
|
490
|
+
gap: 8px;
|
|
491
|
+
box-sizing: border-box;
|
|
386
492
|
list-style: none;
|
|
387
493
|
user-select: none;
|
|
388
|
-
line-height: 1.
|
|
494
|
+
line-height: 1.25;
|
|
495
|
+
}
|
|
496
|
+
.nav-rail__doc-hub-summary:hover {
|
|
497
|
+
background: color-mix(in oklab, CanvasText 6%, Canvas);
|
|
498
|
+
}
|
|
499
|
+
.nav-rail__doc-hub-summary__caption {
|
|
500
|
+
white-space: nowrap;
|
|
501
|
+
}
|
|
502
|
+
.nav-rail__doc-hub-summary__glyph {
|
|
503
|
+
display: none;
|
|
504
|
+
}
|
|
505
|
+
.nav-rail__doc-hub-summary svg {
|
|
506
|
+
display: block;
|
|
507
|
+
flex: 0 0 auto;
|
|
389
508
|
}
|
|
390
509
|
.nav-rail__doc-hub-summary::-webkit-details-marker { display: none; }
|
|
391
510
|
.nav-rail__doc-hub-inner {
|
|
@@ -396,7 +515,10 @@ const CODE_BROWSER_STYLES = `
|
|
|
396
515
|
min-width: min(280px, 78vw);
|
|
397
516
|
max-width: min(440px, 94vw);
|
|
398
517
|
max-height: min(52vh, 400px);
|
|
399
|
-
|
|
518
|
+
display: flex;
|
|
519
|
+
flex-direction: column;
|
|
520
|
+
gap: 8px;
|
|
521
|
+
overflow: hidden;
|
|
400
522
|
padding: 8px 10px;
|
|
401
523
|
font-size: 12px;
|
|
402
524
|
border: 1px solid color-mix(in oklab, CanvasText 16%, Canvas);
|
|
@@ -404,6 +526,33 @@ const CODE_BROWSER_STYLES = `
|
|
|
404
526
|
background: Canvas;
|
|
405
527
|
box-shadow: 0 8px 28px color-mix(in oklab, CanvasText 12%, transparent);
|
|
406
528
|
}
|
|
529
|
+
.nav-rail__doc-hub-filter-row {
|
|
530
|
+
flex: 0 0 auto;
|
|
531
|
+
}
|
|
532
|
+
.nav-rail__doc-hub-filter-label {
|
|
533
|
+
display: block;
|
|
534
|
+
font-size: var(--cr-label-caps-fs);
|
|
535
|
+
font-weight: 700;
|
|
536
|
+
letter-spacing: var(--cr-label-caps-track);
|
|
537
|
+
text-transform: uppercase;
|
|
538
|
+
opacity: 0.78;
|
|
539
|
+
margin-bottom: 4px;
|
|
540
|
+
}
|
|
541
|
+
.nav-rail__doc-hub-filter {
|
|
542
|
+
width: 100%;
|
|
543
|
+
box-sizing: border-box;
|
|
544
|
+
font: inherit;
|
|
545
|
+
font-size: 12px;
|
|
546
|
+
padding: 4px 8px;
|
|
547
|
+
border-radius: 6px;
|
|
548
|
+
border: 1px solid color-mix(in oklab, CanvasText 22%, Canvas);
|
|
549
|
+
background: color-mix(in oklab, CanvasText 4%, Canvas);
|
|
550
|
+
color: CanvasText;
|
|
551
|
+
}
|
|
552
|
+
.nav-rail__doc-hub-filter:focus {
|
|
553
|
+
outline: 2px solid color-mix(in oklab, CanvasText 40%, Canvas);
|
|
554
|
+
outline-offset: 1px;
|
|
555
|
+
}
|
|
407
556
|
.nav-rail__doc-hub-hint {
|
|
408
557
|
margin: 0 0 8px;
|
|
409
558
|
opacity: 0.78;
|
|
@@ -426,41 +575,298 @@ const CODE_BROWSER_STYLES = `
|
|
|
426
575
|
line-height: 1.4;
|
|
427
576
|
color: color-mix(in oklab, CanvasText 72%, Canvas);
|
|
428
577
|
}
|
|
429
|
-
.app__footer-line { margin: 0; }
|
|
430
|
-
.app__footer time { font-variant-numeric: tabular-nums; }
|
|
431
|
-
.toolbar {
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
578
|
+
.app__footer-line { margin: 0; }
|
|
579
|
+
.app__footer time { font-variant-numeric: tabular-nums; }
|
|
580
|
+
.toolbar {
|
|
581
|
+
position: relative;
|
|
582
|
+
display: flex;
|
|
583
|
+
flex-wrap: wrap;
|
|
584
|
+
align-items: center;
|
|
585
|
+
gap: 10px 14px;
|
|
586
|
+
padding: 8px 12px;
|
|
587
|
+
border-bottom: 1px solid color-mix(in oklab, CanvasText 18%, Canvas);
|
|
588
|
+
background: color-mix(in oklab, CanvasText 4%, Canvas);
|
|
589
|
+
font-size: var(--cr-ui-fs);
|
|
590
|
+
flex: 0 0 auto;
|
|
591
|
+
min-width: 0;
|
|
592
|
+
}
|
|
593
|
+
.toolbar__primary {
|
|
594
|
+
display: flex;
|
|
595
|
+
flex-direction: row;
|
|
596
|
+
flex-wrap: wrap;
|
|
597
|
+
align-items: center;
|
|
598
|
+
gap: 10px 14px;
|
|
599
|
+
flex: 1 1 auto;
|
|
600
|
+
min-width: 0;
|
|
601
|
+
}
|
|
602
|
+
.toolbar__primary-main {
|
|
603
|
+
display: flex;
|
|
604
|
+
flex-direction: row;
|
|
605
|
+
flex-wrap: wrap;
|
|
606
|
+
align-items: center;
|
|
607
|
+
gap: 10px 14px;
|
|
608
|
+
flex: 0 1 auto;
|
|
609
|
+
min-width: 0;
|
|
610
|
+
}
|
|
611
|
+
.toolbar__primary-trail {
|
|
612
|
+
display: flex;
|
|
613
|
+
flex-direction: row;
|
|
614
|
+
flex-wrap: wrap;
|
|
615
|
+
align-items: center;
|
|
616
|
+
justify-content: flex-end;
|
|
617
|
+
gap: 10px 14px;
|
|
618
|
+
margin-left: auto;
|
|
619
|
+
min-width: 0;
|
|
620
|
+
}
|
|
621
|
+
.toolbar__end {
|
|
622
|
+
display: flex;
|
|
623
|
+
flex-wrap: wrap;
|
|
624
|
+
align-items: center;
|
|
625
|
+
justify-content: flex-end;
|
|
626
|
+
gap: 10px 14px;
|
|
627
|
+
min-width: 0;
|
|
628
|
+
}
|
|
629
|
+
.toolbar-github {
|
|
630
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
631
|
+
width: var(--cr-control-h);
|
|
632
|
+
height: var(--cr-control-h);
|
|
633
|
+
border-radius: var(--cr-control-radius);
|
|
634
|
+
border: 1px solid color-mix(in oklab, CanvasText 22%, Canvas);
|
|
635
|
+
background: color-mix(in oklab, CanvasText 6%, Canvas);
|
|
636
|
+
color: CanvasText;
|
|
637
|
+
}
|
|
638
|
+
.toolbar-github svg {
|
|
639
|
+
width: var(--cr-icon-inner);
|
|
640
|
+
height: var(--cr-icon-inner);
|
|
641
|
+
display: block;
|
|
642
|
+
}
|
|
643
|
+
.toolbar-github:hover { background: color-mix(in oklab, CanvasText 11%, Canvas); }
|
|
644
|
+
.toolbar-github:focus-visible { outline: 2px solid color-mix(in oklab, CanvasText 45%, Canvas); outline-offset: 2px; }
|
|
645
|
+
.app__footer-attribution {
|
|
646
|
+
margin: 0;
|
|
647
|
+
color: color-mix(in oklab, CanvasText 88%, Canvas);
|
|
648
|
+
}
|
|
649
|
+
.app__footer-attribution a {
|
|
650
|
+
color: inherit;
|
|
651
|
+
font-weight: 600;
|
|
652
|
+
text-decoration: underline;
|
|
653
|
+
text-underline-offset: 2px;
|
|
654
|
+
}
|
|
655
|
+
.app__footer-attribution__version { font-weight: 600; }
|
|
656
|
+
.toolbar label { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; user-select: none; }
|
|
657
|
+
.toolbar-wrap-lines {
|
|
658
|
+
position: relative;
|
|
659
|
+
margin: 0;
|
|
660
|
+
min-height: var(--cr-control-h);
|
|
661
|
+
padding: 0 12px 0 10px;
|
|
662
|
+
border-radius: var(--cr-control-radius);
|
|
663
|
+
border: 1px solid color-mix(in oklab, CanvasText 16%, Canvas);
|
|
664
|
+
background: Canvas;
|
|
665
|
+
display: inline-flex;
|
|
666
|
+
flex-direction: row;
|
|
667
|
+
align-items: center;
|
|
668
|
+
justify-content: flex-start;
|
|
669
|
+
gap: 8px;
|
|
670
|
+
font-size: var(--cr-ui-fs);
|
|
671
|
+
font-weight: 500;
|
|
672
|
+
color: color-mix(in oklab, CanvasText 88%, Canvas);
|
|
673
|
+
cursor: pointer;
|
|
674
|
+
}
|
|
675
|
+
.toolbar-wrap-lines:hover {
|
|
676
|
+
background: color-mix(in oklab, CanvasText 6%, Canvas);
|
|
677
|
+
}
|
|
678
|
+
.toolbar-wrap-lines__input {
|
|
679
|
+
position: absolute;
|
|
680
|
+
width: 1px;
|
|
681
|
+
height: 1px;
|
|
682
|
+
padding: 0;
|
|
683
|
+
margin: -1px;
|
|
684
|
+
overflow: hidden;
|
|
685
|
+
clip: rect(0, 0, 0, 0);
|
|
686
|
+
white-space: nowrap;
|
|
687
|
+
border: 0;
|
|
688
|
+
opacity: 0;
|
|
689
|
+
}
|
|
690
|
+
/** Visible tick box: the real input is visually hidden for a11y; unchecked looked like an empty box with no mark when on. */
|
|
691
|
+
.toolbar-wrap-lines__box {
|
|
692
|
+
flex: 0 0 auto;
|
|
693
|
+
width: 16px;
|
|
694
|
+
height: 16px;
|
|
695
|
+
box-sizing: border-box;
|
|
696
|
+
border: 1.5px solid color-mix(in oklab, CanvasText 38%, Canvas);
|
|
697
|
+
border-radius: 3px;
|
|
698
|
+
background: Canvas;
|
|
699
|
+
display: inline-flex;
|
|
700
|
+
align-items: center;
|
|
701
|
+
justify-content: center;
|
|
702
|
+
color: CanvasText;
|
|
703
|
+
}
|
|
704
|
+
.toolbar-wrap-lines:has(.toolbar-wrap-lines__input:checked) .toolbar-wrap-lines__box {
|
|
705
|
+
border-color: color-mix(in oklab, CanvasText 52%, Canvas);
|
|
706
|
+
background: color-mix(in oklab, CanvasText 6%, Canvas);
|
|
707
|
+
}
|
|
708
|
+
.toolbar-wrap-lines__box::after {
|
|
709
|
+
content: "";
|
|
710
|
+
display: none;
|
|
711
|
+
width: 4px;
|
|
712
|
+
height: 9px;
|
|
713
|
+
margin-top: -2px;
|
|
714
|
+
border: solid currentColor;
|
|
715
|
+
border-width: 0 2px 2px 0;
|
|
716
|
+
transform: rotate(45deg);
|
|
717
|
+
}
|
|
718
|
+
.toolbar-wrap-lines:has(.toolbar-wrap-lines__input:checked) .toolbar-wrap-lines__box::after {
|
|
719
|
+
display: block;
|
|
720
|
+
}
|
|
721
|
+
.toolbar-wrap-lines__face {
|
|
722
|
+
display: none;
|
|
723
|
+
align-items: center;
|
|
724
|
+
justify-content: center;
|
|
725
|
+
min-height: var(--cr-control-h);
|
|
726
|
+
min-width: var(--cr-control-h);
|
|
727
|
+
color: color-mix(in oklab, CanvasText 82%, Canvas);
|
|
728
|
+
}
|
|
729
|
+
.toolbar-wrap-lines__caption {
|
|
730
|
+
white-space: nowrap;
|
|
731
|
+
}
|
|
732
|
+
.toolbar-wrap-lines:has(.toolbar-wrap-lines__input:checked) {
|
|
733
|
+
color: CanvasText;
|
|
734
|
+
background: color-mix(in oklab, CanvasText 10%, Canvas);
|
|
735
|
+
}
|
|
736
|
+
.toolbar-wrap-lines:has(.toolbar-wrap-lines__input:checked) .toolbar-wrap-lines__caption {
|
|
737
|
+
color: CanvasText;
|
|
738
|
+
}
|
|
739
|
+
.toolbar-wrap-lines:has(.toolbar-wrap-lines__input:checked) .toolbar-wrap-lines__face {
|
|
740
|
+
color: CanvasText;
|
|
741
|
+
background: color-mix(in oklab, CanvasText 10%, Canvas);
|
|
742
|
+
border-radius: calc(var(--cr-control-radius) - 1px);
|
|
743
|
+
}
|
|
744
|
+
.toolbar-wrap-lines:has(.toolbar-wrap-lines__input:focus-visible) {
|
|
745
|
+
outline: 2px solid color-mix(in oklab, CanvasText 45%, Canvas);
|
|
746
|
+
outline-offset: 2px;
|
|
747
|
+
}
|
|
748
|
+
.toolbar-icon-btn {
|
|
749
|
+
display: none;
|
|
750
|
+
align-items: center;
|
|
751
|
+
justify-content: center;
|
|
752
|
+
width: var(--cr-control-h);
|
|
753
|
+
height: var(--cr-control-h);
|
|
754
|
+
padding: 0;
|
|
755
|
+
margin: 0;
|
|
756
|
+
border-radius: var(--cr-control-radius);
|
|
757
|
+
border: 1px solid color-mix(in oklab, CanvasText 22%, Canvas);
|
|
758
|
+
background: color-mix(in oklab, CanvasText 6%, Canvas);
|
|
759
|
+
color: CanvasText;
|
|
760
|
+
cursor: pointer;
|
|
761
|
+
flex: 0 0 auto;
|
|
762
|
+
}
|
|
763
|
+
.toolbar-icon-btn svg {
|
|
764
|
+
display: block;
|
|
765
|
+
flex: 0 0 auto;
|
|
766
|
+
}
|
|
767
|
+
.toolbar-icon-btn:hover {
|
|
768
|
+
background: color-mix(in oklab, CanvasText 14%, Canvas);
|
|
769
|
+
border-color: color-mix(in oklab, CanvasText 34%, Canvas);
|
|
770
|
+
}
|
|
771
|
+
.toolbar-icon-btn:focus-visible {
|
|
772
|
+
outline: 2px solid color-mix(in oklab, CanvasText 45%, Canvas);
|
|
773
|
+
outline-offset: 2px;
|
|
774
|
+
}
|
|
775
|
+
.toolbar label input:focus-visible {
|
|
776
|
+
outline: 2px solid color-mix(in oklab, CanvasText 45%, Canvas);
|
|
777
|
+
outline-offset: 2px;
|
|
778
|
+
}
|
|
779
|
+
.toolbar .toolbar-theme {
|
|
780
|
+
position: relative;
|
|
781
|
+
display: inline-flex;
|
|
782
|
+
align-items: center;
|
|
783
|
+
margin: 0;
|
|
784
|
+
padding: 0;
|
|
785
|
+
min-width: 0;
|
|
786
|
+
border: 0;
|
|
787
|
+
}
|
|
788
|
+
.toolbar-theme__trigger {
|
|
789
|
+
display: inline-flex;
|
|
790
|
+
align-items: center;
|
|
791
|
+
justify-content: center;
|
|
792
|
+
width: var(--cr-control-h);
|
|
793
|
+
height: var(--cr-control-h);
|
|
794
|
+
padding: 0;
|
|
795
|
+
margin: 0;
|
|
796
|
+
border-radius: var(--cr-control-radius);
|
|
797
|
+
border: 1px solid color-mix(in oklab, CanvasText 22%, Canvas);
|
|
798
|
+
background: color-mix(in oklab, CanvasText 6%, Canvas);
|
|
799
|
+
color: CanvasText;
|
|
800
|
+
cursor: pointer;
|
|
801
|
+
}
|
|
802
|
+
.toolbar-theme__trigger:hover {
|
|
803
|
+
background: color-mix(in oklab, CanvasText 14%, Canvas);
|
|
804
|
+
border-color: color-mix(in oklab, CanvasText 34%, Canvas);
|
|
805
|
+
}
|
|
806
|
+
.toolbar-theme__trigger:active {
|
|
807
|
+
background: color-mix(in oklab, CanvasText 18%, Canvas);
|
|
808
|
+
}
|
|
809
|
+
.toolbar-theme__trigger:focus-visible {
|
|
810
|
+
outline: 2px solid color-mix(in oklab, CanvasText 45%, Canvas);
|
|
811
|
+
outline-offset: 2px;
|
|
812
|
+
}
|
|
813
|
+
.toolbar-theme__trigger .toolbar-theme__icon {
|
|
814
|
+
display: none;
|
|
815
|
+
flex: 0 0 auto;
|
|
435
816
|
}
|
|
436
|
-
.
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
817
|
+
.toolbar-theme__trigger[data-commentray-trigger-mode="system"] .toolbar-theme__icon--system,
|
|
818
|
+
.toolbar-theme__trigger[data-commentray-trigger-mode="light"] .toolbar-theme__icon--light,
|
|
819
|
+
.toolbar-theme__trigger[data-commentray-trigger-mode="dark"] .toolbar-theme__icon--dark {
|
|
820
|
+
display: block;
|
|
440
821
|
}
|
|
441
|
-
.
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
822
|
+
.toolbar-theme__menu {
|
|
823
|
+
position: absolute;
|
|
824
|
+
left: 0;
|
|
825
|
+
top: calc(100% + 4px);
|
|
826
|
+
z-index: 80;
|
|
827
|
+
min-width: 148px;
|
|
828
|
+
padding: 4px;
|
|
829
|
+
margin: 0;
|
|
830
|
+
list-style: none;
|
|
831
|
+
border-radius: 8px;
|
|
832
|
+
border: 1px solid color-mix(in oklab, CanvasText 16%, Canvas);
|
|
833
|
+
background: Canvas;
|
|
834
|
+
color: CanvasText;
|
|
835
|
+
box-shadow: 0 8px 28px color-mix(in oklab, CanvasText 12%, transparent);
|
|
445
836
|
}
|
|
446
|
-
.toolbar-
|
|
447
|
-
display:
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
837
|
+
.toolbar-theme__menu[hidden] {
|
|
838
|
+
display: none !important;
|
|
839
|
+
}
|
|
840
|
+
.toolbar-theme__menuitem {
|
|
841
|
+
display: block;
|
|
842
|
+
width: 100%;
|
|
843
|
+
margin: 0;
|
|
844
|
+
padding: 8px 10px;
|
|
845
|
+
border: 0;
|
|
846
|
+
border-radius: 6px;
|
|
847
|
+
font: inherit;
|
|
848
|
+
font-size: var(--cr-ui-fs);
|
|
849
|
+
font-weight: 500;
|
|
850
|
+
text-align: left;
|
|
851
|
+
cursor: pointer;
|
|
451
852
|
color: CanvasText;
|
|
853
|
+
background: transparent;
|
|
452
854
|
}
|
|
453
|
-
.toolbar-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
855
|
+
.toolbar-theme__menuitem:hover {
|
|
856
|
+
background: color-mix(in oklab, CanvasText 8%, Canvas);
|
|
857
|
+
}
|
|
858
|
+
.toolbar-theme__menuitem:focus-visible {
|
|
859
|
+
outline: 2px solid color-mix(in oklab, CanvasText 45%, Canvas);
|
|
860
|
+
outline-offset: 0;
|
|
861
|
+
}
|
|
862
|
+
.toolbar-theme__menuitem[aria-checked="true"] {
|
|
863
|
+
background: color-mix(in oklab, CanvasText 10%, Canvas);
|
|
864
|
+
font-weight: 500;
|
|
458
865
|
}
|
|
459
|
-
.toolbar-attribution a { color: inherit; font-weight: 600; text-decoration: underline; text-underline-offset: 2px; }
|
|
460
|
-
.toolbar label { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; user-select: none; }
|
|
461
866
|
.toolbar .file-path {
|
|
462
867
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
|
|
463
|
-
font-size:
|
|
868
|
+
font-size: var(--cr-ui-fs);
|
|
869
|
+
font-weight: 500;
|
|
464
870
|
display: inline-flex; align-items: baseline; gap: 0; margin-right: 4px;
|
|
465
871
|
max-width: 60vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
466
872
|
}
|
|
@@ -469,21 +875,29 @@ const CODE_BROWSER_STYLES = `
|
|
|
469
875
|
}
|
|
470
876
|
.toolbar .file-path__dir--root { letter-spacing: 0; }
|
|
471
877
|
.toolbar .file-path__base {
|
|
472
|
-
color: CanvasText;
|
|
878
|
+
color: CanvasText;
|
|
879
|
+
font-weight: 500;
|
|
473
880
|
}
|
|
474
|
-
.toolbar .file-path--title { font-weight:
|
|
881
|
+
.toolbar .file-path--title { font-weight: 500; }
|
|
475
882
|
.toolbar-related {
|
|
476
883
|
display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: 6px 10px;
|
|
477
|
-
max-width: min(520px, 90vw);
|
|
884
|
+
max-width: min(520px, 90vw);
|
|
885
|
+
font-size: var(--cr-ui-fs);
|
|
886
|
+
line-height: 1.35;
|
|
478
887
|
color: color-mix(in oklab, CanvasText 88%, Canvas);
|
|
479
888
|
}
|
|
480
|
-
.toolbar-related__prefix { font-weight:
|
|
889
|
+
.toolbar-related__prefix { font-weight: 500; opacity: 0.88; white-space: nowrap; }
|
|
481
890
|
.toolbar-related__links { min-width: 0; }
|
|
482
891
|
.toolbar-related a {
|
|
483
892
|
color: inherit; text-decoration: underline; text-underline-offset: 2px; font-weight: 500;
|
|
484
893
|
word-break: break-word;
|
|
485
894
|
}
|
|
486
895
|
.toolbar-related__sep { opacity: 0.55; user-select: none; }
|
|
896
|
+
#documented-files-tree {
|
|
897
|
+
flex: 1 1 auto;
|
|
898
|
+
min-height: 0;
|
|
899
|
+
overflow: auto;
|
|
900
|
+
}
|
|
487
901
|
.documented-files-tree ul { list-style: none; margin: 0; padding-left: 12px; }
|
|
488
902
|
.documented-files-tree > ul { padding-left: 0; }
|
|
489
903
|
.documented-files-tree li { margin: 2px 0; line-height: 1.35; }
|
|
@@ -504,8 +918,15 @@ const CODE_BROWSER_STYLES = `
|
|
|
504
918
|
opacity: 0.92;
|
|
505
919
|
}
|
|
506
920
|
.toolbar button {
|
|
507
|
-
font: inherit;
|
|
508
|
-
|
|
921
|
+
font: inherit;
|
|
922
|
+
font-size: var(--cr-ui-fs);
|
|
923
|
+
font-weight: 500;
|
|
924
|
+
min-height: var(--cr-control-h);
|
|
925
|
+
padding: 0 12px;
|
|
926
|
+
border-radius: var(--cr-control-radius);
|
|
927
|
+
cursor: pointer;
|
|
928
|
+
border: 1px solid color-mix(in oklab, CanvasText 25%, Canvas);
|
|
929
|
+
background: color-mix(in oklab, CanvasText 6%, Canvas);
|
|
509
930
|
color: CanvasText;
|
|
510
931
|
}
|
|
511
932
|
.search-results {
|
|
@@ -542,15 +963,83 @@ const CODE_BROWSER_STYLES = `
|
|
|
542
963
|
-webkit-box-decoration-break: clone;
|
|
543
964
|
}
|
|
544
965
|
@media (prefers-color-scheme: dark) {
|
|
545
|
-
.search-results mark.search-hit {
|
|
966
|
+
:root:is(:not([data-commentray-theme]), [data-commentray-theme="system"]) .search-results mark.search-hit {
|
|
546
967
|
background: color-mix(in oklab, #c9a227 55%, Canvas);
|
|
547
968
|
}
|
|
548
969
|
}
|
|
549
|
-
|
|
970
|
+
:root[data-commentray-theme="dark"] .search-results mark.search-hit {
|
|
971
|
+
background: color-mix(in oklab, #c9a227 55%, Canvas);
|
|
972
|
+
}
|
|
973
|
+
.shell:not(.shell--stretch-rows) {
|
|
974
|
+
display: flex;
|
|
975
|
+
flex-direction: column;
|
|
976
|
+
flex: 1;
|
|
977
|
+
min-height: 0;
|
|
978
|
+
min-width: 0;
|
|
979
|
+
--split-pct: 46%;
|
|
980
|
+
}
|
|
550
981
|
.app__main .shell { flex: 1 1 auto; }
|
|
982
|
+
.shell__panes {
|
|
983
|
+
display: flex;
|
|
984
|
+
flex-direction: row;
|
|
985
|
+
flex: 1 1 auto;
|
|
986
|
+
min-height: 0;
|
|
987
|
+
min-width: 0;
|
|
988
|
+
}
|
|
989
|
+
.shell__pair-context {
|
|
990
|
+
flex: 0 0 auto;
|
|
991
|
+
display: flex;
|
|
992
|
+
flex-direction: row;
|
|
993
|
+
align-items: stretch;
|
|
994
|
+
padding: 6px 0 8px;
|
|
995
|
+
border-bottom: 1px solid color-mix(in oklab, CanvasText 15%, Canvas);
|
|
996
|
+
background: color-mix(in oklab, CanvasText 3%, Canvas);
|
|
997
|
+
font-size: var(--cr-ui-fs);
|
|
998
|
+
line-height: 1.3;
|
|
999
|
+
}
|
|
1000
|
+
.shell__pair-cell {
|
|
1001
|
+
display: flex;
|
|
1002
|
+
flex-direction: row;
|
|
1003
|
+
align-items: center;
|
|
1004
|
+
gap: 8px;
|
|
1005
|
+
min-width: 0;
|
|
1006
|
+
}
|
|
1007
|
+
.shell__pair-cell--src {
|
|
1008
|
+
flex: 0 0 var(--split-pct);
|
|
1009
|
+
padding-left: var(--cr-pane-inline-pad);
|
|
1010
|
+
}
|
|
1011
|
+
.shell__pair-gutter-spacer {
|
|
1012
|
+
flex: 0 0 14px;
|
|
1013
|
+
min-width: 14px;
|
|
1014
|
+
align-self: stretch;
|
|
1015
|
+
}
|
|
1016
|
+
.shell__pair-cell--doc {
|
|
1017
|
+
flex: 1 1 auto;
|
|
1018
|
+
min-width: 0;
|
|
1019
|
+
padding-left: var(--cr-pane-inline-pad);
|
|
1020
|
+
}
|
|
1021
|
+
.shell__pair-lab {
|
|
1022
|
+
flex: 0 0 auto;
|
|
1023
|
+
font-size: var(--cr-label-caps-fs);
|
|
1024
|
+
font-weight: 700;
|
|
1025
|
+
letter-spacing: var(--cr-label-caps-track);
|
|
1026
|
+
text-transform: uppercase;
|
|
1027
|
+
opacity: 0.72;
|
|
1028
|
+
}
|
|
1029
|
+
.shell__pair-path {
|
|
1030
|
+
flex: 1 1 auto;
|
|
1031
|
+
min-width: 0;
|
|
1032
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
|
|
1033
|
+
font-size: var(--cr-ui-fs);
|
|
1034
|
+
color: CanvasText;
|
|
1035
|
+
overflow: hidden;
|
|
1036
|
+
text-overflow: ellipsis;
|
|
1037
|
+
white-space: nowrap;
|
|
1038
|
+
}
|
|
1039
|
+
.shell__pair-path--secondary { opacity: 0.88; }
|
|
551
1040
|
.pane--code {
|
|
552
|
-
flex: 0 0
|
|
553
|
-
min-width: 120px; overflow: auto; padding: 12px
|
|
1041
|
+
flex: 0 0 var(--split-pct, 46%);
|
|
1042
|
+
min-width: 120px; overflow: auto; padding: 12px var(--cr-pane-inline-pad);
|
|
554
1043
|
border-right: 1px solid color-mix(in oklab, CanvasText 15%, Canvas);
|
|
555
1044
|
--code-line-font-size: 13px;
|
|
556
1045
|
--code-line-height: 1.5;
|
|
@@ -558,9 +1047,10 @@ const CODE_BROWSER_STYLES = `
|
|
|
558
1047
|
.pane--code .code-line-stack { --code-ln-min-ch: 3; }
|
|
559
1048
|
.pane--code .code-line {
|
|
560
1049
|
display: grid;
|
|
561
|
-
grid-template-columns: max-content 1fr;
|
|
1050
|
+
grid-template-columns: max-content minmax(0, 1fr);
|
|
562
1051
|
column-gap: 10px;
|
|
563
1052
|
align-items: start;
|
|
1053
|
+
min-width: 0;
|
|
564
1054
|
}
|
|
565
1055
|
.pane--code .code-line pre {
|
|
566
1056
|
margin: 0;
|
|
@@ -600,8 +1090,35 @@ const CODE_BROWSER_STYLES = `
|
|
|
600
1090
|
white-space: pre;
|
|
601
1091
|
}
|
|
602
1092
|
.gutter {
|
|
603
|
-
flex: 0 0
|
|
1093
|
+
flex: 0 0 14px; cursor: col-resize; background: color-mix(in oklab, CanvasText 12%, Canvas);
|
|
604
1094
|
position: relative;
|
|
1095
|
+
--commentray-ray-accent: #3b7dd8;
|
|
1096
|
+
}
|
|
1097
|
+
@media (prefers-color-scheme: dark) {
|
|
1098
|
+
:root:is(:not([data-commentray-theme]), [data-commentray-theme="system"]) .gutter {
|
|
1099
|
+
--commentray-ray-accent: #6eb0ff;
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
:root[data-commentray-theme="dark"] .gutter {
|
|
1103
|
+
--commentray-ray-accent: #6eb0ff;
|
|
1104
|
+
}
|
|
1105
|
+
.gutter__rays {
|
|
1106
|
+
position: absolute; inset: 0; pointer-events: none; z-index: 1;
|
|
1107
|
+
}
|
|
1108
|
+
.gutter__rays svg { width: 100%; height: 100%; display: block; overflow: visible; }
|
|
1109
|
+
.gutter__rays-path {
|
|
1110
|
+
fill: none; stroke-linecap: round; vector-effect: non-scaling-stroke;
|
|
1111
|
+
stroke: color-mix(in oklab, var(--commentray-ray-accent) 72%, CanvasText);
|
|
1112
|
+
stroke-width: 1.35px; opacity: 0.26;
|
|
1113
|
+
}
|
|
1114
|
+
.gutter__rays-path--active {
|
|
1115
|
+
stroke-width: 2.4px; opacity: 0.88;
|
|
1116
|
+
}
|
|
1117
|
+
.gutter__rays-path--trail {
|
|
1118
|
+
stroke-dasharray: 3 4; opacity: 0.42;
|
|
1119
|
+
}
|
|
1120
|
+
.gutter__rays-path--active.gutter__rays-path--trail {
|
|
1121
|
+
opacity: 0.72;
|
|
605
1122
|
}
|
|
606
1123
|
.gutter:hover { background: color-mix(in oklab, CanvasText 22%, Canvas); }
|
|
607
1124
|
.gutter::after {
|
|
@@ -609,18 +1126,359 @@ const CODE_BROWSER_STYLES = `
|
|
|
609
1126
|
}
|
|
610
1127
|
.pane--doc {
|
|
611
1128
|
flex: 1 1 auto; min-width: 0; min-height: 0;
|
|
612
|
-
display: flex; flex-direction: column; overflow: hidden; padding: 12px
|
|
1129
|
+
display: flex; flex-direction: column; overflow: hidden; padding: 12px var(--cr-pane-inline-pad);
|
|
1130
|
+
background: Canvas;
|
|
1131
|
+
color: CanvasText;
|
|
1132
|
+
}
|
|
1133
|
+
/* #doc-pane-body.wrap beats pre code.hljs from the hljs theme so fenced blocks follow the toggle. */
|
|
1134
|
+
#doc-pane-body.wrap pre,
|
|
1135
|
+
#doc-pane-body.wrap pre code {
|
|
1136
|
+
white-space: pre-wrap;
|
|
1137
|
+
word-break: break-word;
|
|
1138
|
+
}
|
|
1139
|
+
#doc-pane-body:not(.wrap) pre,
|
|
1140
|
+
#doc-pane-body:not(.wrap) pre code {
|
|
1141
|
+
white-space: pre;
|
|
1142
|
+
word-break: normal;
|
|
613
1143
|
}
|
|
614
1144
|
.doc-pane-body {
|
|
615
1145
|
flex: 1 1 auto; min-height: 0; overflow: auto;
|
|
616
1146
|
}
|
|
1147
|
+
/** Wide GFM tables: intrinsic width so the doc pane scrolls sideways instead of squeezing columns. */
|
|
1148
|
+
.pane--doc .doc-pane-body :where(table) {
|
|
1149
|
+
width: max-content;
|
|
1150
|
+
max-width: none;
|
|
1151
|
+
border-collapse: collapse;
|
|
1152
|
+
}
|
|
1153
|
+
.pane--doc .doc-pane-body .commentray-mermaid {
|
|
1154
|
+
overflow-x: auto;
|
|
1155
|
+
max-width: 100%;
|
|
1156
|
+
}
|
|
1157
|
+
/** Wrap on: break long URLs/words in prose; tables opt out so they stay wide + scroll with the body. */
|
|
1158
|
+
#doc-pane-body.wrap {
|
|
1159
|
+
overflow-wrap: break-word;
|
|
1160
|
+
}
|
|
1161
|
+
#doc-pane-body.wrap :where(table) {
|
|
1162
|
+
overflow-wrap: normal;
|
|
1163
|
+
word-break: normal;
|
|
1164
|
+
}
|
|
1165
|
+
#doc-pane-body:not(.wrap) {
|
|
1166
|
+
overflow-wrap: normal;
|
|
1167
|
+
word-break: normal;
|
|
1168
|
+
}
|
|
617
1169
|
.toolbar-angle-picker {
|
|
618
|
-
display: inline-flex;
|
|
619
|
-
|
|
1170
|
+
display: inline-flex;
|
|
1171
|
+
align-items: center;
|
|
1172
|
+
gap: 6px;
|
|
1173
|
+
flex: 0 0 auto;
|
|
1174
|
+
}
|
|
1175
|
+
/* Angle caption uses the same class as the Search label (.nav-rail__search-label). */
|
|
1176
|
+
.toolbar-angle-picker__lab {
|
|
1177
|
+
display: inline-block;
|
|
1178
|
+
margin: 0;
|
|
1179
|
+
padding: 0;
|
|
1180
|
+
cursor: default;
|
|
1181
|
+
flex: 0 0 auto;
|
|
1182
|
+
white-space: nowrap;
|
|
1183
|
+
user-select: none;
|
|
620
1184
|
}
|
|
621
1185
|
.toolbar-angle-picker select {
|
|
622
|
-
font: inherit;
|
|
623
|
-
|
|
1186
|
+
font: inherit;
|
|
1187
|
+
font-size: var(--cr-ui-fs);
|
|
1188
|
+
font-weight: 500;
|
|
1189
|
+
min-height: var(--cr-control-h);
|
|
1190
|
+
height: var(--cr-control-h);
|
|
1191
|
+
padding: 0 10px;
|
|
1192
|
+
border-radius: var(--cr-control-radius);
|
|
1193
|
+
border: 1px solid color-mix(in oklab, CanvasText 25%, Canvas);
|
|
1194
|
+
background: Canvas;
|
|
1195
|
+
color: color-mix(in oklab, CanvasText 88%, Canvas);
|
|
1196
|
+
}
|
|
1197
|
+
.toolbar-angle-picker select:focus-visible {
|
|
1198
|
+
outline: 2px solid color-mix(in oklab, CanvasText 45%, Canvas);
|
|
1199
|
+
outline-offset: 2px;
|
|
1200
|
+
}
|
|
1201
|
+
/* Single-pane + compact chrome below typical tablet / Bootstrap md threshold (768px). */
|
|
1202
|
+
@media (max-width: 767px) {
|
|
1203
|
+
html,
|
|
1204
|
+
body {
|
|
1205
|
+
overflow-x: auto;
|
|
1206
|
+
overflow-y: auto;
|
|
1207
|
+
}
|
|
1208
|
+
.app {
|
|
1209
|
+
height: auto;
|
|
1210
|
+
min-height: 100vh;
|
|
1211
|
+
min-height: 100dvh;
|
|
1212
|
+
min-width: 0;
|
|
1213
|
+
overflow-x: auto;
|
|
1214
|
+
overflow-y: visible;
|
|
1215
|
+
}
|
|
1216
|
+
.app__main {
|
|
1217
|
+
flex: 0 0 auto;
|
|
1218
|
+
width: 100%;
|
|
1219
|
+
min-height: 0;
|
|
1220
|
+
}
|
|
1221
|
+
.app__main > #shell:not(.shell--stretch-rows) {
|
|
1222
|
+
flex: none !important;
|
|
1223
|
+
min-height: auto !important;
|
|
1224
|
+
overflow: visible !important;
|
|
1225
|
+
}
|
|
1226
|
+
.app__main > #shell:not(.shell--stretch-rows) .shell__panes {
|
|
1227
|
+
flex: none !important;
|
|
1228
|
+
min-height: auto !important;
|
|
1229
|
+
min-width: 0;
|
|
1230
|
+
width: 100%;
|
|
1231
|
+
max-width: 100%;
|
|
1232
|
+
box-sizing: border-box;
|
|
1233
|
+
}
|
|
1234
|
+
.app__main > #shell:not(.shell--stretch-rows) .pane--code,
|
|
1235
|
+
.app__main > #shell:not(.shell--stretch-rows) .pane--doc {
|
|
1236
|
+
flex: none !important;
|
|
1237
|
+
min-height: auto !important;
|
|
1238
|
+
overflow: visible !important;
|
|
1239
|
+
max-height: none !important;
|
|
1240
|
+
/* flex:none + basis:auto otherwise sizes to max-content so line-wrap has no width cap */
|
|
1241
|
+
width: 100%;
|
|
1242
|
+
max-width: 100%;
|
|
1243
|
+
min-width: 0 !important;
|
|
1244
|
+
box-sizing: border-box;
|
|
1245
|
+
}
|
|
1246
|
+
.app__main > #shell:not(.shell--stretch-rows) .pane--doc {
|
|
1247
|
+
display: block;
|
|
1248
|
+
}
|
|
1249
|
+
.app__main > #shell:not(.shell--stretch-rows) .doc-pane-body {
|
|
1250
|
+
flex: none !important;
|
|
1251
|
+
min-height: auto !important;
|
|
1252
|
+
min-width: 0;
|
|
1253
|
+
overflow: visible !important;
|
|
1254
|
+
}
|
|
1255
|
+
.app__footer {
|
|
1256
|
+
margin-top: auto;
|
|
1257
|
+
flex-shrink: 0;
|
|
1258
|
+
padding: 5px 10px 8px;
|
|
1259
|
+
font-size: 10px;
|
|
1260
|
+
line-height: 1.35;
|
|
1261
|
+
}
|
|
1262
|
+
.app__main > #shell.shell--stretch-rows {
|
|
1263
|
+
flex: 1 1 auto;
|
|
1264
|
+
min-height: min(72vh, 720px);
|
|
1265
|
+
min-height: min(72dvh, 720px);
|
|
1266
|
+
overflow: auto;
|
|
1267
|
+
}
|
|
1268
|
+
.toolbar {
|
|
1269
|
+
padding: 5px 8px 5px;
|
|
1270
|
+
row-gap: 4px;
|
|
1271
|
+
}
|
|
1272
|
+
.toolbar__primary {
|
|
1273
|
+
display: flex;
|
|
1274
|
+
flex-direction: row;
|
|
1275
|
+
flex-wrap: nowrap;
|
|
1276
|
+
align-items: center;
|
|
1277
|
+
gap: 6px;
|
|
1278
|
+
min-width: 0;
|
|
1279
|
+
width: 100%;
|
|
1280
|
+
box-sizing: border-box;
|
|
1281
|
+
}
|
|
1282
|
+
.toolbar__primary-main {
|
|
1283
|
+
flex: 1 1 auto;
|
|
1284
|
+
min-width: 0;
|
|
1285
|
+
flex-wrap: nowrap;
|
|
1286
|
+
overflow-x: auto;
|
|
1287
|
+
overflow-y: visible;
|
|
1288
|
+
-webkit-overflow-scrolling: touch;
|
|
1289
|
+
gap: 6px;
|
|
1290
|
+
scrollbar-width: thin;
|
|
1291
|
+
}
|
|
1292
|
+
.toolbar__primary-trail {
|
|
1293
|
+
flex: 0 0 auto;
|
|
1294
|
+
flex-wrap: nowrap;
|
|
1295
|
+
align-self: center;
|
|
1296
|
+
}
|
|
1297
|
+
.toolbar-angle-picker {
|
|
1298
|
+
position: relative;
|
|
1299
|
+
flex: 0 1 auto;
|
|
1300
|
+
min-width: 0;
|
|
1301
|
+
max-width: 100%;
|
|
1302
|
+
}
|
|
1303
|
+
.toolbar-angle-picker__lab {
|
|
1304
|
+
position: absolute;
|
|
1305
|
+
width: 1px;
|
|
1306
|
+
height: 1px;
|
|
1307
|
+
padding: 0;
|
|
1308
|
+
margin: -1px;
|
|
1309
|
+
overflow: hidden;
|
|
1310
|
+
clip: rect(0, 0, 0, 0);
|
|
1311
|
+
white-space: nowrap;
|
|
1312
|
+
border: 0;
|
|
1313
|
+
opacity: 0;
|
|
1314
|
+
pointer-events: none;
|
|
1315
|
+
}
|
|
1316
|
+
.toolbar-angle-picker select {
|
|
1317
|
+
max-width: min(200px, 52vw);
|
|
1318
|
+
min-width: 0;
|
|
1319
|
+
text-overflow: ellipsis;
|
|
1320
|
+
}
|
|
1321
|
+
.app__chrome {
|
|
1322
|
+
padding: 5px 8px 6px;
|
|
1323
|
+
gap: 5px;
|
|
1324
|
+
max-height: min(36vh, 360px);
|
|
1325
|
+
}
|
|
1326
|
+
/* Compact chrome: avoid heavy rings on inline fields (clear stays a real button). */
|
|
1327
|
+
.chrome__search-row input[type="search"]:focus-visible {
|
|
1328
|
+
outline: none;
|
|
1329
|
+
border-color: color-mix(in oklab, CanvasText 42%, Canvas);
|
|
1330
|
+
}
|
|
1331
|
+
.chrome__search-row #search-clear:focus-visible {
|
|
1332
|
+
outline: 2px solid color-mix(in oklab, CanvasText 45%, Canvas);
|
|
1333
|
+
outline-offset: 2px;
|
|
1334
|
+
}
|
|
1335
|
+
.chrome__search-label__caption {
|
|
1336
|
+
position: absolute;
|
|
1337
|
+
width: 1px;
|
|
1338
|
+
height: 1px;
|
|
1339
|
+
padding: 0;
|
|
1340
|
+
margin: -1px;
|
|
1341
|
+
overflow: hidden;
|
|
1342
|
+
clip: rect(0, 0, 0, 0);
|
|
1343
|
+
white-space: nowrap;
|
|
1344
|
+
border: 0;
|
|
1345
|
+
}
|
|
1346
|
+
.chrome__search-label__glyph {
|
|
1347
|
+
display: inline-flex;
|
|
1348
|
+
align-items: center;
|
|
1349
|
+
justify-content: center;
|
|
1350
|
+
padding: 0 2px;
|
|
1351
|
+
margin: 0;
|
|
1352
|
+
color: color-mix(in oklab, CanvasText 72%, Canvas);
|
|
1353
|
+
}
|
|
1354
|
+
.chrome__search-label__glyph:hover {
|
|
1355
|
+
color: color-mix(in oklab, CanvasText 88%, Canvas);
|
|
1356
|
+
}
|
|
1357
|
+
.chrome__search-label:focus-within {
|
|
1358
|
+
outline: none;
|
|
1359
|
+
}
|
|
1360
|
+
.chrome__search-label__glyph svg {
|
|
1361
|
+
display: block;
|
|
1362
|
+
flex: 0 0 auto;
|
|
1363
|
+
}
|
|
1364
|
+
.toolbar-angle-picker select:focus-visible {
|
|
1365
|
+
outline: none;
|
|
1366
|
+
border-color: color-mix(in oklab, CanvasText 42%, Canvas);
|
|
1367
|
+
}
|
|
1368
|
+
.toolbar-icon-btn--flip-only-narrow {
|
|
1369
|
+
display: inline-flex;
|
|
1370
|
+
}
|
|
1371
|
+
/**
|
|
1372
|
+
* Secondary flip: only on narrow viewports, only while the toolbar flip is off-screen
|
|
1373
|
+
* (see client IntersectionObserver). Same control as toolbar; fixed so it stays reachable.
|
|
1374
|
+
*/
|
|
1375
|
+
.toolbar-icon-btn--flip-scroll-narrow {
|
|
1376
|
+
display: none;
|
|
1377
|
+
}
|
|
1378
|
+
#mobile-pane-flip-scroll.toolbar-icon-btn--flip-scroll-narrow.is-visible {
|
|
1379
|
+
display: inline-flex;
|
|
1380
|
+
position: fixed;
|
|
1381
|
+
top: calc(10px + env(safe-area-inset-top, 0px));
|
|
1382
|
+
right: calc(12px + env(safe-area-inset-right, 0px));
|
|
1383
|
+
z-index: 50;
|
|
1384
|
+
box-shadow:
|
|
1385
|
+
0 1px 2px color-mix(in oklab, CanvasText 12%, transparent),
|
|
1386
|
+
0 4px 14px color-mix(in oklab, CanvasText 18%, transparent);
|
|
1387
|
+
}
|
|
1388
|
+
/** Region connector lines are not needed on the narrow single-pane layout (gutter is hidden). */
|
|
1389
|
+
.shell:not(.shell--stretch-rows) .gutter .gutter__rays {
|
|
1390
|
+
opacity: 0 !important;
|
|
1391
|
+
pointer-events: none !important;
|
|
1392
|
+
}
|
|
1393
|
+
.nav-rail__doc-hub-summary {
|
|
1394
|
+
min-width: var(--cr-control-h);
|
|
1395
|
+
padding: 0 10px;
|
|
1396
|
+
justify-content: center;
|
|
1397
|
+
gap: 0;
|
|
1398
|
+
}
|
|
1399
|
+
.nav-rail__doc-hub-summary__caption {
|
|
1400
|
+
position: absolute;
|
|
1401
|
+
width: 1px;
|
|
1402
|
+
height: 1px;
|
|
1403
|
+
padding: 0;
|
|
1404
|
+
margin: -1px;
|
|
1405
|
+
overflow: hidden;
|
|
1406
|
+
clip: rect(0, 0, 0, 0);
|
|
1407
|
+
white-space: nowrap;
|
|
1408
|
+
border: 0;
|
|
1409
|
+
}
|
|
1410
|
+
.nav-rail__doc-hub-summary__glyph {
|
|
1411
|
+
display: inline-flex;
|
|
1412
|
+
}
|
|
1413
|
+
.toolbar-wrap-lines {
|
|
1414
|
+
min-width: var(--cr-control-h);
|
|
1415
|
+
padding: 0;
|
|
1416
|
+
justify-content: center;
|
|
1417
|
+
gap: 0;
|
|
1418
|
+
font-weight: 500;
|
|
1419
|
+
}
|
|
1420
|
+
.toolbar-wrap-lines__caption {
|
|
1421
|
+
position: absolute;
|
|
1422
|
+
width: 1px;
|
|
1423
|
+
height: 1px;
|
|
1424
|
+
padding: 0;
|
|
1425
|
+
margin: -1px;
|
|
1426
|
+
overflow: hidden;
|
|
1427
|
+
clip: rect(0, 0, 0, 0);
|
|
1428
|
+
white-space: nowrap;
|
|
1429
|
+
border: 0;
|
|
1430
|
+
}
|
|
1431
|
+
.toolbar-wrap-lines__box {
|
|
1432
|
+
display: none;
|
|
1433
|
+
}
|
|
1434
|
+
.toolbar-wrap-lines__face {
|
|
1435
|
+
display: inline-flex;
|
|
1436
|
+
position: relative;
|
|
1437
|
+
width: 100%;
|
|
1438
|
+
height: 100%;
|
|
1439
|
+
min-height: var(--cr-control-h);
|
|
1440
|
+
min-width: var(--cr-control-h);
|
|
1441
|
+
}
|
|
1442
|
+
.toolbar-wrap-lines:has(.toolbar-wrap-lines__input:checked) .toolbar-wrap-lines__face::after {
|
|
1443
|
+
content: "✓";
|
|
1444
|
+
position: absolute;
|
|
1445
|
+
right: 1px;
|
|
1446
|
+
bottom: 0;
|
|
1447
|
+
font-size: 11px;
|
|
1448
|
+
line-height: 1;
|
|
1449
|
+
font-weight: 800;
|
|
1450
|
+
color: CanvasText;
|
|
1451
|
+
text-shadow: 0 0 2px Canvas, 0 0 3px Canvas;
|
|
1452
|
+
}
|
|
1453
|
+
.shell:not(.shell--stretch-rows)[data-dual-mobile-pane="code"] .pane--doc,
|
|
1454
|
+
.shell:not(.shell--stretch-rows)[data-dual-mobile-pane="code"] .gutter {
|
|
1455
|
+
display: none !important;
|
|
1456
|
+
}
|
|
1457
|
+
.shell:not(.shell--stretch-rows)[data-dual-mobile-pane="doc"] .pane--code,
|
|
1458
|
+
.shell:not(.shell--stretch-rows)[data-dual-mobile-pane="doc"] .gutter {
|
|
1459
|
+
display: none !important;
|
|
1460
|
+
}
|
|
1461
|
+
.shell:not(.shell--stretch-rows)[data-dual-mobile-pane="code"] .pane--code,
|
|
1462
|
+
.shell:not(.shell--stretch-rows)[data-dual-mobile-pane="doc"] .pane--doc {
|
|
1463
|
+
border-right: 0 !important;
|
|
1464
|
+
}
|
|
1465
|
+
.shell:not(.shell--stretch-rows) .shell__pair-context {
|
|
1466
|
+
flex-direction: column;
|
|
1467
|
+
align-items: stretch;
|
|
1468
|
+
gap: 4px;
|
|
1469
|
+
padding: 4px 0 6px;
|
|
1470
|
+
}
|
|
1471
|
+
.shell:not(.shell--stretch-rows) .shell__pair-gutter-spacer {
|
|
1472
|
+
display: none;
|
|
1473
|
+
}
|
|
1474
|
+
.shell:not(.shell--stretch-rows) .shell__pair-cell--src {
|
|
1475
|
+
flex: 1 1 auto;
|
|
1476
|
+
padding-left: var(--cr-pane-inline-pad);
|
|
1477
|
+
}
|
|
1478
|
+
.shell:not(.shell--stretch-rows) .shell__pair-cell--doc {
|
|
1479
|
+
flex: 1 1 auto;
|
|
1480
|
+
padding-left: var(--cr-pane-inline-pad);
|
|
1481
|
+
}
|
|
624
1482
|
}
|
|
625
1483
|
.pane--doc { font-size: 15px; line-height: 1.45; }
|
|
626
1484
|
.pane--doc img { max-width: 100%; height: auto; }
|
|
@@ -637,7 +1495,6 @@ const CODE_BROWSER_STYLES = `
|
|
|
637
1495
|
border-top: 1px solid color-mix(in oklab, CanvasText 22%, Canvas);
|
|
638
1496
|
pointer-events: none;
|
|
639
1497
|
}
|
|
640
|
-
.pane h2.pane-title { margin: 0 0 10px; font-size: 12px; letter-spacing: 0.06em; text-transform: uppercase; opacity: 0.75; }
|
|
641
1498
|
.shell--stretch-rows {
|
|
642
1499
|
flex: 1;
|
|
643
1500
|
min-height: 0;
|
|
@@ -651,8 +1508,15 @@ const CODE_BROWSER_STYLES = `
|
|
|
651
1508
|
border-bottom: 1px solid color-mix(in oklab, CanvasText 12%, Canvas);
|
|
652
1509
|
font-size: 15px;
|
|
653
1510
|
line-height: 1.45;
|
|
1511
|
+
overflow-x: auto;
|
|
1512
|
+
max-width: 100%;
|
|
654
1513
|
}
|
|
655
1514
|
.shell--stretch-rows .stretch-preamble img { max-width: 100%; height: auto; }
|
|
1515
|
+
.shell--stretch-rows .stretch-preamble :where(table) {
|
|
1516
|
+
width: max-content;
|
|
1517
|
+
max-width: none;
|
|
1518
|
+
border-collapse: collapse;
|
|
1519
|
+
}
|
|
656
1520
|
.block-stretch {
|
|
657
1521
|
width: 100%;
|
|
658
1522
|
border-collapse: collapse;
|
|
@@ -673,8 +1537,30 @@ const CODE_BROWSER_STYLES = `
|
|
|
673
1537
|
.block-stretch td.stretch-doc .stretch-doc-inner {
|
|
674
1538
|
font-size: 15px;
|
|
675
1539
|
line-height: 1.45;
|
|
1540
|
+
min-width: 0;
|
|
1541
|
+
overflow-x: auto;
|
|
676
1542
|
}
|
|
677
1543
|
.block-stretch td.stretch-doc .stretch-doc-inner img { max-width: 100%; height: auto; }
|
|
1544
|
+
.block-stretch td.stretch-doc .stretch-doc-inner :where(table) {
|
|
1545
|
+
width: max-content;
|
|
1546
|
+
max-width: none;
|
|
1547
|
+
border-collapse: collapse;
|
|
1548
|
+
}
|
|
1549
|
+
.block-stretch td.stretch-doc .stretch-doc-inner .commentray-mermaid {
|
|
1550
|
+
overflow-x: auto;
|
|
1551
|
+
max-width: 100%;
|
|
1552
|
+
}
|
|
1553
|
+
.block-stretch.wrap td.stretch-doc .stretch-doc-inner {
|
|
1554
|
+
overflow-wrap: break-word;
|
|
1555
|
+
}
|
|
1556
|
+
.block-stretch.wrap td.stretch-doc .stretch-doc-inner :where(table) {
|
|
1557
|
+
overflow-wrap: normal;
|
|
1558
|
+
word-break: normal;
|
|
1559
|
+
}
|
|
1560
|
+
.block-stretch:not(.wrap) td.stretch-doc .stretch-doc-inner {
|
|
1561
|
+
overflow-wrap: normal;
|
|
1562
|
+
word-break: normal;
|
|
1563
|
+
}
|
|
678
1564
|
.block-stretch td.stretch-doc--gap {
|
|
679
1565
|
color: color-mix(in oklab, CanvasText 38%, Canvas);
|
|
680
1566
|
font-size: 13px;
|
|
@@ -721,68 +1607,117 @@ const CODE_BROWSER_STYLES = `
|
|
|
721
1607
|
.block-stretch.wrap .code-line pre code { white-space: pre-wrap; word-break: break-word; }
|
|
722
1608
|
.block-stretch:not(.wrap) .code-line pre,
|
|
723
1609
|
.block-stretch:not(.wrap) .code-line pre code { white-space: pre; }
|
|
724
|
-
.block-stretch-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
1610
|
+
.block-stretch.wrap .stretch-doc-inner pre,
|
|
1611
|
+
.block-stretch.wrap .stretch-doc-inner pre code {
|
|
1612
|
+
white-space: pre-wrap;
|
|
1613
|
+
word-break: break-word;
|
|
1614
|
+
}
|
|
1615
|
+
.block-stretch:not(.wrap) .stretch-doc-inner pre,
|
|
1616
|
+
.block-stretch:not(.wrap) .stretch-doc-inner pre code {
|
|
1617
|
+
white-space: pre;
|
|
730
1618
|
}
|
|
731
|
-
.block-stretch-headings .pane-title { margin: 0; }
|
|
732
1619
|
`;
|
|
733
1620
|
/** Native tooltip on #search-q (short hint is visible under the search row). */
|
|
734
1621
|
const CODE_BROWSER_SEARCH_INPUT_TITLE = "Filename, path, or words. Matches this pair (source + commentray lines) first; merges commentray-nav-search.json when the export includes it (indexed paths + commentray lines).";
|
|
735
1622
|
function buildCodeBrowserPageHtml(p) {
|
|
736
1623
|
const shellClass = p.layout === "stretch" ? "shell shell--stretch-rows" : "shell";
|
|
1624
|
+
const dualFlipControlHtml = p.layout === "dual"
|
|
1625
|
+
? `<button type="button" id="mobile-pane-flip" class="toolbar-icon-btn toolbar-icon-btn--flip-only-narrow" aria-label="Switch between source code and commentary" title="Switch between source code and commentary">${TOOLBAR_ICON_FLIP_PANES_SVG}</button>`
|
|
1626
|
+
: "";
|
|
1627
|
+
const dualFlipScrollAffordanceHtml = p.layout === "dual"
|
|
1628
|
+
? `<button type="button" id="mobile-pane-flip-scroll" class="toolbar-icon-btn toolbar-icon-btn--flip-scroll-narrow" hidden aria-label="Switch between source code and commentary" title="Switch between source code and commentary">${TOOLBAR_ICON_FLIP_PANES_SVG}</button>`
|
|
1629
|
+
: "";
|
|
737
1630
|
return `<!doctype html>
|
|
738
|
-
<html lang="en">
|
|
1631
|
+
<html lang="en" data-commentray-theme="system">
|
|
739
1632
|
<head>
|
|
740
1633
|
<meta charset="utf-8" />
|
|
741
1634
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
742
|
-
${
|
|
743
|
-
|
|
744
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.11.1/build/styles/${escapeHtml(p.
|
|
1635
|
+
${COMMENTRAY_FAVICON_LINK_HTML}
|
|
1636
|
+
${p.metaDescriptionHtml}${p.generatorMetaHtml}<title>${escapeHtml(p.title)}</title>
|
|
1637
|
+
<link rel="stylesheet" id="commentray-hljs-light" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.11.1/build/styles/${escapeHtml(p.hljs)}.min.css" media="(prefers-color-scheme: light)" />
|
|
1638
|
+
<link rel="stylesheet" id="commentray-hljs-dark" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.11.1/build/styles/${escapeHtml(p.hljsDark)}.min.css" media="(prefers-color-scheme: dark)" />
|
|
1639
|
+
<script>
|
|
1640
|
+
${commentrayColorThemeHeadBoot()}
|
|
1641
|
+
</script>
|
|
745
1642
|
<style>
|
|
746
1643
|
${CODE_BROWSER_STYLES}
|
|
747
1644
|
</style>
|
|
748
1645
|
</head>
|
|
749
1646
|
<body>
|
|
1647
|
+
<a class="skip-link" href="#main-content">Skip to main content</a>
|
|
750
1648
|
<div class="app">
|
|
751
|
-
<header class="
|
|
1649
|
+
<header class="toolbar" role="banner" aria-label="View options">
|
|
1650
|
+
<h1 class="sr-only">${escapeHtml(p.title)}</h1>
|
|
1651
|
+
<div class="toolbar__primary">
|
|
1652
|
+
<div class="toolbar__primary-main">
|
|
1653
|
+
${p.toolbarSiteHubHtml}
|
|
1654
|
+
${p.navRailDocumentedHtml}
|
|
1655
|
+
${p.angleSelectHtml}
|
|
1656
|
+
<label class="toolbar-wrap-lines" title="Wrap long lines in the source pane; in commentary, wrap long words and fenced code when on (wide tables and diagrams scroll horizontally).">
|
|
1657
|
+
<input type="checkbox" id="wrap-lines" class="toolbar-wrap-lines__input" />
|
|
1658
|
+
<span class="toolbar-wrap-lines__box" aria-hidden="true"></span>
|
|
1659
|
+
<span class="toolbar-wrap-lines__face" aria-hidden="true">${TOOLBAR_ICON_WRAP_SVG}</span>
|
|
1660
|
+
<span class="toolbar-wrap-lines__caption">Wrap lines</span>
|
|
1661
|
+
</label>
|
|
1662
|
+
${dualFlipControlHtml}
|
|
1663
|
+
${p.toolbarDocHubHtml}
|
|
1664
|
+
${p.relatedNavHtml}
|
|
1665
|
+
</div>
|
|
1666
|
+
<div class="toolbar__primary-trail">
|
|
1667
|
+
${p.toolbarEndHtml}
|
|
1668
|
+
${TOOLBAR_COLOR_THEME_HTML}
|
|
1669
|
+
</div>
|
|
1670
|
+
</div>
|
|
1671
|
+
</header>
|
|
1672
|
+
${dualFlipScrollAffordanceHtml}
|
|
1673
|
+
<header class="app__chrome" role="region" aria-label="Search">
|
|
752
1674
|
<div class="chrome__search-row">
|
|
753
|
-
<label class="chrome__search-label
|
|
1675
|
+
<label class="chrome__search-label" for="search-q" aria-label="Search" title="Search"><span class="chrome__search-label__caption nav-rail__search-label">Search</span><span class="chrome__search-label__glyph" aria-hidden="true">${CHROME_ICON_SEARCH_SVG}</span></label>
|
|
754
1676
|
<input type="search" id="search-q" placeholder="${escapeHtml(p.searchPlaceholder)}" title="${escapeHtml(CODE_BROWSER_SEARCH_INPUT_TITLE)}" autocomplete="off" spellcheck="false" />
|
|
755
|
-
<button type="button" id="search-clear" title="Clear search">Clear</button>
|
|
1677
|
+
<button type="button" id="search-clear" aria-label="Clear search" title="Clear search">Clear</button>
|
|
756
1678
|
</div>
|
|
757
1679
|
<div class="search-results" id="search-results" hidden aria-live="polite"></div>
|
|
758
|
-
<p class="nav-rail__search-hint chrome__search-hint">This pair + merged <code class="nav-rail__code">commentray-nav-search.json</code> when the export ships it.</p>
|
|
759
1680
|
</header>
|
|
760
|
-
<
|
|
761
|
-
<
|
|
762
|
-
<div class="toolbar__main">
|
|
763
|
-
${p.navRailContextHtml}
|
|
764
|
-
${p.navRailDocumentedHtml}
|
|
765
|
-
${p.angleSelectHtml}
|
|
766
|
-
${p.toolbarDocHubHtml}
|
|
767
|
-
${p.relatedNavHtml}
|
|
768
|
-
<label><input type="checkbox" id="wrap-lines" /> Wrap code lines</label>
|
|
769
|
-
</div>
|
|
770
|
-
${p.toolbarEndHtml}
|
|
771
|
-
</header>
|
|
772
|
-
<div class="${shellClass}" id="shell" data-layout="${p.layout}" data-raw-code-b64="${escapeHtml(p.rawCodeB64)}" data-raw-md-b64="${escapeHtml(p.rawMdB64)}" data-scroll-block-links-b64="${escapeHtml(p.scrollBlockLinksB64)}"${p.shellDocumentedPairsAttr}${p.shellSearchAttrs}>
|
|
1681
|
+
<main id="main-content" class="app__main" tabindex="-1">
|
|
1682
|
+
<div class="${shellClass}" id="shell" data-layout="${p.layout}"${p.layout === "dual" ? ' data-dual-mobile-pane="doc"' : ""} data-raw-code-b64="${escapeHtml(p.rawCodeB64)}" data-raw-md-b64="${escapeHtml(p.rawMdB64)}" data-scroll-block-links-b64="${escapeHtml(p.scrollBlockLinksB64)}"${p.shellDocumentedPairsAttr}${p.shellSearchAttrs}${p.shellPairDocDataAttr}>
|
|
773
1683
|
${p.shellInner}
|
|
774
1684
|
</div>
|
|
775
|
-
</
|
|
1685
|
+
</main>
|
|
776
1686
|
${p.pageFooterHtml}
|
|
777
1687
|
</div>
|
|
778
1688
|
<script type="text/plain" id="commentray-multi-angle-b64">${p.multiAngleScriptBlock}</script>
|
|
1689
|
+
${p.mermaidScript}
|
|
779
1690
|
<script>
|
|
780
1691
|
${loadCodeBrowserClientBundle()}
|
|
781
1692
|
</script>
|
|
782
|
-
${p.mermaidScript}
|
|
783
1693
|
</body>
|
|
784
1694
|
</html>`;
|
|
785
1695
|
}
|
|
1696
|
+
async function multiAngleJsonRowAndDocHtml(opts, spec) {
|
|
1697
|
+
const rows = spec.blockStretchRows;
|
|
1698
|
+
const links = rows !== undefined
|
|
1699
|
+
? buildBlockScrollLinks(rows.index, rows.sourceRelative, rows.commentrayPathRel, spec.markdown, opts.code)
|
|
1700
|
+
: [];
|
|
1701
|
+
const mdForDoc = injectCommentrayDocAnchors(spec.markdown, links.length > 0 ? links : undefined);
|
|
1702
|
+
const scrollB64 = links.length > 0 ? Buffer.from(JSON.stringify(links), "utf8").toString("base64") : "";
|
|
1703
|
+
const commentrayHtml = await renderMarkdownToHtml(mdForDoc, {
|
|
1704
|
+
commentrayOutputUrls: opts.commentrayOutputUrls,
|
|
1705
|
+
});
|
|
1706
|
+
return {
|
|
1707
|
+
jsonRow: {
|
|
1708
|
+
id: spec.id,
|
|
1709
|
+
title: spec.title?.trim() || spec.id,
|
|
1710
|
+
docInnerHtmlB64: Buffer.from(commentrayHtml, "utf8").toString("base64"),
|
|
1711
|
+
rawMdB64: Buffer.from(spec.markdown, "utf8").toString("base64"),
|
|
1712
|
+
scrollBlockLinksB64: scrollB64,
|
|
1713
|
+
commentrayPathForSearch: spec.commentrayPathRel.trim(),
|
|
1714
|
+
commentrayOnGithubUrl: spec.commentrayOnGithubUrl,
|
|
1715
|
+
staticBrowseUrl: spec.staticBrowseUrl,
|
|
1716
|
+
},
|
|
1717
|
+
commentrayHtml,
|
|
1718
|
+
scrollB64,
|
|
1719
|
+
};
|
|
1720
|
+
}
|
|
786
1721
|
async function buildMultiAngleDualPaneShell(opts, multi) {
|
|
787
1722
|
const defaultId = multi.angles.some((a) => a.id === multi.defaultAngleId)
|
|
788
1723
|
? multi.defaultAngleId
|
|
@@ -792,34 +1727,24 @@ async function buildMultiAngleDualPaneShell(opts, multi) {
|
|
|
792
1727
|
let defaultScrollB64 = "";
|
|
793
1728
|
let defaultPathSearch = (opts.commentrayPathForSearch ?? "").trim();
|
|
794
1729
|
let defaultGh = opts.commentrayOnGithubUrl;
|
|
1730
|
+
let defaultStaticBrowse = (opts.commentrayStaticBrowseUrl ?? "").trim();
|
|
795
1731
|
let defaultPaneHtml = "";
|
|
796
1732
|
const codeHtml = await renderHighlightedCodeLineRows(opts.code, opts.language);
|
|
797
1733
|
for (const spec of multi.angles) {
|
|
798
|
-
const
|
|
799
|
-
const links = rows !== undefined
|
|
800
|
-
? buildBlockScrollLinks(rows.index, rows.sourceRelative, rows.commentrayPathRel, spec.markdown, opts.code)
|
|
801
|
-
: [];
|
|
802
|
-
const mdForDoc = injectCommentrayDocAnchors(spec.markdown, links.length > 0 ? links : undefined);
|
|
803
|
-
const scrollB64 = links.length > 0 ? Buffer.from(JSON.stringify(links), "utf8").toString("base64") : "";
|
|
804
|
-
const commentrayHtml = await renderMarkdownToHtml(mdForDoc, {
|
|
805
|
-
commentrayOutputUrls: opts.commentrayOutputUrls,
|
|
806
|
-
});
|
|
1734
|
+
const { jsonRow, commentrayHtml, scrollB64 } = await multiAngleJsonRowAndDocHtml(opts, spec);
|
|
807
1735
|
if (spec.id === defaultId) {
|
|
808
1736
|
defaultMarkdown = spec.markdown;
|
|
809
1737
|
defaultScrollB64 = scrollB64;
|
|
810
1738
|
defaultPathSearch = spec.commentrayPathRel.trim();
|
|
811
1739
|
defaultGh = spec.commentrayOnGithubUrl;
|
|
1740
|
+
{
|
|
1741
|
+
const sb = (spec.staticBrowseUrl ?? "").trim();
|
|
1742
|
+
if (sb.length > 0)
|
|
1743
|
+
defaultStaticBrowse = sb;
|
|
1744
|
+
}
|
|
812
1745
|
defaultPaneHtml = commentrayHtml;
|
|
813
1746
|
}
|
|
814
|
-
jsonAngles.push(
|
|
815
|
-
id: spec.id,
|
|
816
|
-
title: spec.title?.trim() || spec.id,
|
|
817
|
-
docInnerHtmlB64: Buffer.from(commentrayHtml, "utf8").toString("base64"),
|
|
818
|
-
rawMdB64: Buffer.from(spec.markdown, "utf8").toString("base64"),
|
|
819
|
-
scrollBlockLinksB64: scrollB64,
|
|
820
|
-
commentrayPathForSearch: spec.commentrayPathRel.trim(),
|
|
821
|
-
commentrayOnGithubUrl: spec.commentrayOnGithubUrl,
|
|
822
|
-
});
|
|
1747
|
+
jsonAngles.push(jsonRow);
|
|
823
1748
|
}
|
|
824
1749
|
const selOpts = multi.angles
|
|
825
1750
|
.map((a) => {
|
|
@@ -827,18 +1752,9 @@ async function buildMultiAngleDualPaneShell(opts, multi) {
|
|
|
827
1752
|
return `<option value="${escapeHtml(a.id)}"${a.id === defaultId ? " selected" : ""}>${lab}</option>`;
|
|
828
1753
|
})
|
|
829
1754
|
.join("");
|
|
830
|
-
const angleSelectHtml = `<span class="toolbar-angle-picker"><label for="angle-select">Angle</label><select id="angle-select" aria-label="Commentray angle">${selOpts}</select></span>`;
|
|
831
|
-
const
|
|
832
|
-
|
|
833
|
-
` ${codeHtml}\n` +
|
|
834
|
-
` </section>\n` +
|
|
835
|
-
` <div class="gutter" id="gutter" role="separator" aria-orientation="vertical" aria-label="Resize panes"></div>\n` +
|
|
836
|
-
` <section class="pane--doc commentray" id="doc-pane" aria-label="Commentray">\n` +
|
|
837
|
-
` <h2 class="pane-title">Commentray</h2>\n` +
|
|
838
|
-
` <div id="doc-pane-body" class="doc-pane-body">\n` +
|
|
839
|
-
` ${defaultPaneHtml}\n` +
|
|
840
|
-
` </div>\n` +
|
|
841
|
-
` </section>\n`;
|
|
1755
|
+
const angleSelectHtml = `<span class="toolbar-angle-picker"><label class="toolbar-angle-picker__lab nav-rail__search-label" for="angle-select">Angle</label><select id="angle-select" aria-label="Commentray angle">${selOpts}</select></span>`;
|
|
1756
|
+
const pairHtml = renderShellPairContextHtml(opts.filePath, defaultPathSearch);
|
|
1757
|
+
const shellInner = wrapDualShellInner(pairHtml, dualPanePanesInnerHtml(codeHtml, defaultPaneHtml));
|
|
842
1758
|
const payloadObj = { defaultAngleId: defaultId, angles: jsonAngles };
|
|
843
1759
|
const multiAnglePayloadB64 = Buffer.from(JSON.stringify(payloadObj), "utf8").toString("base64");
|
|
844
1760
|
return {
|
|
@@ -848,6 +1764,7 @@ async function buildMultiAngleDualPaneShell(opts, multi) {
|
|
|
848
1764
|
scrollBlockLinksB64: defaultScrollB64,
|
|
849
1765
|
commentrayPathForSearch: defaultPathSearch,
|
|
850
1766
|
commentrayOnGithubUrl: defaultGh,
|
|
1767
|
+
...(defaultStaticBrowse.length > 0 ? { commentrayStaticBrowseUrl: defaultStaticBrowse } : {}),
|
|
851
1768
|
},
|
|
852
1769
|
angleSelectHtml,
|
|
853
1770
|
multiAnglePayloadB64,
|
|
@@ -883,13 +1800,7 @@ async function buildCodeBrowserShell(opts, layoutPref) {
|
|
|
883
1800
|
});
|
|
884
1801
|
if (stretched) {
|
|
885
1802
|
layout = "stretch";
|
|
886
|
-
shellInner =
|
|
887
|
-
` <div class="block-stretch-headings">` +
|
|
888
|
-
`<h2 class="pane-title">Code</h2>` +
|
|
889
|
-
`<h2 class="pane-title">Commentray</h2>` +
|
|
890
|
-
`</div>\n` +
|
|
891
|
-
` ${stretched.preambleHtml}\n` +
|
|
892
|
-
` ${stretched.tableInnerHtml}\n`;
|
|
1803
|
+
shellInner = ` ${stretched.preambleHtml}\n` + ` ${stretched.tableInnerHtml}\n`;
|
|
893
1804
|
}
|
|
894
1805
|
}
|
|
895
1806
|
if (layout === "dual") {
|
|
@@ -906,18 +1817,8 @@ async function buildCodeBrowserShell(opts, layoutPref) {
|
|
|
906
1817
|
commentrayOutputUrls: opts.commentrayOutputUrls,
|
|
907
1818
|
}),
|
|
908
1819
|
]);
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
`<h2 class="pane-title">Code</h2>\n` +
|
|
912
|
-
` ${codeHtml}\n` +
|
|
913
|
-
` </section>\n` +
|
|
914
|
-
` <div class="gutter" id="gutter" role="separator" aria-orientation="vertical" aria-label="Resize panes"></div>\n` +
|
|
915
|
-
` <section class="pane--doc commentray" id="doc-pane" aria-label="Commentray">\n` +
|
|
916
|
-
` <h2 class="pane-title">Commentray</h2>\n` +
|
|
917
|
-
` <div id="doc-pane-body" class="doc-pane-body">\n` +
|
|
918
|
-
` ${commentrayHtml}\n` +
|
|
919
|
-
` </div>\n` +
|
|
920
|
-
` </section>\n`;
|
|
1820
|
+
const pairHtml = renderShellPairContextHtml(opts.filePath, (opts.commentrayPathForSearch ?? "").trim());
|
|
1821
|
+
shellInner = wrapDualShellInner(pairHtml, dualPanePanesInnerHtml(codeHtml, commentrayHtml));
|
|
921
1822
|
}
|
|
922
1823
|
return {
|
|
923
1824
|
layout,
|
|
@@ -949,22 +1850,30 @@ function shellDocumentedPairsAttrFromOptions(opts) {
|
|
|
949
1850
|
function codeBrowserPageTitle(opts) {
|
|
950
1851
|
return opts.title ?? opts.filePath ?? "Commentray";
|
|
951
1852
|
}
|
|
952
|
-
function codeBrowserHljsThemes(opts) {
|
|
953
|
-
const hljs = opts.hljsTheme ?? "github";
|
|
954
|
-
const hljsDark = opts.hljsTheme?.includes("dark") ? opts.hljsTheme : "github-dark";
|
|
955
|
-
return { hljs, hljsDark };
|
|
956
|
-
}
|
|
957
1853
|
function toolbarCommentrayGithubFromShell(shell, opts) {
|
|
958
1854
|
return shell.multiShell?.commentrayOnGithubUrl ?? opts.commentrayOnGithubUrl;
|
|
959
1855
|
}
|
|
960
1856
|
function rawMdB64FromShell(shell, opts) {
|
|
961
1857
|
return (shell.multiShell?.rawMdB64 ?? Buffer.from(opts.commentrayMarkdown, "utf8").toString("base64"));
|
|
962
1858
|
}
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
1859
|
+
/** Canonical doc target for static validation: same-site `./browse/…` when present, else GitHub blob. */
|
|
1860
|
+
function shellPairDocDataAttr(shell, opts) {
|
|
1861
|
+
if (shell.layout !== "dual")
|
|
1862
|
+
return "";
|
|
1863
|
+
const browseRaw = (shell.multiShell?.commentrayStaticBrowseUrl ??
|
|
1864
|
+
opts.commentrayStaticBrowseUrl ??
|
|
966
1865
|
"").trim();
|
|
967
|
-
|
|
1866
|
+
if (browseRaw.length > 0) {
|
|
1867
|
+
const href = safeToolbarNavigationHref(browseRaw);
|
|
1868
|
+
if (href !== null) {
|
|
1869
|
+
return ` data-commentray-pair-browse-href="${escapeHtml(href)}"`;
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
const gh = safeExternalHttpUrl(toolbarCommentrayGithubFromShell(shell, opts));
|
|
1873
|
+
if (gh !== null) {
|
|
1874
|
+
return ` data-commentray-pair-browse-href="${escapeHtml(gh)}"`;
|
|
1875
|
+
}
|
|
1876
|
+
return "";
|
|
968
1877
|
}
|
|
969
1878
|
function shellSearchAttrsWithNavJson(shellSearchAttrsBase, documentedNavJsonUrl) {
|
|
970
1879
|
const navJson = documentedNavJsonUrl?.trim() ?? "";
|
|
@@ -980,11 +1889,17 @@ function shellSearchAttrsWithNavJson(shellSearchAttrsBase, documentedNavJsonUrl)
|
|
|
980
1889
|
export async function renderCodeBrowserHtml(opts) {
|
|
981
1890
|
const rawCodeB64 = Buffer.from(opts.code, "utf8").toString("base64");
|
|
982
1891
|
const title = codeBrowserPageTitle(opts);
|
|
1892
|
+
const metaDescriptionHtml = renderMetaDescriptionHtml(opts, title);
|
|
983
1893
|
const builtAt = opts.builtAt ?? new Date();
|
|
984
1894
|
const renderSemver = commentrayRenderVersion();
|
|
985
|
-
const
|
|
986
|
-
const
|
|
987
|
-
const
|
|
1895
|
+
const toolbarSiteHubHtml = buildToolbarSiteHubHtml(opts.siteHubUrl);
|
|
1896
|
+
const toolbarEndHtml = buildToolbarEndHtml(opts.githubRepoUrl, opts.siteHubUrl);
|
|
1897
|
+
const pageFooterHtml = renderPageFooterHtml({
|
|
1898
|
+
builtAt,
|
|
1899
|
+
toolHomeUrl: opts.toolHomeUrl,
|
|
1900
|
+
commentrayRenderSemver: renderSemver,
|
|
1901
|
+
});
|
|
1902
|
+
const { hljsLight, hljsDark } = hljsStylesheetThemes(opts.hljsTheme);
|
|
988
1903
|
const mermaidScript = mermaidRuntimeScriptHtml(opts.includeMermaidRuntime);
|
|
989
1904
|
const relatedNavHtml = renderRelatedGithubNavHtml(opts.relatedGithubNav ?? []);
|
|
990
1905
|
const generatorMetaHtml = renderGeneratorMetaHtml(opts.generatorLabel);
|
|
@@ -999,14 +1914,13 @@ export async function renderCodeBrowserHtml(opts) {
|
|
|
999
1914
|
const { searchPlaceholder, shellSearchAttrs: shellSearchAttrsBase } = searchChromeFromOptions(opts, shell.multiShell?.commentrayPathForSearch);
|
|
1000
1915
|
const shellDocumentedPairsAttr = shellDocumentedPairsAttrFromOptions(opts);
|
|
1001
1916
|
const shellSearchAttrs = shellSearchAttrsWithNavJson(shellSearchAttrsBase, opts.documentedNavJsonUrl);
|
|
1002
|
-
const
|
|
1003
|
-
sourceOnGithubUrl: opts.sourceOnGithubUrl,
|
|
1004
|
-
commentrayOnGithubUrl: toolbarCommentrayGithubFromShell(shell, opts),
|
|
1005
|
-
});
|
|
1917
|
+
const pairDocDataAttr = shellPairDocDataAttr(shell, opts);
|
|
1006
1918
|
return buildCodeBrowserPageHtml({
|
|
1007
1919
|
title,
|
|
1920
|
+
metaDescriptionHtml,
|
|
1008
1921
|
generatorMetaHtml,
|
|
1009
|
-
|
|
1922
|
+
toolbarSiteHubHtml,
|
|
1923
|
+
shellPairDocDataAttr: pairDocDataAttr,
|
|
1010
1924
|
angleSelectHtml: shell.angleSelectHtml,
|
|
1011
1925
|
toolbarDocHubHtml,
|
|
1012
1926
|
navRailDocumentedHtml,
|
|
@@ -1019,7 +1933,7 @@ export async function renderCodeBrowserHtml(opts) {
|
|
|
1019
1933
|
rawMdB64,
|
|
1020
1934
|
scrollBlockLinksB64,
|
|
1021
1935
|
shellDocumentedPairsAttr,
|
|
1022
|
-
hljs,
|
|
1936
|
+
hljs: hljsLight,
|
|
1023
1937
|
hljsDark,
|
|
1024
1938
|
mermaidScript,
|
|
1025
1939
|
searchPlaceholder,
|