+ {/* Header */}
+
+
+
+
+
+ Zurück zur Startseite
+
+
+
+
+
+
+ {/* Main Content */}
+
+
+ {/* Post Header */}
+
+
+ {/* Post Content */}
+
+
+
+
{/* Modal for zoomed image */}
{zoomImgSrc && (
setZoomImgSrc(null)}
+ className="fixed inset-0 bg-black bg-opacity-90 z-50 flex items-center justify-center cursor-grab active:cursor-grabbing"
+ onMouseDown={handleMouseDown}
+ onMouseMove={handleMouseMove}
+ onMouseUp={handleMouseUp}
+ onMouseLeave={handleMouseUp}
+ onTouchStart={handleTouchStart}
+ onTouchMove={handleTouchMove}
+ onTouchEnd={handleTouchEnd}
onWheel={handleWheel}
- style={{ touchAction: 'none' }}
+ onClick={(e) => {
+ if (e.target === e.currentTarget) {
+ setZoomImgSrc(null);
+ }
+ }}
>
-
e.stopPropagation()}
+

+
+
+
)}
- {/* Mobile: Full width, no borders */}
-
- {/* Mobile back button */}
-
-
- {/* Mobile content - full width, optimized for reading */}
-
-
{post.title}
-
-
- {post.date ? (
-
Veröffentlicht: {format(new Date(post.date), 'd. MMMM yyyy')}
- ) : (
-
- ⚙️
- In Bearbeitung
-
- )}
-
Erstellt: {format(new Date(post.createdAt), 'd. MMMM yyyy HH:mm')}
-
-
-
- {post.tags.map((tag) => (
-
- {tag}
-
- ))}
-
-
- {/* Mobile-optimized prose content */}
-
-
-
-
- {/* Desktop: Wider content area with minimal borders */}
-
-
- {/* Desktop back button */}
-
-
- Zurück zu den Beiträgen
-
-
- {/* Desktop content with minimal border */}
-
-
{post.title}
-
-
- {post.date ? (
-
Veröffentlicht: {format(new Date(post.date), 'd. MMMM yyyy')}
- ) : (
-
- ⚙️
- In Bearbeitung
-
- )}
-
Erstellt: {format(new Date(post.createdAt), 'd. MMMM yyyy HH:mm')}
-
-
-
- {post.tags.map((tag) => (
-
- {tag}
-
- ))}
-
-
- {/* Desktop-optimized prose content */}
-
-
-
-
-
+
);
}
\ No newline at end of file
diff --git a/src/lib/markdown.ts b/src/lib/markdown.ts
deleted file mode 100644
index 8f36e2e..0000000
--- a/src/lib/markdown.ts
+++ /dev/null
@@ -1,272 +0,0 @@
-// This is the frontend Markdown parser.
-// It is written in TypeScript
-// While I was writing this, only I and God knew how it works.
-// Now, only God knows.
-//
-// If you are trying to understand how it works , and optimize it. Please increse the counter
-//
-// Hours wasted here: 12
-
-import fs from 'fs';
-import path from 'path';
-import matter from 'gray-matter';
-import { marked } from 'marked';
-import DOMPurify from 'dompurify';
-import { JSDOM } from 'jsdom';
-import chokidar from 'chokidar';
-import type { FSWatcher } from 'chokidar';
-import hljs from 'highlight.js';
-import { getPostsDirectory } from './postsDirectory';
-
-export interface Post {
- slug: string;
- title: string;
- date: string;
- tags: string[];
- summary: string;
- content: string;
- createdAt: Date;
- author: string;
-}
-
-const postsDirectory = getPostsDirectory();
-
-// Function to get file creation date
-function getFileCreationDate(filePath: string): Date {
- const stats = fs.statSync(filePath);
- return stats.birthtime;
-}
-
-// Function to generate ID from text (matches frontend logic)
-function generateId(text: string): string {
- return text
- .toLowerCase()
- .replace(/[^a-z0-9]+/g, '-')
- .replace(/^-+|-+$/g, '');
-}
-
-// Enhanced slugification function that matches GitHub-style anchor links
-function slugify(text: string): string {
- return text
- .toLowerCase()
- .trim()
- .replace(/[^\w\s-]/g, '') // Remove special characters except spaces and hyphens
- .replace(/[\s_-]+/g, '-') // Replace spaces, underscores, and multiple hyphens with single hyphen
- .replace(/^-+|-+$/g, ''); // Remove leading/trailing hyphens
-}
-
-// Function to process anchor links in markdown content
-function processAnchorLinks(content: string): string {
- // Find all markdown links that point to anchors (e.g., [text](#anchor))
- return content.replace(/\[([^\]]+)\]\(#([^)]+)\)/g, (match, linkText, anchor) => {
- // Only slugify if the anchor doesn't already look like a slug
- // This prevents double-processing of already-correct anchor links
- const isAlreadySlugified = /^[a-z0-9-]+$/.test(anchor);
- const slugifiedAnchor = isAlreadySlugified ? anchor : slugify(anchor);
- return `[${linkText}](#${slugifiedAnchor})`;
- });
-}
-
-// Utility function to debug anchor links (for development)
-export function debugAnchorLinks(content: string): void {
- if (process.env.NODE_ENV !== 'development') return;
-
- console.log('=== Anchor Link Debug Info ===');
-
- // Extract all headings and their IDs
- const headingRegex = /^(#{1,6})\s+(.+)$/gm;
- const headings: Array<{ level: number; text: string; id: string }> = [];
-
- let match;
- while ((match = headingRegex.exec(content)) !== null) {
- const level = match[1].length;
- const text = match[2].trim();
- const id = slugify(text);
- headings.push({ level, text, id });
- }
-
- console.log('Generated heading IDs:');
- headings.forEach(({ level, text, id }) => {
- console.log(` H${level}: "${text}" -> id="${id}"`);
- });
-
- // Extract all anchor links
- const anchorLinkRegex = /\[([^\]]+)\]\(#([^)]+)\)/g;
- const anchorLinks: Array<{ linkText: string; originalAnchor: string; slugifiedAnchor: string }> = [];
-
- while ((match = anchorLinkRegex.exec(content)) !== null) {
- const linkText = match[1];
- const originalAnchor = match[2];
- const slugifiedAnchor = slugify(originalAnchor);
- anchorLinks.push({ linkText, originalAnchor, slugifiedAnchor });
- }
-
- console.log('Anchor links found:');
- anchorLinks.forEach(({ linkText, originalAnchor, slugifiedAnchor }) => {
- const headingExists = headings.some(h => h.id === slugifiedAnchor);
- const status = headingExists ? '✅' : '❌';
- console.log(` ${status} [${linkText}](#${originalAnchor}) -> [${linkText}](#${slugifiedAnchor})`);
- });
-
- // Show missing headings
- const missingAnchors = anchorLinks.filter(({ slugifiedAnchor }) =>
- !headings.some(h => h.id === slugifiedAnchor)
- );
-
- if (missingAnchors.length > 0) {
- console.warn('Missing headings for these anchor links:');
- missingAnchors.forEach(({ linkText, originalAnchor, slugifiedAnchor }) => {
- console.warn(` - [${linkText}](#${originalAnchor}) -> id="${slugifiedAnchor}"`);
- });
- }
-
- console.log('=== End Debug Info ===');
-}
-
-const renderer = new marked.Renderer();
-
-// Custom heading renderer to add IDs
-renderer.heading = (text, level) => {
- const id = slugify(text);
- return `