Files
mule-image/web/src/lib/components/layout/KebabMenu.svelte
dtoro 8c2526d982 feat: PhotoPrism M0 bring-up — compose stack, web client, sidecar, migrate
Replace the legacy mule-image backend with PhotoPrism plus a thin
SvelteKit client and a Node sidecar for endpoints PhotoPrism doesn't
expose (file rename), and add a two-phase migrator (metadata via PUT,
heaps → albums) for the existing Postgres library.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 16:06:58 +02:00

57 lines
1.8 KiB
Svelte

<!--
Thin wrapper around bits-ui's DM. Provides:
- A round ⋯ trigger button styled like the rest of the sidebar's hover
affordances (muted, becomes accent on hover/open).
- A portal-positioned content container with shadcn-zinc styling.
- An `Item` re-export consumers compose into the menu body so we don't
also have to redeclare the item styling at every call site.
Items are passed as a snippet via `children` so callers can mix the
`Item` re-export, separators, or destructive variants freely.
-->
<script lang="ts" module>
import { DropdownMenu as DM } from 'bits-ui';
export const Item = DM.Item;
export const Separator = DM.Separator;
</script>
<script lang="ts">
import { MoreHorizontal } from 'lucide-svelte';
interface Props {
/** Tooltip + aria-label for the trigger button. */
label?: string;
/** Force the trigger visible regardless of hover state. Used when
* the menu is open so it doesn't disappear underneath a row hover
* transition while the user is interacting with it. */
alwaysVisible?: boolean;
children: import('svelte').Snippet;
}
let { label = 'More', alwaysVisible = false, children }: Props = $props();
let open = $state(false);
</script>
<DM.Root bind:open>
<DM.Trigger
class="rounded p-0.5 text-xs text-muted-foreground transition-opacity hover:bg-accent hover:text-foreground focus:outline-none {open ||
alwaysVisible
? 'opacity-100'
: 'opacity-0 group-hover:opacity-100'}"
title={label}
aria-label={label}
onclick={(e) => e.stopPropagation()}
>
<MoreHorizontal class="h-3.5 w-3.5" />
</DM.Trigger>
<DM.Portal>
<DM.Content
class="z-50 min-w-[180px] overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md outline-none"
sideOffset={4}
align="end"
>
{@render children()}
</DM.Content>
</DM.Portal>
</DM.Root>