From 081420ceb87e394d00754d33c57782380d5568cd Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 9 Oct 2026 07:21:02 +0000 Subject: [PATCH] fix(web): show feed images again, widen the grid, soften covers - Drop the service worker's image cache: its cross-origin fetch() is bound by the CSP's connect-src 'self', so every cover failed and fell back to the green placeholder (in the grid and the reader). - Grid fills the width with as many ~20rem columns as fit (max 2400px), now that the sidebar is gone. - Covers fade in once loaded and get a light bottom shade. - Placeholder cover shows a centered initial instead of the feed name that overlapped the feed chip. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01NsXUyMEGFFGVRcHNVfcBLh --- web/src/components/ArticleCard.tsx | 11 ++++++++--- web/src/components/TopBar.tsx | 2 +- web/src/index.css | 7 +++++++ web/src/pages/DashboardPage.tsx | 6 +++--- web/vite.config.ts | 12 +++--------- 5 files changed, 22 insertions(+), 16 deletions(-) diff --git a/web/src/components/ArticleCard.tsx b/web/src/components/ArticleCard.tsx index 2c3ffa9..8087677 100644 --- a/web/src/components/ArticleCard.tsx +++ b/web/src/components/ArticleCard.tsx @@ -15,9 +15,10 @@ interface ArticleCardProps { /** Initial-letter cover used when a feed provides no image (no third-party fallback). */ function CoverFallback({ title, feed }: { title: string; feed?: string }) { + const initial = (feed || title).trim().charAt(0).toUpperCase(); return ( -
- {feed || title} + ); } @@ -25,6 +26,7 @@ function CoverFallback({ title, feed }: { title: string; feed?: string }) { function ArticleCardImpl({ article, index, isCurrent, onOpen, onToggleRead, onToggleFavorite }: ArticleCardProps) { const [offset, setOffset] = useState(0); const [imgFailed, setImgFailed] = useState(false); + const [imgLoaded, setImgLoaded] = useState(false); // Touch-only swipe: right = read/unread, left = favorite. Mouse drags (text // selection) never trigger it. @@ -80,12 +82,15 @@ function ArticleCardImpl({ article, index, isCurrent, onOpen, onToggleRead, onTo referrerPolicy="no-referrer" width={640} height={360} - className="w-full h-full object-cover transition-transform duration-700 group-hover:scale-[1.03]" + className={`w-full h-full object-cover transition-[transform,opacity] duration-700 group-hover:scale-[1.03] ${imgLoaded ? 'opacity-100' : 'opacity-0'}`} + onLoad={() => setImgLoaded(true)} onError={() => setImgFailed(true)} /> ) : ( )} + {/* Light bottom shade: gives the cover depth and lifts the feed chip. */} +