feat(brand): new brand module + logo assets
Adds the canonical brand definition used by the v0.42.0 brand refresh:
- client/lib/brand.ts — single source of truth for name, tagline,
repository URL, asset paths, navigation glyphs, and accent palette
(BRAND_GLYPHS / accent tokens consumed by Brand.tsx + page chrome).
- client/components/brand/Brand.tsx — BrandMark (img with the
logo asset), BrandWordmark, BrandGlyph, and a small BrandStack
used by the layout chrome.
- client/public/brand/{logo,pwa-192,pwa-512,apple-touch-icon}.png —
replaces the inline img-cut references in README/HISTORY with a
canonical set; PWA manifest + favicon now point here.
This is commit 1 of 9 splitting the working-tree brand refresh into
per-layer commits. Each commit is independently buildable; the order
matches the dependency direction (lib → component → chrome → UI
primitives → page consumers → admin/dialog consumers → docs).
This commit is contained in:
parent
1f57b22ff8
commit
dfee7f9401
|
|
@ -0,0 +1,53 @@
|
||||||
|
import type { ComponentProps } from 'react';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
import { BRAND, BRAND_GLYPHS, type BrandGlyphName } from '@/lib/brand';
|
||||||
|
|
||||||
|
type ImgProps = Omit<ComponentProps<'img'>, 'src' | 'alt'>;
|
||||||
|
|
||||||
|
export function BrandMark({ className, ...props }: ImgProps) {
|
||||||
|
return (
|
||||||
|
<img
|
||||||
|
src={BRAND.assets.logo}
|
||||||
|
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,
|
||||||
|
iconClassName,
|
||||||
|
}: {
|
||||||
|
name: BrandGlyphName;
|
||||||
|
className?: string;
|
||||||
|
iconClassName?: string;
|
||||||
|
}) {
|
||||||
|
const glyph = BRAND_GLYPHS[name];
|
||||||
|
const Icon = glyph.icon;
|
||||||
|
|
||||||
|
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',
|
||||||
|
'before:absolute before:inset-x-2 before:bottom-1.5 before:h-4 before:rounded-t-sm before:bg-gradient-to-t before:from-primary/25 before:to-primary/5',
|
||||||
|
'after:absolute after:inset-x-3 after:bottom-1.5 after:h-6 after:rounded-t-sm after:border-l after:border-r after:border-primary/15',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
aria-label={glyph.label}
|
||||||
|
role="img"
|
||||||
|
>
|
||||||
|
<Icon className={cn('relative z-10 h-5 w-5', iconClassName)} />
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
import {
|
||||||
|
BarChart3,
|
||||||
|
CalendarDays,
|
||||||
|
Database,
|
||||||
|
Landmark,
|
||||||
|
LockKeyhole,
|
||||||
|
Receipt,
|
||||||
|
ShieldCheck,
|
||||||
|
TrendingDown,
|
||||||
|
type LucideIcon,
|
||||||
|
} from 'lucide-react';
|
||||||
|
|
||||||
|
export const BRAND = {
|
||||||
|
name: 'Bill Tracker',
|
||||||
|
compactName: 'Bill Tracker',
|
||||||
|
tagline: 'Calm command for household money.',
|
||||||
|
repositoryUrl: 'https://dream.scheller.ltd/null/BillTracker',
|
||||||
|
assets: {
|
||||||
|
logo: '/brand/logo.png',
|
||||||
|
favicon: '/brand/logo.png',
|
||||||
|
appleTouchIcon: '/brand/apple-touch-icon.png',
|
||||||
|
pwa192: '/brand/pwa-192.png',
|
||||||
|
pwa512: '/brand/pwa-512.png',
|
||||||
|
legacyLogo: '/img/logo.png',
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type BrandGlyphName =
|
||||||
|
| 'tracker'
|
||||||
|
| 'bills'
|
||||||
|
| 'calendar'
|
||||||
|
| 'analytics'
|
||||||
|
| 'data'
|
||||||
|
| 'banking'
|
||||||
|
| 'snowball'
|
||||||
|
| 'security';
|
||||||
|
|
||||||
|
export const BRAND_GLYPHS: Record<BrandGlyphName, { label: string; icon: LucideIcon }> = {
|
||||||
|
tracker: { label: 'Tracker', icon: BarChart3 },
|
||||||
|
bills: { label: 'Bills', icon: Receipt },
|
||||||
|
calendar: { label: 'Calendar', icon: CalendarDays },
|
||||||
|
analytics: { label: 'Analytics', icon: BarChart3 },
|
||||||
|
data: { label: 'Data', icon: Database },
|
||||||
|
banking: { label: 'Banking', icon: Landmark },
|
||||||
|
snowball: { label: 'Snowball', icon: TrendingDown },
|
||||||
|
security: { label: 'Security', icon: ShieldCheck },
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ADMIN_GLYPH = { label: 'Admin', icon: LockKeyhole } as const;
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 143 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 115 KiB |
Loading…
Reference in New Issue