TUI Renderer, Element Types, and Page Updates
This commit is contained in:
@@ -1,34 +1,55 @@
|
||||
<script lang="ts">
|
||||
import Icon from '@iconify/svelte';
|
||||
import { getButtonStyle, parseColorText, getSegmentStyle } from './utils';
|
||||
import { themeColors } from '$lib/stores/theme';
|
||||
import type { TerminalLine } from './types';
|
||||
import '$lib/assets/css/tui-accordion.css';
|
||||
import Icon from "@iconify/svelte";
|
||||
import { getButtonStyle, parseColorText, getSegmentStyle } from "./utils";
|
||||
import { themeColors } from "$lib/stores/theme";
|
||||
import type { AccordionLine } from "./types";
|
||||
import TuiLine from "./TuiLine.svelte";
|
||||
import "$lib/assets/css/tui-accordion.css";
|
||||
|
||||
export let line: TerminalLine;
|
||||
|
||||
let openItems: Set<number> = new Set(line.accordionOpen ? [0] : []);
|
||||
|
||||
function toggleItem(index: number) {
|
||||
if (openItems.has(index)) {
|
||||
openItems.delete(index);
|
||||
} else {
|
||||
openItems.add(index);
|
||||
}
|
||||
openItems = openItems; // trigger reactivity
|
||||
interface Props {
|
||||
line: AccordionLine;
|
||||
inline?: boolean;
|
||||
}
|
||||
|
||||
$: items = line.accordionItems || [{ title: line.content, content: '' }];
|
||||
let { line, inline = false }: Props = $props();
|
||||
|
||||
let openItems = $state(new Set(line.accordionOpen ? [0] : []));
|
||||
|
||||
function toggleItem(index: number) {
|
||||
const newSet = new Set(openItems);
|
||||
if (newSet.has(index)) {
|
||||
newSet.delete(index);
|
||||
} else {
|
||||
newSet.add(index);
|
||||
}
|
||||
openItems = newSet;
|
||||
}
|
||||
|
||||
const items = $derived(
|
||||
line.accordionItems || [{ title: line.content, content: "" }],
|
||||
);
|
||||
const isSingleItemMode = $derived(
|
||||
!line.accordionItems && line.children && line.children.length > 0,
|
||||
);
|
||||
</script>
|
||||
|
||||
<div class="tui-accordion" style="--accordion-accent: {getButtonStyle(line.style)}">
|
||||
<div
|
||||
class="tui-accordion"
|
||||
class:inline
|
||||
style="--accordion-accent: {getButtonStyle(line.style)}"
|
||||
>
|
||||
{#each items as item, i}
|
||||
{@const contentSegments = parseColorText(item.content, $themeColors.colorMap)}
|
||||
{@const contentSegments = parseColorText(
|
||||
item.content,
|
||||
$themeColors.colorMap,
|
||||
)}
|
||||
<div class="accordion-item" class:open={openItems.has(i)}>
|
||||
<button class="accordion-header" on:click={() => toggleItem(i)}>
|
||||
<Icon
|
||||
icon={openItems.has(i) ? 'mdi:chevron-down' : 'mdi:chevron-right'}
|
||||
width="16"
|
||||
<button class="accordion-header" onclick={() => toggleItem(i)}>
|
||||
<Icon
|
||||
icon={openItems.has(i)
|
||||
? "mdi:chevron-down"
|
||||
: "mdi:chevron-right"}
|
||||
width="16"
|
||||
class="accordion-icon"
|
||||
/>
|
||||
<span class="accordion-title">{item.title}</span>
|
||||
@@ -37,11 +58,33 @@
|
||||
<div class="accordion-content">
|
||||
{#each contentSegments as segment}
|
||||
{#if getSegmentStyle(segment)}
|
||||
<span style={getSegmentStyle(segment)}>{segment.text}</span>
|
||||
<span style={getSegmentStyle(segment)}
|
||||
>{segment.text}</span
|
||||
>
|
||||
{:else}
|
||||
{segment.text}
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
{#if isSingleItemMode && line.children}
|
||||
<div
|
||||
class="accordion-children"
|
||||
class:flex={line.display === "flex"}
|
||||
class:grid={line.display === "grid"}
|
||||
>
|
||||
{#each line.children as child, k}
|
||||
<TuiLine
|
||||
line={child}
|
||||
index={k}
|
||||
segments={parseColorText(child.content)}
|
||||
complete={true}
|
||||
showImage={true}
|
||||
selectedIndex={-1}
|
||||
inline={false}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -108,6 +151,25 @@
|
||||
animation: slideDown 0.2s ease-out;
|
||||
}
|
||||
|
||||
.accordion-children {
|
||||
margin-top: 0.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.accordion-children.flex {
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.accordion-children.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
|
||||
Reference in New Issue
Block a user