From d3fcde9b0b35705e901a42eb029be3a3855f35f5 Mon Sep 17 00:00:00 2001 From: Mischa Date: Thu, 18 Jun 2026 01:10:41 +0200 Subject: [PATCH] =?UTF-8?q?Phase=204=20M1:=20Entry=20enrichment=20?= =?UTF-8?q?=E2=80=94=20location,=20weather,=20gallery,=20hero=20image?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- accounts/.htaccess | 10 + blueprints/entry.yaml | 38 ++- config/.htaccess | 10 + pages/01.tracker/2026-06-17.entry/entry.md | 8 +- pages/02.post/post-form.md | 24 ++ themes/intotheeast/css/style.css | 280 +++++++++++++++++- themes/intotheeast/templates/entry.html.twig | 95 ++++++ .../intotheeast/templates/post-form.html.twig | 59 +++- .../intotheeast/templates/tracker.html.twig | 38 ++- 9 files changed, 531 insertions(+), 31 deletions(-) create mode 100644 accounts/.htaccess create mode 100644 config/.htaccess diff --git a/accounts/.htaccess b/accounts/.htaccess new file mode 100644 index 0000000..9fc26b8 --- /dev/null +++ b/accounts/.htaccess @@ -0,0 +1,10 @@ +# Deny all direct web access to this folder and everything beneath it. +# Grav reads these files server-side; they must never be served over HTTP. +# This is a defense-in-depth backup for the rules in the site root .htaccess. + + Require all denied + + + Order allow,deny + Deny from all + diff --git a/blueprints/entry.yaml b/blueprints/entry.yaml index c5c6e67..f26a14f 100644 --- a/blueprints/entry.yaml +++ b/blueprints/entry.yaml @@ -41,20 +41,54 @@ form: title: Location fields: + header.location_city: + type: text + label: City + placeholder: 'e.g. Kyoto' + + header.location_country: + type: text + label: Country + placeholder: 'e.g. Japan' + header.lat: type: number label: Latitude - help: 'GPS latitude (for map, Milestone 2)' + help: 'GPS latitude (for map)' placeholder: '48.8566' step: any header.lng: type: number label: Longitude - help: 'GPS longitude (for map, Milestone 2)' + help: 'GPS longitude (for map)' placeholder: '2.3522' step: any + weather: + type: tab + title: Weather + + fields: + header.weather_temp_c: + type: number + label: 'Temperature (°C)' + help: 'Auto-filled from post form. Edit if needed.' + step: 1 + + header.weather_desc: + type: select + label: 'Weather Condition' + options: + Sunny: '☀️ Sunny' + 'Partly cloudy': '⛅ Partly cloudy' + Cloudy: '☁️ Cloudy' + Foggy: '🌫️ Foggy' + Drizzle: '🌦️ Drizzle' + Rain: '🌧️ Rain' + Snow: '❄️ Snow' + Thunderstorm: '⛈️ Thunderstorm' + publishing: type: tab title: Publishing diff --git a/config/.htaccess b/config/.htaccess new file mode 100644 index 0000000..9fc26b8 --- /dev/null +++ b/config/.htaccess @@ -0,0 +1,10 @@ +# Deny all direct web access to this folder and everything beneath it. +# Grav reads these files server-side; they must never be served over HTTP. +# This is a defense-in-depth backup for the rules in the site root .htaccess. + + Require all denied + + + Order allow,deny + Deny from all + diff --git a/pages/01.tracker/2026-06-17.entry/entry.md b/pages/01.tracker/2026-06-17.entry/entry.md index f91533f..262745b 100644 --- a/pages/01.tracker/2026-06-17.entry/entry.md +++ b/pages/01.tracker/2026-06-17.entry/entry.md @@ -4,8 +4,12 @@ date: '2026-06-17 10:00' template: entry published: true hero_image: '' -lat: '' -lng: '' +lat: '52.3676' +lng: '4.9041' +location_city: 'Amsterdam' +location_country: 'Netherlands' +weather_temp_c: 19 +weather_desc: 'Partly cloudy' --- First entry. Bags are packed, passport is ready, the adventure starts here. diff --git a/pages/02.post/post-form.md b/pages/02.post/post-form.md index 9a18860..555584e 100644 --- a/pages/02.post/post-form.md +++ b/pages/02.post/post-form.md @@ -56,6 +56,26 @@ form: type: text placeholder: '' + - + name: location_city + label: City + type: text + placeholder: 'e.g. Kyoto' + + - + name: location_country + label: Country + type: text + placeholder: 'e.g. Japan' + + - + name: weather_temp_c + type: hidden + + - + name: weather_desc + type: hidden + buttons: - type: submit @@ -73,6 +93,10 @@ form: date: '{{ form.value.date }}' lat: '{{ form.value.lat }}' lng: '{{ form.value.lng }}' + location_city: '{{ form.value.location_city }}' + location_country: '{{ form.value.location_country }}' + weather_temp_c: '{{ form.value.weather_temp_c }}' + weather_desc: '{{ form.value.weather_desc }}' - message: 'Entry posted successfully!' - diff --git a/themes/intotheeast/css/style.css b/themes/intotheeast/css/style.css index 4a5ecde..8c122ed 100644 --- a/themes/intotheeast/css/style.css +++ b/themes/intotheeast/css/style.css @@ -39,7 +39,8 @@ body { padding: 1.5rem 1.25rem; } -/* Feed */ +/* ── Feed ──────────────────────────────────────────────────────────────────── */ + .feed { display: flex; flex-direction: column; gap: 2rem; } .entry-card { @@ -53,15 +54,31 @@ body { color: #666; text-transform: uppercase; letter-spacing: 0.05em; - margin-bottom: 0.4rem; + margin-bottom: 0.25rem; } +.entry-card-meta { + display: flex; + align-items: center; + gap: 0.75rem; + margin-bottom: 0.5rem; + flex-wrap: wrap; +} + +.entry-card-meta .entry-date { margin-bottom: 0; } + .entry-card .entry-title { font-size: 1.3rem; margin-bottom: 0.75rem; } .entry-card .entry-title a { color: inherit; text-decoration: none; } .entry-card .entry-title a:hover { text-decoration: underline; } .entry-thumb { margin-bottom: 0.75rem; } -.entry-thumb img { width: 100%; height: 200px; object-fit: cover; border-radius: 4px; } +.entry-thumb img { + width: 100%; + aspect-ratio: 16 / 9; + object-fit: cover; + border-radius: 8px; + display: block; +} .entry-excerpt { color: #444; margin-bottom: 0.75rem; } @@ -73,17 +90,231 @@ body { .feed-empty { color: #666; font-style: italic; } -/* Single entry */ +/* ── Location & Weather badges ─────────────────────────────────────────────── */ + +.entry-location { + font-size: 0.82rem; + color: #555; + display: inline-flex; + align-items: center; + gap: 0.2rem; +} + +.entry-location--card { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 200px; +} + +.entry-weather { + font-size: 0.82rem; + color: #555; + margin-bottom: 0.25rem; +} + +/* ── Single entry ───────────────────────────────────────────────────────────── */ + .entry-header { margin-bottom: 1.5rem; } -.entry-header .entry-date { margin-bottom: 0.5rem; } -.entry .entry-title { font-size: 1.8rem; } +.entry-header .entry-date { margin-bottom: 0.3rem; } +.entry-header .entry-location { margin-bottom: 0.2rem; display: block; } +.entry-header .entry-weather { margin-bottom: 0.75rem; } +.entry .entry-title { font-size: 1.8rem; margin-top: 0.5rem; } .entry-body { margin-bottom: 2rem; } .entry-body p { margin-bottom: 1em; } .entry-body img { max-width: 100%; height: auto; border-radius: 4px; } .entry-footer { border-top: 1px solid #e5e5e5; padding-top: 1rem; } .entry-footer a { color: #0066cc; text-decoration: none; font-size: 0.9rem; } -/* Login form */ +/* ── Photo gallery ──────────────────────────────────────────────────────────── */ + +.entry-gallery { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 4px; + margin-bottom: 2rem; +} + +@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; + border-radius: 4px; +} + +.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.85; } + +.gallery-thumb:focus { outline: 2px solid #0066cc; outline-offset: 2px; } + +/* ── Lightbox ───────────────────────────────────────────────────────────────── */ + +.lightbox { + position: fixed; + inset: 0; + background: rgba(0,0,0,0.92); + z-index: 1000; + display: flex; + align-items: center; + justify-content: center; +} + +.lightbox[hidden] { display: none; } + +.lightbox-img { + max-width: 92vw; + max-height: 90vh; + object-fit: contain; + border-radius: 4px; + display: block; +} + +.lightbox-close, +.lightbox-prev, +.lightbox-next { + position: absolute; + background: rgba(255,255,255,0.15); + border: none; + color: #fff; + cursor: pointer; + border-radius: 50%; + width: 44px; + height: 44px; + font-size: 1.4rem; + display: flex; + align-items: center; + justify-content: center; + line-height: 1; +} + +.lightbox-close { top: 1rem; right: 1rem; } +.lightbox-prev { left: 0.75rem; top: 50%; transform: translateY(-50%); } +.lightbox-next { right: 0.75rem; top: 50%; transform: translateY(-50%); } + +.lightbox-close:hover, +.lightbox-prev:hover, +.lightbox-next:hover { background: rgba(255,255,255,0.28); } + +/* ── Map page ───────────────────────────────────────────────────────────────── */ + +.map-page .site-main { max-width: none; padding: 0; } + +.map-container { + height: calc(100vh - 61px); + width: 100%; +} + +.map-empty { + display: flex; + align-items: center; + justify-content: center; + height: 100%; + color: #666; + font-style: italic; +} + +/* ── Stats page ─────────────────────────────────────────────────────────────── */ + +.stats-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 1rem; + margin-bottom: 2rem; +} + +.stat-block { + border: 1px solid #e5e5e5; + border-radius: 8px; + padding: 1.25rem 1rem; + text-align: center; + box-shadow: 0 1px 3px rgba(0,0,0,0.06); +} + +.stat-value { + display: block; + font-size: 2.5rem; + font-weight: 700; + color: #0066cc; + line-height: 1.1; + margin-bottom: 0.3rem; +} + +.stat-label { + display: block; + font-size: 0.8rem; + color: #666; + text-transform: uppercase; + letter-spacing: 0.04em; +} + +.stats-countries { + font-size: 0.9rem; + color: #444; + text-align: center; + line-height: 1.8; +} + +.stats-countries-label { + font-weight: 600; + display: block; + margin-bottom: 0.4rem; + color: #1a1a1a; +} + +.stats-note { + font-size: 0.78rem; + color: #999; + text-align: center; + margin-top: 1.5rem; +} + +/* ── Mini-map on tracker feed ───────────────────────────────────────────────── */ + +.feed-map-wrap { + margin-bottom: 2rem; + border-radius: 8px; + overflow: hidden; + border: 1px solid #e5e5e5; +} + +.feed-map { + height: 240px; + width: 100%; +} + +@media (min-width: 520px) { + .feed-map { height: 320px; } +} + +.feed-map-link { + display: block; + text-align: right; + font-size: 0.8rem; + color: #0066cc; + text-decoration: none; + padding: 0.4rem 0.6rem; + background: #fafafa; + border-top: 1px solid #e5e5e5; +} + +/* ── Login form ─────────────────────────────────────────────────────────────── */ + .login-form { max-width: 400px; margin: 2rem auto; padding: 0 1rem; } .login-form .form-field { margin-bottom: 1.25rem; } .login-form .form-label label { display: block; font-size: 0.9rem; font-weight: 600; margin-bottom: 0.4rem; } @@ -101,12 +332,33 @@ body { .login-form .button.secondary { background: #f0f0f0; color: #333; text-decoration: none; line-height: 44px; padding: 0 1rem; } .login-form .rememberme { display: flex; align-items: center; gap: 0.5rem; font-size: 0.9rem; } -/* Post form */ +/* ── Post form ──────────────────────────────────────────────────────────────── */ + .post-form-wrap h1 { font-size: 1.4rem; margin-bottom: 1.5rem; } -.post-form-wrap .btn-location { - display: block; width: 100%; margin-top: 1rem; - padding: 0.85rem 1rem; min-height: 44px; - background: #f0f0f0; border: 1px solid #ccc; - border-radius: 6px; font-size: 1rem; cursor: pointer; + +.form-actions-extra { + display: flex; + gap: 0.75rem; + margin-top: 1rem; +} + +.btn-extra { + flex: 1; + padding: 0.75rem 0.5rem; + min-height: 44px; + background: #f0f0f0; + border: 1px solid #ccc; + border-radius: 6px; + font-size: 0.95rem; + cursor: pointer; + text-align: center; +} + +.btn-extra:hover { background: #e5e5e5; } + +.field-status { + font-size: 0.85rem; + color: #555; + margin-top: 0.4rem; + min-height: 1.2em; } -.post-form-wrap .location-status { font-size: 0.85rem; color: #666; margin-top: 0.5rem; text-align: center; } diff --git a/themes/intotheeast/templates/entry.html.twig b/themes/intotheeast/templates/entry.html.twig index 3f231bb..605419d 100644 --- a/themes/intotheeast/templates/entry.html.twig +++ b/themes/intotheeast/templates/entry.html.twig @@ -1,16 +1,111 @@ {% extends 'default.html.twig' %} {% block content %} +{% set weather_icons = { + 'Sunny': '☀️', 'Partly cloudy': '⛅', 'Cloudy': '☁️', + 'Foggy': '🌫️', 'Drizzle': '🌦️', 'Rain': '🌧️', + 'Snow': '❄️', 'Thunderstorm': '⛈️' +} %} +
+ + {% if page.header.location_city or page.header.location_country %} +

