83 lines
2.5 KiB
TypeScript
83 lines
2.5 KiB
TypeScript
|
|
export type LifecycleStatus = "draft" | "scheduled" | "published" | "archived";
|
||
|
|
|
||
|
|
export function slugify(text: string): string {
|
||
|
|
return text
|
||
|
|
.toLowerCase()
|
||
|
|
.normalize("NFKD")
|
||
|
|
.replace(/[^a-z0-9\s-]/g, "")
|
||
|
|
.replace(/\s+/g, "-")
|
||
|
|
.replace(/-+/g, "-")
|
||
|
|
.slice(0, 100)
|
||
|
|
.replace(/^-|-$/g, "");
|
||
|
|
}
|
||
|
|
|
||
|
|
function stripHtml(html: string): string {
|
||
|
|
return html.replace(/<[^>]*>/g, " ").replace(/\s+/g, " ").trim();
|
||
|
|
}
|
||
|
|
|
||
|
|
export function extractH1Title(html: string): string {
|
||
|
|
const match = html.match(/<h1\b[^>]*>([\s\S]*?)<\/h1>/i);
|
||
|
|
if (!match?.[1]) return "";
|
||
|
|
return stripHtml(match[1]).slice(0, 160).trim();
|
||
|
|
}
|
||
|
|
|
||
|
|
export function toDateValue(date?: Date | string | null) {
|
||
|
|
if (!date) return "";
|
||
|
|
return new Date(date).toISOString().slice(0, 10);
|
||
|
|
}
|
||
|
|
|
||
|
|
export function toTimeValue(date?: Date | string | null) {
|
||
|
|
if (!date) return "";
|
||
|
|
return new Date(date).toISOString().slice(11, 16);
|
||
|
|
}
|
||
|
|
|
||
|
|
export function combineDateTime(date: string, time: string) {
|
||
|
|
if (!date || !time) return undefined;
|
||
|
|
return new Date(`${date}T${time}:00`);
|
||
|
|
}
|
||
|
|
|
||
|
|
export function isSchedulingVisible(status: LifecycleStatus) {
|
||
|
|
return status === "draft" || status === "scheduled";
|
||
|
|
}
|
||
|
|
|
||
|
|
export function validatePublishInputs(
|
||
|
|
status: LifecycleStatus,
|
||
|
|
publishDate: string,
|
||
|
|
publishTime: string,
|
||
|
|
) {
|
||
|
|
if (!isSchedulingVisible(status)) return null;
|
||
|
|
|
||
|
|
if (status === "scheduled" && (!publishDate || !publishTime)) {
|
||
|
|
return "Für den Status Geplant sind Datum und Uhrzeit erforderlich.";
|
||
|
|
}
|
||
|
|
|
||
|
|
if ((publishDate && !publishTime) || (!publishDate && publishTime)) {
|
||
|
|
return "Bitte Datum und Uhrzeit gemeinsam setzen.";
|
||
|
|
}
|
||
|
|
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function resolveSubmitStatus(
|
||
|
|
status: LifecycleStatus,
|
||
|
|
publishDate: string,
|
||
|
|
publishTime: string,
|
||
|
|
) {
|
||
|
|
if (status === "draft" && publishDate && publishTime) return "scheduled" as const;
|
||
|
|
return status;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function statusLabel(status: LifecycleStatus) {
|
||
|
|
if (status === "archived") return "Archiviert";
|
||
|
|
if (status === "published") return "Veröffentlicht";
|
||
|
|
if (status === "scheduled") return "Geplant";
|
||
|
|
return "Entwurf";
|
||
|
|
}
|
||
|
|
|
||
|
|
export function statusClass(status: LifecycleStatus) {
|
||
|
|
if (status === "archived") return "bg-gray-200 text-gray-700 dark:bg-neutral-700 dark:text-neutral-300";
|
||
|
|
if (status === "published") return "bg-green-50 text-green-700 dark:bg-green-950/50 dark:text-green-400";
|
||
|
|
if (status === "scheduled") return "bg-indigo-50 text-indigo-700 dark:bg-indigo-950/50 dark:text-indigo-400";
|
||
|
|
return "bg-gray-100 text-gray-500 dark:bg-neutral-700 dark:text-neutral-400";
|
||
|
|
}
|