personal memory agent
0

Configure Feed

Select the types of activity you want to include in your feed.

fix(convey): share drawer line formatting

Extract Drawer.formatLine so hand-authored drawer markup can use the same escaped numeric emphasis as Drawer.render output. This keeps settings aligned with the shared drawer standard without copying the line-emphasis regex.

+17 -7
+2 -1
solstone/apps/body/tests/test_body_app.py
··· 590 590 node = _node_or_skip() 591 591 source = Path("solstone/convey/static/drawer.js").read_text(encoding="utf-8") 592 592 functions = "\n".join( 593 - _function_source(source, name) for name in ("escapeHtml", "render") 593 + _function_source(source, name) 594 + for name in ("escapeHtml", "formatLine", "render") 594 595 ) 595 596 script = "\n".join( 596 597 [
+10 -5
solstone/convey/static/drawer.js
··· 17 17 })[char]); 18 18 } 19 19 20 + function formatLine(line) { 21 + const value = String(line ?? '').trim(); 22 + return value 23 + ? escapeHtml(value).replace(/&#?\w+;|\d[\d,.:]*(?:\s?(?:am|pm|s))?/g, (m) => (m.startsWith('&') ? m : `<b>${m}</b>`)) 24 + : ''; 25 + } 26 + 20 27 function render(options) { 21 28 const config = options || {}; 22 29 const id = String(config.id ?? '').trim(); 23 30 const idAttr = id ? ` data-drawer-id="${escapeHtml(id)}"` : ''; 24 31 const openAttr = config.open ? ' open' : ''; 25 - const line = String(config.line ?? '').trim(); 26 - const lineHtml = line 27 - ? `<span class="drawer-line">${escapeHtml(line).replace(/&#?\w+;|\d[\d,.:]*(?:\s?(?:am|pm|s))?/g, (m) => (m.startsWith('&') ? m : `<b>${m}</b>`))}</span>` 28 - : ''; 32 + const line = formatLine(config.line); 33 + const lineHtml = line ? `<span class="drawer-line">${line}</span>` : ''; 29 34 const chipText = String(config.chipText ?? '').trim(); 30 35 const chipTone = config.chipTone === 'warn' || config.chipTone === 'danger' 31 36 ? ` drawer-chip--${config.chipTone}` ··· 65 70 return result; 66 71 } 67 72 68 - window.Drawer = Object.freeze({ render, preserveOpen }); 73 + window.Drawer = Object.freeze({ render, preserveOpen, formatLine }); 69 74 })();
+5 -1
tests/test_convey_drawer.py
··· 59 59 60 60 assert "(function () {" in source 61 61 assert "'use strict';" in source 62 - assert "window.Drawer = Object.freeze({ render, preserveOpen });" in source 62 + assert ( 63 + "window.Drawer = Object.freeze({ render, preserveOpen, formatLine });" in source 64 + ) 63 65 assert "Storage" not in source 64 66 assert "localStorage" not in source 65 67 assert "sessionStorage" not in source ··· 285 287 line: "median statement length 1.5s — needs 2s", 286 288 bodyHtml: "", 287 289 }); 290 + assert(Object.keys(window.Drawer).join("|") === "render|preserveOpen|formatLine", "drawer exports formatLine"); 291 + assert(window.Drawer.formatLine("2 files created · <5>").includes("<b>2</b> files created · &lt;<b>5</b>&gt;"), "formatLine escapes and emphasizes digits"); 288 292 assert(lineHtml(directDrawer).includes("<b>1.5s</b>"), "drawer emphasizes compact seconds"); 289 293 290 294 const tooFewPayload = payload();