fix: cleanup book reviews HTML and improve about layout
Some checks failed
Dev Deployment (Zero Downtime) / deploy-dev (push) Has been cancelled
Some checks failed
Dev Deployment (Zero Downtime) / deploy-dev (push) Has been cancelled
Stripped HTML tags from book reviews, added a grid layout for About section on desktop, and fixed hobby icon mapping.
This commit is contained in:
@@ -26,6 +26,10 @@ export async function GET(request: NextRequest) {
|
|||||||
|
|
||||||
const reviews = await getBookReviews(locale);
|
const reviews = await getBookReviews(locale);
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
console.log(`[API] Book Reviews geladen für ${locale}:`, reviews?.length || 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (reviews && reviews.length > 0) {
|
if (reviews && reviews.length > 0) {
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
bookReviews: reviews,
|
bookReviews: reviews,
|
||||||
|
|||||||
@@ -160,7 +160,8 @@ const About = () => {
|
|||||||
Shield,
|
Shield,
|
||||||
Activity,
|
Activity,
|
||||||
Lightbulb,
|
Lightbulb,
|
||||||
Gamepad2
|
Gamepad2,
|
||||||
|
Gamepad
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fallback Hobbies
|
// Fallback Hobbies
|
||||||
@@ -296,7 +297,7 @@ const About = () => {
|
|||||||
>
|
>
|
||||||
{t("techStackTitle")}
|
{t("techStackTitle")}
|
||||||
</motion.h3>
|
</motion.h3>
|
||||||
<div className="grid grid-cols-1 gap-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
{techStack.map((stack, idx) => (
|
{techStack.map((stack, idx) => (
|
||||||
<motion.div
|
<motion.div
|
||||||
key={`${stack.category}-${idx}`}
|
key={`${stack.category}-${idx}`}
|
||||||
@@ -346,58 +347,58 @@ const About = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Hobbies */}
|
{/* Hobbies & Reading Grid */}
|
||||||
<div>
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||||
<motion.h3
|
{/* Hobbies Column */}
|
||||||
variants={fadeInUp}
|
<div className="space-y-6">
|
||||||
className="text-xl font-bold text-stone-900 mb-4"
|
<motion.h3
|
||||||
>
|
variants={fadeInUp}
|
||||||
{t("hobbiesTitle")}
|
className="text-xl font-bold text-stone-900 mb-4"
|
||||||
</motion.h3>
|
>
|
||||||
<div className="space-y-3">
|
{t("hobbiesTitle")}
|
||||||
{hobbies.map((hobby, idx) => (
|
</motion.h3>
|
||||||
<motion.div
|
<div className="space-y-3">
|
||||||
key={`hobby-${hobby.text}-${idx}`}
|
{hobbies.map((hobby, idx) => (
|
||||||
variants={fadeInUp}
|
<motion.div
|
||||||
whileHover={{
|
key={`hobby-${hobby.text}-${idx}`}
|
||||||
x: 8,
|
variants={fadeInUp}
|
||||||
scale: 1.02,
|
whileHover={{
|
||||||
transition: { duration: 0.4, ease: "easeOut" },
|
x: 8,
|
||||||
}}
|
scale: 1.02,
|
||||||
className={`flex items-center gap-3 p-4 rounded-xl border-2 transition-[background-color,border-color,box-shadow] duration-500 ease-out backdrop-blur-md ${
|
transition: { duration: 0.4, ease: "easeOut" },
|
||||||
idx === 0
|
}}
|
||||||
? "bg-gradient-to-r from-liquid-mint/25 to-liquid-sky/25 border-liquid-mint/50 hover:border-liquid-mint/70 hover:from-liquid-mint/35 hover:to-liquid-sky/35"
|
className={`flex items-center gap-3 p-4 rounded-xl border-2 transition-[background-color,border-color,box-shadow] duration-500 ease-out backdrop-blur-md ${
|
||||||
: idx === 1
|
idx === 0
|
||||||
? "bg-gradient-to-r from-liquid-coral/25 to-liquid-peach/25 border-liquid-coral/50 hover:border-liquid-coral/70 hover:from-liquid-coral/35 hover:to-liquid-peach/35"
|
? "bg-gradient-to-r from-liquid-mint/25 to-liquid-sky/25 border-liquid-mint/50 hover:border-liquid-mint/70 hover:from-liquid-mint/35 hover:to-liquid-sky/35"
|
||||||
: idx === 2
|
: idx === 1
|
||||||
? "bg-gradient-to-r from-liquid-lavender/25 to-liquid-pink/25 border-liquid-lavender/50 hover:border-liquid-lavender/70 hover:from-liquid-lavender/35 hover:to-liquid-pink/35"
|
? "bg-gradient-to-r from-liquid-coral/25 to-liquid-peach/25 border-liquid-coral/50 hover:border-liquid-coral/70 hover:from-liquid-coral/35 hover:to-liquid-peach/35"
|
||||||
: "bg-gradient-to-r from-liquid-lime/25 to-liquid-teal/25 border-liquid-lime/50 hover:border-liquid-lime/70 hover:from-liquid-lime/35 hover:to-liquid-teal/35"
|
: idx === 2
|
||||||
}`}
|
? "bg-gradient-to-r from-liquid-lavender/25 to-liquid-pink/25 border-liquid-lavender/50 hover:border-liquid-lavender/70 hover:from-liquid-lavender/35 hover:to-liquid-pink/35"
|
||||||
>
|
: "bg-gradient-to-r from-liquid-lime/25 to-liquid-teal/25 border-liquid-lime/50 hover:border-liquid-lime/70 hover:from-liquid-lime/35 hover:to-liquid-teal/35"
|
||||||
<hobby.icon size={20} className="text-stone-700" />
|
}`}
|
||||||
<span className="text-stone-800 font-semibold">
|
>
|
||||||
{String(hobby.text)}
|
<hobby.icon size={20} className="text-stone-700" />
|
||||||
</span>
|
<span className="text-stone-800 font-semibold">
|
||||||
</motion.div>
|
{String(hobby.text)}
|
||||||
))}
|
</span>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Reading Column */}
|
||||||
|
<div className="space-y-6">
|
||||||
|
{/* Currently Reading */}
|
||||||
|
<motion.div variants={fadeInUp}>
|
||||||
|
<CurrentlyReading />
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
{/* Read Books */}
|
||||||
|
<motion.div variants={fadeInUp}>
|
||||||
|
<ReadBooks />
|
||||||
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Currently Reading */}
|
|
||||||
<motion.div
|
|
||||||
variants={fadeInUp}
|
|
||||||
className="mt-8"
|
|
||||||
>
|
|
||||||
<CurrentlyReading />
|
|
||||||
</motion.div>
|
|
||||||
|
|
||||||
{/* Read Books with Ratings */}
|
|
||||||
<motion.div
|
|
||||||
variants={fadeInUp}
|
|
||||||
className="mt-6"
|
|
||||||
>
|
|
||||||
<ReadBooks />
|
|
||||||
</motion.div>
|
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -35,6 +35,12 @@ const StarRating = ({ rating }: { rating: number }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const stripHtml = (html: string) => {
|
||||||
|
if (typeof window === 'undefined') return html; // Fallback for SSR
|
||||||
|
const doc = new DOMParser().parseFromString(html, 'text/html');
|
||||||
|
return doc.body.textContent || "";
|
||||||
|
};
|
||||||
|
|
||||||
const ReadBooks = () => {
|
const ReadBooks = () => {
|
||||||
const locale = useLocale();
|
const locale = useLocale();
|
||||||
const t = useTranslations("home.about.readBooks");
|
const t = useTranslations("home.about.readBooks");
|
||||||
@@ -75,8 +81,12 @@ const ReadBooks = () => {
|
|||||||
fetchReviews();
|
fetchReviews();
|
||||||
}, [locale]);
|
}, [locale]);
|
||||||
|
|
||||||
if (loading || reviews.length === 0) {
|
if (loading) {
|
||||||
return null;
|
return <div className="text-stone-400 text-sm animate-pulse">Lade Buch-Bewertungen...</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reviews.length === 0) {
|
||||||
|
return null; // Hier kannst du temporär "Keine Bücher gefunden" reinschreiben zum Testen
|
||||||
}
|
}
|
||||||
|
|
||||||
const visibleReviews = expanded ? reviews : reviews.slice(0, INITIAL_SHOW);
|
const visibleReviews = expanded ? reviews : reviews.slice(0, INITIAL_SHOW);
|
||||||
@@ -169,7 +179,7 @@ const ReadBooks = () => {
|
|||||||
{/* Review Text (Optional) */}
|
{/* Review Text (Optional) */}
|
||||||
{review.review && (
|
{review.review && (
|
||||||
<p className="text-sm text-stone-700 dark:text-stone-300 leading-relaxed line-clamp-3 italic">
|
<p className="text-sm text-stone-700 dark:text-stone-300 leading-relaxed line-clamp-3 italic">
|
||||||
“{review.review}”
|
“{stripHtml(review.review)}”
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -444,7 +444,7 @@ export async function getBookReviews(locale: string): Promise<BookReview[] | nul
|
|||||||
query {
|
query {
|
||||||
book_reviews(
|
book_reviews(
|
||||||
filter: { status: { _eq: "published" } }
|
filter: { status: { _eq: "published" } }
|
||||||
sort: ["-finished_at", "-date_created"]
|
sort: ["-finished_at"]
|
||||||
) {
|
) {
|
||||||
id
|
id
|
||||||
hardcover_id
|
hardcover_id
|
||||||
|
|||||||
Reference in New Issue
Block a user