Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 21 additions & 15 deletions src/components/Landing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1475,7 +1475,7 @@ export function Landing() {
useEffect(() => {
const updateStroke = () => {
const convo = convoRef.current;
const mascot = document.getElementById('mascot-core'); // Targets the 260x260 container
const mascot = document.getElementById('mascot-core'); // Targets the mascot's square container
const container = pageContainerRef.current;
const features = document.getElementById('features');
if (!convo || !mascot || !container || !features) return;
Expand Down Expand Up @@ -1548,7 +1548,7 @@ export function Landing() {

// Scroll-spy: highlight the nav item for whichever section the reader is in. Active = the LAST
// section whose top has crossed ~38% of the viewport height (document order:
// philosophy -> how-it-works -> Mr.OneHook -> get-app). Above the first section nothing highlights.
// philosophy -> how-it-works -> Intelligence -> get-app). Above the first section nothing highlights.
useEffect(() => {
const ids = ['philosophy', 'features', 'under-the-hood', 'get-app'];
let raf = 0;
Expand Down Expand Up @@ -1935,7 +1935,7 @@ export function Landing() {
<span className="h-4 w-px" />
<span className={deskNav('')}>Philosophy</span>
<span className={deskNav('')}>How it works</span>
<span className={deskNav('')}>Mr.OneHook</span>
<span className={deskNav('')}>Intelligence</span>
<span className={deskNav('')}>Get the app</span>
<span className="h-4 w-px" />
<span className={deskNav('')}>Pricing</span>
Expand Down Expand Up @@ -1993,7 +1993,7 @@ export function Landing() {
onClick={() => scrollToSection('under-the-hood')} {...trackProps(UiElement.LANDING_SECTION_NAV, { value: 'under_the_hood' })}
className={deskNav('under-the-hood')}
>
Mr.OneHook
Intelligence
</button>
<button
onClick={() => scrollToSection('get-app')} {...trackProps(UiElement.LANDING_SECTION_NAV, { value: 'get_app' })}
Expand Down Expand Up @@ -2034,7 +2034,7 @@ export function Landing() {
How it works
</button>
<button onClick={() => scrollToSection('under-the-hood')} {...trackProps(UiElement.LANDING_SECTION_NAV, { value: 'under_the_hood' })} className={mobNav('under-the-hood')}>
Mr.OneHook
Intelligence
</button>
<button onClick={() => scrollToSection('get-app')} {...trackProps(UiElement.LANDING_SECTION_NAV, { value: 'get_app' })} className={mobNav('get-app')}>
Get the app
Expand Down Expand Up @@ -2105,7 +2105,7 @@ export function Landing() {
onClick={() => scrollToSection('under-the-hood')} {...trackProps(UiElement.LANDING_SECTION_NAV, { value: 'under_the_hood' })}
className={mobNav('under-the-hood')}
>
Mr.OneHook
Intelligence
</button>
<button
onClick={() => scrollToSection('get-app')} {...trackProps(UiElement.LANDING_SECTION_NAV, { value: 'get_app' })}
Expand Down Expand Up @@ -2837,13 +2837,13 @@ export function Landing() {
<div className="max-w-6xl mx-auto px-6 sm:px-12 lg:px-16">
<section className="relative pb-16 lg:pb-20 pt-10">
<div className="max-w-3xl relative mx-auto text-center">
<Kicker chapter="03" className="mb-5 text-white/60">Mr.OneHook</Kicker>
<Kicker chapter="03" className="mb-5 text-white/60">Intelligence</Kicker>

<h2 className={SECTION_TITLE}>
The <Accent tone="silver">science</Accent> of one good match.
</h2>
<p className={`${SECTION_LEAD} mt-6 text-white/70`}>
Mr.OneHook does the hard work under the hood, so all you see is one person worth meeting.
OneHook Intelligence does the hard work under the hood, so all you see is one person worth meeting.
</p>
</div>

Expand Down Expand Up @@ -2957,19 +2957,24 @@ export function Landing() {
className="relative flex flex-col items-center justify-center gap-6 mx-auto z-10 w-full"
id="mascot-container"
>
{/* Message Above Mascot */}
<div className="rounded-2xl border-2 border-accent bg-white px-6 py-4 text-center text-[11px] font-black uppercase leading-relaxed tracking-[0.14em] text-accent shadow-2xl">
Click to watch me explain more about onehook.club
</div>
{/* Message above the mascot: also opens the explainer video */}
<button
type="button"
onClick={() => setShowMascotVideo(true)}
{...trackProps(UiElement.LANDING_DEMO_INTERACT, { value: 'mascot' })}
className="rounded-2xl border-2 border-accent bg-white px-6 py-4 text-center text-[11px] font-black uppercase leading-relaxed tracking-[0.14em] text-accent shadow-2xl transition-transform hover:-translate-y-0.5 focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2"
>
Click to watch Mr.OneHook explain more about onehook.club
</button>

{/* The Mascot */}
<div
id="mascot-core"
className="relative w-[260px] h-[260px] flex items-center justify-center shrink-0"
className="relative flex h-[var(--mascot)] w-[var(--mascot)] shrink-0 items-center justify-center [--mascot:clamp(84px,28vw,180px)]"
ref={mascotRef}
>
<AlienScanner
className="w-[260px] h-[260px] shrink-0"
className="h-[var(--mascot)] w-[var(--mascot)] shrink-0"
primaryColor="#ff69b4"
scanColor="#0052CC"
onClick={() => setShowMascotVideo((open) => !open)}
Expand All @@ -2979,7 +2984,8 @@ export function Landing() {
</div>

{/* Social Links Below Mascot */}
<div className="flex w-max items-center justify-center gap-2 rounded-xl border border-accent bg-white/90 backdrop-blur-sm px-5 py-3 text-[10px] font-black uppercase tracking-[0.14em] text-accent shadow-lg">
{/* On narrow screens the sparkle's lower labels sit either side of this pill: start it below them. */}
<div className="flex w-max items-center justify-center gap-2 rounded-xl border border-accent bg-white/90 backdrop-blur-sm px-5 py-3 text-[10px] font-black uppercase tracking-[0.14em] text-accent shadow-lg max-sm:mt-10">
MR.ONEHOOK'S SOCIALS:
<a
href="https://www.instagram.com/mr.onehook"
Expand Down
2 changes: 1 addition & 1 deletion src/components/common/SiteFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export function SiteFooter({ compact = false }: { compact?: boolean }) {
How it works
</button>
<button onClick={() => goToSection('under-the-hood')} {...trackProps(UiElement.LANDING_SECTION_NAV, { value: 'under_the_hood' })} className="hover:opacity-100 transition-opacity">
Mr.OneHook
Intelligence
</button>
</span>
</div>
Expand Down
30 changes: 26 additions & 4 deletions src/components/common/SiteHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,28 @@ function isMobileDevice(): boolean {
return /Android|iPhone|iPad|iPod|Mobile/i.test(navigator.userAgent);
}

/** The long-form story pages share one header layout (see `fitTitles`). */
export const STORY_PAGE_TITLES = ['Science', 'Messenger'] as const;

/**
* Lightweight top header used on standalone pages (login, redeem, legal pages). The brand
* mark returns to the landing page. On mobile devices an "Open in app" action
* appears on the right so users can jump into the native app.
*
* @param pageTitle - Optional page title to display in the center (e.g., "Privacy", "Terms", "Pricing")
* @param onApply - Optional callback for Apply button (e.g., on Careers page). Shows button next to close button.
* @param fitTitles - Sibling pages that should share one header layout. The full-or-compact choice is
* made for the widest of these titles, so every page in the group switches at the same width.
*/
export function SiteHeader({ pageTitle, onApply }: { pageTitle?: string; onApply?: () => void }) {
export function SiteHeader({
pageTitle,
onApply,
fitTitles,
}: {
pageTitle?: string;
onApply?: () => void;
fitTitles?: readonly string[];
}) {
const navigate = useNavigate();
const mobile = isMobileDevice();

Expand All @@ -30,6 +43,7 @@ export function SiteHeader({ pageTitle, onApply }: { pageTitle?: string; onApply
const actionsRef = useRef<HTMLDivElement>(null);
const measureRef = useRef<HTMLDivElement>(null);
const measureTitleRef = useRef<HTMLDivElement>(null);
const fitKey = (fitTitles ?? []).join('|');
const [compact, setCompact] = useState(false);
useLayoutEffect(() => {
const row = rowRef.current;
Expand All @@ -42,7 +56,11 @@ export function SiteHeader({ pageTitle, onApply }: { pageTitle?: string; onApply
const actionsLeft = actionsRef.current?.getBoundingClientRect().left ?? rowBox.right;
const GAP = 16;
const markRight = left + measure.scrollWidth;
const titleW = measureTitleRef.current?.scrollWidth ?? 0;
// The widest of the measured titles (this page's, plus any sibling pages sharing the layout).
const titleW = Math.max(
0,
...[...(measureTitleRef.current?.children ?? [])].map((el) => (el as HTMLElement).scrollWidth)
);
let next: boolean;
if (titleW) {
const centre = rowBox.left + rowBox.width / 2;
Expand All @@ -64,7 +82,7 @@ export function SiteHeader({ pageTitle, onApply }: { pageTitle?: string; onApply
ro.disconnect();
window.removeEventListener('resize', check);
};
}, [pageTitle]);
}, [pageTitle, fitKey]);

return (
<header className="sticky top-0 z-40 w-full border-b border-border bg-white/80 backdrop-blur-md">
Expand All @@ -75,7 +93,11 @@ export function SiteHeader({ pageTitle, onApply }: { pageTitle?: string; onApply
</div>
{pageTitle && (
<div ref={measureTitleRef} aria-hidden="true" className="pointer-events-none invisible absolute left-0 top-0 w-max whitespace-nowrap text-xs sm:text-sm font-black uppercase tracking-[0.2em]">
{pageTitle}
{[pageTitle, ...(fitTitles ?? [])].map((t, i) => (
<div key={`${i}-${t}`} className="w-max">
{t}
</div>
))}
</div>
)}
<div className="flex min-w-0 items-center gap-3 pr-3">
Expand Down
4 changes: 2 additions & 2 deletions src/components/mascot/AlienScanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export const AlienScanner: React.FC<AlienScannerProps> = ({
className,
style,
onClick,
hoverLabel = 'Click to watch me explain more about onehook.club',
hoverLabel = 'Click to watch Mr.OneHook explain more about onehook.club',
forceExcited = false,
hideTooltips = false,
settled = false,
Expand Down Expand Up @@ -297,7 +297,7 @@ export const AlienScanner: React.FC<AlienScannerProps> = ({
{!bare && <AiSparkle
settled={settled}
size="320%"
className="hidden md:block absolute top-[80%] left-1/2 -translate-x-1/2 -translate-y-1/2 -z-10 pointer-events-none opacity-80"
className="absolute top-[80%] left-1/2 -translate-x-1/2 -translate-y-1/2 -z-10 pointer-events-none opacity-80"
/>}

{/* Excited hover tooltip (plain conditional: exit-coordination could leave
Expand Down
Loading
Loading