Files
intotheeast-com/docs/working/plans/2026-06-24-frontend-polish.md
T

13 KiB
Raw Blame History

Frontend Polish Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [x]) syntax for tracking.

Status: Complete — implemented 2026-06-24

Spec: docs/working/specs/2026-06-24-frontend-polish-design.md

Goal: Visual polish across the five primary page templates: pill grammar, stats field-notes style, header identity, emoji replacement, trip card cover images, story progress bar, and story opening transition.

Architecture: Tasks 12 are pure CSS (style.css only). Task 3 touches one partial (emoji). Task 4 adds a blueprint field and updates one template. Tasks 56 each add CSS + a small Twig block to story.html.twig.

Already done (this session):

  • entry.html.twig unified with feed partial — hero removed, PhotoSwipe replaces broken lightbox
  • Dead CSS from old entry layout stripped from style.css

Global Constraints

  • All changes in user/ — commit with git -C user, not main-repo git
  • All new CSS uses token variables only — no hardcoded hex values
  • Changes must degrade gracefully when optional data (cover image, location) is absent
  • prefers-reduced-motion must be respected for any animations in Tasks 56
  • Clear Grav cache after each template change: make remote-cache-clear or via Admin

Task 1: Pure CSS — Pill grammar + Stats style + Header identity

Files:

  • Modify: user/themes/intotheeast/css/style.css

Interfaces:

  • Produces: visual changes to trip filter buttons, stats blocks, and site header across all pages

  • Step 1: Pill grammar — change filter/sort buttons to rounded-rect

Find .trip-filter-btn, selector block:

.trip-filter-btn,
.trip-stats-btn {
    ...
    border-radius: var(--radius-full);
    ...
}

Change only border-radius to var(--radius-sm). Leave all other properties unchanged.

  • Step 2: Stats — remove box, add left rule

Find .stat-block rule:

.stat-block {
    background: var(--color-canvas);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: var(--space-6) var(--space-5);
    text-align: center;
    box-shadow: var(--shadow-sm);
}

Replace with:

.stat-block {
    border-left: 2px solid var(--color-accent);
    padding: var(--space-2) 0 var(--space-2) var(--space-4);
    text-align: left;
}
  • Step 3: Stats — change number color from accent to ink

Find .stat-value rule. It contains color: var(--color-accent). Change to color: var(--color-ink). Leave all other properties unchanged.

  • Step 4: Header — widen site title tracking and size

Find .site-title rule:

.site-title {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 400;
    letter-spacing: -0.01em;
    ...
}

Change:

  • font-size: var(--text-lg)font-size: var(--text-xl)

  • letter-spacing: -0.01emletter-spacing: 0.06em

  • Step 5: Header — thicken and gradient the accent stripe

Find .site-header rule. It contains border-top: 3px solid var(--color-accent).

Change to:

border-top: 4px solid transparent;
border-image: linear-gradient(90deg, var(--color-accent), var(--color-accent-hover)) 1;
  • Step 6: Visual smoke check

Open browser and verify:

  • /trips — trip filter buttons are square-cornered (not pill-shaped)

  • /trips/<any-trip> — stats panel shows left accent stripe, cream numbers, no box border

  • Header — "into the east" is slightly larger with wider tracking; accent stripe has gradient

  • Step 7: Commit

git -C user add themes/intotheeast/css/style.css
git -C user commit -m "style: pill grammar, stats field-notes, header identity"

Task 2: Replace emoji icons in journal entry partial

Files:

  • Modify: user/themes/intotheeast/templates/partials/entry-journal.html.twig

Interfaces:

  • Affects: every journal entry in the home feed, trip feed, and standalone entry page

  • Step 1: Replace location emoji with SVG pin

Find in the partial:

· 📍

Replace with:

· <svg width="11" height="13" viewBox="0 0 12 14" fill="currentColor" aria-hidden="true" style="flex-shrink:0;vertical-align:-1px"><path d="M6 0C3.24 0 1 2.24 1 5c0 3.75 5 9 5 9s5-5.25 5-9c0-2.76-2.24-5-5-5zm0 6.75A1.75 1.75 0 1 1 6 3.25a1.75 1.75 0 0 1 0 3.5z"/></svg>
  • Step 2: Strip weather emoji prefix

