57 lines
2.4 KiB
TypeScript
57 lines
2.4 KiB
TypeScript
import type Database from 'better-sqlite3';
|
|
import { randomUUID } from 'node:crypto';
|
|
import { getDb } from './db';
|
|
import { contentSeed, seedByTag, type ContentType } from '../data/content-seed';
|
|
import { stylesToClasses } from './style-presets';
|
|
|
|
interface Entry { value: string; type: ContentType; styles: Record<string, string>; guid: string }
|
|
|
|
export function syncSeed(db: Database.Database): void {
|
|
const ins = db.prepare('INSERT OR IGNORE INTO content_blocks (tag, type, value, guid) VALUES (?, ?, ?, ?)');
|
|
const tx = db.transaction(() => { for (const e of contentSeed) ins.run(e.tag, e.type, e.value, randomUUID()); });
|
|
tx();
|
|
}
|
|
|
|
export function makeContentStore(dbGetter: () => Database.Database) {
|
|
let cache: Map<string, Entry> | null = null;
|
|
|
|
const load = (): Map<string, Entry> => {
|
|
if (cache) return cache;
|
|
const rows = dbGetter().prepare('SELECT tag, type, value, styles, guid FROM content_blocks').all() as
|
|
{ tag: string; type: ContentType; value: string; styles: string; guid: string | null }[];
|
|
cache = new Map(rows.map((r) => {
|
|
let styles: Record<string, string> = {};
|
|
try { styles = JSON.parse(r.styles); } catch { /* styles corrotto: si ignora */ }
|
|
if (typeof styles !== 'object' || styles === null) styles = {};
|
|
return [r.tag, { value: r.value, type: r.type, styles, guid: r.guid ?? '' }];
|
|
}));
|
|
return cache;
|
|
};
|
|
|
|
return {
|
|
resolve(tag: string): { value: string; type: ContentType; classes: string; guid: string } {
|
|
const hit = load().get(tag);
|
|
if (hit) return { value: hit.value, type: hit.type, classes: stylesToClasses(hit.styles), guid: hit.guid };
|
|
const seed = seedByTag.get(tag);
|
|
if (seed) return { value: seed.value, type: seed.type, classes: '', guid: '' };
|
|
console.warn(`[content] tag sconosciuto: ${tag}`);
|
|
return { value: '', type: 'text', classes: '', guid: '' };
|
|
},
|
|
invalidate(): void { cache = null; },
|
|
};
|
|
}
|
|
|
|
const store = makeContentStore(getDb);
|
|
|
|
export const resolveContent = (tag: string) => store.resolve(tag);
|
|
export const t = (tag: string): string => store.resolve(tag).value;
|
|
export const invalidateContentCache = (): void => store.invalidate();
|
|
|
|
export function getImageOverride(tag: string): string | null {
|
|
const r = store.resolve(tag);
|
|
return r.type === 'image' && r.value ? `/uploads/${r.value}` : null;
|
|
}
|
|
|
|
export const contentImageUrl = (tag: string, fallback: string): string =>
|
|
getImageOverride(tag) ?? fallback;
|