Use WhyMyRatingLogo component with horizontal-full variant

- Copy logo component from brand site (standalone version)
- Use horizontal-full variant in header
- Tagline: 'Project Hub'

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Alejandro Gutiérrez
2026-02-02 01:11:09 +00:00
parent 7f91f28b37
commit e3959607eb
3 changed files with 258 additions and 37 deletions

View File

@@ -1,7 +1,7 @@
'use client';
import { useState } from 'react';
import { Icon } from '@/components';
import { Icon, WhyMyRatingLogo } from '@/components';
type TabId = 'home' | 'settings';
@@ -27,42 +27,7 @@ export default function Home() {
<header className="sticky top-0 z-50 bg-white dark:bg-stone-950 border-b border-slate-200 dark:border-stone-800">
<div className="max-w-4xl mx-auto px-4 sm:px-6">
<div className="py-4 flex items-center justify-between">
<div className="flex items-center gap-3">
{/* WhyRating Logo Icon */}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120" width="44" height="44">
<defs>
<clipPath id="lens-clip">
<circle cx="60" cy="62" r="21"/>
</clipPath>
</defs>
<polygon
points="60,15 71.5,42 101,46 79.5,66 85,95 60,82 35,95 40.5,66 19,46 48.5,42"
fill="#FBBC05"
stroke="#FBBC05"
strokeWidth="6"
strokeLinejoin="round"
/>
<g>
<circle cx="60" cy="62" r="27" fill="#1E293B"/>
<line x1="83" y1="81" x2="95" y2="91" stroke="#1E293B" strokeWidth="9" strokeLinecap="round"/>
<circle cx="60" cy="62" r="21" fill="#FEF3C7"/>
<rect x="68" y="44" width="11" height="18" rx="1.5" fill="#15803D"/>
<g clipPath="url(#lens-clip)">
<rect x="42" y="58" width="11" height="35" rx="1.5" fill="#86EFAC"/>
<rect x="55" y="51" width="11" height="42" rx="1.5" fill="#22C55E"/>
<rect x="68" y="44" width="11" height="49" rx="1.5" fill="#15803D"/>
</g>
</g>
</svg>
<div>
<h1 className="font-bold text-xl text-slate-900 dark:text-stone-100">
whyrating<span className="text-amber-500">.com</span>
</h1>
<p className="text-xs text-slate-500 dark:text-stone-500">
The story behind your stars
</p>
</div>
</div>
<WhyMyRatingLogo variant="horizontal-full" size={140} colorScheme="dark" />
</div>
{/* Tabs */}

View File

@@ -0,0 +1,255 @@
'use client';
import { useId } from 'react';
export type LogoVariant = 'icon' | 'primary' | 'full' | 'horizontal' | 'horizontal-full' | 'horizontal-v2' | 'horizontal-full-v2';
export type ColorScheme = 'light' | 'dark' | 'mono-dark' | 'mono-light';
interface WhyMyRatingLogoProps {
size?: number;
variant?: LogoVariant;
colorScheme?: ColorScheme;
tagline?: string;
}
// Hub-specific defaults
const config = {
domain: 'whyrating',
domainTLD: '.com',
tagline: 'Project Hub',
};
export function WhyMyRatingLogo({
size = 120,
variant = 'primary',
colorScheme = 'light',
tagline,
}: WhyMyRatingLogoProps) {
// Generate unique ID for clip paths
const clipId = useId();
// Use custom tagline if provided
const displayTagline = tagline || config.tagline;
// Enforce minimum sizes per guidelines
const minSize = variant === 'icon' ? 32 : 120;
const u = Math.max(size, minSize);
const calc = {
icon: u,
wordmarkFont: u * 0.15,
taglineFont: u * 0.092,
gapIconToWordmark: u * 0.02,
gapWordmarkToTagline: u * 0.05,
clearSpace: u * 0.12,
horizontalIcon: u * 0.60,
horizontalWordmarkFont: u * 0.233,
horizontalTaglineFont: u * 0.13,
horizontalGap: u * 0.176,
horizontalClearSpace: u * 0.05,
// V2: Tighter proportions - less gap, bigger text
v2Icon: u * 0.50,
v2Gap: u * 0.10,
v2WordmarkFont: u * 0.28,
v2TaglineFont: u * 0.15,
v2ClearSpace: u * 0.02,
};
const isDark = colorScheme === 'dark';
const isMono = colorScheme === 'mono-dark' || colorScheme === 'mono-light';
const monoColor = colorScheme === 'mono-light' ? '#FFFFFF' : '#1E293B';
const monoContrast = colorScheme === 'mono-light' ? '#1E293B' : '#FFFFFF';
const colors = isMono ? {
star: monoColor,
magnifier: monoColor,
lens: 'none',
barLight: monoColor,
barMid: monoColor,
barDark: monoColor,
wordmark: monoColor,
accent: monoColor,
tagline: monoColor,
stroke: monoContrast,
strokeWidth: 2,
} : {
star: '#FBBC05',
magnifier: '#1E293B',
lens: '#FEF3C7',
barLight: '#86EFAC',
barMid: '#22C55E',
barDark: '#15803D',
wordmark: isDark ? '#FAFAF9' : '#1E293B',
accent: '#F59E0B',
tagline: isDark ? '#A8A29E' : '#64748B',
stroke: isDark ? '#78716C' : 'none',
strokeWidth: isDark ? 1.5 : 0,
};
const LogoIcon = ({ iconSize }: { iconSize?: number }) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 120 120"
width={iconSize || calc.icon}
height={iconSize || calc.icon}
>
<defs>
<clipPath id={clipId}>
<circle cx="60" cy="62" r="21"/>
</clipPath>
</defs>
{isMono && (
<polygon
points="60,15 71.5,42 101,46 79.5,66 85,95 60,82 35,95 40.5,66 19,46 48.5,42"
fill="none"
stroke={colors.stroke}
strokeWidth="8"
strokeLinejoin="round"
/>
)}
<polygon
points="60,15 71.5,42 101,46 79.5,66 85,95 60,82 35,95 40.5,66 19,46 48.5,42"
fill={colors.star}
stroke={colors.star}
strokeWidth="6"
strokeLinejoin="round"
/>
<g>
{isDark && !isMono && (
<line x1="83" y1="81" x2="95" y2="91" stroke="#78716C" strokeWidth="11" strokeLinecap="round"/>
)}
{isMono && (
<line x1="83" y1="81" x2="95" y2="91" stroke={monoContrast} strokeWidth="12" strokeLinecap="round"/>
)}
{isMono && (
<circle cx="60" cy="62" r="28" fill="none" stroke={monoContrast} strokeWidth="2"/>
)}
<circle cx="60" cy="62" r="27" fill={colors.magnifier}/>
<line x1="83" y1="81" x2="95" y2="91" stroke={colors.magnifier} strokeWidth="9" strokeLinecap="round"/>
{!isMono && <circle cx="60" cy="62" r="21" fill={colors.lens}/>}
{isMono && (
<circle cx="60" cy="62" r="21" fill={monoContrast} stroke={colors.stroke} strokeWidth="2"/>
)}
{isMono && (
<rect x="68" y="62" width="11" height="21" rx="1.5" fill={colors.barDark} stroke={monoContrast} strokeWidth="2" clipPath={`url(#${clipId})`}/>
)}
{isMono && (
<rect x="68" y="44" width="11" height="18" rx="1.5" fill={colors.barDark} stroke={monoContrast} strokeWidth="2"/>
)}
{isMono && <rect x="69" y="60" width="9" height="4" fill={colors.barDark}/>}
{!isMono && <rect x="68" y="44" width="11" height="18" rx="1.5" fill={colors.barDark}/>}
<g clipPath={`url(#${clipId})`}>
<rect x="42" y="58" width="11" height="35" rx="1.5" fill={colors.barLight}/>
<rect x="55" y="51" width="11" height="42" rx="1.5" fill={colors.barMid}/>
{!isMono && <rect x="68" y="44" width="11" height="49" rx="1.5" fill={colors.barDark}/>}
</g>
</g>
</svg>
);
const Wordmark = ({ fontSize }: { fontSize?: number }) => (
<span
className="font-bold leading-tight tracking-tight"
style={{ fontSize: fontSize || calc.wordmarkFont, color: colors.wordmark }}
>
{config.domain}<span style={{ color: colors.accent }}>{config.domainTLD}</span>
</span>
);
const Tagline = ({ fontSize }: { fontSize?: number }) => (
<span
style={{ fontSize: fontSize || calc.taglineFont, color: colors.tagline }}
>
{displayTagline}
</span>
);
if (variant === 'icon') {
return (
<div className="inline-flex" style={{ padding: calc.clearSpace }}>
<LogoIcon />
</div>
);
}
if (variant === 'primary') {
return (
<div className="inline-flex flex-col items-center" style={{ padding: calc.clearSpace }}>
<LogoIcon />
<div style={{ height: calc.gapIconToWordmark }} />
<Wordmark />
</div>
);
}
if (variant === 'full') {
return (
<div className="inline-flex flex-col items-center" style={{ padding: calc.clearSpace }}>
<LogoIcon />
<div style={{ height: calc.gapIconToWordmark }} />
<Wordmark />
<div style={{ height: calc.gapWordmarkToTagline }} />
<Tagline />
</div>
);
}
if (variant === 'horizontal') {
return (
<div className="inline-flex items-center" style={{ padding: calc.horizontalClearSpace }}>
<div style={{ marginTop: calc.horizontalIcon * 0.02 }}>
<LogoIcon iconSize={calc.horizontalIcon} />
</div>
<div style={{ width: calc.horizontalGap }} />
<Wordmark fontSize={calc.horizontalWordmarkFont} />
</div>
);
}
if (variant === 'horizontal-full') {
return (
<div className="inline-flex items-center" style={{ padding: calc.horizontalClearSpace }}>
<LogoIcon iconSize={calc.horizontalIcon} />
<div style={{ width: calc.horizontalGap }} />
<div className="flex flex-col">
<Wordmark fontSize={calc.horizontalWordmarkFont} />
<div style={{ height: calc.gapWordmarkToTagline * 0.5 }} />
<Tagline fontSize={calc.horizontalTaglineFont} />
</div>
</div>
);
}
if (variant === 'horizontal-v2') {
return (
<div className="inline-flex items-center" style={{ padding: calc.v2ClearSpace }}>
<LogoIcon iconSize={calc.v2Icon} />
<div style={{ width: calc.v2Gap }} />
<Wordmark fontSize={calc.v2WordmarkFont} />
</div>
);
}
if (variant === 'horizontal-full-v2') {
const textGap = u * 0.02;
const totalTextHeight = calc.v2WordmarkFont + textGap + calc.v2TaglineFont;
const fullIconSize = totalTextHeight / 0.667;
const iconOffset = fullIconSize * 0.12;
return (
<div className="inline-flex items-center" style={{ padding: calc.v2ClearSpace }}>
<div style={{ marginTop: iconOffset }}>
<LogoIcon iconSize={fullIconSize} />
</div>
<div style={{ width: calc.v2Gap }} />
<div className="flex flex-col">
<Wordmark fontSize={calc.v2WordmarkFont} />
<div style={{ height: textGap }} />
<Tagline fontSize={calc.v2TaglineFont} />
</div>
</div>
);
}
return null;
}

View File

@@ -1 +1,2 @@
export { Icon, icons } from './Icons';
export { WhyMyRatingLogo } from './WhyMyRatingLogo';