/onthisday redesign: CD's green-key "letter" with hero + year overlay
Rebuilt /onthisday to CD's On This Day design — the QOTD "letter" language in a green key: deckle frame, "On This Day" eyelash title, a flush dateline rule, a hero image with a left scrim and the year overlaid (Playfair), the event in Playfair italic, a "The story" note, and a "Read more on Wikipedia" pill. Wired to live /api/onthisday/today; hero sits on a deep-green backdrop so transparent seal/logo images never read as broken. HubShell (bar + Back + footer + icon). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -8,11 +8,13 @@
|
||||
|
||||
const MONTHS = ['January', 'February', 'March', 'April', 'May', 'June',
|
||||
'July', 'August', 'September', 'October', 'November', 'December'];
|
||||
function dayLabel(dateStr) {
|
||||
if (!dateStr) return '';
|
||||
const [, m, d] = dateStr.split('-').map(Number);
|
||||
return `${MONTHS[m - 1]} ${d}`;
|
||||
const WEEKDAYS = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
|
||||
function dateline(s) {
|
||||
if (!s) return '';
|
||||
const [y, m, d] = s.split('-').map(Number);
|
||||
return `${WEEKDAYS[new Date(y, m - 1, d).getDay()]}, ${MONTHS[m - 1]} ${d}`;
|
||||
}
|
||||
let readLabel = $derived(f?.source_url?.includes('wikipedia') ? 'Read more on Wikipedia' : 'Read more');
|
||||
|
||||
onMount(async () => {
|
||||
try {
|
||||
@@ -32,25 +34,50 @@
|
||||
<HubShell active="">
|
||||
<article class="otd-page">
|
||||
{#if state === 'ready'}
|
||||
<p class="eyebrow">A good thing today</p>
|
||||
<h1 class="date">{dayLabel(f.date)}</h1>
|
||||
<!-- CD's "letter" treatment in a green key: deckle frame, dateline, hero with year overlay -->
|
||||
<div class="card">
|
||||
<div class="deckle">
|
||||
<div class="eyebrow">
|
||||
<span class="eye-rule"></span>
|
||||
<span class="eye-label">On This Day</span>
|
||||
</div>
|
||||
|
||||
<div class="event">
|
||||
<p class="year-line"><span class="year">{f.year}</span><span class="ago">on this day in history</span></p>
|
||||
<p class="fact">{f.text}</p>
|
||||
<div class="dateline">
|
||||
<span class="dl-rule"></span>
|
||||
<span class="dl-label">{dateline(f.date)}</span>
|
||||
</div>
|
||||
|
||||
<div class="hero">
|
||||
{#if f.image_url}
|
||||
<img class="hero-img" src={f.image_url} alt="" loading="lazy" />
|
||||
{/if}
|
||||
<div class="hero-scrim"></div>
|
||||
<div class="hero-year">
|
||||
<div class="hy-eyebrow">In history</div>
|
||||
<div class="hy-year">{f.year}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="headline">{f.text}</p>
|
||||
|
||||
{#if f.summary}
|
||||
<div class="story-head">
|
||||
<span class="sh-rule"></span>
|
||||
<span class="sh-label">The story</span>
|
||||
</div>
|
||||
<p class="story">{f.summary}</p>
|
||||
{/if}
|
||||
|
||||
{#if f.source_url}
|
||||
<div class="cta-row">
|
||||
<a class="cta" href={f.source_url} target="_blank" rel="noopener">
|
||||
{readLabel}
|
||||
<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if f.image_url}
|
||||
<div class="photo" style="background-image:url({f.image_url})"></div>
|
||||
{/if}
|
||||
|
||||
{#if f.summary}
|
||||
<p class="summary">{f.summary}</p>
|
||||
{/if}
|
||||
|
||||
{#if f.source_url}
|
||||
<a class="source" href={f.source_url} target="_blank" rel="noopener">Read more on Wikipedia →</a>
|
||||
{/if}
|
||||
{:else if state === 'empty'}
|
||||
<p class="note">Today's moment in history is on its way. Check back soon.</p>
|
||||
{:else}
|
||||
@@ -60,40 +87,64 @@
|
||||
</HubShell>
|
||||
|
||||
<style>
|
||||
.otd-page { max-width: 680px; margin: 0 auto; text-align: center; }
|
||||
.eyebrow {
|
||||
font-size: 12px; font-weight: 700; letter-spacing: 0.18em; text-transform: uppercase;
|
||||
color: #3f9a66; margin: clamp(8px, 3vw, 28px) 0 0;
|
||||
@font-face { font-family: 'Playfair Display'; src: url('/fonts/playfair-var.woff2') format('woff2'); font-weight: 500 700; font-style: normal; font-display: swap; }
|
||||
@font-face { font-family: 'Playfair Display'; src: url('/fonts/playfair-italic-var.woff2') format('woff2'); font-weight: 500 700; font-style: italic; font-display: swap; }
|
||||
|
||||
.otd-page { max-width: 880px; margin: 0 auto; }
|
||||
|
||||
.card {
|
||||
position: relative; margin-top: clamp(24px, 4vw, 40px); background: #f6ead0;
|
||||
border: 1px solid rgba(120, 90, 40, 0.10); border-radius: 16px;
|
||||
box-shadow: 0 26px 50px -32px rgba(60, 80, 55, 0.6); padding: clamp(12px, 1.6vw, 18px);
|
||||
}
|
||||
.date {
|
||||
font-family: 'Newsreader', Georgia, serif; font-weight: 500; letter-spacing: -0.015em;
|
||||
font-size: clamp(2.4rem, 7vw, 4rem); line-height: 1; margin: 12px 0 0; color: var(--ink);
|
||||
}
|
||||
.event { margin-top: clamp(22px, 4vw, 34px); }
|
||||
.year-line { display: flex; align-items: baseline; justify-content: center; gap: 12px; margin: 0; }
|
||||
.year { font-family: 'Newsreader', Georgia, serif; font-weight: 500; font-size: clamp(1.8rem, 4vw, 2.6rem); color: #1e5b3b; line-height: 1; }
|
||||
.ago { font-size: 0.9rem; letter-spacing: 0.04em; color: #6f9683; text-transform: uppercase; }
|
||||
.fact {
|
||||
font-family: 'Newsreader', Georgia, serif; font-size: clamp(1.3rem, 3vw, 1.7rem); line-height: 1.34;
|
||||
color: #214a35; margin: 14px 0 0;
|
||||
.deckle {
|
||||
position: relative; border: 1.5px dashed rgba(70, 120, 90, 0.38); border-radius: 11px;
|
||||
padding: clamp(26px, 5vw, 34px) clamp(20px, 5vw, 34px) clamp(34px, 6vw, 44px); overflow: hidden;
|
||||
}
|
||||
|
||||
.photo {
|
||||
margin: clamp(26px, 5vw, 40px) auto 0; max-width: 460px; aspect-ratio: 3/2;
|
||||
background-size: cover; background-position: center; border-radius: 16px;
|
||||
border: 1px solid #d8e6da; box-shadow: 0 10px 30px -16px rgba(40, 120, 75, 0.4);
|
||||
.eyebrow { display: flex; align-items: center; gap: 14px; }
|
||||
.eye-rule { width: 34px; height: 3px; background: #3a7d5b; border-radius: 2px; flex: none; }
|
||||
.eye-label { font-family: 'Hanken Grotesk', sans-serif; font-size: clamp(13px, 1.7vw, 16px); font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; color: #2c5d44; }
|
||||
|
||||
.dateline { display: flex; align-items: center; gap: 16px; margin: clamp(20px, 3vw, 26px) 0 14px; }
|
||||
.dl-rule { flex: 1; height: 1.5px; background: rgba(70, 120, 90, 0.26); }
|
||||
.dl-label { font-family: 'Hanken Grotesk', sans-serif; font-weight: 700; font-size: clamp(14px, 1.7vw, 17px); letter-spacing: 0.1em; text-transform: uppercase; color: #2c5d44; }
|
||||
|
||||
.hero {
|
||||
position: relative; border-radius: 12px; overflow: hidden; background: #21392e;
|
||||
height: clamp(220px, 38vw, 330px);
|
||||
}
|
||||
.hero-img { width: 100%; height: 100%; object-fit: cover; display: block; }
|
||||
.hero-scrim {
|
||||
position: absolute; inset: 0; pointer-events: none;
|
||||
background: linear-gradient(105deg, rgba(18, 32, 25, 0.74) 0%, rgba(18, 32, 25, 0.45) 38%, rgba(18, 32, 25, 0.06) 70%);
|
||||
}
|
||||
.hero-year { position: absolute; left: clamp(20px, 4vw, 30px); bottom: clamp(20px, 3vw, 26px); text-shadow: 0 1px 14px rgba(10, 20, 15, 0.55); }
|
||||
.hy-eyebrow { font-family: 'Hanken Grotesk', sans-serif; font-size: 12px; font-weight: 700; letter-spacing: 0.18em; text-transform: uppercase; color: #bfe8cf; }
|
||||
.hy-year { font-family: 'Playfair Display', Georgia, serif; font-weight: 700; font-size: clamp(50px, 11vw, 76px); line-height: 0.9; color: #fff; margin-top: 4px; }
|
||||
|
||||
.headline {
|
||||
font-family: 'Playfair Display', Georgia, serif; font-style: italic; font-weight: 600;
|
||||
font-size: clamp(1.45rem, 4vw, 2.06rem); line-height: 1.28; color: #243d31;
|
||||
margin: clamp(24px, 4vw, 30px) 0 0; max-width: 40ch;
|
||||
}
|
||||
|
||||
.summary {
|
||||
margin: clamp(26px, 5vw, 38px) auto 0; max-width: 600px; text-align: left;
|
||||
font-size: 1.05rem; line-height: 1.65; color: #4a5a50;
|
||||
.story-head { display: flex; align-items: center; gap: 12px; margin-top: clamp(26px, 4vw, 34px); }
|
||||
.sh-rule { width: 26px; height: 2px; background: #bcae93; border-radius: 2px; flex: none; }
|
||||
.sh-label { font-family: 'Hanken Grotesk', sans-serif; font-size: 11px; font-weight: 700; letter-spacing: 0.13em; text-transform: uppercase; color: #a89880; }
|
||||
.story {
|
||||
font-family: 'Newsreader', Georgia, serif; font-size: clamp(1rem, 1.8vw, 1.13rem);
|
||||
line-height: 1.68; color: #4f574f; margin: 12px 0 0; max-width: 64ch;
|
||||
}
|
||||
|
||||
.source {
|
||||
display: inline-block; margin-top: clamp(24px, 4vw, 34px);
|
||||
font-size: 0.95rem; font-weight: 600; color: #3f9a66; text-decoration: none;
|
||||
.cta-row { margin-top: clamp(24px, 4vw, 30px); }
|
||||
.cta {
|
||||
display: inline-flex; align-items: center; gap: 8px; background: #2f6b4f; color: #fff;
|
||||
text-decoration: none; font-family: 'Hanken Grotesk', sans-serif; font-size: 14px; font-weight: 600;
|
||||
padding: 11px 20px; border-radius: 999px; -webkit-tap-highlight-color: transparent;
|
||||
transition: background 0.15s ease;
|
||||
}
|
||||
.source:hover { text-decoration: underline; }
|
||||
.cta:hover { background: #265a42; }
|
||||
|
||||
.note { text-align: center; color: var(--muted); font-size: 1.05rem; margin-top: 60px; }
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user