diff --git a/app/components/home-social-links.tsx b/app/components/home-social-links.tsx index 6ca0de8..1a0cb8f 100644 --- a/app/components/home-social-links.tsx +++ b/app/components/home-social-links.tsx @@ -83,7 +83,7 @@ export default function HomeSocialLinks() { `home-social-link home-social-link--${brand}`; return ( -
+
{SOCIAL_LINKS.map(({ href, label, tip, ariaLabel, brand, external, icon }) => ( {external ? ( diff --git a/app/components/identity-photo-column.tsx b/app/components/identity-photo-column.tsx new file mode 100644 index 0000000..a6f0a06 --- /dev/null +++ b/app/components/identity-photo-column.tsx @@ -0,0 +1,76 @@ +"use client"; + +import { useLayoutEffect, useRef, useState } from "react"; +import AvatarCard from "./avatar-card"; +import HomeSocialLinks from "./home-social-links"; +import { TocSection } from "./toc-section"; + +const MIN_AVATAR_PX = 120; +/** Space between avatar bottom and social row (matches `gap-4`). */ +const AVATAR_SOCIAL_GAP_PX = 16; +const MD_MEDIA = "(min-width: 768px)"; + +function measureAvatarPx(column: HTMLElement, social: HTMLElement): number { + const available = column.clientHeight - social.offsetHeight - AVATAR_SOCIAL_GAP_PX; + const width = column.clientWidth; + return Math.max(MIN_AVATAR_PX, Math.min(width, available)); +} + +export default function IdentityPhotoColumn() { + const columnRef = useRef(null); + const socialRef = useRef(null); + const [avatarPx, setAvatarPx] = useState(null); + + useLayoutEffect(() => { + const column = columnRef.current; + const social = socialRef.current; + if (!column || !social) return; + + const update = () => { + if (!window.matchMedia(MD_MEDIA).matches) { + setAvatarPx(null); + return; + } + setAvatarPx(measureAvatarPx(column, social)); + }; + + update(); + + const ro = new ResizeObserver(update); + ro.observe(column); + ro.observe(social); + + const mq = window.matchMedia(MD_MEDIA); + mq.addEventListener("change", update); + + return () => { + ro.disconnect(); + mq.removeEventListener("change", update); + }; + }, []); + + return ( +
+
+ +
+ + +
+ +
+
+ +
+
+ ); +} diff --git a/app/page.tsx b/app/page.tsx index 0d5e3d8..97d5934 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,9 +1,8 @@ -import AvatarCard from "./components/avatar-card"; import JumpText from "./components/jump-text"; import ListeningCard from "./components/listening-card"; import WeatherCard from "./components/weather-card"; import ProjectsSplit from "./components/oxford-dul/projects-split"; -import HomeSocialLinks from "./components/home-social-links"; +import IdentityPhotoColumn from "./components/identity-photo-column"; import { TocSection } from "./components/toc-section"; import { getPinnedProjects } from "./lib/github-pinned"; import { getBerkeleyWeather } from "./lib/weather"; @@ -131,18 +130,7 @@ export default async function Home() {
- {/* Photo + social */} -
-
- -
- - - - - -
-
+
{/* ── Layer 2: Status Cards ───────────────────────────────── */}