chore: fix linting and build errors
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 5s
Build & Deploy / 🧪 QA (push) Failing after 1m31s
Build & Deploy / 🏗️ Build (push) Failing after 3m51s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🩺 Health Check (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s

This commit is contained in:
2026-02-17 23:48:52 +01:00
parent 786d35010b
commit 3eccff42e4
33 changed files with 303 additions and 66 deletions

View File

@@ -0,0 +1,56 @@
import React from 'react';
interface ArticleMemeProps {
template: string;
captions: string[];
className?: string;
}
export const ArticleMeme: React.FC<ArticleMemeProps> = ({ template, captions, className = '' }) => {
return (
<div className={`not-prose relative overflow-hidden group rounded-2xl border border-slate-200 bg-white shadow-xl max-w-2xl mx-auto my-12 ${className}`}>
{/* Meme "Image" Placeholder with Industrial Styling */}
<div className="aspect-video bg-slate-900 flex flex-col items-center justify-between p-8 text-center relative overflow-hidden">
{/* Decorative Grid */}
<div className="absolute inset-0 opacity-10 pointer-events-none"
style={{ backgroundImage: 'radial-gradient(#ffffff 1px, transparent 1px)', backgroundSize: '20px 20px' }} />
{/* Top Caption */}
<div className="relative z-10 w-full">
<h4 className="text-white text-3xl md:text-4xl font-black uppercase tracking-tighter leading-none [text-shadow:_2px_2px_0_rgb(0_0_0_/_80%)]">
{captions[0]}
</h4>
</div>
{/* Meme Figure/Avatar Placeholder */}
<div className="relative z-10 w-32 h-32 md:w-40 md:h-40 bg-gradient-to-br from-indigo-500 to-purple-600 rounded-full flex items-center justify-center border-4 border-white transform group-hover:scale-105 transition-transform duration-500 shadow-2xl">
<span className="text-5xl">🤖</span>
</div>
{/* Bottom Caption */}
<div className="relative z-10 w-full">
<h4 className="text-white text-2xl md:text-3xl font-bold uppercase tracking-tight leading-none [text-shadow:_1px_1px_0_rgb(0_0_0_/_80%)]">
{captions[1] || ''}
</h4>
</div>
</div>
{/* Meme Footer / Metadata */}
<div className="p-4 bg-slate-50 flex items-center justify-between border-t border-slate-100">
<div className="flex items-center gap-3">
<div className="w-8 h-8 rounded bg-slate-200 flex items-center justify-center text-[10px] font-mono text-slate-500 uppercase tracking-widest font-bold">
AI
</div>
<div>
<p className="text-[10px] font-bold text-slate-400 uppercase tracking-widest leading-none">Meme Template</p>
<p className="text-xs font-bold text-slate-900 mt-1 uppercase">{template}</p>
</div>
</div>
<div className="text-slate-300">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M15 3h6v6" /><path d="M10 14 21 3" /><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" /></svg>
</div>
</div>
</div>
);
};

View File

@@ -1,6 +1,6 @@
"use client";
/* eslint-disable no-unused-vars */
import * as React from "react";
import { cn } from "../utils/cn";
import { ShieldCheck, ArrowLeft, ArrowRight, RefreshCw } from "lucide-react";
@@ -125,8 +125,8 @@ export const IframeSection: React.FC<IframeSectionProps> = ({
desktopWidth = 1200,
minimal = false,
perspective = false,
rotate = 0,
delay = 0,
rotate: _rotate = 0,
delay: _delay = 0,
noScale = false,
dynamicGlow = true,
minHeight = 400,
@@ -142,7 +142,6 @@ export const IframeSection: React.FC<IframeSectionProps> = ({
React.useState(desktopWidth);
const [isLoading, setIsLoading] = React.useState(true);
const [isIframeLoaded, setIsIframeLoaded] = React.useState(false);
const [isMinTimePassed, setIsMinTimePassed] = React.useState(false);
const [glowColors, setGlowColors] = React.useState<string[]>([
"rgba(148, 163, 184, 0.1)",
"rgba(148, 163, 184, 0.1)",
@@ -213,7 +212,7 @@ export const IframeSection: React.FC<IframeSectionProps> = ({
const isScrollable = doc.scrollHeight > doc.clientHeight + 10;
setScrollState({ atTop, atBottom, isScrollable });
}
} catch (e) {}
} catch (_e) { }
}, []);
// Ambilight effect (sampled from iframe if same-origin)
@@ -258,7 +257,7 @@ export const IframeSection: React.FC<IframeSectionProps> = ({
);
updateScrollState();
} catch (e) {}
} catch (_e) { }
}, [dynamicGlow, offsetY, updateScrollState]);
// Height parse helper
@@ -377,9 +376,9 @@ export const IframeSection: React.FC<IframeSectionProps> = ({
"w-full relative flex flex-col z-10",
minimal ? "bg-transparent" : "bg-slate-50",
!minimal &&
"rounded-[2.5rem] border border-slate-200/50 shadow-[0_80px_160px_-40px_rgba(0,0,0,0.18),0_0_1px_rgba(0,0,0,0.1)]",
"rounded-[2.5rem] border border-slate-200/50 shadow-[0_80px_160px_-40px_rgba(0,0,0,0.18),0_0_1px_rgba(0,0,0,0.1)]",
perspective &&
"hover:scale-[1.03] hover:-translate-y-3 transition-[transform,shadow,scale] duration-1000 ease-[cubic-bezier(0.23,1,0.32,1)]",
"hover:scale-[1.03] hover:-translate-y-3 transition-[transform,shadow,scale] duration-1000 ease-[cubic-bezier(0.23,1,0.32,1)]",
"overflow-hidden",
)}
style={chassisStyle}

View File

@@ -1,6 +1,6 @@
"use client";
/* eslint-disable no-unused-vars */
import * as React from "react";
import { motion } from "framer-motion";

View File

@@ -1,6 +1,6 @@
"use client";
/* eslint-disable no-unused-vars */
import * as React from "react";
import { motion } from "framer-motion";

View File

@@ -1,6 +1,6 @@
"use client";
/* eslint-disable no-unused-vars */
import * as React from "react";
import { motion } from "framer-motion";

View File

@@ -1,6 +1,6 @@
"use client";
/* eslint-disable no-unused-vars */
import * as React from "react";
import { motion } from "framer-motion";

View File

@@ -1,6 +1,6 @@
"use client";
/* eslint-disable no-unused-vars */
import * as React from "react";
import { motion } from "framer-motion";

View File

@@ -1,6 +1,6 @@
"use client";
/* eslint-disable no-unused-vars */
import * as React from "react";
import { motion } from "framer-motion";

View File

@@ -1,6 +1,6 @@
"use client";
/* eslint-disable no-unused-vars */
import * as React from "react";
import { motion } from "framer-motion";

View File

@@ -1,6 +1,6 @@
"use client";
/* eslint-disable no-unused-vars */
import * as React from "react";
import { motion } from "framer-motion";

View File

@@ -1,7 +1,7 @@
"use client";
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable no-unused-vars */
import * as React from "react";
export interface IllustrationProps {

View File

@@ -45,15 +45,15 @@ export const ParticleNetwork: React.FC<ParticleNetworkProps> = ({ className = ''
const initParticles = useCallback((width: number, height: number) => {
const particles: Particle[] = [];
const count = config.particleCount;
// Create particles primarily in the side gutters
for (let i = 0; i < count; i++) {
const isLeft = Math.random() > 0.5;
// Random position within the gutter (0-25% or 75-100%)
const gutterX = isLeft
? Math.random() * (width * config.gutterWidth)
const gutterX = isLeft
? Math.random() * (width * config.gutterWidth)
: width - (Math.random() * (width * config.gutterWidth));
// Add some occasional strays near the content but not IN it
const x = gutterX;
const y = Math.random() * height;
@@ -89,7 +89,7 @@ export const ParticleNetwork: React.FC<ParticleNetworkProps> = ({ className = ''
ctx.clearRect(0, 0, width, height);
// Update and draw particles
particles.forEach((p, i) => {
particles.forEach((p, _i) => {
// 1. Movement
// Apply downward flow
p.y += p.vy;
@@ -111,7 +111,7 @@ export const ParticleNetwork: React.FC<ParticleNetworkProps> = ({ className = ''
const angle = Math.atan2(dy, dx);
const pushX = Math.cos(angle) * force * 2;
const pushY = Math.sin(angle) * force * 2;
p.x += pushX;
p.y += pushY;
}
@@ -145,17 +145,17 @@ export const ParticleNetwork: React.FC<ParticleNetworkProps> = ({ className = ''
// Draw Connections
// We only connect particles that are close enough
ctx.lineWidth = 0.5;
for (let i = 0; i < particles.length; i++) {
const p1 = particles[i];
// Optimization: only check particles after this one
for (let j = i + 1; j < particles.length; j++) {
const p2 = particles[j];
// Quick check for distance
const dx = p1.x - p2.x;
const dy = p1.y - p2.y;
// Optimization: skip sqrt if obviously too far
if (Math.abs(dx) > config.connectionDistance || Math.abs(dy) > config.connectionDistance) continue;
@@ -164,7 +164,7 @@ export const ParticleNetwork: React.FC<ParticleNetworkProps> = ({ className = ''
if (dist < config.connectionDistance) {
// Calculate opacity based on distance
const opacity = (1 - dist / config.connectionDistance) * 0.3;
ctx.beginPath();
ctx.moveTo(p1.x, p1.y);
ctx.lineTo(p2.x, p2.y);
@@ -185,12 +185,12 @@ export const ParticleNetwork: React.FC<ParticleNetworkProps> = ({ className = ''
const rect = container.getBoundingClientRect();
const dpr = window.devicePixelRatio || 1;
canvas.width = rect.width * dpr;
canvas.height = rect.height * dpr;
canvas.style.width = `${rect.width}px`;
canvas.style.height = `${rect.height}px`;
const ctx = canvas.getContext('2d');
if (ctx) {
ctx.scale(dpr, dpr);
@@ -209,7 +209,7 @@ export const ParticleNetwork: React.FC<ParticleNetworkProps> = ({ className = ''
const handleMouseMove = useCallback((e: MouseEvent) => {
const container = containerRef.current;
if (!container) return;
const rect = container.getBoundingClientRect();
mouseRef.current = {
x: e.clientX - rect.left,

View File

@@ -2,7 +2,6 @@
import * as React from "react";
import { Reveal } from "./Reveal";
import { H1, LeadText } from "./Typography";
import { cn } from "../utils/cn";
import { Share2, Clock, Calendar } from "lucide-react";
import { ShareModal } from "./ShareModal";

View File

@@ -54,11 +54,10 @@ export const SearchBar: React.FC<SearchBarProps> = ({
type="text"
placeholder="Suchen..."
value={value}
className={`w-full max-w-full px-8 py-4 font-bold text-slate-900 bg-white rounded-2xl border transition-all focus:outline-none placeholder:text-slate-300 ${
size === "large"
? "text-2xl md:text-4xl py-6 rounded-3xl"
: "text-lg"
} ${isFocused ? "border-slate-400" : "border-slate-200"}`}
className={`w-full max-w-full px-8 py-4 font-bold text-slate-900 bg-white rounded-2xl border transition-all focus:outline-none placeholder:text-slate-300 ${size === "large"
? "text-2xl md:text-4xl py-6 rounded-3xl"
: "text-lg"
} ${isFocused ? "border-slate-400" : "border-slate-200"}`}
onChange={handleInput}
onKeyDown={handleKeyDown}
onFocus={() => setIsFocused(true)}

View File

@@ -2,7 +2,6 @@ import * as React from "react";
import { Reveal } from "./Reveal";
import { Label } from "./Typography";
import { cn } from "../utils/cn";
import { GlitchText } from "./GlitchText";
interface SectionProps {
number?: string;

View File

@@ -123,8 +123,8 @@ export function ShareModal({
}
await navigator.share(shareData);
} catch (e) {
console.error("Share failed", e);
} catch (_e) {
console.error("Share failed", _e);
}
}
};

View File

@@ -1,7 +1,7 @@
"use client";
import React, { useEffect, useState, useRef } from "react";
import { Share2, Copy, Check } from "lucide-react";
import { Copy, Check } from "lucide-react";
import { useAnalytics } from "./analytics/useAnalytics";
import { motion, AnimatePresence } from "framer-motion";

View File

@@ -1,6 +1,4 @@
"use client";
/* eslint-disable react/prop-types */
import * as React from "react";
import { motion, AnimatePresence } from "framer-motion";
import { cn } from "../../utils/cn";
@@ -8,10 +6,10 @@ 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;
}

View File

@@ -6,10 +6,10 @@ import { cn } from "../../utils/cn";
interface BlogFilterBarProps {
searchQuery: string;
onSearchChange: (value: string) => void;
onSearchChange: (_value: string) => void;
tags: string[];
activeTags: string[];
onTagToggle: (tag: string) => void;
onTagToggle: (_tag: string) => void;
className?: string;
}

View File

@@ -1,7 +1,6 @@
/* eslint-disable react/prop-types */
import type {
ThumbnailIcon,
BlogThumbnailConfig,
} from "./blogThumbnails";
import { blogThumbnails } from "./blogThumbnails";
@@ -602,7 +601,7 @@ function renderGear(cx: number, cy: number, accent: string) {
const angle = (i * 2 * Math.PI) / teeth;
const a1 = angle - toothWidth;
const a2 = angle + toothWidth;
const midAngle = (a1 + a2) / 2;
const _midAngle = (a1 + a2) / 2;
if (i === 0) {
d += `M ${cx + outerR * Math.cos(a1)} ${cy + outerR * Math.sin(a1)} `;
@@ -954,7 +953,7 @@ function renderSync(cx: number, cy: number, accent: string) {
const iconRenderers: Record<
ThumbnailIcon,
(cx: number, cy: number, accent: string) => React.ReactNode
(_cx: number, _cy: number, _accent: string) => React.ReactNode
> = {
gauge: renderGauge,
bottleneck: renderBottleneck,

View File

@@ -13,6 +13,7 @@ import { DiagramGantt } from '../components/DiagramGantt';
import { DiagramPie } from '../components/DiagramPie';
import { DiagramSequence } from '../components/DiagramSequence';
import { IconList, IconListItem } from '../components/IconList';
import { ArticleMeme } from '../components/ArticleMeme';
import { Section } from '../components/Section';
import { Reveal } from '../components/Reveal';
@@ -36,6 +37,7 @@ export const mdxComponents = {
DiagramSequence,
IconList,
IconListItem,
ArticleMeme,
Section,
Reveal
};

View File

@@ -25,7 +25,7 @@ export async function getOgFonts() {
regularFontPath = r;
break;
}
} catch (e) {
} catch (_e) {
continue;
}
}

View File

@@ -1,7 +1,7 @@
import fs from "fs";
import path from "path";
/* eslint-disable no-unused-vars */
const DOCS_DIR = path.join(process.cwd(), "docs");

View File

@@ -2,7 +2,7 @@
* Analytics interfaces - decoupled contracts
*/
/* eslint-disable no-unused-vars */
export interface AnalyticsEvent {
name: string;

View File

@@ -4,7 +4,7 @@ import * as path from "node:path";
import { existsSync } from "node:fs";
import * as crypto from "node:crypto";
/* eslint-disable no-unused-vars */
export class FileCacheAdapter implements CacheAdapter {
private cacheDir: string;

View File

@@ -3,9 +3,9 @@
*/
export interface CacheAdapter {
get<T>(key: string): Promise<T | null>;
set<T>(key: string, value: T, ttl?: number): Promise<void>;
del(key: string): Promise<void>;
get<T>(_key: string): Promise<T | null>;
set<T>(_key: string, _value: T, _ttl?: number): Promise<void>;
del(_key: string): Promise<void>;
clear(): Promise<void>;
}

View File

@@ -14,11 +14,11 @@ export interface ErrorContext {
}
export interface ErrorTrackingAdapter {
captureException(error: any, context?: ErrorContext): void;
captureMessage(message: string, context?: ErrorContext): void;
setUser(user: ErrorContext['user']): void;
setTag(key: string, value: string): void;
setExtra(key: string, value: any): void;
captureException(_error: any, _context?: ErrorContext): void;
captureMessage(_message: string, _context?: ErrorContext): void;
setUser(_user: ErrorContext['user']): void;
setTag(_key: string, _value: string): void;
setExtra(_key: string, _value: any): void;
}
export interface ErrorTrackingConfig {

View File

@@ -11,11 +11,11 @@ import { getImgproxyUrl } from "./imgproxy";
export default function imgproxyLoader({
src,
width,
quality,
_quality,
}: {
src: string;
width: number;
quality?: number;
_quality?: number;
}) {
// We use the width provided by Next.js for responsive images
// Height is set to 0 to maintain aspect ratio