initial commit
This commit is contained in:
commit
3ba76b4f02
90 changed files with 12507 additions and 0 deletions
145
docs/design-system/ui_kits/home/HeroZone.jsx
Normal file
145
docs/design-system/ui_kits/home/HeroZone.jsx
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
// HeroZone — the reserved interactive hero. For now a constrained placeholder:
|
||||
// a chamfer-clipped panel of warm chiaroscuro whose light source drifts toward
|
||||
// the pointer (the one signature motion moment), with the ink stroke parallaxing
|
||||
// and the watermark beneath. A toggle reveals the zone spec + safe area so any
|
||||
// future interactive element inherits the same frame.
|
||||
const ASSET = '../../assets';
|
||||
|
||||
function HeroZone() {
|
||||
const [p, setP] = React.useState({ x: 0.62, y: 0.28 });
|
||||
const [showSpec, setShowSpec] = React.useState(false);
|
||||
const ref = React.useRef(null);
|
||||
const reduce = React.useRef(
|
||||
typeof matchMedia !== 'undefined' &&
|
||||
matchMedia('(prefers-reduced-motion: reduce)').matches
|
||||
);
|
||||
|
||||
function onMove(e) {
|
||||
if (reduce.current) return;
|
||||
const r = ref.current.getBoundingClientRect();
|
||||
setP({
|
||||
x: Math.min(1, Math.max(0, (e.clientX - r.left) / r.width)),
|
||||
y: Math.min(1, Math.max(0, (e.clientY - r.top) / r.height)),
|
||||
});
|
||||
}
|
||||
function onLeave() {
|
||||
setP({ x: 0.62, y: 0.28 });
|
||||
}
|
||||
|
||||
// light follows pointer; ink drifts opposite for depth (short travel).
|
||||
const lx = 30 + p.x * 50;
|
||||
const ly = 8 + p.y * 40;
|
||||
const inkShift = `translate(${(0.5 - p.x) * 26}px, ${(0.5 - p.y) * 16}px)`;
|
||||
|
||||
const hz = {
|
||||
frame: {
|
||||
position: 'relative',
|
||||
width: '100%',
|
||||
aspectRatio: '4 / 5',
|
||||
borderRadius: 'var(--radius-cutout)',
|
||||
background: `radial-gradient(120% 95% at ${lx}% ${ly}%, #C9B299 0%, #8A6A47 30%, #4A3826 60%, #221E18 92%)`,
|
||||
transition: 'background 700ms var(--ease-out)',
|
||||
overflow: 'hidden',
|
||||
cursor: 'crosshair',
|
||||
boxShadow: 'var(--shadow-2)',
|
||||
},
|
||||
accent: {
|
||||
position: 'absolute',
|
||||
right: '9%',
|
||||
top: '12%',
|
||||
width: '76px',
|
||||
opacity: 0.16,
|
||||
filter: 'invert(1)',
|
||||
transform: inkShift,
|
||||
transition: 'transform 900ms var(--ease-out)',
|
||||
pointerEvents: 'none',
|
||||
},
|
||||
grain: {
|
||||
position: 'absolute',
|
||||
inset: 0,
|
||||
backgroundImage: `url(${ASSET}/texture-grain.svg)`,
|
||||
backgroundSize: '220px',
|
||||
opacity: 0.12,
|
||||
mixBlendMode: 'overlay',
|
||||
pointerEvents: 'none',
|
||||
},
|
||||
watermark: {
|
||||
position: 'absolute',
|
||||
left: '8%',
|
||||
bottom: '8%',
|
||||
width: '128px',
|
||||
opacity: 0.1,
|
||||
filter: 'invert(1)',
|
||||
pointerEvents: 'none',
|
||||
},
|
||||
toggle: {
|
||||
position: 'absolute',
|
||||
right: '8%',
|
||||
bottom: '7%',
|
||||
fontFamily: 'var(--font-mono)',
|
||||
fontSize: '10px',
|
||||
letterSpacing: '0.12em',
|
||||
textTransform: 'uppercase',
|
||||
color: 'rgba(239,231,218,0.55)',
|
||||
background: 'transparent',
|
||||
border: '1px solid rgba(239,231,218,0.22)',
|
||||
borderRadius: '2px',
|
||||
padding: '5px 9px',
|
||||
cursor: 'pointer',
|
||||
zIndex: 3,
|
||||
},
|
||||
safe: {
|
||||
position: 'absolute',
|
||||
inset: '9% 9% 9% 9%',
|
||||
border: '1px dashed rgba(239,231,218,0.4)',
|
||||
pointerEvents: 'none',
|
||||
display: showSpec ? 'block' : 'none',
|
||||
},
|
||||
safeLabel: {
|
||||
position: 'absolute',
|
||||
top: '-9px',
|
||||
left: '10px',
|
||||
background: '#221E18',
|
||||
padding: '0 6px',
|
||||
fontFamily: 'var(--font-mono)',
|
||||
fontSize: '9px',
|
||||
letterSpacing: '0.1em',
|
||||
color: 'rgba(239,231,218,0.7)',
|
||||
},
|
||||
placeholderTag: {
|
||||
position: 'absolute',
|
||||
left: '7%',
|
||||
top: '8%',
|
||||
fontFamily: 'var(--font-mono)',
|
||||
fontSize: '10px',
|
||||
letterSpacing: '0.14em',
|
||||
textTransform: 'uppercase',
|
||||
color: 'rgba(239,231,218,0.45)',
|
||||
display: showSpec ? 'block' : 'none',
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
style={hz.frame}
|
||||
onMouseMove={onMove}
|
||||
onMouseLeave={onLeave}
|
||||
>
|
||||
<img src={`${ASSET}/accent-ringdots.svg`} style={hz.accent} alt="" />
|
||||
<div style={hz.grain} />
|
||||
<span style={hz.placeholderTag}>Hero zone — interactive · TBD</span>
|
||||
<div style={hz.safe}>
|
||||
<span style={hz.safeLabel}>SAFE AREA · 1:1.25 · pad 9%</span>
|
||||
</div>
|
||||
<img src={`${ASSET}/mark-rings.svg`} style={hz.watermark} alt="" />
|
||||
<button
|
||||
style={hz.toggle}
|
||||
onClick={() => setShowSpec((s) => !s)}
|
||||
>
|
||||
{showSpec ? 'Hide spec' : 'Zone spec'}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Object.assign(window, { HeroZone });
|
||||
Loading…
Add table
Add a link
Reference in a new issue