This commit is contained in:
parent
c0382827ea
commit
ff6c9dc91a
1222
package-lock.json
generated
1222
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -54,6 +54,7 @@
|
||||
"react-day-picker": "^8.10.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-hook-form": "^7.53.0",
|
||||
"react-markdown": "^10.1.0",
|
||||
"react-resizable-panels": "^2.1.3",
|
||||
"react-responsive-carousel": "^3.2.23",
|
||||
"react-router-dom": "^6.30.0",
|
||||
@ -66,7 +67,8 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.9.0",
|
||||
"@tailwindcss/typography": "^0.5.15",
|
||||
"@tailwindcss/line-clamp": "^0.4.4",
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
"@types/node": "^22.5.5",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
|
||||
@ -184,7 +184,7 @@ const NewsManager = () => {
|
||||
{uploading && <p className="text-sm text-gray-400">Bild wird hochgeladen...</p>}
|
||||
{newImageUrl && (
|
||||
<img
|
||||
src={newImageUrl}
|
||||
src={`${apiBase}${newImageUrl}`}
|
||||
alt="Vorschau"
|
||||
className="mt-2 max-h-40 rounded-md shadow-md"
|
||||
/>
|
||||
@ -238,7 +238,7 @@ const NewsManager = () => {
|
||||
<p className="text-gray-600 mb-2">{item.description}</p>
|
||||
{item.image_url && (
|
||||
<img
|
||||
src={item.image_url}
|
||||
src={`${apiBase}${item.image_url}`}
|
||||
alt={item.title}
|
||||
className="w-full rounded-md my-2 max-h-40 object-cover"
|
||||
/>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
|
||||
const apiBase = import.meta.env.VITE_API_URL;
|
||||
|
||||
@ -14,6 +15,8 @@ type NewsItem = {
|
||||
|
||||
const AlleNeuigkeitenPage = () => {
|
||||
const [news, setNews] = useState<NewsItem[]>([]);
|
||||
const [expandedIds, setExpandedIds] = useState<number[]>([]);
|
||||
const [activeCardId, setActiveCardId] = useState<number | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
fetch(`${apiBase}/api/news`)
|
||||
@ -22,6 +25,12 @@ const AlleNeuigkeitenPage = () => {
|
||||
.catch((err) => console.error("Fehler beim Laden der News:", err));
|
||||
}, []);
|
||||
|
||||
|
||||
const toggleCard = (id: number) => {
|
||||
setActiveCardId((prev) => (prev === id ? null : id));
|
||||
};
|
||||
|
||||
|
||||
// Gruppieren nach Jahren
|
||||
const groupedNews = news.reduce((acc: Record<string, NewsItem[]>, item) => {
|
||||
const year = new Date(item.created_at).getFullYear().toString();
|
||||
@ -30,6 +39,13 @@ const AlleNeuigkeitenPage = () => {
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
//Toggle der Cards
|
||||
const toggleExpand = (id: number) => {
|
||||
setExpandedIds((prev) =>
|
||||
prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id]
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="max-w-5xl mx-auto px-4 py-12">
|
||||
<h1 className="text-3xl font-bold text-center mb-8 text-frog-600">Alle Neuigkeiten</h1>
|
||||
@ -40,20 +56,43 @@ const AlleNeuigkeitenPage = () => {
|
||||
<h2 className="text-2xl font-bold text-frog-500 mb-4">{year}</h2>
|
||||
<div className="grid md:grid-cols-2 gap-6">
|
||||
{items.map((item) => (
|
||||
<Card key={item.id} className="overflow-hidden">
|
||||
<Card
|
||||
key={item.id}
|
||||
className={`overflow-hidden transition-all duration-500 ease-in-out ${
|
||||
activeCardId === item.id
|
||||
? "col-span-2 lg:col-span-2 xl:col-span-2 scale-[1.02] shadow-xl"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
<div className="h-48 overflow-hidden">
|
||||
<img
|
||||
src={item.image_url || "https://via.placeholder.com/400x300?text=Kein+Bild"}
|
||||
alt={item.title}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
<img
|
||||
src={
|
||||
item.image_url
|
||||
? `${apiBase}${item.image_url}`
|
||||
: "https://via.placeholder.com/400x300?text=Kein+Bild"
|
||||
}
|
||||
alt={item.title}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
<CardHeader>
|
||||
<CardTitle>{item.title}</CardTitle>
|
||||
<CardDescription>{new Date(item.created_at).toLocaleDateString("de-DE")}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p>{item.description}</p>
|
||||
<div
|
||||
className={`prose max-w-none text-gray-700 transition-all duration-300 prose-p:my-1 prose-a:text-frog-600 ${
|
||||
activeCardId === item.id ? "" : "line-clamp-3 overflow-hidden"
|
||||
}`}
|
||||
>
|
||||
<ReactMarkdown>{item.description}</ReactMarkdown>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => toggleCard(item.id)}
|
||||
className="mt-2 text-frog-600 text-sm font-medium hover:underline"
|
||||
>
|
||||
{activeCardId === item.id ? "Weniger anzeigen" : "Weiterlesen"}
|
||||
</button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
|
||||
@ -111,5 +111,8 @@ export default {
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [require("tailwindcss-animate")],
|
||||
plugins: [
|
||||
require("tailwindcss-animate"),
|
||||
require("@tailwindcss/typography"),
|
||||
],
|
||||
} satisfies Config;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user