feat(voyage): replace pencil-icon with numbered-badge gutter + yellow-tint highlight

Step 18 of v4.3 playground plan. Replaces v4.2 Gesture 2 pencil-icon
hover-reveal with numbered circular badges in the left gutter (one per
anchored paragraph; ordering matches sidebar jumplist). 2-3px accent stripe
extends right from the badge into the gutter. Yellow-tint highlight
(rgba 255, 235, 59, 0.25 — Google Docs pattern) applies to the anchored
paragraph when an annotation is active. Body text never reflowed or
recolored. Gesture 1 (text-select adder) and Gesture 3 (page-level note)
remain for new annotation creation.

CSS uses --color-scope-voyage token for badge background and stripe.
JS adds injectAnchorBadges() + setActiveAnchor() and rewires mountRender.

Trace: SC1 + SC6, research/04 Insight 3 + Recommendation marker-design.
This commit is contained in:
Kjell Tore Guttormsen 2026-05-10 17:06:59 +02:00
commit 84f41014f9
2 changed files with 120 additions and 45 deletions

View file

@ -226,3 +226,27 @@ test('voyage-playground.html declares relocateAnchorsToBlockBoundaries pure func
assert.match(text, /function\s+relocateAnchorsToBlockBoundaries\s*\(\s*text\s*,\s*anchors\s*\)/,
'relocateAnchorsToBlockBoundaries(text, anchors) pure function required');
});
test('voyage-playground.html declares .voyage-anchor-badge gutter component (v4.3 Step 18)', () => {
const text = readFileSync(HTML, 'utf-8');
assert.match(text, /\.voyage-anchor-badge\s*\{/, '.voyage-anchor-badge CSS class required');
assert.match(text, /position:\s*absolute/, '.voyage-anchor-badge must use absolute positioning');
assert.match(text, /var\(--color-scope-voyage\)/, 'badge must use --color-scope-voyage token');
});
test('voyage-playground.html declares .voyage-anchor-active yellow-tint highlight (v4.3 Step 18)', () => {
const text = readFileSync(HTML, 'utf-8');
assert.match(text, /\.voyage-anchor-active\s*\{/, '.voyage-anchor-active CSS class required');
assert.match(text, /rgba\(255,\s*235,\s*59,\s*0\.25\)/, 'yellow-tint rgba(255, 235, 59, 0.25) required');
});
test('voyage-playground.html does NOT contain v4.2 pencil-icon references (v4.3 Step 18 cleanup)', () => {
const text = readFileSync(HTML, 'utf-8');
assert.doesNotMatch(text, /voyage-pencil-btn/, 'pencil-btn class must be removed');
assert.doesNotMatch(text, /injectPencilIcons/, 'injectPencilIcons function must be replaced by injectAnchorBadges');
});
test('voyage-playground.html declares injectAnchorBadges JS function (v4.3 Step 18)', () => {
const text = readFileSync(HTML, 'utf-8');
assert.match(text, /function\s+injectAnchorBadges\s*\(\s*\)/, 'injectAnchorBadges() function required');
});