feat(blog): restore typography ratios and implement smooth filter animations
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 6s
Build & Deploy / 🧪 QA (push) Failing after 1m13s
Build & Deploy / 🏗️ Build (push) Failing after 10m57s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🩺 Health Check (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 1s

This commit is contained in:
2026-02-17 22:52:53 +01:00
parent d41d4d3d89
commit 786d35010b
8 changed files with 152 additions and 114 deletions

View File

@@ -1,15 +1,17 @@
"use client";
/* eslint-disable react/prop-types */
import * as React from "react";
import { motion, AnimatePresence } from "framer-motion";
import { cn } from "../../utils/cn";
import { Search } from "lucide-react";
interface BlogCommandBarProps {
searchQuery: string;
onSearchChange: (value: string) => void;
onSearchChange: (_value: string) => void;
tags: string[];
activeTags: string[];
onTagToggle: (tag: string) => void;
onTagToggle: (_tag: string) => void;
className?: string;
}
@@ -44,37 +46,55 @@ export const BlogCommandBar: React.FC<BlogCommandBarProps> = ({
placeholder="Beiträge suchen..."
className="w-full bg-transparent px-3 md:px-4 py-2 md:py-3 text-base md:text-lg text-slate-900 placeholder:text-slate-300 outline-none font-bold"
/>
{searchQuery && (
<button
onClick={() => onSearchChange("")}
className="mr-2 px-2.5 py-1 md:px-3 md:py-1.5 bg-slate-100 hover:bg-slate-200 rounded-lg text-[9px] md:text-[10px] font-bold uppercase tracking-wider text-slate-500 hover:text-slate-900 transition-colors"
>
Leeren
</button>
)}
<AnimatePresence>
{searchQuery && (
<motion.button
initial={{ opacity: 0, scale: 0.8, x: 10 }}
animate={{ opacity: 1, scale: 1, x: 0 }}
exit={{ opacity: 0, scale: 0.8, x: 10 }}
onClick={() => onSearchChange("")}
className="mr-2 px-2.5 py-1 md:px-3 md:py-1.5 bg-slate-100 hover:bg-slate-200 rounded-lg text-[9px] md:text-[10px] font-bold uppercase tracking-wider text-slate-500 hover:text-slate-900 transition-colors"
>
Leeren
</motion.button>
)}
</AnimatePresence>
</div>
</div>
{/* Tag Command Row */}
<div className="flex flex-wrap items-center justify-center gap-1.5 md:gap-2 px-4 md:px-0">
<motion.div
layout
className="flex flex-wrap items-center justify-center gap-1.5 md:gap-2 px-4 md:px-0"
>
{tags.map((tag) => {
const isActive = activeTags.includes(tag);
return (
<button
<motion.button
key={tag}
layout
onClick={() => onTagToggle(tag)}
className={cn(
"px-2.5 py-1 md:px-3 md:py-1.5 rounded-lg text-[9px] md:text-[10px] font-mono uppercase tracking-wider border transition-all duration-200 select-none",
"relative px-2.5 py-1 md:px-3 md:py-1.5 rounded-lg text-[9px] md:text-[10px] font-mono uppercase tracking-wider border transition-all duration-200 select-none overflow-hidden",
isActive
? "bg-slate-900 text-white border-slate-900 shadow-md transform scale-105"
? "text-white border-slate-900 shadow-md"
: "bg-white text-slate-500 border-slate-200 hover:border-slate-400 hover:text-slate-900 hover:bg-slate-50",
)}
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
>
#{tag}
</button>
<span className="relative z-10">#{tag}</span>
{isActive && (
<motion.div
layoutId="activeTag"
className="absolute inset-0 bg-slate-900 z-0"
transition={{ type: "spring", bounce: 0.2, duration: 0.6 }}
/>
)}
</motion.button>
);
})}
</div>
</motion.div>
</div>
);
};