Initial commit

This commit is contained in:
2025-08-03 18:48:24 +02:00
parent 49bb62fc4e
commit 62ebe48adb
14 changed files with 1262 additions and 1092 deletions

View File

@@ -1,3 +1,4 @@
// components/ImprovedCategoryFilter.jsx
import React from "react";
import { motion } from "framer-motion";
import { Button } from "@/components/ui/button";
@@ -13,31 +14,31 @@ export default function ImprovedCategoryFilter({
{
id: 'all',
name: '🔥 All Fonts',
description: 'Complete collection',
description: 'Complete collection of 60 styles',
gradient: 'from-pink-500 to-purple-600'
},
{
id: 'modern',
name: '🔤 Modern',
description: 'Clean & professional',
description: 'Clean & professional fonts',
gradient: 'from-blue-500 to-indigo-600'
},
{
id: 'handwriting',
name: '✍️ Handwriting',
description: 'Personal & casual',
description: 'Personal, casual and handwritten',
gradient: 'from-green-500 to-emerald-600'
},
{
id: 'statement',
name: '🧑‍🎤 Statement',
description: 'Bold & eye-catching',
description: 'Bold & attention-grabbing',
gradient: 'from-red-500 to-pink-600'
},
{
id: 'futuristic',
name: '🚀 Futuristic',
description: 'Tech & gaming',
description: 'Tech & gaming inspired',
gradient: 'from-purple-500 to-violet-600'
},
{
@@ -59,7 +60,7 @@ export default function ImprovedCategoryFilter({
<div className="text-center mb-6">
<h2 className="text-2xl font-bold text-white mb-2">Choose Your Style</h2>
<p className="text-white/70 text-sm">
Browse fonts by category or view all {fontCounts.all} unique styles
Browse fonts by category or view all {fontCounts?.all ?? 60} unique styles
</p>
</div>
@@ -97,7 +98,7 @@ export default function ImprovedCategoryFilter({
: 'bg-white/10 text-white/80 border-white/20'
}`}
>
{fontCounts[category.id] || 0} fonts
{fontCounts?.[category.id] ?? 0} fonts
</Badge>
</div>
</Button>
@@ -114,7 +115,7 @@ export default function ImprovedCategoryFilter({
>
<div className="bg-white/10 backdrop-blur-sm rounded-lg p-3 inline-block">
<p className="text-white/80 text-sm">
Showing <span className="font-semibold text-white">{fontCounts[selectedCategory]}</span> fonts
Showing <span className="font-semibold text-white">{fontCounts?.[selectedCategory] ?? 0}</span> fonts
in <span className="font-semibold text-white">{categories.find(c => c.id === selectedCategory)?.name}</span> category
</p>
</div>
@@ -122,4 +123,4 @@ export default function ImprovedCategoryFilter({
)}
</motion.div>
);
}
}

View File

@@ -95,26 +95,16 @@ const PerformanceOptimizedFontCard = forwardRef(({
const getFontStyle = useCallback((name) => {
const baseStyle = { wordBreak: "break-word", lineHeight: "1.3", willChange: "auto" };
const fontMap = {
Montserrat: { fontFamily: "Montserrat, sans-serif", fontWeight: "500" },
'Bebas Neue': { fontFamily: '"Bebas Neue", cursive', fontWeight: "400", textTransform: "uppercase", letterSpacing: "0.05em" },
Oswald: { fontFamily: "Oswald, sans-serif", fontWeight: "500", textTransform: "uppercase" },
Raleway: { fontFamily: "Raleway, sans-serif", fontWeight: "400" },
Poppins: { fontFamily: "Poppins, sans-serif", fontWeight: "500" },
Inter: { fontFamily: "Inter, sans-serif", fontWeight: "400" },
Caveat: { fontFamily: "Caveat, cursive", fontWeight: "400" },
Pacifico: { fontFamily: "Pacifico, cursive", fontWeight: "400" },
'Dancing Script': { fontFamily: '"Dancing Script", cursive', fontWeight: "400" },
'Amatic SC': { fontFamily: '"Amatic SC", cursive', fontWeight: "400" },
Anton: { fontFamily: "Anton, sans-serif", fontWeight: "400", textTransform: "uppercase" },
'Luckiest Guy': { fontFamily: '"Luckiest Guy", cursive', fontWeight: "400", textTransform: "uppercase" },
'Fredoka One': { fontFamily: '"Fredoka One", cursive', fontWeight: "400" },
Bangers: { fontFamily: "Bangers, cursive", fontWeight: "400", textTransform: "uppercase" },
Orbitron: { fontFamily: "Orbitron, sans-serif", fontWeight: "400" },
'Press Start 2P': { fontFamily: '"Press Start 2P", cursive', fontWeight: "400", fontSize: "0.85em" },
'Playfair Display': { fontFamily: '"Playfair Display", serif', fontWeight: "400" }
};
return { ...baseStyle, ...(fontMap[name] || {}) };
const fontEntry = fontTransforms[name];
if (!fontEntry) return baseStyle;
const style = { ...baseStyle };
if (fontEntry.fontFamily) style.fontFamily = fontEntry.fontFamily;
if (fontEntry.fontWeight) style.fontWeight = fontEntry.fontWeight;
if (fontEntry.textTransform) style.textTransform = fontEntry.textTransform;
if (fontEntry.letterSpacing) style.letterSpacing = fontEntry.letterSpacing;
if (fontEntry.fontSize) style.fontSize = fontEntry.fontSize;
return style;
}, []);
const previewText = sStr(transformedText) || "Hallo Instagram!";
@@ -185,7 +175,7 @@ const PerformanceOptimizedFontCard = forwardRef(({
{copied ? (
<><Check className="w-4 h-4 mr-2" /> Copy! </>
) : (
<><Copy className="w-4 h-4 mr-2" /> Copy! </>
<><Copy className="w-4 h-4 mr-2" /> Start Typing </>
)}
</Button>
</div>

View File

@@ -1,20 +1,18 @@
// components/fontTransforms.jsx
// Unicode-basiertes Font-Transformationsmapping für deine aktuelle Font-Liste
// Nutzt verschiedene Unicode-Blöcke, damit beim Kopieren der "fancy" Stil erhalten bleibt.
// 1) Definition der Unicode-Blöcke (Startpunkte)
// 1) Unicode-Blöcke (Startpunkte)
const unicodeBlocks = {
sansSerif: { upperStart: 0x1D5A0, lowerStart: 0x1D5BA }, // Mathematical Sans-Serif
sansSerifBold: { upperStart: 0x1D5D4, lowerStart: 0x1D5EE }, // Bold Sans-Serif
script: { upperStart: 0x1D49C, lowerStart: 0x1D4B6 }, // Mathematical Script
scriptBold: { upperStart: 0x1D4D0, lowerStart: 0x1D4EA }, // Bold Script
fraktur: { upperStart: 0x1D504, lowerStart: 0x1D51E }, // Mathematical Fraktur
frakturBold: { upperStart: 0x1D56C, lowerStart: 0x1D586 }, // Bold Fraktur
monospace: { upperStart: 0x1D670, lowerStart: 0x1D68A }, // Mathematical Monospace
fullwidth: { upperStart: 0xFF21, lowerStart: 0xFF41 } // Fullwidth Latin
sansSerif: { upperStart: 0x1D5A0, lowerStart: 0x1D5BA },
sansSerifBold: { upperStart: 0x1D5D4, lowerStart: 0x1D5EE },
script: { upperStart: 0x1D49C, lowerStart: 0x1D4B6 },
scriptBold: { upperStart: 0x1D4D0, lowerStart: 0x1D4EA },
fraktur: { upperStart: 0x1D504, lowerStart: 0x1D51E },
frakturBold: { upperStart: 0x1D56C, lowerStart: 0x1D586 },
monospace: { upperStart: 0x1D670, lowerStart: 0x1D68A },
fullwidth: { upperStart: 0xFF21, lowerStart: 0xFF41 }
};
// 2) Helfer zum Mappen von A-Z und a-z in den jeweiligen Unicode-Block
// 2) Unicode-Mapping-Helfer
const mapUnicode = (char, block) => {
const code = char.charCodeAt(0);
if (code >= 65 && code <= 90) return String.fromCodePoint(block.upperStart + (code - 65));
@@ -23,64 +21,105 @@ const mapUnicode = (char, block) => {
};
const createTransform = (blockKey) => (text) =>
text
.split('')
.map((c) => mapUnicode(c, unicodeBlocks[blockKey]))
.join('');
text.split('').map((c) => mapUnicode(c, unicodeBlocks[blockKey])).join('');
// 3) Font-Transformations für deine Liste
export const fontTransforms = {
// 🔤 Modern Clean & professional
Montserrat: { transform: createTransform('sansSerifBold'), category: 'modern', description: 'Montserrat Sans-Serif Bold Unicode' },
Lato: { transform: createTransform('sansSerif'), category: 'modern', description: 'Lato Humanistischer Sans-Serif Unicode' },
Raleway: { transform: createTransform('sansSerif'), category: 'modern', description: 'Raleway Elegant Display Unicode' },
Poppins: { transform: createTransform('sansSerif'), category: 'modern', description: 'Poppins Rund & freundlich Unicode' },
'Open Sans': { transform: createTransform('sansSerif'), category: 'modern', description: 'Open Sans Vielseitig Unicode' },
Roboto: { transform: createTransform('sansSerif'), category: 'modern', description: 'Roboto Modernes Grotesk Unicode' },
'Work Sans': { transform: createTransform('sansSerif'), category: 'modern', description: 'Work Sans Tech & Clean Unicode' },
// 3) Font-Transformationen
export const fontTransforms = Object.fromEntries(
Object.entries({
// 🔤 Modern
Montserrat: ['sansSerifBold', 'modern', 'Montserrat Sans-Serif Bold Unicode'],
Lato: ['sansSerif', 'modern', 'Lato Humanistischer Sans-Serif Unicode'],
Raleway: ['sansSerif', 'modern', 'Raleway Elegant Display Unicode'],
Poppins: ['sansSerif', 'modern', 'Poppins Rund & freundlich Unicode'],
'Open Sans': ['sansSerif', 'modern', 'Open Sans Vielseitig Unicode'],
Roboto: ['sansSerif', 'modern', 'Roboto Modernes Grotesk Unicode'],
'Work Sans': ['sansSerif', 'modern', 'Work Sans Tech & Clean Unicode'],
'Noto Sans': ['sansSerif', 'modern', 'Noto Sans International Unicode'],
Jost: ['sansSerif', 'modern', 'Jost Geometrisch modern Unicode'],
Quicksand: ['sansSerif', 'modern', 'Quicksand Soft Rounded Unicode'],
'Averia Libre': ['sansSerif', 'modern', 'Averia Libre Experimentell Unicode'],
'Philosopher': ['sansSerif', 'modern', 'Philosopher Elegant Unicode'],
// ✍️ Handwriting Personal & casual
Pacifico: { transform: createTransform('scriptBold'), category: 'handwriting', description: 'Pacifico Lockerer Pinsel Bold Script Unicode' },
Sacramento: { transform: createTransform('scriptBold'), category: 'handwriting', description: 'Sacramento Retro-Handlettering Bold Script Unicode' },
Caveat: { transform: createTransform('scriptBold'), category: 'handwriting', description: 'Caveat Natural Handwriting Bold Script Unicode' },
'Dancing Script': { transform: createTransform('scriptBold'), category: 'handwriting', description: 'Dancing Script Lebhafte Kursive Bold Script Unicode' },
'Indie Flower': { transform: createTransform('scriptBold'), category: 'handwriting', description: 'Indie Flower Verspieltes Bold Script Unicode' },
'Amatic SC': { transform: createTransform('scriptBold'), category: 'handwriting', description: 'Amatic SC Skizzenartiges Bold Script Unicode' },
'Kaushan Script': { transform: createTransform('scriptBold'), category: 'handwriting', description: 'Kaushan Script Fettere Kursive Bold Script Unicode' },
// ✍️ Handwriting
Pacifico: ['scriptBold', 'handwriting', 'Pacifico Lockerer Pinsel Bold Script Unicode'],
Sacramento: ['scriptBold', 'handwriting', 'Sacramento Retro-Handlettering Bold Script Unicode'],
Caveat: ['scriptBold', 'handwriting', 'Caveat Natural Handwriting Bold Script Unicode'],
'Dancing Script': ['scriptBold', 'handwriting', 'Dancing Script Lebhafte Kursive Bold Script Unicode'],
'Indie Flower': ['scriptBold', 'handwriting', 'Indie Flower Verspieltes Bold Script Unicode'],
'Amatic SC': ['scriptBold', 'handwriting', 'Amatic SC Skizzenartiges Bold Script Unicode'],
'Kaushan Script': ['scriptBold', 'handwriting', 'Kaushan Script Fettere Kursive Bold Script Unicode'],
'Architects Daughter': ['scriptBold','handwriting', 'Architects Daughter Skizzenhafte Handschrift Unicode'],
Neucha: ['scriptBold', 'handwriting', 'Neucha Persönlich und kantig Unicode'],
'Great Vibes': ['scriptBold', 'handwriting', 'Great Vibes Elegante Kalligraphie Unicode'],
Satisfy: ['scriptBold', 'handwriting', 'Satisfy Weiche Script Unicode'],
Yellowtail: ['scriptBold', 'handwriting', 'Yellowtail Vintage Script Unicode'],
'Gloria Hallelujah': ['scriptBold', 'handwriting', 'Gloria Hallelujah Lebendige Handschrift Unicode'],
// 🧑‍🎤 Statement Bold & eye-catching
Oswald: { transform: createTransform('sansSerifBold'), category: 'statement', description: 'Oswald Bold Grotesk Unicode' },
'Bebas Neue': { transform: createTransform('fullwidth'), category: 'statement', description: 'Bebas Neue Fullwidth Caps Unicode' },
Anton: { transform: createTransform('fullwidth'), category: 'statement', description: 'Anton Plakative Fullwidth Unicode' },
Ultra: { transform: createTransform('sansSerifBold'), category: 'statement', description: 'Ultra Kompakte Bold Unicode' },
'Stint Ultra Condensed': { transform: createTransform('sansSerifBold'), category: 'statement', description: 'Stint Ultra Condensed Kompakte Bold Unicode' },
'Playfair Display': { transform: createTransform('scriptBold'), category: 'statement', description: 'Playfair Display Elegante Bold Script Unicode' },
'Abril Fatface': { transform: createTransform('scriptBold'), category: 'statement', description: 'Abril Fatface Fettere Bold Script Unicode' },
// 🧑‍🎤 Statement
Oswald: ['sansSerifBold', 'statement', 'Oswald Bold Grotesk Unicode'],
'Bebas Neue': ['fullwidth', 'statement', 'Bebas Neue Fullwidth Caps Unicode'],
Anton: ['fullwidth', 'statement', 'Anton Plakative Fullwidth Unicode'],
Ultra: ['sansSerifBold', 'statement', 'Ultra Kompakte Bold Unicode'],
'Stint Ultra Condensed': ['sansSerifBold', 'statement', 'Stint Ultra Condensed Kompakte Bold Unicode'],
'Playfair Display': ['scriptBold', 'statement', 'Playfair Display Elegante Bold Script Unicode'],
'Abril Fatface': ['scriptBold', 'statement', 'Abril Fatface Fettere Bold Script Unicode'],
'Permanent Marker': ['scriptBold', 'statement', 'Permanent Marker Marker-Style Unicode'],
'Alfa Slab One': ['fullwidth', 'statement', 'Alfa Slab One Slab Serif Heavy Unicode'],
'Black Ops One': ['fullwidth', 'statement', 'Black Ops One Military Display Unicode'],
'Germania One': ['frakturBold', 'statement', 'Germania One Oldstyle Fraktur Unicode'],
'Holtwood One SC': ['fullwidth', 'statement', 'Holtwood One SC Klassisch Bold Small Caps Unicode'],
Courgette: ['scriptBold', 'statement', 'Courgette Verspieltes Script Unicode'],
// 🚀 Futuristic Tech & gaming
Exo: { transform: createTransform('sansSerif'), category: 'futuristic', description: 'Exo Tech Grotesk Unicode' },
Orbitron: { transform: createTransform('monospace'), category: 'futuristic', description: 'Orbitron Sci-Fi Monospace Unicode' },
Audiowide: { transform: createTransform('monospace'), category: 'futuristic', description: 'Audiowide Rundes Monospace Unicode' },
Rajdhani: { transform: createTransform('monospace'), category: 'futuristic', description: 'Rajdhani Digital Monospace Unicode' },
'Space Mono': { transform: createTransform('monospace'), category: 'futuristic', description: 'Space Mono Tech Monospace Unicode' },
Questrial: { transform: createTransform('sansSerif'), category: 'futuristic', description: 'Questrial Clean Sans-Serif Unicode' },
// 🚀 Futuristic
Exo: ['sansSerif', 'futuristic', 'Exo Tech Grotesk Unicode'],
Orbitron: ['monospace', 'futuristic', 'Orbitron Sci-Fi Monospace Unicode'],
Audiowide: ['monospace', 'futuristic', 'Audiowide Rundes Monospace Unicode'],
Rajdhani: ['monospace', 'futuristic', 'Rajdhani Digital Monospace Unicode'],
'Space Mono': ['monospace', 'futuristic', 'Space Mono Tech Monospace Unicode'],
Questrial: ['sansSerif', 'futuristic', 'Questrial Clean Sans-Serif Unicode'],
'Syncopate': ['monospace', 'futuristic', 'Syncopate Techno Unicode'],
'Unica One': ['monospace', 'futuristic', 'Unica One Monospace Mix Unicode'],
'Italiana': ['sansSerif', 'futuristic', 'Italiana Futuristisch Serif Unicode'],
'Staatliches': ['monospace', 'futuristic', 'Staatliches Moderne Grotesk Unicode'],
// 🧢 Aesthetic Retro & Instagram vibes
'Press Start 2P': { transform: createTransform('monospace'), category: 'aesthetic', description: 'Press Start 2P Pixel Monospace Unicode' },
Righteous: { transform: createTransform('frakturBold'), category: 'aesthetic', description: 'Righteous Stylische Bold Fraktur Unicode' },
'Metal Mania': { transform: createTransform('scriptBold'), category: 'aesthetic', description: 'Metal Mania Fettere Script Unicode' }
};
// Hilfsfunktionen
export const getPopularFonts = () => Object.keys(fontTransforms).slice(0, 10);
export const getFontsByCategory = (category) => (
category === 'all'
? Object.keys(fontTransforms)
: Object.keys(fontTransforms).filter(f => fontTransforms[f].category === category)
// 🧢 Aesthetic
'Press Start 2P': ['monospace', 'aesthetic', 'Press Start 2P Pixel Monospace Unicode'],
Righteous: ['frakturBold', 'aesthetic', 'Righteous Stylische Bold Fraktur Unicode'],
'Metal Mania': ['scriptBold', 'aesthetic', 'Metal Mania Fettere Script Unicode'],
'Alegreya': ['frakturBold', 'aesthetic', 'Alegreya Literatur Serif Unicode'],
'Spectral': ['frakturBold', 'aesthetic', 'Spectral Editorial Serif Unicode'],
'Fjalla One': ['sansSerifBold', 'aesthetic', 'Fjalla One Headline Sans Unicode'],
'Glass Antiqua': ['scriptBold', 'aesthetic', 'Glass Antiqua Zarte Antiqua Script Unicode'],
'Cinzel Decorative': ['scriptBold', 'aesthetic', 'Cinzel Decorative Klassische Zier-Serif Unicode'],
'Andika': ['sansSerif', 'aesthetic', 'Andika Leserlich Unicode'],
'Almendra': ['scriptBold', 'aesthetic', 'Almendra Historische Handschrift Unicode'],
}).map(([name, [block, category, description]]) => [
name,
{
transform: createTransform(block),
category,
description,
className: `font-${name.toLowerCase().replace(/\s+/g, '')}`,
},
])
);
// 🔝 Neue transformText-Funktion gibt transformierten Text **und** Tailwind-Klasse zurück
export const transformText = (text, fontName) => {
const font = fontTransforms[fontName];
if (!font || !text) return text;
return font.transform(text);
if (!font || !text) return { transformed: text, fontClassName: '' };
return {
transformed: font.transform(text),
fontClassName: font.className,
};
};
// Weitere Helfer
export const getPopularFonts = () => Object.keys(fontTransforms).slice(0, 10);
export const getFontsByCategory = (category) =>
category === 'all'
? Object.keys(fontTransforms)
: Object.keys(fontTransforms).filter(
(f) => fontTransforms[f].category === category
);

View File

@@ -4,8 +4,9 @@ import { Card } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Copy, Check, Heart, Share2, Info } from "lucide-react";
import { fontTransforms } from "../fontTransforms";
import { transformText, fontTransforms } from "../fontTransforms";
import { getFontData } from "@/lib/fonts";
import fontMap from "@/lib/tailwind-font-map";
export default function FontCard({
fontName,
@@ -19,12 +20,20 @@ export default function FontCard({
const fontInfo = fontTransforms[fontName];
const fontData = getFontData(fontName);
const displayText = transformedText || "Hallo Instagram!";
const fontKey = fontName.toLowerCase().replace(/\s+/g, "");
const fontVarName = fontMap[fontKey];
const fontVar = fontVarName ? { fontFamily: `var(${fontVarName})` } : {};
const fontClass = fontData?.className || "";
const rawText = "Hallo Instagram!";
const transformed = transformText(rawText, fontName);
const finalText = transformed?.transformed || rawText;
const copyText = transformed?.transformed || rawText;
const handleCopy = () => {
if (navigator.clipboard && window.isSecureContext) {
navigator.clipboard
.writeText(displayText)
.writeText(copyText)
.then(() => flashCopied())
.catch(() => fallbackCopy());
} else {
@@ -39,7 +48,7 @@ export default function FontCard({
const fallbackCopy = () => {
const textarea = document.createElement("textarea");
textarea.value = displayText;
textarea.value = copyText;
textarea.setAttribute("readonly", "");
textarea.style.position = "fixed";
textarea.style.top = "0";
@@ -69,7 +78,7 @@ export default function FontCard({
try {
await navigator.share({
title: `FancyText ${fontName}`,
text: displayText,
text: copyText,
url: window.location.href,
});
} catch (err) {
@@ -124,10 +133,10 @@ export default function FontCard({
<input
type="text"
value={displayText}
value={finalText}
readOnly
className={`${fontData.className} text-2xl md:text-3xl mb-6 p-4 bg-gray-50 rounded-xl text-center text-gray-800 min-h-[80px] w-full select-all border-0 focus:ring-0`}
style={{ lineHeight: "1.2" }}
className={`${fontClass} text-2xl md:text-3xl mb-6 p-4 bg-gray-50 rounded-xl text-center text-gray-800 min-h-[80px] w-full select-all border-0 focus:ring-0`}
style={{ ...fontVar, lineHeight: "1.2" }}
/>
<Button