+ 📍 + {% if page.header.location_city %}{{ page.header.location_city }}{% endif %} + {% if page.header.location_city and page.header.location_country %}, {% endif %} + {% if page.header.location_country %}{{ page.header.location_country }}{% endif %} +

+ {% endif %} + + {% if page.header.weather_desc or page.header.weather_temp_c %} +

+ {% 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 %} +

+ {% endif %} +

{{ page.title }}

+
{{ page.content }}
+ + {% set images = page.media.images %} + {% if images|length > 0 %} +
+ {% for image in images %} + + {% endfor %} +
+ + + + + {% endif %} + diff --git a/themes/intotheeast/templates/post-form.html.twig b/themes/intotheeast/templates/post-form.html.twig index 950ca4e..5f5df6c 100644 --- a/themes/intotheeast/templates/post-form.html.twig +++ b/themes/intotheeast/templates/post-form.html.twig @@ -4,11 +4,29 @@

{{ page.title }}

{% include 'forms/form.html.twig' ignore missing %} - -

+ +
+ + +
+

+

{% endblock %} diff --git a/themes/intotheeast/templates/tracker.html.twig b/themes/intotheeast/templates/tracker.html.twig index 84fced8..0ef7e00 100644 --- a/themes/intotheeast/templates/tracker.html.twig +++ b/themes/intotheeast/templates/tracker.html.twig @@ -6,17 +6,39 @@ {% if entries|length > 0 %} {% for entry in entries %}
- + {% set hero = null %} + {% if entry.header.hero_image and entry.media[entry.header.hero_image] is defined %} + {% set hero = entry.media[entry.header.hero_image] %} + {% elseif entry.media.images|length > 0 %} + {% set hero = entry.media.images|first %} + {% endif %} + + {% if hero %} +
+ + {{ entry.title }} + +
+ {% endif %} + +
+ + {% if entry.header.location_city or entry.header.location_country %} + + 📍 + {% if entry.header.location_city %}{{ entry.header.location_city|slice(0,25) }}{% endif %} + {% if entry.header.location_city and entry.header.location_country %}, {% endif %} + {% if entry.header.location_country %}{{ entry.header.location_country }}{% endif %} + + {% endif %} +
+

{{ entry.title }}

- {% if entry.header.hero_image %} -
- {{ entry.title }} -
- {% endif %} +
{{ entry.summary }}