fix: cleanup book reviews HTML and improve about layout
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:
2026-02-16 00:42:57 +01:00
parent 931843a5c6
commit 0b1a45038d
4 changed files with 71 additions and 56 deletions

View File

@@ -25,6 +25,10 @@ export async function GET(request: NextRequest) {
const locale = searchParams.get('locale') || 'en'; const locale = searchParams.get('locale') || 'en';
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({

View File

@@ -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>

View File

@@ -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">
&ldquo;{review.review}&rdquo; &ldquo;{stripHtml(review.review)}&rdquo;
</p> </p>
)} )}

View File

@@ -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