Find in the partial:

<span class="journal-post-weather">· {{ weather_icons[entry.header.weather_desc] ?? '' }} {{ entry.header.weather_desc }}</span>

Replace with:

<span class="journal-post-weather">· {{ entry.header.weather_desc }}</span>

The weather_icons map at the top of the partial can stay (removing it is optional cleanup); it will simply go unused.

  • Step 3: Smoke check

Open any trip page in browser. Confirm:

  • Location shows small SVG pin instead of 📍

  • Weather shows plain text (e.g. "· Sunny") with no emoji

  • Step 4: Commit

git -C user add themes/intotheeast/templates/partials/entry-journal.html.twig
git -C user commit -m "style: replace emoji icons with SVG pin and plain weather text"

Task 3: Trip cards — cover image

Files:

  • Modify: user/themes/intotheeast/blueprints/trip.yaml
  • Modify: user/themes/intotheeast/templates/trips.html.twig
  • Modify: user/themes/intotheeast/css/style.css

Interfaces:

  • Produces: optional cover image banner on each trip card

  • Consumes: trip.header.cover_image (new field) or first image from first published entry

  • Step 1: Read the current trip blueprint

cat user/themes/intotheeast/blueprints/trip.yaml

Locate the correct position to insert the new field (after tagline or near other media fields).

  • Step 2: Add cover_image field to blueprint

Insert in trip.yaml at an appropriate location:

cover_image:
    type: filepicker
    label: Cover Image
    preview_images: true
    folder: '@self'
    accept:
        - image/*
  • Step 3: Add cover image CSS to style.css

In the /* ── Past trips archive */ section, add after .trip-card-counts:

.trip-card-cover {
    aspect-ratio: 3 / 1;
    overflow: hidden;
    border-radius: var(--radius-md) var(--radius-md) 0 0;
    background: var(--color-border);
    margin: calc(-1 * var(--space-6)) calc(-1 * var(--space-6)) var(--space-5);
}

.trip-card-cover img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    transition: transform 0.45s ease;
}

.trip-card:hover .trip-card-cover img { transform: scale(1.04); }
  • Step 4: Update trips.html.twig to render cover image

Inside the {% for trip in trips %} loop, before the .trip-card-title div, add:

