Răsfoiți Sursa

Ajouter page changelog et data

Implémente la page /changelog en créant src/data/changelog.ts et src/pages/Changelog.tsx, en ajoutant la route et le lien Header, et en mettre à jour le sitemap.xml. Integrations incluent SEO, affichage des versions, et données typées.
gpt-engineer-app[bot] 3 săptămâni în urmă
părinte
comite
ae3829b7ec
5 a modificat fișierele cu 233 adăugiri și 1 ștergeri
  1. 6 0
      public/sitemap.xml
  2. 2 0
      src/App.tsx
  3. 8 1
      src/components/Header.tsx
  4. 66 0
      src/data/changelog.ts
  5. 151 0
      src/pages/Changelog.tsx

+ 6 - 0
public/sitemap.xml

@@ -24,4 +24,10 @@
     <changefreq>monthly</changefreq>
     <priority>0.5</priority>
   </url>
+  <url>
+    <loc>https://feeds.duhaz.fr/changelog</loc>
+    <lastmod>2025-01-20</lastmod>
+    <changefreq>weekly</changefreq>
+    <priority>0.6</priority>
+  </url>
 </urlset>

+ 2 - 0
src/App.tsx

@@ -10,6 +10,7 @@ import FeedDetail from "./pages/FeedDetail";
 import NotFound from "./pages/NotFound";
 import Auth from "./pages/Auth";
 import Gone from "./pages/Gone";
+import Changelog from "./pages/Changelog";
 import LegacyRedirect from "./components/LegacyRedirect";
 
 const queryClient = new QueryClient();
