From 786d35010b53e4ff2df0f51077837b12af095bd3 Mon Sep 17 00:00:00 2001 From: Marc Mintel Date: Tue, 17 Feb 2026 22:52:53 +0100 Subject: [PATCH] feat(blog): restore typography ratios and implement smooth filter animations --- apps/web/app/blog/[slug]/page.tsx | 4 +- apps/web/app/blog/page.tsx | 76 ++++++++---- apps/web/app/globals.css | 116 +++++++++--------- apps/web/src/components/ArticleBlockquote.tsx | 2 +- apps/web/src/components/ArticleHeading.tsx | 6 +- apps/web/src/components/ArticleParagraph.tsx | 4 +- .../src/components/blog/BlogCommandBar.tsx | 54 +++++--- apps/web/src/content-engine/components.ts | 4 +- 8 files changed, 152 insertions(+), 114 deletions(-) diff --git a/apps/web/app/blog/[slug]/page.tsx b/apps/web/app/blog/[slug]/page.tsx index a39695e..2cb1fb1 100644 --- a/apps/web/app/blog/[slug]/page.tsx +++ b/apps/web/app/blog/[slug]/page.tsx @@ -83,7 +83,7 @@ export default async function BlogPostPage({ />
-
+
{post.tags && post.tags.length > 0 && (
@@ -98,7 +98,7 @@ export default async function BlogPostPage({
)} -
+
([]); @@ -133,35 +135,55 @@ export default function BlogPage() {
{/* Posts List (Vertical & Minimal) */}
- {postsToShow.length === 0 ? ( -
-

- Keine Beiträge gefunden. -

- -
- ) : ( -
- {postsToShow.map((post, i) => ( - + Keine Beiträge gefunden. +

+
- )} + Filter zurücksetzen + + + ) : ( + + + {postsToShow.map((post, i) => ( + + + + ))} + + + )} + {/* Pagination */} {hasMore && ( diff --git a/apps/web/app/globals.css b/apps/web/app/globals.css index 53f0545..b09e887 100644 --- a/apps/web/app/globals.css +++ b/apps/web/app/globals.css @@ -40,7 +40,7 @@ } p { - @apply mb-4 text-sm md:text-base leading-relaxed text-slate-700; + @apply mb-6 text-base leading-relaxed text-slate-700; } .lead { @@ -86,6 +86,7 @@ /* Components - Tailwind utility classes */ @layer components { + /* Legacy hooks required by tests */ .file-example { @apply w-full; @@ -149,32 +150,36 @@ } .article-content { - @apply text-lg leading-relaxed; + @apply font-serif antialiased text-slate-700; } .article-content p { - @apply mb-5; + @apply text-lg md:text-xl leading-relaxed mb-6; + } + + .article-content h1 { + @apply text-3xl md:text-5xl font-bold text-slate-900 mb-8 mt-12 tracking-tight leading-[1.1] font-sans; } .article-content h2 { - @apply text-2xl font-bold mt-8 mb-3; + @apply text-2xl md:text-4xl font-bold text-slate-900 mb-6 mt-10 tracking-tight leading-tight font-sans; } .article-content h3 { - @apply text-xl font-bold mt-6 mb-2; + @apply text-xl md:text-2xl font-bold text-slate-900 mb-4 mt-8 tracking-tight leading-snug font-sans; } .article-content ul, .article-content ol { - @apply ml-6 mb-5; + @apply ml-6 mb-6 text-lg md:text-xl; } .article-content li { - @apply mb-1; + @apply mb-2; } .article-content blockquote { - @apply border-l-2 border-slate-400 pl-4 italic text-slate-600 my-5 text-lg; + @apply border-l-4 border-slate-900 pl-6 italic text-slate-700 my-10 text-xl md:text-2xl; } /* Buttons */ @@ -286,6 +291,7 @@ /* Print styles */ @media print { + .floating-back-to-top, .reading-progress-bar { display: none !important; @@ -344,38 +350,30 @@ } .highlighter-yellow { - background: linear-gradient( - 135deg, - rgba(255, 235, 59, 0.95) 0%, - rgba(255, 213, 79, 0.95) 100% - ); + background: linear-gradient(135deg, + rgba(255, 235, 59, 0.95) 0%, + rgba(255, 213, 79, 0.95) 100%); color: #3f2f00; } .highlighter-pink { - background: linear-gradient( - 135deg, - rgba(255, 167, 209, 0.95) 0%, - rgba(255, 122, 175, 0.95) 100% - ); + background: linear-gradient(135deg, + rgba(255, 167, 209, 0.95) 0%, + rgba(255, 122, 175, 0.95) 100%); color: #3f0018; } .highlighter-green { - background: linear-gradient( - 135deg, - rgba(129, 199, 132, 0.95) 0%, - rgba(102, 187, 106, 0.95) 100% - ); + background: linear-gradient(135deg, + rgba(129, 199, 132, 0.95) 0%, + rgba(102, 187, 106, 0.95) 100%); color: #002f0a; } .highlighter-blue { - background: linear-gradient( - 135deg, - rgba(226, 232, 240, 0.95) 0%, - rgba(203, 213, 225, 0.95) 100% - ); + background: linear-gradient(135deg, + rgba(226, 232, 240, 0.95) 0%, + rgba(203, 213, 225, 0.95) 100%); color: #0f172a; } @@ -411,17 +409,14 @@ border-radius: 0.18em; z-index: -1; - background: linear-gradient( - 180deg, - rgba(255, 255, 255, 0) 0%, - rgba(255, 255, 255, 0) 20%, - rgba(253, 230, 138, 0.7) 20%, - rgba(253, 230, 138, 0.7) 100% - ); + background: linear-gradient(180deg, + rgba(255, 255, 255, 0) 0%, + rgba(255, 255, 255, 0) 20%, + rgba(253, 230, 138, 0.7) 20%, + rgba(253, 230, 138, 0.7) 100%); transform-origin: left center; - transform: rotate(calc((var(--marker-seed, 0) - 3) * 0.45deg)) - skewX(calc((var(--marker-seed, 0) - 3) * -0.25deg)); + transform: rotate(calc((var(--marker-seed, 0) - 3) * 0.45deg)) skewX(calc((var(--marker-seed, 0) - 3) * -0.25deg)); filter: saturate(1.05); } @@ -436,28 +431,24 @@ border-radius: 0.18em; z-index: -1; - background: linear-gradient( - 90deg, - rgba(253, 230, 138, 0) 0%, - rgba(253, 230, 138, 0.6) 8%, - rgba(253, 230, 138, 0.55) 60%, - rgba(253, 230, 138, 0.35) 100% - ); + background: linear-gradient(90deg, + rgba(253, 230, 138, 0) 0%, + rgba(253, 230, 138, 0.6) 8%, + rgba(253, 230, 138, 0.55) 60%, + rgba(253, 230, 138, 0.35) 100%); opacity: 0.75; mix-blend-mode: multiply; - transform: rotate(calc((var(--marker-seed, 0) - 3) * 0.45deg)) - translateY(0.02em); + transform: rotate(calc((var(--marker-seed, 0) - 3) * 0.45deg)) translateY(0.02em); - mask-image: linear-gradient( - 180deg, - rgba(0, 0, 0, 0) 0%, - rgba(0, 0, 0, 1) 20%, - rgba(0, 0, 0, 1) 100% - ); + mask-image: linear-gradient(180deg, + rgba(0, 0, 0, 0) 0%, + rgba(0, 0, 0, 1) 20%, + rgba(0, 0, 0, 1) 100%); } @media (prefers-reduced-motion: no-preference) { + .post-link:hover .marker-title::before, .post-link:hover .marker-title::after { filter: saturate(1.08) contrast(1.02); @@ -720,6 +711,7 @@ pre:has(code[class*="language-"]) { /* Gradient Mesh Blob Animations */ @keyframes gradient-blob-1 { + 0%, 100% { transform: translate(0, 0) scale(1); @@ -739,6 +731,7 @@ pre:has(code[class*="language-"]) { } @keyframes gradient-blob-2 { + 0%, 100% { transform: translate(0, 0) scale(1); @@ -754,6 +747,7 @@ pre:has(code[class*="language-"]) { } @keyframes gradient-blob-3 { + 0%, 100% { transform: translate(0, 0) scale(1); @@ -789,6 +783,7 @@ pre:has(code[class*="language-"]) { /* Circuit Pulse (used for node glow effects) */ @keyframes circuit-pulse { + 0%, 100% { opacity: 0.2; @@ -892,14 +887,12 @@ pre:has(code[class*="language-"]) { inset: 0; border-radius: inherit; padding: 1px; - background: linear-gradient( - 90deg, - transparent 0%, - rgba(148, 163, 184, 0.3) 25%, - rgba(191, 206, 228, 0.2) 50%, - rgba(148, 163, 184, 0.3) 75%, - transparent 100% - ); + background: linear-gradient(90deg, + transparent 0%, + rgba(148, 163, 184, 0.3) 25%, + rgba(191, 206, 228, 0.2) 50%, + rgba(148, 163, 184, 0.3) 75%, + transparent 100%); background-size: 200% 100%; animation: border-trace 4s linear infinite; -webkit-mask: @@ -969,6 +962,7 @@ pre:has(code[class*="language-"]) { } @keyframes junctionGlow { + 0%, 100% { opacity: 0.1; @@ -977,4 +971,4 @@ pre:has(code[class*="language-"]) { 50% { opacity: 0.4; } -} +} \ No newline at end of file diff --git a/apps/web/src/components/ArticleBlockquote.tsx b/apps/web/src/components/ArticleBlockquote.tsx index 9889f22..b655b6e 100644 --- a/apps/web/src/components/ArticleBlockquote.tsx +++ b/apps/web/src/components/ArticleBlockquote.tsx @@ -20,7 +20,7 @@ interface BlockquoteProps { } export const ArticleBlockquote: React.FC = ({ children, className = '' }) => ( -
+
{children}
); diff --git a/apps/web/src/components/ArticleHeading.tsx b/apps/web/src/components/ArticleHeading.tsx index 0e7852c..cdff17d 100644 --- a/apps/web/src/components/ArticleHeading.tsx +++ b/apps/web/src/components/ArticleHeading.tsx @@ -7,7 +7,7 @@ interface HeadingProps { export const H1: React.FC = ({ children, className = "" }) => (

{children}

@@ -15,7 +15,7 @@ export const H1: React.FC = ({ children, className = "" }) => ( export const H2: React.FC = ({ children, className = "" }) => (

{children}

@@ -23,7 +23,7 @@ export const H2: React.FC = ({ children, className = "" }) => ( export const H3: React.FC = ({ children, className = "" }) => (

{children}

diff --git a/apps/web/src/components/ArticleParagraph.tsx b/apps/web/src/components/ArticleParagraph.tsx index 63c1de4..b620262 100644 --- a/apps/web/src/components/ArticleParagraph.tsx +++ b/apps/web/src/components/ArticleParagraph.tsx @@ -10,7 +10,7 @@ export const Paragraph: React.FC = ({ className = "", }) => (
{children}
@@ -21,7 +21,7 @@ export const LeadParagraph: React.FC = ({ className = "", }) => (
{children}
diff --git a/apps/web/src/components/blog/BlogCommandBar.tsx b/apps/web/src/components/blog/BlogCommandBar.tsx index cf60f61..f6e0098 100644 --- a/apps/web/src/components/blog/BlogCommandBar.tsx +++ b/apps/web/src/components/blog/BlogCommandBar.tsx @@ -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 = ({ 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 && ( - - )} + + {searchQuery && ( + 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 + + )} +
{/* Tag Command Row */} -
+ {tags.map((tag) => { const isActive = activeTags.includes(tag); return ( - + #{tag} + {isActive && ( + + )} + ); })} -
+
); }; diff --git a/apps/web/src/content-engine/components.ts b/apps/web/src/content-engine/components.ts index d9b6ccd..5e63495 100644 --- a/apps/web/src/content-engine/components.ts +++ b/apps/web/src/content-engine/components.ts @@ -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,