feat(ux): implement masonry dashboard layout and immersive focus mode

This commit is contained in:
Michael committed 2026-02-18 11:48:17 +01:00
1 parent 02c3c333cf
commit 908d907629
47 files changed
+1522 -365

No files matched your search

+1 -1
View File
@@ -66,7 +66,7 @@ export function MobileReaderView({ article, onClose, onToggleFavorite, onNext, o
</header>
<div
className="magazine-content text-paper-white/90 text-lg font-reading leading-relaxed space-y-6 selection:bg-nature/20 break-words overflow-x-hidden mb-12"
className="magazine-content text-paper-white/90 text-xl font-reading leading-loose space-y-6 selection:bg-nature/20 break-words overflow-x-hidden mb-12"
dangerouslySetInnerHTML={{ __html: displayContent }}
/>
+2 -2
View File
@@ -28,7 +28,7 @@ export function ReaderView({ article, onClose, onToggleFavorite }: ReaderViewPro
onClick={onClose}
>
<div
className="w-full max-w-4xl bg-carbon-light h-fit min-h-[50vh] my-12 shadow-[0_0_100px_rgba(0,0,0,0.8)] relative animate-in slide-in-from-bottom duration-700 rounded-3xl border border-white/5"
className="w-full max-w-4xl bg-carbon-light/95 h-fit min-h-[50vh] my-0 md:my-12 shadow-2xl relative animate-in slide-in-from-bottom duration-700 md:rounded-3xl border border-white/5 backdrop-blur-sm"
onClick={(e) => e.stopPropagation()}
>
@@ -108,7 +108,7 @@ export function ReaderView({ article, onClose, onToggleFavorite }: ReaderViewPro
</header>
<div
className="magazine-content text-paper-white/90 text-xl font-reading leading-relaxed space-y-8 selection:bg-nature/20 break-words overflow-x-hidden mb-12"
className="magazine-content max-w-2xl mx-auto text-paper-white/90 text-xl font-reading leading-loose space-y-8 selection:bg-nature/20 break-words overflow-x-hidden mb-12"
dangerouslySetInnerHTML={{ __html: displayContent }}
/>
+14 -3
View File
@@ -1,5 +1,6 @@
import { useState, useEffect, useRef } from 'react';
import { useInfiniteQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import Masonry from 'react-masonry-css';
import { articlesApi } from '../api/articles';
import { feedsApi } from '../api/feeds';
import { ArticleCard } from '../components/ArticleCard';
@@ -8,6 +9,12 @@ import { MobileReaderView } from '../components/MobileReaderView';
import { useWebsocket } from '../hooks/useWebsocket';
import type { Article } from '../api/articles';
const breakpointColumnsObj = {
default: 3,
1100: 2,
700: 1
};
interface DashboardPageProps {
selectedFeedId: string | null;
onEnterFocus: () => void;
@@ -279,9 +286,13 @@ export function DashboardPage({ selectedFeedId, onEnterFocus }: DashboardPagePro
{/* Grid */}
{articles.length > 0 ? (
<>
<div className="magazine-grid">
<Masonry
breakpointCols={breakpointColumnsObj}
className="flex w-auto -ml-6"
columnClassName="pl-6 bg-clip-padding"
>
{articles.map((article, index) => (
<div key={`${article.id}-${index}`} className={index % 6 === 0 ? 'md:col-span-2' : ''}>
<div key={`${article.id}-${index}`} className="mb-6">
<ArticleCard
article={article}
onClick={(article) => {
@@ -295,7 +306,7 @@ export function DashboardPage({ selectedFeedId, onEnterFocus }: DashboardPagePro
/>
</div>
))}
</div>
</Masonry>
{/* Infinite Scroll Sentinel */}
<div ref={loadMoreRef} className="mt-20 py-10 flex flex-col items-center justify-center space-y-4">