139 lines
5.7 KiB
TypeScript
139 lines
5.7 KiB
TypeScript
import { useId, type ComponentProps } from 'react';
|
|
import { cn } from '@/lib/utils';
|
|
import { BRAND, BRAND_GLYPHS, type BrandGlyphName } from '@/lib/brand';
|
|
import { useTheme } from '@/contexts/ThemeContext';
|
|
|
|
type ImgProps = Omit<ComponentProps<'img'>, 'src' | 'alt'>;
|
|
|
|
export function BrandMark({ className, ...props }: ImgProps) {
|
|
const { resolvedTheme } = useTheme();
|
|
const src = resolvedTheme === 'light' ? BRAND.assets.logoLight : BRAND.assets.logo;
|
|
|
|
return (
|
|
<img
|
|
src={src}
|
|
alt={BRAND.name}
|
|
className={cn('object-contain', className)}
|
|
{...props}
|
|
/>
|
|
);
|
|
}
|
|
|
|
export function BrandWordmark({ compact = false, className }: { compact?: boolean; className?: string }) {
|
|
return (
|
|
<span className={cn('font-semibold tracking-tight text-foreground', className)}>
|
|
{compact ? BRAND.compactName : BRAND.name}
|
|
</span>
|
|
);
|
|
}
|
|
|
|
export function BrandGlyph({
|
|
name,
|
|
className,
|
|
}: {
|
|
name: BrandGlyphName;
|
|
className?: string;
|
|
}) {
|
|
const glyph = BRAND_GLYPHS[name];
|
|
const gradientId = `bt-glyph-${useId().replace(/:/g, '')}`;
|
|
|
|
return (
|
|
<span
|
|
className={cn(
|
|
'relative inline-grid h-10 w-10 shrink-0 place-items-center overflow-hidden rounded-xl',
|
|
'border border-primary/20 bg-primary/[0.08] text-primary shadow-sm shadow-primary/10',
|
|
className,
|
|
)}
|
|
aria-label={glyph.label}
|
|
role="img"
|
|
>
|
|
<svg viewBox="0 0 48 48" className="h-7 w-7" aria-hidden="true">
|
|
<defs>
|
|
<linearGradient id={gradientId} x1="8" x2="40" y1="40" y2="8" gradientUnits="userSpaceOnUse">
|
|
<stop offset="0" stopColor="currentColor" stopOpacity="0.68" />
|
|
<stop offset="1" stopColor="currentColor" />
|
|
</linearGradient>
|
|
</defs>
|
|
<BrandGlyphShape name={name} gradientId={gradientId} />
|
|
</svg>
|
|
</span>
|
|
);
|
|
}
|
|
|
|
function BrandGlyphShape({ name, gradientId }: { name: BrandGlyphName; gradientId: string }) {
|
|
const fill = `url(#${gradientId})`;
|
|
const commonStroke = 'currentColor';
|
|
|
|
switch (name) {
|
|
case 'bills':
|
|
return (
|
|
<>
|
|
<path d="M13 8h22v31l-4-3-4 3-4-3-4 3-4-3-2 1.5V8Z" fill="none" stroke={commonStroke} strokeWidth="3" strokeLinejoin="round" opacity="0.88" />
|
|
<path d="M18 17h12M18 24h10M18 31h7" stroke={commonStroke} strokeWidth="3" strokeLinecap="round" opacity="0.72" />
|
|
<path d="m27 17 3 3 7-8" fill="none" stroke={commonStroke} strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" />
|
|
</>
|
|
);
|
|
case 'calendar':
|
|
return (
|
|
<>
|
|
<rect x="10" y="12" width="28" height="27" rx="5" fill="none" stroke={commonStroke} strokeWidth="3" />
|
|
<path d="M16 8v8M32 8v8M11 20h26" stroke={commonStroke} strokeWidth="3" strokeLinecap="round" />
|
|
<rect x="17" y="25" width="6" height="6" rx="2" fill={fill} />
|
|
<path d="m25 31 3 3 7-8" fill="none" stroke={commonStroke} strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" />
|
|
</>
|
|
);
|
|
case 'analytics':
|
|
return (
|
|
<>
|
|
<path d="M10 36h30" stroke={commonStroke} strokeWidth="3" strokeLinecap="round" opacity="0.35" />
|
|
<path d="M12 31 20 23l7 5 10-14" fill="none" stroke={commonStroke} strokeWidth="4" strokeLinecap="round" strokeLinejoin="round" />
|
|
<circle cx="20" cy="23" r="3" fill={fill} />
|
|
<circle cx="37" cy="14" r="3" fill={fill} />
|
|
</>
|
|
);
|
|
case 'data':
|
|
return (
|
|
<>
|
|
<ellipse cx="24" cy="13" rx="13" ry="5" fill="none" stroke={commonStroke} strokeWidth="3" />
|
|
<path d="M11 13v19c0 2.8 5.8 5 13 5s13-2.2 13-5V13" fill="none" stroke={commonStroke} strokeWidth="3" />
|
|
<path d="M11 22c0 2.8 5.8 5 13 5s13-2.2 13-5M11 31c0 2.8 5.8 5 13 5s13-2.2 13-5" stroke={commonStroke} strokeWidth="3" opacity="0.58" />
|
|
<path d="m29 23 3 3 7-8" fill="none" stroke={commonStroke} strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" />
|
|
</>
|
|
);
|
|
case 'banking':
|
|
return (
|
|
<>
|
|
<path d="M8 18 24 9l16 9H8Z" fill="none" stroke={commonStroke} strokeWidth="3" strokeLinejoin="round" />
|
|
<path d="M13 21v13M21 21v13M29 21v13M37 21v13M10 38h28" stroke={commonStroke} strokeWidth="3" strokeLinecap="round" />
|
|
<path d="m28 29 3 3 7-8" fill="none" stroke={commonStroke} strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" />
|
|
</>
|
|
);
|
|
case 'snowball':
|
|
return (
|
|
<>
|
|
<circle cx="17" cy="18" r="5" fill="none" stroke={commonStroke} strokeWidth="3" opacity="0.74" />
|
|
<circle cx="29" cy="28" r="9" fill="none" stroke={commonStroke} strokeWidth="3" />
|
|
<path d="M11 37c8-1 18-7 27-23" fill="none" stroke={commonStroke} strokeWidth="4" strokeLinecap="round" />
|
|
<path d="m31 14 7 0 0 7" fill="none" stroke={commonStroke} strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" />
|
|
</>
|
|
);
|
|
case 'security':
|
|
return (
|
|
<>
|
|
<path d="M24 8 37 13v10c0 8-5 14-13 17-8-3-13-9-13-17V13l13-5Z" fill="none" stroke={commonStroke} strokeWidth="3" strokeLinejoin="round" />
|
|
<path d="m18 24 4 4 9-10" fill="none" stroke={commonStroke} strokeWidth="4" strokeLinecap="round" strokeLinejoin="round" />
|
|
</>
|
|
);
|
|
case 'tracker':
|
|
default:
|
|
return (
|
|
<>
|
|
<rect x="10" y="25" width="7" height="13" rx="2.5" fill={fill} opacity="0.78" />
|
|
<rect x="20.5" y="18" width="7" height="20" rx="2.5" fill={fill} opacity="0.88" />
|
|
<rect x="31" y="11" width="7" height="27" rx="2.5" fill={fill} />
|
|
<path d="m10 15 8 8 20-16" fill="none" stroke={commonStroke} strokeWidth="4" strokeLinecap="round" strokeLinejoin="round" />
|
|
</>
|
|
);
|
|
}
|
|
}
|