{# Cover image: explicit field first, then first entry's first image #}
{% set cover = null %}
{% if trip.header.cover_image and trip.media[trip.header.cover_image] is defined %}
    {% set cover = trip.media[trip.header.cover_image] %}
{% elseif dailies_page %}
    {% set first_entry = dailies_page.children.published()|first %}
    {% if first_entry and first_entry.media.images|length > 0 %}
        {% set cover = first_entry.media.images|first %}
    {% endif %}
{% endif %}
{% if cover %}
<div class="trip-card-cover">
    <img src="{{ cover.cropResize(720, 240).url }}" alt="{{ trip.title }}" loading="lazy">
</div>
{% endif %}
  • Step 5: Smoke check

Open /trips in browser. Confirm:

  • Trips with media show a 3:1 cover photo banner

  • Trips without media show text-only card (no broken image element)

  • Hover scales the image slightly

  • Step 6: Commit

git -C user add themes/intotheeast/blueprints/trip.yaml themes/intotheeast/templates/trips.html.twig themes/intotheeast/css/style.css
git -C user commit -m "feat: trip cards show cover image with 3:1 crop and hover zoom"

Task 4: Story opening transition

Files:

  • Modify: user/themes/intotheeast/templates/story.html.twig
  • Modify: user/themes/intotheeast/css/style.css

Interfaces:

  • Consumes: date_str and location already computed at the top of story.html.twig

  • Produces: a centered location/date block at the top of .story-body with fade-in animation

  • Step 1: Add story-opener CSS to style.css

In the /* ── Story pages */ section, after .story-body p rules, add:

.story-opener {
    text-align: center;
    padding-bottom: var(--space-12);
    margin-bottom: var(--space-12);
    border-bottom: 1px solid var(--color-border);
    opacity: 0;
    animation: storyReveal 0.9s cubic-bezier(.16,1,.3,1) 0.8s both;
}

.story-opener__text {
    font-family: var(--font-ui);
    font-size: var(--text-sm);
    color: var(--color-ink-muted);
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

@media (prefers-reduced-motion: reduce) {
    .story-opener { opacity: 1; animation: none; }
}
  • Step 2: Add opener block to story.html.twig

Inside .story-body, immediately before {{ page.content|raw }}, add:

{% if location or date_str %}
<div class="story-opener">
    <span class="story-opener__text">
        {{- date_str -}}
        {%- if location and date_str %} · {% endif -%}
        {{- location -}}
    </span>
</div>
{% endif %}
  • Step 3: Smoke check

Open any published story in browser. Confirm:

  • A small uppercase line showing date and location appears below the hero spacer

  • It is separated from the prose by a thin horizontal rule

  • It fades in after the hero title animation completes

  • On a story with no location set: only date appears (or nothing if both are absent)

  • Step 4: Commit

git -C user add themes/intotheeast/templates/story.html.twig themes/intotheeast/css/style.css
git -C user commit -m "feat: story opening transition with location and date eyebrow"

Task 5: Reading progress bar on story pages

Files:

  • Modify: user/themes/intotheeast/templates/story.html.twig
  • Modify: user/themes/intotheeast/css/style.css

Interfaces:

  • Produces: 2px teal bar fixed at bottom of site header, progress tied to .story-body scroll position

  • No bar rendered at all if prefers-reduced-motion is set (JS skips creating it)

  • Step 1: Add progress bar CSS to style.css

In the /* ── Story pages */ section, add:

.story-progress {
    position: fixed;
    top: var(--site-header-height);
    left: 0;
    height: 2px;
    width: 0%;
    background: var(--color-accent);
    z-index: 200;
    pointer-events: none;
    will-change: width;
}
  • Step 2: Add progress bar element and JS to story.html.twig

Immediately after {% block content %} (before the hero markup), add:

<div class="story-progress" id="story-progress"></div>

In the <script> block at the bottom (after the existing scroll/reveal scripts), add:

/* ── Reading progress bar ────────────────────────────────── */
(function () {
    if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
    var bar  = document.getElementById('story-progress');
    var body = document.querySelector('.story-body');
    if (!bar || !body) return;

    function update() {
        var rect    = body.getBoundingClientRect();
        var total   = body.offsetHeight - window.innerHeight;
        var scrolled = -rect.top;
        var pct     = total > 0 ? Math.min(100, Math.max(0, (scrolled / total) * 100)) : 0;
        bar.style.width = pct.toFixed(1) + '%';
    }

    window.addEventListener('scroll', update, { passive: true });
    update();
})();
  • Step 3: Smoke check

Open any published story in browser. Confirm:

  • A thin teal line appears at the top of the content area (below the sticky header) as you scroll into the story body

  • Bar is at 0% when the hero is visible, fills to 100% as you reach the story footer

  • Bar is invisible (absent) on a device with prefers-reduced-motion

  • Step 4: Commit

git -C user add themes/intotheeast/templates/story.html.twig themes/intotheeast/css/style.css
git -C user commit -m "feat: reading progress bar on story pages"

Final Verification

After all tasks complete:

  1. Visual check list (browser):

    • /trips — cover images on trip cards, hover scales; text-only fallback if no media
    • /trips/<any-trip> — filter buttons square-cornered; stats left-rule style with cream numbers
    • /trips/<any-trip>/dailies/<any-entry> (standalone URL) — SVG location pin, plain weather text, photo strip + PhotoSwipe, no hero image
    • /trips/<any-trip>/<any-story> — opener block visible below hero; progress bar fills on scroll; no emoji anywhere
    • Any page header — "into the east" wider-tracked; accent stripe slightly thicker with gradient
  2. Reduced-motion check: simulate prefers-reduced-motion: reduce in browser devtools and confirm no animations fire on story pages (opener snaps visible immediately, progress bar absent).

  3. Empty-data check: visit a trip with no media attached and confirm /trips degrades to text-only card without errors.