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
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:
@@ -20,7 +20,7 @@ interface BlockquoteProps {
|
||||
}
|
||||
|
||||
export const ArticleBlockquote: React.FC<BlockquoteProps> = ({ children, className = '' }) => (
|
||||
<blockquote className={`not-prose border-l-4 border-slate-900 pl-6 italic text-slate-700 my-8 text-xl md:text-2xl font-serif ${className}`}>
|
||||
<blockquote className={`not-prose border-l-4 border-slate-900 pl-6 italic text-slate-700 my-10 text-xl md:text-2xl font-serif ${className}`}>
|
||||
{children}
|
||||
</blockquote>
|
||||
);
|
||||
|
||||
@@ -7,7 +7,7 @@ interface HeadingProps {
|
||||
|
||||
export const H1: React.FC<HeadingProps> = ({ children, className = "" }) => (
|
||||
<h1
|
||||
className={`not-prose text-4xl md:text-5xl font-bold text-slate-900 mb-6 mt-8 leading-[1.1] tracking-tight ${className}`}
|
||||
className={`not-prose text-3xl md:text-5xl font-bold text-slate-900 mb-8 mt-12 leading-[1.1] tracking-tight font-sans ${className}`}
|
||||
>
|
||||
{children}
|
||||
</h1>
|
||||
@@ -15,7 +15,7 @@ export const H1: React.FC<HeadingProps> = ({ children, className = "" }) => (
|
||||
|
||||
export const H2: React.FC<HeadingProps> = ({ children, className = "" }) => (
|
||||
<h2
|
||||
className={`not-prose text-3xl md:text-4xl font-bold text-slate-900 mb-4 mt-10 leading-[1.2] tracking-tight ${className}`}
|
||||
className={`not-prose text-2xl md:text-4xl font-bold text-slate-900 mb-6 mt-10 leading-tight tracking-tight font-sans ${className}`}
|
||||
>
|
||||
{children}
|
||||
</h2>
|
||||
@@ -23,7 +23,7 @@ export const H2: React.FC<HeadingProps> = ({ children, className = "" }) => (
|
||||
|
||||
export const H3: React.FC<HeadingProps> = ({ children, className = "" }) => (
|
||||
<h3
|
||||
className={`not-prose text-2xl md:text-3xl font-bold text-slate-900 mb-3 mt-8 leading-[1.3] tracking-tight ${className}`}
|
||||
className={`not-prose text-xl md:text-2xl font-bold text-slate-900 mb-4 mt-8 leading-snug tracking-tight font-sans ${className}`}
|
||||
>
|
||||
{children}
|
||||
</h3>
|
||||
|
||||
@@ -10,7 +10,7 @@ export const Paragraph: React.FC<ParagraphProps> = ({
|
||||
className = "",
|
||||
}) => (
|
||||
<div
|
||||
className={`not-prose text-slate-700 font-serif text-lg md:text-xl leading-[1.6] mb-4 [&_p]:mb-4 last:[&_p]:mb-0 ${className}`}
|
||||
className={`not-prose text-slate-700 font-serif text-lg md:text-xl leading-[1.6] mb-8 ${className}`}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
@@ -21,7 +21,7 @@ export const LeadParagraph: React.FC<ParagraphProps> = ({
|
||||
className = "",
|
||||
}) => (
|
||||
<div
|
||||
className={`not-prose text-xl md:text-2xl text-slate-700 font-serif italic leading-snug mb-6 [&_p]:mb-6 last:[&_p]:mb-0 ${className}`}
|
||||
className={`not-prose text-xl md:text-2xl text-slate-700 font-serif italic leading-snug mb-10 ${className}`}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
import { LeadParagraph } from '../components/ArticleParagraph';
|
||||
import { H2, H3 } from '../components/ArticleHeading';
|
||||
import { H1, H2, H3 } from '../components/ArticleHeading';
|
||||
import { Paragraph } from '../components/ArticleParagraph';
|
||||
import { ArticleBlockquote } from '../components/ArticleBlockquote';
|
||||
import { Marker } from '../components/Marker';
|
||||
@@ -18,7 +18,9 @@ import { Section } from '../components/Section';
|
||||
import { Reveal } from '../components/Reveal';
|
||||
|
||||
export const mdxComponents = {
|
||||
// Named exports for explicit MDX usage
|
||||
LeadParagraph,
|
||||
H1,
|
||||
H2,
|
||||
H3,
|
||||
Paragraph,
|
||||
|
||||
Reference in New Issue
Block a user