Skip to content

Commit 080e043

Browse files
ShlomoSteptclaude
andcommitted
Implement comprehensive UI improvements for Phase 2
## Phase 1: Foundation (Craft.do Style) - Add 50+ CSS custom properties for colors, spacing, shadows - Implement warm cream/off-white color palette - Add paper texture background effect - Define frosted glass variables for sticky headers ## Phase 2: User Messages - Make user messages collapsible with cell wrapper - Add text wrapping (overflow-wrap, word-break) to prevent overflow - Add .user-cell CSS styling matching other cell types ## Phase 3: Toggle System - Replace small toggle buttons with shadcn-inspired tab controls - Add Markdown | JSON tabs with clear active states - Include ARIA attributes for accessibility - Update JavaScript for tab-based toggle behavior ## Phase 4: Collapsibility Unification - Make message headers sticky (z-index: 30) - Create cascading sticky headers: message → cell → subcell - Add frosted glass backdrop-filter effects - Ensure no overflow:hidden breaks sticky positioning ## Phase 5: Copy System - Remove duplicate copy buttons (skip inside .cell-content) - Add cell-level master toggle for tools cells - Propagate view mode to all child elements ## Phase 6: Specialized Tools - Add Markdown/JSON toggles to Write, Edit, Bash, TodoWrite - Pass input_json_html to all specialized tool macros - Preserve existing specialized displays in Markdown view All 133 tests pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 39db2e0 commit 080e043

18 files changed

Lines changed: 1941 additions & 769 deletions

src/claude_code_transcripts/__init__.py

Lines changed: 311 additions & 148 deletions
Large diffs are not rendered by default.

src/claude_code_transcripts/templates/macros.html

Lines changed: 64 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,17 @@
4646
{%- endif %}
4747
{% endmacro %}
4848

