preserve colorful brand logos

This commit is contained in:
134 2026-07-08 15:22:17 +08:00
parent d48e26fe9a
commit 778fc1c0b8
14 changed files with 27 additions and 208 deletions

View File

@ -501,11 +501,6 @@ export default function Page() {
const displayLogo = mounted const displayLogo = mounted
? (resolvedTheme === "dark" && siteLogoDark ? siteLogoDark : siteLogo) ? (resolvedTheme === "dark" && siteLogoDark ? siteLogoDark : siteLogo)
: siteLogo; : siteLogo;
const shouldInvertLogo =
mounted &&
resolvedTheme === "dark" &&
!siteLogoDark?.trim() &&
Boolean(siteLogo?.trim());
const hasThirdPartyLogin = const hasThirdPartyLogin =
(isDingTalkEnabled && (Boolean(dingTalkAppKey) || dingTalkOrganizations.length > 0)) || (isDingTalkEnabled && (Boolean(dingTalkAppKey) || dingTalkOrganizations.length > 0)) ||
(isGoogleEnabled && isGoogleConfigured); (isGoogleEnabled && isGoogleConfigured);
@ -545,7 +540,7 @@ export default function Page() {
<img <img
src={displayLogo} src={displayLogo}
alt={siteName} alt={siteName}
className={`mb-2 h-12 w-auto object-contain ${shouldInvertLogo ? "brightness-0 invert" : ""}`} className="mb-2 h-12 w-auto object-contain"
/> />
) : null} ) : null}
<h3 className="font-semibold text-xl dark:text-zinc-50">登录 {siteName}</h3> <h3 className="font-semibold text-xl dark:text-zinc-50">登录 {siteName}</h3>

View File

