feat: Implement inline grouping for TuiLine components within TuiGroup, enhancing layout and music player UI.

This commit is contained in:
2025-12-01 09:10:55 +00:00
parent 84056824b5
commit 436e0a5910
5 changed files with 150 additions and 55 deletions

View File

@@ -24,7 +24,8 @@
align-items: flex-start; align-items: flex-start;
} }
.tui-inline-group:has(.inline-image) .inline-content { .tui-inline-group:has(.inline-image) .inline-content,
.tui-inline-group:has(.inline-image) .tui-group {
flex: 1; flex: 1;
min-width: 0; min-width: 0;
} }

View File

@@ -94,9 +94,7 @@
<span class="card-title"> <span class="card-title">
{#each titleSegments as segment} {#each titleSegments as segment}
{#if getSegmentStyle(segment)} {#if getSegmentStyle(segment)}
<span style={getSegmentStyle(segment)} <span style={getSegmentStyle(segment)}>{segment.text}</span>
>{segment.text}</span
>
{:else} {:else}
{segment.text} {segment.text}
{/if} {/if}
@@ -107,11 +105,7 @@
<div class="card-body"> <div class="card-body">
{#if line.image} {#if line.image}
<img <img src={line.image} alt={line.imageAlt || ""} class="card-image" />
src={line.image}
alt={line.imageAlt || ""}
class="card-image"
/>
{/if} {/if}
<div class="card-content"> <div class="card-content">
{#each segments as segment} {#each segments as segment}
@@ -249,7 +243,10 @@
.card-children.grid { .card-children.grid {
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); grid-template-columns: repeat(
auto-fill,
minmax(max(200px, calc((100% - 5rem) / 6)), 1fr)
);
gap: 1rem; gap: 1rem;
} }

View File

@@ -31,6 +31,47 @@
}), }),
); );
// Group consecutive inline elements
const processedChildren = $derived.by(() => {
const groups: Array<
| { kind: "single"; index: number; line: TerminalLine }
| {
kind: "inline";
items: Array<{ index: number; line: TerminalLine }>;
}
> = [];
let i = 0;
while (i < parsedChildren.length) {
const child = parsedChildren[i];
const isInline = child.line.inline || child.line.display === "inline";
if (isInline) {
const inlineItems: Array<{
index: number;
line: TerminalLine;
}> = [];
while (i < parsedChildren.length) {
const nextChild = parsedChildren[i];
const nextIsInline =
nextChild.line.inline || nextChild.line.display === "inline";
if (!nextIsInline) break;
inlineItems.push({
index: i,
line: nextChild.line,
});
i++;
}
groups.push({ kind: "inline", items: inlineItems });
} else {
groups.push({ kind: "single", index: i, line: child.line });
i++;
}
}
return groups;
});
// Style for the group container // Style for the group container
const groupStyle = $derived(() => { const groupStyle = $derived(() => {
const styles: string[] = []; const styles: string[] = [];
@@ -64,21 +105,40 @@
style={groupStyle()} style={groupStyle()}
id={line.id} id={line.id}
> >
{#each parsedChildren as parsed, idx (idx)} {#each processedChildren as group}
{#if group.kind === "inline"}
<div class="tui-inline-group">
{#each group.items as item}
<TuiLine <TuiLine
line={parsed.line} line={item.line}
index={idx} index={item.index}
segments={parsed.segments} segments={parseColorText(item.line.content)}
complete={true} complete={true}
showImage={parsed.line.type === "image"} showImage={item.line.type === "image"}
selectedIndex={-1} selectedIndex={-1}
inline={parsed.line.inline !== false} inline={true}
{onButtonClick} {onButtonClick}
{onHoverButton} {onHoverButton}
{onLinkClick} {onLinkClick}
/> />
{/each} {/each}
</div> </div>
{:else}
<TuiLine
line={group.line}
index={group.index}
segments={parseColorText(group.line.content)}
complete={true}
showImage={group.line.type === "image"}
selectedIndex={-1}
inline={false}
{onButtonClick}
{onHoverButton}
{onLinkClick}
/>
{/if}
{/each}
</div>
<style> <style>
.tui-group { .tui-group {
@@ -95,7 +155,10 @@
.tui-group.grid { .tui-group.grid {
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); grid-template-columns: repeat(
auto-fill,
minmax(max(200px, calc((100% - 3.75rem) / 6)), 1fr)
);
width: 100%; width: 100%;
} }

View File

@@ -138,7 +138,7 @@
<img <img
src={line.image} src={line.image}
alt={line.imageAlt || "Image"} alt={line.imageAlt || "Image"}
style="max-width: {line.imageWidth || 300}px" style="width: {line.imageWidth + "px" || "100%"}"
/> />
{#if line.content}<span class="image-caption">{line.content}</span>{/if} {#if line.content}<span class="image-caption">{line.content}</span>{/if}
</div> </div>

View File

@@ -74,6 +74,28 @@
const song = songs[currentSongIndex]; const song = songs[currentSongIndex];
terminal.updateById("music-player", { terminal.updateById("music-player", {
children: [
{
type: "image",
content: "",
image: song.thumbnail,
imageAlt: song.title,
inline: true,
imageWidth: 200,
},
{
type: "group",
content: "",
groupDirection: "column",
groupAlign: "stretch",
inline: true,
children: [
{
type: "group",
content: "",
groupDirection: "row",
groupAlign: "center",
inline: false,
children: [ children: [
{ {
type: "output", type: "output",
@@ -87,7 +109,15 @@
inline: true, inline: true,
external: true, external: true,
}, },
{ type: "blank", content: "" }, ]
},
{
type: "group",
content: "",
groupDirection: "row",
groupAlign: "center",
inline: false,
children: [
{ {
type: "output", type: "output",
content: `(&primary)Artist:(&)`, content: `(&primary)Artist:(&)`,
@@ -100,6 +130,8 @@
inline: true, inline: true,
external: true, external: true,
}, },
]
},
{ {
type: "progress", type: "progress",
content: "", content: "",
@@ -108,6 +140,8 @@
inline: false, inline: false,
progressStyle: "text", progressStyle: "text",
}, },
]
},
{ {
type: "group", type: "group",
content: "", content: "",