show the stack icon and name in stack action popups

This commit is contained in:
Jarek Krochmalski committed 2026-09-13 14:50:02 +02:00
1 parent fb37d931ae
commit 968fea0230
5 files changed
+29 -16

No files matched your search

+6 -2
View File
@@ -22,6 +22,8 @@
onOpenChange?: (open: boolean) => void;
children: Snippet<[{ open: boolean }]>;
extraContent?: Snippet;
/** Optional leading glyph rendered before the confirm text (e.g. a stack icon). */
icon?: Snippet;
}
let {
@@ -39,7 +41,8 @@
onConfirm,
onOpenChange,
children,
extraContent
extraContent,
icon
}: Props = $props();
const triggerClass = $derived(unstyled
@@ -109,7 +112,8 @@
>
<div class="flex flex-col gap-1.5">
<div class="flex items-center gap-2">
<span class="text-xs whitespace-nowrap">{action} {itemType} {#if displayName}<strong>{displayName}</strong>{/if}?</span>
{#if icon}{@render icon()}{/if}
<span class="text-xs whitespace-nowrap">{action} {itemType} {#if displayName}<strong class="font-semibold text-foreground">{displayName}</strong>{/if}?</span>
<Button size="sm" {variant} class="h-6 px-2 text-xs" onclick={handleConfirm}>
{confirmText}
</Button>
+7 -3
View File
@@ -1,5 +1,5 @@
<script lang="ts">
import { Box } from 'lucide-svelte';
import { Box, Layers } from 'lucide-svelte';
import { getStackIconComponent, isSelfhstIcon, selfhstRef, isCustomIcon } from '$lib/utils/icons';
import { selfhstIcons, requestSelfhst } from '$lib/stores/selfhst-icons';
@@ -23,8 +23,12 @@
const selfhst = $derived(selfhstRef(icon));
const custom = $derived(isCustomIcon(icon));
// Lucide is the fallback for any non-selfhst, non-custom value (incl. null).
const LucideIcon = $derived(!isSelfhstIcon(icon) && !custom ? getStackIconComponent(icon || '') : null);
// A named lucide icon resolves via the map; an EMPTY/null value falls back to Layers -
// the generic stack glyph used everywhere else in the stacks UI (page header, tiles,
// list). getStackIconComponent's own default is Boxes, which reads as a different icon.
const LucideIcon = $derived(
!isSelfhstIcon(icon) && !custom ? (icon ? getStackIconComponent(icon) : Layers) : null
);
// Resolve the selfh.st icon via the shared batch store (one request for the whole
// list) instead of a per-icon <img src>. `resolved`: data URI when ready, '' when it
+4 -1
View File
@@ -4,6 +4,7 @@
import { Checkbox } from '$lib/components/ui/checkbox';
import { Trash2, Folder, Database, Loader2, ArrowRight } from 'lucide-svelte';
import GitGenericIcon from '$lib/components/icons/GitGenericIcon.svelte';
import StackIcon from '$lib/components/StackIcon.svelte';
import { appendEnvParam } from '$lib/stores/environment';
// The parent owns the fetch; onConfirm receives what the user chose to remove.
@@ -11,11 +12,13 @@
open = $bindable(false),
stackName = '',
envId = null as number | null,
stackIcon = null as string | null,
onConfirm,
}: {
open?: boolean;
stackName?: string;
envId?: number | null;
stackIcon?: string | null;
onConfirm: (opts: { deleteFiles: boolean; deleteVolumes: boolean }) => void | Promise<void>;
} = $props();
@@ -90,7 +93,7 @@
<Dialog.Content class="max-w-2xl">
<Dialog.Header>
<Dialog.Title class="flex items-center gap-2">
<Trash2 class="w-5 h-5 text-destructive" />
<StackIcon icon={stackIcon} {stackName} {envId} class="w-5 h-5 shrink-0 text-muted-foreground" />
Remove stack "{stackName}"
</Dialog.Title>
<Dialog.Description>
+3 -8
View File
@@ -1,5 +1,5 @@
<script lang="ts">
import { Loader2, CheckCircle2, XCircle, Rocket, Layers } from 'lucide-svelte';
import { Loader2, CheckCircle2, XCircle, Rocket } from 'lucide-svelte';
import StackIcon from '$lib/components/StackIcon.svelte';
import EnvironmentIcon from '$lib/components/EnvironmentIcon.svelte';
import { environments } from '$lib/stores/environment';
@@ -13,8 +13,7 @@
// The action word, e.g. "Bringing down" or "Git deploy".
verb: string;
stackName?: string;
// Icon value (lucide/selfhst/custom). When unset, a generic Layers glyph shows --
// never StackIcon's Boxes fallback, which reads as a different icon.
// Icon value (lucide/selfhst/custom). When unset, StackIcon shows the generic Layers glyph.
stackIcon?: string | null;
envId?: number | null;
// Drives the leading icon. 'idle' shows a rocket (a not-yet-started deploy prompt).
@@ -41,11 +40,7 @@
{/if}
<span class="shrink-0 font-medium">{verb}</span>
{#if stackName}
{#if stackIcon}
<StackIcon icon={stackIcon} {stackName} {envId} class="{iconClass} shrink-0 text-muted-foreground" />
{:else}
<Layers class="{iconClass} shrink-0 text-muted-foreground" />
{/if}
<StackIcon icon={stackIcon} {stackName} {envId} class="{iconClass} shrink-0 text-muted-foreground" />
<span class="truncate font-medium">{stackName}</span>
{/if}
{#if env}
+9 -2
View File
@@ -6,10 +6,13 @@
import { Loader2 } from 'lucide-svelte';
import type { Snippet } from 'svelte';
import { cn } from '$lib/utils';
import StackIcon from '$lib/components/StackIcon.svelte';
interface Props {
stackName: string;
envId: number | null;
/** The stack's icon value (custom/selfhst/lucide/null); shown in the header. */
stackIcon?: string | null;
disabled?: boolean;
side?: 'top' | 'bottom';
align?: 'start' | 'center' | 'end';
@@ -47,6 +50,7 @@
let {
stackName,
envId,
stackIcon = null,
disabled = false,
side = 'top',
align = 'end',
@@ -110,13 +114,16 @@
{/snippet}
</Popover.Trigger>
<Popover.Content
class="w-56 p-3 z-[200]"
class="w-72 p-3 z-[200]"
{side}
{align}
sideOffset={8}
>
<div class="space-y-3">
<p class="text-xs font-medium">Redeploy stack</p>
<p class="flex items-center gap-1.5 text-xs text-muted-foreground">
<StackIcon icon={stackIcon} {stackName} {envId} class="w-4 h-4 shrink-0" />
<span class="truncate">Redeploy stack <strong class="font-semibold text-foreground">{stackName}</strong></span>
</p>
<div class="space-y-2">
<label class="flex items-center gap-2 cursor-pointer">
<Checkbox bind:checked={pull} disabled={deploying} />