Skip to content
Source
Sign inSign up
Open History to see the last commit

DraftHeroProjectHeading.tsx

63 lines2.6 KB

1import { useLayoutEffect, useRef, useState, type ReactNode } from "react";
2​
3import { observeResize } from "~/lib/observeResize";
4​
5export function DraftHeroProjectHeading({
6 children,
7 projectName,
8}: {
9 children: ReactNode;
10 projectName: string;
11}) {
12 const containerRef = useRef<HTMLDivElement>(null);
13 const inlineRef = useRef<HTMLSpanElement>(null);
14 const [fitsInline, setFitsInline] = useState(false);
15​
16 // oxlint-disable-next-line t3code/no-unreasoned-state-sync -- measures the heading against its container via ResizeObserver to choose inline or stacked layout
17 useLayoutEffect(() => {
18 const container = containerRef.current;
19 const inline = inlineRef.current;
20 if (!container || !inline) return;
21​
22 // Measure the full inline heading independently of its current layout, so
23 // moving the name below it cannot make the fit check oscillate.
24 const update = () =>
25 setFitsInline(
26 inline.getBoundingClientRect().width <= container.getBoundingClientRect().width,
27 );
28 update();
29 return observeResize([container, inline], update);
30 }, []);
31​
32 return (
33 <div ref={containerRef} className="group/draft-hero relative w-full" data-inline={fitsInline}>
34 <span
35 aria-hidden="true"
36 className="pointer-events-none invisible absolute inset-x-0 top-0 h-0 overflow-hidden"
37 >
38 <span
39 ref={inlineRef}
40 className="flex w-max items-baseline gap-2 whitespace-nowrap font-normal text-3xl tracking-tight"
41 >
42 <span>What should we build in</span>
43 <span>
44 <span className="font-medium">{projectName}</span>?
45 </span>
46 </span>
47 </span>
48 <h1 className="flex w-full flex-col items-center justify-center gap-2 text-center font-normal text-2xl text-foreground tracking-tight sm:text-3xl lg:group-data-[inline=true]/draft-hero:flex-row">
49 <span className="max-w-full lg:group-data-[inline=true]/draft-hero:shrink-0 [@media(max-height:28rem)]:sr-only">
50 What should we build
51 <span className="lg:group-data-[inline=true]/draft-hero:hidden">?</span>
52 <span className="hidden lg:group-data-[inline=true]/draft-hero:inline"> in</span>
53 </span>
54 <span className="flex min-w-0 max-w-full items-baseline justify-center text-base tracking-normal lg:group-data-[inline=true]/draft-hero:text-3xl lg:group-data-[inline=true]/draft-hero:tracking-tight">
55 <span className="min-w-0">{children}</span>
56 <span className="hidden shrink-0 lg:group-data-[inline=true]/draft-hero:inline [@media(max-height:28rem)]:hidden!">
57 ?
58 </span>
59 </span>
60 </h1>
61 </div>
62 );