Replace entire repo content with correct code from /root/shahikitchen-website/
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
import type { MenuItem } from '@/domain/menu/entities';
|
||||
import {
|
||||
MEDIA_FOLDERS,
|
||||
SITE_ASSETS,
|
||||
mediaUrl,
|
||||
} from '@/infrastructure/assets/site-assets';
|
||||
|
||||
export type PosterVariant = 'standard' | 'optimized';
|
||||
|
||||
/** Strip .mp4 extension from a video filename */
|
||||
export function videoBaseName(videoFilename: string): string {
|
||||
return videoFilename.replace(/\.mp4$/i, '');
|
||||
}
|
||||
|
||||
/** Full URL for a dish image filename (e.g. "butter-chicken.jpg") */
|
||||
export function dishImageUrl(filename: string): string {
|
||||
return mediaUrl(MEDIA_FOLDERS.dishes, filename);
|
||||
}
|
||||
|
||||
/** Poster URL derived from a video filename */
|
||||
export function dishPosterFromVideo(
|
||||
videoFilename: string,
|
||||
variant: PosterVariant = 'standard'
|
||||
): string {
|
||||
const base = videoBaseName(videoFilename);
|
||||
const suffix = variant === 'optimized' ? '-optimized-poster.jpg' : '-poster.jpg';
|
||||
return mediaUrl(MEDIA_FOLDERS.dishes, `${base}${suffix}`);
|
||||
}
|
||||
|
||||
/** Primary logo used in navbar, footer, login, etc. */
|
||||
export function logoUrl(): string {
|
||||
return SITE_ASSETS.logo.primary;
|
||||
}
|
||||
|
||||
/** Hero banner video sources for homepage */
|
||||
export function heroBannerSources() {
|
||||
return {
|
||||
mobileWebm: SITE_ASSETS.banner.mobileWebm,
|
||||
mobileMp4: SITE_ASSETS.banner.mobileMp4,
|
||||
desktopMp4: SITE_ASSETS.banner.desktopMp4,
|
||||
};
|
||||
}
|
||||
|
||||
/** Chef expression images for PlayfulHeroScene */
|
||||
export function chefExpressionUrl(expression: 'wink' | 'smile' | 'normal'): string {
|
||||
const map = {
|
||||
wink: SITE_ASSETS.animation.chefWink,
|
||||
smile: SITE_ASSETS.animation.chefSmile,
|
||||
normal: SITE_ASSETS.animation.chefNormal,
|
||||
};
|
||||
return map[expression];
|
||||
}
|
||||
|
||||
/** Resolve primary poster path for a menu item */
|
||||
export function getMenuPosterSrc(
|
||||
item: MenuItem,
|
||||
variant: PosterVariant = 'standard'
|
||||
): string {
|
||||
// Prefer static dish photo when available (sweets use synced .jpg, not -poster.jpg)
|
||||
if (item.image) {
|
||||
return dishImageUrl(item.image);
|
||||
}
|
||||
if (item.video) {
|
||||
return dishPosterFromVideo(item.video, variant);
|
||||
}
|
||||
return variant === 'optimized'
|
||||
? SITE_ASSETS.dishes.defaultPoster
|
||||
: SITE_ASSETS.fallbacks.dishPoster;
|
||||
}
|
||||
|
||||
/** Poster candidates for progressive fallback in UI `<img onError>` */
|
||||
export function getMenuPosterCandidates(item: MenuItem): string[] {
|
||||
const base = item.video ? videoBaseName(item.video) : '';
|
||||
const candidates: string[] = [];
|
||||
|
||||
if (item.image) candidates.push(dishImageUrl(item.image));
|
||||
if (item.video) {
|
||||
candidates.push(
|
||||
dishPosterFromVideo(item.video, 'standard'),
|
||||
dishPosterFromVideo(item.video, 'optimized'),
|
||||
mediaUrl(MEDIA_FOLDERS.dishes, `${base}.jpg`),
|
||||
);
|
||||
}
|
||||
candidates.push(
|
||||
SITE_ASSETS.dishes.defaultPoster,
|
||||
SITE_ASSETS.fallbacks.dishPoster,
|
||||
SITE_ASSETS.fallbacks.logo,
|
||||
);
|
||||
|
||||
return [...new Set(candidates)];
|
||||
}
|
||||
|
||||
/** Full video URL for a menu item */
|
||||
export function getMenuVideoSrc(item: MenuItem): string | null {
|
||||
if (!item.video) return null;
|
||||
return mediaUrl(MEDIA_FOLDERS.videos, item.video);
|
||||
}
|
||||
|
||||
/** Optimized + fallback video sources for kiosk displays */
|
||||
export function getMenuVideoSources(videoFilename: string) {
|
||||
if (!videoFilename) {
|
||||
return { webm: '', mp4: '', fallback: '' };
|
||||
}
|
||||
const base = videoBaseName(videoFilename);
|
||||
return {
|
||||
webm: mediaUrl(MEDIA_FOLDERS.videos, `${base}-optimized.webm`),
|
||||
mp4: mediaUrl(MEDIA_FOLDERS.videos, `${base}-optimized.mp4`),
|
||||
fallback: mediaUrl(MEDIA_FOLDERS.videos, `${base}.mp4`),
|
||||
};
|
||||
}
|
||||
|
||||
/** Apply next fallback src in an img onError handler */
|
||||
export function applyNextImageFallback(
|
||||
target: HTMLImageElement,
|
||||
candidates: string[],
|
||||
currentSrc: string
|
||||
): void {
|
||||
const currentIndex = candidates.indexOf(currentSrc);
|
||||
const nextIndex = currentIndex >= 0 ? currentIndex + 1 : 0;
|
||||
if (nextIndex < candidates.length) {
|
||||
target.src = candidates[nextIndex];
|
||||
}
|
||||
}
|
||||
|
||||
// Re-export registry for direct access when needed
|
||||
export { SITE_ASSETS, MEDIA_FOLDERS, mediaUrl } from '@/infrastructure/assets/site-assets';
|
||||
Reference in New Issue
Block a user