@@ -26,6 +27,7 @@ const App = () => (
           <Route path="/pinned" element={<Pinned />} />
           <Route path="/feed/:feedId" element={<FeedDetail />} />
           <Route path="/auth" element={<Auth />} />
+          <Route path="/changelog" element={<Changelog />} />
           <Route path="/gone" element={<Gone />} />
           
           {/* Legacy URL redirects */}

+ 8 - 1
src/components/Header.tsx

@@ -1,7 +1,7 @@
 import { Button } from '@/components/ui/button';
 import { Input } from '@/components/ui/input';
 import { Badge } from '@/components/ui/badge';
-import { Search, Plus, Settings, User, Rss, List, LogOut, Shield, Pin } from 'lucide-react';
+import { Search, Plus, Settings, User, Rss, List, LogOut, Shield, Pin, FileText } from 'lucide-react';
 import { Link } from 'react-router-dom';
 import { useAuth } from '@/hooks/useAuth';
 import { useSuperUser } from '@/hooks/useSuperUser';
@@ -48,6 +48,13 @@ const Header = ({
               <Input placeholder="Rechercher..." value={searchQuery} onChange={e => onSearchChange(e.target.value)} className="pl-10 w-64" />
             </div>
             
+            <Link to="/changelog">
+              <Button variant="ghost" size="sm" className="gap-2">
+                <FileText className="h-4 w-4" />
+                <span className="hidden sm:inline">Changelog</span>
+              </Button>
+            </Link>
+
             {user ? <>
                 <Link to="/pinned">
                   <Button variant="outline" size="sm" className="gap-2">

+ 66 - 0
src/data/changelog.ts

@@ -0,0 +1,66 @@
+export interface ChangelogEntry {
+  version: string;
+  date: string; // Format ISO: "2025-01-20"
+  category: 'feature' | 'improvement' | 'bugfix' | 'security';
+  title: string;
+  description: string;
+  details?: string[];
+}
+
+export const changelogData: ChangelogEntry[] = [
+  {
+    version: "1.3.0",
+    date: "2025-01-20",
+    category: "feature",
+    title: "Détection automatique de flux RSS",
+    description: "Ajout d'une fonctionnalité pour détecter automatiquement les flux RSS d'un site web lors de l'ajout d'un nouveau flux.",
+    details: [
+      "Détection automatique des flux RSS/Atom",
+      "Support de plusieurs flux sur un même site",
+      "Pré-remplissage automatique du nom du site",
+      "Gestion des erreurs avec messages informatifs"
+    ]
+  },
+  {
+    version: "1.2.0",
+    date: "2025-01-19",
+    category: "improvement",
+    title: "Pages 410 Gone pour anciennes URLs",
+    description: "Mise en place de redirections intelligentes et pages 410 pour améliorer le SEO et gérer les anciennes URLs indexées.",
+    details: [
+      "Redirections 301 pour /flux/youtube-* vers /feeds",
+      "Redirections 301 pour /account/* vers /auth",
+      "Page 410 Gone pour les contenus définitivement supprimés",
+      "Mise à jour du robots.txt"
+    ]
+  },
+  {
+    version: "1.1.0",
+    date: "2025-01-15",
+    category: "improvement",
+    title: "Amélioration des notifications par email",
+    description: "Configuration du domaine notifications.duhaz.fr pour l'envoi d'emails de purge.",
+    details: [
+      "Domaine personnalisé pour les emails",
+      "Amélioration de la délivrabilité",
+      "Templates d'emails optimisés"
+    ]
+  },
+  {
+    version: "1.0.0",
+    date: "2025-01-10",
+    category: "feature",
+    title: "Lancement de Feeds.Duhaz.fr",
+    description: "Première version publique du site avec toutes les fonctionnalités de base.",
+    details: [
+      "Gestion complète des flux RSS et Atom",
+      "Détection automatique des chaînes YouTube",
+      "Système d'épinglage d'articles",
+      "Filtres par catégorie et date",
+      "Authentification utilisateur sécurisée",
+      "Mode lecture avec articles lus/non lus",
+      "Interface responsive et moderne",
+      "Support du dark mode"
+    ]
+  }
+];

+ 151 - 0
src/pages/Changelog.tsx

@@ -0,0 +1,151 @@
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
+import { Badge } from "@/components/ui/badge";
+import { Separator } from "@/components/ui/separator";
+import { ScrollArea } from "@/components/ui/scroll-area";
+import { Sparkles, TrendingUp, Bug, Shield } from "lucide-react";
+import { changelogData, ChangelogEntry } from "@/data/changelog";
+import { SEO } from "@/components/SEO";
+import { format, parseISO } from "date-fns";
+import { fr } from "date-fns/locale";
+
+const getCategoryConfig = (category: ChangelogEntry['category']) => {
+  const configs = {
+    feature: {
+      icon: Sparkles,
+      label: "Nouvelle fonctionnalité",
+      variant: "default" as const,
+      color: "text-primary"
+    },
+    improvement: {
+      icon: TrendingUp,
+      label: "Amélioration",
+      variant: "secondary" as const,
+      color: "text-green-600 dark:text-green-400"
+    },
+    bugfix: {
+      icon: Bug,
+      label: "Correction de bug",
+      variant: "outline" as const,
+      color: "text-orange-600 dark:text-orange-400"
+    },
+    security: {
+      icon: Shield,
+      label: "Sécurité",
+      variant: "destructive" as const,
+      color: "text-destructive"
+    }
+  };
+  return configs[category];
+};
+
+const Changelog = () => {
+  const sortedChangelog = [...changelogData].sort((a, b) => 
+    new Date(b.date).getTime() - new Date(a.date).getTime()
+  );
+
+  const latestUpdate = sortedChangelog[0]?.date;
+
+  return (
+    <>
+      <SEO 
+        title="Changelog - Historique des évolutions"
+        description="Découvrez toutes les évolutions, nouvelles fonctionnalités et améliorations de Feeds.Duhaz.fr. Historique complet des mises à jour."
+        keywords="changelog, mises à jour, évolutions, nouveautés, historique, versions"
+      />
+      
+      <div className="min-h-screen bg-background">
+        <div className="container mx-auto px-4 py-8 max-w-4xl">
+          {/* Header */}
+          <div className="mb-8">
+            <div className="flex items-center gap-3 mb-4">
+              <div className="h-12 w-12 rounded-lg bg-primary/10 flex items-center justify-center">
+                <Sparkles className="h-6 w-6 text-primary" />
+              </div>
+              <div>
+                <h1 className="text-3xl font-bold">Changelog</h1>
+                <p className="text-muted-foreground">
+                  Historique des évolutions du site
+                </p>
+              </div>
+            </div>
+            
+            <div className="flex items-center gap-4 text-sm text-muted-foreground">
+              <span>{sortedChangelog.length} versions</span>
+              <Separator orientation="vertical" className="h-4" />
+              <span>
+                Dernière mise à jour : {latestUpdate && format(parseISO(latestUpdate), "d MMMM yyyy", { locale: fr })}
+              </span>
+            </div>
+          </div>
+
+          {/* Timeline */}
+          <ScrollArea className="h-[calc(100vh-250px)]">
+            <div className="space-y-6">
+              {sortedChangelog.map((entry, index) => {
+                const config = getCategoryConfig(entry.category);
+                const Icon = config.icon;
+                
+                return (
+                  <div key={`${entry.version}-${entry.date}`}>
+                    <Card>
+                      <CardHeader>
+                        <div className="flex items-start justify-between gap-4">
+                          <div className="flex items-center gap-3">
+                            <div className={`h-10 w-10 rounded-lg bg-card border flex items-center justify-center ${config.color}`}>
+                              <Icon className="h-5 w-5" />
+                            </div>
+                            <div>
+                              <div className="flex items-center gap-2 mb-1">
+                                <CardTitle className="text-xl">
+                                  {entry.title}
+                                </CardTitle>
+                              </div>
+                              <div className="flex items-center gap-2 flex-wrap">
+                                <Badge variant={config.variant} className="gap-1">
+                                  <Icon className="h-3 w-3" />
+                                  {config.label}
+                                </Badge>
+                                <Badge variant="outline">v{entry.version}</Badge>
+                                <span className="text-sm text-muted-foreground">
+                                  {format(parseISO(entry.date), "d MMMM yyyy", { locale: fr })}
+                                </span>
+                              </div>
+                            </div>
+                          </div>
+                        </div>
+                        <CardDescription className="mt-3">
+                          {entry.description}
+                        </CardDescription>
+                      </CardHeader>
+                      
+                      {entry.details && entry.details.length > 0 && (
+                        <CardContent>
+                          <ul className="space-y-2">
+                            {entry.details.map((detail, idx) => (
+                              <li key={idx} className="flex items-start gap-2 text-sm">
+                                <span className="text-primary mt-1">•</span>
+                                <span className="text-muted-foreground">{detail}</span>
+                              </li>
+                            ))}
+                          </ul>
+                        </CardContent>
+                      )}
+                    </Card>
+                    
+                    {index < sortedChangelog.length - 1 && (
+                      <div className="flex justify-center my-4">
+                        <Separator className="w-[2px] h-6" orientation="vertical" />
+                      </div>
+                    )}
+                  </div>
+                );
+              })}
+            </div>
+          </ScrollArea>
+        </div>
+      </div>
+    </>
+  );
+};
+
+export default Changelog;