230 lines
12 KiB
TypeScript
230 lines
12 KiB
TypeScript
import type { SiteData } from '../api'
|
||
|
||
export type FieldType = 'text' | 'textarea' | 'number' | 'image' | 'list' | 'wysiwyg' | 'select' | 'date'
|
||
|
||
export type FieldConfig = {
|
||
name: string
|
||
label: string
|
||
type: FieldType
|
||
hint?: string
|
||
/** فقط برای type === 'select' — گزینههای ثابت react-select */
|
||
options?: string[]
|
||
/** ویجت سفارشی نوع list — 'tags' یعنی react-select قابل ساخت (Creatable) */
|
||
ui?: 'lines' | 'tags'
|
||
}
|
||
|
||
export type EntityConfig = {
|
||
resource: string
|
||
dataKey: string
|
||
title: string
|
||
kind: 'collection' | 'singleton'
|
||
titleKey: string
|
||
fields: FieldConfig[]
|
||
defaults: Record<string, unknown>
|
||
}
|
||
|
||
const F = (
|
||
name: string,
|
||
label: string,
|
||
type: FieldType = 'text',
|
||
hint?: string,
|
||
extra?: Partial<FieldConfig>,
|
||
): FieldConfig => ({
|
||
name,
|
||
label,
|
||
type,
|
||
hint,
|
||
...extra,
|
||
})
|
||
|
||
/** دستهبندیهای استاندارد مقاله — با react-select در کشو و صفحه نوشتن نمایش داده میشوند */
|
||
export const ARTICLE_CATEGORIES = [
|
||
'معماری و ساخت',
|
||
'سرمایهگذاری ملکی',
|
||
'طراحی داخلی',
|
||
'اخبار و اطلاعیهها',
|
||
'یادداشت مدیریت',
|
||
]
|
||
|
||
export const ENTITIES: Record<string, EntityConfig> = {
|
||
services: {
|
||
resource: 'services', dataKey: 'services', title: 'خدمات', kind: 'collection',
|
||
titleKey: 'title',
|
||
fields: [F('title', 'عنوان'), F('desc', 'توضیح', 'textarea'), F('icon', 'آیکون', 'text', 'draft / tower / mall / villa / renew / manage / invest / landscape')],
|
||
defaults: { title: 'خدمت جدید', desc: '', icon: 'draft' },
|
||
},
|
||
projects: {
|
||
resource: 'projects', dataKey: 'projects', title: 'پروژهها', kind: 'collection',
|
||
titleKey: 'title',
|
||
fields: [
|
||
F('title', 'عنوان'), F('slug', 'نشانی (slug)'), F('location', 'موقعیت'),
|
||
F('year', 'سال'), F('status', 'وضعیت', 'text', 'done یا progress'),
|
||
F('image', 'تصویر شاخص', 'image'), F('gallery', 'گالری (هر خط یک URL)', 'list'),
|
||
F('area', 'زیربنا'), F('floors', 'طبقات'), F('units', 'واحدها'), F('client', 'کارفرما'),
|
||
F('summary', 'خلاصه', 'textarea'), F('body', 'متن پروژه (هر پاراگراف یک خط)', 'list'),
|
||
],
|
||
defaults: { title: 'پروژه جدید', slug: `project-${Date.now()}`, location: '', year: '', status: 'done', image: '', gallery: [], area: '', floors: '', units: '', client: '', summary: '', body: [] },
|
||
},
|
||
articles: {
|
||
resource: 'articles', dataKey: 'articles', title: 'مقالات', kind: 'collection',
|
||
titleKey: 'title',
|
||
fields: [
|
||
F('title', 'عنوان'),
|
||
F('body', 'متن مقاله', 'wysiwyg'),
|
||
F('excerpt', 'چکیده (روی کارت مقاله)'),
|
||
F('meta_description', 'توضیحات سئو (Meta Description)', 'textarea', '۱۵۰ تا ۱۶۰ کاراکتر — زیر عنوان در نتایج گوگل نمایش داده میشود'),
|
||
F('image', 'تصویر شاخص', 'image'),
|
||
F('category', 'دستهبندی (Category)', 'select', undefined, { options: ARTICLE_CATEGORIES }),
|
||
F('tags', 'هشتگها / برچسبها', 'list', 'با Enter هر هشتگ جدید را اضافه کنید', { ui: 'tags' }),
|
||
F('author', 'نویسنده'),
|
||
F('date', 'تاریخ انتشار (شمسی)', 'date'),
|
||
F('read', 'زمان مطالعه (دقیقه)'),
|
||
F('slug', 'نشانی (slug)'),
|
||
],
|
||
defaults: {
|
||
title: 'مقاله جدید',
|
||
slug: `article-${Date.now()}`,
|
||
date: new Date().toISOString().split('T')[0],
|
||
category: ARTICLE_CATEGORIES[0],
|
||
tags: ['مدیریت پروژه', 'ساختوساز'],
|
||
image: '',
|
||
image_alt: '',
|
||
author: '',
|
||
meta_description: '',
|
||
read: '۵ دقیقه',
|
||
excerpt: '',
|
||
seo_keyphrase: '',
|
||
body: { type: 'doc', content: [{ type: 'paragraph' }] }
|
||
},
|
||
},
|
||
testimonials: {
|
||
resource: 'testimonials', dataKey: 'testimonials', title: 'نظرات مشتریان', kind: 'collection',
|
||
titleKey: 'name',
|
||
fields: [F('name', 'نام'), F('role', 'سمت'), F('quote', 'متن نظر', 'textarea')],
|
||
defaults: { name: 'نظر جدید', role: '', quote: '' },
|
||
},
|
||
faqs: {
|
||
resource: 'faqs', dataKey: 'faqs', title: 'سوالات متداول', kind: 'collection',
|
||
titleKey: 'question',
|
||
fields: [F('question', 'سوال'), F('answer', 'پاسخ', 'textarea')],
|
||
defaults: { question: 'سوال جدید', answer: '' },
|
||
},
|
||
team: {
|
||
resource: 'team', dataKey: 'team', title: 'تیم', kind: 'collection',
|
||
titleKey: 'name',
|
||
fields: [F('name', 'نام'), F('role', 'سمت'), F('bio', 'معرفی', 'textarea')],
|
||
defaults: { name: 'عضو جدید', role: '', bio: '' },
|
||
},
|
||
timeline: {
|
||
resource: 'timeline', dataKey: 'timeline', title: 'تایملاین', kind: 'collection',
|
||
titleKey: 'title',
|
||
fields: [F('year', 'سال'), F('title', 'عنوان'), F('desc', 'توضیح', 'textarea'), F('image', 'تصویر', 'image')],
|
||
defaults: { year: '۱۴۰۰', title: 'رویداد جدید', desc: '', image: '' },
|
||
},
|
||
stats: {
|
||
resource: 'stats', dataKey: 'stats', title: 'آمار', kind: 'collection',
|
||
titleKey: 'label',
|
||
fields: [F('label', 'برچسب'), F('value', 'عدد', 'number'), F('suffix', 'پسوند (مثل + یا هزار)')],
|
||
defaults: { label: 'شاخص جدید', value: 0, suffix: '' },
|
||
},
|
||
why_us: {
|
||
resource: 'why-us', dataKey: 'why_us', title: 'چرا آرامش', kind: 'collection',
|
||
titleKey: 'title',
|
||
fields: [F('title', 'عنوان'), F('desc', 'توضیح', 'textarea')],
|
||
defaults: { title: 'مورد جدید', desc: '' },
|
||
},
|
||
investment_models: {
|
||
resource: 'investment-models', dataKey: 'investment_models', title: 'مدلهای سرمایهگذاری', kind: 'collection',
|
||
titleKey: 'title',
|
||
fields: [F('title', 'عنوان'), F('desc', 'توضیح', 'textarea'), F('points', 'نکات (هر خط یک مورد)', 'list')],
|
||
defaults: { title: 'مدل جدید', desc: '', points: [] },
|
||
},
|
||
process_steps: {
|
||
resource: 'process-steps', dataKey: 'process_steps', title: 'مراحل فرآیند کار', kind: 'collection',
|
||
titleKey: 'title',
|
||
fields: [F('step', 'شماره مرحله'), F('title', 'عنوان'), F('desc', 'توضیح', 'textarea')],
|
||
defaults: { step: '۰۱', title: 'مرحله جدید', desc: '' },
|
||
},
|
||
offices: {
|
||
resource: 'offices', dataKey: 'offices', title: 'دفاتر', kind: 'collection',
|
||
titleKey: 'city',
|
||
fields: [F('city', 'شهر'), F('address', 'نشانی', 'textarea'), F('hours', 'ساعات کاری')],
|
||
defaults: { city: 'شهر جدید', address: '', hours: '' },
|
||
},
|
||
gallery: {
|
||
resource: 'gallery', dataKey: 'gallery', title: 'گالری تصاویر', kind: 'collection',
|
||
titleKey: 'alt',
|
||
fields: [F('src', 'تصویر', 'image'), F('alt', 'متن جایگزین')],
|
||
defaults: { src: '', alt: 'تصویر گالری' },
|
||
},
|
||
nav: {
|
||
resource: 'nav', dataKey: 'nav', title: 'منوی ناوبری', kind: 'collection',
|
||
titleKey: 'label',
|
||
fields: [F('label', 'عنوان'), F('href', 'مسیر (مثل /about)')],
|
||
defaults: { label: 'آیتم جدید', href: '/' },
|
||
},
|
||
seo_meta: {
|
||
resource: 'seo-meta', dataKey: 'seo_meta', title: 'سئوی صفحه', kind: 'collection',
|
||
titleKey: 'page_key',
|
||
fields: [
|
||
F('page_key', 'کلید صفحه', 'text', 'home / about / services / projects / investment / blog / faq / contact'),
|
||
F('title', 'عنوان سئو (عنوان تب مرورگر و گوگل)'),
|
||
F('description', 'توضیح سئو (متا دیسکریپشن)', 'textarea'),
|
||
],
|
||
defaults: { page_key: '', title: '', description: '' },
|
||
},
|
||
brand: {
|
||
resource: 'brand', dataKey: 'brand', title: 'برند و تماس', kind: 'singleton',
|
||
titleKey: 'name',
|
||
fields: [F('name', 'نام برند'), F('logo', 'لوگو', 'image'), F('hero', 'تصویر هیرو', 'image'), F('contact_bg', 'پسزمینه بخش تماس', 'image'), F('phone', 'تلفن نمایشی'), F('phone_href', 'لینک تلفن'), F('email', 'ایمیل'), F('address', 'نشانی', 'textarea')],
|
||
defaults: {},
|
||
},
|
||
hero: {
|
||
resource: 'hero', dataKey: 'hero', title: 'تنظیمات هیرو', kind: 'singleton',
|
||
titleKey: 'title',
|
||
fields: [F('title_highlight', 'واژه مسیِ تیتر'), F('badge_value', 'عدد کارت کنار'), F('badge_label', 'متن کارت کنار', 'textarea'), F('cta_primary_label', 'متن دکمه اصلی'), F('cta_primary_href', 'لینک دکمه اصلی'), F('cta_secondary_label', 'متن دکمه دوم'), F('cta_secondary_href', 'لینک دکمه دوم'), F('scroll_label', 'متن اسکرول'), F('kicker', 'متن بالای تیتر', 'textarea')],
|
||
defaults: {},
|
||
},
|
||
story: {
|
||
resource: 'story', dataKey: 'story', title: 'تصاویر بخش درباره ما', kind: 'singleton',
|
||
titleKey: 'title',
|
||
fields: [F('quote', 'نقلقول مدیرعامل', 'textarea'), F('quote_author', 'استناد نقلقول'), F('stat1_value', 'آمار ۱ — عدد'), F('stat1_label', 'آمار ۱ — برچسب'), F('stat2_value', 'آمار ۲ — عدد'), F('stat2_label', 'آمار ۲ — برچسب'), F('link_label', 'متن دکمه'), F('link_href', 'لینک دکمه')],
|
||
defaults: {},
|
||
},
|
||
before_after: {
|
||
resource: 'before-after', dataKey: 'before_after', title: 'بخش قبل/بعد', kind: 'singleton',
|
||
titleKey: 'title',
|
||
fields: [F('title', 'عنوان'), F('lead', 'توضیح', 'textarea'), F('before', 'تصویر قبل', 'image'), F('after', 'تصویر بعد', 'image'), F('before_label', 'برچسب قبل'), F('after_label', 'برچسب بعد')],
|
||
defaults: {},
|
||
},
|
||
contact_section: {
|
||
resource: 'contact-section', dataKey: 'contact_section', title: 'فرم تماس', kind: 'singleton',
|
||
titleKey: 'title',
|
||
fields: [
|
||
F('label', 'برچسب بالا'), F('title', 'عنوان'), F('lead', 'توضیح', 'textarea'),
|
||
F('address_label', 'برچسب نشانی'), F('phone_label', 'برچسب تلفن'), F('email_label', 'برچسب ایمیل'),
|
||
F('name_label', 'برچسب نام'), F('name_placeholder', 'جاینگهدار نام'),
|
||
F('phone_field_label', 'برچسب تلفن (فرم)'), F('phone_placeholder', 'جاینگهدار تلفن'),
|
||
F('note_label', 'برچسب توضیحات'), F('note_optional_label', 'برچسب اختیاری'), F('note_placeholder', 'جاینگهدار توضیحات'),
|
||
F('submit_label', 'متن دکمه ارسال'), F('sending_label', 'متن در حال ارسال'),
|
||
F('success_title', 'عنوان پیام موفقیت'), F('success_text', 'متن پیام موفقیت', 'textarea'), F('success_button_label', 'دکمه پیام موفقیت'),
|
||
],
|
||
defaults: {},
|
||
},
|
||
newsletter: {
|
||
resource: 'newsletter', dataKey: 'newsletter', title: 'خبرنامه', kind: 'singleton',
|
||
titleKey: 'title',
|
||
fields: [F('title', 'عنوان'), F('lead', 'توضیح', 'textarea'), F('placeholder', 'جاینگهدار ایمیل'), F('button_label', 'متن دکمه'), F('sending_label', 'متن در حال ارسال'), F('success_text', 'پیام موفقیت')],
|
||
defaults: {},
|
||
},
|
||
footer: {
|
||
resource: 'footer', dataKey: 'footer', title: 'فوتر', kind: 'singleton',
|
||
titleKey: 'pages_heading',
|
||
fields: [F('about_text', 'متن معرفی', 'textarea'), F('pages_heading', 'تیتر ستون صفحات'), F('services_heading', 'تیتر ستون خدمات'), F('contact_heading', 'تیتر ستون تماس'), F('copyright', 'متن کپیرایت'), F('tagline', 'شعار پایین')],
|
||
defaults: {},
|
||
},
|
||
}
|
||
|
||
export function getEntityData(data: SiteData, config: EntityConfig): Record<string, unknown> & { id: number }[] | (Record<string, unknown> & { id: number }) {
|
||
return data[config.dataKey as keyof SiteData] as never
|
||
} |