* fix(branding): render tenant logos unoptimized so self-hosted sidebars work (#2203) On the official Docker image a byrå logo uploaded under Settings > Brand worked as favicon but rendered broken in the sidebar. BrandHomeLink (and BrandWordmark) sent the Supabase Storage URL through the Next.js image optimizer, whose remote-host allowlist is derived from NEXT_PUBLIC_SUPABASE_URL at BUILD time. The generic image bakes a sentinel there and docker-entrypoint.sh substitutes the real URL only at container start, so /_next/image answered 400 '"url" parameter is not allowed'. Both tenant-logo <Image> elements now pass `unoptimized`: the browser fetches the public object directly, which is exactly what the favicon already did, and CSP img-src already permits https:. The remotePatterns block in next.config.ts stays for builds that know the URL, with its comment updated to say what it still covers. Closes #2203 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VnConrmMCxJRQ5kfiPPWyy * chore: carry the DECISIONS.md line for this PR in #2247 instead (append-only log conflicts on every merge) --------- Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
72 lines
2.8 KiB
TypeScript
72 lines
2.8 KiB
TypeScript
'use client'
|
|
|
|
/**
|
|
* Dashboard sidebar brand mark: the top-left home link (WL-12 slice A3).
|
|
*
|
|
* On a branded host with an uploaded logo it renders that logo; on every
|
|
* other host it renders exactly the legacy `getBranding().logoPath` image
|
|
* with the same dimensions, classes and aria-label as before, keeping
|
|
* default hosts byte-identical.
|
|
*
|
|
* With `showLabel` (expanded sidebar) a branded host without an uploaded
|
|
* logo renders the brand's app name beside the mark (byra-editable in the
|
|
* Varumärke settings). With an uploaded logo the logo carries the brand
|
|
* alone (same founder call as BrandWordmark, 2026-08-05: byrå logos usually
|
|
* carry their own name, so logo + text read as a duplicate). Unbranded
|
|
* hosts never show a label.
|
|
*/
|
|
|
|
import Link from 'next/link'
|
|
import Image from 'next/image'
|
|
import { useBranding } from '@/lib/branding/brand-context'
|
|
import { useCompanyOptional } from '@/contexts/CompanyContext'
|
|
|
|
export function BrandHomeLink({ showLabel = false }: { showLabel?: boolean }) {
|
|
const { appName, logoUrl, logoPath, brand } = useBranding()
|
|
const label = brand && !logoUrl ? brand.appName : null
|
|
// Byrå team members (any role) home to the cockpit, never to "/" (which
|
|
// would open whatever client company happens to be active). Everyone
|
|
// outside a byrå keeps the legacy home link.
|
|
const byraTeam = useCompanyOptional()?.byraTeam
|
|
const homeHref = byraTeam ? '/byra' : '/'
|
|
return (
|
|
<Link href={homeHref} aria-label={appName} className="flex items-center gap-2 rounded-lg">
|
|
{logoUrl ? (
|
|
<Image
|
|
src={logoUrl}
|
|
alt=""
|
|
width={26}
|
|
height={26}
|
|
className="h-[26px] w-[26px] rounded-lg object-contain"
|
|
// Tenant logos live on the deployment's Supabase Storage host, and
|
|
// the image optimizer only allows that host when
|
|
// NEXT_PUBLIC_SUPABASE_URL was known at BUILD time. The generic
|
|
// Docker image bakes a sentinel and substitutes the real URL at
|
|
// container start, so on self-hosted installs /_next/image answered
|
|
// 400 '"url" parameter is not allowed' and the sidebar mark rendered
|
|
// broken while the favicon (same URL, no optimizer) worked (issue
|
|
// #2203). The browser fetches the public object directly instead; at
|
|
// 26px there is nothing to optimize anyway.
|
|
unoptimized
|
|
/>
|
|
) : (
|
|
<Image
|
|
src={logoPath}
|
|
alt=""
|
|
width={26}
|
|
height={26}
|
|
className="h-[26px] w-[26px] rounded-lg"
|
|
/>
|
|
)}
|
|
{showLabel && label && (
|
|
<span
|
|
className="truncate font-display text-base tracking-tight text-foreground"
|
|
style={{ fontWeight: 700 }}
|
|
>
|
|
{label}
|
|
</span>
|
|
)}
|
|
</Link>
|
|
)
|
|
}
|