Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 11 additions & 14 deletions claude_code_log/html/templates/components/message_styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -84,14 +84,11 @@
font-size: 1.1em;
line-height: 1;
color: var(--fold-color);
/* Tighten the gap between the two glyphs in ``▼▼`` / ``▶▶`` —
Chrome renders default kerning much wider than Firefox does,
leaving an awkward gap. The pulled-in -0.2em compromise reads
cleanly in Chrome without crowding the glyphs in Firefox
(issue #73 / #153). No visible effect on single-glyph ``▼``
since letter-spacing only matters when two characters are
adjacent. */
letter-spacing: -.2em;
/* The doubled glyphs ``⏷⏷`` / ``⏵⏵`` (U+23F7 / U+23F5) sit at a
natural, even spacing in both Chrome and Firefox, so no kerning
trick is needed (the earlier ``▼▼`` / ``▶▶`` needed a -0.2em
letter-spacing pull-in to tame Chrome's wide default — issue
#73 / #153 / #247). */
}

.fold-count {
Expand Down Expand Up @@ -1051,9 +1048,9 @@ pre > code {
}

/* Fold-valued rows hoist their toggle into the KEY column: the key cell's
▶/▼ button (wired in transcript.html, state derived from toggle events)
⏵/⏷ button (wired in transcript.html, state derived from toggle events)
replaces the per-fold in-summary collapse chrome, which only remained
useful en masse — every row showing " collapse" drowned the content.
useful en masse — every row showing " collapse" drowned the content.
Scoped to keyed rows: the top-level root fold has no key column and
keeps its summary affordances (the pure-CSS ::after "collapse" hint —
no interactive child). */
Expand All @@ -1077,7 +1074,7 @@ pre > code {
/* The shared fold glyph: the BROWSER'S native disclosure marker (the same
UA-drawn icon a <summary> shows) via display:list-item — geometrically
symmetric open/closed, and immune to the italic style of the button
labels (font glyphs like ▶/▼ skew in italics; the marker icon doesn't).
labels (font glyphs like ⏵/⏷ skew in italics; the marker icon doesn't).
The empty span doubles as the key-column alignment slot: every key cell
renders one (markerless on scalar rows), so all key texts start at the
same x. */
Expand All @@ -1094,13 +1091,13 @@ pre > code {
button > .tool-param-fold-glyph {
display: list-item;
list-style-position: inside;
list-style-type: "\25B8";
list-style-type: "\23F5";
list-style-type: disclosure-closed;
}

.tool-param-key-toggle[aria-expanded='true'] > .tool-param-fold-glyph,
[data-state='expanded'] > .tool-param-fold-glyph {
list-style-type: "\25BE";
list-style-type: "\23F7";
list-style-type: disclosure-open;
}

Expand All @@ -1123,7 +1120,7 @@ button > .tool-param-fold-glyph {
display: none;
}

/* A keyed fold's open summary carries nothing (the key glyph shows and
/* A keyed fold's open summary carries nothing (the key glyph shows and
the rows-toggle sits in the controls strip below) — drop the line it
would occupy. This also suppresses the generic ::after "collapse". */
.tool-param-row-fold > .tool-param-value > details[open] > summary {
Expand Down
44 changes: 22 additions & 22 deletions claude_code_log/html/templates/transcript.html
Original file line number Diff line number Diff line change
Expand Up @@ -135,17 +135,17 @@ <h3>🔍 Search & Filter</h3>
{% if message.immediate_children_count == message.total_descendants_count %}
{# Same count = only one level, show single full-width button #}
<div class='fold-bar-section fold-one-level full-width' data-action='fold-one' data-target='{{ message.message_id }}' data-title-unfolded='Fold {{ message.get_immediate_children_label() }}' data-title-folded='Unfold (1st level) {{ message.get_immediate_children_label() }}' title='Fold {{ message.get_immediate_children_label() }}'>
<span class='fold-icon'></span>
<span class='fold-icon'></span>
<span class='fold-label'>{{ message.get_immediate_children_label() }}</span>
</div>
{% else %}
{# Multiple levels, show both buttons #}
<div class='fold-bar-section fold-one-level' data-action='fold-one' data-target='{{ message.message_id }}' data-title-unfolded='Fold (all levels) all {{ message.total_descendants_count }} descendants' data-title-folded='Unfold (1st level) {{ message.get_immediate_children_label() }}' title='Fold (all levels) all {{ message.total_descendants_count }} descendants'>
<span class='fold-icon'></span>
<span class='fold-icon'></span>
<span class='fold-label'>{{ message.get_immediate_children_label() }}</span>
</div>
<div class='fold-bar-section fold-all-levels' data-action='fold-all' data-target='{{ message.message_id }}' data-title-unfolded='Fold (to 1st level) {{ message.get_immediate_children_label() }}' data-title-folded='Unfold (all levels) all {{ message.total_descendants_count }} descendants' title='Fold (to 1st level) {{ message.get_immediate_children_label() }}'>
<span class='fold-icon'>▼▼</span>
<span class='fold-icon'>⏷⏷</span>
<span class='fold-label'>{{ message.get_total_descendants_label() }} total</span>
</div>
{% endif %}
Expand Down Expand Up @@ -197,17 +197,17 @@ <h3>🔍 Search & Filter</h3>
{% if message.immediate_children_count == message.total_descendants_count %}
{# Same count = only one level, show single full-width button #}
<div class='fold-bar-section fold-one-level full-width' data-action='fold-one' data-target='{{ message.message_id }}' data-title-unfolded='Fold {{ message.get_immediate_children_label() }}' data-title-folded='Unfold (1st level) {{ message.get_immediate_children_label() }}' title='Fold {{ message.get_immediate_children_label() }}'>
<span class='fold-icon'></span>
<span class='fold-icon'></span>
<span class='fold-label'>{{ message.get_immediate_children_label() }}</span>
</div>
{% else %}
{# Multiple levels, show both buttons #}
<div class='fold-bar-section fold-one-level' data-action='fold-one' data-target='{{ message.message_id }}' data-title-unfolded='Fold (all levels) all {{ message.total_descendants_count }} descendants' data-title-folded='Unfold (1st level) {{ message.get_immediate_children_label() }}' title='Fold (all levels) all {{ message.total_descendants_count }} descendants'>
<span class='fold-icon'></span>
<span class='fold-icon'></span>
<span class='fold-label'>{{ message.get_immediate_children_label() }}</span>
</div>
<div class='fold-bar-section fold-all-levels' data-action='fold-all' data-target='{{ message.message_id }}' data-title-unfolded='Fold (to 1st level) {{ message.get_immediate_children_label() }}' data-title-folded='Unfold (all levels) all {{ message.total_descendants_count }} descendants' title='Fold (to 1st level) {{ message.get_immediate_children_label() }}'>
<span class='fold-icon'>▼▼</span>
<span class='fold-icon'>⏷⏷</span>
<span class='fold-label'>{{ message.get_total_descendants_label() }} total</span>
</div>
{% endif %}
Expand Down Expand Up @@ -446,7 +446,7 @@ <h3>🔍 Search & Filter</h3>
const allOpen = rows.length > 0 &&
Array.from(rows).every(row => row.open);
const kind = button.dataset.kind || 'rows';
// data-state drives the CSS rotation of the constant glyph;
// data-state drives the CSS rotation of the constant glyph;
// only the label text changes.
button.dataset.state = allOpen ? 'expanded' : 'collapsed';
const label = button.querySelector('.tool-param-fold-label');
Expand Down Expand Up @@ -482,7 +482,7 @@ <h3>🔍 Search & Filter</h3>
syncExpandAll(root);
return;
}
// Key-column fold toggle (▶/▼): drives the value cell's
// Key-column fold toggle (⏵/⏷): drives the value cell's
// details from the key cell, keeping the summary free of
// per-fold collapse chrome. Glyph state is derived in the
// toggle listener below, so any other opener stays in sync.
Expand Down Expand Up @@ -530,7 +530,7 @@ <h3>🔍 Search & Filter</h3>
const keyBtn = row && row.querySelector(
':scope > .tool-param-key > .tool-param-key-toggle');
if (keyBtn) {
// CSS rotates the single glyph on aria-expanded —
// CSS rotates the single glyph on aria-expanded —
// symmetric open/closed states by construction.
keyBtn.setAttribute('aria-expanded',
details.open ? 'true' : 'false');
Expand Down Expand Up @@ -867,18 +867,18 @@ <h3>🔍 Search & Filter</h3>
const allSection = foldBar ? foldBar.querySelector('.fold-all-levels') : null;
if (state === 'folded') {
if (cc) cc.style.display = 'none';
setSectionState(oneSection, true, '');
setSectionState(allSection, true, '▶▶');
setSectionState(oneSection, true, '');
setSectionState(allSection, true, '⏵⏵');
} else if (state === 'first') {
if (cc) cc.style.display = '';
getImmediateChildMessages(messageEl).forEach(child => applyFoldState(child, 'folded'));
setSectionState(oneSection, false, '');
setSectionState(allSection, true, '▶▶');
setSectionState(oneSection, false, '');
setSectionState(allSection, true, '⏵⏵');
} else { // 'open'
if (cc) cc.style.display = '';
getImmediateChildMessages(messageEl).forEach(child => applyFoldState(child, 'open'));
setSectionState(oneSection, false, '');
setSectionState(allSection, false, '▼▼');
setSectionState(oneSection, false, '');
setSectionState(allSection, false, '⏷⏷');
}
}

Expand Down Expand Up @@ -924,15 +924,15 @@ <h3>🔍 Search & Filter</h3>

const cc = getChildrenContainer(msg);
if ((isSession || isUser) && !hasOnlyTools) {
// First level visible (), deeper levels folded (▶▶)
// First level visible (), deeper levels folded (⏵⏵)
if (cc) cc.style.display = '';
setSectionState(oneSection, false, '');
setSectionState(allSection, true, '▶▶');
setSectionState(oneSection, false, '');
setSectionState(allSection, true, '⏵⏵');
} else {
// Fully folded
if (cc) cc.style.display = 'none';
setSectionState(oneSection, true, '');
setSectionState(allSection, true, '▶▶');
setSectionState(oneSection, true, '');
setSectionState(allSection, true, '⏵⏵');
}
});
}
Expand All @@ -959,8 +959,8 @@ <h3>🔍 Search & Filter</h3>
const card = wrapper ? wrapper.querySelector(':scope > .message') : null;
const foldBar = card ? card.querySelector(':scope > .fold-bar') : null;
if (foldBar) {
setSectionState(foldBar.querySelector('.fold-one-level'), false, '');
setSectionState(foldBar.querySelector('.fold-all-levels'), false, '▼▼');
setSectionState(foldBar.querySelector('.fold-one-level'), false, '');
setSectionState(foldBar.querySelector('.fold-all-levels'), false, '⏷⏷');
}
}
node = node.parentElement;
Expand Down
2 changes: 1 addition & 1 deletion claude_code_log/html/tool_formatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -1222,7 +1222,7 @@ def _param_value_html(value: Any, depth: int) -> str:
def _params_table_html(items: "Iterable[tuple[Any, Any]]", depth: int) -> str:
"""Build one key/value table; nested levels get a marker class.

A fold-valued row hoists its ▶/▼ toggle into the KEY column (wired in
A fold-valued row hoists its ⏵/⏷ toggle into the KEY column (wired in
transcript.html), so the value summary stays free of per-fold collapse
chrome — only the previews (closed) and the rows-toggle buttons (open)
remain there. The ``<details`` probe is exact: every fold helper emits
Expand Down
2 changes: 1 addition & 1 deletion claude_code_log/renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -1782,7 +1782,7 @@ def _build_pairing_indices(messages: list[TemplateMessage]) -> PairingIndices:
# Indexing them here would let a chained system entry (e.g. a
# ``stop_hook_summary`` whose ``parentUuid`` is the hook
# attachment) pair the hook as its parent — visible as a
# spurious " 1 system" fold-bar on every hook in dense
# spurious " 1 system" fold-bar on every hook in dense
# transcripts (e.g. ClMail bursts).
if (
msg.meta.uuid
Expand Down
Loading
Loading