Initial HOM arch studio website (home, about, contact) on Meshkee
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
import { cache } from "react";
|
||||
|
||||
import { meshkeeGet, tenantPath } from "@/lib/meshkee";
|
||||
|
||||
export type StaticImage = {
|
||||
url?: string | null;
|
||||
titleFa?: string | null;
|
||||
titleEn?: string | null;
|
||||
subtext?: string | null;
|
||||
linkUrl?: string | null;
|
||||
};
|
||||
|
||||
export type StaticImageSlot = {
|
||||
key: string;
|
||||
label: string;
|
||||
kind: "single" | "list";
|
||||
pageKey: string;
|
||||
aspectRatio: string;
|
||||
itemCount: number | null;
|
||||
recommendedWidth: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Catalog served at `GET /meshkee/static-image-slots`.
|
||||
* Keep `aspectRatio` / `recommendedWidth` in sync with the on-page frames —
|
||||
* if a frame’s size or ratio changes in development, update the matching entry here.
|
||||
*/
|
||||
export const STATIC_IMAGE_SLOTS: StaticImageSlot[] = [
|
||||
{
|
||||
key: "hero",
|
||||
label: "تصویر اصلی صفحه اول",
|
||||
kind: "single",
|
||||
pageKey: "home",
|
||||
aspectRatio: "16:9",
|
||||
itemCount: 1,
|
||||
recommendedWidth: 1920,
|
||||
},
|
||||
{
|
||||
key: "projects",
|
||||
label: "پروژههای منتخب صفحه اول",
|
||||
kind: "list",
|
||||
pageKey: "home",
|
||||
aspectRatio: "4:5",
|
||||
itemCount: null,
|
||||
recommendedWidth: 1200,
|
||||
},
|
||||
{
|
||||
key: "studio-image",
|
||||
label: "تصویر معرفی استودیو (صفحه اول)",
|
||||
kind: "single",
|
||||
pageKey: "home",
|
||||
aspectRatio: "4:3",
|
||||
itemCount: 1,
|
||||
recommendedWidth: 1400,
|
||||
},
|
||||
{
|
||||
key: "about-hero",
|
||||
label: "تصویر اصلی درباره ما",
|
||||
kind: "single",
|
||||
pageKey: "about",
|
||||
aspectRatio: "16:9",
|
||||
itemCount: 1,
|
||||
recommendedWidth: 1920,
|
||||
},
|
||||
{
|
||||
key: "about-gallery",
|
||||
label: "گالری درباره ما",
|
||||
kind: "list",
|
||||
pageKey: "about",
|
||||
aspectRatio: "1:1",
|
||||
itemCount: 3,
|
||||
recommendedWidth: 900,
|
||||
},
|
||||
{
|
||||
key: "contact-image",
|
||||
label: "تصویر تماس با ما",
|
||||
kind: "single",
|
||||
pageKey: "contact",
|
||||
aspectRatio: "4:5",
|
||||
itemCount: 1,
|
||||
recommendedWidth: 1200,
|
||||
},
|
||||
];
|
||||
|
||||
type StaticImagesResponse = {
|
||||
items?: {
|
||||
key: string;
|
||||
aspectRatio?: string | null;
|
||||
images?: (StaticImage & { sortOrder?: number })[];
|
||||
}[];
|
||||
};
|
||||
|
||||
export type PageSlots = Record<string, { images: StaticImage[]; aspectRatio: string | null }>;
|
||||
|
||||
/** `GET /tenants/{domain}/website/static-images?pageKey=…` grouped by slot key. */
|
||||
export const getPageSlots = cache(async (pageKey: string): Promise<PageSlots> => {
|
||||
const data = await meshkeeGet<StaticImagesResponse>(
|
||||
tenantPath(`/website/static-images?pageKey=${encodeURIComponent(pageKey)}`),
|
||||
{},
|
||||
);
|
||||
const grouped: PageSlots = {};
|
||||
for (const slot of data.items ?? []) {
|
||||
const images = (slot.images ?? [])
|
||||
.filter((image) => image?.url)
|
||||
.sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0));
|
||||
if (images.length) grouped[slot.key] = { images, aspectRatio: slot.aspectRatio ?? null };
|
||||
}
|
||||
return grouped;
|
||||
});
|
||||
|
||||
/** CSS `aspect-ratio` for a slot: API value first, then the local catalog. */
|
||||
export function slotRatio(key: string, slots?: PageSlots) {
|
||||
const fromApi = slots?.[key]?.aspectRatio;
|
||||
const fromCatalog = STATIC_IMAGE_SLOTS.find((entry) => entry.key === key)?.aspectRatio;
|
||||
return (fromApi || fromCatalog || "4:3").replace(":", " / ");
|
||||
}
|
||||
|
||||
/** Images for a slot, or the local fallback list when CMS has none. */
|
||||
export function slotImages(key: string, slots: PageSlots, fallback: StaticImage[]) {
|
||||
return slots[key]?.images?.length ? slots[key].images : fallback;
|
||||
}
|
||||
Reference in New Issue
Block a user