feat(domains): Inline-Edit + Favicon in Settings + Filter IN Suchmaske
All checks were successful
Build & Publish Docker Image / build-and-push (push) Successful in 1m17s
All checks were successful
Build & Publish Docker Image / build-and-push (push) Successful in 1m17s
Domain-Admin-Seite bekommt jetzt ein Favicon-Icon vor jedem Eintrag, einen Pencil-Button zum Inline-Editieren von Domain und Anzeigename, und Save/Cancel-Buttons. Beim Ändern des Domain-Namens wird das Favicon zurückgesetzt und beim Speichern frisch nachgeladen (den Filter-Dropdown- Icons reicht der neue favicon_path automatisch zu). Der Filter-Button auf der Hauptseite sitzt jetzt IM weißen Suchfeld- Container (neuer .search-box-Wrapper mit Border) statt daneben, analog zum Referenz-Screenshot von rezeptwelt.de. Neue inline-Prop an SearchFilter schaltet eigenen Border/Background ab und setzt stattdessen einen vertikalen Divider nach rechts. - Neuer PATCH /api/domains/[id] mit zod-Schema. - Repository: updateDomain(id, patch) + getDomainById(id). domain-Change nullt favicon_path → Caller lädt neu. - Tests für updateDomain-Fälle und getDomainById. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,10 @@
|
||||
import { SlidersHorizontal, Check, ChevronDown } from 'lucide-svelte';
|
||||
import { searchFilterStore } from '$lib/client/search-filter.svelte';
|
||||
|
||||
// inline: Button wird transparent und ohne eigenen Border gestylt,
|
||||
// damit er sich in einen umgebenden Such-Container einpassen lässt.
|
||||
let { inline = false }: { inline?: boolean } = $props();
|
||||
|
||||
let open = $state(false);
|
||||
let container: HTMLElement | undefined = $state();
|
||||
|
||||
@@ -53,6 +57,7 @@
|
||||
<button
|
||||
class="trigger"
|
||||
class:filtered={searchFilterStore.isFiltered}
|
||||
class:inline
|
||||
type="button"
|
||||
aria-label="Suchfilter"
|
||||
aria-haspopup="menu"
|
||||
@@ -136,6 +141,22 @@
|
||||
background: #eaf4ed;
|
||||
border-color: #2b6a3d;
|
||||
}
|
||||
/* In der Suchmaske: kein eigener Rahmen/Hintergrund, der Container drumherum
|
||||
trägt die visuelle Form. */
|
||||
.trigger.inline {
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-right: 1px solid #e4eae7;
|
||||
border-radius: 0;
|
||||
padding: 0.5rem 0.85rem 0.5rem 0.65rem;
|
||||
}
|
||||
.trigger.inline.filtered {
|
||||
background: transparent;
|
||||
color: #2b6a3d;
|
||||
}
|
||||
.trigger.inline:hover {
|
||||
background: rgba(43, 106, 61, 0.06);
|
||||
}
|
||||
.badge {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@@ -44,3 +44,35 @@ export function setDomainFavicon(
|
||||
id
|
||||
);
|
||||
}
|
||||
|
||||
export function getDomainById(
|
||||
db: Database.Database,
|
||||
id: number
|
||||
): AllowedDomain | null {
|
||||
const row = db
|
||||
.prepare(
|
||||
'SELECT id, domain, display_name, favicon_path FROM allowed_domain WHERE id = ?'
|
||||
)
|
||||
.get(id) as AllowedDomain | undefined;
|
||||
return row ?? null;
|
||||
}
|
||||
|
||||
export function updateDomain(
|
||||
db: Database.Database,
|
||||
id: number,
|
||||
patch: { domain?: string; display_name?: string | null }
|
||||
): AllowedDomain | null {
|
||||
const current = getDomainById(db, id);
|
||||
if (!current) return null;
|
||||
const nextDomain =
|
||||
patch.domain !== undefined ? normalizeDomain(patch.domain) : current.domain;
|
||||
const nextLabel =
|
||||
patch.display_name !== undefined ? patch.display_name : current.display_name;
|
||||
// Wenn sich die Domain ändert: favicon_path zurücksetzen, damit der Caller
|
||||
// es neu laden kann. Sonst zeigen wir fälschlich das alte Icon.
|
||||
const nextFavicon = nextDomain !== current.domain ? null : current.favicon_path;
|
||||
db.prepare(
|
||||
'UPDATE allowed_domain SET domain = ?, display_name = ?, favicon_path = ? WHERE id = ?'
|
||||
).run(nextDomain, nextLabel, nextFavicon, id);
|
||||
return getDomainById(db, id);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user