feat: Implement inline grouping for TuiLine components within TuiGroup, enhancing layout and music player UI.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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%;
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user