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;
}
.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;
min-width: 0;
}

View File

@@ -94,9 +94,7 @@
<span class="card-title">
{#each titleSegments as segment}
{#if getSegmentStyle(segment)}
<span style={getSegmentStyle(segment)}
>{segment.text}</span
>
<span style={getSegmentStyle(segment)}>{segment.text}</span>
{:else}
{segment.text}
{/if}
@@ -107,11 +105,7 @@
<div class="card-body">
{#if line.image}
<img
src={line.image}
alt={line.imageAlt || ""}
class="card-image"
/>
<img src={line.image} alt={line.imageAlt || ""} class="card-image" />
{/if}
<div class="card-content">
{#each segments as segment}
@@ -249,7 +243,10 @@
.card-children.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;
}

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
const groupStyle = $derived(() => {
const styles: string[] = [];
@@ -64,19 +105,38 @@
style={groupStyle()}
id={line.id}
>
{#each parsedChildren as parsed, idx (idx)}
<TuiLine
line={parsed.line}
index={idx}
segments={parsed.segments}
complete={true}
showImage={parsed.line.type === "image"}
selectedIndex={-1}
inline={parsed.line.inline !== false}
{onButtonClick}
{onHoverButton}
{onLinkClick}
/>
{#each processedChildren as group}
{#if group.kind === "inline"}
<div class="tui-inline-group">
{#each group.items as item}
<TuiLine
line={item.line}
index={item.index}
segments={parseColorText(item.line.content)}
complete={true}
showImage={item.line.type === "image"}
selectedIndex={-1}
inline={true}
{onButtonClick}
{onHoverButton}
{onLinkClick}
/>
{/each}
</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>
@@ -95,7 +155,10 @@
.tui-group.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%;
}

View File

@@ -138,7 +138,7 @@
<img
src={line.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}
</div>

View File

@@ -76,37 +76,71 @@
terminal.updateById("music-player", {
children: [
{
type: "output",
content: `(&primary)Now Playing:(&)`,
inline: true,
},
{
type: "link",
content: `(&blue)${song.title}(&)`,
href: song.url,
inline: true,
external: true,
},
{ type: "blank", content: "" },
{
type: "output",
content: `(&primary)Artist:(&)`,
inline: true,
},
{
type: "link",
content: `(&blue)${song.author}(&)`,
href: song.authorUrl,
inline: true,
external: true,
},
{
type: "progress",
type: "image",
content: "",
progress: progress,
progressLabel: `${formatTime(Math.floor((progress / 100) * parseDuration(song.duration || "0:00")))} / ${song.duration}`,
inline: false,
progressStyle: "text",
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: [
{
type: "output",
content: `(&primary)Now Playing:(&)`,
inline: true,
},
{
type: "link",
content: `(&blue)${song.title}(&)`,
href: song.url,
inline: true,
external: true,
},
]
},
{
type: "group",
content: "",
groupDirection: "row",
groupAlign: "center",
inline: false,
children: [
{
type: "output",
content: `(&primary)Artist:(&)`,
inline: true,
},
{
type: "link",
content: `(&blue)${song.author}(&)`,
href: song.authorUrl,
inline: true,
external: true,
},
]
},
{
type: "progress",
content: "",
progress: progress,
progressLabel: `${formatTime(Math.floor((progress / 100) * parseDuration(song.duration || "0:00")))} / ${song.duration}`,
inline: false,
progressStyle: "text",
},
]
},
{
type: "group",