feat: admin API integration, LogoMark, settings page, i18n, RTL font, docs
- Wire admin API into homepage + templates page (ISR 60s, null fallback) - Add src/lib/admin-api.ts with safeFetch helper - Add adminProjectToTemplateItem + adminProjectToCatalogTemplate mappers - Add LogoMark SVG component, replace Sparkles icon in Navbar/Footer/Sidebar - Add public/favicon.svg (SVG brand mark) - Rewrite opengraph-image.tsx with FlatRender branding - Add RTL/Persian font cascade: unlayered [dir=rtl] block forces Vazirmatn - Dashboard Settings page: Profile, Security, Billing, Notifications sections - Add src/lib/supabase/client.ts browser client - Admin API: GET /me, PATCH /profile, POST /change-password endpoints - Admin API DTOs: AdminUserDto, UpdateProfileRequest, ChangePasswordRequest - Admin UI Settings page with TanStack Query + mutations - Add CLAUDE.md + README.md to both repos for new-machine onboarding - Update PROJECT_MEMORY.md with session log - Add appsettings.Development.json.example template
This commit is contained in:
@@ -430,3 +430,80 @@ export function toProjectTemplate(
|
||||
category: "Video",
|
||||
};
|
||||
}
|
||||
|
||||
// ── Admin API → catalog helpers ───────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Map an admin category name (or slug) to the closest hardcoded
|
||||
* VideoSidebarCategoryId. Falls back to "social" when nothing matches.
|
||||
*/
|
||||
export function adminCategoryNameToSidebarId(
|
||||
categoryName?: string
|
||||
): Exclude<VideoSidebarCategoryId, "all"> {
|
||||
if (!categoryName) return "social";
|
||||
const n = categoryName.toLowerCase();
|
||||
if (n.includes("animat")) return "animation";
|
||||
if (n.includes("intro") || n.includes("logo")) return "intros";
|
||||
if (n.includes("edit")) return "editing";
|
||||
if (n.includes("invit")) return "invitation";
|
||||
if (
|
||||
n.includes("holiday") ||
|
||||
n.includes("christmas") ||
|
||||
n.includes("new year")
|
||||
)
|
||||
return "holiday";
|
||||
if (n.includes("slide")) return "slideshow";
|
||||
if (
|
||||
n.includes("present") ||
|
||||
n.includes("pitch") ||
|
||||
n.includes("deck")
|
||||
)
|
||||
return "presentations";
|
||||
if (
|
||||
n.includes("social") ||
|
||||
n.includes("instagram") ||
|
||||
n.includes("tiktok") ||
|
||||
n.includes("reel")
|
||||
)
|
||||
return "social";
|
||||
if (n.includes("ad") || n.includes("promo") || n.includes("ads"))
|
||||
return "ads";
|
||||
if (n.includes("sale") || n.includes("real estate")) return "sales";
|
||||
if (n.includes("music") || n.includes("audio")) return "music";
|
||||
return "social";
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a raw AdminProject (from admin-api.ts) to a VideoCatalogTemplate
|
||||
* so admin-managed templates can be shown on the templates page.
|
||||
*
|
||||
* Import type only — do not import from admin-api in this file at runtime.
|
||||
*/
|
||||
export interface AdminProjectLike {
|
||||
slug: string;
|
||||
title: string;
|
||||
description?: string;
|
||||
type: "video" | "image";
|
||||
categoryName?: string;
|
||||
coverImageUrl?: string;
|
||||
previewVideoUrl?: string;
|
||||
}
|
||||
|
||||
export function adminProjectToCatalogTemplate(
|
||||
p: AdminProjectLike
|
||||
): VideoCatalogTemplate {
|
||||
return {
|
||||
id: p.slug,
|
||||
name: p.title,
|
||||
videoCategory: adminCategoryNameToSidebarId(p.categoryName),
|
||||
aspectRatio: "widescreen",
|
||||
durationType: "flexible",
|
||||
premium: false,
|
||||
sceneCount: 0,
|
||||
supports4k: false,
|
||||
colorChange: false,
|
||||
scriptToVideo: false,
|
||||
description: p.description,
|
||||
isNew: true,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user