| 1 | --- |
| 2 | import { Image } from "astro:assets"; |
| 3 | import pastoral from "@/assets/the-pastoral-state.jpg"; |
| 4 | import savage from "@/assets/the-savage-state.jpg"; |
| 5 | import consumation from "@/assets/the-consumation-of-empire.jpg"; |
| 6 | import desolation from "@/assets/desolation.jpg"; |
| 7 | import destruction from "@/assets/destruction.jpg"; |
| 8 | |
| 9 | const paintings = [ |
| 10 | { |
| 11 | src: savage, |
| 12 | title: "The Savage State", |
| 13 | year: "1834", |
| 14 | description: |
| 15 | "The first in Thomas Cole's Course of Empire. Dawn breaks over a wilderness as nomadic hunters chase a wounded deer and storm clouds wreathe the mountain. Nature is supreme; man clings to its edges.", |
| 16 | link: "https://explorethomascole.org/project/the-savage-state/", |
| 17 | }, |
| 18 | { |
| 19 | src: pastoral, |
| 20 | title: "The Pastoral or Arcadian State", |
| 21 | year: "1834", |
| 22 | description: |
| 23 | "The second in Thomas Cole's Course of Empire. Morning light, cleared fields, a Stonehenge-like temple, an old man tracing geometry in the dirt while a boy sketches a figure on stone. Civilization stirs; agriculture, science, art, all still close to the earth.", |
| 24 | link: "https://explorethomascole.org/project/the-arcadian-or-pastoral-state/", |
| 25 | }, |
| 26 | { |
| 27 | src: consumation, |
| 28 | title: "The Consummation of Empire", |
| 29 | year: "1836", |
| 30 | description: |
| 31 | "The central panel of Thomas Cole's Course of Empire. High noon over a marble city. A triumphant ruler crosses the bridge in an elephant-drawn car, temples crowd the bay, the harbor brims with ships. Splendor so total it can only precede collapse.", |
| 32 | link: "https://explorethomascole.org/project/the-consummation-of-empire/", |
| 33 | }, |
| 34 | { |
| 35 | src: destruction, |
| 36 | title: "Destruction", |
| 37 | year: "1836", |
| 38 | description: |
| 39 | "The fourth panel of Thomas Cole's Course of Empire. Storm and sack. Invaders pour through the gates, the temple porch becomes a catapult, ships burn in the harbor, a headless warrior presides over the slaughter as the sky turns to fire.", |
| 40 | link: "https://explorethomascole.org/project/destruction/", |
| 41 | }, |
| 42 | { |
| 43 | src: desolation, |
| 44 | title: "Desolation", |
| 45 | year: "1836", |
| 46 | description: |
| 47 | "The final panel of Thomas Cole's Course of Empire. Sunset and moonrise over silent ruins. Vines climb a lone column, a bird nests where a temple stood, deer roam the broken friezes. No human figures remain. Nature outlasts everything man builds.", |
| 48 | link: "https://explorethomascole.org/project/desolation/", |
| 49 | }, |
| 50 | ]; |
| 51 | |
| 52 | const estHour = parseInt( |
| 53 | new Date().toLocaleString("en-US", { |
| 54 | timeZone: "America/New_York", |
| 55 | hour: "numeric", |
| 56 | hour12: false, |
| 57 | }), |
| 58 | ); |
| 59 | |
| 60 | const boundaries = [6, 9, 12, 15, 18]; |
| 61 | const idx = boundaries.findLastIndex((b) => estHour >= b); |
| 62 | const { src, title, year, description, link } = paintings[idx === -1 ? 4 : idx]; |
| 63 | --- |
| 64 | |
| 65 | <div class="hero-wrapper mb-12" id="hero-wrapper"> |
| 66 | <a href={link} target="_blank" rel="noreferrer"> |
| 67 | <Image |
| 68 | src={src} |
| 69 | loading="eager" |
| 70 | fetchpriority="high" |
| 71 | decoding="async" |
| 72 | widths={[640, 960, 1280, 1920]} |
| 73 | sizes="(max-width: 768px) 100vw, 1280px" |
| 74 | formats={['avif', 'webp']} |
| 75 | alt={`${title} by Thomas Cole`} |
| 76 | class="aspect-video w-full object-cover" |
| 77 | /> |
| 78 | <div class="hero-overlay" id="hero-overlay" aria-hidden="true"> |
| 79 | <p class="hero-title">{title} <span class="hero-year">({year})</span></p> |
| 80 | <p class="hero-desc">{description}</p> |
| 81 | </div> |
| 82 | </a> |
| 83 | </div> |
| 84 | |
| 85 | <style> |
| 86 | .hero-wrapper { |
| 87 | position: relative; |
| 88 | overflow: hidden; |
| 89 | } |
| 90 | |
| 91 | .hero-overlay { |
| 92 | position: absolute; |
| 93 | inset: 0; |
| 94 | background: rgba(18, 17, 19, 0.76); |
| 95 | display: flex; |
| 96 | flex-direction: column; |
| 97 | justify-content: flex-end; |
| 98 | padding: 1.5rem; |
| 99 | opacity: 0; |
| 100 | transition: opacity 0.4s ease; |
| 101 | pointer-events: none; |
| 102 | } |
| 103 | |
| 104 | .hero-overlay.visible { |
| 105 | opacity: 1; |
| 106 | } |
| 107 | |
| 108 | .hero-title { |
| 109 | font-weight: 600; |
| 110 | color: #fff; |
| 111 | font-size: 1rem; |
| 112 | margin-bottom: 0.35rem; |
| 113 | } |
| 114 | |
| 115 | .hero-year { |
| 116 | font-weight: 400; |
| 117 | color: #aaa; |
| 118 | } |
| 119 | |
| 120 | .hero-desc { |
| 121 | color: #ccc; |
| 122 | font-size: 0.8125rem; |
| 123 | line-height: 1.55; |
| 124 | max-width: 60ch; |
| 125 | } |
| 126 | </style> |
| 127 | |
| 128 | <script> |
| 129 | const wrapper = document.getElementById("hero-wrapper"); |
| 130 | const overlay = document.getElementById("hero-overlay"); |
| 131 | |
| 132 | wrapper?.addEventListener("mouseenter", () => { |
| 133 | overlay?.classList.add("visible"); |
| 134 | }); |
| 135 | |
| 136 | wrapper?.addEventListener("mouseleave", () => { |
| 137 | overlay?.classList.remove("visible"); |
| 138 | }); |
| 139 | </script> |