Reset-Button, Service-Reorder, Port/HTTPS-Spalten, Healthcheck in Sidebar, Kategorien-Sync

This commit is contained in:
2026-07-19 15:14:44 +02:00
parent 20ea4d382d
commit fc1ea4fa70
16 changed files with 447 additions and 20 deletions

View File

@@ -0,0 +1,47 @@
import type { Service } from "@launchpad/shared";
export interface FavoritesBarProps {
services: Service[];
onOpen: (service: Service) => void;
}
/**
* Zeigt Favoriten als anklickbare Chips immer sichtbar, unabhängig vom
* Suchfeld. Reihenfolge folgt service.order (im Adminbereich per Drag & Drop
* änderbar).
*/
export function FavoritesBar({ services, onOpen }: FavoritesBarProps) {
if (services.length === 0) return null;
return (
<div
role="toolbar"
aria-label="Favoriten"
className="flex flex-wrap items-center justify-center gap-2"
>
{services.map((service) => (
<button
key={service.id}
type="button"
onClick={() => onOpen(service)}
title={`${service.displayName} (${service.hostname}:${service.port})`}
className="flex items-center gap-2 rounded-full border border-black/10 bg-white/70
px-3 py-1.5 text-sm text-black transition-colors hover:bg-black/5
dark:border-white/10 dark:bg-white/5 dark:text-white dark:hover:bg-white/10"
>
{service.favicon ? (
<img src={service.favicon} alt="" className="h-4 w-4 shrink-0 rounded" />
) : (
<span
className="flex h-4 w-4 shrink-0 items-center justify-center rounded-full
bg-black/10 text-[9px] font-medium text-black/50 dark:bg-white/10 dark:text-white/50"
>
{service.displayName.charAt(0).toUpperCase()}
</span>
)}
<span className="max-w-[10rem] truncate">{service.displayName}</span>
</button>
))}
</div>
);
}

View File

@@ -9,3 +9,6 @@ export type { ResultsListProps } from "./ResultsList.js";
export { Button } from "./Button.js";
export type { ButtonProps } from "./Button.js";
export { FavoritesBar } from "./FavoritesBar.js";
export type { FavoritesBarProps } from "./FavoritesBar.js";