feat(electrobun): diamonds, footer icons, gapless timeline
- Timeline dots → diamonds (rotated 45deg squares) - Timeline lines: split into up/down segments, no gaps - First message: no line up. Last: no line down. - Footer icons: upload file, add context, browse web, slash commands - Context state indicator (clock icon) - Send button: paper plane icon (was arrow-up) - Model label moved right (before divider)
This commit is contained in:
parent
8248d465df
commit
9a1195a964
6 changed files with 121 additions and 72 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -4,8 +4,8 @@
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Svelte App</title>
|
<title>Svelte App</title>
|
||||||
<script type="module" crossorigin src="/assets/index-8IlHjlDZ.js"></script>
|
<script type="module" crossorigin src="/assets/index-DioorjbE.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-yFiSNunC.css">
|
<link rel="stylesheet" crossorigin href="/assets/index--nz-Qfge.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
|
|
||||||
|
|
@ -108,25 +108,27 @@
|
||||||
<div class="agent-pane" bind:this={agentPaneEl}>
|
<div class="agent-pane" bind:this={agentPaneEl}>
|
||||||
<!-- Scroll area -->
|
<!-- Scroll area -->
|
||||||
<div class="messages-scroll" bind:this={scrollEl}>
|
<div class="messages-scroll" bind:this={scrollEl}>
|
||||||
{#each messages as msg (msg.id)}
|
{#each messages as msg, idx (msg.id)}
|
||||||
|
{@const isFirst = idx === 0}
|
||||||
|
{@const isLast = idx === messages.length - 1}
|
||||||
|
{@const isTimeline = msg.role !== 'user'}
|
||||||
<div class="msg-row msg-animated">
|
<div class="msg-row msg-animated">
|
||||||
{#if msg.role === 'user'}
|
{#if msg.role === 'user'}
|
||||||
<!-- Left-aligned inline block -->
|
|
||||||
<div class="user-bubble">{msg.content}</div>
|
<div class="user-bubble">{msg.content}</div>
|
||||||
|
|
||||||
{:else if msg.role === 'assistant'}
|
{:else if msg.role === 'assistant'}
|
||||||
<!-- Timeline pattern -->
|
|
||||||
<div class="timeline-row">
|
<div class="timeline-row">
|
||||||
<div class="timeline-line"></div>
|
{#if !isFirst}<div class="timeline-line-up"></div>{/if}
|
||||||
<div class="timeline-dot dot-success"></div>
|
<div class="timeline-diamond dot-success"></div>
|
||||||
|
{#if !isLast}<div class="timeline-line-down"></div>{/if}
|
||||||
<div class="timeline-content">{msg.content}</div>
|
<div class="timeline-content">{msg.content}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{:else if msg.role === 'tool-call'}
|
{:else if msg.role === 'tool-call'}
|
||||||
<!-- Flat bordered tool box -->
|
|
||||||
<div class="timeline-row">
|
<div class="timeline-row">
|
||||||
<div class="timeline-line"></div>
|
{#if !isFirst}<div class="timeline-line-up"></div>{/if}
|
||||||
<div class="timeline-dot dot-progress"></div>
|
<div class="timeline-diamond dot-progress"></div>
|
||||||
|
{#if !isLast}<div class="timeline-line-down"></div>{/if}
|
||||||
<div class="tool-box">
|
<div class="tool-box">
|
||||||
<div class="tool-header">
|
<div class="tool-header">
|
||||||
<span class="tool-name">{msg.toolName ?? 'Tool'}</span>
|
<span class="tool-name">{msg.toolName ?? 'Tool'}</span>
|
||||||
|
|
@ -153,8 +155,9 @@
|
||||||
|
|
||||||
{:else if msg.role === 'tool-result'}
|
{:else if msg.role === 'tool-result'}
|
||||||
<div class="timeline-row">
|
<div class="timeline-row">
|
||||||
<div class="timeline-line"></div>
|
{#if !isFirst}<div class="timeline-line-up"></div>{/if}
|
||||||
<div class="timeline-dot dot-success"></div>
|
<div class="timeline-diamond dot-success"></div>
|
||||||
|
{#if !isLast}<div class="timeline-line-down"></div>{/if}
|
||||||
<div class="tool-box tool-result-box">
|
<div class="tool-box tool-result-box">
|
||||||
<div class="tool-grid">
|
<div class="tool-grid">
|
||||||
<span class="tool-col-label">result</span>
|
<span class="tool-col-label">result</span>
|
||||||
|
|
@ -306,22 +309,33 @@
|
||||||
padding-left: 1.875rem; /* 30px */
|
padding-left: 1.875rem; /* 30px */
|
||||||
}
|
}
|
||||||
|
|
||||||
.timeline-line {
|
/* Line segments: up (above diamond) and down (below diamond) — no gaps */
|
||||||
|
.timeline-line-up {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 12px;
|
left: 12px;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
height: 14px; /* stops at diamond top */
|
||||||
|
width: 1px;
|
||||||
|
background: var(--ctp-surface0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-line-down {
|
||||||
|
position: absolute;
|
||||||
|
left: 12px;
|
||||||
|
top: 22px; /* starts at diamond bottom (15px + 7px) */
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
width: 1px;
|
width: 1px;
|
||||||
background: var(--ctp-surface0);
|
background: var(--ctp-surface0);
|
||||||
}
|
}
|
||||||
|
|
||||||
.timeline-dot {
|
/* Diamond marker (rotated square) */
|
||||||
|
.timeline-diamond {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 9px;
|
left: 9px;
|
||||||
top: 15px;
|
top: 14px;
|
||||||
width: 7px;
|
width: 7px;
|
||||||
height: 7px;
|
height: 7px;
|
||||||
border-radius: 50%;
|
transform: rotate(45deg);
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,17 +43,44 @@
|
||||||
></textarea>
|
></textarea>
|
||||||
|
|
||||||
<div class="footer-strip">
|
<div class="footer-strip">
|
||||||
<!-- Left: attach + model -->
|
<!-- Left: action buttons -->
|
||||||
<button class="footer-btn attach-btn" aria-label="Attach file" title="Attach">
|
<!-- Upload file -->
|
||||||
<svg width="14" height="14" viewBox="0 0 16 16" fill="none" aria-hidden="true">
|
<button class="footer-btn" aria-label="Upload file" title="Upload from computer">
|
||||||
<path d="M3 8l5-5a3.5 3.5 0 015 5l-6 6a2 2 0 01-3-3l5-5a.5.5 0 01.7.7L5 11.3a1 1 0 001.4 1.4l6-6a2.5 2.5 0 00-3.5-3.5L3.7 8.7" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/>
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||||
|
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<!-- Add context -->
|
||||||
|
<button class="footer-btn" aria-label="Add context" title="Add context">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||||
|
<rect x="3" y="3" width="18" height="18" rx="2"/><line x1="12" y1="8" x2="12" y2="16"/><line x1="8" y1="12" x2="16" y2="12"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<!-- Browse web -->
|
||||||
|
<button class="footer-btn" aria-label="Browse the web" title="Browse the web">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||||
|
<circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<!-- Slash commands -->
|
||||||
|
<button class="footer-btn" aria-label="Slash commands" title="Slash commands (/)">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" aria-hidden="true">
|
||||||
|
<line x1="7" y1="20" x2="17" y2="4"/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<span class="model-label">{model}</span>
|
|
||||||
|
|
||||||
<!-- Right: divider + send -->
|
<!-- Context state indicator -->
|
||||||
|
<span class="context-indicator" title="Context window usage">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||||
|
<circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
|
||||||
<span class="footer-spacer"></span>
|
<span class="footer-spacer"></span>
|
||||||
|
<span class="model-label">{model}</span>
|
||||||
<span class="footer-divider" aria-hidden="true"></span>
|
<span class="footer-divider" aria-hidden="true"></span>
|
||||||
|
|
||||||
|
<!-- Send button — paper plane icon -->
|
||||||
<button
|
<button
|
||||||
class="send-btn"
|
class="send-btn"
|
||||||
onclick={onSend}
|
onclick={onSend}
|
||||||
|
|
@ -61,8 +88,9 @@
|
||||||
aria-label="Send message"
|
aria-label="Send message"
|
||||||
title="Send (Enter)"
|
title="Send (Enter)"
|
||||||
>
|
>
|
||||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" aria-hidden="true">
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
||||||
<path d="M10 15V5M10 5L6 9M10 5l4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
|
<path d="M22 2L11 13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M22 2L15 22L11 13L2 9L22 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -144,6 +172,13 @@
|
||||||
max-width: 8rem;
|
max-width: 8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.context-indicator {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--ctp-overlay0);
|
||||||
|
padding: 0.125rem;
|
||||||
|
}
|
||||||
|
|
||||||
.footer-spacer { flex: 1; }
|
.footer-spacer { flex: 1; }
|
||||||
|
|
||||||
.footer-divider {
|
.footer-divider {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue