Bug Fixes and Formatting Update

This commit is contained in:
2025-11-28 05:13:49 +00:00
parent c61cb39475
commit 88b068a2b5
18 changed files with 863 additions and 199 deletions
+158 -66
View File
@@ -22,79 +22,137 @@
export let onLinkClick: (idx: number) => void;
export let terminalSettings: any;
// Group displayed lines into regular items and inline groups
type GroupedItem =
| { type: 'single'; index: number; displayed: DisplayedLine }
| { type: 'inline-group'; indices: number[]; items: DisplayedLine[] };
$: groupedLines = (() => {
const result: GroupedItem[] = [];
let i = 0;
while (i < displayedLines.length) {
const displayed = displayedLines[i];
const line = displayed.parsed.line;
if (line.inline) {
// Start an inline group
const group: GroupedItem = { type: 'inline-group', indices: [], items: [] };
while (i < displayedLines.length && displayedLines[i].parsed.line.inline) {
group.indices.push(i);
group.items.push(displayedLines[i]);
i++;
}
result.push(group);
} else {
result.push({ type: 'single', index: i, displayed });
i++;
}
}
return result;
})();
</script>
<div class="tui-body" bind:this={ref}>
{#each displayedLines as { parsed, charIndex, complete, showImage }, i}
{@const line = parsed.line}
{@const visibleSegments = getSegmentsUpToChar(parsed.segments, charIndex)}
{#if line.type === 'divider'}
<div class="tui-divider">
<span class="divider-line"></span>
{#if line.content}
<span class="divider-text">{line.content}</span>
{/if}
<span class="divider-line"></span>
{#each groupedLines as group}
{#if group.type === 'inline-group'}
<!-- Inline group container -->
<div class="tui-inline-group">
{#each group.items as displayed, j}
{@const line = displayed.parsed.line}
{@const idx = group.indices[j]}
{@const visibleSegments = getSegmentsUpToChar(displayed.parsed.segments, displayed.charIndex)}
{#if line.type === 'button'}
<TuiButton {line} index={idx} selected={selectedIndex === idx} onClick={onButtonClick} onHover={onHoverButton} inline={true} />
{:else if line.type === 'link'}
<TuiLink {line} onClick={() => onLinkClick(idx)} />
{:else if line.type === 'tooltip'}
<TuiTooltip {line} />
{:else if line.type === 'progress'}
<TuiProgress {line} inline={true} />
{:else}
<span class="inline-content {line.type}">
{getLinePrefix(line.type)}{#each visibleSegments as segment}{#if segment.icon}<Icon icon={segment.icon} width="14" class="inline-icon" />{:else if getSegmentStyle(segment)}<span style={getSegmentStyle(segment)}>{segment.text}</span>{:else}{segment.text}{/if}{/each}
</span>
{/if}
{/each}
</div>
{:else if line.type === 'button'}
<TuiButton {line} index={i} selected={selectedIndex === i} onClick={onButtonClick} onHover={onHoverButton} />
{:else if line.type === 'link'}
<div class="tui-line link">
<TuiLink {line} onClick={() => onLinkClick(i)} />
</div>
{:else if line.type === 'card'}
<TuiCard {line} />
{:else if line.type === 'cardgrid'}
<TuiCardGrid {line} />
{:else if line.type === 'progress'}
<TuiProgress {line} />
{:else if line.type === 'accordion'}
<TuiAccordion {line} />
{:else if line.type === 'table'}
<TuiTable {line} />
{:else if line.type === 'tooltip'}
<div class="tui-line">
<TuiTooltip {line} />
</div>
{:else}
<div class="tui-line {line.type}" class:complete>
{#if line.type === 'command' || line.type === 'prompt'}
<span class="prompt">
<span class="user">{user.username}</span><span class="at">@</span><span class="host">{user.hostname}</span>
<span class="separator">:</span><span class="path">~</span><span class="symbol">$</span>
</span>
{/if}
{:else if group.type === 'single'}
{@const i = group.index}
{@const displayed = group.displayed}
{@const line = displayed.parsed.line}
{@const visibleSegments = getSegmentsUpToChar(displayed.parsed.segments, displayed.charIndex)}
{@const complete = displayed.complete}
{@const showImage = displayed.showImage}
{#if line.type === 'divider'}
<div class="tui-divider" id={line.id}>
<span class="divider-line"></span>
{#if line.content}
<span class="divider-text">{line.content}</span>
{/if}
<span class="divider-line"></span>
</div>
{:else if line.type === 'button'}
<TuiButton {line} index={i} selected={selectedIndex === i} onClick={onButtonClick} onHover={onHoverButton} />
{:else if line.type === 'link'}
<div class="tui-line link">
<TuiLink {line} onClick={() => onLinkClick(i)} />
</div>
{:else if line.type === 'card'}
<TuiCard {line} />
{:else if line.type === 'cardgrid'}
<TuiCardGrid {line} />
{:else if line.type === 'progress'}
<TuiProgress {line} />
{:else if line.type === 'accordion'}
<TuiAccordion {line} />
{:else if line.type === 'table'}
<TuiTable {line} />
{:else if line.type === 'tooltip'}
<div class="tui-line">
<TuiTooltip {line} />
</div>
{:else}
<div class="tui-line {line.type}" class:complete id={line.id}>
{#if line.type === 'command' || line.type === 'prompt'}
<span class="prompt">
<span class="user">{user.username}</span><span class="at">@</span><span class="host">{user.hostname}</span>
<span class="separator">:</span><span class="path">~</span><span class="symbol">$</span>
</span>
{/if}
{#if line.type === 'image' && showImage}
<div class="tui-image">
<img src={line.image} alt={line.imageAlt || 'Image'} style="max-width: {line.imageWidth || 300}px" />
{#if line.content}
<span class="image-caption">{line.content}</span>
{/if}
</div>
{:else if line.type === 'header'}
<span class="content header-text">
<Icon icon="mdi:pound" width="14" class="header-icon" />
{#each visibleSegments as segment}
{#if segment.icon}
<Icon icon={segment.icon} width="16" class="inline-icon" />
{:else if getSegmentStyle(segment)}
<span style={getSegmentStyle(segment)}>{segment.text}</span>
{:else}
{segment.text}
{#if line.type === 'image' && showImage}
<div class="tui-image">
<img src={line.image} alt={line.imageAlt || 'Image'} style="max-width: {line.imageWidth || 300}px" />
{#if line.content}
<span class="image-caption">{line.content}</span>
{/if}
{/each}
</span>
{:else if line.type !== 'blank'}
<span class="content">
{getLinePrefix(line.type)}{#each visibleSegments as segment}{#if segment.icon}<Icon icon={segment.icon} width="14" class="inline-icon" />{:else if getSegmentStyle(segment)}<span style={getSegmentStyle(segment)}>{segment.text}</span>{:else}{segment.text}{/if}{/each}
</span>
{/if}
</div>
{:else if line.type === 'header'}
<span class="content header-text">
<Icon icon="mdi:pound" width="14" class="header-icon" />
{#each visibleSegments as segment}
{#if segment.icon}
<Icon icon={segment.icon} width="16" class="inline-icon" />
{:else if getSegmentStyle(segment)}
<span style={getSegmentStyle(segment)}>{segment.text}</span>
{:else}
{segment.text}
{/if}
{/each}
</span>
{:else if line.type !== 'blank'}
<span class="content">
{getLinePrefix(line.type)}{#each visibleSegments as segment}{#if segment.icon}<Icon icon={segment.icon} width="14" class="inline-icon" />{:else if getSegmentStyle(segment)}<span style={getSegmentStyle(segment)}>{segment.text}</span>{:else}{segment.text}{/if}{/each}
</span>
{/if}
{#if terminalSettings.showCursor && i === currentLineIndex && !complete && isTyping && line.type !== 'image' && line.type !== 'blank'}
<span class="cursor"></span>
{/if}
</div>
{#if terminalSettings.showCursor && i === currentLineIndex && !complete && isTyping && line.type !== 'image' && line.type !== 'blank'}
<span class="cursor"></span>
{/if}
</div>
{/if}
{/if}
{/each}
@@ -120,6 +178,40 @@
min-height: 0;
}
/* Inline group wrapper - groups consecutive inline elements */
.tui-inline-group {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-bottom: 0.2rem;
animation: lineSlideIn 0.15s ease-out;
}
.inline-content {
display: inline;
white-space: pre-wrap;
}
.inline-content.output {
color: var(--terminal-muted);
}
.inline-content.info {
color: var(--terminal-primary);
}
.inline-content.success {
color: #a6e3a1;
}
.inline-content.error {
color: #f38ba8;
}
.inline-content.warning {
color: #f9e2af;
}
/* Lines */
.tui-line {
display: flex;