49-
{# Todo list #}
50-
{% macro todo_list(todos, tool_id) %}
51-
<div class="todo-list" data-tool-id="{{ tool_id }}"><div class="todo-header"><span class="todo-header-icon"></span> Task List</div><ul class="todo-items">
49+
{# Todo list - input_json_html is pre-rendered JSON so needs |safe #}
50+
{% macro todo_list(todos, input_json_html, tool_id) %}
51+
<div class="todo-list" data-tool-id="{{ tool_id }}">
52+
<div class="todo-header"><span class="todo-header-icon"></span> Task List
53+
<div class="view-toggle" role="tablist">
54+
<button class="view-toggle-tab active" role="tab" data-view="markdown">Markdown</button>
55+
<button class="view-toggle-tab" role="tab" data-view="json">JSON</button>
56+
</div>
57+
</div>
58+
<div class="view-markdown">
59+
<ul class="todo-items">
5260
{%- for todo in todos -%}
5361
{%- set status = todo.status|default('pending') -%}
5462
{%- set content = todo.content|default('') -%}
@@ -64,46 +72,81 @@
6472
{%- endif -%}
6573
<li class="todo-item {{ status_class }}"><span class="todo-icon">{{ icon }}</span><span class="todo-content">{{ content }}</span></li>
6674
{%- endfor -%}
67-
</ul></div>
75+
</ul>
76+
</div>
77+
<div class="view-json" style="display: none;">
78+
{{ input_json_html|safe }}
79+
</div>
80+
</div>
6881
{%- endmacro %}
6982

70-
{# Write tool - content is pre-highlighted so needs |safe #}
71-
{% macro write_tool(file_path, content, tool_id) %}
83+
{# Write tool - content is pre-highlighted so needs |safe, input_json_html is pre-rendered JSON so needs |safe #}
84+
{% macro write_tool(file_path, content, input_json_html, tool_id) %}
7285
{%- set filename = file_path.split('/')[-1] if '/' in file_path else file_path -%}
7386
<div class="file-tool write-tool" data-tool-id="{{ tool_id }}">
74-
<div class="file-tool-header write-header"><span class="file-tool-icon">📝</span> Write <span class="file-tool-path">{{ filename }}</span></div>
87+
<div class="file-tool-header write-header"><span class="file-tool-icon">📝</span> Write <span class="file-tool-path">{{ filename }}</span>
88+
<div class="view-toggle" role="tablist">
89+
<button class="view-toggle-tab active" role="tab" data-view="markdown">Markdown</button>
90+
<button class="view-toggle-tab" role="tab" data-view="json">JSON</button>
91+
</div>
92+
</div>
93+
<div class="view-markdown">
7594
<div class="file-tool-fullpath">{{ file_path }}</div>
7695
<div class="truncatable"><div class="truncatable-content"><pre class="file-content highlight">{{ content|safe }}</pre></div><button class="expand-btn">Show more</button></div>
7796
</div>
97+
<div class="view-json" style="display: none;">
98+
{{ input_json_html|safe }}
99+
</div>
100+
</div>
78101
{%- endmacro %}
79102

80-
{# Edit tool - old/new strings are pre-highlighted so need |safe #}
81-
{% macro edit_tool(file_path, old_string, new_string, replace_all, tool_id) %}
103+
{# Edit tool - old/new strings are pre-highlighted so need |safe, input_json_html is pre-rendered JSON so needs |safe #}
104+
{% macro edit_tool(file_path, old_string, new_string, replace_all, input_json_html, tool_id) %}
82105
{%- set filename = file_path.split('/')[-1] if '/' in file_path else file_path -%}
83106
<div class="file-tool edit-tool" data-tool-id="{{ tool_id }}">
84-
<div class="file-tool-header edit-header"><span class="file-tool-icon">✏️</span> Edit <span class="file-tool-path">{{ filename }}</span>{% if replace_all %} <span class="edit-replace-all">(replace all)</span>{% endif %}</div>
107+
<div class="file-tool-header edit-header"><span class="file-tool-icon">✏️</span> Edit <span class="file-tool-path">{{ filename }}</span>{% if replace_all %} <span class="edit-replace-all">(replace all)</span>{% endif %}
108+
<div class="view-toggle" role="tablist">
109+
<button class="view-toggle-tab active" role="tab" data-view="markdown">Markdown</button>
110+
<button class="view-toggle-tab" role="tab" data-view="json">JSON</button>
111+
</div>
112+
</div>
113+
<div class="view-markdown">
85114
<div class="file-tool-fullpath">{{ file_path }}</div>
86115
<div class="truncatable"><div class="truncatable-content">
87116
<div class="edit-section edit-old"><div class="edit-label"></div><pre class="edit-content highlight">{{ old_string|safe }}</pre></div>
88117
<div class="edit-section edit-new"><div class="edit-label">+</div><pre class="edit-content highlight">{{ new_string|safe }}</pre></div>
89118
</div><button class="expand-btn">Show more</button></div>
90119
</div>
120+
<div class="view-json" style="display: none;">
121+
{{ input_json_html|safe }}
122+
</div>
123+
</div>
91124
{%- endmacro %}
92125

93-
{# Bash tool - description_html is pre-rendered markdown so needs |safe #}
94-
{% macro bash_tool(command, description_html, tool_id) %}
126+
{# Bash tool - description_html is pre-rendered markdown so needs |safe, input_json_html is pre-rendered JSON so needs |safe #}
127+
{% macro bash_tool(command, description_html, input_json_html, tool_id) %}
95128
<div class="tool-use bash-tool" data-tool-id="{{ tool_id }}">
96-
<div class="tool-header"><span class="tool-call-label"><span class="call-icon"></span> Call</span><span class="tool-icon">$</span> Bash</div>
129+
<div class="tool-header"><span class="tool-call-label"><span class="call-icon"></span> Call</span><span class="tool-icon">$</span> Bash
130+
<div class="view-toggle" role="tablist">
131+
<button class="view-toggle-tab active" role="tab" data-view="markdown">Markdown</button>
132+
<button class="view-toggle-tab" role="tab" data-view="json">JSON</button>
133+
</div>
134+
</div>
135+
<div class="view-markdown">
97136
{%- if description_html %}
98137
<div class="tool-description">{{ description_html|safe }}</div>
99138
{%- endif -%}
100139
<div class="truncatable"><div class="truncatable-content"><pre class="bash-command">{{ command }}</pre></div><button class="expand-btn">Show more</button></div>
101140
</div>
141+
<div class="view-json" style="display: none;">
142+
{{ input_json_html|safe }}
143+
</div>
144+
</div>
102145
{%- endmacro %}
103146

104147
{# Generic tool use - description_html, input_markdown_html, input_json_html are pre-rendered so need |safe #}
105148
{% macro tool_use(tool_name, description_html, input_markdown_html, input_json_html, tool_id) %}
106-
<div class="tool-use" data-tool-id="{{ tool_id }}"><div class="tool-header"><span class="tool-call-label"><span class="call-icon"></span> Call</span><span class="tool-icon"></span> {{ tool_name }}<button class="view-toggle-btn" type="button">JSON</button></div>
149+
<div class="tool-use" data-tool-id="{{ tool_id }}"><div class="tool-header"><span class="tool-call-label"><span class="call-icon"></span> Call</span><span class="tool-icon"></span> {{ tool_name }}<div class="view-toggle" role="tablist"><button class="view-toggle-tab active" role="tab" aria-selected="true" data-view="markdown">Markdown</button><button class="view-toggle-tab" role="tab" aria-selected="false" data-view="json">JSON</button></div></div>
107150
{%- if description_html -%}
108151
<div class="tool-description">{{ description_html|safe }}</div>
109152
{%- endif -%}
@@ -113,7 +156,7 @@
113156
{# Tool result - content_markdown_html and content_json_html are pre-rendered so need |safe #}
114157
{% macro tool_result(content_markdown_html, content_json_html, is_error) %}
115158
{%- set error_class = ' tool-error' if is_error else '' -%}
116-
<div class="tool-result{{ error_class }}"><div class="tool-result-header"><span class="tool-result-label">{% if is_error %}<span class="result-icon"></span> Error{% else %}<span class="result-icon"></span> Result{% endif %}</span><button class="view-toggle-btn" type="button">JSON</button></div><div class="truncatable"><div class="truncatable-content"><div class="view-markdown">{{ content_markdown_html|safe }}</div><div class="view-json">{{ content_json_html|safe }}</div></div><button class="expand-btn">Show more</button></div></div>
159+
<div class="tool-result{{ error_class }}"><div class="tool-result-header"><span class="tool-result-label">{% if is_error %}<span class="result-icon"></span> Error{% else %}<span class="result-icon"></span> Result{% endif %}</span><div class="view-toggle" role="tablist"><button class="view-toggle-tab active" role="tab" aria-selected="true" data-view="markdown">Markdown</button><button class="view-toggle-tab" role="tab" aria-selected="false" data-view="json">JSON</button></div></div><div class="truncatable"><div class="truncatable-content"><div class="view-markdown">{{ content_markdown_html|safe }}</div><div class="view-json">{{ content_json_html|safe }}</div></div><button class="expand-btn">Show more</button></div></div>
117160
{%- endmacro %}
118161

119162
{# Tool pair wrapper - tool_use_html/tool_result_html are pre-rendered #}
@@ -126,6 +169,12 @@
126169
<details class="cell {{ cell_type }}-cell"{% if open_by_default %} open{% endif %}>
127170
<summary class="cell-header">
128171
<span class="cell-label">{{ label }}{% if count %} ({{ count }}){% endif %}</span>
172+
{% if cell_type == 'tools' %}
173+
<div class="view-toggle cell-view-toggle" role="tablist">
174+
<button class="view-toggle-tab active" role="tab" data-view="markdown">All Markdown</button>
175+
<button class="view-toggle-tab" role="tab" data-view="json">All JSON</button>
176+
</div>
177+
{% endif %}
129178
<button class="cell-copy-btn" aria-label="Copy {{ label }}" tabindex="0"{% if raw_content %} data-copy-content="{{ raw_content | e }}"{% endif %}>Copy</button>
130179
</summary>
131180
<div class="cell-content">{{ content_html|safe }}</div>

0 commit comments

Comments
 (0)