diff --git a/web/src/App.tsx b/web/src/App.tsx
index 90fc47a..28cc786 100644
--- a/web/src/App.tsx
+++ b/web/src/App.tsx
@@ -5,28 +5,26 @@ import { useAuthStore } from './stores/authStore';
import { authApi } from './api/auth';
import { LoginPage } from './pages/LoginPage';
import { RegisterPage } from './pages/RegisterPage';
-import { DashboardPage } from './pages/DashboardPage';
+import { RootLayout } from './layouts/RootLayout';
import { ProtectedRoute } from './components/ProtectedRoute';
-import './App.css';
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: 1,
- staleTime: 5 * 60 * 1000, // 5 minutes
+ staleTime: 5 * 60 * 1000,
},
},
});
function AuthChecker({ children }: { children: React.ReactNode }) {
- const { setUser, setLoading } = useAuthStore();
+ const setUser = useAuthStore((state) => state.setUser);
useEffect(() => {
- // Check if user is authenticated on app load
authApi.getMe()
.then((user) => setUser(user))
.catch(() => setUser(null));
- }, [setUser, setLoading]);
+ }, [setUser]);
return <>{children}>;
}
@@ -40,7 +38,7 @@ function App() {
} />
} />
}>
- } />
+ } />
} />
diff --git a/web/src/components/AddFeedModal.tsx b/web/src/components/AddFeedModal.tsx
new file mode 100644
index 0000000..618e88b
--- /dev/null
+++ b/web/src/components/AddFeedModal.tsx
@@ -0,0 +1,87 @@
+import { useState } from 'react';
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { feedsApi } from '../api/feeds';
+
+interface AddFeedModalProps {
+ isOpen: boolean;
+ onClose: () => void;
+}
+
+export function AddFeedModal({ isOpen, onClose }: AddFeedModalProps) {
+ const [url, setUrl] = useState('');
+ const queryClient = useQueryClient();
+
+ const addFeedMutation = useMutation({
+ mutationFn: (url: string) => feedsApi.add({ url }),
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: ['feeds'] });
+ setUrl('');
+ onClose();
+ },
+ });
+
+ if (!isOpen) return null;
+
+ const handleSubmit = (e: React.FormEvent) => {
+ e.preventDefault();
+ addFeedMutation.mutate(url);
+ };
+
+ return (
+
+
e.stopPropagation()}
+ >
+
+
Nouveau Flux
+
+
+
+
+ Entrez l'URL d'un flux RSS ou Atom. FlowReader récupérera automatiquement le titre et le contenu.
+
+
+
+
+
+ );
+}
diff --git a/web/src/components/ArticleCard.tsx b/web/src/components/ArticleCard.tsx
index 59721b2..cda29e0 100644
--- a/web/src/components/ArticleCard.tsx
+++ b/web/src/components/ArticleCard.tsx
@@ -8,63 +8,67 @@ interface ArticleCardProps {
}
export function ArticleCard({ article, onClick, onToggleRead, onToggleFavorite }: ArticleCardProps) {
- // Simulate a "reading time" based on typical RSS snippet length
- const readTime = Math.max(1, Math.ceil((article.content?.length || 500) / 1000));
+ const timeToRead = Math.ceil((article.content?.length || 500) / 1000) + 1;
return (
- onClick(article)}
- >
-
- {/* Fallback pattern for articles without images */}
-
-
- F
-
+
onClick(article)}>
+ {/* Image Placeholder with Gold Overlay */}
+
+
- {!article.is_read && (
-
- )}
+ {/* Visual placeholder */}
+
+
+ {/* Meta on top of image */}
+
+
+ {article.feed_title || 'Journal'}
+
+
+ {timeToRead} min
+
+
-
-
-
- {article.feed_title || 'Source'}
-
-
- {readTime} MIN READ
-
-
-
-
+ {/* Content */}
+
+
{article.title}
-
-
+ {article.summary && (
+
+ {article.summary.replace(/<[^>]*>?/gm, '').substring(0, 160)}...
+
+ )}
-
+
+
+
+
+
diff --git a/web/src/components/Sidebar.tsx b/web/src/components/Sidebar.tsx
index 86b70a1..ac9caba 100644
--- a/web/src/components/Sidebar.tsx
+++ b/web/src/components/Sidebar.tsx
@@ -1,5 +1,7 @@
+import { useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import { feedsApi } from '../api/feeds';
+import { AddFeedModal } from './AddFeedModal';
interface SidebarProps {
onSelectFeed: (feedId: string | null) => void;
@@ -7,77 +9,80 @@ interface SidebarProps {
}
export function Sidebar({ onSelectFeed, selectedFeedId }: SidebarProps) {
+ const [isAddModalOpen, setIsAddModalOpen] = useState(false);
const { data: feeds } = useQuery({
queryKey: ['feeds'],
queryFn: () => feedsApi.list(),
});
return (
-