import type { Metadata } from "next"; import { cache } from "react"; import Link from "next/link"; import { Header } from "@/components/header/Header"; import { Footer } from "@/components/footer/Footer"; import { defineQuery } from "next-sanity"; import { sanity } from "@/lib/sanity"; import { ReleaseCover } from "@/components/release/ReleaseCover"; import { urlFor } from "@/lib/sanityImage"; import { ARTIST_PLACEHOLDER_SRC, CARD_GRID_CLASSES_4 } from "@/lib/constants"; import { ArrowLink } from "@/components/ArrowLink"; import { IconButtonLink } from "@/components/IconButton"; import { IoPersonOutline } from "react-icons/io5"; import { ReleaseCard, type ReleaseCardData } from "@/components/release/ReleaseCard"; import { BlogCard, type BlogCardData } from "@/components/blog/BlogCard"; import { ConcertTable, type ConcertData } from "@/components/concert/ConcertTable"; import { formatYears } from "@/components/artist/types"; import type { SanityImageSource } from "@sanity/image-url"; import type { TrackData } from "@/components/release/Tracklist"; import { FeaturedReleaseActions } from "@/components/release/FeaturedReleaseActions"; export const revalidate = 86400; type FeaturedAlbum = { name?: string; albumArtist?: string; slug?: string; albumCover?: SanityImageSource; shortDescription?: string; tracks?: TrackData[]; }; type FeaturedArtist = { name?: string; role?: string; slug?: string; image?: SanityImageSource; bioExcerpt?: string; }; type FeaturedComposer = { name?: string; slug?: string; birthYear?: number; deathYear?: number; image?: SanityImageSource; bioExcerpt?: string; }; type HomeSettings = { featuredAlbum: FeaturedAlbum | null; featuredArtist: FeaturedArtist | null; featuredComposer: FeaturedComposer | null; }; const SETTINGS_QUERY = defineQuery(` *[_type == "settings"][0]{ "featuredAlbum": featuredAlbum->{ name, albumArtist, "slug": slug.current, albumCover, shortDescription, "tracks": tracks[]{ "workId": work->_id, "workTitle": work->title, "composerName": work->composer->name, "arrangerName": work->arranger->name, movement, displayTitle, duration, artist, "previewMp3Url": previewMp3.asset->url } }, "featuredArtist": featuredArtist->{ name, role, "slug": slug.current, image, "bioExcerpt": pt::text(bio) }, "featuredComposer": featuredComposer->{ name, "slug": slug.current, birthYear, deathYear, image, "bioExcerpt": pt::text(bio) } } `); const LATEST_RELEASES_QUERY = defineQuery(` *[_type == "release"] | order(coalesce(releaseDate, "0000-01-01") desc) [0...8] { _id, name, albumArtist, catalogNo, releaseDate, "slug": slug.current, albumCover } `); const LATEST_BLOGS_QUERY = defineQuery(` *[_type == "blog"] | order(coalesce(publishDate, "0000-01-01") desc) [0...8] { _id, title, subtitle, author, publishDate, category, "slug": slug.current, featuredImage } `); const HOME_UPCOMING_CONCERTS_QUERY = defineQuery(` *[_type == "concert" && date >= $today] { _id, title, subtitle, date, time, locationName, city, country, "artists": artists[]->{ _id, name, "slug": slug.current }, ticketUrl } | order(date asc, time asc) [0...10] `); const getHomeSettings = cache(async () => { try { return await sanity.fetch(SETTINGS_QUERY); } catch (error) { console.error("Failed to fetch home settings:", error); return { featuredAlbum: null, featuredArtist: null, featuredComposer: null }; } }); export async function generateMetadata(): Promise { const { featuredAlbum: release } = await getHomeSettings(); const description = release?.shortDescription ?? "Recording the extraordinary."; const ogImage = release?.albumCover ? urlFor(release.albumCover).width(1200).height(1200).url() : undefined; return { title: "TRPTK • Recording the extraordinary", description, alternates: { canonical: "/" }, openGraph: { title: "TRPTK", description, type: "website", ...(ogImage && { images: [ { url: ogImage, width: 1200, height: 1200, alt: "TRPTK • Recording the extraordinary" }, ], }), }, twitter: { card: "summary_large_image", title: "TRPTK", description, ...(ogImage && { images: [ogImage] }), }, }; } function cardVisibility(index: number) { if (index < 4) return ""; if (index < 6) return "hidden md:block"; return "hidden lg:block"; } export default async function Home() { const today = new Date().toISOString().slice(0, 10); const [ { featuredAlbum: release, featuredArtist: artist, featuredComposer: composer }, latestReleases, latestBlogs, upcomingConcerts, ] = await Promise.all([ getHomeSettings(), sanity.fetch(LATEST_RELEASES_QUERY), sanity.fetch(LATEST_BLOGS_QUERY), sanity.fetch(HOME_UPCOMING_CONCERTS_QUERY, { today }), ]); const displayName = release?.name ?? ""; const displayArtist = release?.albumArtist ?? ""; const jsonLd = { "@context": "https://schema.org", "@type": "WebPage", name: "TRPTK", url: "https://trptk.com", description: "Recording the extraordinary.", ...(release && { mainEntity: { "@type": "MusicAlbum", name: release.name, ...(release.slug && { url: `https://trptk.com/release/${release.slug}` }), ...(release.albumArtist && { byArtist: { "@type": "MusicGroup", name: release.albumArtist }, }), ...(release.albumCover && { image: urlFor(release.albumCover).width(800).url(), }), }, }), }; return ( <>