feat: update website layout, components, and assets
This commit is contained in:
94
src/components/for-people/FpCard.tsx
Normal file
94
src/components/for-people/FpCard.tsx
Normal file
@@ -0,0 +1,94 @@
|
||||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
/**
|
||||
* The single card system for the "For People" page.
|
||||
* Wraps the shared `.fp-card*` classes (defined in VerticalScrollWrapper) so
|
||||
* every section imports one component and the markup can't drift.
|
||||
*/
|
||||
|
||||
type Theme = 'light' | 'dark' | 'fill';
|
||||
|
||||
const themeClass: Record<Theme, string> = {
|
||||
light: 'fp-card--light',
|
||||
dark: 'fp-card--dark',
|
||||
fill: 'fp-card--fill',
|
||||
};
|
||||
|
||||
const DEFAULT_ICON_BG: Record<Theme, string> = {
|
||||
light: 'rgba(244,190,40,0.14)',
|
||||
dark: 'rgba(244,190,40,0.14)',
|
||||
fill: 'rgba(244,190,40,0.16)',
|
||||
};
|
||||
|
||||
const sora = 'Sora, sans-serif';
|
||||
|
||||
interface TagCardProps {
|
||||
theme?: Theme;
|
||||
icon: React.ReactNode;
|
||||
/** Icon-badge background; falls back to the theme's gold tint. */
|
||||
iconBg?: string;
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
/** Compact icon + label pill (radius 12). */
|
||||
export function FpTagCard({ theme = 'light', icon, iconBg, children, className = '', style }: TagCardProps) {
|
||||
return (
|
||||
<div className={`fp-card ${themeClass[theme]} ${className}`.trim()} style={style}>
|
||||
<span className="fp-card-icon" style={{ background: iconBg ?? DEFAULT_ICON_BG[theme] }}>{icon}</span>
|
||||
<span style={{
|
||||
fontSize: 13, fontWeight: 700, fontFamily: sora, letterSpacing: '-0.01em',
|
||||
whiteSpace: 'nowrap', color: theme === 'light' ? '#171512' : '#fff',
|
||||
}}>
|
||||
{children}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface StatCardProps {
|
||||
theme?: Theme;
|
||||
layout?: 'row' | 'column';
|
||||
icon: React.ReactNode;
|
||||
iconBg?: string;
|
||||
/** May be a plain node or a count-up <span> ref. */
|
||||
value: React.ReactNode;
|
||||
label: string;
|
||||
/** Value text color; defaults to theme-appropriate. */
|
||||
color?: string;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
/** Larger icon + value + label card (radius 20). */
|
||||
export function FpStatCard({
|
||||
theme = 'light', layout = 'column', icon, iconBg, value, label, color, className = '', style,
|
||||
}: StatCardProps) {
|
||||
const dark = theme !== 'light';
|
||||
const column = layout === 'column';
|
||||
return (
|
||||
<div
|
||||
className={`fp-card fp-card--stat ${themeClass[theme]} ${className}`.trim()}
|
||||
style={{ flexDirection: column ? 'column' : 'row', alignItems: 'center', ...style }}
|
||||
>
|
||||
<span className="fp-card-icon fp-card-icon--lg" style={{ background: iconBg ?? DEFAULT_ICON_BG[theme] }}>{icon}</span>
|
||||
<div style={{ textAlign: column ? 'center' : 'left' }}>
|
||||
<div style={{
|
||||
fontSize: column ? 'clamp(20px, 2.4vw, 26px)' : 18, fontWeight: 900, fontFamily: sora,
|
||||
letterSpacing: '-0.03em', lineHeight: 1, color: color ?? (dark ? '#fff' : '#171512'),
|
||||
}}>
|
||||
{value}
|
||||
</div>
|
||||
<div style={{
|
||||
fontSize: column ? 11.5 : 10.5, fontWeight: 600, marginTop: 5, fontFamily: sora,
|
||||
color: dark ? 'rgba(255,255,255,0.55)' : 'rgba(23,21,18,0.5)',
|
||||
}}>
|
||||
{label}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user