返回 oh-my-ppt
design-contract.ts
根目录 / src / main / presentation / design-contract.ts
1 import type { DesignContract } from '@shared/generation'
2
3 export const DEFAULT_TITLE_FONT = 'Inter'
4 export const DEFAULT_BODY_FONT = 'Noto Sans SC'
5
6 const DEFAULT_PALETTE = ['#ffffff', '#111827', '#2563eb', '#64748b']
7
8 export const createDefaultDesignContract = (): DesignContract => ({
9 theme: 'clean modern presentation',
10 background: 'light canvas with subtle neutral depth',
11 palette: DEFAULT_PALETTE,
12 titleStyle: 'text-4xl font-semibold text-slate-950',
13 layoutMotif: 'clear editorial grids with balanced whitespace',
14 chartStyle: 'simple readable charts with restrained color',
15 shapeLanguage: '8px radius, light borders, subtle shadows',
16 titleFont: DEFAULT_TITLE_FONT,
17 bodyFont: DEFAULT_BODY_FONT
18 })
19
20 const parseRecord = (value: unknown): Record<string, unknown> | null => {
21 if (typeof value === 'string') {
22 if (value.trim().length === 0) return null
23 try {
24 const parsed = JSON.parse(value) as unknown
25 return parseRecord(parsed)
26 } catch {
27 return null
28 }
29 }
30 if (!value || typeof value !== 'object' || Array.isArray(value)) return null
31 return value as Record<string, unknown>
32 }
33
34 const normalizeText = (value: unknown): string => String(value ?? '').replace(/\s+/g, ' ').trim()
35
36 const normalizePalette = (value: unknown, fallback: string[]): string[] => {
37 if (!Array.isArray(value)) return fallback
38 const colors = value.map((item) => normalizeText(item)).filter(Boolean).slice(0, 6)
39 return colors.length >= 3 ? colors : fallback
40 }
41
42 export const normalizeDesignContract = (value: unknown): DesignContract => {
43 const fallback = createDefaultDesignContract()
44 const record = parseRecord(value)
45 if (!record) return fallback
46
47 return {
48 theme: normalizeText(record.theme) || fallback.theme,
49 background: normalizeText(record.background) || fallback.background,
50 palette: normalizePalette(record.palette, fallback.palette),
51 titleStyle: normalizeText(record.titleStyle) || fallback.titleStyle,
52 layoutMotif: normalizeText(record.layoutMotif) || fallback.layoutMotif,
53 chartStyle: normalizeText(record.chartStyle) || fallback.chartStyle,
54 shapeLanguage: normalizeText(record.shapeLanguage) || fallback.shapeLanguage,
55 titleFont: normalizeText(record.titleFont) || fallback.titleFont,
56 bodyFont: normalizeText(record.bodyFont) || fallback.bodyFont
57 }
58 }
59
60 export const resolveDesignContract = (
61 value: unknown
62 ): { contract: DesignContract; shouldPersist: boolean } => {
63 const record = parseRecord(value)
64 const contract = normalizeDesignContract(record)
65 if (!record) return { contract, shouldPersist: true }
66 return {
67 contract,
68 shouldPersist: JSON.stringify(contract) !== JSON.stringify(record)
69 }
70 }
71
71 lines TYPESCRIPT