@commentray/render 0.0.4 → 0.0.6
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/block-stretch-layout.d.ts.map +1 -1
- package/dist/block-stretch-layout.js +11 -23
- package/dist/block-stretch-layout.js.map +1 -1
- 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 +22 -6
- package/dist/build-commentray-nav-search.d.ts.map +1 -1
- package/dist/build-commentray-nav-search.js +55 -36
- package/dist/build-commentray-nav-search.js.map +1 -1
- package/dist/build-stamp.d.ts +6 -0
- package/dist/build-stamp.d.ts.map +1 -0
- package/dist/build-stamp.js +23 -0
- package/dist/build-stamp.js.map +1 -0
- 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 -7
- package/dist/code-browser-client.js +787 -100
- package/dist/code-browser-client.js.map +1 -1
- package/dist/code-browser-pair-nav.d.ts +23 -0
- package/dist/code-browser-pair-nav.d.ts.map +1 -0
- package/dist/code-browser-pair-nav.js +59 -0
- package/dist/code-browser-pair-nav.js.map +1 -0
- package/dist/code-browser-search.d.ts +50 -0
- package/dist/code-browser-search.d.ts.map +1 -1
- package/dist/code-browser-search.js +117 -0
- package/dist/code-browser-search.js.map +1 -1
- package/dist/code-browser.d.ts +51 -2
- package/dist/code-browser.d.ts.map +1 -1
- package/dist/code-browser.js +863 -196
- package/dist/code-browser.js.map +1 -1
- package/dist/highlighted-code-lines.d.ts +19 -0
- package/dist/highlighted-code-lines.d.ts.map +1 -0
- package/dist/highlighted-code-lines.js +61 -0
- package/dist/highlighted-code-lines.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/markdown-pipeline.d.ts.map +1 -1
- package/dist/markdown-pipeline.js +3 -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 +3 -1
- package/dist/mermaid-runtime-html.js.map +1 -1
- package/package.json +2 -2
package/dist/code-browser.js
CHANGED
|
@@ -3,83 +3,137 @@ import { dirname, join } from "node:path";
|
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { MARKER_ID_BODY, buildBlockScrollLinks, } from "@commentray/core";
|
|
5
5
|
import { tryBuildBlockStretchTableHtml } from "./block-stretch-layout.js";
|
|
6
|
+
import { formatCommentrayBuiltAtLocal } from "./build-stamp.js";
|
|
6
7
|
import { escapeHtml } from "./html-utils.js";
|
|
8
|
+
import { renderHighlightedCodeLineRows } from "./highlighted-code-lines.js";
|
|
7
9
|
import { mermaidRuntimeScriptHtml } from "./mermaid-runtime-html.js";
|
|
8
|
-
import {
|
|
10
|
+
import { renderMarkdownToHtml } from "./markdown-pipeline.js";
|
|
11
|
+
import { commentrayRenderVersion } from "./package-version.js";
|
|
9
12
|
function renderGeneratorMetaHtml(label) {
|
|
10
13
|
const t = label?.trim();
|
|
11
14
|
if (!t)
|
|
12
15
|
return "";
|
|
13
16
|
return `<meta name="generator" content="${escapeHtml(t)}" />\n `;
|
|
14
17
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
const META_DESCRIPTION_MAX_LEN = 320;
|
|
19
|
+
function codeBrowserMetaDescription(opts, title) {
|
|
20
|
+
const custom = opts.metaDescription?.trim();
|
|
21
|
+
if (custom)
|
|
22
|
+
return custom.slice(0, META_DESCRIPTION_MAX_LEN);
|
|
23
|
+
const fallback = `${title} — Side-by-side source and commentray documentation.`;
|
|
24
|
+
return fallback.slice(0, META_DESCRIPTION_MAX_LEN);
|
|
25
|
+
}
|
|
26
|
+
function renderMetaDescriptionHtml(opts, title) {
|
|
27
|
+
const content = codeBrowserMetaDescription(opts, title);
|
|
28
|
+
return `<meta name="description" content="${escapeHtml(content)}" />\n `;
|
|
18
29
|
}
|
|
19
30
|
/** Single capture: marker id (avoid a wrapping group around the whole comment — that shifted indices). */
|
|
20
31
|
const BLOCK_MARKER_HTML_LINE = new RegExp(`^<!--\\s*commentray:block\\s+id=(${MARKER_ID_BODY})\\s*-->$`, "i");
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
function trimEndSpacesTabs(s) {
|
|
33
|
+
let end = s.length;
|
|
34
|
+
while (end > 0) {
|
|
35
|
+
const c = s[end - 1];
|
|
36
|
+
if (c !== " " && c !== "\t")
|
|
37
|
+
break;
|
|
38
|
+
end--;
|
|
39
|
+
}
|
|
40
|
+
return s.slice(0, end);
|
|
41
|
+
}
|
|
42
|
+
function isSetextUnderlineLine(line) {
|
|
43
|
+
const t = trimEndSpacesTabs(line);
|
|
44
|
+
return /^\s{0,3}=+\s*$/.test(t) || /^\s{0,3}-+\s*$/.test(t);
|
|
45
|
+
}
|
|
46
|
+
function isThematicBreakLine(line) {
|
|
47
|
+
const t = trimEndSpacesTabs(line);
|
|
48
|
+
return (/^\s{0,3}(?:\*[ \t]*){3,}\s*$/.test(t) ||
|
|
49
|
+
/^\s{0,3}(?:-[ \t]*){3,}\s*$/.test(t) ||
|
|
50
|
+
/^\s{0,3}(?:_[ \t]*){3,}\s*$/.test(t));
|
|
51
|
+
}
|
|
52
|
+
function parseFenceDelimiter(line) {
|
|
53
|
+
const t = trimEndSpacesTabs(line);
|
|
54
|
+
const m = /^(\s{0,3})(`{3,}|~{3,})(.*)$/.exec(t);
|
|
55
|
+
if (!m)
|
|
56
|
+
return null;
|
|
57
|
+
const run = m[2];
|
|
58
|
+
const head = run[0];
|
|
59
|
+
if (head !== "`" && head !== "~")
|
|
60
|
+
return null;
|
|
61
|
+
const ch = head === "`" ? "`" : "~";
|
|
62
|
+
return { ch, runLen: run.length, rest: m[3] ?? "" };
|
|
63
|
+
}
|
|
64
|
+
function isClosingFenceLine(info, open) {
|
|
65
|
+
if (info.ch !== open.ch || info.runLen < open.len)
|
|
66
|
+
return false;
|
|
67
|
+
return info.rest.trim() === "";
|
|
68
|
+
}
|
|
69
|
+
function lineAnchorHtml(mdLine0) {
|
|
70
|
+
const mdLine = String(mdLine0);
|
|
71
|
+
return `<span class="commentray-line-anchor" data-commentray-md-line="${mdLine}" id="commentray-md-line-${mdLine}" aria-hidden="true"></span>`;
|
|
72
|
+
}
|
|
73
|
+
function appendMdLineAnchorWhenAllowed(line, mdLine0) {
|
|
74
|
+
if (isSetextUnderlineLine(line) || isThematicBreakLine(line))
|
|
75
|
+
return line;
|
|
76
|
+
/** Blank lines must stay blank: a line that is only `<span …>` breaks CommonMark HTML / paragraph starts after block markers. */
|
|
77
|
+
if (line === "")
|
|
78
|
+
return "";
|
|
79
|
+
return `${line}${lineAnchorHtml(mdLine0)}`;
|
|
38
80
|
}
|
|
39
|
-
/**
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
81
|
+
/**
|
|
82
|
+
* Inserts per-line anchors for search / hash jumps and block separator anchors after each
|
|
83
|
+
* `<!-- commentray:block … -->` line (optional index attrs).
|
|
84
|
+
*
|
|
85
|
+
* Anchors are appended to the line when safe. A **leading** `<span>` breaks CommonMark block
|
|
86
|
+
* recognition (`#` headings, lists, thematic breaks, fences). Fenced code lines must not get a
|
|
87
|
+
* trailing anchor either (would corrupt fence delimiters or appear inside code).
|
|
88
|
+
*/
|
|
89
|
+
function injectCommentrayDocAnchors(markdown, links) {
|
|
90
|
+
const byId = links ? new Map(links.map((l) => [l.id, l])) : undefined;
|
|
91
|
+
const lines = markdown.split("\n");
|
|
92
|
+
let fence = null;
|
|
93
|
+
const out = [];
|
|
44
94
|
for (let i = 0; i < lines.length; i++) {
|
|
45
|
-
const line = lines[i]
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
95
|
+
const line = lines[i];
|
|
96
|
+
const delim = parseFenceDelimiter(line);
|
|
97
|
+
if (fence) {
|
|
98
|
+
if (delim && isClosingFenceLine(delim, fence)) {
|
|
99
|
+
fence = null;
|
|
100
|
+
out.push(line);
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
out.push(line);
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (delim) {
|
|
107
|
+
fence = { ch: delim.ch, len: delim.runLen };
|
|
108
|
+
out.push(line);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
const m = BLOCK_MARKER_HTML_LINE.exec(line);
|
|
112
|
+
if (m?.[1]) {
|
|
113
|
+
const id = m[1];
|
|
114
|
+
const link = byId?.get(id);
|
|
115
|
+
const attrs = link !== undefined
|
|
116
|
+
? ` data-source-start="${String(link.sourceStart)}" data-commentray-line="${String(link.commentrayLine)}"`
|
|
117
|
+
: "";
|
|
118
|
+
/** One `push` with embedded `\n\n` merged poorly with `join("\\n")`; keep real blank lines around raw `<div>`. */
|
|
119
|
+
out.push(`${line}${lineAnchorHtml(i)}`);
|
|
120
|
+
out.push("");
|
|
121
|
+
out.push(`<div id="commentray-block-${escapeHtml(id)}" class="commentray-block-anchor" aria-hidden="true"${attrs}></div>`);
|
|
122
|
+
out.push("");
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
out.push(appendMdLineAnchorWhenAllowed(line, i));
|
|
69
126
|
}
|
|
70
|
-
|
|
71
|
-
const dirHtml = dir
|
|
72
|
-
? `<span class="file-path__dir">${escapeHtml(dir)}</span>`
|
|
73
|
-
: `<span class="file-path__dir file-path__dir--root" title="Repository root">/ </span>`;
|
|
74
|
-
return (`<strong class="file-path" title="${escapeHtml(shown)}">` +
|
|
75
|
-
dirHtml +
|
|
76
|
-
`<span class="file-path__base">${escapeHtml(base)}</span>` +
|
|
77
|
-
`</strong>`);
|
|
127
|
+
return out.join("\n");
|
|
78
128
|
}
|
|
79
129
|
/** GitHub “mark” glyph (Octicons-style path), MIT-licensed silhouette. */
|
|
80
130
|
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">' +
|
|
81
131
|
'<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"/>' +
|
|
82
132
|
"</svg>";
|
|
133
|
+
/** Simple home glyph for same-site hub link (matches Octocat control size). */
|
|
134
|
+
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">' +
|
|
135
|
+
'<path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/>' +
|
|
136
|
+
"</svg>";
|
|
83
137
|
function safeExternalHttpUrl(url) {
|
|
84
138
|
const t = url?.trim();
|
|
85
139
|
if (!t)
|
|
@@ -88,22 +142,47 @@ function safeExternalHttpUrl(url) {
|
|
|
88
142
|
return null;
|
|
89
143
|
return t;
|
|
90
144
|
}
|
|
91
|
-
|
|
145
|
+
/** Allows relative static browse links (`./browse/…`) and `http(s):` URLs; rejects `javascript:` / `data:`. */
|
|
146
|
+
function safeToolbarNavigationHref(url) {
|
|
147
|
+
const t = url?.trim();
|
|
148
|
+
if (!t)
|
|
149
|
+
return null;
|
|
150
|
+
if (/^(javascript|data):/i.test(t))
|
|
151
|
+
return null;
|
|
152
|
+
return t;
|
|
153
|
+
}
|
|
154
|
+
function buildToolbarSiteHubHtml(siteHubUrl) {
|
|
155
|
+
const site = safeToolbarNavigationHref(siteHubUrl);
|
|
156
|
+
if (!site)
|
|
157
|
+
return "";
|
|
158
|
+
const se = escapeHtml(site);
|
|
159
|
+
return `<a class="toolbar-github" href="${se}" aria-label="Documentation home" title="Back to this site (hub)">${SITE_HOME_SVG}</a>`;
|
|
160
|
+
}
|
|
161
|
+
function buildToolbarEndHtml(githubRepoUrl, toolHomeUrl, commentrayRenderSemver, siteHubUrl) {
|
|
162
|
+
const site = safeToolbarNavigationHref(siteHubUrl);
|
|
92
163
|
const gh = safeExternalHttpUrl(githubRepoUrl);
|
|
93
164
|
const tool = safeExternalHttpUrl(toolHomeUrl);
|
|
94
165
|
const bits = [];
|
|
95
|
-
if (gh) {
|
|
166
|
+
if (!site && gh) {
|
|
96
167
|
const he = escapeHtml(gh);
|
|
97
168
|
bits.push(`<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>`);
|
|
98
169
|
}
|
|
99
170
|
if (tool) {
|
|
100
171
|
const te = escapeHtml(tool);
|
|
101
|
-
|
|
172
|
+
const ver = escapeHtml(commentrayRenderSemver);
|
|
173
|
+
bits.push(`<span class="toolbar-attribution" role="note">Rendered with <a href="${te}" target="_blank" rel="noopener noreferrer">Commentray</a> <span class="toolbar-attribution__version" translate="no">v${ver}</span></span>`);
|
|
102
174
|
}
|
|
103
175
|
if (bits.length === 0)
|
|
104
176
|
return "";
|
|
105
177
|
return `<div class="toolbar__end">${bits.join("")}</div>`;
|
|
106
178
|
}
|
|
179
|
+
function renderPageFooterHtml(builtAt) {
|
|
180
|
+
const iso = builtAt.toISOString();
|
|
181
|
+
const human = formatCommentrayBuiltAtLocal(builtAt);
|
|
182
|
+
return (`<footer class="app__footer" role="contentinfo">` +
|
|
183
|
+
`<p class="app__footer-line">HTML generated <time datetime="${escapeHtml(iso)}">${escapeHtml(human)}</time></p>` +
|
|
184
|
+
`</footer>`);
|
|
185
|
+
}
|
|
107
186
|
function renderRelatedGithubNavHtml(links) {
|
|
108
187
|
if (links.length === 0)
|
|
109
188
|
return "";
|
|
@@ -114,34 +193,57 @@ function renderRelatedGithubNavHtml(links) {
|
|
|
114
193
|
`</nav>`);
|
|
115
194
|
}
|
|
116
195
|
function renderToolbarDocHubHtml(opts) {
|
|
117
|
-
const parts = [];
|
|
118
|
-
const src = safeExternalHttpUrl(opts.sourceOnGithubUrl);
|
|
119
|
-
const cr = safeExternalHttpUrl(opts.commentrayOnGithubUrl);
|
|
120
196
|
const nav = opts.documentedNavJsonUrl?.trim();
|
|
121
197
|
const hasEmbed = (opts.documentedPairsEmbeddedB64?.trim() ?? "").length > 0;
|
|
122
198
|
const showDocumentedTree = Boolean(nav) || hasEmbed;
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const toolbarDocHubHtml = parts.length > 0
|
|
134
|
-
? `<div class="toolbar-doc-hub">${parts.join('<span class="toolbar-doc-hub__sep" aria-hidden="true"> · </span>')}</div>`
|
|
135
|
-
: "";
|
|
136
|
-
const documentedPanelHtml = showDocumentedTree
|
|
137
|
-
? `<div id="documented-files-panel" class="documented-files-panel" hidden>
|
|
138
|
-
<div class="documented-files-panel__inner">
|
|
139
|
-
<p class="documented-files-panel__hint">Indexed source ↔ commentray pairs (embedded for offline when available). Links open on GitHub.</p>
|
|
199
|
+
const toolbarDocHubHtml = "";
|
|
200
|
+
const navAttr = escapeHtml(nav ?? "");
|
|
201
|
+
const navRailDocumentedHtml = showDocumentedTree
|
|
202
|
+
? `<details class="nav-rail__doc-hub" id="documented-files-hub" data-nav-json-url="${navAttr}">
|
|
203
|
+
<summary class="nav-rail__doc-hub-summary">Comment-rayed files</summary>
|
|
204
|
+
<div class="nav-rail__doc-hub-inner">
|
|
205
|
+
<div class="nav-rail__doc-hub-filter-row">
|
|
206
|
+
<label class="nav-rail__doc-hub-filter-label" for="documented-files-filter">Filter</label>
|
|
207
|
+
<input type="search" id="documented-files-filter" class="nav-rail__doc-hub-filter" placeholder="Filter by path…" autocomplete="off" spellcheck="false" />
|
|
208
|
+
</div>
|
|
140
209
|
<div id="documented-files-tree" class="documented-files-tree" role="tree"></div>
|
|
141
210
|
</div>
|
|
142
|
-
</
|
|
211
|
+
</details>`
|
|
143
212
|
: "";
|
|
144
|
-
return { toolbarDocHubHtml,
|
|
213
|
+
return { toolbarDocHubHtml, navRailDocumentedHtml };
|
|
214
|
+
}
|
|
215
|
+
function renderNavRailContextHtml(filePath, commentrayPath, opts) {
|
|
216
|
+
const fpRaw = (filePath ?? "").trim();
|
|
217
|
+
const crRaw = (commentrayPath ?? "").trim();
|
|
218
|
+
const srcUrl = safeExternalHttpUrl(opts?.sourceOnGithubUrl);
|
|
219
|
+
const crUrl = safeExternalHttpUrl(opts?.commentrayOnGithubUrl);
|
|
220
|
+
const browseForCr = safeToolbarNavigationHref(opts?.commentrayStaticBrowseUrl);
|
|
221
|
+
const srcGh = srcUrl !== null
|
|
222
|
+
? `<a class="nav-rail__pair-gh" id="toolbar-source-github" href="${escapeHtml(srcUrl)}" target="_blank" rel="noopener noreferrer" aria-label="Source file on GitHub" title="Open source on GitHub">${GITHUB_MARK_SVG}</a>`
|
|
223
|
+
: "";
|
|
224
|
+
const crGh = browseForCr !== null
|
|
225
|
+
? `<a class="nav-rail__pair-gh" id="toolbar-commentray-github" href="${escapeHtml(browseForCr)}" rel="noopener" aria-label="Open companion pair in the site viewer" title="Open on site">${GITHUB_MARK_SVG}</a>`
|
|
226
|
+
: crUrl !== null
|
|
227
|
+
? `<a class="nav-rail__pair-gh" id="toolbar-commentray-github" href="${escapeHtml(crUrl)}" target="_blank" rel="noopener noreferrer" aria-label="Companion commentray on GitHub" title="Open companion Markdown on GitHub">${GITHUB_MARK_SVG}</a>`
|
|
228
|
+
: "";
|
|
229
|
+
if (fpRaw.length === 0 && crRaw.length === 0 && srcGh === "" && crGh === "") {
|
|
230
|
+
return "";
|
|
231
|
+
}
|
|
232
|
+
const fp = escapeHtml(fpRaw);
|
|
233
|
+
const cr = escapeHtml(crRaw);
|
|
234
|
+
const fpDisp = fpRaw.length > 0 ? fp : "—";
|
|
235
|
+
const crDisp = crRaw.length > 0 ? cr : "—";
|
|
236
|
+
return `<div class="nav-rail__context nav-rail__context--compact" aria-label="Current documentation pair">
|
|
237
|
+
<span class="nav-rail__pair">
|
|
238
|
+
<span class="nav-rail__pair-lab">Src</span>
|
|
239
|
+
<span class="nav-rail__pair-path" title="${fp}">${fpDisp}</span>${srcGh}
|
|
240
|
+
</span>
|
|
241
|
+
<span class="nav-rail__pair-sep" aria-hidden="true">·</span>
|
|
242
|
+
<span class="nav-rail__pair">
|
|
243
|
+
<span class="nav-rail__pair-lab">Doc</span>
|
|
244
|
+
<span class="nav-rail__pair-path nav-rail__pair-path--secondary" id="nav-rail-doc-path" title="${cr}">${crDisp}</span>${crGh}
|
|
245
|
+
</span>
|
|
246
|
+
</div>`;
|
|
145
247
|
}
|
|
146
248
|
/** IIFE produced by `npm run build -w @commentray/render` (esbuild of `code-browser-client.ts`). */
|
|
147
249
|
function loadCodeBrowserClientBundle() {
|
|
@@ -156,17 +258,328 @@ function loadCodeBrowserClientBundle() {
|
|
|
156
258
|
throw new Error("Missing code-browser-client.bundle.js. Run `npm run build -w @commentray/render` to bundle the browser client.");
|
|
157
259
|
}
|
|
158
260
|
const CODE_BROWSER_STYLES = `
|
|
159
|
-
:root {
|
|
261
|
+
:root {
|
|
262
|
+
color-scheme: light dark;
|
|
263
|
+
--cr-control-h: 32px;
|
|
264
|
+
--cr-control-radius: 8px;
|
|
265
|
+
--cr-icon-inner: 18px;
|
|
266
|
+
--cr-label-caps-fs: 10px;
|
|
267
|
+
--cr-label-caps-track: 0.06em;
|
|
268
|
+
--cr-ui-fs: 12px;
|
|
269
|
+
}
|
|
160
270
|
* { box-sizing: border-box; }
|
|
161
271
|
body { margin: 0; font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif; }
|
|
272
|
+
.skip-link {
|
|
273
|
+
position: absolute;
|
|
274
|
+
left: -9999px;
|
|
275
|
+
top: 0;
|
|
276
|
+
z-index: 10000;
|
|
277
|
+
padding: 8px 16px;
|
|
278
|
+
margin: 0;
|
|
279
|
+
font: inherit;
|
|
280
|
+
font-size: 14px;
|
|
281
|
+
text-decoration: none;
|
|
282
|
+
border-radius: 8px;
|
|
283
|
+
border: 1px solid color-mix(in oklab, CanvasText 25%, Canvas);
|
|
284
|
+
background: Canvas;
|
|
285
|
+
color: CanvasText;
|
|
286
|
+
}
|
|
287
|
+
.skip-link:focus {
|
|
288
|
+
left: 12px;
|
|
289
|
+
top: 8px;
|
|
290
|
+
outline: 2px solid color-mix(in oklab, CanvasText 45%, Canvas);
|
|
291
|
+
outline-offset: 2px;
|
|
292
|
+
}
|
|
293
|
+
.skip-link:focus:not(:focus-visible) {
|
|
294
|
+
left: -9999px;
|
|
295
|
+
top: 0;
|
|
296
|
+
outline: none;
|
|
297
|
+
}
|
|
298
|
+
.skip-link:focus-visible {
|
|
299
|
+
left: 12px;
|
|
300
|
+
top: 8px;
|
|
301
|
+
outline: 2px solid color-mix(in oklab, CanvasText 45%, Canvas);
|
|
302
|
+
outline-offset: 2px;
|
|
303
|
+
}
|
|
304
|
+
.sr-only {
|
|
305
|
+
position: absolute;
|
|
306
|
+
width: 1px;
|
|
307
|
+
height: 1px;
|
|
308
|
+
padding: 0;
|
|
309
|
+
margin: -1px;
|
|
310
|
+
overflow: hidden;
|
|
311
|
+
clip: rect(0, 0, 0, 0);
|
|
312
|
+
white-space: nowrap;
|
|
313
|
+
border: 0;
|
|
314
|
+
}
|
|
315
|
+
.app {
|
|
316
|
+
display: flex;
|
|
317
|
+
flex-direction: column;
|
|
318
|
+
align-items: stretch;
|
|
319
|
+
height: 100vh;
|
|
320
|
+
width: 100%;
|
|
321
|
+
overflow: hidden;
|
|
322
|
+
}
|
|
323
|
+
.app__chrome {
|
|
324
|
+
flex: 0 0 auto;
|
|
325
|
+
display: flex;
|
|
326
|
+
flex-direction: column;
|
|
327
|
+
gap: 8px;
|
|
328
|
+
padding: 8px 12px 10px;
|
|
329
|
+
border-bottom: 1px solid color-mix(in oklab, CanvasText 15%, Canvas);
|
|
330
|
+
background: color-mix(in oklab, CanvasText 4%, Canvas);
|
|
331
|
+
max-height: min(40vh, 420px);
|
|
332
|
+
min-height: 0;
|
|
333
|
+
overflow: auto;
|
|
334
|
+
}
|
|
335
|
+
.chrome__search-row {
|
|
336
|
+
display: flex;
|
|
337
|
+
flex-direction: row;
|
|
338
|
+
align-items: center;
|
|
339
|
+
gap: 10px;
|
|
340
|
+
flex-wrap: nowrap;
|
|
341
|
+
}
|
|
342
|
+
.chrome__search-row input[type="search"] {
|
|
343
|
+
flex: 1 1 auto;
|
|
344
|
+
min-width: 140px;
|
|
345
|
+
min-height: var(--cr-control-h);
|
|
346
|
+
padding: 0 12px;
|
|
347
|
+
font: inherit;
|
|
348
|
+
font-size: var(--cr-ui-fs);
|
|
349
|
+
line-height: 1.25;
|
|
350
|
+
border-radius: var(--cr-control-radius);
|
|
351
|
+
border: 1px solid color-mix(in oklab, CanvasText 25%, Canvas);
|
|
352
|
+
background: Canvas;
|
|
353
|
+
color: CanvasText;
|
|
354
|
+
}
|
|
355
|
+
.chrome__search-row #search-clear {
|
|
356
|
+
flex: 0 0 auto;
|
|
357
|
+
font: inherit;
|
|
358
|
+
font-size: var(--cr-ui-fs);
|
|
359
|
+
font-weight: 500;
|
|
360
|
+
min-height: var(--cr-control-h);
|
|
361
|
+
padding: 0 16px;
|
|
362
|
+
border-radius: var(--cr-control-radius);
|
|
363
|
+
cursor: pointer;
|
|
364
|
+
border: 1px solid color-mix(in oklab, CanvasText 25%, Canvas);
|
|
365
|
+
background: color-mix(in oklab, CanvasText 6%, Canvas);
|
|
366
|
+
color: CanvasText;
|
|
367
|
+
}
|
|
368
|
+
.chrome__search-row input[type="search"]:focus-visible,
|
|
369
|
+
.chrome__search-row #search-clear:focus-visible {
|
|
370
|
+
outline: 2px solid color-mix(in oklab, CanvasText 45%, Canvas);
|
|
371
|
+
outline-offset: 2px;
|
|
372
|
+
}
|
|
373
|
+
.chrome__search-label {
|
|
374
|
+
flex: 0 0 auto;
|
|
375
|
+
white-space: nowrap;
|
|
376
|
+
}
|
|
377
|
+
.nav-rail__context--compact {
|
|
378
|
+
display: flex;
|
|
379
|
+
flex-direction: row;
|
|
380
|
+
flex-wrap: wrap;
|
|
381
|
+
align-items: center;
|
|
382
|
+
gap: 6px 10px;
|
|
383
|
+
padding: 5px 10px;
|
|
384
|
+
border-radius: var(--cr-control-radius);
|
|
385
|
+
border: 1px solid color-mix(in oklab, CanvasText 14%, Canvas);
|
|
386
|
+
background: Canvas;
|
|
387
|
+
font-size: var(--cr-ui-fs);
|
|
388
|
+
line-height: 1.3;
|
|
389
|
+
}
|
|
390
|
+
.nav-rail__pair {
|
|
391
|
+
display: inline-flex;
|
|
392
|
+
flex-direction: row;
|
|
393
|
+
align-items: center;
|
|
394
|
+
gap: 6px;
|
|
395
|
+
min-width: 0;
|
|
396
|
+
flex: 1 1 140px;
|
|
397
|
+
max-width: min(48%, 100%);
|
|
398
|
+
}
|
|
399
|
+
.nav-rail__pair-lab {
|
|
400
|
+
flex: 0 0 auto;
|
|
401
|
+
font-size: var(--cr-label-caps-fs);
|
|
402
|
+
font-weight: 700;
|
|
403
|
+
letter-spacing: var(--cr-label-caps-track);
|
|
404
|
+
text-transform: uppercase;
|
|
405
|
+
opacity: 0.72;
|
|
406
|
+
}
|
|
407
|
+
.nav-rail__pair-path {
|
|
408
|
+
flex: 1 1 auto;
|
|
409
|
+
min-width: 0;
|
|
410
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
|
|
411
|
+
font-size: var(--cr-ui-fs);
|
|
412
|
+
color: CanvasText;
|
|
413
|
+
overflow: hidden;
|
|
414
|
+
text-overflow: ellipsis;
|
|
415
|
+
white-space: nowrap;
|
|
416
|
+
}
|
|
417
|
+
.nav-rail__pair-path--secondary { opacity: 0.88; }
|
|
418
|
+
.nav-rail__pair-sep {
|
|
419
|
+
flex: 0 0 auto;
|
|
420
|
+
opacity: 0.45;
|
|
421
|
+
user-select: none;
|
|
422
|
+
padding: 0 2px;
|
|
423
|
+
}
|
|
424
|
+
.nav-rail__pair-gh {
|
|
425
|
+
flex: 0 0 auto;
|
|
426
|
+
display: inline-flex;
|
|
427
|
+
align-items: center;
|
|
428
|
+
justify-content: center;
|
|
429
|
+
width: var(--cr-control-h);
|
|
430
|
+
height: var(--cr-control-h);
|
|
431
|
+
border-radius: var(--cr-control-radius);
|
|
432
|
+
border: 1px solid color-mix(in oklab, CanvasText 20%, Canvas);
|
|
433
|
+
background: color-mix(in oklab, CanvasText 5%, Canvas);
|
|
434
|
+
color: CanvasText;
|
|
435
|
+
}
|
|
436
|
+
.nav-rail__pair-gh:hover {
|
|
437
|
+
background: color-mix(in oklab, CanvasText 10%, Canvas);
|
|
438
|
+
}
|
|
439
|
+
.nav-rail__pair-gh:focus-visible {
|
|
440
|
+
outline: 2px solid color-mix(in oklab, CanvasText 45%, Canvas);
|
|
441
|
+
outline-offset: 2px;
|
|
442
|
+
}
|
|
443
|
+
.nav-rail__pair-gh svg {
|
|
444
|
+
width: var(--cr-icon-inner);
|
|
445
|
+
height: var(--cr-icon-inner);
|
|
446
|
+
display: block;
|
|
447
|
+
}
|
|
448
|
+
.toolbar .nav-rail__context--compact {
|
|
449
|
+
border: 0;
|
|
450
|
+
background: transparent;
|
|
451
|
+
padding: 0;
|
|
452
|
+
flex: 1 1 200px;
|
|
453
|
+
min-width: 0;
|
|
454
|
+
max-width: none;
|
|
455
|
+
gap: 6px 10px;
|
|
456
|
+
}
|
|
457
|
+
.toolbar .nav-rail__pair {
|
|
458
|
+
flex: 1 1 auto;
|
|
459
|
+
min-width: 0;
|
|
460
|
+
max-width: min(44vw, 420px);
|
|
461
|
+
}
|
|
462
|
+
.nav-rail__search-label {
|
|
463
|
+
font-size: var(--cr-label-caps-fs);
|
|
464
|
+
font-weight: 700;
|
|
465
|
+
letter-spacing: var(--cr-label-caps-track);
|
|
466
|
+
text-transform: uppercase;
|
|
467
|
+
opacity: 0.78;
|
|
468
|
+
}
|
|
469
|
+
.nav-rail__search-hint {
|
|
470
|
+
margin: 0;
|
|
471
|
+
font-size: 11px;
|
|
472
|
+
line-height: 1.35;
|
|
473
|
+
opacity: 0.78;
|
|
474
|
+
}
|
|
475
|
+
.nav-rail__code {
|
|
476
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
|
|
477
|
+
font-size: 10px;
|
|
478
|
+
}
|
|
479
|
+
.nav-rail__doc-hub {
|
|
480
|
+
position: relative;
|
|
481
|
+
flex: 0 0 auto;
|
|
482
|
+
align-self: center;
|
|
483
|
+
display: block;
|
|
484
|
+
border: 1px solid color-mix(in oklab, CanvasText 16%, Canvas);
|
|
485
|
+
border-radius: var(--cr-control-radius);
|
|
486
|
+
background: Canvas;
|
|
487
|
+
overflow: visible;
|
|
488
|
+
}
|
|
489
|
+
.nav-rail__doc-hub-summary {
|
|
490
|
+
cursor: pointer;
|
|
491
|
+
font-size: var(--cr-ui-fs);
|
|
492
|
+
font-weight: 600;
|
|
493
|
+
padding: 0 12px;
|
|
494
|
+
min-height: var(--cr-control-h);
|
|
495
|
+
display: inline-flex;
|
|
496
|
+
align-items: center;
|
|
497
|
+
box-sizing: border-box;
|
|
498
|
+
list-style: none;
|
|
499
|
+
user-select: none;
|
|
500
|
+
line-height: 1.25;
|
|
501
|
+
}
|
|
502
|
+
.nav-rail__doc-hub-summary::-webkit-details-marker { display: none; }
|
|
503
|
+
.nav-rail__doc-hub-inner {
|
|
504
|
+
position: absolute;
|
|
505
|
+
left: 0;
|
|
506
|
+
top: calc(100% + 4px);
|
|
507
|
+
z-index: 60;
|
|
508
|
+
min-width: min(280px, 78vw);
|
|
509
|
+
max-width: min(440px, 94vw);
|
|
510
|
+
max-height: min(52vh, 400px);
|
|
511
|
+
display: flex;
|
|
512
|
+
flex-direction: column;
|
|
513
|
+
gap: 8px;
|
|
514
|
+
overflow: hidden;
|
|
515
|
+
padding: 8px 10px;
|
|
516
|
+
font-size: 12px;
|
|
517
|
+
border: 1px solid color-mix(in oklab, CanvasText 16%, Canvas);
|
|
518
|
+
border-radius: 8px;
|
|
519
|
+
background: Canvas;
|
|
520
|
+
box-shadow: 0 8px 28px color-mix(in oklab, CanvasText 12%, transparent);
|
|
521
|
+
}
|
|
522
|
+
.nav-rail__doc-hub-filter-row {
|
|
523
|
+
flex: 0 0 auto;
|
|
524
|
+
}
|
|
525
|
+
.nav-rail__doc-hub-filter-label {
|
|
526
|
+
display: block;
|
|
527
|
+
font-size: var(--cr-label-caps-fs);
|
|
528
|
+
font-weight: 700;
|
|
529
|
+
letter-spacing: var(--cr-label-caps-track);
|
|
530
|
+
text-transform: uppercase;
|
|
531
|
+
opacity: 0.78;
|
|
532
|
+
margin-bottom: 4px;
|
|
533
|
+
}
|
|
534
|
+
.nav-rail__doc-hub-filter {
|
|
535
|
+
width: 100%;
|
|
536
|
+
box-sizing: border-box;
|
|
537
|
+
font: inherit;
|
|
538
|
+
font-size: 12px;
|
|
539
|
+
padding: 4px 8px;
|
|
540
|
+
border-radius: 6px;
|
|
541
|
+
border: 1px solid color-mix(in oklab, CanvasText 22%, Canvas);
|
|
542
|
+
background: color-mix(in oklab, CanvasText 4%, Canvas);
|
|
543
|
+
color: CanvasText;
|
|
544
|
+
}
|
|
545
|
+
.nav-rail__doc-hub-filter:focus {
|
|
546
|
+
outline: 2px solid color-mix(in oklab, CanvasText 40%, Canvas);
|
|
547
|
+
outline-offset: 1px;
|
|
548
|
+
}
|
|
549
|
+
.nav-rail__doc-hub-hint {
|
|
550
|
+
margin: 0 0 8px;
|
|
551
|
+
opacity: 0.78;
|
|
552
|
+
line-height: 1.4;
|
|
553
|
+
font-size: 12px;
|
|
554
|
+
}
|
|
555
|
+
.app__main {
|
|
556
|
+
flex: 1 1 auto;
|
|
557
|
+
min-width: 0;
|
|
558
|
+
min-height: 0;
|
|
559
|
+
display: flex;
|
|
560
|
+
flex-direction: column;
|
|
561
|
+
}
|
|
562
|
+
.app__footer {
|
|
563
|
+
flex: 0 0 auto;
|
|
564
|
+
padding: 6px 12px 10px;
|
|
565
|
+
border-top: 1px solid color-mix(in oklab, CanvasText 12%, Canvas);
|
|
566
|
+
background: color-mix(in oklab, CanvasText 3%, Canvas);
|
|
567
|
+
font-size: 11px;
|
|
568
|
+
line-height: 1.4;
|
|
569
|
+
color: color-mix(in oklab, CanvasText 72%, Canvas);
|
|
570
|
+
}
|
|
571
|
+
.app__footer-line { margin: 0; }
|
|
572
|
+
.app__footer time { font-variant-numeric: tabular-nums; }
|
|
162
573
|
.toolbar {
|
|
574
|
+
position: relative;
|
|
163
575
|
display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; padding: 8px 12px;
|
|
164
576
|
border-bottom: 1px solid color-mix(in oklab, CanvasText 18%, Canvas);
|
|
165
|
-
font-size:
|
|
577
|
+
font-size: var(--cr-ui-fs);
|
|
578
|
+
flex: 0 0 auto;
|
|
166
579
|
}
|
|
167
580
|
.toolbar__main {
|
|
168
581
|
display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px;
|
|
169
|
-
flex:
|
|
582
|
+
flex: 0 1 auto;
|
|
170
583
|
min-width: 0;
|
|
171
584
|
}
|
|
172
585
|
.toolbar__end {
|
|
@@ -176,22 +589,49 @@ const CODE_BROWSER_STYLES = `
|
|
|
176
589
|
}
|
|
177
590
|
.toolbar-github {
|
|
178
591
|
display: inline-flex; align-items: center; justify-content: center;
|
|
179
|
-
width:
|
|
592
|
+
width: var(--cr-control-h);
|
|
593
|
+
height: var(--cr-control-h);
|
|
594
|
+
border-radius: var(--cr-control-radius);
|
|
180
595
|
border: 1px solid color-mix(in oklab, CanvasText 22%, Canvas);
|
|
181
596
|
background: color-mix(in oklab, CanvasText 6%, Canvas);
|
|
182
597
|
color: CanvasText;
|
|
183
598
|
}
|
|
599
|
+
.toolbar-github svg {
|
|
600
|
+
width: var(--cr-icon-inner);
|
|
601
|
+
height: var(--cr-icon-inner);
|
|
602
|
+
display: block;
|
|
603
|
+
}
|
|
184
604
|
.toolbar-github:hover { background: color-mix(in oklab, CanvasText 11%, Canvas); }
|
|
185
605
|
.toolbar-github:focus-visible { outline: 2px solid color-mix(in oklab, CanvasText 45%, Canvas); outline-offset: 2px; }
|
|
186
606
|
.toolbar-attribution {
|
|
187
|
-
font-size:
|
|
188
|
-
|
|
607
|
+
font-size: var(--cr-ui-fs);
|
|
608
|
+
line-height: 1.35;
|
|
609
|
+
opacity: 0.85;
|
|
610
|
+
max-width: min(360px, 42vw);
|
|
611
|
+
text-align: right;
|
|
612
|
+
color: color-mix(in oklab, CanvasText 88%, Canvas);
|
|
189
613
|
}
|
|
190
614
|
.toolbar-attribution a { color: inherit; font-weight: 600; text-decoration: underline; text-underline-offset: 2px; }
|
|
191
615
|
.toolbar label { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; user-select: none; }
|
|
616
|
+
.toolbar__main > label:has(#wrap-lines) {
|
|
617
|
+
margin: 0;
|
|
618
|
+
min-height: var(--cr-control-h);
|
|
619
|
+
padding: 0 12px 0 10px;
|
|
620
|
+
border-radius: var(--cr-control-radius);
|
|
621
|
+
border: 1px solid color-mix(in oklab, CanvasText 16%, Canvas);
|
|
622
|
+
background: color-mix(in oklab, CanvasText 4%, Canvas);
|
|
623
|
+
font-size: var(--cr-ui-fs);
|
|
624
|
+
font-weight: 500;
|
|
625
|
+
gap: 8px;
|
|
626
|
+
}
|
|
627
|
+
.toolbar label input:focus-visible {
|
|
628
|
+
outline: 2px solid color-mix(in oklab, CanvasText 45%, Canvas);
|
|
629
|
+
outline-offset: 2px;
|
|
630
|
+
}
|
|
192
631
|
.toolbar .file-path {
|
|
193
632
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
|
|
194
|
-
font-size:
|
|
633
|
+
font-size: var(--cr-ui-fs);
|
|
634
|
+
font-weight: 500;
|
|
195
635
|
display: inline-flex; align-items: baseline; gap: 0; margin-right: 4px;
|
|
196
636
|
max-width: 60vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
197
637
|
}
|
|
@@ -205,7 +645,9 @@ const CODE_BROWSER_STYLES = `
|
|
|
205
645
|
.toolbar .file-path--title { font-weight: 600; }
|
|
206
646
|
.toolbar-related {
|
|
207
647
|
display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: 6px 10px;
|
|
208
|
-
max-width: min(520px, 90vw);
|
|
648
|
+
max-width: min(520px, 90vw);
|
|
649
|
+
font-size: var(--cr-ui-fs);
|
|
650
|
+
line-height: 1.35;
|
|
209
651
|
color: color-mix(in oklab, CanvasText 88%, Canvas);
|
|
210
652
|
}
|
|
211
653
|
.toolbar-related__prefix { font-weight: 600; opacity: 0.85; white-space: nowrap; }
|
|
@@ -215,69 +657,82 @@ const CODE_BROWSER_STYLES = `
|
|
|
215
657
|
word-break: break-word;
|
|
216
658
|
}
|
|
217
659
|
.toolbar-related__sep { opacity: 0.55; user-select: none; }
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
}
|
|
223
|
-
.toolbar-doc-hub__sep { opacity: 0.45; user-select: none; }
|
|
224
|
-
.toolbar-blob-link {
|
|
225
|
-
color: inherit; font-weight: 500; text-decoration: underline; text-underline-offset: 2px;
|
|
226
|
-
white-space: nowrap;
|
|
660
|
+
#documented-files-tree {
|
|
661
|
+
flex: 1 1 auto;
|
|
662
|
+
min-height: 0;
|
|
663
|
+
overflow: auto;
|
|
227
664
|
}
|
|
228
|
-
.
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
665
|
+
.documented-files-tree ul { list-style: none; margin: 0; padding-left: 12px; }
|
|
666
|
+
.documented-files-tree > ul { padding-left: 0; }
|
|
667
|
+
.documented-files-tree li { margin: 2px 0; line-height: 1.35; }
|
|
668
|
+
.documented-files-tree .tree-dir { font-weight: 600; margin-top: 4px; font-size: 12px; }
|
|
669
|
+
.documented-files-tree .tree-file {
|
|
670
|
+
margin: 3px 0;
|
|
671
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
|
|
672
|
+
font-size: 11px;
|
|
232
673
|
}
|
|
233
|
-
.
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
674
|
+
.documented-files-tree .tree-file-link {
|
|
675
|
+
color: inherit;
|
|
676
|
+
font-weight: 500;
|
|
677
|
+
text-decoration: underline;
|
|
678
|
+
text-underline-offset: 2px;
|
|
679
|
+
word-break: break-word;
|
|
238
680
|
}
|
|
239
|
-
.documented-files-
|
|
240
|
-
|
|
241
|
-
.documented-files-panel__code { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace; font-size: 12px; }
|
|
242
|
-
.documented-files-tree ul { list-style: none; margin: 0; padding-left: 14px; }
|
|
243
|
-
.documented-files-tree > ul { padding-left: 0; }
|
|
244
|
-
.documented-files-tree li { margin: 2px 0; line-height: 1.4; }
|
|
245
|
-
.documented-files-tree .tree-dir { font-weight: 600; margin-top: 6px; }
|
|
246
|
-
.documented-files-tree .tree-file { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 10px; margin: 4px 0; }
|
|
247
|
-
.documented-files-tree .tree-file-name { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace; font-size: 12px; }
|
|
248
|
-
.documented-files-tree .tree-file-links { display: inline-flex; flex-wrap: wrap; gap: 6px 10px; font-size: 11px; }
|
|
249
|
-
.documented-files-tree .tree-file-links a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
|
|
250
|
-
.toolbar .search-field {
|
|
251
|
-
display: inline-flex; align-items: center; gap: 6px; flex: 1 1 220px; min-width: 160px;
|
|
252
|
-
}
|
|
253
|
-
.toolbar .search-field input[type="search"] {
|
|
254
|
-
flex: 1; min-width: 0; padding: 4px 8px; font: inherit; border-radius: 6px;
|
|
255
|
-
border: 1px solid color-mix(in oklab, CanvasText 25%, Canvas); background: Canvas;
|
|
256
|
-
color: CanvasText;
|
|
681
|
+
.documented-files-tree .tree-file-link:hover {
|
|
682
|
+
opacity: 0.92;
|
|
257
683
|
}
|
|
258
684
|
.toolbar button {
|
|
259
|
-
font: inherit;
|
|
260
|
-
|
|
685
|
+
font: inherit;
|
|
686
|
+
font-size: var(--cr-ui-fs);
|
|
687
|
+
font-weight: 500;
|
|
688
|
+
min-height: var(--cr-control-h);
|
|
689
|
+
padding: 0 12px;
|
|
690
|
+
border-radius: var(--cr-control-radius);
|
|
691
|
+
cursor: pointer;
|
|
692
|
+
border: 1px solid color-mix(in oklab, CanvasText 25%, Canvas);
|
|
693
|
+
background: color-mix(in oklab, CanvasText 6%, Canvas);
|
|
261
694
|
color: CanvasText;
|
|
262
695
|
}
|
|
263
696
|
.search-results {
|
|
264
|
-
flex: 0
|
|
265
|
-
|
|
266
|
-
|
|
697
|
+
flex: 0 1 auto;
|
|
698
|
+
min-height: 0;
|
|
699
|
+
max-height: min(320px, 38vh);
|
|
700
|
+
overflow: auto;
|
|
701
|
+
padding: 8px 8px 10px;
|
|
702
|
+
border-radius: 8px;
|
|
703
|
+
border: 1px solid color-mix(in oklab, CanvasText 12%, Canvas);
|
|
704
|
+
background: Canvas;
|
|
705
|
+
font-size: 13px;
|
|
267
706
|
}
|
|
268
707
|
.search-results[hidden] { display: none !important; }
|
|
269
|
-
.search-results .hint { opacity: 0.75; margin-bottom:
|
|
708
|
+
.search-results .hint { opacity: 0.75; margin-bottom: 8px; line-height: 1.45; }
|
|
270
709
|
.search-results button.hit {
|
|
271
|
-
display: block; width: 100%; text-align: left; margin:
|
|
710
|
+
display: block; width: 100%; text-align: left; margin: 4px 0; padding: 8px 10px;
|
|
272
711
|
border-radius: 6px; border: 1px solid color-mix(in oklab, CanvasText 14%, Canvas);
|
|
273
712
|
background: color-mix(in oklab, CanvasText 5%, Canvas); color: CanvasText; cursor: pointer;
|
|
274
713
|
font: inherit;
|
|
275
714
|
}
|
|
276
715
|
.search-results button.hit:hover { background: color-mix(in oklab, CanvasText 10%, Canvas); }
|
|
277
|
-
.search-results button.hit .meta { opacity: 0.8; font-size:
|
|
278
|
-
.search-results button.hit .src-tag { opacity: 0.75; font-weight: 500; font-size:
|
|
279
|
-
.search-results button.hit .snippet {
|
|
716
|
+
.search-results button.hit .meta { opacity: 0.8; font-size: 12px; }
|
|
717
|
+
.search-results button.hit .src-tag { opacity: 0.75; font-weight: 500; font-size: 11px; }
|
|
718
|
+
.search-results button.hit .snippet {
|
|
719
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace; font-size: 13px;
|
|
720
|
+
line-height: 1.45; white-space: pre-wrap; word-break: break-word; margin-top: 4px;
|
|
721
|
+
}
|
|
722
|
+
.search-results mark.search-hit {
|
|
723
|
+
padding: 0 2px; border-radius: 3px; font: inherit;
|
|
724
|
+
background: color-mix(in oklab, #f5a623 70%, Canvas);
|
|
725
|
+
color: CanvasText;
|
|
726
|
+
box-decoration-break: clone;
|
|
727
|
+
-webkit-box-decoration-break: clone;
|
|
728
|
+
}
|
|
729
|
+
@media (prefers-color-scheme: dark) {
|
|
730
|
+
.search-results mark.search-hit {
|
|
731
|
+
background: color-mix(in oklab, #c9a227 55%, Canvas);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
280
734
|
.shell { display: flex; flex-direction: row; flex: 1; min-height: 0; }
|
|
735
|
+
.app__main .shell { flex: 1 1 auto; }
|
|
281
736
|
.pane--code {
|
|
282
737
|
flex: 0 0 50%;
|
|
283
738
|
min-width: 120px; overflow: auto; padding: 12px 16px;
|
|
@@ -285,12 +740,12 @@ const CODE_BROWSER_STYLES = `
|
|
|
285
740
|
--code-line-font-size: 13px;
|
|
286
741
|
--code-line-height: 1.5;
|
|
287
742
|
}
|
|
743
|
+
.pane--code .code-line-stack { --code-ln-min-ch: 3; }
|
|
288
744
|
.pane--code .code-line {
|
|
289
745
|
display: grid;
|
|
290
|
-
/* max-content: column wide enough for the longest line number (avoids 100+ bleeding into code). */
|
|
291
746
|
grid-template-columns: max-content 1fr;
|
|
292
|
-
column-gap:
|
|
293
|
-
align-items:
|
|
747
|
+
column-gap: 10px;
|
|
748
|
+
align-items: start;
|
|
294
749
|
}
|
|
295
750
|
.pane--code .code-line pre {
|
|
296
751
|
margin: 0;
|
|
@@ -316,6 +771,8 @@ const CODE_BROWSER_STYLES = `
|
|
|
316
771
|
white-space: nowrap;
|
|
317
772
|
font-size: var(--code-line-font-size);
|
|
318
773
|
line-height: var(--code-line-height);
|
|
774
|
+
min-width: calc(var(--code-ln-min-ch, 3) * 1ch + 0.6ch);
|
|
775
|
+
box-sizing: content-box;
|
|
319
776
|
}
|
|
320
777
|
.pane--code .code-line:target .ln,
|
|
321
778
|
.pane--code .code-line:hover .ln {
|
|
@@ -328,18 +785,78 @@ const CODE_BROWSER_STYLES = `
|
|
|
328
785
|
white-space: pre;
|
|
329
786
|
}
|
|
330
787
|
.gutter {
|
|
331
|
-
flex: 0 0
|
|
788
|
+
flex: 0 0 14px; cursor: col-resize; background: color-mix(in oklab, CanvasText 12%, Canvas);
|
|
332
789
|
position: relative;
|
|
790
|
+
--commentray-ray-accent: #3b7dd8;
|
|
791
|
+
}
|
|
792
|
+
@media (prefers-color-scheme: dark) {
|
|
793
|
+
.gutter { --commentray-ray-accent: #6eb0ff; }
|
|
794
|
+
}
|
|
795
|
+
.gutter__rays {
|
|
796
|
+
position: absolute; inset: 0; pointer-events: none; z-index: 1;
|
|
797
|
+
}
|
|
798
|
+
.gutter__rays svg { width: 100%; height: 100%; display: block; overflow: visible; }
|
|
799
|
+
.gutter__rays-path {
|
|
800
|
+
fill: none; stroke-linecap: round; vector-effect: non-scaling-stroke;
|
|
801
|
+
stroke: color-mix(in oklab, var(--commentray-ray-accent) 72%, CanvasText);
|
|
802
|
+
stroke-width: 1.35px; opacity: 0.26;
|
|
803
|
+
}
|
|
804
|
+
.gutter__rays-path--active {
|
|
805
|
+
stroke-width: 2.4px; opacity: 0.88;
|
|
806
|
+
}
|
|
807
|
+
.gutter__rays-path--trail {
|
|
808
|
+
stroke-dasharray: 3 4; opacity: 0.42;
|
|
809
|
+
}
|
|
810
|
+
.gutter__rays-path--active.gutter__rays-path--trail {
|
|
811
|
+
opacity: 0.72;
|
|
333
812
|
}
|
|
334
813
|
.gutter:hover { background: color-mix(in oklab, CanvasText 22%, Canvas); }
|
|
335
814
|
.gutter::after {
|
|
336
815
|
content: ""; position: absolute; top: 0; bottom: 0; left: -4px; right: -4px;
|
|
337
816
|
}
|
|
338
817
|
.pane--doc {
|
|
339
|
-
flex: 1 1 auto; min-width:
|
|
818
|
+
flex: 1 1 auto; min-width: 0; min-height: 0;
|
|
819
|
+
display: flex; flex-direction: column; overflow: hidden; padding: 12px 16px;
|
|
820
|
+
}
|
|
821
|
+
.doc-pane-body {
|
|
822
|
+
flex: 1 1 auto; min-height: 0; overflow: auto;
|
|
823
|
+
}
|
|
824
|
+
.toolbar-angle-picker {
|
|
825
|
+
display: inline-flex;
|
|
826
|
+
align-items: center;
|
|
827
|
+
gap: 8px;
|
|
828
|
+
flex: 0 0 auto;
|
|
829
|
+
color: color-mix(in oklab, CanvasText 88%, Canvas);
|
|
830
|
+
}
|
|
831
|
+
.toolbar-angle-picker > label {
|
|
832
|
+
font-size: var(--cr-label-caps-fs);
|
|
833
|
+
font-weight: 700;
|
|
834
|
+
letter-spacing: var(--cr-label-caps-track);
|
|
835
|
+
text-transform: uppercase;
|
|
836
|
+
opacity: 0.72;
|
|
837
|
+
}
|
|
838
|
+
.toolbar-angle-picker select {
|
|
839
|
+
font: inherit;
|
|
840
|
+
font-size: var(--cr-ui-fs);
|
|
841
|
+
min-height: var(--cr-control-h);
|
|
842
|
+
height: var(--cr-control-h);
|
|
843
|
+
padding: 0 10px;
|
|
844
|
+
border-radius: var(--cr-control-radius);
|
|
845
|
+
border: 1px solid color-mix(in oklab, CanvasText 25%, Canvas);
|
|
846
|
+
background: Canvas;
|
|
847
|
+
color: CanvasText;
|
|
848
|
+
}
|
|
849
|
+
.toolbar-angle-picker select:focus-visible {
|
|
850
|
+
outline: 2px solid color-mix(in oklab, CanvasText 45%, Canvas);
|
|
851
|
+
outline-offset: 2px;
|
|
340
852
|
}
|
|
341
853
|
.pane--doc { font-size: 15px; line-height: 1.45; }
|
|
342
854
|
.pane--doc img { max-width: 100%; height: auto; }
|
|
855
|
+
.pane--doc .commentray-line-anchor {
|
|
856
|
+
display: inline;
|
|
857
|
+
vertical-align: baseline;
|
|
858
|
+
scroll-margin-top: 10px;
|
|
859
|
+
}
|
|
343
860
|
.pane--doc .commentray-block-anchor {
|
|
344
861
|
display: block;
|
|
345
862
|
height: 0;
|
|
@@ -348,8 +865,6 @@ const CODE_BROWSER_STYLES = `
|
|
|
348
865
|
border-top: 1px solid color-mix(in oklab, CanvasText 22%, Canvas);
|
|
349
866
|
pointer-events: none;
|
|
350
867
|
}
|
|
351
|
-
.pane h2.pane-title { margin: 0 0 10px; font-size: 12px; letter-spacing: 0.06em; text-transform: uppercase; opacity: 0.75; }
|
|
352
|
-
.app { display: flex; flex-direction: column; height: 100vh; }
|
|
353
868
|
.shell--stretch-rows {
|
|
354
869
|
flex: 1;
|
|
355
870
|
min-height: 0;
|
|
@@ -413,6 +928,7 @@ const CODE_BROWSER_STYLES = `
|
|
|
413
928
|
font-size: var(--code-line-font-size, 13px);
|
|
414
929
|
line-height: var(--code-line-height, 1.5);
|
|
415
930
|
}
|
|
931
|
+
.block-stretch .code-line-stack { --code-ln-min-ch: 3; }
|
|
416
932
|
.block-stretch .code-line .ln {
|
|
417
933
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
|
|
418
934
|
font-variant-numeric: tabular-nums;
|
|
@@ -425,20 +941,16 @@ const CODE_BROWSER_STYLES = `
|
|
|
425
941
|
white-space: nowrap;
|
|
426
942
|
font-size: var(--code-line-font-size, 13px);
|
|
427
943
|
line-height: var(--code-line-height, 1.5);
|
|
944
|
+
min-width: calc(var(--code-ln-min-ch, 3) * 1ch + 0.6ch);
|
|
945
|
+
box-sizing: content-box;
|
|
428
946
|
}
|
|
429
947
|
.block-stretch.wrap .code-line pre,
|
|
430
948
|
.block-stretch.wrap .code-line pre code { white-space: pre-wrap; word-break: break-word; }
|
|
431
949
|
.block-stretch:not(.wrap) .code-line pre,
|
|
432
950
|
.block-stretch:not(.wrap) .code-line pre code { white-space: pre; }
|
|
433
|
-
.block-stretch-headings {
|
|
434
|
-
display: grid;
|
|
435
|
-
grid-template-columns: 1fr 1fr;
|
|
436
|
-
gap: 0 16px;
|
|
437
|
-
padding: 4px 12px 8px;
|
|
438
|
-
border-bottom: 1px solid color-mix(in oklab, CanvasText 10%, Canvas);
|
|
439
|
-
}
|
|
440
|
-
.block-stretch-headings .pane-title { margin: 0; }
|
|
441
951
|
`;
|
|
952
|
+
/** Native tooltip on #search-q (short hint is visible under the search row). */
|
|
953
|
+
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).";
|
|
442
954
|
function buildCodeBrowserPageHtml(p) {
|
|
443
955
|
const shellClass = p.layout === "stretch" ? "shell shell--stretch-rows" : "shell";
|
|
444
956
|
return `<!doctype html>
|
|
@@ -446,7 +958,7 @@ function buildCodeBrowserPageHtml(p) {
|
|
|
446
958
|
<head>
|
|
447
959
|
<meta charset="utf-8" />
|
|
448
960
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
449
|
-
${p.generatorMetaHtml}<title>${escapeHtml(p.title)}</title>
|
|
961
|
+
${p.metaDescriptionHtml}${p.generatorMetaHtml}<title>${escapeHtml(p.title)}</title>
|
|
450
962
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.11.1/build/styles/${escapeHtml(p.hljs)}.min.css" media="(prefers-color-scheme: light)" />
|
|
451
963
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.11.1/build/styles/${escapeHtml(p.hljsDark)}.min.css" media="(prefers-color-scheme: dark)" />
|
|
452
964
|
<style>
|
|
@@ -454,27 +966,38 @@ ${CODE_BROWSER_STYLES}
|
|
|
454
966
|
</style>
|
|
455
967
|
</head>
|
|
456
968
|
<body>
|
|
969
|
+
<a class="skip-link" href="#main-content">Skip to main content</a>
|
|
457
970
|
<div class="app">
|
|
458
|
-
<header class="toolbar" aria-label="View options">
|
|
971
|
+
<header class="toolbar" role="banner" aria-label="View options">
|
|
972
|
+
<h1 class="sr-only">${escapeHtml(p.title)}</h1>
|
|
459
973
|
<div class="toolbar__main">
|
|
460
|
-
${p.
|
|
974
|
+
${p.toolbarSiteHubHtml}
|
|
975
|
+
${p.navRailContextHtml}
|
|
976
|
+
${p.navRailDocumentedHtml}
|
|
977
|
+
${p.angleSelectHtml}
|
|
461
978
|
${p.toolbarDocHubHtml}
|
|
462
|
-
<span class="search-field">
|
|
463
|
-
<label for="search-q">Search</label>
|
|
464
|
-
<input type="search" id="search-q" placeholder="${escapeHtml(p.searchPlaceholder)}" autocomplete="off" spellcheck="false" />
|
|
465
|
-
<button type="button" id="search-clear" title="Clear search">Clear</button>
|
|
466
|
-
</span>
|
|
467
979
|
${p.relatedNavHtml}
|
|
468
980
|
<label><input type="checkbox" id="wrap-lines" /> Wrap code lines</label>
|
|
469
981
|
</div>
|
|
470
982
|
${p.toolbarEndHtml}
|
|
471
983
|
</header>
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
984
|
+
<header class="app__chrome" role="region" aria-label="Search">
|
|
985
|
+
<div class="chrome__search-row">
|
|
986
|
+
<label class="chrome__search-label nav-rail__search-label" for="search-q">Search</label>
|
|
987
|
+
<input type="search" id="search-q" placeholder="${escapeHtml(p.searchPlaceholder)}" title="${escapeHtml(CODE_BROWSER_SEARCH_INPUT_TITLE)}" autocomplete="off" spellcheck="false" />
|
|
988
|
+
<button type="button" id="search-clear" title="Clear search">Clear</button>
|
|
989
|
+
</div>
|
|
990
|
+
<div class="search-results" id="search-results" hidden aria-live="polite"></div>
|
|
991
|
+
<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>
|
|
992
|
+
</header>
|
|
993
|
+
<main id="main-content" class="app__main" tabindex="-1">
|
|
994
|
+
<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}>
|
|
475
995
|
${p.shellInner}
|
|
476
|
-
|
|
996
|
+
</div>
|
|
997
|
+
</main>
|
|
998
|
+
${p.pageFooterHtml}
|
|
477
999
|
</div>
|
|
1000
|
+
<script type="text/plain" id="commentray-multi-angle-b64">${p.multiAngleScriptBlock}</script>
|
|
478
1001
|
<script>
|
|
479
1002
|
${loadCodeBrowserClientBundle()}
|
|
480
1003
|
</script>
|
|
@@ -482,10 +1005,108 @@ ${loadCodeBrowserClientBundle()}
|
|
|
482
1005
|
</body>
|
|
483
1006
|
</html>`;
|
|
484
1007
|
}
|
|
1008
|
+
async function multiAngleJsonRowAndDocHtml(opts, spec) {
|
|
1009
|
+
const rows = spec.blockStretchRows;
|
|
1010
|
+
const links = rows !== undefined
|
|
1011
|
+
? buildBlockScrollLinks(rows.index, rows.sourceRelative, rows.commentrayPathRel, spec.markdown, opts.code)
|
|
1012
|
+
: [];
|
|
1013
|
+
const mdForDoc = injectCommentrayDocAnchors(spec.markdown, links.length > 0 ? links : undefined);
|
|
1014
|
+
const scrollB64 = links.length > 0 ? Buffer.from(JSON.stringify(links), "utf8").toString("base64") : "";
|
|
1015
|
+
const commentrayHtml = await renderMarkdownToHtml(mdForDoc, {
|
|
1016
|
+
commentrayOutputUrls: opts.commentrayOutputUrls,
|
|
1017
|
+
});
|
|
1018
|
+
return {
|
|
1019
|
+
jsonRow: {
|
|
1020
|
+
id: spec.id,
|
|
1021
|
+
title: spec.title?.trim() || spec.id,
|
|
1022
|
+
docInnerHtmlB64: Buffer.from(commentrayHtml, "utf8").toString("base64"),
|
|
1023
|
+
rawMdB64: Buffer.from(spec.markdown, "utf8").toString("base64"),
|
|
1024
|
+
scrollBlockLinksB64: scrollB64,
|
|
1025
|
+
commentrayPathForSearch: spec.commentrayPathRel.trim(),
|
|
1026
|
+
commentrayOnGithubUrl: spec.commentrayOnGithubUrl,
|
|
1027
|
+
staticBrowseUrl: spec.staticBrowseUrl,
|
|
1028
|
+
},
|
|
1029
|
+
commentrayHtml,
|
|
1030
|
+
scrollB64,
|
|
1031
|
+
};
|
|
1032
|
+
}
|
|
1033
|
+
async function buildMultiAngleDualPaneShell(opts, multi) {
|
|
1034
|
+
const defaultId = multi.angles.some((a) => a.id === multi.defaultAngleId)
|
|
1035
|
+
? multi.defaultAngleId
|
|
1036
|
+
: (multi.angles[0]?.id ?? "main");
|
|
1037
|
+
const jsonAngles = [];
|
|
1038
|
+
let defaultMarkdown = opts.commentrayMarkdown;
|
|
1039
|
+
let defaultScrollB64 = "";
|
|
1040
|
+
let defaultPathSearch = (opts.commentrayPathForSearch ?? "").trim();
|
|
1041
|
+
let defaultGh = opts.commentrayOnGithubUrl;
|
|
1042
|
+
let defaultStaticBrowse = (opts.commentrayStaticBrowseUrl ?? "").trim();
|
|
1043
|
+
let defaultPaneHtml = "";
|
|
1044
|
+
const codeHtml = await renderHighlightedCodeLineRows(opts.code, opts.language);
|
|
1045
|
+
for (const spec of multi.angles) {
|
|
1046
|
+
const { jsonRow, commentrayHtml, scrollB64 } = await multiAngleJsonRowAndDocHtml(opts, spec);
|
|
1047
|
+
if (spec.id === defaultId) {
|
|
1048
|
+
defaultMarkdown = spec.markdown;
|
|
1049
|
+
defaultScrollB64 = scrollB64;
|
|
1050
|
+
defaultPathSearch = spec.commentrayPathRel.trim();
|
|
1051
|
+
defaultGh = spec.commentrayOnGithubUrl;
|
|
1052
|
+
{
|
|
1053
|
+
const sb = (spec.staticBrowseUrl ?? "").trim();
|
|
1054
|
+
if (sb.length > 0)
|
|
1055
|
+
defaultStaticBrowse = sb;
|
|
1056
|
+
}
|
|
1057
|
+
defaultPaneHtml = commentrayHtml;
|
|
1058
|
+
}
|
|
1059
|
+
jsonAngles.push(jsonRow);
|
|
1060
|
+
}
|
|
1061
|
+
const selOpts = multi.angles
|
|
1062
|
+
.map((a) => {
|
|
1063
|
+
const lab = escapeHtml(a.title?.trim() || a.id);
|
|
1064
|
+
return `<option value="${escapeHtml(a.id)}"${a.id === defaultId ? " selected" : ""}>${lab}</option>`;
|
|
1065
|
+
})
|
|
1066
|
+
.join("");
|
|
1067
|
+
const angleSelectHtml = `<span class="toolbar-angle-picker"><label for="angle-select">Angle</label><select id="angle-select" aria-label="Commentray angle">${selOpts}</select></span>`;
|
|
1068
|
+
const shellInner = ` <section class="pane--code" id="code-pane" aria-label="Source code">` +
|
|
1069
|
+
` ${codeHtml}\n` +
|
|
1070
|
+
` </section>\n` +
|
|
1071
|
+
` <div class="gutter" id="gutter" role="separator" aria-orientation="vertical" aria-label="Resize panes"></div>\n` +
|
|
1072
|
+
` <section class="pane--doc commentray" id="doc-pane" aria-label="Commentray">\n` +
|
|
1073
|
+
` <div id="doc-pane-body" class="doc-pane-body">\n` +
|
|
1074
|
+
` ${defaultPaneHtml}\n` +
|
|
1075
|
+
` </div>\n` +
|
|
1076
|
+
` </section>\n`;
|
|
1077
|
+
const payloadObj = { defaultAngleId: defaultId, angles: jsonAngles };
|
|
1078
|
+
const multiAnglePayloadB64 = Buffer.from(JSON.stringify(payloadObj), "utf8").toString("base64");
|
|
1079
|
+
return {
|
|
1080
|
+
shellInner,
|
|
1081
|
+
multiShell: {
|
|
1082
|
+
rawMdB64: Buffer.from(defaultMarkdown, "utf8").toString("base64"),
|
|
1083
|
+
scrollBlockLinksB64: defaultScrollB64,
|
|
1084
|
+
commentrayPathForSearch: defaultPathSearch,
|
|
1085
|
+
commentrayOnGithubUrl: defaultGh,
|
|
1086
|
+
...(defaultStaticBrowse.length > 0 ? { commentrayStaticBrowseUrl: defaultStaticBrowse } : {}),
|
|
1087
|
+
},
|
|
1088
|
+
angleSelectHtml,
|
|
1089
|
+
multiAnglePayloadB64,
|
|
1090
|
+
};
|
|
1091
|
+
}
|
|
485
1092
|
async function buildCodeBrowserShell(opts, layoutPref) {
|
|
486
1093
|
let layout = "dual";
|
|
487
1094
|
let shellInner = "";
|
|
488
1095
|
let scrollBlockLinksB64 = "";
|
|
1096
|
+
const multi = opts.multiAngleBrowsing;
|
|
1097
|
+
const multiActive = Boolean(multi && multi.angles.length >= 2);
|
|
1098
|
+
if (multiActive && multi) {
|
|
1099
|
+
const built = await buildMultiAngleDualPaneShell(opts, multi);
|
|
1100
|
+
const ms = built.multiShell;
|
|
1101
|
+
return {
|
|
1102
|
+
layout: "dual",
|
|
1103
|
+
shellInner: built.shellInner,
|
|
1104
|
+
scrollBlockLinksB64: ms.scrollBlockLinksB64,
|
|
1105
|
+
angleSelectHtml: built.angleSelectHtml,
|
|
1106
|
+
multiAnglePayloadB64: built.multiAnglePayloadB64,
|
|
1107
|
+
multiShell: ms,
|
|
1108
|
+
};
|
|
1109
|
+
}
|
|
489
1110
|
if (opts.blockStretchRows && layoutPref !== "dual") {
|
|
490
1111
|
const stretched = await tryBuildBlockStretchTableHtml({
|
|
491
1112
|
code: opts.code,
|
|
@@ -498,51 +1119,52 @@ async function buildCodeBrowserShell(opts, layoutPref) {
|
|
|
498
1119
|
});
|
|
499
1120
|
if (stretched) {
|
|
500
1121
|
layout = "stretch";
|
|
501
|
-
shellInner =
|
|
502
|
-
` <div class="block-stretch-headings">` +
|
|
503
|
-
`<h2 class="pane-title">Code</h2>` +
|
|
504
|
-
`<h2 class="pane-title">Commentray</h2>` +
|
|
505
|
-
`</div>\n` +
|
|
506
|
-
` ${stretched.preambleHtml}\n` +
|
|
507
|
-
` ${stretched.tableInnerHtml}\n`;
|
|
1122
|
+
shellInner = ` ${stretched.preambleHtml}\n` + ` ${stretched.tableInnerHtml}\n`;
|
|
508
1123
|
}
|
|
509
1124
|
}
|
|
510
1125
|
if (layout === "dual") {
|
|
511
1126
|
const links = opts.blockStretchRows !== undefined
|
|
512
1127
|
? buildBlockScrollLinks(opts.blockStretchRows.index, opts.blockStretchRows.sourceRelative, opts.blockStretchRows.commentrayPathRel, opts.commentrayMarkdown, opts.code)
|
|
513
1128
|
: [];
|
|
514
|
-
const mdForDoc =
|
|
1129
|
+
const mdForDoc = injectCommentrayDocAnchors(opts.commentrayMarkdown, links.length > 0 ? links : undefined);
|
|
515
1130
|
if (links.length > 0) {
|
|
516
1131
|
scrollBlockLinksB64 = Buffer.from(JSON.stringify(links), "utf8").toString("base64");
|
|
517
1132
|
}
|
|
518
1133
|
const [codeHtml, commentrayHtml] = await Promise.all([
|
|
519
|
-
|
|
1134
|
+
renderHighlightedCodeLineRows(opts.code, opts.language),
|
|
520
1135
|
renderMarkdownToHtml(mdForDoc, {
|
|
521
1136
|
commentrayOutputUrls: opts.commentrayOutputUrls,
|
|
522
1137
|
}),
|
|
523
1138
|
]);
|
|
524
1139
|
shellInner =
|
|
525
1140
|
` <section class="pane--code" id="code-pane" aria-label="Source code">` +
|
|
526
|
-
`<h2 class="pane-title">Code</h2>\n` +
|
|
527
1141
|
` ${codeHtml}\n` +
|
|
528
1142
|
` </section>\n` +
|
|
529
1143
|
` <div class="gutter" id="gutter" role="separator" aria-orientation="vertical" aria-label="Resize panes"></div>\n` +
|
|
530
1144
|
` <section class="pane--doc commentray" id="doc-pane" aria-label="Commentray">\n` +
|
|
531
|
-
` <
|
|
1145
|
+
` <div id="doc-pane-body" class="doc-pane-body">\n` +
|
|
532
1146
|
` ${commentrayHtml}\n` +
|
|
1147
|
+
` </div>\n` +
|
|
533
1148
|
` </section>\n`;
|
|
534
1149
|
}
|
|
535
|
-
return {
|
|
1150
|
+
return {
|
|
1151
|
+
layout,
|
|
1152
|
+
shellInner,
|
|
1153
|
+
scrollBlockLinksB64,
|
|
1154
|
+
angleSelectHtml: "",
|
|
1155
|
+
multiAnglePayloadB64: "",
|
|
1156
|
+
};
|
|
536
1157
|
}
|
|
537
|
-
function searchChromeFromOptions(opts) {
|
|
1158
|
+
function searchChromeFromOptions(opts, commentrayPathOverride) {
|
|
1159
|
+
const crPath = (commentrayPathOverride ?? opts.commentrayPathForSearch ?? "").trim();
|
|
538
1160
|
if (opts.staticSearchScope === "commentray-and-paths") {
|
|
539
1161
|
return {
|
|
540
|
-
searchPlaceholder: "
|
|
541
|
-
shellSearchAttrs: ` data-search-scope="commentray-and-paths" data-search-file-path="${escapeHtml(opts.filePath ?? "")}" data-search-commentray-path="${escapeHtml(
|
|
1162
|
+
searchPlaceholder: "Filename, path, or keywords…",
|
|
1163
|
+
shellSearchAttrs: ` data-search-scope="commentray-and-paths" data-search-file-path="${escapeHtml(opts.filePath ?? "")}" data-search-commentray-path="${escapeHtml(crPath)}"`,
|
|
542
1164
|
};
|
|
543
1165
|
}
|
|
544
1166
|
return {
|
|
545
|
-
searchPlaceholder: "
|
|
1167
|
+
searchPlaceholder: "Filename, path, or keywords…",
|
|
546
1168
|
shellSearchAttrs: "",
|
|
547
1169
|
};
|
|
548
1170
|
}
|
|
@@ -552,6 +1174,38 @@ function shellDocumentedPairsAttrFromOptions(opts) {
|
|
|
552
1174
|
return "";
|
|
553
1175
|
return ` data-documented-pairs-b64="${escapeHtml(emb)}"`;
|
|
554
1176
|
}
|
|
1177
|
+
function codeBrowserPageTitle(opts) {
|
|
1178
|
+
return opts.title ?? opts.filePath ?? "Commentray";
|
|
1179
|
+
}
|
|
1180
|
+
function codeBrowserHljsThemes(opts) {
|
|
1181
|
+
const hljs = opts.hljsTheme ?? "github";
|
|
1182
|
+
const hljsDark = opts.hljsTheme?.includes("dark") ? opts.hljsTheme : "github-dark";
|
|
1183
|
+
return { hljs, hljsDark };
|
|
1184
|
+
}
|
|
1185
|
+
function toolbarCommentrayGithubFromShell(shell, opts) {
|
|
1186
|
+
return shell.multiShell?.commentrayOnGithubUrl ?? opts.commentrayOnGithubUrl;
|
|
1187
|
+
}
|
|
1188
|
+
function toolbarCommentrayStaticBrowseFromShell(shell, opts) {
|
|
1189
|
+
const t = (shell.multiShell?.commentrayStaticBrowseUrl ??
|
|
1190
|
+
opts.commentrayStaticBrowseUrl ??
|
|
1191
|
+
"").trim();
|
|
1192
|
+
return t.length > 0 ? t : undefined;
|
|
1193
|
+
}
|
|
1194
|
+
function rawMdB64FromShell(shell, opts) {
|
|
1195
|
+
return (shell.multiShell?.rawMdB64 ?? Buffer.from(opts.commentrayMarkdown, "utf8").toString("base64"));
|
|
1196
|
+
}
|
|
1197
|
+
function navRailCommentrayPathFromShell(shell, opts) {
|
|
1198
|
+
const trimmed = (shell.multiShell?.commentrayPathForSearch ??
|
|
1199
|
+
opts.commentrayPathForSearch ??
|
|
1200
|
+
"").trim();
|
|
1201
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
1202
|
+
}
|
|
1203
|
+
function shellSearchAttrsWithNavJson(shellSearchAttrsBase, documentedNavJsonUrl) {
|
|
1204
|
+
const navJson = documentedNavJsonUrl?.trim() ?? "";
|
|
1205
|
+
if (navJson.length === 0)
|
|
1206
|
+
return shellSearchAttrsBase;
|
|
1207
|
+
return `${shellSearchAttrsBase} data-nav-search-json-url="${escapeHtml(navJson)}"`;
|
|
1208
|
+
}
|
|
555
1209
|
/**
|
|
556
1210
|
* Static HTML shell for a minimal “code browser”: code + rendered commentray,
|
|
557
1211
|
* draggable vertical splitter, togglable line wrap for the code pane, and
|
|
@@ -559,35 +1213,47 @@ function shellDocumentedPairsAttrFromOptions(opts) {
|
|
|
559
1213
|
*/
|
|
560
1214
|
export async function renderCodeBrowserHtml(opts) {
|
|
561
1215
|
const rawCodeB64 = Buffer.from(opts.code, "utf8").toString("base64");
|
|
562
|
-
const
|
|
563
|
-
const
|
|
564
|
-
const
|
|
565
|
-
const
|
|
566
|
-
const
|
|
567
|
-
const
|
|
1216
|
+
const title = codeBrowserPageTitle(opts);
|
|
1217
|
+
const metaDescriptionHtml = renderMetaDescriptionHtml(opts, title);
|
|
1218
|
+
const builtAt = opts.builtAt ?? new Date();
|
|
1219
|
+
const renderSemver = commentrayRenderVersion();
|
|
1220
|
+
const toolbarSiteHubHtml = buildToolbarSiteHubHtml(opts.siteHubUrl);
|
|
1221
|
+
const toolbarEndHtml = buildToolbarEndHtml(opts.githubRepoUrl, opts.toolHomeUrl, renderSemver, opts.siteHubUrl);
|
|
1222
|
+
const pageFooterHtml = renderPageFooterHtml(builtAt);
|
|
1223
|
+
const { hljs, hljsDark } = codeBrowserHljsThemes(opts);
|
|
568
1224
|
const mermaidScript = mermaidRuntimeScriptHtml(opts.includeMermaidRuntime);
|
|
569
1225
|
const relatedNavHtml = renderRelatedGithubNavHtml(opts.relatedGithubNav ?? []);
|
|
570
1226
|
const generatorMetaHtml = renderGeneratorMetaHtml(opts.generatorLabel);
|
|
571
|
-
const
|
|
572
|
-
|
|
573
|
-
|
|
1227
|
+
const layoutPref = opts.codeBrowserLayout ?? "auto";
|
|
1228
|
+
const shell = await buildCodeBrowserShell(opts, layoutPref);
|
|
1229
|
+
const { toolbarDocHubHtml, navRailDocumentedHtml } = renderToolbarDocHubHtml({
|
|
574
1230
|
documentedNavJsonUrl: opts.documentedNavJsonUrl,
|
|
575
1231
|
documentedPairsEmbeddedB64: opts.documentedPairsEmbeddedB64,
|
|
576
1232
|
});
|
|
577
|
-
const
|
|
578
|
-
const
|
|
579
|
-
const { searchPlaceholder, shellSearchAttrs } = searchChromeFromOptions(opts);
|
|
1233
|
+
const rawMdB64 = rawMdB64FromShell(shell, opts);
|
|
1234
|
+
const scrollBlockLinksB64 = shell.scrollBlockLinksB64;
|
|
1235
|
+
const { searchPlaceholder, shellSearchAttrs: shellSearchAttrsBase } = searchChromeFromOptions(opts, shell.multiShell?.commentrayPathForSearch);
|
|
580
1236
|
const shellDocumentedPairsAttr = shellDocumentedPairsAttrFromOptions(opts);
|
|
1237
|
+
const shellSearchAttrs = shellSearchAttrsWithNavJson(shellSearchAttrsBase, opts.documentedNavJsonUrl);
|
|
1238
|
+
const navRailContextHtml = renderNavRailContextHtml(opts.filePath, navRailCommentrayPathFromShell(shell, opts), {
|
|
1239
|
+
sourceOnGithubUrl: opts.sourceOnGithubUrl,
|
|
1240
|
+
commentrayOnGithubUrl: toolbarCommentrayGithubFromShell(shell, opts),
|
|
1241
|
+
commentrayStaticBrowseUrl: toolbarCommentrayStaticBrowseFromShell(shell, opts),
|
|
1242
|
+
});
|
|
581
1243
|
return buildCodeBrowserPageHtml({
|
|
582
1244
|
title,
|
|
1245
|
+
metaDescriptionHtml,
|
|
583
1246
|
generatorMetaHtml,
|
|
584
|
-
|
|
1247
|
+
toolbarSiteHubHtml,
|
|
1248
|
+
navRailContextHtml,
|
|
1249
|
+
angleSelectHtml: shell.angleSelectHtml,
|
|
585
1250
|
toolbarDocHubHtml,
|
|
586
|
-
|
|
1251
|
+
navRailDocumentedHtml,
|
|
587
1252
|
relatedNavHtml,
|
|
588
1253
|
toolbarEndHtml,
|
|
589
|
-
|
|
590
|
-
|
|
1254
|
+
pageFooterHtml,
|
|
1255
|
+
layout: shell.layout,
|
|
1256
|
+
shellInner: shell.shellInner,
|
|
591
1257
|
rawCodeB64,
|
|
592
1258
|
rawMdB64,
|
|
593
1259
|
scrollBlockLinksB64,
|
|
@@ -597,6 +1263,7 @@ export async function renderCodeBrowserHtml(opts) {
|
|
|
597
1263
|
mermaidScript,
|
|
598
1264
|
searchPlaceholder,
|
|
599
1265
|
shellSearchAttrs,
|
|
1266
|
+
multiAngleScriptBlock: shell.multiAnglePayloadB64,
|
|
600
1267
|
});
|
|
601
1268
|
}
|
|
602
1269
|
//# sourceMappingURL=code-browser.js.map
|