사장님이 고를 수 있는 숙박 템플릿이 고택 하나뿐이었다. 모두 stay2 콘텐츠(날씨·미니 블로그· 지역 이야기·객실·축제·일정·후기·엽서·노래)를 그대로 싣고 모양만 다르다. - layouts/<id>/: 템플릿별 Frame·섹션·CSS. 데스크톱은 넓은 배치(1024px 이상), 모바일 우선 - layouts/kit/kit.css: 탭 전환·시트·예약 폼·접기 등 공통 구조 - shared templates.json · builder.ts · catalog.ts: 템플릿·LayoutId 등록 - seo/head.ts: 템플릿별 한글 웹폰트 — 서로 겹치지 않게 배정 - paper Frame·Intro: 같은 탭을 다시 눌러도 맨 위로, 미니 블로그를 글 여러 개로 - docs/TEMPLATES.md · TEMPLATE_DESIGN.md: 목록과 화면 규칙(간격·접기·✓ 표시·글꼴) eslint·tsc 통과, vitest 123 passed, 템플릿 9개 굽기 성공 · 간격 검사 0건
47 lines
1.8 KiB
TypeScript
47 lines
1.8 KiB
TypeScript
import catalog from '../data/templates.json';
|
|
import type {IndustryDef, IndustryType, LayoutId, TemplateDef} from '../types';
|
|
|
|
export type TemplateId = keyof typeof catalog.templates;
|
|
|
|
export const LAYOUT_IDS: readonly LayoutId[] = ['basic', 'paper', 'round', 'cinema', 'bigtype', 'boutique', 'graphic', 'coral', 'minimal', 'pine'];
|
|
|
|
export const TEMPLATES = catalog.templates as Record<TemplateId, TemplateDef>;
|
|
|
|
export const INDUSTRIES = catalog.industries as Record<IndustryType, IndustryDef>;
|
|
|
|
export function isTemplateId(id: string): id is TemplateId {
|
|
return Object.hasOwn(TEMPLATES, id);
|
|
}
|
|
|
|
export function templateOf(id: string): TemplateDef {
|
|
if (!isTemplateId(id)) throw new Error(`등록되지 않은 템플릿: ${id}`);
|
|
return TEMPLATES[id];
|
|
}
|
|
|
|
export function industryTemplates(industry: IndustryType): TemplateId[] {
|
|
return INDUSTRIES[industry].templates as TemplateId[];
|
|
}
|
|
|
|
export function resolveTemplateId(industry: IndustryType, stored: string | null | undefined): TemplateId {
|
|
const id = stored?.trim() || INDUSTRIES[industry].defaultTemplate;
|
|
if (!INDUSTRIES[industry].templates.includes(id)) {
|
|
throw new Error(`${industry} 업종에서 쓸 수 없는 템플릿: ${id}`);
|
|
}
|
|
return id as TemplateId;
|
|
}
|
|
|
|
for (const [id, template] of Object.entries(TEMPLATES)) {
|
|
if (!LAYOUT_IDS.includes(template.layout)) {
|
|
throw new Error(`템플릿 ${id}의 레이아웃이 등록되지 않았다: ${template.layout}`);
|
|
}
|
|
}
|
|
|
|
for (const [industry, def] of Object.entries(INDUSTRIES)) {
|
|
for (const id of [def.defaultTemplate, ...def.templates]) {
|
|
if (!isTemplateId(id)) throw new Error(`${industry} 업종이 없는 템플릿을 가리킨다: ${id}`);
|
|
}
|
|
if (!def.templates.includes(def.defaultTemplate)) {
|
|
throw new Error(`${industry} 업종의 기본 템플릿이 허용 목록에 없다: ${def.defaultTemplate}`);
|
|
}
|
|
}
|