@ -8,7 +8,6 @@ export const dynamic = "force-dynamic";
export const revalidate = 0; export const revalidate = 0;
const DEFAULT_CONTENT_TYPE = "image/x-icon"; const DEFAULT_CONTENT_TYPE = "image/x-icon";
const DARK_FAVICON_CONTENT_TYPE = "image/png";
const FETCH_TIMEOUT_MS = 10_000; const FETCH_TIMEOUT_MS = 10_000;
function noStoreHeaders(contentType: string) { function noStoreHeaders(contentType: string) {
@ -71,86 +70,16 @@ function uniqueNonEmptyValues(values: string[]) {
return result; return result;
} }
async function readLocalFallbackFavicon(preferDark = false) { async function readLocalFallbackFavicon() {
const file = await readFile( const file = await readFile(
join(process.cwd(), "public", "default-favicon.ico") join(process.cwd(), "public", "default-favicon.ico")
); );
if (preferDark) {
const transformed = await transformFaviconForDark(file).catch(() => null);
const fallback =
transformed || (await renderDarkFallbackFavicon().catch(() => null));
if (fallback) {
return new NextResponse(fallback, {
status: 200,
headers: noStoreHeaders(DARK_FAVICON_CONTENT_TYPE),
});
}
}
return new NextResponse(file, { return new NextResponse(file, {
status: 200, status: 200,
headers: noStoreHeaders(DEFAULT_CONTENT_TYPE), headers: noStoreHeaders(DEFAULT_CONTENT_TYPE),
}); });
} }
async function renderDarkFallbackFavicon() {
const sharp = (await import("sharp")).default;
const svg = `\
<svg width="64" height="64" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
<rect width="64" height="64" fill="none"/>
<path d="M15 9h34v12H29v13h20v12H29v9l-14-11V9z" fill="#fff"/>
<path d="M37 25h12v30L37 45V25z" fill="#fff" opacity=".92"/>
</svg>`;
return await sharp(Buffer.from(svg)).png().toBuffer();
}
async function transformFaviconForDark(buffer: Buffer | ArrayBuffer) {
const sharp = (await import("sharp")).default;
const inputBuffer = Buffer.isBuffer(buffer)
? buffer
: Buffer.from(new Uint8Array(buffer));
const createBaseImage = () =>
sharp(inputBuffer, {
animated: false,
failOn: "none",
}).resize({
width: 64,
height: 64,
fit: "contain",
background: { r: 0, g: 0, b: 0, alpha: 0 },
});
const { data, info } = await createBaseImage()
.ensureAlpha()
.raw()
.toBuffer({ resolveWithObject: true });
let visiblePixelCount = 0;
let luminanceTotal = 0;
for (let index = 0; index < data.length; index += info.channels) {
const alpha = data[index + 3] ?? 255;
if (alpha < 24) continue;
const red = data[index] ?? 0;
const green = data[index + 1] ?? 0;
const blue = data[index + 2] ?? 0;
luminanceTotal += 0.2126 * red + 0.7152 * green + 0.0722 * blue;
visiblePixelCount += 1;
}
const averageLuminance =
visiblePixelCount > 0 ? luminanceTotal / visiblePixelCount : 0;
const needsInvertForDark = averageLuminance < 150;
const output = createBaseImage();
if (needsInvertForDark) {
output.negate({ alpha: false });
}
return await output
.png()
.toBuffer();
}
export async function GET(request: Request) { export async function GET(request: Request) {
try { try {
const requestUrl = new URL(request.url); const requestUrl = new URL(request.url);
@ -159,20 +88,14 @@ export async function GET(request: Request) {
const configuredFavicon = String(settings?.favicon || "").trim(); const configuredFavicon = String(settings?.favicon || "").trim();
const configuredLightLogo = String(settings?.siteLogo || "").trim(); const configuredLightLogo = String(settings?.siteLogo || "").trim();
const configuredDarkLogo = String(settings?.siteLogoDark || "").trim(); const configuredDarkLogo = String(settings?.siteLogoDark || "").trim();
const rawFaviconCandidates = preferDark const rawFaviconCandidates = configuredFavicon
? uniqueNonEmptyValues([ ? [configuredFavicon]
configuredFavicon, : preferDark
configuredDarkLogo, ? uniqueNonEmptyValues([configuredDarkLogo, configuredLightLogo])
configuredLightLogo, : uniqueNonEmptyValues([configuredLightLogo, configuredDarkLogo]);
])
: uniqueNonEmptyValues([
configuredFavicon,
configuredLightLogo,
configuredDarkLogo,
]);
if (rawFaviconCandidates.length === 0) { if (rawFaviconCandidates.length === 0) {
return await readLocalFallbackFavicon(preferDark); return await readLocalFallbackFavicon();
} }
for (const rawFaviconUrl of rawFaviconCandidates) { for (const rawFaviconUrl of rawFaviconCandidates) {
@ -220,42 +143,15 @@ export async function GET(request: Request) {
const contentType = const contentType =
upstream.headers.get("content-type") || inferContentType(faviconUrl); upstream.headers.get("content-type") || inferContentType(faviconUrl);
if (preferDark) {
const transformed = await transformFaviconForDark(buffer).catch((error) => {
console.error("[favicon] Failed to transform dark favicon candidate:", {
targetUrl,
error,
});
return null;
});
if (!transformed) continue;
return new NextResponse(transformed, {
status: 200,
headers: noStoreHeaders(DARK_FAVICON_CONTENT_TYPE),
});
}
return new NextResponse(buffer, { return new NextResponse(buffer, {
status: 200, status: 200,
headers: noStoreHeaders(contentType), headers: noStoreHeaders(contentType),
}); });
} }
if (preferDark) { return await readLocalFallbackFavicon();
const fallback = await renderDarkFallbackFavicon().catch(() => null);
if (fallback) {
return new NextResponse(fallback, {
status: 200,
headers: noStoreHeaders(DARK_FAVICON_CONTENT_TYPE),
});
}
}
return await readLocalFallbackFavicon(preferDark);
} catch (error) { } catch (error) {
console.error("[favicon] Failed to proxy favicon:", error); console.error("[favicon] Failed to proxy favicon:", error);
const preferDark = new URL(request.url).searchParams.get("theme") === "dark"; return await readLocalFallbackFavicon();
return await readLocalFallbackFavicon(preferDark);
} }
} }

View File

@ -9636,10 +9636,6 @@ export default function CanvasEditorLegacyPage({
: lightCanvasBrandLogo || darkCanvasBrandLogo : lightCanvasBrandLogo || darkCanvasBrandLogo
: lightCanvasBrandLogo || darkCanvasBrandLogo : lightCanvasBrandLogo || darkCanvasBrandLogo
).trim(); ).trim();
const shouldInvertCanvasBrandLogo =
isDarkCanvasTheme &&
Boolean(canvasBrandLogo) &&
!hasSeparateDarkCanvasBrandLogo;
const brandEntry = ( const brandEntry = (
<div <div
@ -9654,11 +9650,7 @@ export default function CanvasEditorLegacyPage({
{canvasBrandLogo ? ( {canvasBrandLogo ? (
<img <img
alt={siteSettingsData?.siteName || "返回首页"} alt={siteSettingsData?.siteName || "返回首页"}
className={cn( className="h-7 w-7 object-contain"
"h-7 w-7 object-contain",
shouldInvertCanvasBrandLogo && "brightness-0 invert",
!hasSeparateDarkCanvasBrandLogo && "dark:brightness-0 dark:invert"
)}
draggable={false} draggable={false}
src={canvasBrandLogo} src={canvasBrandLogo}
/> />

View File

@ -24,19 +24,10 @@ export async function generateMetadata(): Promise<Metadata> {
"AI design workspace for Canvas, Agent workflows, image editing, 3D/CAD, and local AI operations.", "AI design workspace for Canvas, Agent workflows, image editing, 3D/CAD, and local AI operations.",
icons: { icons: {
icon: [ icon: [
{
url: "/api/favicon?theme=dark",
media: "(prefers-color-scheme: dark)",
sizes: "any",
type: "image/png",
},
{ {
url: "/api/favicon", url: "/api/favicon",
media: "(prefers-color-scheme: light)",
sizes: "any", sizes: "any",
}, },
{ url: "/api/favicon?theme=dark", sizes: "any", type: "image/png" },
{ url: "/api/favicon", type: "image/x-icon" },
], ],
apple: "/api/favicon", apple: "/api/favicon",
shortcut: "/api/favicon", shortcut: "/api/favicon",

View File

@ -53,7 +53,6 @@ export function AgentCanvasTopNavDark({
}: AgentCanvasTopNavDarkProps) { }: AgentCanvasTopNavDarkProps) {
const resolvedSiteName = String(siteName || "AI Chatbot").trim() || "AI Chatbot"; const resolvedSiteName = String(siteName || "AI Chatbot").trim() || "AI Chatbot";
const displayLogo = siteLogoDark?.trim() || siteLogo?.trim() || ""; const displayLogo = siteLogoDark?.trim() || siteLogo?.trim() || "";
const shouldInvertLogo = !siteLogoDark?.trim() && Boolean(siteLogo?.trim());
return ( return (
<header className="fixed top-0 left-0 right-0 z-50 border-b border-white/5 bg-black/80 backdrop-blur-xl"> <header className="fixed top-0 left-0 right-0 z-50 border-b border-white/5 bg-black/80 backdrop-blur-xl">
@ -80,10 +79,7 @@ export function AgentCanvasTopNavDark({
<img <img
src={displayLogo} src={displayLogo}
alt={resolvedSiteName} alt={resolvedSiteName}
className={cn( className="h-8 w-8 shrink-0 object-contain"
"h-8 w-8 shrink-0 object-contain",
shouldInvertLogo && "brightness-0 invert"
)}
/> />
) : ( ) : (
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-white/10"> <div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-white/10">

View File

@ -6695,17 +6695,13 @@ function StylizedBrandLogo({
}) { }) {
const resolvedSiteName = resolveSiteName(siteName); const resolvedSiteName = resolveSiteName(siteName);
const displayLogo = siteLogoDark?.trim() || siteLogo?.trim() || ""; const displayLogo = siteLogoDark?.trim() || siteLogo?.trim() || "";
const shouldInvertLogo = !siteLogoDark?.trim() && Boolean(siteLogo?.trim());
return ( return (
<span className="flex min-w-0 items-center gap-2.5"> <span className="flex min-w-0 items-center gap-2.5">
{displayLogo ? ( {displayLogo ? (
<img <img
alt={resolvedSiteName} alt={resolvedSiteName}
className={cn( className="h-8 w-8 shrink-0 object-contain"
"h-8 w-8 shrink-0 object-contain",
shouldInvertLogo && "brightness-0 invert"
)}
src={displayLogo} src={displayLogo}
/> />
) : ( ) : (

View File

@ -33,9 +33,7 @@ export function CanvasLogoLoadingView({
alt={resolvedSiteName} alt={resolvedSiteName}
className={cn( className={cn(
"h-[34px] w-[34px] object-contain", "h-[34px] w-[34px] object-contain",
hasSeparateDarkLogo hasSeparateDarkLogo && "dark:hidden"
? "dark:hidden"
: "dark:brightness-0 dark:invert"
)} )}
src={lightLogo} src={lightLogo}
/> />

View File

@ -5,24 +5,12 @@ import { useEffect } from "react";
export function FaviconUpdater() { export function FaviconUpdater() {
useEffect(() => { useEffect(() => {
let isDisposed = false; let isDisposed = false;
const mediaQuery = window.matchMedia?.("(prefers-color-scheme: dark)"); const getFaviconUrl = () => "/api/favicon";
const getFaviconUrl = () => {
const html = document.documentElement;
const hasDarkClass = html.classList.contains("dark");
const hasLightClass = html.classList.contains("light");
const prefersDark = Boolean(mediaQuery?.matches);
const isDark = hasDarkClass || (!hasLightClass && prefersDark);
return isDark ? "/api/favicon?theme=dark" : "/api/favicon";
};
const updateFavicon = () => { const updateFavicon = () => {
if (isDisposed) return; if (isDisposed) return;
const urlWithTheme = getFaviconUrl(); const urlWithTheme = getFaviconUrl();
const iconType = urlWithTheme.includes("theme=dark")
? "image/png"
: "image/x-icon";
const href = const href =
`${urlWithTheme}${urlWithTheme.includes("?") ? "&" : "?"}v=${Date.now()}`; `${urlWithTheme}${urlWithTheme.includes("?") ? "&" : "?"}v=${Date.now()}`;
const managedSelector = const managedSelector =
@ -35,12 +23,12 @@ export function FaviconUpdater() {
link.href = href; link.href = href;
link.setAttribute("data-managed-favicon", "true"); link.setAttribute("data-managed-favicon", "true");
if (link.rel === "icon" || link.rel === "shortcut icon") { if (link.rel === "icon" || link.rel === "shortcut icon") {
link.type = iconType; link.removeAttribute("type");
link.setAttribute("sizes", "any"); link.setAttribute("sizes", "any");
} }
}); });
const ensureLink = (rel: string, type?: string) => { const ensureLink = (rel: string) => {
let link = document.querySelector( let link = document.querySelector(
`link[rel="${rel}"]` `link[rel="${rel}"]`
) as HTMLLinkElement | null; ) as HTMLLinkElement | null;
@ -51,17 +39,15 @@ export function FaviconUpdater() {
} }
link.href = href; link.href = href;
link.setAttribute("data-managed-favicon", "true"); link.setAttribute("data-managed-favicon", "true");
if (type) { link.removeAttribute("type");
link.type = type;
}
if (rel === "icon") { if (rel === "icon") {
link.setAttribute("sizes", "any"); link.setAttribute("sizes", "any");
} }
}; };
ensureLink("icon", iconType); ensureLink("icon");
ensureLink("apple-touch-icon"); ensureLink("apple-touch-icon");
ensureLink("shortcut icon", iconType); ensureLink("shortcut icon");
}; };
const observer = new MutationObserver(updateFavicon); const observer = new MutationObserver(updateFavicon);
@ -69,8 +55,6 @@ export function FaviconUpdater() {
attributes: true, attributes: true,
attributeFilter: ["class"], attributeFilter: ["class"],
}); });
mediaQuery?.addEventListener?.("change", updateFavicon);
Promise.resolve().then(() => { Promise.resolve().then(() => {
updateFavicon(); updateFavicon();
}); });
@ -78,7 +62,6 @@ export function FaviconUpdater() {
return () => { return () => {
isDisposed = true; isDisposed = true;
observer.disconnect(); observer.disconnect();
mediaQuery?.removeEventListener?.("change", updateFavicon);
}; };
}, []); }, []);

View File

@ -653,8 +653,6 @@ export function LovartHome({
resolvedTheme === "dark" resolvedTheme === "dark"
? siteLogoDark || siteLogo || "" ? siteLogoDark || siteLogo || ""
: siteLogo || siteLogoDark || ""; : siteLogo || siteLogoDark || "";
const shouldInvertLogo =
resolvedTheme === "dark" && !siteLogoDark && Boolean(siteLogo);
const { data: tutorialVideosData } = useSWR<{ videos: TutorialVideo[] }>( const { data: tutorialVideosData } = useSWR<{ videos: TutorialVideo[] }>(
isSecondaryDataReady && siteSettingsData?.tutorialEnabled isSecondaryDataReady && siteSettingsData?.tutorialEnabled
@ -1528,7 +1526,6 @@ export function LovartHome({
contentClassName="pl-[98px]" contentClassName="pl-[98px]"
logo={displayLogo} logo={displayLogo}
onLogoClick={() => window.scrollTo({ top: 0, behavior: "smooth" })} onLogoClick={() => window.scrollTo({ top: 0, behavior: "smooth" })}
shouldInvertLogo={shouldInvertLogo}
showBrand={false} showBrand={false}
siteName={siteName || "Lovart"} siteName={siteName || "Lovart"}
> >
@ -1778,7 +1775,6 @@ export function LovartHome({
? "/settings/agent-workflow" ? "/settings/agent-workflow"
: null : null
} }
shouldInvertLogo={shouldInvertLogo}
siteLogo={displayLogo} siteLogo={displayLogo}
siteName={siteName || "Lovart"} siteName={siteName || "Lovart"}
toolbox1Enabled={siteSettingsData?.toolbox1Enabled !== false} toolbox1Enabled={siteSettingsData?.toolbox1Enabled !== false}
@ -1814,7 +1810,6 @@ export function LovartHome({
prompt={prompt} prompt={prompt}
removeFile={removeFile} removeFile={removeFile}
setPrompt={setPrompt} setPrompt={setPrompt}
shouldInvertLogo={shouldInvertLogo}
siteName={siteName} siteName={siteName}
selectedModelId={selectedComposerModel.id} selectedModelId={selectedComposerModel.id}
/> />
@ -1952,7 +1947,7 @@ export function LovartHome({
<img <img
src={displayLogo} src={displayLogo}
alt={siteName} alt={siteName}
className={`h-7 w-7 rounded-full object-cover ${shouldInvertLogo ? "brightness-0 invert" : ""}`} className="h-7 w-7 rounded-full object-cover"
/> />
) : ( ) : (
<div className="flex h-7 w-7 items-center justify-center rounded-full bg-black text-white dark:bg-white dark:text-black"> <div className="flex h-7 w-7 items-center justify-center rounded-full bg-black text-white dark:bg-white dark:text-black">

View File

@ -34,7 +34,6 @@ type LovartHeroComposerProps = {
prompt: string; prompt: string;
removeFile: (id: string) => void; removeFile: (id: string) => void;
setPrompt: (value: string) => void; setPrompt: (value: string) => void;
shouldInvertLogo: boolean;
siteName: string; siteName: string;
modelOptions: ModelOption[]; modelOptions: ModelOption[];
onModelChange: (modelId: string) => void; onModelChange: (modelId: string) => void;
@ -60,7 +59,6 @@ export function LovartHeroComposer({
prompt, prompt,
removeFile, removeFile,
setPrompt, setPrompt,
shouldInvertLogo,
siteName, siteName,
modelOptions, modelOptions,
onModelChange, onModelChange,
@ -91,7 +89,7 @@ export function LovartHeroComposer({
<img <img
src={displayLogo} src={displayLogo}
alt={siteName} alt={siteName}
className={`h-10 w-10 rounded-full object-cover ${shouldInvertLogo ? "brightness-0 invert" : ""}`} className="h-10 w-10 rounded-full object-cover"
/> />
) : ( ) : (
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-black text-white dark:bg-white dark:text-black"> <div className="flex h-10 w-10 items-center justify-center rounded-full bg-black text-white dark:bg-white dark:text-black">

View File

@ -42,7 +42,6 @@ type LovartSidebarProps = {
} }
) => ReactNode; ) => ReactNode;
settingsHref: string | null; settingsHref: string | null;
shouldInvertLogo?: boolean;
siteLogo?: string | null; siteLogo?: string | null;
siteName: string; siteName: string;
toolbox1Enabled: boolean; toolbox1Enabled: boolean;
@ -71,7 +70,6 @@ export function LovartSidebar({
productPlanningEnabled, productPlanningEnabled,
renderIcon, renderIcon,
settingsHref, settingsHref,
shouldInvertLogo = false,
siteLogo, siteLogo,
siteName, siteName,
toolbox1Enabled, toolbox1Enabled,
@ -184,12 +182,7 @@ export function LovartSidebar({
<img <img
src={siteLogo} src={siteLogo}
alt={siteName} alt={siteName}
className={[ className="h-8 w-8 rounded-full object-cover"
"h-8 w-8 rounded-full object-cover",
shouldInvertLogo ? "brightness-0 invert" : "",
]
.filter(Boolean)
.join(" ")}
/> />
) : ( ) : (
<span className="flex h-8 w-8 items-center justify-center rounded-full bg-black text-[13px] font-semibold text-white dark:bg-white dark:text-black"> <span className="flex h-8 w-8 items-center justify-center rounded-full bg-black text-[13px] font-semibold text-white dark:bg-white dark:text-black">

View File

@ -12,7 +12,6 @@ type BrandTopBarProps = {
logo?: string | null; logo?: string | null;
onLogoClick?: () => void; onLogoClick?: () => void;
position?: "fixed" | "sticky" | "static"; position?: "fixed" | "sticky" | "static";
shouldInvertLogo?: boolean;
showBrand?: boolean; showBrand?: boolean;
siteName: string; siteName: string;
}; };
@ -25,7 +24,6 @@ export function BrandTopBar({
logo, logo,
onLogoClick, onLogoClick,
position = "fixed", position = "fixed",
shouldInvertLogo = false,
showBrand = true, showBrand = true,
siteName, siteName,
}: BrandTopBarProps) { }: BrandTopBarProps) {
@ -61,10 +59,7 @@ export function BrandTopBar({
{logo ? ( {logo ? (
<img <img
alt={resolvedSiteName} alt={resolvedSiteName}
className={cn( className="h-8 w-8 rounded-full object-cover"
"h-8 w-8 rounded-full object-cover",
shouldInvertLogo && "brightness-0 invert"
)}
src={logo} src={logo}
/> />
) : ( ) : (

View File

@ -59,8 +59,6 @@ export function PascalEditorFrame({
const lightLogo = String(siteLogo || "").trim(); const lightLogo = String(siteLogo || "").trim();
return darkLogo || lightLogo; return darkLogo || lightLogo;
}, [siteLogo, siteLogoDark]); }, [siteLogo, siteLogoDark]);
const shouldInvertLogo =
!String(siteLogoDark || "").trim() && Boolean(String(siteLogo || "").trim());
const userEmail = String(user?.email || "").trim(); const userEmail = String(user?.email || "").trim();
const userLabel = String(user?.name || userEmail || "已登录用户").trim(); const userLabel = String(user?.name || userEmail || "已登录用户").trim();
const isGuest = guestRegex.test(userEmail); const isGuest = guestRegex.test(userEmail);
@ -91,10 +89,7 @@ export function PascalEditorFrame({
{displayLogo ? ( {displayLogo ? (
<img <img
alt={resolvedSiteName} alt={resolvedSiteName}
className={cn( className="h-7 w-7 shrink-0 object-contain"
"h-7 w-7 shrink-0 object-contain",
shouldInvertLogo && "brightness-0 invert"
)}
src={displayLogo} src={displayLogo}
/> />
) : ( ) : (

View File

@ -150,7 +150,7 @@ export function TopNavbar({
} }
}; };
// 决定显示哪个 LOGO(浅色用普通,深色用暗色) // 彩色 logo 不能用滤镜自动反白;暗色主题只在配置了独立 dark logo 时切换。
const displayLogo = const displayLogo =
resolvedTheme === "dark" resolvedTheme === "dark"
? siteLogoDark && siteLogoDark.trim() !== "" ? siteLogoDark && siteLogoDark.trim() !== ""
@ -159,10 +159,6 @@ export function TopNavbar({
: siteLogo && siteLogo.trim() !== "" : siteLogo && siteLogo.trim() !== ""
? siteLogo ? siteLogo
: siteLogoDark; : siteLogoDark;
const shouldInvertLogo =
resolvedTheme === "dark" &&
(!siteLogoDark || siteLogoDark.trim() === "") &&
Boolean(siteLogo && siteLogo.trim() !== "");
const getShortLabel = (label: string) => { const getShortLabel = (label: string) => {
const trimmed = label.trim(); const trimmed = label.trim();
@ -287,7 +283,7 @@ export function TopNavbar({
{displayLogo && ( {displayLogo && (
<img <img
alt={siteName} alt={siteName}
className={shouldInvertLogo ? "h-7 w-7 object-contain brightness-0 invert" : "h-7 w-7 object-contain"} className="h-7 w-7 object-contain"
src={displayLogo} src={displayLogo}
/> />
)} )}