Compare commits
6
Commits
ed25907545
...
d7a772ae02
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d7a772ae02 | ||
|
|
ac38ae2a54 | ||
|
|
9fa1988211 | ||
|
|
f6ee4944f9 | ||
|
|
b017d2ff64 | ||
|
|
3345c076a9 |
+212
-154
@@ -39,21 +39,34 @@ body::after {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 var(--space-5);
|
||||
box-sizing: border-box;
|
||||
/* 4px top offsets the green ::before gradient (top 4px of the bar) so all
|
||||
content centres in the VISIBLE dark area, not the geometric header box. */
|
||||
padding: 4px var(--space-5) 0;
|
||||
height: var(--site-header-height);
|
||||
background: var(--color-canvas);
|
||||
border-top: 3px solid var(--color-accent);
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.site-header::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 4px;
|
||||
background: linear-gradient(90deg, var(--color-accent), var(--color-accent-hover));
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.site-title {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--text-lg);
|
||||
font-size: var(--text-xl);
|
||||
font-weight: 400;
|
||||
letter-spacing: -0.01em;
|
||||
letter-spacing: var(--tracking-display-sm);
|
||||
text-decoration: none;
|
||||
color: var(--color-ink);
|
||||
line-height: 1;
|
||||
@@ -66,9 +79,12 @@ body::after {
|
||||
}
|
||||
|
||||
.site-nav a {
|
||||
font-family: var(--font-ui);
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 500;
|
||||
/* Nav uses the display serif (not the UI sans) so it shares the wordmark's
|
||||
anatomy: with one typeface, logo and nav centre identically — no optical
|
||||
nudge needed. Sentence case keeps it quiet support beneath the wordmark. */
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--text-base);
|
||||
font-weight: 400;
|
||||
color: var(--color-ink-2);
|
||||
text-decoration: none;
|
||||
padding: var(--space-2) var(--space-3);
|
||||
@@ -80,11 +96,69 @@ body::after {
|
||||
}
|
||||
|
||||
.site-nav a:hover { color: var(--color-ink); background: var(--color-paper); }
|
||||
.site-nav a[aria-current="page"] { color: var(--color-accent); font-weight: 600; }
|
||||
.site-nav a[aria-current="page"] { color: var(--color-accent); }
|
||||
|
||||
@media (max-width: 380px) {
|
||||
.site-title { font-size: var(--text-md); }
|
||||
.site-nav a { padding: var(--space-2); font-size: 0.8rem; }
|
||||
/* ── Hamburger toggle ────────────────────────────────────────────────────────── */
|
||||
.nav-toggle {
|
||||
display: none; /* shown only on mobile, via the media query below */
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 5px;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
padding: 11px 10px;
|
||||
margin-right: -10px; /* cancel inner padding so the bars align to the bar edge */
|
||||
background: none;
|
||||
border: 0;
|
||||
cursor: pointer;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
.nav-toggle__bar {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
border-radius: 2px;
|
||||
background: var(--color-ink-2);
|
||||
transition: transform 0.25s ease, opacity 0.2s ease, background 0.15s;
|
||||
}
|
||||
.nav-toggle:hover .nav-toggle__bar { background: var(--color-ink); }
|
||||
.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(1) { transform: translateY(7px) rotate(45deg); }
|
||||
.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(2) { opacity: 0; }
|
||||
.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.nav-toggle { display: flex; }
|
||||
|
||||
/* Nav collapses into a slide-down panel beneath the header bar. */
|
||||
.site-nav {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 0;
|
||||
padding: var(--space-2) var(--space-5) var(--space-4);
|
||||
background: var(--color-canvas);
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
box-shadow: var(--shadow-lg);
|
||||
transform: translateY(-8px);
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s;
|
||||
}
|
||||
.site-nav[data-open="true"] {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
.site-nav a {
|
||||
font-size: var(--text-lg);
|
||||
padding: var(--space-3) 0;
|
||||
min-height: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
.site-nav a:hover { background: none; color: var(--color-ink); }
|
||||
}
|
||||
|
||||
/* ── Feed ────────────────────────────────────────────────────────────────────── */
|
||||
@@ -132,6 +206,7 @@ body::after {
|
||||
font-size: var(--text-xl);
|
||||
font-weight: 400;
|
||||
line-height: var(--leading-snug);
|
||||
letter-spacing: var(--tracking-display);
|
||||
color: var(--color-ink);
|
||||
margin-bottom: var(--space-3);
|
||||
transition: color 0.15s;
|
||||
@@ -140,21 +215,6 @@ body::after {
|
||||
.entry-card:hover .entry-title { color: var(--color-accent); }
|
||||
|
||||
|
||||
/* Location & weather badges (single entry page) */
|
||||
|
||||
.entry-location {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--color-ink-2);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-1);
|
||||
}
|
||||
|
||||
.entry-weather {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--color-ink-2);
|
||||
}
|
||||
|
||||
@keyframes card-highlight {
|
||||
0% { background-color: color-mix(in srgb, var(--color-accent) 12%, transparent); }
|
||||
100% { background-color: transparent; }
|
||||
@@ -178,6 +238,7 @@ body::after {
|
||||
font-size: var(--text-xl);
|
||||
font-weight: 400;
|
||||
line-height: var(--leading-snug);
|
||||
letter-spacing: var(--tracking-display);
|
||||
color: var(--color-ink);
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
@@ -203,6 +264,9 @@ body::after {
|
||||
.journal-post-location,
|
||||
.journal-post-weather {
|
||||
color: var(--color-ink-muted);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-1);
|
||||
}
|
||||
|
||||
.journal-photo-wrap {
|
||||
@@ -346,21 +410,6 @@ body::after {
|
||||
|
||||
/* ── Single entry ────────────────────────────────────────────────────────────── */
|
||||
|
||||
.entry-hero {
|
||||
width: 100%;
|
||||
max-height: 480px;
|
||||
overflow: hidden;
|
||||
margin-bottom: var(--space-8);
|
||||
border-radius: var(--radius-md);
|
||||
}
|
||||
|
||||
.entry-hero img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.entry-back-fixed {
|
||||
position: fixed;
|
||||
top: calc(var(--site-header-height) + var(--space-3));
|
||||
@@ -368,91 +417,10 @@ body::after {
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.entry-header { margin-bottom: var(--space-8); }
|
||||
|
||||
.entry-header-meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.entry-header .entry-date {
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
color: var(--color-ink-muted);
|
||||
display: inline;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.entry .entry-title {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--text-2xl);
|
||||
font-weight: 400;
|
||||
line-height: var(--leading-snug);
|
||||
color: var(--color-ink);
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
@media (min-width: 520px) {
|
||||
.entry .entry-title { font-size: var(--text-3xl); }
|
||||
}
|
||||
|
||||
.entry-title-rule {
|
||||
height: 1px;
|
||||
background: var(--color-border);
|
||||
margin-bottom: var(--space-8);
|
||||
}
|
||||
|
||||
.entry-body { margin-bottom: var(--space-10); }
|
||||
.entry-body p { margin-bottom: 1.4em; font-size: var(--text-md); line-height: var(--leading-normal); color: var(--color-ink-2); }
|
||||
.entry-body img { max-width: 100%; height: auto; border-radius: var(--radius-sm); }
|
||||
|
||||
.entry-footer { border-top: 1px solid var(--color-border); padding-top: var(--space-5); }
|
||||
.entry-footer a { color: var(--color-accent); text-decoration: none; font-size: var(--text-sm); font-weight: 500; }
|
||||
.entry-footer a:hover { color: var(--color-accent-hover); }
|
||||
|
||||
/* ── Photo gallery ───────────────────────────────────────────────────────────── */
|
||||
|
||||
.entry-gallery {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 3px;
|
||||
margin-bottom: var(--space-10);
|
||||
border-radius: var(--radius-md);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@media (min-width: 520px) {
|
||||
.entry-gallery { grid-template-columns: repeat(3, 1fr); }
|
||||
}
|
||||
|
||||
.gallery-thumb {
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
aspect-ratio: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.gallery-thumb img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
transition: opacity 0.15s;
|
||||
}
|
||||
|
||||
.gallery-thumb:hover img,
|
||||
.gallery-thumb:focus img { opacity: 0.82; }
|
||||
|
||||
.gallery-thumb:focus { outline: 2px solid var(--color-accent); outline-offset: 2px; }
|
||||
|
||||
/* ── PhotoSwipe overrides ─────────────────────────────────────────────────────── */
|
||||
|
||||
.pswp__bg { background: #000; }
|
||||
@@ -577,6 +545,8 @@ body::after {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--text-2xl);
|
||||
font-weight: 400;
|
||||
line-height: var(--leading-tight);
|
||||
letter-spacing: var(--tracking-display);
|
||||
margin-bottom: var(--space-8);
|
||||
color: var(--color-ink);
|
||||
}
|
||||
@@ -593,12 +563,9 @@ body::after {
|
||||
}
|
||||
|
||||
.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);
|
||||
border-left: 2px solid var(--color-accent);
|
||||
padding: var(--space-2) 0 var(--space-2) var(--space-4);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
@@ -606,7 +573,7 @@ body::after {
|
||||
font-family: var(--font-display);
|
||||
font-size: clamp(2rem, 6vw, var(--text-3xl));
|
||||
font-weight: 400;
|
||||
color: var(--color-accent);
|
||||
color: var(--color-ink);
|
||||
line-height: 1.1;
|
||||
margin-bottom: var(--space-2);
|
||||
font-variant-numeric: tabular-nums;
|
||||
@@ -618,7 +585,7 @@ body::after {
|
||||
font-weight: 600;
|
||||
color: var(--color-ink-muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.07em;
|
||||
letter-spacing: var(--tracking-caps);
|
||||
}
|
||||
|
||||
.stats-countries {
|
||||
@@ -635,7 +602,7 @@ body::after {
|
||||
color: var(--color-ink);
|
||||
text-transform: uppercase;
|
||||
font-size: var(--text-xs);
|
||||
letter-spacing: 0.07em;
|
||||
letter-spacing: var(--tracking-caps);
|
||||
}
|
||||
|
||||
.stats-note {
|
||||
@@ -763,6 +730,8 @@ body::after {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--text-xl);
|
||||
font-weight: 400;
|
||||
line-height: var(--leading-snug);
|
||||
letter-spacing: var(--tracking-display);
|
||||
margin-bottom: var(--space-6);
|
||||
color: var(--color-ink);
|
||||
}
|
||||
@@ -832,13 +801,13 @@ body::after {
|
||||
|
||||
/* Inline field validation */
|
||||
.post-form-wrap .field-invalid {
|
||||
border-color: #c0392b !important;
|
||||
outline-color: #c0392b !important;
|
||||
border-color: var(--color-error) !important;
|
||||
outline-color: var(--color-error) !important;
|
||||
}
|
||||
|
||||
.post-form-wrap .field-error {
|
||||
display: block;
|
||||
color: #c0392b;
|
||||
color: var(--color-error);
|
||||
font-size: var(--text-sm);
|
||||
margin-top: var(--space-1);
|
||||
}
|
||||
@@ -876,7 +845,7 @@ body::after {
|
||||
}
|
||||
|
||||
.form-status--ok { color: var(--color-accent); }
|
||||
.form-status--err { color: #B44A2A; }
|
||||
.form-status--err { color: var(--color-error); }
|
||||
|
||||
/* ── Accessibility & motion ──────────────────────────────────────────────────── */
|
||||
|
||||
@@ -964,10 +933,18 @@ body::after {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--text-2xl);
|
||||
font-weight: 400;
|
||||
line-height: var(--leading-tight);
|
||||
letter-spacing: var(--tracking-display);
|
||||
color: var(--color-ink);
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
.trip-dates {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--color-ink-muted);
|
||||
margin: var(--space-1) 0 var(--space-2);
|
||||
}
|
||||
|
||||
.home-trip-counts {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--color-ink-muted);
|
||||
@@ -1004,7 +981,7 @@ body::after {
|
||||
color: var(--color-ink-muted);
|
||||
background: transparent;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-full);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: var(--space-1) var(--space-4);
|
||||
cursor: pointer;
|
||||
transition: color 0.15s, border-color 0.15s, background 0.15s;
|
||||
@@ -1076,6 +1053,8 @@ body::after {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--text-2xl);
|
||||
font-weight: 400;
|
||||
line-height: var(--leading-tight);
|
||||
letter-spacing: var(--tracking-display);
|
||||
color: var(--color-ink);
|
||||
margin-bottom: var(--space-8);
|
||||
}
|
||||
@@ -1107,10 +1086,30 @@ body::after {
|
||||
background: var(--color-surface-raised);
|
||||
}
|
||||
|
||||
.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); }
|
||||
|
||||
.trip-card-title {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--text-xl);
|
||||
font-weight: 400;
|
||||
line-height: var(--leading-snug);
|
||||
letter-spacing: var(--tracking-display);
|
||||
color: var(--color-ink);
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
@@ -1152,7 +1151,7 @@ body::after {
|
||||
font-size: var(--text-xs);
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
letter-spacing: var(--tracking-caps);
|
||||
color: var(--color-ink-muted);
|
||||
margin-bottom: var(--space-3);
|
||||
}
|
||||
@@ -1202,7 +1201,7 @@ body::after {
|
||||
font-size: var(--text-xs);
|
||||
font-weight: 600;
|
||||
font-variant: small-caps;
|
||||
letter-spacing: 0.08em;
|
||||
letter-spacing: var(--tracking-caps);
|
||||
color: var(--color-accent);
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
@@ -1299,6 +1298,8 @@ body::after {
|
||||
.trip-cycling-title {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--text-lg);
|
||||
line-height: var(--leading-snug);
|
||||
letter-spacing: var(--tracking-display-sm);
|
||||
color: var(--color-ink);
|
||||
}
|
||||
|
||||
@@ -1328,7 +1329,7 @@ body::after {
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 500;
|
||||
color: rgba(255,255,255,0.85);
|
||||
background: rgba(26,24,20,0.55);
|
||||
background: var(--color-paper-glass-high);
|
||||
backdrop-filter: blur(6px);
|
||||
-webkit-backdrop-filter: blur(6px);
|
||||
border: 1px solid rgba(255,255,255,0.12);
|
||||
@@ -1337,7 +1338,7 @@ body::after {
|
||||
text-decoration: none;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
.story-escape:hover { background: rgba(26,24,20,0.8); }
|
||||
.story-escape:hover { background: var(--color-paper-glass-hover); }
|
||||
|
||||
/* Hero */
|
||||
.story-hero { position: relative; }
|
||||
@@ -1386,7 +1387,7 @@ body::after {
|
||||
.story-hero__title {
|
||||
font-family: var(--font-display);
|
||||
font-size: clamp(2.2rem, 6vw, 4.5rem);
|
||||
font-weight: 900;
|
||||
font-weight: 400;
|
||||
line-height: 1.08;
|
||||
letter-spacing: -0.02em;
|
||||
margin-bottom: var(--space-3);
|
||||
@@ -1437,13 +1438,27 @@ body::after {
|
||||
}
|
||||
.story-body p {
|
||||
font-family: var(--font-ui);
|
||||
font-size: 1.0625rem;
|
||||
line-height: 1.85;
|
||||
font-size: var(--text-story);
|
||||
line-height: var(--leading-story);
|
||||
color: var(--color-ink-2);
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
.story-body h2, .story-body h3 {
|
||||
.story-body h2 {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--text-xl);
|
||||
font-weight: 400;
|
||||
line-height: var(--leading-snug);
|
||||
letter-spacing: var(--tracking-display);
|
||||
color: var(--color-ink);
|
||||
margin-top: var(--space-10);
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
.story-body h3 {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--text-lg);
|
||||
font-weight: 400;
|
||||
line-height: var(--leading-snug);
|
||||
letter-spacing: var(--tracking-display-sm);
|
||||
color: var(--color-ink);
|
||||
margin-top: var(--space-10);
|
||||
margin-bottom: var(--space-4);
|
||||
@@ -1460,6 +1475,41 @@ body::after {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* ── Story progress bar ──────────────────────────────────── */
|
||||
.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;
|
||||
}
|
||||
|
||||
/* ── Story opener (location + date eyebrow) ──────────────── */
|
||||
.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: var(--tracking-caps);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.story-opener { opacity: 1; animation: none; }
|
||||
}
|
||||
|
||||
/* ── Story nav title (desktop: fades into header center) ─────── */
|
||||
.story-nav-title {
|
||||
position: absolute;
|
||||
@@ -1469,7 +1519,7 @@ body::after {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--text-lg);
|
||||
font-weight: 400;
|
||||
letter-spacing: -0.01em;
|
||||
letter-spacing: var(--tracking-display-sm);
|
||||
color: var(--color-ink);
|
||||
white-space: nowrap;
|
||||
max-width: 40%;
|
||||
@@ -1553,7 +1603,7 @@ body::after {
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
padding: var(--space-10) var(--space-12);
|
||||
background: rgba(26,24,20,0.25);
|
||||
background: var(--color-paper-glass-mid);
|
||||
backdrop-filter: blur(18px) saturate(1.4);
|
||||
-webkit-backdrop-filter: blur(18px) saturate(1.4);
|
||||
border: 1px solid rgba(255,255,255,0.12);
|
||||
@@ -1581,8 +1631,9 @@ body::after {
|
||||
.chapter-break__title {
|
||||
font-family: var(--font-display);
|
||||
font-size: clamp(1.6rem, 4vw, 2.6rem);
|
||||
font-weight: 700;
|
||||
font-weight: 400;
|
||||
line-height: 1.15;
|
||||
letter-spacing: var(--tracking-display);
|
||||
color: #fff;
|
||||
text-shadow: 0 2px 16px rgba(0,0,0,0.4);
|
||||
margin: 0;
|
||||
@@ -1671,8 +1722,8 @@ body::after {
|
||||
}
|
||||
.scrolly-step__inner p {
|
||||
font-family: var(--font-ui);
|
||||
font-size: 1.05rem;
|
||||
line-height: 1.8;
|
||||
font-size: var(--text-story);
|
||||
line-height: var(--leading-story);
|
||||
color: var(--color-ink-2);
|
||||
margin-bottom: var(--space-3);
|
||||
}
|
||||
@@ -1719,7 +1770,7 @@ body::after {
|
||||
padding: var(--space-10) var(--space-8);
|
||||
backdrop-filter: blur(14px) saturate(1.3);
|
||||
-webkit-backdrop-filter: blur(14px) saturate(1.3);
|
||||
background: rgba(26,24,20,0.08);
|
||||
background: var(--color-paper-glass-low);
|
||||
text-align: center;
|
||||
}
|
||||
.pull-quote__inner--no-image {
|
||||
@@ -1740,6 +1791,7 @@ body::after {
|
||||
font-family: var(--font-display);
|
||||
font-size: clamp(1.2rem, 3vw, 1.6rem);
|
||||
font-style: italic;
|
||||
letter-spacing: var(--tracking-display-sm);
|
||||
color: #fff;
|
||||
line-height: 1.5;
|
||||
margin: var(--space-4) 0;
|
||||
@@ -1891,6 +1943,8 @@ body::after {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--text-2xl);
|
||||
font-weight: 400;
|
||||
line-height: var(--leading-tight);
|
||||
letter-spacing: var(--tracking-display);
|
||||
color: var(--color-ink);
|
||||
margin-bottom: 0;
|
||||
}
|
||||
@@ -1923,7 +1977,7 @@ body::after {
|
||||
font-size: var(--text-xs);
|
||||
color: var(--color-ink-muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
letter-spacing: var(--tracking-caps);
|
||||
margin-bottom: var(--space-1);
|
||||
}
|
||||
.story-card__location {
|
||||
@@ -1937,9 +1991,10 @@ body::after {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--text-lg);
|
||||
font-weight: 400;
|
||||
line-height: var(--leading-snug);
|
||||
letter-spacing: var(--tracking-display-sm);
|
||||
color: var(--color-ink);
|
||||
margin-bottom: var(--space-3);
|
||||
line-height: var(--leading-snug);
|
||||
}
|
||||
.story-card__cta {
|
||||
font-family: var(--font-ui);
|
||||
@@ -1964,6 +2019,8 @@ body::after {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--text-2xl);
|
||||
font-weight: 400;
|
||||
line-height: var(--leading-tight);
|
||||
letter-spacing: var(--tracking-display);
|
||||
color: var(--color-ink);
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
@@ -2021,7 +2078,7 @@ body::after {
|
||||
font-size: var(--text-xs);
|
||||
font-weight: 600;
|
||||
font-variant: small-caps;
|
||||
letter-spacing: 0.08em;
|
||||
letter-spacing: var(--tracking-caps);
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
@@ -2033,9 +2090,10 @@ body::after {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--text-lg);
|
||||
font-weight: 400;
|
||||
line-height: var(--leading-snug);
|
||||
letter-spacing: var(--tracking-display-sm);
|
||||
color: var(--color-ink);
|
||||
text-decoration: none;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.home-highlight-title:hover { color: var(--color-accent); }
|
||||
|
||||
@@ -13,25 +13,39 @@
|
||||
--color-accent-on: #FFFFFF; /* text on accent surfaces */
|
||||
--color-surface-raised: #2A2720; /* elevated surfaces: tooltips, hover */
|
||||
--color-ink-inverse: #17171A; /* text on accent-coloured buttons */
|
||||
--color-error: #c0392b; /* validation errors, form error status */
|
||||
|
||||
/* ── Glass overlays (paper colour at opacity, for story components) ── */
|
||||
--color-paper-glass-low: color-mix(in srgb, var(--color-paper) 8%, transparent);
|
||||
--color-paper-glass-mid: color-mix(in srgb, var(--color-paper) 25%, transparent);
|
||||
--color-paper-glass-high: color-mix(in srgb, var(--color-paper) 55%, transparent);
|
||||
--color-paper-glass-hover: color-mix(in srgb, var(--color-paper) 80%, transparent);
|
||||
|
||||
/* ── Fonts ───────────────────────────────────────────────── */
|
||||
--font-display: 'DM Serif Display', Georgia, serif;
|
||||
--font-ui: 'DM Sans', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
|
||||
/* ── Type scale ──────────────────────────────────────────── */
|
||||
--text-xs: 0.75rem;
|
||||
--text-sm: 0.875rem;
|
||||
--text-base: 1rem;
|
||||
--text-md: 1.125rem;
|
||||
--text-lg: 1.375rem;
|
||||
--text-xl: 1.75rem;
|
||||
--text-2xl: 2.25rem;
|
||||
--text-3xl: 3rem;
|
||||
--text-xs: 0.75rem;
|
||||
--text-sm: 0.875rem;
|
||||
--text-base: 1rem;
|
||||
--text-md: 1.125rem;
|
||||
--text-lg: 1.375rem;
|
||||
--text-xl: 1.75rem;
|
||||
--text-2xl: 2.25rem;
|
||||
--text-3xl: 3rem;
|
||||
--text-story: 1.0625rem; /* long-form reading size: story body + scrolly steps */
|
||||
|
||||
/* ── Leading ─────────────────────────────────────────────── */
|
||||
--leading-tight: 1.2;
|
||||
--leading-snug: 1.35;
|
||||
--leading-normal: 1.65;
|
||||
--leading-story: 1.85; /* relaxed reading rhythm for story long-form */
|
||||
|
||||
/* ── Tracking ────────────────────────────────────────────── */
|
||||
--tracking-caps: 0.07em; /* uppercase UI labels: dates, badges, sidebar headings */
|
||||
--tracking-display: -0.015em; /* display headings: text-xl and text-2xl */
|
||||
--tracking-display-sm: -0.01em; /* display headings: text-lg and smaller; site logotype */
|
||||
|
||||
/* ── Spacing (4px grid) ──────────────────────────────────── */
|
||||
--space-1: 0.25rem;
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/* Mobile nav: hamburger toggle for the slide-down menu panel.
|
||||
Standalone (not part of the esbuild bundle) — a small progressive
|
||||
enhancement for the header. Loaded via base.html.twig. */
|
||||
(function () {
|
||||
var toggle = document.querySelector('.nav-toggle');
|
||||
var nav = document.getElementById('site-nav');
|
||||
if (!toggle || !nav) return;
|
||||
|
||||
function setOpen(open) {
|
||||
toggle.setAttribute('aria-expanded', open ? 'true' : 'false');
|
||||
toggle.setAttribute('aria-label', open ? 'Close menu' : 'Open menu');
|
||||
nav.setAttribute('data-open', open ? 'true' : 'false');
|
||||
}
|
||||
|
||||
toggle.addEventListener('click', function (e) {
|
||||
e.stopPropagation();
|
||||
setOpen(toggle.getAttribute('aria-expanded') !== 'true');
|
||||
});
|
||||
|
||||
/* Tapping a link closes the panel before navigating. */
|
||||
nav.addEventListener('click', function (e) {
|
||||
if (e.target.closest('a')) setOpen(false);
|
||||
});
|
||||
|
||||
/* Close on outside tap or Escape. */
|
||||
document.addEventListener('click', function (e) {
|
||||
if (!nav.contains(e.target) && !toggle.contains(e.target)) setOpen(false);
|
||||
});
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if (e.key === 'Escape') setOpen(false);
|
||||
});
|
||||
|
||||
/* Reset to closed if the viewport grows back to desktop. */
|
||||
window.addEventListener('resize', function () {
|
||||
if (window.innerWidth > 768) setOpen(false);
|
||||
});
|
||||
})();
|
||||
Generated
+9
-1
@@ -13,7 +13,8 @@
|
||||
"scrollama": "^3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.21"
|
||||
"esbuild": "^0.21",
|
||||
"lucide-static": "latest"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/aix-ppc64": {
|
||||
@@ -747,6 +748,13 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lucide-static": {
|
||||
"version": "1.21.0",
|
||||
"resolved": "https://registry.npmjs.org/lucide-static/-/lucide-static-1.21.0.tgz",
|
||||
"integrity": "sha512-6248z2/4sEyKkYAPPUYxOPiB2RCfMmLdMHuoOhsTFnoD40ixAoHmTVhOPux8ADa1NTBmzpEKF7WNePm+Ms503Q==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/maplibre-gl": {
|
||||
"version": "4.7.1",
|
||||
"resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-4.7.1.tgz",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "esbuild js/src/main.js --bundle --minify --format=iife --outfile=js/main.js --loader:.woff2=file --loader:.woff=file --asset-names=../fonts/[name] && esbuild js/src/map.js --bundle --minify --format=iife --outfile=js/map.js && mkdir -p css-compiled fonts && { mv js/main.css css-compiled/main.css 2>/dev/null || true; } && { mv js/map.css css-compiled/map.css 2>/dev/null || true; }"
|
||||
"build": "node scripts/gen-weather-icons.js && esbuild js/src/main.js --bundle --minify --format=iife --outfile=js/main.js --loader:.woff2=file --loader:.woff=file --asset-names=../fonts/[name] && esbuild js/src/map.js --bundle --minify --format=iife --outfile=js/map.js && mkdir -p css-compiled fonts && { mv js/main.css css-compiled/main.css 2>/dev/null || true; } && { mv js/map.css css-compiled/map.css 2>/dev/null || true; }"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource-variable/dm-sans": "latest",
|
||||
@@ -12,6 +12,7 @@
|
||||
"scrollama": "^3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.21"
|
||||
"esbuild": "^0.21",
|
||||
"lucide-static": "latest"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const iconMap = {
|
||||
'sunny': 'sun',
|
||||
'partly cloudy': 'cloud-sun',
|
||||
'cloudy': 'cloud',
|
||||
'foggy': 'cloud-fog',
|
||||
'drizzle': 'cloud-drizzle',
|
||||
'rain': 'cloud-rain',
|
||||
'snow': 'cloud-snow',
|
||||
'thunderstorm': 'cloud-lightning'
|
||||
};
|
||||
|
||||
const wrapAttrs = 'width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"';
|
||||
|
||||
function buildSvg(iconName) {
|
||||
const src = path.resolve(__dirname, '..', 'node_modules', 'lucide-static', 'icons', iconName + '.svg');
|
||||
const raw = fs.readFileSync(src, 'utf8');
|
||||
const inner = raw
|
||||
.replace(/^[\s\S]*?<svg[^>]*>/, '')
|
||||
.replace(/<\/svg>[\s\S]*$/, '')
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim();
|
||||
return `<svg ${wrapAttrs}>${inner}</svg>`;
|
||||
}
|
||||
|
||||
const entries = Object.entries(iconMap);
|
||||
const lines = entries.map(([condition, iconName], i) => {
|
||||
const svg = buildSvg(iconName).replace(/'/g, "\\'");
|
||||
const pad = ' '.repeat(Math.max(0, 16 - condition.length));
|
||||
const comma = i < entries.length - 1 ? ',' : '';
|
||||
return ` '${condition}':${pad}'${svg}'${comma}`;
|
||||
});
|
||||
|
||||
const twig = [
|
||||
'{# Auto-generated by scripts/gen-weather-icons.js — do not edit directly #}',
|
||||
'{% set weather_icons = {',
|
||||
...lines,
|
||||
'} %}'
|
||||
].join('\n') + '\n';
|
||||
|
||||
const dest = path.resolve(__dirname, '..', 'templates', 'partials', 'weather-icons.html.twig');
|
||||
fs.writeFileSync(dest, twig);
|
||||
console.log('Generated ' + path.relative(path.resolve(__dirname, '..'), dest));
|
||||
@@ -6,7 +6,6 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@5/dist/photoswipe.css">
|
||||
{% set journal_entries = page.collection() %}
|
||||
{% set stories_page = grav.pages.find(page.parent().route ~ '/stories') %}
|
||||
{% set story_entries = stories_page ? stories_page.children.published() : [] %}
|
||||
@@ -68,67 +67,4 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<script type="module">
|
||||
import PhotoSwipeLightbox from 'https://cdn.jsdelivr.net/npm/photoswipe@5/dist/photoswipe-lightbox.esm.min.js';
|
||||
|
||||
const lightbox = new PhotoSwipeLightbox({
|
||||
gallery: '.pswp-gallery',
|
||||
children: 'a.journal-photo-slide',
|
||||
pswpModule: () => import('https://cdn.jsdelivr.net/npm/photoswipe@5/dist/photoswipe.esm.min.js')
|
||||
});
|
||||
lightbox.on('afterOpen', function () {
|
||||
var pswp = lightbox.pswp;
|
||||
var keyDir = 0;
|
||||
var clearTimer = null;
|
||||
function onKey(e) {
|
||||
if (e.key === 'ArrowRight') keyDir = 1;
|
||||
else if (e.key === 'ArrowLeft') keyDir = -1;
|
||||
else keyDir = 0;
|
||||
}
|
||||
document.addEventListener('keydown', onKey, true);
|
||||
pswp.on('change', function () {
|
||||
if (!keyDir) return;
|
||||
var dir = keyDir;
|
||||
keyDir = 0;
|
||||
var el = pswp.currSlide && pswp.currSlide.container;
|
||||
if (!el) return;
|
||||
el.classList.remove('pswp-key-from-left', 'pswp-key-from-right');
|
||||
el.offsetWidth;
|
||||
el.classList.add(dir > 0 ? 'pswp-key-from-right' : 'pswp-key-from-left');
|
||||
clearTimeout(clearTimer);
|
||||
clearTimer = setTimeout(function () { el.classList.remove('pswp-key-from-left', 'pswp-key-from-right'); }, 400);
|
||||
});
|
||||
pswp.on('close', function () {
|
||||
document.removeEventListener('keydown', onKey, true);
|
||||
clearTimeout(clearTimer);
|
||||
});
|
||||
});
|
||||
lightbox.init();
|
||||
|
||||
/* Per-strip: dot sync + expand button → tap the visible slide to trigger pswp */
|
||||
document.querySelectorAll('.journal-photo-wrap').forEach(function (wrap) {
|
||||
var strip = wrap.querySelector('.journal-photo-strip');
|
||||
var slides = Array.from(strip.querySelectorAll('a.journal-photo-slide'));
|
||||
var expandBtn = wrap.querySelector('.journal-photo-expand');
|
||||
var article = wrap.closest('article');
|
||||
var dots = article ? Array.from(article.querySelectorAll('.journal-photo-dot')) : [];
|
||||
var visibleIdx = 0;
|
||||
|
||||
var io = new IntersectionObserver(function (entries) {
|
||||
entries.forEach(function (e) {
|
||||
if (!e.isIntersecting) return;
|
||||
visibleIdx = slides.indexOf(e.target);
|
||||
dots.forEach(function (d) { d.classList.remove('is-active'); });
|
||||
if (dots[visibleIdx]) dots[visibleIdx].classList.add('is-active');
|
||||
});
|
||||
}, { root: strip, threshold: 0.5 });
|
||||
slides.forEach(function (s) { io.observe(s); });
|
||||
|
||||
if (expandBtn && slides.length) {
|
||||
expandBtn.addEventListener('click', function () {
|
||||
slides[visibleIdx].dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }));
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,129 +1,12 @@
|
||||
{% extends 'default.html.twig' %}
|
||||
{% extends 'partials/base.html.twig' %}
|
||||
|
||||
{% block content %}
|
||||
{% set weather_icons = {
|
||||
'Sunny': '☀️', 'Partly cloudy': '⛅', 'Cloudy': '☁️',
|
||||
'Foggy': '🌫️', 'Drizzle': '🌦️', 'Rain': '🌧️',
|
||||
'Snow': '❄️', 'Thunderstorm': '⛈️'
|
||||
} %}
|
||||
|
||||
{% set hero = null %}
|
||||
{% if page.header.hero_image and page.media[page.header.hero_image] is defined %}
|
||||
{% set hero = page.media[page.header.hero_image] %}
|
||||
{% elseif page.media.images|length > 0 %}
|
||||
{% set hero = page.media.images|first %}
|
||||
{% endif %}
|
||||
|
||||
<a class="back-pill entry-back-fixed" href="{{ page.parent().url }}" onclick="if(history.length > 1){ history.back(); return false; }">← Back</a>
|
||||
|
||||
<article class="entry">
|
||||
{% if hero %}
|
||||
<div class="entry-hero">
|
||||
<img src="{{ hero.cropResize(1440, 720).url }}" alt="{{ page.title }}" loading="eager">
|
||||
</div>
|
||||
{% endif %}
|
||||
{% set entry = page %}
|
||||
{% include 'partials/entry-journal.html.twig' %}
|
||||
|
||||
<header class="entry-header">
|
||||
<div class="entry-header-meta">
|
||||
<time class="entry-date" datetime="{{ page.date|date('Y-m-d') }}">
|
||||
{{ page.date|date('l, d F Y') }}
|
||||
</time>
|
||||
{% if page.header.location_city or page.header.location_country %}
|
||||
<p class="entry-location">
|
||||
{%- set _loc = [] -%}
|
||||
{%- if page.header.location_city -%}{%- set _loc = _loc|merge([page.header.location_city]) -%}{%- endif -%}
|
||||
{%- if page.header.location_country -%}{%- set _loc = _loc|merge([page.header.location_country]) -%}{%- endif -%}
|
||||
📍 {{ _loc|join(', ') }}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% if page.header.weather_desc or page.header.weather_temp_c %}
|
||||
<p class="entry-weather">
|
||||
{% if page.header.weather_desc %}
|
||||
{{ weather_icons[page.header.weather_desc] ?? '🌡️' }} {{ page.header.weather_desc }}
|
||||
{% endif %}
|
||||
{% if page.header.weather_temp_c %}
|
||||
· {{ page.header.weather_temp_c|round }}°C
|
||||
{% endif %}
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<h1 class="entry-title">{{ page.title }}</h1>
|
||||
<div class="entry-title-rule"></div>
|
||||
</header>
|
||||
|
||||
<div class="entry-body">
|
||||
{{ page.content|raw }}
|
||||
</div>
|
||||
|
||||
{% set images = page.media.images %}
|
||||
{% if images|length > 0 %}
|
||||
<div class="entry-gallery" id="entry-gallery">
|
||||
{% for image in images %}
|
||||
<button class="gallery-thumb" data-full="{{ image.url }}" data-alt="{{ image.filename }}" aria-label="View {{ image.filename }}">
|
||||
<img src="{{ image.cropResize(300, 300).url }}" alt="{{ image.filename }}" loading="lazy">
|
||||
</button>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="lightbox" id="lightbox" role="dialog" aria-modal="true" aria-label="Photo viewer" hidden>
|
||||
<button class="lightbox-close" id="lb-close" aria-label="Close">✕</button>
|
||||
<button class="lightbox-prev" id="lb-prev" aria-label="Previous">‹</button>
|
||||
<img class="lightbox-img" id="lb-img" src="" alt="">
|
||||
<button class="lightbox-next" id="lb-next" aria-label="Next">›</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
var gallery = document.getElementById('entry-gallery');
|
||||
var lightbox = document.getElementById('lightbox');
|
||||
var lbImg = document.getElementById('lb-img');
|
||||
var thumbs = Array.from(gallery.querySelectorAll('.gallery-thumb'));
|
||||
var current = 0;
|
||||
|
||||
function open(index) {
|
||||
current = index;
|
||||
var btn = thumbs[index];
|
||||
lbImg.src = btn.dataset.full;
|
||||
lbImg.alt = btn.dataset.alt;
|
||||
lightbox.hidden = false;
|
||||
document.body.style.overflow = 'hidden';
|
||||
document.getElementById('lb-close').focus();
|
||||
}
|
||||
|
||||
function close() {
|
||||
lightbox.hidden = true;
|
||||
document.body.style.overflow = '';
|
||||
thumbs[current].focus();
|
||||
}
|
||||
|
||||
function prev() { open((current - 1 + thumbs.length) % thumbs.length); }
|
||||
function next() { open((current + 1) % thumbs.length); }
|
||||
|
||||
thumbs.forEach(function(btn, i) {
|
||||
btn.addEventListener('click', function() { open(i); });
|
||||
});
|
||||
|
||||
document.getElementById('lb-close').addEventListener('click', close);
|
||||
document.getElementById('lb-prev').addEventListener('click', prev);
|
||||
document.getElementById('lb-next').addEventListener('click', next);
|
||||
|
||||
lightbox.addEventListener('click', function(e) {
|
||||
if (e.target === lightbox) close();
|
||||
});
|
||||
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (lightbox.hidden) return;
|
||||
if (e.key === 'Escape') close();
|
||||
if (e.key === 'ArrowLeft') prev();
|
||||
if (e.key === 'ArrowRight') next();
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
<footer class="entry-footer">
|
||||
<a class="back-pill" href="{{ page.parent().url }}" onclick="if(history.length > 1){ history.back(); return false; }">← Back</a>
|
||||
</footer>
|
||||
</article>
|
||||
<footer class="entry-footer">
|
||||
<a class="back-pill" href="{{ page.parent().url }}" onclick="if(history.length > 1){ history.back(); return false; }">← Back</a>
|
||||
</footer>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
{% extends 'partials/base.html.twig' %}
|
||||
|
||||
{% block map_assets %}
|
||||
{% do assets.addCss('theme://css-compiled/map.css') %}
|
||||
{% do assets.addJs('theme://js/map.js', {group: 'bottom'}) %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@5/dist/photoswipe.css">
|
||||
{% set trip_route = config.site.active_trip %}
|
||||
{% set trip = grav.pages.find(trip_route) %}
|
||||
|
||||
@@ -80,18 +84,13 @@
|
||||
</div>
|
||||
|
||||
{% if map_entries|length > 0 %}
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/maplibre-gl@4/dist/maplibre-gl.css">
|
||||
<script src="https://cdn.jsdelivr.net/npm/maplibre-gl@4/dist/maplibre-gl.js"></script>
|
||||
{% if home_gpx_urls|length > 0 %}
|
||||
<script src="https://cdn.jsdelivr.net/npm/@mapbox/togeojson@0.16.2/togeojson.min.js"></script>
|
||||
{% endif %}
|
||||
<script src="{{ url('theme://js/maplibre-utils.js') }}"></script>
|
||||
<script>
|
||||
var HOME_ENTRIES = {{ map_entries|json_encode|raw }};
|
||||
var HOME_GPX_URLS = {{ home_gpx_urls|json_encode|raw }};
|
||||
var USE_GPX = {{ trip and trip.header.use_gpx is not null ? (trip.header.use_gpx ? 'true' : 'false') : 'true' }};
|
||||
var AUTOCONNECT = "{{ trip ? (trip.header.autoconnect ?? 'on') : 'on' }}";
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var homeMap = new maplibregl.Map({
|
||||
container: 'home-map',
|
||||
style: MapUtils.MAP_STYLE,
|
||||
@@ -135,71 +134,10 @@ homeMap.on('load', function () {
|
||||
|
||||
MapUtils.renderGpxJourney(homeMap, USE_GPX ? HOME_GPX_URLS : [], HOME_ENTRIES, 'home-gpx', 'home-journey', { connectMode: AUTOCONNECT });
|
||||
});
|
||||
}); // DOMContentLoaded
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
<script type="module">
|
||||
import PhotoSwipeLightbox from 'https://cdn.jsdelivr.net/npm/photoswipe@5/dist/photoswipe-lightbox.esm.min.js';
|
||||
const lightbox = new PhotoSwipeLightbox({
|
||||
gallery: '.pswp-gallery',
|
||||
children: 'a.journal-photo-slide',
|
||||
pswpModule: () => import('https://cdn.jsdelivr.net/npm/photoswipe@5/dist/photoswipe.esm.min.js')
|
||||
});
|
||||
lightbox.on('afterOpen', function () {
|
||||
var pswp = lightbox.pswp;
|
||||
var keyDir = 0;
|
||||
var clearTimer = null;
|
||||
function onKey(e) {
|
||||
if (e.key === 'ArrowRight') keyDir = 1;
|
||||
else if (e.key === 'ArrowLeft') keyDir = -1;
|
||||
else keyDir = 0;
|
||||
}
|
||||
document.addEventListener('keydown', onKey, true);
|
||||
pswp.on('change', function () {
|
||||
if (!keyDir) return;
|
||||
var dir = keyDir;
|
||||
keyDir = 0;
|
||||
var el = pswp.currSlide && pswp.currSlide.container;
|
||||
if (!el) return;
|
||||
el.classList.remove('pswp-key-from-left', 'pswp-key-from-right');
|
||||
el.offsetWidth;
|
||||
el.classList.add(dir > 0 ? 'pswp-key-from-right' : 'pswp-key-from-left');
|
||||
clearTimeout(clearTimer);
|
||||
clearTimer = setTimeout(function () { el.classList.remove('pswp-key-from-left', 'pswp-key-from-right'); }, 400);
|
||||
});
|
||||
pswp.on('close', function () {
|
||||
document.removeEventListener('keydown', onKey, true);
|
||||
clearTimeout(clearTimer);
|
||||
});
|
||||
});
|
||||
lightbox.init();
|
||||
|
||||
document.querySelectorAll('.journal-photo-wrap').forEach(function (wrap) {
|
||||
var strip = wrap.querySelector('.journal-photo-strip');
|
||||
var slides = Array.from(strip.querySelectorAll('a.journal-photo-slide'));
|
||||
var expandBtn = wrap.querySelector('.journal-photo-expand');
|
||||
var article = wrap.closest('article');
|
||||
var dots = article ? Array.from(article.querySelectorAll('.journal-photo-dot')) : [];
|
||||
var visibleIdx = 0;
|
||||
|
||||
var io = new IntersectionObserver(function (entries) {
|
||||
entries.forEach(function (e) {
|
||||
if (!e.isIntersecting) return;
|
||||
visibleIdx = slides.indexOf(e.target);
|
||||
dots.forEach(function (d) { d.classList.remove('is-active'); });
|
||||
if (dots[visibleIdx]) dots[visibleIdx].classList.add('is-active');
|
||||
});
|
||||
}, { root: strip, threshold: 0.5 });
|
||||
slides.forEach(function (s) { io.observe(s); });
|
||||
|
||||
if (expandBtn && slides.length) {
|
||||
expandBtn.addEventListener('click', function () {
|
||||
slides[visibleIdx].dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }));
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{% else %}
|
||||
{# ══════════════════════════════════════════════════════ BETWEEN-TRIPS MODE #}
|
||||
|
||||
@@ -305,12 +243,10 @@ document.querySelectorAll('.journal-photo-wrap').forEach(function (wrap) {
|
||||
</div>
|
||||
|
||||
{% if highlights_map_entries|length > 0 %}
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/maplibre-gl@4/dist/maplibre-gl.css">
|
||||
<script src="https://cdn.jsdelivr.net/npm/maplibre-gl@4/dist/maplibre-gl.js"></script>
|
||||
<script src="{{ url('theme://js/maplibre-utils.js') }}"></script>
|
||||
<script>
|
||||
var HIGHLIGHTS_ENTRIES = {{ highlights_map_entries|json_encode|raw }};
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var homeMap = new maplibregl.Map({
|
||||
container: 'home-map',
|
||||
style: MapUtils.MAP_STYLE,
|
||||
@@ -349,6 +285,7 @@ homeMap.on('load', function () {
|
||||
|
||||
setTimeout(function () { homeMap.resize(); }, 100);
|
||||
});
|
||||
}); // DOMContentLoaded
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
{% do assets.addCss('theme://css/style.css') %}
|
||||
{% do assets.addCss('theme://css-compiled/main.css') %}
|
||||
{% do assets.addJs('theme://js/main.js', {group: 'bottom'}) %}
|
||||
{% do assets.addJs('theme://js/nav.js', {group: 'bottom'}) %}
|
||||
{% block map_assets %}{% endblock %}
|
||||
{{ assets.css()|raw }}
|
||||
{{ assets.js()|raw }}
|
||||
@@ -17,7 +18,12 @@
|
||||
<header class="site-header">
|
||||
<a class="site-title" href="{{ base_url_absolute }}">into the east</a>
|
||||
{% block nav %}
|
||||
<nav class="site-nav" aria-label="Main navigation">
|
||||
<button class="nav-toggle" type="button" aria-label="Open menu" aria-controls="site-nav" aria-expanded="false">
|
||||
<span class="nav-toggle__bar"></span>
|
||||
<span class="nav-toggle__bar"></span>
|
||||
<span class="nav-toggle__bar"></span>
|
||||
</button>
|
||||
<nav class="site-nav" id="site-nav" aria-label="Main navigation">
|
||||
<a href="{{ base_url_absolute }}"{% if page.template == 'home' %} aria-current="page"{% endif %}>Home</a>
|
||||
<a href="{{ base_url_absolute }}/trips"{% if page.template == 'trips' %} aria-current="page"{% endif %}>Past Trips</a>
|
||||
</nav>
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
{% set weather_icons = {
|
||||
'Sunny': '☀️', 'Partly cloudy': '⛅', 'Cloudy': '☁️',
|
||||
'Foggy': '🌫️', 'Drizzle': '🌦️', 'Rain': '🌧️',
|
||||
'Snow': '❄️', 'Thunderstorm': '⛈️'
|
||||
} %}
|
||||
{% include 'partials/weather-icons.html.twig' %}
|
||||
<article class="journal-post" id="entry-{{ entry.slug }}" data-type="journal" data-lat="{{ entry.header.lat }}" data-lng="{{ entry.header.lng }}">
|
||||
<header class="journal-post-header">
|
||||
<h2 class="journal-post-title">{{ entry.title }}</h2>
|
||||
@@ -12,7 +8,7 @@
|
||||
</a>
|
||||
{% if entry.header.location_city or entry.header.location_country %}
|
||||
<span class="journal-post-location">
|
||||
· 📍
|
||||
· <svg width="11" height="13" viewBox="0 0 12 14" fill="currentColor" aria-hidden="true"><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>
|
||||
{%- set _loc = [] -%}
|
||||
{%- if entry.header.location_city -%}{%- set _loc = _loc|merge([entry.header.location_city]) -%}{%- endif -%}
|
||||
{%- if entry.header.location_country -%}{%- set _loc = _loc|merge([entry.header.location_country]) -%}{%- endif -%}
|
||||
@@ -20,7 +16,7 @@
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if entry.header.weather_desc %}
|
||||
<span class="journal-post-weather">· {{ weather_icons[entry.header.weather_desc] ?? '' }} {{ entry.header.weather_desc }}</span>
|
||||
<span class="journal-post-weather">· {{ weather_icons[entry.header.weather_desc|lower]|default('')|raw }} {{ entry.header.weather_desc }}</span>
|
||||
{% endif %}
|
||||
</p>
|
||||
</header>
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{# Auto-generated by scripts/gen-weather-icons.js — do not edit directly #}
|
||||
{% set weather_icons = {
|
||||
'sunny': '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="4" /> <path d="M12 2v2" /> <path d="M12 20v2" /> <path d="m4.93 4.93 1.41 1.41" /> <path d="m17.66 17.66 1.41 1.41" /> <path d="M2 12h2" /> <path d="M20 12h2" /> <path d="m6.34 17.66-1.41 1.41" /> <path d="m19.07 4.93-1.41 1.41" /></svg>',
|
||||
'partly cloudy': '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 2v2" /> <path d="m4.93 4.93 1.41 1.41" /> <path d="M20 12h2" /> <path d="m19.07 4.93-1.41 1.41" /> <path d="M15.947 12.65a4 4 0 0 0-5.925-4.128" /> <path d="M13 22H7a5 5 0 1 1 4.9-6H13a3 3 0 0 1 0 6Z" /></svg>',
|
||||
'cloudy': '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z" /></svg>',
|
||||
'foggy': '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 14.899A7 7 0 1 1 15.71 8h1.79a4.5 4.5 0 0 1 2.5 8.242" /> <path d="M16 17H7" /> <path d="M17 21H9" /></svg>',
|
||||
'drizzle': '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 14.899A7 7 0 1 1 15.71 8h1.79a4.5 4.5 0 0 1 2.5 8.242" /> <path d="M8 19v1" /> <path d="M8 14v1" /> <path d="M16 19v1" /> <path d="M16 14v1" /> <path d="M12 21v1" /> <path d="M12 16v1" /></svg>',
|
||||
'rain': '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 14.899A7 7 0 1 1 15.71 8h1.79a4.5 4.5 0 0 1 2.5 8.242" /> <path d="M16 14v6" /> <path d="M8 14v6" /> <path d="M12 16v6" /></svg>',
|
||||
'snow': '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 14.899A7 7 0 1 1 15.71 8h1.79a4.5 4.5 0 0 1 2.5 8.242" /> <path d="M8 15h.01" /> <path d="M8 19h.01" /> <path d="M12 17h.01" /> <path d="M12 21h.01" /> <path d="M16 15h.01" /> <path d="M16 19h.01" /></svg>',
|
||||
'thunderstorm': '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 16.326A7 7 0 1 1 15.71 8h1.79a4.5 4.5 0 0 1 .5 8.973" /> <path d="m13 12-3 5h4l-3 5" /></svg>'
|
||||
} %}
|
||||
@@ -6,6 +6,7 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="story-progress" id="story-progress"></div>
|
||||
{% import 'macros/date-range.html.twig' as dr_m %}
|
||||
{% set hero_url = null %}
|
||||
{% if page.header.hero_image %}
|
||||
@@ -46,6 +47,15 @@
|
||||
</div>
|
||||
|
||||
<div class="story-body">
|
||||
{% 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 %}
|
||||
{{ page.content|raw }}
|
||||
|
||||
<footer class="story-footer">
|
||||
@@ -187,6 +197,25 @@
|
||||
});
|
||||
})();
|
||||
|
||||
/* ── 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();
|
||||
})();
|
||||
|
||||
/* ── ScrollySection (Scrollama) ──────────────────────────── */
|
||||
(function () {
|
||||
var reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
<div class="home-trip-header">
|
||||
<h1 class="home-trip-name">{{ page.title }}</h1>
|
||||
{% if page.header.date_start %}
|
||||
<p class="trip-dates" style="font-size:var(--text-sm);color:var(--color-ink-muted);margin:var(--space-1) 0 var(--space-2);">
|
||||
<p class="trip-dates">
|
||||
{{ page.header.date_start|date('d M Y') }}
|
||||
{% if page.header.date_end %} — {{ page.header.date_end|date('d M Y') }}{% else %} — Ongoing{% endif %}
|
||||
</p>
|
||||
|
||||
@@ -13,6 +13,20 @@
|
||||
{% set journal_count = dailies_page ? dailies_page.children.published()|length : 0 %}
|
||||
{% set story_count = stories_page ? stories_page.children.published()|length : 0 %}
|
||||
<a class="trip-card" href="{{ trip.url }}">
|
||||
{% 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 %}
|
||||
<div class="trip-card-title">{{ trip.title }}</div>
|
||||
<div class="trip-card-meta">
|
||||
{% if trip.header.date_start %}
|
||||
|
||||
Reference in New Issue
Block a user