Add a static images manager and polish dashboard layout and fonts.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-08-16 23:56:17 +03:30
co-authored by Cursor
parent e79211e3cd
commit b9024ad77a
57 changed files with 2025 additions and 122 deletions
+27
View File
@@ -0,0 +1,27 @@
export function parseAspectRatio(value?: string | null): number {
if (!value) return 16 / 9
const [widthRaw, heightRaw] = value.split(':')
const width = Number(widthRaw)
const height = Number(heightRaw)
if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
return 16 / 9
}
return width / height
}
export function cssAspectRatio(value?: string | null): string {
if (!value?.includes(':')) return '16 / 9'
return value.replace(':', ' / ')
}
/** Preview box that keeps the slot ratio: landscape is wide, portrait is tall. */
export function slotPreviewSize(value?: string | null): { width: number; height: number } {
const aspect = parseAspectRatio(value)
const long = 220
if (aspect >= 1) {
const width = Math.min(360, Math.round(long * aspect))
return { width, height: Math.round(width / aspect) }
}
const height = long
return { width: Math.round(height * aspect), height }
}
@@ -1,5 +1,6 @@
export const BUSINESS_PRIMARY_COLOR_IDS = [
'red',
'dark-red',
'yellow',
'black',
'cyan',
@@ -59,6 +60,16 @@ export const BUSINESS_PRIMARY_COLOR_PALETTE: Record<
primaryDarkRgb: '220 38 38',
...PURPLE_ACCENT,
},
'dark-red': {
label: 'Dark Red',
primary: '#991b1b',
primaryDark: '#7f1d1d',
primaryLight: '#fee2e2',
primaryGlow: '#b91c1c',
primaryRgb: '153 27 27',
primaryDarkRgb: '127 29 29',
...PURPLE_ACCENT,
},
yellow: {
label: 'Yellow',
primary: '#eab308',
@@ -0,0 +1,38 @@
import type { BusinessMessageKey } from '../i18n/messages'
export const STATIC_IMAGE_PAGE_KEYS = [
'home',
'products',
'product',
'categories',
'brands',
'blog',
'about',
'contact',
] as const
const PAGE_LABELS: Record<string, BusinessMessageKey> = {
home: 'website.staticImages.pageHome',
products: 'website.staticImages.pageProducts',
product: 'website.staticImages.pageProduct',
categories: 'website.staticImages.pageCategories',
brands: 'website.staticImages.pageBrands',
blog: 'website.staticImages.pageBlog',
about: 'website.staticImages.pageAbout',
contact: 'website.staticImages.pageContact',
}
export function staticImagePageLabel(
pageKey: string,
t: (key: BusinessMessageKey, vars?: Record<string, string | number>) => string,
) {
const mapped = PAGE_LABELS[pageKey]
return mapped ? t(mapped) : pageKey
}
export function staticImagePageOptions(existing: string[]) {
const extras = [...new Set(existing.filter(Boolean))].filter(
(key) => !(STATIC_IMAGE_PAGE_KEYS as readonly string[]).includes(key),
)
return [...STATIC_IMAGE_PAGE_KEYS, ...extras]
}