diff --git a/src/components/GlassyRecordCard.css b/src/components/GlassyRecordCard.css index 4aa8d45..26ea3a3 100644 --- a/src/components/GlassyRecordCard.css +++ b/src/components/GlassyRecordCard.css @@ -86,6 +86,7 @@ .glassy-record-card__button { display: grid; + align-items: start; width: 100%; grid-template-columns: minmax(10rem, 1fr) minmax(36rem, 42rem); gap: 1rem; @@ -118,6 +119,7 @@ .glassy-record-card__aside { display: grid; align-self: start; + margin-top: var(--record-aside-offset, 0px); grid-template-columns: minmax(15rem, 1fr) minmax(8.75rem, 9.5rem) 7.75rem 1.25rem; @@ -225,6 +227,7 @@ .glassy-record-card__aside { display: flex; + margin-top: 0; flex-wrap: wrap; justify-content: flex-start; } diff --git a/src/components/GlassyRecordCard.tsx b/src/components/GlassyRecordCard.tsx index 740b0a7..35d6b62 100644 --- a/src/components/GlassyRecordCard.tsx +++ b/src/components/GlassyRecordCard.tsx @@ -1,4 +1,4 @@ -import type { ReactNode } from "react"; +import { useLayoutEffect, useRef, type ReactNode } from "react"; import { ChevronDown } from "lucide-react"; @@ -40,6 +40,42 @@ export function GlassyRecordCard({ summary, title, }: GlassyRecordCardProps) { + const headerRef = useRef(null); + useLayoutEffect(() => { + const header = headerRef.current; + if (!header) return; + const copy = header.querySelector(".glassy-record-card__copy"); + const summary = header.querySelector( + ".glassy-record-card__summary", + ); + const aside = header.querySelector( + ".glassy-record-card__aside", + ); + if (!copy || !summary || !aside) return; + + const alignMetadata = () => { + // Anchor to the collapsed header even while the full summary is visible. + const summaryLineHeight = Number.parseFloat( + getComputedStyle(summary).minHeight, + ); + const expandedHeight = Math.max( + 0, + summary.getBoundingClientRect().height - summaryLineHeight, + ); + const collapsedHeight = + copy.getBoundingClientRect().height - expandedHeight; + const offset = Math.max( + 0, + (collapsedHeight - aside.getBoundingClientRect().height) / 2, + ); + header.style.setProperty("--record-aside-offset", `${offset}px`); + }; + alignMetadata(); + const observer = new ResizeObserver(alignMetadata); + for (const element of [copy, summary, aside]) observer.observe(element); + return () => observer.disconnect(); + }, []); + const renderedSummary = typeof summary === "string" ? normalizePreviewText(summary) : summary; @@ -55,6 +91,7 @@ export function GlassyRecordCard({ )} >