feat(viewer): show document summary together with the original (TODO.md L5)
This commit is contained in:
@@ -12,7 +12,13 @@
|
||||
* in a ≤46rem centered column;
|
||||
* • any other → the raw content as a text node inside
|
||||
* <pre class="doc-raw"> (mono, horizontal
|
||||
* scroll).
|
||||
* scroll);
|
||||
* • doc.summary non-empty (phase 36 — phase 30 summaries exist
|
||||
* only on non-markdown docs) → a labeled
|
||||
* .doc-summary section ABOVE the content;
|
||||
* null / empty / whitespace renders nothing, so
|
||||
* markdown docs and fail-soft rows are
|
||||
* byte-for-byte unchanged.
|
||||
*
|
||||
* 2. The /document.html page itself: reads `source`/`path` query
|
||||
* params, fetches the stateless content endpoint
|
||||
@@ -40,6 +46,11 @@
|
||||
* around the page block below). Importing renderDocument elsewhere has
|
||||
* no side effects: no back-link resolution, no whoami, no content
|
||||
* fetch, no New Chat binding.
|
||||
*
|
||||
* Phase 36: the renderer owns the optional summary panel — a non-empty
|
||||
* doc.summary renders as a labeled .doc-summary section above the
|
||||
* original content on BOTH surfaces (page + modal) through this one
|
||||
* core; the summary text is a text node (XSS contract unchanged).
|
||||
*/
|
||||
|
||||
import { fetchIsAdmin, initSharedHeader } from "./header.js";
|
||||
@@ -66,10 +77,13 @@ function metaBadge(cls, text) {
|
||||
/* ---------- shared renderer (phase 26, task 02) ----------
|
||||
* Populates the three elements every render surface provides: a title,
|
||||
* a .doc-meta badge row (source · format · mono path · indexed ·
|
||||
* chunks), and a content container — .doc-md for md/markdown (the
|
||||
* shared escape-first renderer), <pre class="doc-raw"> otherwise. The
|
||||
* XSS contract: innerHTML only through renderMarkdown; every
|
||||
* document-derived string is a text node. */
|
||||
* chunks), and a content container — an optional .doc-summary section
|
||||
* first (phase 36: only when doc.summary is non-empty — markdown docs
|
||||
* and fail-soft rows carry none, so they render exactly as before),
|
||||
* then .doc-md for md/markdown (the shared escape-first renderer),
|
||||
* <pre class="doc-raw"> otherwise. The XSS contract: innerHTML only
|
||||
* through renderMarkdown; every document-derived string (summary text
|
||||
* included) is a text node. */
|
||||
export function renderDocument(doc, { titleEl, metaEl, contentEl }) {
|
||||
titleEl.textContent = doc.title;
|
||||
// Phase 34 task 04: the titlebar title ellipsizes — the full title
|
||||
@@ -88,6 +102,24 @@ export function renderDocument(doc, { titleEl, metaEl, contentEl }) {
|
||||
);
|
||||
|
||||
contentEl.replaceChildren();
|
||||
// Phase 36: the summary panel — labeled section ABOVE the original
|
||||
// content, on BOTH surfaces (page + modal) through this one core.
|
||||
// Only a non-empty summary renders: markdown docs carry none (phase
|
||||
// 30) and the fail-soft path leaves summary NULL, so both are
|
||||
// byte-for-byte unchanged here.
|
||||
if (doc.summary && doc.summary.trim() !== "") {
|
||||
const section = document.createElement("section");
|
||||
section.className = "doc-summary";
|
||||
section.setAttribute("aria-label", "Summary");
|
||||
const title = document.createElement("h2");
|
||||
title.className = "doc-summary-title";
|
||||
title.textContent = "Summary";
|
||||
const body = document.createElement("p");
|
||||
body.className = "doc-summary-text";
|
||||
body.textContent = doc.summary; // text node — XSS contract unchanged
|
||||
section.append(title, body);
|
||||
contentEl.appendChild(section);
|
||||
}
|
||||
if (doc.format === "md" || doc.format === "markdown") {
|
||||
const wrap = document.createElement("div");
|
||||
wrap.className = "doc-md";
|
||||
|
||||
Reference in New Issue
Block a user