Use site branding on video canvas
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-04-18 23:16:01 +08:00
parent df9a28d752
commit 3f1923701b

View File

@ -24,6 +24,7 @@ import {
Upload,
UserRound,
Video,
Wand2,
X,
type LucideIcon,
} from "lucide-react";
@ -42,8 +43,9 @@ import {
useState,
} from "react";
import { toast } from "sonner";
import useSWR from "swr";
import capturedCanvasModules from "@/artifacts/liblib-frontend-capture-ed9a2c12570a49b9a1186017b2c38b52/canvas-modules.json";
import { cn } from "@/lib/utils";
import { cn, fetcher } from "@/lib/utils";
import { canvasService } from "@/services/canvas";
type ActivePanel =
@ -230,6 +232,12 @@ type LiblibVideoCanvasReplicaProps = {
isLoading?: boolean;
};
type SiteBrandSettings = {
siteName?: string | null;
siteLogo?: string | null;
siteLogoDark?: string | null;
};
const capturedTools = ((capturedCanvasModules as any).tools || []) as CapturedTool[];
const capturedCounts = (capturedCanvasModules as any).counts || {};
const capturedWorkflows = ((capturedCanvasModules as any).workflows || []) as WorkflowPreset[];
@ -1355,6 +1363,7 @@ export function LiblibVideoCanvasReplica({ canvasId, isLoading = false }: Liblib
const router = useRouter();
const canvasRef = useRef<HTMLDivElement | null>(null);
const dragRef = useRef<DragState | null>(null);
const { data: siteBrandSettings } = useSWR<SiteBrandSettings>("/api/site-settings", fetcher);
const [nodes, setNodes] = useState<CloneNode[]>([]);
const [edges, setEdges] = useState<CloneEdge[]>([]);
const [selectedNodeId, setSelectedNodeId] = useState<string | null>(null);
@ -2524,6 +2533,9 @@ export function LiblibVideoCanvasReplica({ canvasId, isLoading = false }: Liblib
onStartTitleEdit={() => setIsTitleEditing(true)}
projectTitle={projectTitle}
routerBack={() => router.push("/")}
siteLogo={siteBrandSettings?.siteLogo}
siteLogoDark={siteBrandSettings?.siteLogoDark}
siteName={siteBrandSettings?.siteName}
/>
<LeftToolbar
@ -2694,6 +2706,9 @@ function TopBar({
onStartTitleEdit,
projectTitle,
routerBack,
siteLogo,
siteLogoDark,
siteName,
}: {
draftTitle: string;
isSaving: boolean;
@ -2709,6 +2724,9 @@ function TopBar({
onStartTitleEdit: () => void;
projectTitle: string;
routerBack: () => void;
siteLogo?: string | null;
siteLogoDark?: string | null;
siteName?: string | null;
}) {
return (
<header className="pointer-events-none absolute left-0 right-0 top-4 z-40 flex h-12 items-center justify-between pl-2 pr-4">
@ -2718,7 +2736,7 @@ function TopBar({
onClick={routerBack}
type="button"
>
<LibTVLogo />
<StylizedBrandLogo siteLogo={siteLogo} siteLogoDark={siteLogoDark} siteName={siteName} />
</button>
<div className="h-4 w-px bg-white/14" />
{isTitleEditing ? (
@ -2895,13 +2913,39 @@ function ZoomDock({
);
}
function LibTVLogo() {
function StylizedBrandLogo({
siteLogo,
siteLogoDark,
siteName,
}: {
siteLogo?: string | null;
siteLogoDark?: string | null;
siteName?: string | null;
}) {
const resolvedSiteName = String(siteName || "AI Chatbot").trim() || "AI Chatbot";
const displayLogo = siteLogoDark?.trim() || siteLogo?.trim() || "";
const shouldInvertLogo = !siteLogoDark?.trim() && Boolean(siteLogo?.trim());
return (
<svg aria-hidden="true" className="h-6 text-white" fill="currentColor" height="17" viewBox="0 0 76.234 16.79" width="77">
<path d="M16.576 16.616H0l.833-4.418H17.65z" />
<path d="m0 16.616 2.314-12.27h4.448l-2.316 12.27zM8.27 0h16.936l-.832 4.416H7.544z" />
<path d="m25.206 0-2.314 12.27-4.512.002L20.76 0zM30.857 14.816 33.09 2.217h2.7l-1.82 10.276h4.968l-.415 2.321h-7.666zM41.025 6.328h2.556l-1.639 8.488h-2.537l1.619-8.488zm.235-2.51c0-.882.701-1.547 1.566-1.547.81 0 1.367.54 1.367 1.315 0 .882-.702 1.547-1.566 1.547-.81 0-1.367-.54-1.367-1.314M53.696 9.488c0 3.077-2.232 5.435-4.933 5.435-1.458 0-2.268-.559-2.735-1.296l-.45 1.189h-2.232L45.56 2.217h2.538l-.738 4.265c.63-.63 1.44-1.025 2.555-1.025 2.214 0 3.78 1.71 3.78 4.03m-2.574.198c0-1.422-.756-2.16-1.87-2.16-1.657 0-2.7 1.547-2.7 3.168 0 1.421.774 2.16 1.89 2.16 1.638 0 2.682-1.548 2.682-3.168zM53.929 2.217h9.934l-.395 2.321H59.85L58.03 14.814h-2.699l1.819-10.276h-3.618zM72.934 2.217h2.879l-6.497 12.599h-3.222L64.042 2.217h2.772l1.368 9.322z" />
</svg>
<span className="flex min-w-0 items-center gap-2.5">
{displayLogo ? (
<img
alt={resolvedSiteName}
className={cn(
"h-8 w-8 shrink-0 object-contain",
shouldInvertLogo && "brightness-0 invert"
)}
src={displayLogo}
/>
) : (
<span className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-white/10">
<Wand2 className="h-4 w-4 text-white" />
</span>
)}
<span className="max-w-[140px] truncate text-base font-semibold text-white">
{resolvedSiteName}
</span>
</span>
);
}