{
  "sha": "10eafb38be69447d39ea888df819e4b694e41ced",
  "message": "feat: show article thumbnails in the all-news index (#319)",
  "author": {
    "login": "nnneeeooo-nnneeeooo",
    "name": "",
    "email": ""
  },
  "committer": {
    "login": "web-flow",
    "name": "",
    "email": ""
  },
  "created_at": "2026-10-18T15:47:42Z",
  "files": [
    {
      "filename": "static/app.js",
      "previous_filename": "",
      "status": "modified",
      "additions": 13,
      "deletions": 0,
      "changes": 13
    },
    {
      "filename": "static/site.css",
      "previous_filename": "",
      "status": "modified",
      "additions": 25,
      "deletions": 1,
      "changes": 26
    },
    {
      "filename": "templates/news_index.html",
      "previous_filename": "",
      "status": "modified",
      "additions": 11,
      "deletions": 1,
      "changes": 12
    }
  ],
  "diff": "@@ -3,6 +3,19 @@\\n (function () {\\n   \"use strict\";\\n \\n+  document.querySelectorAll(\".news-thumbnail img[data-fallback]\").forEach(function (image) {\\n+    function useFallback() {\\n+      if (image.dataset.fallbackTried === \"true\") return;\\n+      image.dataset.fallbackTried = \"true\";\\n+      image.alt = \"SKYTICAL\";\\n+      var credit = image.parentElement.querySelector(\".news-image-credit\");\\n+      if (credit) credit.hidden = true;\\n+      image.src = image.dataset.fallback;\\n+    }\\n+    image.addEventListener(\"error\", useFallback);\\n+    if (image.complete && image.naturalWidth === 0) useFallback();\\n+  });\\n+\\n   /* — UTC + TPE clocks, updated every 10 s (per the design) — */\\n   var utcEl = document.getElementById(\"clock-utc\");\\n   var tpeEl = document.getElementById(\"clock-tpe\");\\n@@ -621,7 +621,23 @@ a.flash-row:hover .flash-text { color: var(--color-accent); }\\n }\\n .search-result-footer a { flex-shrink: 0; font-weight: 700; }\\n \\n-/* — static news-index pagination — */\\n+/* — illustrated news index and pagination — */\\n+.feed-row--illustrated {\\n+  grid-template-columns: 144px 48px 84px minmax(0, 1fr) auto;\\n+  grid-template-areas:\\n+    \"thumbnail time category copy source\"\\n+    \"thumbnail . . summary summary\";\\n+}\\n+.news-thumbnail { grid-area: thumbnail; min-width: 0; }\\n+.news-thumbnail img {\\n+  display: block; width: 100%; height: auto; aspect-ratio: 16 / 9;\\n+  object-fit: cover; border-radius: 6px; background: var(--color-surface);\\n+}\\n+.news-image-credit {\\n+  display: block; margin-top: 4px; font-size: 10px; line-height: 1.4;\\n+  color: color-mix(in srgb, var(--color-text) 58%, transparent); overflow-wrap: anywhere;\\n+}\\n+.news-image-credit[hidden] { display: none; }\\n .news-pagination {\\n   display: flex; align-items: center; justify-content: center; gap: 14px;\\n   flex-wrap: wrap; margin-top: 24px; padding-top: 18px;\\n@@ -754,6 +770,14 @@ a.flash-row:hover .flash-text { color: var(--color-accent); }\\n     gap: 7px 10px; padding: 15px 0;\\n   }\\n   .feed-category { justify-self: start; }\\n+  .feed-row--illustrated {\\n+    grid-template-columns: 96px auto minmax(0, 1fr);\\n+    grid-template-areas:\\n+      \"thumbnail time category\"\\n+      \"thumbnail copy copy\"\\n+      \"thumbnail summary summary\"\\n+      \". source source\";\\n+  }\\n   .feed-source { justify-self: start; white-space: normal; }\\n   .summary-preview--feed { margin-top: 0; }\\n   .article-page { padding: 20px 12px 44px; }\\n@@ -14,7 +14,17 @@ <h1>{{ t.newsTitle }}</h1>\\n     </header>\\n     <section aria-label=\"{{ t.newsTitle }}\">\\n       {% for item in articles %}\\n-      <a class=\"feed-row\" href=\"{{ item.url }}\">\\n+      {% set fallback = base ~ '/assets/skytical-social.png?v=' ~ asset_version %}\\n+      <a class=\"feed-row feed-row--illustrated\" href=\"{{ item.url }}\">\\n+        <span class=\"news-thumbnail\">\\n+          <img src=\"{{ item.image.url if item.image else fallback }}\"\\n+               alt=\"{{ (item.image.subject or item.title) if item.image else 'SKYTICAL' }}\"\\n+               width=\"160\" height=\"90\" loading=\"lazy\" decoding=\"async\"\\n+               data-fallback=\"{{ fallback }}\">\\n+          {% if item.image and (item.image.credit or item.image.license) %}\\n+          <span class=\"news-image-credit\">{% if item.image.credit %}© {{ item.image.credit }}{% endif %}{% if item.image.credit and item.image.license %} · {% endif %}{{ item.image.license or '' }}</span>\\n+          {% endif %}\\n+        </span>\\n         <span class=\"feed-time\">{{ item.time }}</span>\\n         <span class=\"feed-category tag {{ item.tag_class }}\">{{ item.cat_label }}{% if item.article_format == \"brief\" %} · {{ t.briefLabel }}{% elif item.article_format == \"roundup\" %} · {{ t.roundupLabel }}{% endif %}</span>\\n         <span class=\"feed-copy\">"
}
