Visitza Branded Logo

PartnerLogo, SupplierLogo, and AdminLogo — wordmark plus vertical separator and uppercase product suffix.

Source

registry/client/visitza/ui/branded-logo.tsx
import * as React from 'react';
import { cn } from '@/lib/utils';
import { Logo } from '@/components/ui/logo';
import type { LogoProps } from '@/components/ui/logo';

// ── Types ───────────────────────────────────────────────────────────────────

type BrandedLogoVariant = 'default' | 'on-dark' | 'mono';

interface BrandedLogoProps extends Omit<LogoProps, 'markerColor' | 'zaColor'> {
  /** Visual variant preset */
  variant?: BrandedLogoVariant;
  /** Override the suffix label (default derived from component) */
  label?: string;
  /** Additional className for the suffix text */
  labelClassName?: string;
}

// ── Colour presets per variant ───────────────────────────────────────────────

const PARTNER_COLORS: Record<BrandedLogoVariant, { marker: string; za: string; suffix: string; separator: string }> = {
  default:   { marker: 'hsl(200 80% 45%)', za: 'hsl(24 95% 53%)',            suffix: 'hsl(200 80% 45%)', separator: 'hsl(200 80% 45% / 0.5)' },
  'on-dark': { marker: 'hsl(200 70% 58%)', za: 'hsl(24 95% 58%)',            suffix: 'hsl(200 70% 58%)', separator: 'hsl(200 70% 58% / 0.5)' },
  mono:      { marker: 'rgba(255,255,255,0.4)', za: 'rgba(255,255,255,0.4)', suffix: 'rgba(255,255,255,0.4)', separator: 'rgba(255,255,255,0.2)' },
};

const SUPPLIER_COLORS: Record<BrandedLogoVariant, { marker: string; za: string; suffix: string; separator: string }> = {
  default:   { marker: 'hsl(38 92% 45%)',  za: 'hsl(24 95% 53%)',            suffix: 'hsl(38 92% 45%)', separator: 'hsl(38 92% 45% / 0.5)' },
  'on-dark': { marker: 'hsl(38 85% 55%)',  za: 'hsl(24 95% 58%)',            suffix: 'hsl(38 85% 55%)', separator: 'hsl(38 85% 55% / 0.5)' },
  mono:      { marker: 'rgba(255,255,255,0.4)', za: 'rgba(255,255,255,0.4)', suffix: 'rgba(255,255,255,0.4)', separator: 'rgba(255,255,255,0.2)' },
};

const ADMIN_COLORS: Record<BrandedLogoVariant, { marker: string; za: string; suffix: string; separator: string }> = {
  default:   { marker: 'hsl(220 10% 25%)', za: 'hsl(24 95% 53%)',            suffix: 'hsl(220 10% 25%)', separator: 'hsl(220 10% 25% / 0.5)' },
  'on-dark': { marker: 'hsl(220 10% 50%)', za: 'hsl(24 95% 58%)',            suffix: 'hsl(220 10% 50%)', separator: 'hsl(220 10% 50% / 0.5)' },
  mono:      { marker: 'rgba(255,255,255,0.4)', za: 'rgba(255,255,255,0.4)', suffix: 'rgba(255,255,255,0.4)', separator: 'rgba(255,255,255,0.2)' },
};

// ── Inner builder ───────────────────────────────────────────────────────────

function buildBrandedLogo(
  displayName: string,
  defaultLabel: string,
  palette: Record<BrandedLogoVariant, { marker: string; za: string; suffix: string; separator: string }>,
) {
  const BrandedLogo = React.forwardRef<SVGSVGElement, BrandedLogoProps & React.SVGAttributes<SVGSVGElement>>(
    ({ variant = 'default', label, labelClassName, className, mono, monoColor, visitColor, ringColor, ...props }, ref) => {
      const colors = palette[mono ? 'mono' : variant];
      const suffixText = (label ?? defaultLabel).toUpperCase();

      // The base Logo viewBox is "0 0 960 300".
      // Separator line sits after wordmark, then suffix text.
      const sepX = 975;
      const textX = sepX + 32;
      const charWidth = 78; // uppercase char width at fontSize 115 + 0.12em tracking
      const suffixWidth = suffixText.length * charWidth + 60;
      const totalWidth = textX + suffixWidth;

      // Wordmark vertical range is roughly y=108 to y=230
      const lineTop = 100;
      const lineBottom = 235;

      return (
        <svg
          ref={ref}
          viewBox={`0 0 ${totalWidth} 300`}
          className={cn('block shrink-0', className)}
          xmlns="http://www.w3.org/2000/svg"
          {...props}
        >
          {/* Nested base logo at original viewBox coordinates */}
          <Logo
            markerColor={colors.marker}
            zaColor={colors.za}
            visitColor={visitColor}
            ringColor={ringColor}
            mono={mono}
            monoColor={monoColor}
            x={0}
            y={0}
            width={960}
            height={300}
          />

          {/* Separator line */}
          <line
            x1={sepX}
            y1={lineTop}
            x2={sepX}
            y2={lineBottom}
            stroke={colors.separator}
            strokeWidth={4.5}
            strokeLinecap="round"
          />

          {/* Suffix text — marker colour, all caps */}
          <text
            x={textX}
            y={225}
            style={{
              fill: colors.suffix,
              fontSize: 115,
              fontFamily: "'Jost', 'Calibri', system-ui, sans-serif",
              fontWeight: 600,
              letterSpacing: '0.12em',
              transition: 'fill 500ms ease',
            }}
          >
            {suffixText}
          </text>
        </svg>
      );
    },
  );
  BrandedLogo.displayName = displayName;
  return BrandedLogo;
}

// ── Exports ─────────────────────────────────────────────────────────────────

const PartnerLogo = buildBrandedLogo('PartnerLogo', 'partner', PARTNER_COLORS);
const SupplierLogo = buildBrandedLogo('SupplierLogo', 'supplier', SUPPLIER_COLORS);
const AdminLogo = buildBrandedLogo('AdminLogo', 'admin', ADMIN_COLORS);

export { PartnerLogo, SupplierLogo, AdminLogo };
export type { BrandedLogoProps, BrandedLogoVariant };