Add SEO settings and root admin save flows
CI / quality (push) Waiting to run

This commit is contained in:
MOH
2026-03-07 18:48:01 +01:00
parent f6a5a37676
commit f259dfc6bd
35 changed files with 1500 additions and 56 deletions
+61
View File
@@ -0,0 +1,61 @@
"use client";
import { Save } from "lucide-react";
import { useEffect, useState } from "react";
import { Button } from "@/components/ui/button";
type FormSaveButtonProps = {
formId: string;
label?: string;
};
function serializeForm(form: HTMLFormElement) {
return JSON.stringify(
Array.from(new FormData(form).entries()).map(([key, value]) => [
key,
value instanceof File ? `${value.name}:${value.size}:${value.type}` : value,
]),
);
}
export function FormSaveButton({
formId,
label = "Speichern",
}: FormSaveButtonProps) {
const [isDirty, setIsDirty] = useState(false);
useEffect(() => {
const form = document.getElementById(formId);
if (!(form instanceof HTMLFormElement)) {
setIsDirty(false);
return undefined;
}
const initialSnapshot = serializeForm(form);
const updateDirtyState = () => {
setIsDirty(serializeForm(form) !== initialSnapshot);
};
updateDirtyState();
form.addEventListener("input", updateDirtyState);
form.addEventListener("change", updateDirtyState);
form.addEventListener("reset", updateDirtyState);
return () => {
form.removeEventListener("input", updateDirtyState);
form.removeEventListener("change", updateDirtyState);
form.removeEventListener("reset", updateDirtyState);
};
}, [formId]);
return (
<Button type="submit" form={formId} disabled={!isDirty}>
<Save className="h-4 w-4" />
{label}
</Button>
);
}