diff --git a/apps/web/package.json b/apps/web/package.json
index f73ffff..6a2ad55 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -30,6 +30,7 @@
},
"dependencies": {
"@directus/sdk": "21.0.0",
+ "@emotion/is-prop-valid": "^1.4.0",
"@mdx-js/loader": "^3.1.1",
"@mdx-js/react": "^3.1.1",
"@mintel/cloner": "^1.8.0",
diff --git a/apps/web/scripts/fix-fenced-mermaid.ts b/apps/web/scripts/fix-fenced-mermaid.ts
new file mode 100644
index 0000000..cb403b7
--- /dev/null
+++ b/apps/web/scripts/fix-fenced-mermaid.ts
@@ -0,0 +1,62 @@
+
+import * as fs from 'fs';
+import * as path from 'path';
+
+const MDX_DIR = path.join(process.cwd(), 'content/blog');
+const TARGET_FILE = process.argv[2] ? path.resolve(process.argv[2]) : null;
+
+function fixFencedMermaid(content: string): string {
+ // Regex to find fenced mermaid blocks
+ // ```mermaid
+ // graph TD...
+ // ```
+ const fencedRegex = /```mermaid\n([\s\S]*?)\n```/g;
+
+ return content.replace(fencedRegex, (match, code) => {
+ // Generate a random ID or use a placeholder
+ const id = `diagram-${Math.random().toString(36).substr(2, 9)}`;
+ return `
+
+${code.trim()}
+
+
`;
+ });
+}
+
+function processFiles() {
+ if (TARGET_FILE) {
+ console.log(`Processing single file: ${TARGET_FILE}`);
+ if (fs.existsSync(TARGET_FILE)) {
+ const content = fs.readFileSync(TARGET_FILE, 'utf8');
+ const fixed = fixFencedMermaid(content);
+ if (content !== fixed) {
+ fs.writeFileSync(TARGET_FILE, fixed);
+ console.log(`β
Fixed fenced mermaid in: ${TARGET_FILE}`);
+ } else {
+ console.log(`- No changes needed.`);
+ }
+ } else {
+ console.error(`File not found: ${TARGET_FILE}`);
+ }
+ return;
+ }
+
+ const files = fs.readdirSync(MDX_DIR).filter(f => f.endsWith('.mdx'));
+ let fixCount = 0;
+
+ for (const file of files) {
+ const filePath = path.join(MDX_DIR, file);
+ const content = fs.readFileSync(filePath, 'utf8');
+ const fixed = fixFencedMermaid(content);
+
+ if (content !== fixed) {
+ fs.writeFileSync(filePath, fixed);
+ fixCount++;
+ console.log(`β
Fixed fenced mermaid in: ${file}`);
+ }
+ }
+
+ console.log(`\nTotal fixed: ${fixCount}`);
+}
+
+processFiles();
diff --git a/apps/web/scripts/optimize-blog-post.ts b/apps/web/scripts/optimize-blog-post.ts
new file mode 100644
index 0000000..5f521f7
--- /dev/null
+++ b/apps/web/scripts/optimize-blog-post.ts
@@ -0,0 +1,107 @@
+
+import { ContentGenerator, OptimizationOptions } from "@mintel/content-engine";
+import * as fs from "node:fs/promises";
+import * as path from "node:path";
+import { fileURLToPath } from "node:url";
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = path.dirname(__filename);
+
+async function main() {
+ const OPENROUTER_KEY = process.env.OPENROUTER_KEY;
+ if (!OPENROUTER_KEY) {
+ console.error("β Error: OPENROUTER_KEY not found in environment.");
+ process.exit(1);
+ }
+
+ const args = process.argv.slice(2);
+ let targetFile = args[0];
+
+ if (!targetFile) {
+ console.error("β Usage: npx tsx scripts/optimize-blog-post.ts ");
+ process.exit(1);
+ }
+
+ // Resolve absolute path
+ if (!path.isAbsolute(targetFile)) {
+ targetFile = path.resolve(process.cwd(), targetFile);
+ }
+
+ console.log(`π Reading file: ${targetFile}`);
+ let content = "";
+ try {
+ content = await fs.readFile(targetFile, "utf8");
+ } catch (err: any) {
+ console.error(`β Could not read file: ${err.message}`);
+ process.exit(1);
+ }
+
+ // Backup original
+ const backupPath = `${targetFile}.bak`;
+ await fs.writeFile(backupPath, content);
+ console.log(`πΎ Backup created at: ${backupPath}`);
+
+ // Instantiate Generator
+ const generator = new ContentGenerator(OPENROUTER_KEY);
+
+ const context = `
+ Project: Mintel.me
+ Style: Industrial, Technical, High-Performance, "No-BS".
+ Author: Marc Mintel (Digital Architect).
+ Focus: Web Architecture, PageSpeed, Core Web Vitals, Data-Driven Design.
+ `;
+
+ // Define Optimization Options based on user request ("astrein verbessert mit daten gestΓΌtzt, links zu quellen usw... mermaid, memes")
+ const options: OptimizationOptions = {
+ enhanceFacts: true,
+ addMemes: true,
+ addDiagrams: true,
+ projectContext: context,
+ availableComponents: [
+ {
+ name: "StatsDisplay",
+ description: "A row of 3 clear statistic cards with values and labels.",
+ usageExample: ` 3s" },
+ { value: "0.1s", label: "Latency", description: "Edge Network" }
+ ]}
+/>`
+ },
+ {
+ name: "ComparisonRow",
+ description: "A comparison component showing a negative 'Standard' vs a positive 'Mintel' approach.",
+ usageExample: ``
+ }
+ ]
+ };
+
+ // 1. Separate Frontmatter from Body
+ const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
+ const frontmatter = fmMatch ? fmMatch[0] : "";
+ const body = fmMatch ? content.replace(frontmatter, "").trim() : content;
+
+ console.log("π Starting Optimization via ContentEngine...");
+ const result = await generator.optimizePost(body, options);
+
+ console.log("β
Optimization Complete!");
+ console.log(` - Added ${result.research.length} facts`);
+ console.log(` - Added ${result.memes.length} meme concepts`);
+ console.log(` - Generated ${result.diagrams.length} diagrams`);
+
+ // We write the content back (re-attaching frontmatter if it was there)
+ const finalContent = frontmatter ? `${frontmatter}\n\n${result.content}` : result.content;
+
+ await fs.writeFile(targetFile, finalContent);
+
+ console.log(`πΎ Saved optimized content to: ${targetFile}`);
+}
+
+main().catch(console.error);
diff --git a/apps/web/src/components/ArticleMeme.tsx b/apps/web/src/components/ArticleMeme.tsx
new file mode 100644
index 0000000..2930eae
--- /dev/null
+++ b/apps/web/src/components/ArticleMeme.tsx
@@ -0,0 +1,56 @@
+
+import React from 'react';
+
+interface ArticleMemeProps {
+ template: string;
+ captions: string[];
+ className?: string;
+}
+
+export const ArticleMeme: React.FC = ({ template, captions, className = '' }) => {
+ return (
+
+ {/* Meme "Image" Placeholder with Industrial Styling */}
+
+ {/* Decorative Grid */}
+
+
+ {/* Top Caption */}
+
+
+ {captions[0]}
+
+
+
+ {/* Meme Figure/Avatar Placeholder */}
+
+ π€
+
+
+ {/* Bottom Caption */}
+
+
+ {captions[1] || ''}
+
+
+
+
+ {/* Meme Footer / Metadata */}
+
+
+
+ AI
+
+
+
Meme Template
+
{template}
+
+
+
+
+
+ );
+};
diff --git a/apps/web/src/components/IframeSection.tsx b/apps/web/src/components/IframeSection.tsx
index bac698c..9d02e8d 100644
--- a/apps/web/src/components/IframeSection.tsx
+++ b/apps/web/src/components/IframeSection.tsx
@@ -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 = ({
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 = ({
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([
"rgba(148, 163, 184, 0.1)",
"rgba(148, 163, 184, 0.1)",
@@ -213,7 +212,7 @@ export const IframeSection: React.FC = ({
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 = ({
);
updateScrollState();
- } catch (e) {}
+ } catch (_e) { }
}, [dynamicGlow, offsetY, updateScrollState]);
// Height parse helper
@@ -377,9 +376,9 @@ export const IframeSection: React.FC = ({
"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}
diff --git a/apps/web/src/components/Landing/AbstractLines.tsx b/apps/web/src/components/Landing/AbstractLines.tsx
index f7eeebf..97d5ea1 100644
--- a/apps/web/src/components/Landing/AbstractLines.tsx
+++ b/apps/web/src/components/Landing/AbstractLines.tsx
@@ -1,6 +1,6 @@
"use client";
-/* eslint-disable no-unused-vars */
+
import * as React from "react";
import { motion } from "framer-motion";
diff --git a/apps/web/src/components/Landing/Illustrations/ConceptAutomation.tsx b/apps/web/src/components/Landing/Illustrations/ConceptAutomation.tsx
index 05aebc4..9a02b61 100644
--- a/apps/web/src/components/Landing/Illustrations/ConceptAutomation.tsx
+++ b/apps/web/src/components/Landing/Illustrations/ConceptAutomation.tsx
@@ -1,6 +1,6 @@
"use client";
-/* eslint-disable no-unused-vars */
+
import * as React from "react";
import { motion } from "framer-motion";
diff --git a/apps/web/src/components/Landing/Illustrations/ConceptMessy.tsx b/apps/web/src/components/Landing/Illustrations/ConceptMessy.tsx
index 01593ef..a7724ed 100644
--- a/apps/web/src/components/Landing/Illustrations/ConceptMessy.tsx
+++ b/apps/web/src/components/Landing/Illustrations/ConceptMessy.tsx
@@ -1,6 +1,6 @@
"use client";
-/* eslint-disable no-unused-vars */
+
import * as React from "react";
import { motion } from "framer-motion";
diff --git a/apps/web/src/components/Landing/Illustrations/ConceptSystem.tsx b/apps/web/src/components/Landing/Illustrations/ConceptSystem.tsx
index 2f06410..e8368c2 100644
--- a/apps/web/src/components/Landing/Illustrations/ConceptSystem.tsx
+++ b/apps/web/src/components/Landing/Illustrations/ConceptSystem.tsx
@@ -1,6 +1,6 @@
"use client";
-/* eslint-disable no-unused-vars */
+
import * as React from "react";
import { motion } from "framer-motion";
diff --git a/apps/web/src/components/Landing/Illustrations/ConceptTarget.tsx b/apps/web/src/components/Landing/Illustrations/ConceptTarget.tsx
index 9fcad44..52ae39f 100644
--- a/apps/web/src/components/Landing/Illustrations/ConceptTarget.tsx
+++ b/apps/web/src/components/Landing/Illustrations/ConceptTarget.tsx
@@ -1,6 +1,6 @@
"use client";
-/* eslint-disable no-unused-vars */
+
import * as React from "react";
import { motion } from "framer-motion";
diff --git a/apps/web/src/components/Landing/Illustrations/ConceptWebsite.tsx b/apps/web/src/components/Landing/Illustrations/ConceptWebsite.tsx
index 53ae674..cdd9054 100644
--- a/apps/web/src/components/Landing/Illustrations/ConceptWebsite.tsx
+++ b/apps/web/src/components/Landing/Illustrations/ConceptWebsite.tsx
@@ -1,6 +1,6 @@
"use client";
-/* eslint-disable no-unused-vars */
+
import * as React from "react";
import { motion } from "framer-motion";
diff --git a/apps/web/src/components/Landing/Illustrations/HeroArchitecture.tsx b/apps/web/src/components/Landing/Illustrations/HeroArchitecture.tsx
index c39953d..3e0cac1 100644
--- a/apps/web/src/components/Landing/Illustrations/HeroArchitecture.tsx
+++ b/apps/web/src/components/Landing/Illustrations/HeroArchitecture.tsx
@@ -1,6 +1,6 @@
"use client";
-/* eslint-disable no-unused-vars */
+
import * as React from "react";
import { motion } from "framer-motion";
diff --git a/apps/web/src/components/Landing/Illustrations/HeroMainIllustration.tsx b/apps/web/src/components/Landing/Illustrations/HeroMainIllustration.tsx
index ab74f88..8a48fb8 100644
--- a/apps/web/src/components/Landing/Illustrations/HeroMainIllustration.tsx
+++ b/apps/web/src/components/Landing/Illustrations/HeroMainIllustration.tsx
@@ -1,6 +1,6 @@
"use client";
-/* eslint-disable no-unused-vars */
+
import * as React from "react";
import { motion } from "framer-motion";
diff --git a/apps/web/src/components/Landing/Illustrations/types.ts b/apps/web/src/components/Landing/Illustrations/types.ts
index 3a29d95..405cfdd 100644
--- a/apps/web/src/components/Landing/Illustrations/types.ts
+++ b/apps/web/src/components/Landing/Illustrations/types.ts
@@ -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 {
diff --git a/apps/web/src/components/Landing/ParticleNetwork.tsx b/apps/web/src/components/Landing/ParticleNetwork.tsx
index 64c6e98..d8a88fc 100644
--- a/apps/web/src/components/Landing/ParticleNetwork.tsx
+++ b/apps/web/src/components/Landing/ParticleNetwork.tsx
@@ -45,15 +45,15 @@ export const ParticleNetwork: React.FC = ({ 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 = ({ 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 = ({ 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 = ({ 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 = ({ 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 = ({ 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 = ({ className = ''
const handleMouseMove = useCallback((e: MouseEvent) => {
const container = containerRef.current;
if (!container) return;
-
+
const rect = container.getBoundingClientRect();
mouseRef.current = {
x: e.clientX - rect.left,
diff --git a/apps/web/src/components/PageHeader.tsx b/apps/web/src/components/PageHeader.tsx
index d165e2f..cd729d3 100644
--- a/apps/web/src/components/PageHeader.tsx
+++ b/apps/web/src/components/PageHeader.tsx
@@ -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";
diff --git a/apps/web/src/components/SearchBar.tsx b/apps/web/src/components/SearchBar.tsx
index ad4956b..002c891 100644
--- a/apps/web/src/components/SearchBar.tsx
+++ b/apps/web/src/components/SearchBar.tsx
@@ -54,11 +54,10 @@ export const SearchBar: React.FC = ({
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)}
diff --git a/apps/web/src/components/Section.tsx b/apps/web/src/components/Section.tsx
index 467c354..a398609 100644
--- a/apps/web/src/components/Section.tsx
+++ b/apps/web/src/components/Section.tsx
@@ -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;
diff --git a/apps/web/src/components/ShareModal.tsx b/apps/web/src/components/ShareModal.tsx
index b76a9bd..4464624 100644
--- a/apps/web/src/components/ShareModal.tsx
+++ b/apps/web/src/components/ShareModal.tsx
@@ -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);
}
}
};
diff --git a/apps/web/src/components/TextSelectionShare.tsx b/apps/web/src/components/TextSelectionShare.tsx
index e3b9e48..bc303d2 100644
--- a/apps/web/src/components/TextSelectionShare.tsx
+++ b/apps/web/src/components/TextSelectionShare.tsx
@@ -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";
diff --git a/apps/web/src/components/blog/BlogCommandBar.tsx b/apps/web/src/components/blog/BlogCommandBar.tsx
index f6e0098..89c2b75 100644
--- a/apps/web/src/components/blog/BlogCommandBar.tsx
+++ b/apps/web/src/components/blog/BlogCommandBar.tsx
@@ -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;
}
diff --git a/apps/web/src/components/blog/BlogFilterBar.tsx b/apps/web/src/components/blog/BlogFilterBar.tsx
index a1be102..b5f34c9 100644
--- a/apps/web/src/components/blog/BlogFilterBar.tsx
+++ b/apps/web/src/components/blog/BlogFilterBar.tsx
@@ -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;
}
diff --git a/apps/web/src/components/blog/BlogThumbnailSVG.tsx b/apps/web/src/components/blog/BlogThumbnailSVG.tsx
index 1d1403e..a2010f3 100644
--- a/apps/web/src/components/blog/BlogThumbnailSVG.tsx
+++ b/apps/web/src/components/blog/BlogThumbnailSVG.tsx
@@ -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,
diff --git a/apps/web/src/content-engine/components.ts b/apps/web/src/content-engine/components.ts
index 5e63495..d749fdd 100644
--- a/apps/web/src/content-engine/components.ts
+++ b/apps/web/src/content-engine/components.ts
@@ -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
};
diff --git a/apps/web/src/lib/og-helper.tsx b/apps/web/src/lib/og-helper.tsx
index 2bd1ab7..cdfb512 100644
--- a/apps/web/src/lib/og-helper.tsx
+++ b/apps/web/src/lib/og-helper.tsx
@@ -25,7 +25,7 @@ export async function getOgFonts() {
regularFontPath = r;
break;
}
- } catch (e) {
+ } catch (_e) {
continue;
}
}
diff --git a/apps/web/src/logic/content-provider.ts b/apps/web/src/logic/content-provider.ts
index f4bb041..e1ed57f 100644
--- a/apps/web/src/logic/content-provider.ts
+++ b/apps/web/src/logic/content-provider.ts
@@ -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");
diff --git a/apps/web/src/utils/analytics/interfaces.ts b/apps/web/src/utils/analytics/interfaces.ts
index 2ecd23f..72adbb1 100644
--- a/apps/web/src/utils/analytics/interfaces.ts
+++ b/apps/web/src/utils/analytics/interfaces.ts
@@ -2,7 +2,7 @@
* Analytics interfaces - decoupled contracts
*/
-/* eslint-disable no-unused-vars */
+
export interface AnalyticsEvent {
name: string;
diff --git a/apps/web/src/utils/cache/file-adapter.ts b/apps/web/src/utils/cache/file-adapter.ts
index eec1397..a7c554d 100644
--- a/apps/web/src/utils/cache/file-adapter.ts
+++ b/apps/web/src/utils/cache/file-adapter.ts
@@ -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;
diff --git a/apps/web/src/utils/cache/interfaces.ts b/apps/web/src/utils/cache/interfaces.ts
index 5bc73fb..b474bb2 100644
--- a/apps/web/src/utils/cache/interfaces.ts
+++ b/apps/web/src/utils/cache/interfaces.ts
@@ -3,9 +3,9 @@
*/
export interface CacheAdapter {
- get(key: string): Promise;
- set(key: string, value: T, ttl?: number): Promise;
- del(key: string): Promise;
+ get(_key: string): Promise;
+ set(_key: string, _value: T, _ttl?: number): Promise;
+ del(_key: string): Promise;
clear(): Promise;
}
diff --git a/apps/web/src/utils/error-tracking/interfaces.ts b/apps/web/src/utils/error-tracking/interfaces.ts
index b0030e6..58926cb 100644
--- a/apps/web/src/utils/error-tracking/interfaces.ts
+++ b/apps/web/src/utils/error-tracking/interfaces.ts
@@ -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 {
diff --git a/apps/web/src/utils/imgproxy-loader.ts b/apps/web/src/utils/imgproxy-loader.ts
index 643871a..f05107e 100644
--- a/apps/web/src/utils/imgproxy-loader.ts
+++ b/apps/web/src/utils/imgproxy-loader.ts
@@ -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
diff --git a/eslint.config.js b/eslint.config.js
index e7e57fd..607513a 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -56,7 +56,7 @@ export default tseslint.config(
"typescript-eslint": tseslint.plugin,
},
rules: {
- "no-unused-vars": "warn",
+ "no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": [
"warn",
{
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 7435355..9ba531e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -98,6 +98,9 @@ importers:
'@directus/sdk':
specifier: 21.0.0
version: 21.0.0
+ '@emotion/is-prop-valid':
+ specifier: ^1.4.0
+ version: 1.4.0
'@mdx-js/loader':
specifier: ^3.1.1
version: 3.1.1(webpack@5.96.1(esbuild@0.27.3))
@@ -190,7 +193,7 @@ importers:
version: 0.27.3
framer-motion:
specifier: ^12.29.2
- version: 12.31.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ version: 12.31.2(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
ioredis:
specifier: ^5.9.1
version: 5.9.2
@@ -858,6 +861,12 @@ packages:
'@emnapi/wasi-threads@1.1.0':
resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==}
+ '@emotion/is-prop-valid@1.4.0':
+ resolution: {integrity: sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==}
+
+ '@emotion/memoize@0.9.0':
+ resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==}
+
'@esbuild-plugins/node-resolve@0.2.2':
resolution: {integrity: sha512-+t5FdX3ATQlb53UFDBRb4nqjYBz492bIrnVWvpQHpzZlu9BQL5HasMZhqc409ygUwOWCXZhrWr6NyZ6T6Y+cxw==}
peerDependencies:
@@ -9004,6 +9013,12 @@ snapshots:
tslib: 2.8.1
optional: true
+ '@emotion/is-prop-valid@1.4.0':
+ dependencies:
+ '@emotion/memoize': 0.9.0
+
+ '@emotion/memoize@0.9.0': {}
+
'@esbuild-plugins/node-resolve@0.2.2(esbuild@0.27.3)':
dependencies:
'@types/resolve': 1.20.6
@@ -13784,12 +13799,13 @@ snapshots:
fraction.js@5.3.4: {}
- framer-motion@12.31.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
+ framer-motion@12.31.2(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
dependencies:
motion-dom: 12.31.2
motion-utils: 12.29.2
tslib: 2.8.1
optionalDependencies:
+ '@emotion/is-prop-valid': 1.4.0
react: 19.2.4
react-dom: 19.2.4(react@19.2.4)