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-day-picker": "^8.10.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-hook-form": "^7.53.0",
|
"react-hook-form": "^7.53.0",
|
||||||
|
"react-markdown": "^10.1.0",
|
||||||
"react-resizable-panels": "^2.1.3",
|
"react-resizable-panels": "^2.1.3",
|
||||||
"react-responsive-carousel": "^3.2.23",
|
"react-responsive-carousel": "^3.2.23",
|
||||||
"react-router-dom": "^6.30.0",
|
"react-router-dom": "^6.30.0",
|
||||||
@ -66,7 +67,8 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.9.0",
|
"@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/node": "^22.5.5",
|
||||||
"@types/react": "^18.3.3",
|
"@types/react": "^18.3.3",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "^18.3.0",
|
||||||
|
|||||||
@ -184,7 +184,7 @@ const NewsManager = () => {
|
|||||||
{uploading && <p className="text-sm text-gray-400">Bild wird hochgeladen...</p>}
|
{uploading && <p className="text-sm text-gray-400">Bild wird hochgeladen...</p>}
|
||||||
{newImageUrl && (
|
{newImageUrl && (
|
||||||
<img
|
<img
|
||||||
src={newImageUrl}
|
src={`${apiBase}${newImageUrl}`}
|
||||||
alt="Vorschau"
|
alt="Vorschau"
|
||||||
className="mt-2 max-h-40 rounded-md shadow-md"
|
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>
|
<p className="text-gray-600 mb-2">{item.description}</p>
|
||||||
{item.image_url && (
|
{item.image_url && (
|
||||||
<img
|
<img
|
||||||
src={item.image_url}
|
src={`${apiBase}${item.image_url}`}
|
||||||
alt={item.title}
|
alt={item.title}
|
||||||
className="w-full rounded-md my-2 max-h-40 object-cover"
|
className="w-full rounded-md my-2 max-h-40 object-cover"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
|
import ReactMarkdown from "react-markdown";
|
||||||
|
|
||||||
const apiBase = import.meta.env.VITE_API_URL;
|
const apiBase = import.meta.env.VITE_API_URL;
|
||||||
|
|
||||||
@ -14,6 +15,8 @@ type NewsItem = {
|
|||||||
|
|
||||||
const AlleNeuigkeitenPage = () => {
|
const AlleNeuigkeitenPage = () => {
|
||||||
const [news, setNews] = useState<NewsItem[]>([]);
|
const [news, setNews] = useState<NewsItem[]>([]);
|
||||||
|
const [expandedIds, setExpandedIds] = useState<number[]>([]);
|
||||||
|
const [activeCardId, setActiveCardId] = useState<number | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetch(`${apiBase}/api/news`)
|
fetch(`${apiBase}/api/news`)
|
||||||
@ -22,6 +25,12 @@ const AlleNeuigkeitenPage = () => {
|
|||||||
.catch((err) => console.error("Fehler beim Laden der News:", err));
|
.catch((err) => console.error("Fehler beim Laden der News:", err));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
|
const toggleCard = (id: number) => {
|
||||||
|
setActiveCardId((prev) => (prev === id ? null : id));
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// Gruppieren nach Jahren
|
// Gruppieren nach Jahren
|
||||||
const groupedNews = news.reduce((acc: Record<string, NewsItem[]>, item) => {
|
const groupedNews = news.reduce((acc: Record<string, NewsItem[]>, item) => {
|
||||||
const year = new Date(item.created_at).getFullYear().toString();
|
const year = new Date(item.created_at).getFullYear().toString();
|
||||||
@ -30,6 +39,13 @@ const AlleNeuigkeitenPage = () => {
|
|||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
|
//Toggle der Cards
|
||||||
|
const toggleExpand = (id: number) => {
|
||||||
|
setExpandedIds((prev) =>
|
||||||
|
prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-5xl mx-auto px-4 py-12">
|
<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>
|
<h1 className="text-3xl font-bold text-center mb-8 text-frog-600">Alle Neuigkeiten</h1>
|
||||||
@ -40,10 +56,21 @@ const AlleNeuigkeitenPage = () => {
|
|||||||
<h2 className="text-2xl font-bold text-frog-500 mb-4">{year}</h2>
|
<h2 className="text-2xl font-bold text-frog-500 mb-4">{year}</h2>
|
||||||
<div className="grid md:grid-cols-2 gap-6">
|
<div className="grid md:grid-cols-2 gap-6">
|
||||||
{items.map((item) => (
|
{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">
|
<div className="h-48 overflow-hidden">
|
||||||
<img
|
<img
|
||||||
src={item.image_url || "https://via.placeholder.com/400x300?text=Kein+Bild"}
|
src={
|
||||||
|
item.image_url
|
||||||
|
? `${apiBase}${item.image_url}`
|
||||||
|
: "https://via.placeholder.com/400x300?text=Kein+Bild"
|
||||||
|
}
|
||||||
alt={item.title}
|
alt={item.title}
|
||||||
className="w-full h-full object-cover"
|
className="w-full h-full object-cover"
|
||||||
/>
|
/>
|
||||||
@ -53,7 +80,19 @@ const AlleNeuigkeitenPage = () => {
|
|||||||
<CardDescription>{new Date(item.created_at).toLocaleDateString("de-DE")}</CardDescription>
|
<CardDescription>{new Date(item.created_at).toLocaleDateString("de-DE")}</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<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>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@ -111,5 +111,8 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [require("tailwindcss-animate")],
|
plugins: [
|
||||||
|
require("tailwindcss-animate"),
|
||||||
|
require("@tailwindcss/typography"),
|
||||||
|
],
|
||||||
} satisfies Config;
|
} satisfies Config;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user