feat: multiple UI improvements, font settings, and memory file display names #175

Merged
naomi merged 22 commits from fix/tweaks into main 2026-03-03 20:21:58 -08:00
2 changed files with 154 additions and 59 deletions
Showing only changes of commit 08f7ca2d55 - Show all commits
+13 -59
View File
@@ -7,6 +7,7 @@
import Markdown from "./Markdown.svelte";
import HighlightedText from "./HighlightedText.svelte";
import ThinkingBlock from "./ThinkingBlock.svelte";
import ToolCallBlock from "./ToolCallBlock.svelte";
import { searchState, searchQuery } from "$lib/stores/search";
import { clipboardStore } from "$lib/stores/clipboard";
import { shouldHidePaths, maskPaths, showThinkingBlocks } from "$lib/stores/config";
@@ -208,22 +209,6 @@
if (!currentConversationId) return;
await invoke("send_prompt", { conversationId: currentConversationId, message: "/compact" });
}
// Collapsible tool lines
const TOOL_COLLAPSE_THRESHOLD = 60;
let expandedToolLines: Record<string, boolean> = {};
function isToolContentLong(content: string): boolean {
return content.length > TOOL_COLLAPSE_THRESHOLD;
}
function truncateToolContent(content: string): string {
return content.slice(0, TOOL_COLLAPSE_THRESHOLD) + "…";
}
function toggleToolLine(id: string) {
expandedToolLines = { ...expandedToolLines, [id]: !expandedToolLines[id] };
}
</script>
<div
@@ -258,6 +243,18 @@
{#if showThinking}
<ThinkingBlock content={line.content} timestamp={line.timestamp} />
{/if}
{:else if line.type === "tool"}
<div
style={line.parentToolUseId
? "margin-left: 16px; padding-left: 8px; border-left: 2px solid var(--accent-primary);"
: ""}
>
<ToolCallBlock
toolName={line.toolName ?? null}
content={maskPaths(line.content, hidePaths)}
timestamp={line.timestamp}
/>
</div>
{:else}
<div
class="terminal-line mb-2 {getLineClass(line.type)} relative group"
@@ -296,9 +293,6 @@
{#if getLinePrefix(line.type)}
<span class="terminal-prefix mr-2">{getLinePrefix(line.type)}</span>
{/if}
{#if line.toolName}
<span class="terminal-tool-name mr-2">[{line.toolName}]</span>
{/if}
{#if line.type === "compact-prompt"}
<button class="compact-action-btn" onclick={handleCompact}>
⚡ Compact Conversation
@@ -330,22 +324,6 @@
<span class="copy-text">{copiedMessageId === line.id ? "Copied!" : "Copy"}</span>
</button>
</div>
{:else if line.type === "tool" && isToolContentLong(maskPaths(line.content, hidePaths))}
<span class="tool-collapsible">
<HighlightedText
content={expandedToolLines[line.id]
? maskPaths(line.content, hidePaths)
: truncateToolContent(maskPaths(line.content, hidePaths))}
searchQuery={currentSearchQuery}
/>
<button
class="tool-toggle-btn"
onclick={() => toggleToolLine(line.id)}
title={expandedToolLines[line.id] ? "Collapse" : "Expand to see full content"}
>
{expandedToolLines[line.id] ? "▲" : "▼"}
</button>
</span>
{:else}
<HighlightedText
content={maskPaths(line.content, hidePaths)}
@@ -501,28 +479,4 @@
.terminal-line {
position: relative;
}
.tool-collapsible {
display: inline-flex;
align-items: baseline;
gap: 0.4em;
}
.tool-toggle-btn {
background: none;
border: none;
color: var(--text-tertiary, #6b7280);
cursor: pointer;
font-size: 0.7em;
padding: 0;
line-height: 1;
opacity: 0.7;
transition: opacity 0.15s ease;
font-family: inherit;
}
.tool-toggle-btn:hover {
opacity: 1;
color: var(--terminal-tool, #c084fc);
}
</style>
+141
View File
@@ -0,0 +1,141 @@
<script lang="ts">
interface Props {
toolName: string | null;
content: string;
timestamp: Date;
}
let { toolName, content, timestamp }: Props = $props();
let isExpanded = $state(false);
function toggleExpanded() {
isExpanded = !isExpanded;
}
function formatTime(date: Date): string {
return date.toLocaleTimeString("en-US", {
hour: "2-digit",
minute: "2-digit",
});
}
</script>
<div class="tool-block">
<button class="tool-header" onclick={toggleExpanded} type="button">
<span class="tool-timestamp">{formatTime(timestamp)}</span>
<svg
class="tool-icon"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
width="16"
height="16"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"
/>
</svg>
{#if toolName}
<span class="tool-name">[{toolName}]</span>
{/if}
<span class="tool-label">{content}</span>
<svg
class="chevron"
class:expanded={isExpanded}
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
width="14"
height="14"
>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
</button>
{#if isExpanded}
<div class="tool-content">
{content}
</div>
{/if}
</div>
<style>
.tool-block {
margin-bottom: 0.5rem;
border: 1px solid var(--border-color);
border-radius: 0.375rem;
background: var(--bg-secondary);
opacity: 0.85;
}
.tool-header {
display: flex;
align-items: center;
gap: 0.5rem;
width: 100%;
padding: 0.5rem 0.75rem;
border: none;
background: transparent;
cursor: pointer;
color: var(--terminal-tool, #c084fc);
font-size: 0.875rem;
transition: all 0.2s;
}
.tool-header:hover {
background: var(--bg-primary);
color: var(--text-primary);
}
.tool-timestamp {
font-family: monospace;
font-size: 0.75rem;
opacity: 0.7;
color: var(--text-secondary);
flex-shrink: 0;
}
.tool-icon {
flex-shrink: 0;
}
.tool-name {
font-family: monospace;
font-weight: 600;
flex-shrink: 0;
color: var(--terminal-tool-name, #ddd6fe);
}
.tool-label {
flex: 1;
text-align: left;
font-style: italic;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.chevron {
flex-shrink: 0;
transition: transform 0.2s;
}
.chevron.expanded {
transform: rotate(180deg);
}
.tool-content {
padding: 0.75rem;
border-top: 1px solid var(--border-color);
color: var(--terminal-tool, #c084fc);
font-family: monospace;
font-size: 0.875rem;
font-style: italic;
line-height: 1.5;
white-space: pre-wrap;
word-break: break-word;
}
</style>