feat: area admin con editor tiptap, api crud e upload immagini

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-02 01:49:12 +02:00
parent f3fb2fe005
commit f0ad162f74
14 changed files with 423 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
import { slugify } from './slug';
import { sanitizeHtml } from './sanitize';
import { CATEGORIES } from './blog-const';
export function parsePostBody(data: Record<string, unknown>) {
const title = String(data.title ?? '').trim();
if (!title) return { error: 'Il titolo è obbligatorio.' } as const;
const category = String(data.category ?? '');
if (!(CATEGORIES as readonly string[]).includes(category)) return { error: 'Categoria non valida.' } as const;
const slug = slugify(String(data.slug ?? '') || title);
if (!slug) return { error: 'Slug non valido.' } as const;
return {
value: {
title, slug, category,
excerpt: String(data.excerpt ?? '').trim().slice(0, 300),
body_html: sanitizeHtml(String(data.body_html ?? '')),
cover: data.cover ? String(data.cover) : null,
draft: Boolean(data.draft),
},
} as const;
}
+11
View File
@@ -0,0 +1,11 @@
import sanitize from 'sanitize-html';
export function sanitizeHtml(html: string): string {
return sanitize(html, {
allowedTags: ['h2', 'h3', 'p', 'strong', 'em', 'u', 's', 'ul', 'ol', 'li', 'a', 'img', 'blockquote', 'br', 'hr'],
allowedAttributes: { a: ['href', 'rel', 'target'], img: ['src', 'alt'] },
allowedSchemes: ['https', 'http', 'mailto'],
allowedSchemesAppliedToAttributes: ['href', 'src'],
allowProtocolRelative: false,
});
}