feat: port all template categories to JSON format
- Ported Minimalist templates to JSON (Swiss Grid, Brutalist, etc.) - Ported Tech templates to JSON (SaaS, Terminal, Cyberpunk, etc.) - Ported Creative templates to JSON (Art Gallery, Zine, Pop Art, etc.) - Ported Industrial templates to JSON (Blueprint, Factory, Schematic, etc.) - Ported Nature templates to JSON (Botanical, Ocean, Mountain, etc.) - Ported Lifestyle templates to JSON (Cookbook, Travel, Coffee House, etc.) - Ported Vintage templates to JSON (Art Deco, Medieval, Retro 80s, etc.) - Updated README.md to reflect the new JSON-based style system (example configuration and contribution workflow) - Completed migration of over 150 styles to the new architecture
This commit is contained in:
471
src/App.tsx
471
src/App.tsx
@@ -1,41 +1,145 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import { motion, AnimatePresence } from 'motion/react';
|
||||
import { AppState, PaperSize } from './types';
|
||||
import { FileUpload } from './components/FileUpload';
|
||||
import { StyleSelector } from './components/StyleSelector';
|
||||
import { Preview } from './components/Preview';
|
||||
import { ZoomControl } from './components/ZoomControl';
|
||||
import { useSettings } from './hooks/useSettings';
|
||||
import { useTemplates } from './hooks/useTemplates';
|
||||
// @ts-ignore
|
||||
import { parse } from 'marked';
|
||||
import { Sparkles, Loader2, FileType } from 'lucide-react';
|
||||
import { Sparkles, Loader2, FileType, Keyboard, X, RefreshCw } from 'lucide-react';
|
||||
|
||||
import { useKeyboardNavigation } from './hooks/useKeyboardNavigation';
|
||||
|
||||
// Keyboard shortcuts help component
|
||||
const KeyboardShortcutsHelp: React.FC<{ onClose: () => void }> = ({ onClose }) => {
|
||||
const shortcuts = [
|
||||
{ key: '↑ / ↓', description: 'Navigate styles' },
|
||||
{ key: '← / →', description: 'Navigate categories (when focused)' },
|
||||
{ key: 'Enter', description: 'Select style or category' },
|
||||
{ key: 'Home / End', description: 'First/last item' },
|
||||
{ key: 'PgUp / PgDn', description: 'Jump 5 items' },
|
||||
{ key: 'Tab', description: 'Switch between sections' },
|
||||
{ key: 'Ctrl + Enter', description: 'Generate document' },
|
||||
{ key: 'Escape', description: 'Go back / Close' },
|
||||
];
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
className="fixed inset-0 bg-black/50 backdrop-blur-sm z-50 flex items-center justify-center p-4"
|
||||
onClick={onClose}
|
||||
>
|
||||
<motion.div
|
||||
initial={{ scale: 0.9, opacity: 0 }}
|
||||
animate={{ scale: 1, opacity: 1 }}
|
||||
exit={{ scale: 0.9, opacity: 0 }}
|
||||
className="bg-zinc-900 border border-zinc-700 rounded-2xl p-6 max-w-md w-full shadow-2xl"
|
||||
onClick={e => e.stopPropagation()}
|
||||
>
|
||||
<div className="flex justify-between items-center mb-6">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="p-2 bg-indigo-500/10 rounded-lg text-indigo-400">
|
||||
<Keyboard size={20} />
|
||||
</div>
|
||||
<h2 className="text-xl font-bold text-white">Keyboard Shortcuts</h2>
|
||||
</div>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="p-1 hover:bg-zinc-800 rounded-lg text-zinc-400 hover:text-white transition-colors"
|
||||
>
|
||||
<X size={20} />
|
||||
</button>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
{shortcuts.map((shortcut, index) => (
|
||||
<motion.div
|
||||
key={shortcut.key}
|
||||
initial={{ opacity: 0, x: -10 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ delay: index * 0.05 }}
|
||||
className="flex justify-between items-center py-2 border-b border-zinc-800 last:border-0"
|
||||
>
|
||||
<span className="text-zinc-400">{shortcut.description}</span>
|
||||
<kbd className="px-2 py-1 bg-zinc-800 rounded text-sm font-mono text-zinc-300 border border-zinc-700">
|
||||
{shortcut.key}
|
||||
</kbd>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
<p className="mt-6 text-xs text-zinc-500 text-center">
|
||||
Press Escape or click outside to close
|
||||
</p>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
);
|
||||
};
|
||||
|
||||
const App: React.FC = () => {
|
||||
const [appState, setAppState] = useState<AppState>(AppState.UPLOAD);
|
||||
const [content, setContent] = useState<string>('');
|
||||
const [inputFileName, setInputFileName] = useState<string>('');
|
||||
const [selectedStyle, setSelectedStyle] = useState<string | null>(null);
|
||||
const [paperSize, setPaperSize] = useState<PaperSize>('Letter');
|
||||
const [generatedHtml, setGeneratedHtml] = useState<string>('');
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [showShortcuts, setShowShortcuts] = useState(false);
|
||||
|
||||
const handleFileLoaded = (text: string) => {
|
||||
const { uiZoom, setUiZoom, isLoaded } = useSettings();
|
||||
const { templates, categories, isLoading: templatesLoading, error: templatesError, refresh, openFolder } = useTemplates();
|
||||
|
||||
// Global keyboard shortcut: Toggle help with ? or /
|
||||
useKeyboardNavigation({
|
||||
onEnter: undefined,
|
||||
}, []);
|
||||
|
||||
// Note: Native file drop is handled by the FileUpload component
|
||||
// The Tauri file drop is disabled to allow the webview to handle drag events
|
||||
// This preserves the drag hover animations in the FileUpload component
|
||||
|
||||
// Global keydown listener for shortcuts help
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (e.key === '?' || e.key === '/') {
|
||||
e.preventDefault();
|
||||
setShowShortcuts(prev => !prev);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('keydown', handleKeyDown);
|
||||
return () => window.removeEventListener('keydown', handleKeyDown);
|
||||
}, []);
|
||||
|
||||
|
||||
|
||||
const handleFileLoaded = (text: string, fileName: string = '') => {
|
||||
setContent(text);
|
||||
setInputFileName(fileName);
|
||||
setAppState(AppState.CONFIG);
|
||||
};
|
||||
|
||||
const handleGenerate = async () => {
|
||||
const handleGenerate = useCallback(async () => {
|
||||
if (!selectedStyle || !content) return;
|
||||
|
||||
|
||||
setAppState(AppState.GENERATING);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
// Small artificial delay to show the "Processing" state for better UX,
|
||||
// otherwise it flickers too fast since local parsing is instant.
|
||||
await new Promise(resolve => setTimeout(resolve, 800));
|
||||
|
||||
// Parse markdown to HTML using the local 'marked' library
|
||||
const html = await parse(content);
|
||||
|
||||
|
||||
if (!html) throw new Error("No content generated");
|
||||
|
||||
|
||||
console.log('--- STAGE 1: MARKDOWN GENERATION ---');
|
||||
console.log('First 500 chars of HTML:', html.substring(0, 500));
|
||||
console.log('Contains h1?', html.includes('<h1'));
|
||||
console.log('Contains h3?', html.includes('<h3'));
|
||||
console.log('Contains table?', html.includes('<table'));
|
||||
|
||||
setGeneratedHtml(html);
|
||||
setAppState(AppState.PREVIEW);
|
||||
} catch (err) {
|
||||
@@ -43,123 +147,298 @@ const App: React.FC = () => {
|
||||
setError("Failed to process the document. Please check your file format and try again.");
|
||||
setAppState(AppState.CONFIG);
|
||||
}
|
||||
};
|
||||
}, [selectedStyle, content]);
|
||||
|
||||
const handleReset = () => {
|
||||
setAppState(AppState.UPLOAD);
|
||||
setContent('');
|
||||
setGeneratedHtml('');
|
||||
setSelectedStyle(null);
|
||||
setInputFileName('');
|
||||
};
|
||||
|
||||
const handleBackToConfig = () => {
|
||||
setAppState(AppState.CONFIG);
|
||||
};
|
||||
|
||||
// Render Logic
|
||||
if (!isLoaded) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (appState === AppState.PREVIEW) {
|
||||
// Pass selectedStyleId to Preview so it can lookup font config
|
||||
// We add the prop via spread or explicit
|
||||
return (
|
||||
// @ts-ignore - Adding prop dynamically if interface not fully updated in previous file change block (it was)
|
||||
<Preview
|
||||
htmlContent={generatedHtml}
|
||||
onBack={handleBackToConfig}
|
||||
<div
|
||||
className="h-screen w-screen overflow-hidden"
|
||||
style={{ fontSize: `${uiZoom}%` }}
|
||||
>
|
||||
<div className="h-full w-full flex flex-col">
|
||||
<Preview
|
||||
htmlContent={generatedHtml}
|
||||
onBack={handleBackToConfig}
|
||||
paperSize={paperSize}
|
||||
// @ts-ignore
|
||||
selectedStyleId={selectedStyle}
|
||||
/>
|
||||
selectedStyleId={selectedStyle}
|
||||
inputFileName={inputFileName}
|
||||
uiZoom={uiZoom}
|
||||
onZoomChange={setUiZoom}
|
||||
templates={templates}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-zinc-950 text-zinc-100 flex flex-col font-sans selection:bg-indigo-500/30">
|
||||
|
||||
{/* Header */}
|
||||
<header className="border-b border-zinc-800 bg-zinc-950/50 backdrop-blur-sm sticky top-0 z-40">
|
||||
<div
|
||||
className="h-screen bg-zinc-950 text-zinc-100 flex flex-col font-sans selection:bg-indigo-500/30 overflow-hidden"
|
||||
style={{ fontSize: `${uiZoom}%` }}
|
||||
>
|
||||
|
||||
{/* Keyboard Shortcuts Modal */}
|
||||
<AnimatePresence>
|
||||
{showShortcuts && (
|
||||
<KeyboardShortcutsHelp onClose={() => setShowShortcuts(false)} />
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
{/* Header - Fixed height */}
|
||||
<motion.header
|
||||
initial={{ y: -20, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
transition={{ duration: 0.5, ease: [0.22, 1, 0.36, 1] }}
|
||||
className="flex-none border-b border-zinc-800 bg-zinc-950/50 backdrop-blur-sm z-40"
|
||||
>
|
||||
<div className="max-w-7xl mx-auto px-6 h-16 flex items-center justify-between">
|
||||
<div className="flex items-center gap-2 cursor-pointer" onClick={handleReset}>
|
||||
<div className="bg-gradient-to-br from-indigo-500 to-violet-600 p-2 rounded-lg">
|
||||
<motion.div
|
||||
className="flex items-center gap-2 cursor-pointer"
|
||||
onClick={handleReset}
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
<motion.div
|
||||
className="bg-gradient-to-br from-indigo-500 to-violet-600 p-2 rounded-lg"
|
||||
whileHover={{ rotate: [0, -10, 10, 0], transition: { duration: 0.5 } }}
|
||||
>
|
||||
<FileType className="text-white" size={20} />
|
||||
</div>
|
||||
</motion.div>
|
||||
<h1 className="text-xl font-bold tracking-tight text-white">TypoGenie</h1>
|
||||
</div>
|
||||
{appState !== AppState.UPLOAD && (
|
||||
<div className="flex items-center gap-4 text-sm text-zinc-500">
|
||||
<span className={appState === AppState.CONFIG ? "text-indigo-400 font-medium" : ""}>Configure</span>
|
||||
<span>/</span>
|
||||
<span className={appState === AppState.GENERATING ? "text-indigo-400 font-medium" : ""}>Generate</span>
|
||||
<span>/</span>
|
||||
<span>Preview</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</header>
|
||||
</motion.div>
|
||||
|
||||
{/* Main Content */}
|
||||
<main className="flex-grow flex flex-col relative">
|
||||
<div className="absolute inset-0 overflow-hidden pointer-events-none">
|
||||
<div className="absolute -top-[20%] -left-[10%] w-[50%] h-[50%] bg-indigo-900/10 rounded-full blur-3xl"></div>
|
||||
<div className="absolute top-[20%] -right-[10%] w-[40%] h-[40%] bg-violet-900/10 rounded-full blur-3xl"></div>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
{/* UI Zoom Control */}
|
||||
<ZoomControl zoom={uiZoom} onZoomChange={setUiZoom} />
|
||||
|
||||
<div className="relative z-10 w-full max-w-7xl mx-auto px-6 py-12 flex-grow flex flex-col">
|
||||
|
||||
{appState === AppState.UPLOAD && (
|
||||
<div className="flex flex-col items-center justify-center flex-grow space-y-8 animate-in fade-in zoom-in-95 duration-500">
|
||||
<div className="text-center space-y-4 max-w-2xl">
|
||||
<h2 className="text-4xl md:text-5xl font-extrabold tracking-tight text-white">
|
||||
Turn Markdown into <br/>
|
||||
<span className="text-transparent bg-clip-text bg-gradient-to-r from-indigo-400 to-violet-400">
|
||||
Professional Word Docs.
|
||||
</span>
|
||||
</h2>
|
||||
<p className="text-lg text-zinc-400 leading-relaxed">
|
||||
Upload your raw text. Select a style.
|
||||
Get a formatted DOCX file ready for Microsoft Word.
|
||||
</p>
|
||||
</div>
|
||||
<FileUpload onFileLoaded={handleFileLoaded} />
|
||||
</div>
|
||||
)}
|
||||
{/* Refresh templates button */}
|
||||
{appState === AppState.CONFIG && (
|
||||
<motion.button
|
||||
onClick={refresh}
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
className="hidden sm:flex items-center gap-2 px-3 py-1.5 text-xs text-zinc-500 hover:text-zinc-300 bg-zinc-900 hover:bg-zinc-800 rounded-lg transition-colors border border-zinc-800"
|
||||
title="Reload templates from disk"
|
||||
>
|
||||
<RefreshCw size={14} />
|
||||
<span>Refresh</span>
|
||||
</motion.button>
|
||||
)}
|
||||
|
||||
{appState === AppState.CONFIG && (
|
||||
<div className="animate-in fade-in slide-in-from-bottom-4 duration-500">
|
||||
<StyleSelector
|
||||
selectedStyle={selectedStyle}
|
||||
onSelectStyle={setSelectedStyle}
|
||||
selectedPaperSize={paperSize}
|
||||
onSelectPaperSize={setPaperSize}
|
||||
onGenerate={handleGenerate}
|
||||
/>
|
||||
{error && (
|
||||
<div className="mt-6 p-4 bg-red-900/20 border border-red-800 rounded-xl text-center text-red-300">
|
||||
{error}
|
||||
</div>
|
||||
{/* Keyboard shortcuts hint */}
|
||||
<motion.button
|
||||
onClick={() => setShowShortcuts(true)}
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
className="hidden sm:flex items-center gap-2 px-3 py-1.5 text-xs text-zinc-500 hover:text-zinc-300 bg-zinc-900 hover:bg-zinc-800 rounded-lg transition-colors border border-zinc-800"
|
||||
title="Show keyboard shortcuts"
|
||||
>
|
||||
<Keyboard size={14} />
|
||||
<span>Shortcuts</span>
|
||||
<kbd className="px-1.5 py-0.5 bg-zinc-800 rounded text-zinc-400 font-mono">?</kbd>
|
||||
</motion.button>
|
||||
|
||||
<AnimatePresence mode="wait">
|
||||
{appState !== AppState.UPLOAD && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: 20 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
exit={{ opacity: 0, x: -20 }}
|
||||
className="flex items-center gap-4 text-sm text-zinc-500"
|
||||
>
|
||||
<span className={appState === AppState.CONFIG ? "text-indigo-400 font-medium" : ""}>Configure</span>
|
||||
<span>/</span>
|
||||
<span className={appState === AppState.GENERATING ? "text-indigo-400 font-medium" : ""}>Generate</span>
|
||||
<span>/</span>
|
||||
<span>Preview</span>
|
||||
</motion.div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</div>
|
||||
</motion.header>
|
||||
|
||||
{appState === AppState.GENERATING && (
|
||||
<div className="flex flex-col items-center justify-center flex-grow text-center animate-in fade-in duration-700">
|
||||
<div className="relative">
|
||||
<div className="absolute inset-0 bg-indigo-500 blur-xl opacity-20 animate-pulse"></div>
|
||||
<Loader2 size={64} className="text-indigo-400 animate-spin relative z-10" />
|
||||
</div>
|
||||
<h3 className="mt-8 text-2xl font-bold text-white">Formatting Document</h3>
|
||||
<p className="mt-2 text-zinc-400 max-w-md">
|
||||
Applying typographic rules and preparing print-ready layout...
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
{/* Main Content - Takes remaining space */}
|
||||
<main className="flex-1 relative overflow-hidden">
|
||||
{/* Animated background blobs */}
|
||||
<div className="absolute inset-0 overflow-hidden pointer-events-none">
|
||||
<motion.div
|
||||
className="absolute -top-[20%] -left-[10%] w-[50%] h-[50%] bg-indigo-900/10 rounded-full blur-3xl"
|
||||
animate={{
|
||||
x: [0, 30, 0],
|
||||
y: [0, -20, 0],
|
||||
scale: [1, 1.1, 1]
|
||||
}}
|
||||
transition={{ duration: 8, repeat: Infinity, ease: "easeInOut" }}
|
||||
/>
|
||||
<motion.div
|
||||
className="absolute top-[20%] -right-[10%] w-[40%] h-[40%] bg-violet-900/10 rounded-full blur-3xl"
|
||||
animate={{
|
||||
x: [0, -20, 0],
|
||||
y: [0, 30, 0],
|
||||
scale: [1, 1.15, 1]
|
||||
}}
|
||||
transition={{ duration: 10, repeat: Infinity, ease: "easeInOut" }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="relative z-10 w-full h-full max-w-7xl mx-auto px-6 py-6">
|
||||
<AnimatePresence mode="wait">
|
||||
{appState === AppState.UPLOAD && (
|
||||
<motion.div
|
||||
key="upload"
|
||||
initial={{ opacity: 0, y: 20, scale: 0.95 }}
|
||||
animate={{ opacity: 1, y: 0, scale: 1 }}
|
||||
exit={{ opacity: 0, y: -20, scale: 1.05 }}
|
||||
transition={{ duration: 0.4, ease: [0.22, 1, 0.36, 1] }}
|
||||
className="h-full flex flex-col items-center justify-center space-y-8"
|
||||
>
|
||||
<motion.div
|
||||
className="text-center space-y-4 max-w-2xl"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.1, duration: 0.5 }}
|
||||
>
|
||||
<motion.h2
|
||||
className="text-4xl md:text-5xl font-extrabold tracking-tight text-white"
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.2, duration: 0.6, ease: [0.22, 1, 0.36, 1] }}
|
||||
>
|
||||
Turn Markdown into <br />
|
||||
<motion.span
|
||||
className="text-transparent bg-clip-text bg-gradient-to-r from-indigo-400 to-violet-400"
|
||||
animate={{
|
||||
backgroundPosition: ["0% 50%", "100% 50%", "0% 50%"]
|
||||
}}
|
||||
transition={{ duration: 5, repeat: Infinity, ease: "linear" }}
|
||||
style={{ backgroundSize: "200% 200%" }}
|
||||
>
|
||||
Professional Word Docs.
|
||||
</motion.span>
|
||||
</motion.h2>
|
||||
<motion.p
|
||||
className="text-lg text-zinc-400 leading-relaxed"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.4, duration: 0.5 }}
|
||||
>
|
||||
Upload your raw text. Select a style.
|
||||
Get a formatted DOCX file ready for Microsoft Word.
|
||||
</motion.p>
|
||||
</motion.div>
|
||||
<FileUpload onFileLoaded={handleFileLoaded} />
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
{appState === AppState.CONFIG && (
|
||||
<motion.div
|
||||
key="config"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: -20 }}
|
||||
transition={{ duration: 0.4, ease: [0.22, 1, 0.36, 1] }}
|
||||
className="h-full"
|
||||
>
|
||||
<StyleSelector
|
||||
templates={templates}
|
||||
categories={categories}
|
||||
selectedStyle={selectedStyle}
|
||||
onSelectStyle={setSelectedStyle}
|
||||
selectedPaperSize={paperSize}
|
||||
onSelectPaperSize={setPaperSize}
|
||||
onGenerate={handleGenerate}
|
||||
isLoading={templatesLoading}
|
||||
error={templatesError}
|
||||
onOpenTemplatesFolder={openFolder}
|
||||
/>
|
||||
<AnimatePresence>
|
||||
{error && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: -10, scale: 0.95 }}
|
||||
animate={{ opacity: 1, y: 0, scale: 1 }}
|
||||
exit={{ opacity: 0, y: -10, scale: 0.95 }}
|
||||
className="mt-4 p-4 bg-red-900/20 border border-red-800 rounded-xl text-center text-red-300"
|
||||
role="alert"
|
||||
aria-live="polite"
|
||||
>
|
||||
{error}
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
{appState === AppState.GENERATING && (
|
||||
<motion.div
|
||||
key="generating"
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
exit={{ opacity: 0, scale: 1.1 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
className="h-full flex flex-col items-center justify-center text-center"
|
||||
>
|
||||
<motion.div
|
||||
className="relative"
|
||||
animate={{ rotate: 360 }}
|
||||
transition={{ duration: 2, repeat: Infinity, ease: "linear" }}
|
||||
>
|
||||
<motion.div
|
||||
className="absolute inset-0 bg-indigo-500 blur-xl opacity-20"
|
||||
animate={{ scale: [1, 1.2, 1], opacity: [0.2, 0.4, 0.2] }}
|
||||
transition={{ duration: 1.5, repeat: Infinity }}
|
||||
/>
|
||||
<Loader2 size={64} className="text-indigo-400 relative z-10" />
|
||||
</motion.div>
|
||||
<motion.h3
|
||||
className="mt-8 text-2xl font-bold text-white"
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.2 }}
|
||||
>
|
||||
Formatting Document
|
||||
</motion.h3>
|
||||
<motion.p
|
||||
className="mt-2 text-zinc-400 max-w-md"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.3 }}
|
||||
>
|
||||
Applying typographic rules and preparing print-ready layout...
|
||||
</motion.p>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer className="py-6 text-center text-zinc-600 text-sm border-t border-zinc-900 print:hidden">
|
||||
{/* Footer - Fixed height, always visible */}
|
||||
<motion.footer
|
||||
initial={{ y: 20, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
transition={{ delay: 0.5, duration: 0.5 }}
|
||||
className="flex-none py-4 text-center text-zinc-600 text-sm border-t border-zinc-900 bg-zinc-950"
|
||||
>
|
||||
<p>TypoGenie - Professional Typesetting Engine</p>
|
||||
</footer>
|
||||
</motion.footer>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
export default App;
|
||||
|
||||
272
src/components/CustomScrollbar.tsx
Normal file
272
src/components/CustomScrollbar.tsx
Normal file
@@ -0,0 +1,272 @@
|
||||
import React, { useRef, useEffect, useState, useCallback } from 'react';
|
||||
|
||||
interface CustomScrollbarProps {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
horizontal?: boolean;
|
||||
}
|
||||
|
||||
export const CustomScrollbar: React.FC<CustomScrollbarProps> = ({
|
||||
children,
|
||||
className = '',
|
||||
horizontal = false
|
||||
}) => {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const thumbRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const [isHoveringContainer, setIsHoveringContainer] = useState(false);
|
||||
const [isHoveringTrack, setIsHoveringTrack] = useState(false);
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
const [thumbSize, setThumbSize] = useState(40);
|
||||
|
||||
// Drag state
|
||||
const dragState = useRef({
|
||||
isActive: false,
|
||||
startMouse: 0,
|
||||
startScroll: 0,
|
||||
trackSize: 0,
|
||||
maxScroll: 0
|
||||
});
|
||||
|
||||
// Update thumb size
|
||||
const updateMetrics = useCallback(() => {
|
||||
const container = containerRef.current;
|
||||
if (!container) return;
|
||||
|
||||
if (horizontal) {
|
||||
const ratio = container.clientWidth / Math.max(container.scrollWidth, 1);
|
||||
setThumbSize(Math.max(40, ratio * container.clientWidth));
|
||||
} else {
|
||||
const ratio = container.clientHeight / Math.max(container.scrollHeight, 1);
|
||||
setThumbSize(Math.max(40, ratio * container.clientHeight));
|
||||
}
|
||||
|
||||
updateThumbVisual();
|
||||
}, [horizontal]);
|
||||
|
||||
// Update thumb position from scroll
|
||||
const updateThumbVisual = useCallback(() => {
|
||||
const container = containerRef.current;
|
||||
const thumb = thumbRef.current;
|
||||
if (!container || !thumb) return;
|
||||
|
||||
if (dragState.current.isActive) return;
|
||||
|
||||
if (horizontal) {
|
||||
const maxScroll = container.scrollWidth - container.clientWidth;
|
||||
const trackSize = container.clientWidth - thumbSize;
|
||||
if (maxScroll <= 0 || trackSize <= 0) {
|
||||
thumb.style.transform = 'translateX(0px)';
|
||||
return;
|
||||
}
|
||||
const ratio = container.scrollLeft / maxScroll;
|
||||
thumb.style.transform = `translateX(${ratio * trackSize}px)`;
|
||||
} else {
|
||||
const maxScroll = container.scrollHeight - container.clientHeight;
|
||||
const trackSize = container.clientHeight - thumbSize;
|
||||
if (maxScroll <= 0 || trackSize <= 0) {
|
||||
thumb.style.transform = 'translateY(0px)';
|
||||
return;
|
||||
}
|
||||
const ratio = container.scrollTop / maxScroll;
|
||||
thumb.style.transform = `translateY(${ratio * trackSize}px)`;
|
||||
}
|
||||
}, [horizontal, thumbSize]);
|
||||
|
||||
// Setup
|
||||
useEffect(() => {
|
||||
updateMetrics();
|
||||
|
||||
const handleResize = () => updateMetrics();
|
||||
window.addEventListener('resize', handleResize);
|
||||
|
||||
const observer = new MutationObserver(() => updateMetrics());
|
||||
if (containerRef.current) {
|
||||
observer.observe(containerRef.current, { childList: true, subtree: true });
|
||||
}
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('resize', handleResize);
|
||||
observer.disconnect();
|
||||
};
|
||||
}, [updateMetrics]);
|
||||
|
||||
// Scroll listener
|
||||
useEffect(() => {
|
||||
const container = containerRef.current;
|
||||
if (!container) return;
|
||||
|
||||
const onScroll = () => {
|
||||
if (!dragState.current.isActive) {
|
||||
updateThumbVisual();
|
||||
}
|
||||
};
|
||||
|
||||
container.addEventListener('scroll', onScroll, { passive: true });
|
||||
return () => container.removeEventListener('scroll', onScroll);
|
||||
}, [updateThumbVisual]);
|
||||
|
||||
// Drag handling - DIRECT synchronous updates
|
||||
useEffect(() => {
|
||||
if (!isDragging) {
|
||||
// Restore transition when not dragging
|
||||
if (thumbRef.current) {
|
||||
thumbRef.current.style.transition = 'opacity 0.15s, width 0.15s, height 0.15s';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const container = containerRef.current;
|
||||
const thumb = thumbRef.current;
|
||||
if (!container || !thumb) return;
|
||||
|
||||
const state = dragState.current;
|
||||
state.isActive = true;
|
||||
|
||||
// REMOVE transition during drag for instant response
|
||||
thumb.style.transition = 'none';
|
||||
|
||||
const handleMouseMove = (e: MouseEvent) => {
|
||||
const mousePos = horizontal ? e.clientX : e.clientY;
|
||||
const deltaMouse = mousePos - state.startMouse;
|
||||
const scrollRatio = deltaMouse / state.trackSize;
|
||||
const newScroll = state.startScroll + (scrollRatio * state.maxScroll);
|
||||
const clampedScroll = Math.max(0, Math.min(newScroll, state.maxScroll));
|
||||
|
||||
if (horizontal) {
|
||||
container.scrollLeft = clampedScroll;
|
||||
const visualRatio = state.maxScroll > 0 ? clampedScroll / state.maxScroll : 0;
|
||||
thumb.style.transform = `translateX(${visualRatio * state.trackSize}px)`;
|
||||
} else {
|
||||
container.scrollTop = clampedScroll;
|
||||
const visualRatio = state.maxScroll > 0 ? clampedScroll / state.maxScroll : 0;
|
||||
thumb.style.transform = `translateY(${visualRatio * state.trackSize}px)`;
|
||||
}
|
||||
};
|
||||
|
||||
const handleMouseUp = () => {
|
||||
state.isActive = false;
|
||||
setIsDragging(false);
|
||||
// Transition will be restored by effect cleanup
|
||||
};
|
||||
|
||||
document.addEventListener('mousemove', handleMouseMove);
|
||||
document.addEventListener('mouseup', handleMouseUp);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('mousemove', handleMouseMove);
|
||||
document.removeEventListener('mouseup', handleMouseUp);
|
||||
state.isActive = false;
|
||||
};
|
||||
}, [isDragging, horizontal]);
|
||||
|
||||
const handleThumbMouseDown = (e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const container = containerRef.current;
|
||||
const thumb = thumbRef.current;
|
||||
if (!container || !thumb) return;
|
||||
|
||||
const state = dragState.current;
|
||||
|
||||
if (horizontal) {
|
||||
state.startMouse = e.clientX;
|
||||
state.startScroll = container.scrollLeft;
|
||||
state.trackSize = container.clientWidth - thumbSize;
|
||||
state.maxScroll = container.scrollWidth - container.clientWidth;
|
||||
} else {
|
||||
state.startMouse = e.clientY;
|
||||
state.startScroll = container.scrollTop;
|
||||
state.trackSize = container.clientHeight - thumbSize;
|
||||
state.maxScroll = container.scrollHeight - container.clientHeight;
|
||||
}
|
||||
|
||||
// Remove transition immediately on mouse down
|
||||
thumb.style.transition = 'none';
|
||||
setIsDragging(true);
|
||||
};
|
||||
|
||||
const handleTrackClick = (e: React.MouseEvent) => {
|
||||
if (e.target === thumbRef.current) return;
|
||||
|
||||
const container = containerRef.current;
|
||||
if (!container) return;
|
||||
|
||||
const rect = container.getBoundingClientRect();
|
||||
|
||||
if (horizontal) {
|
||||
const clickX = e.clientX - rect.left;
|
||||
const percentage = clickX / rect.width;
|
||||
container.scrollTo({
|
||||
left: percentage * (container.scrollWidth - container.clientWidth),
|
||||
behavior: 'smooth'
|
||||
});
|
||||
} else {
|
||||
const clickY = e.clientY - rect.top;
|
||||
const percentage = clickY / rect.height;
|
||||
container.scrollTo({
|
||||
top: percentage * (container.scrollHeight - container.clientHeight),
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const isActive = isHoveringTrack || isDragging;
|
||||
const opacity = isActive ? 0.6 : (isHoveringContainer ? 0.2 : 0);
|
||||
const size = isActive ? '6px' : '2px';
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`relative ${className}`}
|
||||
onMouseEnter={() => setIsHoveringContainer(true)}
|
||||
onMouseLeave={() => {
|
||||
setIsHoveringContainer(false);
|
||||
if (!isDragging) setIsHoveringTrack(false);
|
||||
}}
|
||||
>
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="h-full w-full overflow-auto scrollbar-hide"
|
||||
style={{
|
||||
scrollbarWidth: 'none',
|
||||
msOverflowStyle: 'none',
|
||||
overflowX: horizontal ? 'auto' : 'hidden',
|
||||
overflowY: horizontal ? 'hidden' : 'auto'
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={`absolute cursor-pointer z-10 ${horizontal ? 'bottom-0 left-0 right-0 h-4' : 'top-0 right-0 bottom-0 w-4'}`}
|
||||
style={{ opacity }}
|
||||
onMouseEnter={() => setIsHoveringTrack(true)}
|
||||
onMouseLeave={() => { if (!isDragging) setIsHoveringTrack(false); }}
|
||||
onClick={handleTrackClick}
|
||||
>
|
||||
<div
|
||||
ref={thumbRef}
|
||||
className="absolute rounded-full bg-zinc-400 cursor-grab active:cursor-grabbing"
|
||||
style={{
|
||||
[horizontal ? 'left' : 'top']: 0,
|
||||
[horizontal ? 'bottom' : 'right']: '4px',
|
||||
[horizontal ? 'width' : 'height']: thumbSize,
|
||||
[horizontal ? 'height' : 'width']: size,
|
||||
opacity: isActive ? 0.9 : 0.5,
|
||||
transition: 'opacity 0.15s, width 0.15s, height 0.15s',
|
||||
transform: horizontal ? 'translateX(0px)' : 'translateY(0px)',
|
||||
willChange: 'transform'
|
||||
}}
|
||||
onMouseDown={handleThumbMouseDown}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<style>{`
|
||||
.scrollbar-hide::-webkit-scrollbar {
|
||||
display: none !important;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
145
src/components/ExportOptionsModal.tsx
Normal file
145
src/components/ExportOptionsModal.tsx
Normal file
@@ -0,0 +1,145 @@
|
||||
import { X } from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
|
||||
interface ExportOptionsModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
onExport: (useTableHeaders: boolean) => void;
|
||||
}
|
||||
|
||||
export default function ExportOptionsModal({ isOpen, onClose, onExport }: ExportOptionsModalProps) {
|
||||
const [selectedMode, setSelectedMode] = useState<'table' | 'semantic'>('semantic');
|
||||
|
||||
if (!isOpen) return null;
|
||||
|
||||
const handleExport = () => {
|
||||
onExport(selectedMode === 'table');
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-zinc-950/80 backdrop-blur-sm">
|
||||
<div className="relative w-full max-w-2xl bg-zinc-900 rounded-2xl shadow-2xl m-4 overflow-hidden border border-zinc-700">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between px-6 py-4 border-b border-zinc-800 bg-zinc-900/50">
|
||||
<h2 className="text-xl font-semibold text-white">Export Options</h2>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="p-1 text-zinc-400 hover:text-white transition-colors rounded-md hover:bg-zinc-800"
|
||||
aria-label="Close"
|
||||
>
|
||||
<X size={20} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="px-6 py-4 space-y-4 bg-zinc-900">
|
||||
<p className="text-sm text-zinc-400 mb-6">
|
||||
Choose how headers should be rendered in your Word document:
|
||||
</p>
|
||||
|
||||
{/* Option 1: High-Fidelity */}
|
||||
<label
|
||||
className={`block p-4 border-2 rounded-lg cursor-pointer transition-all ${selectedMode === 'table'
|
||||
? 'border-indigo-500 bg-indigo-500/10'
|
||||
: 'border-zinc-700 hover:border-zinc-600 bg-zinc-800/50'
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-start">
|
||||
<input
|
||||
type="radio"
|
||||
name="exportMode"
|
||||
value="table"
|
||||
checked={selectedMode === 'table'}
|
||||
onChange={() => setSelectedMode('table')}
|
||||
className="mt-1 mr-3 text-indigo-600 focus:ring-indigo-500 bg-zinc-700 border-zinc-600"
|
||||
/>
|
||||
<div className="flex-1">
|
||||
<div className="font-semibold text-white mb-2">High-Fidelity Layout</div>
|
||||
<div className="space-y-1 text-sm">
|
||||
<div className="flex items-start">
|
||||
<span className="text-green-500 mr-2">✓</span>
|
||||
<span className="text-zinc-300">Perfect padding and border alignment</span>
|
||||
</div>
|
||||
<div className="flex items-start">
|
||||
<span className="text-green-500 mr-2">✓</span>
|
||||
<span className="text-zinc-300">Backgrounds contained precisely</span>
|
||||
</div>
|
||||
<div className="flex items-start">
|
||||
<span className="text-red-500 mr-2">✗</span>
|
||||
<span className="text-zinc-300">No automatic Table of Contents</span>
|
||||
</div>
|
||||
<div className="flex items-start">
|
||||
<span className="text-red-500 mr-2">✗</span>
|
||||
<span className="text-zinc-300">Document outline/navigation disabled</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-3 text-xs text-zinc-500 italic">
|
||||
Best for: Portfolios, brochures, print-ready designs
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
{/* Option 2: Semantic */}
|
||||
<label
|
||||
className={`block p-4 border-2 rounded-lg cursor-pointer transition-all ${selectedMode === 'semantic'
|
||||
? 'border-indigo-500 bg-indigo-500/10'
|
||||
: 'border-zinc-700 hover:border-zinc-600 bg-zinc-800/50'
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-start">
|
||||
<input
|
||||
type="radio"
|
||||
name="exportMode"
|
||||
value="semantic"
|
||||
checked={selectedMode === 'semantic'}
|
||||
onChange={() => setSelectedMode('semantic')}
|
||||
className="mt-1 mr-3 text-indigo-600 focus:ring-indigo-500 bg-zinc-700 border-zinc-600"
|
||||
/>
|
||||
<div className="flex-1">
|
||||
<div className="font-semibold text-white mb-2">Semantic Structure</div>
|
||||
<div className="space-y-1 text-sm">
|
||||
<div className="flex items-start">
|
||||
<span className="text-green-500 mr-2">✓</span>
|
||||
<span className="text-zinc-300">Auto-generated Table of Contents</span>
|
||||
</div>
|
||||
<div className="flex items-start">
|
||||
<span className="text-green-500 mr-2">✓</span>
|
||||
<span className="text-zinc-300">Document navigation panel works</span>
|
||||
</div>
|
||||
<div className="flex items-start">
|
||||
<span className="text-green-500 mr-2">✓</span>
|
||||
<span className="text-zinc-300">Screen reader accessible</span>
|
||||
</div>
|
||||
<div className="flex items-start">
|
||||
<span className="text-yellow-500 mr-2">⚠</span>
|
||||
<span className="text-zinc-300">Minor padding/border alignment issues</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-3 text-xs text-zinc-500 italic">
|
||||
Best for: Academic papers, reports, accessible documents
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<div className="flex items-center justify-end gap-3 px-6 py-4 border-t border-zinc-800 bg-zinc-900">
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="px-4 py-2 text-sm font-medium text-zinc-300 bg-zinc-800 border border-zinc-700 rounded-md hover:bg-zinc-700 transition-colors"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
onClick={handleExport}
|
||||
className="px-4 py-2 text-sm font-medium text-white bg-indigo-600 rounded-md hover:bg-indigo-500 transition-colors"
|
||||
>
|
||||
Export to Word
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,13 +1,19 @@
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import React, { useCallback, useState, useRef, useEffect } from 'react';
|
||||
import { motion } from 'motion/react';
|
||||
import { Upload, FileText, AlertCircle } from 'lucide-react';
|
||||
import { useKeyboardNavigation } from '../hooks/useKeyboardNavigation';
|
||||
|
||||
interface FileUploadProps {
|
||||
onFileLoaded: (content: string) => void;
|
||||
onFileLoaded: (content: string, fileName: string) => void;
|
||||
}
|
||||
|
||||
export const FileUpload: React.FC<FileUploadProps> = ({ onFileLoaded }) => {
|
||||
const [dragActive, setDragActive] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [isFocused, setIsFocused] = useState(false);
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const dropzoneRef = useRef<HTMLDivElement>(null);
|
||||
const dragCounter = useRef(0);
|
||||
|
||||
const handleFile = (file: File) => {
|
||||
setError(null);
|
||||
@@ -20,7 +26,9 @@ export const FileUpload: React.FC<FileUploadProps> = ({ onFileLoaded }) => {
|
||||
reader.onload = (e) => {
|
||||
const text = e.target?.result;
|
||||
if (typeof text === 'string') {
|
||||
onFileLoaded(text);
|
||||
// Extract filename without extension
|
||||
const fileName = file.name.replace(/\.[^/.]+$/, '');
|
||||
onFileLoaded(text, fileName);
|
||||
}
|
||||
};
|
||||
reader.onerror = () => setError('Error reading file.');
|
||||
@@ -30,16 +38,24 @@ export const FileUpload: React.FC<FileUploadProps> = ({ onFileLoaded }) => {
|
||||
const handleDrag = useCallback((e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (e.type === 'dragenter' || e.type === 'dragover') {
|
||||
if (e.type === 'dragenter') {
|
||||
dragCounter.current += 1;
|
||||
setDragActive(true);
|
||||
} else if (e.type === 'dragleave') {
|
||||
setDragActive(false);
|
||||
dragCounter.current -= 1;
|
||||
if (dragCounter.current === 0) {
|
||||
setDragActive(false);
|
||||
}
|
||||
} else if (e.type === 'dragover') {
|
||||
// Keep drag active during dragover
|
||||
setDragActive(true);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleDrop = useCallback((e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
dragCounter.current = 0;
|
||||
setDragActive(false);
|
||||
if (e.dataTransfer.files && e.dataTransfer.files[0]) {
|
||||
handleFile(e.dataTransfer.files[0]);
|
||||
@@ -53,40 +69,158 @@ export const FileUpload: React.FC<FileUploadProps> = ({ onFileLoaded }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const openFilePicker = useCallback(() => {
|
||||
inputRef.current?.click();
|
||||
}, []);
|
||||
|
||||
// Keyboard navigation for the dropzone
|
||||
useKeyboardNavigation({
|
||||
onEnter: () => {
|
||||
if (isFocused) {
|
||||
openFilePicker();
|
||||
}
|
||||
},
|
||||
onSpace: () => {
|
||||
if (isFocused) {
|
||||
openFilePicker();
|
||||
}
|
||||
},
|
||||
}, [isFocused]);
|
||||
|
||||
// Clear error after 5 seconds
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
const timer = setTimeout(() => setError(null), 5000);
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
}, [error]);
|
||||
|
||||
return (
|
||||
<div className="w-full max-w-xl mx-auto">
|
||||
<div
|
||||
className={`relative group flex flex-col items-center justify-center w-full h-64 border-2 border-dashed rounded-2xl transition-all duration-300 ease-in-out cursor-pointer overflow-hidden
|
||||
${dragActive ? 'border-indigo-500 bg-indigo-500/10' : 'border-zinc-700 bg-zinc-900/50 hover:border-zinc-500 hover:bg-zinc-800/50'}`}
|
||||
<motion.div
|
||||
className="w-full max-w-xl mx-auto"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.5, duration: 0.5 }}
|
||||
role="region"
|
||||
aria-label="File upload"
|
||||
>
|
||||
<motion.div
|
||||
ref={dropzoneRef}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label="Drop zone. Click or press Enter to select a file."
|
||||
className={`relative group flex flex-col items-center justify-center w-full h-64 border-2 border-dashed rounded-2xl cursor-pointer overflow-hidden outline-none transition-all
|
||||
${dragActive ? 'border-indigo-500 bg-indigo-500/10' : 'border-zinc-700 bg-zinc-900/50'}
|
||||
${isFocused ? 'ring-2 ring-indigo-500 ring-offset-2 ring-offset-zinc-950 border-indigo-400' : ''}
|
||||
`}
|
||||
onDragEnter={handleDrag}
|
||||
onDragLeave={handleDrag}
|
||||
onDragOver={handleDrag}
|
||||
onDrop={handleDrop}
|
||||
onClick={openFilePicker}
|
||||
onFocus={() => setIsFocused(true)}
|
||||
onBlur={() => setIsFocused(false)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault();
|
||||
openFilePicker();
|
||||
}
|
||||
}}
|
||||
whileHover={{
|
||||
scale: 1.02,
|
||||
borderColor: '#6366f1',
|
||||
backgroundColor: 'rgba(99, 102, 241, 0.05)'
|
||||
}}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
transition={{ type: "spring", stiffness: 300, damping: 20 }}
|
||||
>
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="file"
|
||||
className="absolute inset-0 w-full h-full opacity-0 cursor-pointer z-10"
|
||||
className="hidden"
|
||||
onChange={handleChange}
|
||||
accept=".md,.txt,.markdown"
|
||||
aria-label="Select file"
|
||||
/>
|
||||
|
||||
<div className="flex flex-col items-center justify-center pt-5 pb-6 text-zinc-400 group-hover:text-zinc-200 transition-colors">
|
||||
<div className={`p-4 rounded-full mb-4 ${dragActive ? 'bg-indigo-500/20 text-indigo-400' : 'bg-zinc-800 text-zinc-500'}`}>
|
||||
<motion.div
|
||||
className="flex flex-col items-center justify-center pt-5 pb-6 text-zinc-400 group-hover:text-zinc-200 transition-colors"
|
||||
animate={dragActive ? { y: [0, -5, 0] } : {}}
|
||||
transition={{ duration: 0.3 }}
|
||||
>
|
||||
<motion.div
|
||||
className={`p-4 rounded-full mb-4 ${dragActive ? 'bg-indigo-500/20 text-indigo-400' : 'bg-zinc-800 text-zinc-500'}`}
|
||||
animate={dragActive ? {
|
||||
scale: [1, 1.2, 1],
|
||||
rotate: [0, 10, -10, 0]
|
||||
} : {}}
|
||||
transition={{ duration: 0.5 }}
|
||||
whileHover={{ scale: 1.1, rotate: 5 }}
|
||||
>
|
||||
<Upload size={32} />
|
||||
</div>
|
||||
<p className="mb-2 text-lg font-medium">
|
||||
<span className="font-semibold text-indigo-400">Click to upload</span> or drag and drop
|
||||
</p>
|
||||
<p className="text-sm text-zinc-500">Markdown or Plain Text files</p>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
<motion.p
|
||||
className="mb-2 text-lg font-medium"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.6 }}
|
||||
>
|
||||
<motion.span
|
||||
className="font-semibold text-indigo-400"
|
||||
whileHover={{ color: '#818cf8' }}
|
||||
>
|
||||
Click to upload
|
||||
</motion.span>{' '}
|
||||
or drag and drop
|
||||
</motion.p>
|
||||
<motion.p
|
||||
className="text-sm text-zinc-500"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.7 }}
|
||||
>
|
||||
Markdown or Plain Text files
|
||||
</motion.p>
|
||||
<motion.p
|
||||
className="text-xs text-zinc-600 mt-2"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.8 }}
|
||||
>
|
||||
Press Enter to browse
|
||||
</motion.p>
|
||||
</motion.div>
|
||||
|
||||
{/* Animated border gradient on hover */}
|
||||
<motion.div
|
||||
className="absolute inset-0 rounded-2xl pointer-events-none"
|
||||
style={{
|
||||
background: 'linear-gradient(90deg, transparent, rgba(99, 102, 241, 0.1), transparent)',
|
||||
}}
|
||||
initial={{ x: '-100%' }}
|
||||
whileHover={{ x: '100%' }}
|
||||
transition={{ duration: 0.6, ease: 'easeInOut' }}
|
||||
/>
|
||||
</motion.div>
|
||||
|
||||
{error && (
|
||||
<div className="mt-4 p-4 bg-red-900/20 border border-red-800 rounded-lg flex items-center gap-3 text-red-200 animate-in fade-in slide-in-from-top-2">
|
||||
<AlertCircle size={20} />
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: -10, height: 0 }}
|
||||
animate={{ opacity: 1, y: 0, height: 'auto' }}
|
||||
exit={{ opacity: 0, y: -10, height: 0 }}
|
||||
className="mt-4 p-4 bg-red-900/20 border border-red-800 rounded-lg flex items-center gap-3 text-red-200"
|
||||
role="alert"
|
||||
aria-live="polite"
|
||||
>
|
||||
<motion.div
|
||||
animate={{ rotate: [0, 10, -10, 0] }}
|
||||
transition={{ duration: 0.5 }}
|
||||
>
|
||||
<AlertCircle size={20} />
|
||||
</motion.div>
|
||||
<span>{error}</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,374 +1,434 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { ArrowLeft, Download, FileText, CheckCircle2, ExternalLink } from 'lucide-react';
|
||||
import { PaperSize, DocxStyleConfig, DocxBorder } from '../types';
|
||||
import { TYPOGRAPHY_STYLES } from '../constants';
|
||||
// @ts-ignore
|
||||
import * as docx from 'docx';
|
||||
import { motion, AnimatePresence } from 'motion/react';
|
||||
import { ArrowLeft, Download, FileText, CheckCircle2, ExternalLink, Loader2, ZoomIn, ZoomOut } from 'lucide-react';
|
||||
import { PaperSize } from '../types';
|
||||
import { StyleOption } from '../types';
|
||||
import { getPreviewCss } from '../services/templateRenderer';
|
||||
import { generateDocxDocument } from '../utils/docxConverter';
|
||||
import ExportOptionsModal from './ExportOptionsModal';
|
||||
import { open } from '@tauri-apps/plugin-shell';
|
||||
import { save } from '@tauri-apps/plugin-dialog';
|
||||
import { writeFile } from '@tauri-apps/plugin-fs';
|
||||
import { useKeyboardNavigation } from '../hooks/useKeyboardNavigation';
|
||||
|
||||
interface PreviewProps {
|
||||
htmlContent: string;
|
||||
onBack: () => void;
|
||||
paperSize: PaperSize;
|
||||
selectedStyleId?: string | null;
|
||||
inputFileName?: string;
|
||||
uiZoom: number;
|
||||
onZoomChange: (zoom: number) => void;
|
||||
templates: StyleOption[];
|
||||
}
|
||||
|
||||
export const Preview: React.FC<PreviewProps> = ({ htmlContent, onBack, paperSize, selectedStyleId }) => {
|
||||
const iframeRef = useRef<HTMLIFrameElement>(null);
|
||||
const [isExporting, setIsExporting] = useState(false);
|
||||
const [successMsg, setSuccessMsg] = useState(false);
|
||||
// Zoom Control Component
|
||||
const ZoomControl: React.FC<{ zoom: number; onZoomChange: (zoom: number) => void }> = ({ zoom, onZoomChange }) => {
|
||||
const decreaseZoom = () => onZoomChange(Math.max(50, zoom - 10));
|
||||
const increaseZoom = () => onZoomChange(Math.min(200, zoom + 10));
|
||||
|
||||
// Get current style
|
||||
const style = TYPOGRAPHY_STYLES.find(s => s.id === selectedStyleId) || TYPOGRAPHY_STYLES[0];
|
||||
return (
|
||||
<div className="flex items-center gap-2 bg-zinc-900/80 rounded-lg border border-zinc-800 px-2 py-1">
|
||||
<motion.button
|
||||
onClick={decreaseZoom}
|
||||
whileHover={{ scale: 1.1 }}
|
||||
whileTap={{ scale: 0.9 }}
|
||||
className="p-1 text-zinc-400 hover:text-white transition-colors"
|
||||
aria-label="Zoom out"
|
||||
>
|
||||
<ZoomOut size={16} />
|
||||
</motion.button>
|
||||
<span className="text-xs font-medium text-zinc-300 min-w-[3rem] text-center">{zoom}%</span>
|
||||
<motion.button
|
||||
onClick={increaseZoom}
|
||||
whileHover={{ scale: 1.1 }}
|
||||
whileTap={{ scale: 0.9 }}
|
||||
className="p-1 text-zinc-400 hover:text-white transition-colors"
|
||||
aria-label="Zoom in"
|
||||
>
|
||||
<ZoomIn size={16} />
|
||||
</motion.button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// Extract unique fonts for display
|
||||
const usedFonts = Array.from(new Set([
|
||||
style.wordConfig.heading1.font,
|
||||
style.wordConfig.heading2.font,
|
||||
style.wordConfig.body.font
|
||||
])).filter(Boolean);
|
||||
// Font download component
|
||||
const FontList: React.FC<{ fonts: string[] }> = ({ fonts }) => {
|
||||
const [downloadingFont, setDownloadingFont] = useState<string | null>(null);
|
||||
const [downloadStatus, setDownloadStatus] = useState<Record<string, string>>({});
|
||||
|
||||
// Helper to convert Points to Half-Points (docx standard)
|
||||
const pt = (points: number) => points * 2;
|
||||
|
||||
// Helper to convert Inches/MM to Twips
|
||||
const inchesToTwips = (inches: number) => Math.round(inches * 1440);
|
||||
const mmToTwips = (mm: number) => Math.round(mm * (1440 / 25.4));
|
||||
|
||||
// Helper to map Border config to Docx Border
|
||||
const mapBorder = (b?: DocxBorder) => {
|
||||
if (!b) return undefined;
|
||||
let style = docx.BorderStyle.SINGLE;
|
||||
if (b.style === 'double') style = docx.BorderStyle.DOUBLE;
|
||||
if (b.style === 'dotted') style = docx.BorderStyle.DOTTED;
|
||||
if (b.style === 'dashed') style = docx.BorderStyle.DASHED;
|
||||
|
||||
return {
|
||||
color: b.color,
|
||||
space: b.space,
|
||||
style: style,
|
||||
size: b.size
|
||||
};
|
||||
const downloadFont = async (fontName: string) => {
|
||||
setDownloadingFont(fontName);
|
||||
setDownloadStatus(prev => ({ ...prev, [fontName]: 'Downloading...' }));
|
||||
try {
|
||||
const encodedName = encodeURIComponent(fontName);
|
||||
const downloadUrl = `https://fonts.google.com/download?family=${encodedName}`;
|
||||
await open(downloadUrl);
|
||||
setDownloadStatus(prev => ({ ...prev, [fontName]: 'Opened in browser' }));
|
||||
setTimeout(() => {
|
||||
setDownloadStatus(prev => { const newStatus = { ...prev }; delete newStatus[fontName]; return newStatus; });
|
||||
}, 3000);
|
||||
} catch (err) {
|
||||
setDownloadStatus(prev => ({ ...prev, [fontName]: 'Failed' }));
|
||||
} finally {
|
||||
setDownloadingFont(null);
|
||||
}
|
||||
};
|
||||
|
||||
const generateDocx = async (styleId: string) => {
|
||||
const openGoogleFonts = async (fontName: string) => {
|
||||
try {
|
||||
const url = `https://fonts.google.com/specimen/${fontName.replace(/\s+/g, '+')}`;
|
||||
await open(url);
|
||||
} catch (err) {
|
||||
window.open(`https://fonts.google.com/specimen/${fontName.replace(/\s+/g, '+')}`, '_blank');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-2 text-sm text-zinc-500">
|
||||
<span className="hidden md:inline">Fonts:</span>
|
||||
<div className="flex gap-2 flex-wrap">
|
||||
{fonts.map((font, index) => (
|
||||
<motion.div key={font} className="relative group" initial={{ opacity: 0, scale: 0.8 }} animate={{ opacity: 1, scale: 1 }} transition={{ delay: index * 0.05 }}>
|
||||
<div className="flex items-center gap-1">
|
||||
<motion.button
|
||||
onClick={() => downloadFont(font)}
|
||||
disabled={downloadingFont === font}
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
className="px-2 py-1 bg-zinc-900 border border-zinc-800 hover:border-zinc-600 rounded-l text-zinc-300 hover:text-white transition-all flex items-center gap-1.5 text-xs font-medium"
|
||||
>
|
||||
{downloadingFont === font ? <Loader2 size={10} className="animate-spin" /> : <Download size={10} />}
|
||||
{font}
|
||||
</motion.button>
|
||||
<motion.button
|
||||
onClick={() => openGoogleFonts(font)}
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
className="px-1.5 py-1 bg-zinc-900 border border-l-0 border-zinc-800 hover:border-zinc-600 rounded-r text-zinc-400 hover:text-white transition-all"
|
||||
>
|
||||
<ExternalLink size={10} />
|
||||
</motion.button>
|
||||
</div>
|
||||
{downloadStatus[font] && (
|
||||
<motion.div className="absolute top-full left-0 mt-1 px-2 py-1 bg-zinc-800 border border-zinc-700 rounded text-xs whitespace-nowrap z-50" initial={{ opacity: 0, y: -5 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0, y: -5 }}>
|
||||
{downloadStatus[font]}
|
||||
</motion.div>
|
||||
)}
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Preview: React.FC<PreviewProps> = ({
|
||||
htmlContent,
|
||||
onBack,
|
||||
paperSize,
|
||||
selectedStyleId,
|
||||
inputFileName = 'document',
|
||||
uiZoom,
|
||||
onZoomChange,
|
||||
templates
|
||||
}) => {
|
||||
const iframeRef = useRef<HTMLIFrameElement>(null);
|
||||
const backButtonRef = useRef<HTMLButtonElement>(null);
|
||||
const saveButtonRef = useRef<HTMLButtonElement>(null);
|
||||
const [isExporting, setIsExporting] = useState(false);
|
||||
const [successMsg, setSuccessMsg] = useState(false);
|
||||
const [showExportModal, setShowExportModal] = useState(false);
|
||||
const [focusedElement, setFocusedElement] = useState<'back' | 'fonts' | 'save'>('save');
|
||||
|
||||
// Get current style from templates
|
||||
const style = templates.find(s => s.id === selectedStyleId) || templates[0] || null;
|
||||
|
||||
// Extract used fonts for display
|
||||
const usedFonts = style ? Array.from(new Set([
|
||||
style.typography?.fonts?.heading || style.wordConfig?.heading1?.font || 'Arial',
|
||||
style.typography?.fonts?.body || style.wordConfig?.body?.font || 'Arial'
|
||||
])).filter(Boolean) : [];
|
||||
|
||||
useKeyboardNavigation({
|
||||
onEscape: () => onBack(),
|
||||
onArrowLeft: () => { if (focusedElement === 'save') { setFocusedElement('back'); backButtonRef.current?.focus(); } },
|
||||
onArrowRight: () => { if (focusedElement === 'back') { setFocusedElement('save'); saveButtonRef.current?.focus(); } },
|
||||
onEnter: () => { if (focusedElement === 'back') onBack(); else if (focusedElement === 'save' && !isExporting) handleSave(); },
|
||||
onCtrlEnter: () => { if (!isExporting) handleSave(); },
|
||||
}, [focusedElement, isExporting, onBack]);
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => saveButtonRef.current?.focus(), 100);
|
||||
}, []);
|
||||
|
||||
const handleSave = async () => {
|
||||
setShowExportModal(true);
|
||||
};
|
||||
|
||||
const handleExportConfirm = async (useTableHeaders: boolean) => {
|
||||
setShowExportModal(false);
|
||||
const sid = selectedStyleId || 'swiss-grid';
|
||||
await generateDocx(sid, useTableHeaders);
|
||||
};
|
||||
|
||||
const generateDocx = async (styleId: string, useTableHeaders: boolean = false) => {
|
||||
setIsExporting(true);
|
||||
try {
|
||||
const style = TYPOGRAPHY_STYLES.find(s => s.id === styleId) || TYPOGRAPHY_STYLES[0];
|
||||
const cfg = style.wordConfig;
|
||||
const template = templates.find(s => s.id === styleId) || templates[0];
|
||||
|
||||
// PARSE HTML
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(htmlContent, 'text/html');
|
||||
const nodes = Array.from(doc.body.childNodes);
|
||||
// Get base config from wordConfig
|
||||
const cfg = template.wordConfig || {
|
||||
heading1: { font: 'Arial', size: 24, color: '000000', align: 'left' },
|
||||
heading2: { font: 'Arial', size: 18, color: '333333', align: 'left' },
|
||||
body: { font: 'Arial', size: 11, color: '000000', align: 'left' },
|
||||
accentColor: '000000'
|
||||
};
|
||||
|
||||
const docxChildren = [];
|
||||
// Extract page background from template
|
||||
const pageBackground = template.typography?.colors?.background;
|
||||
|
||||
for (const node of nodes) {
|
||||
if (node.nodeType !== Node.ELEMENT_NODE) continue;
|
||||
const el = node as HTMLElement;
|
||||
const tagName = el.tagName.toLowerCase();
|
||||
|
||||
// --- Run Parser (Inline Styles) ---
|
||||
const parseRuns = (element: HTMLElement, baseConfig: DocxStyleConfig) => {
|
||||
const runs = [];
|
||||
for (const child of Array.from(element.childNodes)) {
|
||||
if (child.nodeType === Node.TEXT_NODE) {
|
||||
runs.push(new docx.TextRun({
|
||||
text: child.textContent || '',
|
||||
font: baseConfig.font,
|
||||
size: pt(baseConfig.size),
|
||||
color: baseConfig.color,
|
||||
underline: baseConfig.underline ? { type: docx.UnderlineType.SINGLE, color: baseConfig.color } : undefined,
|
||||
}));
|
||||
} else if (child.nodeType === Node.ELEMENT_NODE) {
|
||||
const childEl = child as HTMLElement;
|
||||
const isBold = childEl.tagName === 'STRONG' || childEl.tagName === 'B';
|
||||
const isItalic = childEl.tagName === 'EM' || childEl.tagName === 'I';
|
||||
runs.push(new docx.TextRun({
|
||||
text: childEl.textContent || '',
|
||||
bold: isBold,
|
||||
italics: isItalic,
|
||||
font: baseConfig.font,
|
||||
size: pt(baseConfig.size),
|
||||
color: baseConfig.color,
|
||||
underline: baseConfig.underline ? { type: docx.UnderlineType.SINGLE, color: baseConfig.color } : undefined,
|
||||
}));
|
||||
}
|
||||
}
|
||||
return runs;
|
||||
};
|
||||
// Get fonts from template
|
||||
const codeFont = template.typography?.fonts?.code || template.typography?.fonts?.body || 'Consolas';
|
||||
|
||||
// Detect dark theme
|
||||
const isDarkTheme = pageBackground ? parseInt(pageBackground, 16) < 0x444444 : false;
|
||||
|
||||
// --- Block Parser ---
|
||||
|
||||
// 1. HEADINGS
|
||||
if (tagName.match(/^h[1-6]$/)) {
|
||||
const level = parseInt(tagName.replace('h', ''));
|
||||
|
||||
// Select config based on level (simplified to H1 or H2, fallback H2 for others)
|
||||
const hCfg = level === 1 ? cfg.heading1 : cfg.heading2;
|
||||
const headingLevel = level === 1 ? docx.HeadingLevel.HEADING_1 : docx.HeadingLevel.HEADING_2;
|
||||
// DEBUG: Specific markdown constructs for DOCX
|
||||
console.log('=== PREVIEW CALLING DOCX (h3, strong, table, ul/ol, li) ===');
|
||||
console.log('wordConfig h3:', JSON.stringify({ font: cfg.heading2?.font, size: cfg.body?.size, color: template.elements?.h3?.color }));
|
||||
console.log('elements h3:', JSON.stringify(template.elements?.h3));
|
||||
console.log('elements strong:', JSON.stringify(template.elements?.strong));
|
||||
console.log('elements table:', JSON.stringify(template.elements?.table));
|
||||
console.log('elements th:', JSON.stringify(template.elements?.th));
|
||||
console.log('elements td:', JSON.stringify(template.elements?.td));
|
||||
console.log('elements ul:', JSON.stringify(template.elements?.ul));
|
||||
console.log('elements ol:', JSON.stringify(template.elements?.ol));
|
||||
console.log('elements li:', JSON.stringify(template.elements?.li));
|
||||
console.log('useTableHeaders:', useTableHeaders);
|
||||
console.log('=== END PREVIEW CALL ===');
|
||||
|
||||
// Border Mapping
|
||||
const borderConfig: any = {};
|
||||
if (hCfg.border) {
|
||||
if (hCfg.border.top) borderConfig.top = mapBorder(hCfg.border.top);
|
||||
if (hCfg.border.bottom) borderConfig.bottom = mapBorder(hCfg.border.bottom);
|
||||
if (hCfg.border.left) borderConfig.left = mapBorder(hCfg.border.left);
|
||||
if (hCfg.border.right) borderConfig.right = mapBorder(hCfg.border.right);
|
||||
}
|
||||
|
||||
// Alignment Mapping
|
||||
let align = docx.AlignmentType.LEFT;
|
||||
if (hCfg.align === 'center') align = docx.AlignmentType.CENTER;
|
||||
if (hCfg.align === 'right') align = docx.AlignmentType.RIGHT;
|
||||
if (hCfg.align === 'both') align = docx.AlignmentType.BOTH;
|
||||
|
||||
docxChildren.push(new docx.Paragraph({
|
||||
children: [
|
||||
new docx.TextRun({
|
||||
text: el.textContent || '',
|
||||
font: hCfg.font,
|
||||
bold: hCfg.bold,
|
||||
italics: hCfg.italic,
|
||||
underline: hCfg.underline ? { type: docx.UnderlineType.SINGLE, color: hCfg.color } : undefined,
|
||||
size: pt(hCfg.size),
|
||||
color: hCfg.color,
|
||||
allCaps: hCfg.allCaps,
|
||||
smallCaps: hCfg.smallCaps,
|
||||
characterSpacing: hCfg.tracking
|
||||
})
|
||||
],
|
||||
heading: headingLevel,
|
||||
alignment: align,
|
||||
spacing: {
|
||||
before: hCfg.spacing?.before,
|
||||
after: hCfg.spacing?.after,
|
||||
line: hCfg.spacing?.line
|
||||
},
|
||||
border: borderConfig,
|
||||
shading: hCfg.shading ? {
|
||||
fill: hCfg.shading.fill,
|
||||
color: hCfg.shading.color,
|
||||
type: docx.ShadingType.CLEAR // usually clear to show fill
|
||||
} : undefined,
|
||||
keepNext: true,
|
||||
keepLines: true
|
||||
}));
|
||||
}
|
||||
|
||||
// 2. PARAGRAPHS
|
||||
else if (tagName === 'p') {
|
||||
let align = docx.AlignmentType.LEFT;
|
||||
if (cfg.body.align === 'center') align = docx.AlignmentType.CENTER;
|
||||
if (cfg.body.align === 'right') align = docx.AlignmentType.RIGHT;
|
||||
if (cfg.body.align === 'both') align = docx.AlignmentType.BOTH;
|
||||
|
||||
docxChildren.push(new docx.Paragraph({
|
||||
children: parseRuns(el, cfg.body),
|
||||
spacing: {
|
||||
before: cfg.body.spacing?.before,
|
||||
after: cfg.body.spacing?.after,
|
||||
line: cfg.body.spacing?.line,
|
||||
lineRule: docx.LineRuleType.AUTO
|
||||
},
|
||||
alignment: align
|
||||
}));
|
||||
}
|
||||
|
||||
// 3. BLOCKQUOTES
|
||||
else if (tagName === 'blockquote') {
|
||||
docxChildren.push(new docx.Paragraph({
|
||||
children: parseRuns(el, { ...cfg.body, size: cfg.body.size + 1, color: cfg.accentColor, italic: true } as DocxStyleConfig),
|
||||
indent: { left: 720 }, // 0.5 inch
|
||||
border: { left: { color: cfg.accentColor, space: 10, style: docx.BorderStyle.SINGLE, size: 24 } },
|
||||
shading: { fill: "F8F8F8", type: docx.ShadingType.CLEAR, color: "auto" }, // Default light grey background for quotes
|
||||
spacing: { before: 200, after: 200, line: 300 }
|
||||
}));
|
||||
}
|
||||
|
||||
// 4. LISTS
|
||||
else if (tagName === 'ul' || tagName === 'ol') {
|
||||
const listItems = Array.from(el.children);
|
||||
for (const li of listItems) {
|
||||
docxChildren.push(new docx.Paragraph({
|
||||
children: parseRuns(li as HTMLElement, cfg.body),
|
||||
bullet: { level: 0 },
|
||||
spacing: { before: 80, after: 80 }
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create Document
|
||||
const docxFile = new docx.Document({
|
||||
sections: [{
|
||||
properties: {
|
||||
page: {
|
||||
size: {
|
||||
width: paperSize === 'A4' ? mmToTwips(210) : inchesToTwips(8.5),
|
||||
height: paperSize === 'A4' ? mmToTwips(297) : inchesToTwips(11),
|
||||
},
|
||||
margin: {
|
||||
top: inchesToTwips(1),
|
||||
right: inchesToTwips(1.2),
|
||||
bottom: inchesToTwips(1),
|
||||
left: inchesToTwips(1.2),
|
||||
}
|
||||
}
|
||||
},
|
||||
children: docxChildren
|
||||
}]
|
||||
const blob = await generateDocxDocument(htmlContent, {
|
||||
paperSize,
|
||||
heading1: cfg.heading1,
|
||||
heading2: cfg.heading2,
|
||||
body: cfg.body,
|
||||
accentColor: cfg.accentColor,
|
||||
pageBackground,
|
||||
codeFont,
|
||||
isDarkTheme,
|
||||
elements: template.elements,
|
||||
fonts: template.typography?.fonts,
|
||||
palette: template.typography?.colors,
|
||||
id: template.id,
|
||||
page: template.page,
|
||||
useTableHeaders
|
||||
});
|
||||
|
||||
const blob = await docx.Packer.toBlob(docxFile);
|
||||
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `typogenie-${style.name.replace(/\s+/g, '-').toLowerCase()}.docx`;
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
|
||||
setSuccessMsg(true);
|
||||
setTimeout(() => setSuccessMsg(false), 3000);
|
||||
const arrayBuffer = await blob.arrayBuffer();
|
||||
const uint8Array = new Uint8Array(arrayBuffer);
|
||||
|
||||
const defaultName = `${inputFileName}.docx`;
|
||||
const savePath = await save({
|
||||
defaultPath: defaultName,
|
||||
filters: [{ name: 'Word Document', extensions: ['docx'] }]
|
||||
});
|
||||
|
||||
if (savePath) {
|
||||
await writeFile(savePath, uint8Array);
|
||||
setSuccessMsg(true);
|
||||
setTimeout(() => setSuccessMsg(false), 3000);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Docx Gen Error", e);
|
||||
alert("Failed to generate DOCX");
|
||||
alert("Failed to generate DOCX: " + e);
|
||||
} finally {
|
||||
setIsExporting(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Track blob URL for cleanup
|
||||
const blobUrlRef = useRef<string | null>(null);
|
||||
|
||||
// Render preview whenever dependencies change
|
||||
useEffect(() => {
|
||||
if (!iframeRef.current) return;
|
||||
|
||||
// We already have 'style' from the component scope, but useEffect needs to be robust
|
||||
const currentStyle = TYPOGRAPHY_STYLES.find(s => s.id === selectedStyleId) || TYPOGRAPHY_STYLES[0];
|
||||
if (!iframeRef.current || !style) return;
|
||||
|
||||
const doc = iframeRef.current.contentDocument;
|
||||
if (doc) {
|
||||
const html = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="${currentStyle.googleFontsImport}" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
background-color: #52525b;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 40px;
|
||||
margin: 0;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
.page {
|
||||
background: white;
|
||||
width: ${paperSize === 'A4' ? '210mm' : '8.5in'};
|
||||
min-height: ${paperSize === 'A4' ? '297mm' : '11in'};
|
||||
padding: 25mm;
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.4);
|
||||
box-sizing: border-box;
|
||||
|
||||
/* Inject default body color to ensure visibility in dark themes */
|
||||
color: #${currentStyle.wordConfig.body.color};
|
||||
// DEBUG: Specific markdown constructs for Preview
|
||||
console.log('=== PREVIEW DEBUG (h3, strong, table, ul/ol, li) ===');
|
||||
console.log('h3:', JSON.stringify(style.elements?.h3));
|
||||
console.log('strong:', JSON.stringify(style.elements?.strong));
|
||||
console.log('table:', JSON.stringify(style.elements?.table));
|
||||
console.log('th:', JSON.stringify(style.elements?.th));
|
||||
console.log('td:', JSON.stringify(style.elements?.td));
|
||||
console.log('ul:', JSON.stringify(style.elements?.ul));
|
||||
console.log('ol:', JSON.stringify(style.elements?.ol));
|
||||
console.log('li:', JSON.stringify(style.elements?.li));
|
||||
console.log('=== END PREVIEW DEBUG ===');
|
||||
|
||||
/* User Selected Typography */
|
||||
${currentStyle.previewCss}
|
||||
}
|
||||
|
||||
.page * { box-sizing: border-box; }
|
||||
.page img { max-width: 100%; }
|
||||
.page table { width: 100%; border-collapse: collapse; margin-bottom: 1em; }
|
||||
.page th, .page td { border: 1px solid #ddd; padding: 8px; text-align: left; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page">
|
||||
${htmlContent}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
doc.open();
|
||||
doc.write(html);
|
||||
doc.close();
|
||||
// Cleanup old blob URL
|
||||
if (blobUrlRef.current) {
|
||||
URL.revokeObjectURL(blobUrlRef.current);
|
||||
blobUrlRef.current = null;
|
||||
}
|
||||
}, [htmlContent, paperSize, selectedStyleId]);
|
||||
|
||||
// Get CSS from template - this generates from elements structure
|
||||
const templateCss = getPreviewCss(style);
|
||||
console.log('Generated preview CSS (first 500 chars):', templateCss.substring(0, 500));
|
||||
|
||||
// Get page background from template
|
||||
const pageBg = style.typography?.colors?.background || 'ffffff';
|
||||
|
||||
// Build the complete CSS - template CSS now includes .page styles
|
||||
const allCss = [
|
||||
/* Reset styles first */
|
||||
'::-webkit-scrollbar { width: 6px !important; height: 6px !important; }',
|
||||
'::-webkit-scrollbar-track { background: transparent !important; }',
|
||||
'::-webkit-scrollbar-thumb { background: #71717a !important; border-radius: 3px !important; }',
|
||||
'* { scrollbar-width: thin; scrollbar-color: #71717a transparent; box-sizing: border-box; }',
|
||||
'html, body { margin: 0; padding: 0; min-height: 100%; }',
|
||||
|
||||
/* Dark outer background */
|
||||
'body { background-color: #18181b; padding: 40px 20px; }',
|
||||
|
||||
/* Template CSS - includes .page styles with fonts, colors, etc. */
|
||||
templateCss,
|
||||
|
||||
/* Page dimensions (not included in template CSS) */
|
||||
`.page {`,
|
||||
` width: ${paperSize === 'A4' ? '210mm' : '8.5in'};`,
|
||||
` min-height: ${paperSize === 'A4' ? '297mm' : '11in'};`,
|
||||
` padding: 25mm;`,
|
||||
` box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.4);`,
|
||||
` box-sizing: border-box;`,
|
||||
` margin: 0 auto;`,
|
||||
`}`,
|
||||
|
||||
/* Utilities */
|
||||
'.page img { max-width: 100%; }'
|
||||
].join('\n');
|
||||
|
||||
// Inject CSS directly as inline style tag
|
||||
const html = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="${style.googleFontsImport || 'https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap'}" rel="stylesheet">
|
||||
<style>
|
||||
${allCss}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page">
|
||||
${htmlContent}
|
||||
<script>
|
||||
console.log('--- STAGE 2: PREVIEW COMPUTED STYLES ---');
|
||||
setTimeout(() => {
|
||||
['h1', 'h2', 'h3', 'p', 'table', 'th', 'td', 'ul', 'ol', 'li', 'blockquote', 'code', 'pre'].forEach(tag => {
|
||||
const el = document.querySelector('.page ' + tag);
|
||||
if (el) {
|
||||
const style = window.getComputedStyle(el);
|
||||
|
||||
// Get borders specifically
|
||||
const borderTop = style.borderTopWidth + ' ' + style.borderTopStyle + ' ' + style.borderTopColor;
|
||||
const borderBottom = style.borderBottomWidth + ' ' + style.borderBottomStyle + ' ' + style.borderBottomColor;
|
||||
const borderLeft = style.borderLeftWidth + ' ' + style.borderLeftStyle + ' ' + style.borderLeftColor;
|
||||
const borderRight = style.borderRightWidth + ' ' + style.borderRightStyle + ' ' + style.borderRightColor;
|
||||
|
||||
console.log(\`PREVIEW \${tag.toUpperCase()}: \`, {
|
||||
fontFamily: style.fontFamily,
|
||||
fontSize: style.fontSize,
|
||||
color: style.color,
|
||||
backgroundColor: style.backgroundColor,
|
||||
fontWeight: style.fontWeight,
|
||||
border: \`T:\${borderTop} R:\${borderRight} B:\${borderBottom} L:\${borderLeft}\`,
|
||||
padding: style.padding,
|
||||
margin: style.margin
|
||||
});
|
||||
} else {
|
||||
console.log(\`PREVIEW \${tag.toUpperCase()}: Not found\`);
|
||||
}
|
||||
});
|
||||
}, 500);
|
||||
</script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
// Create blob URL for CSP compliance
|
||||
const blob = new Blob([html], { type: 'text/html' });
|
||||
const blobUrl = URL.createObjectURL(blob);
|
||||
blobUrlRef.current = blobUrl;
|
||||
iframeRef.current.src = blobUrl;
|
||||
|
||||
// Cleanup on unmount
|
||||
return () => {
|
||||
if (blobUrlRef.current) {
|
||||
URL.revokeObjectURL(blobUrlRef.current);
|
||||
blobUrlRef.current = null;
|
||||
}
|
||||
};
|
||||
}, [htmlContent, paperSize, selectedStyleId, templates, style]);
|
||||
|
||||
if (!style) {
|
||||
return <div className="h-screen flex items-center justify-center text-white">Loading...</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-screen flex flex-col bg-zinc-900">
|
||||
{/* Toolbar */}
|
||||
<div className="sticky top-0 z-50 bg-zinc-950/90 backdrop-blur-md border-b border-zinc-800 p-4">
|
||||
<motion.div className="h-screen flex flex-col bg-zinc-950" initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ duration: 0.3 }}>
|
||||
<motion.div className="sticky top-0 z-50 bg-zinc-950/90 backdrop-blur-md border-b border-zinc-800 p-4" initial={{ y: -20, opacity: 0 }} animate={{ y: 0, opacity: 1 }} transition={{ duration: 0.4, ease: [0.22, 1, 0.36, 1] }}>
|
||||
<div className="max-w-7xl mx-auto flex flex-col sm:flex-row justify-between items-center gap-4">
|
||||
<button
|
||||
onClick={onBack}
|
||||
className="flex items-center gap-2 text-zinc-400 hover:text-white transition-colors"
|
||||
>
|
||||
<motion.button ref={backButtonRef} onClick={onBack} onFocus={() => setFocusedElement('back')} whileHover={{ x: -3 }} whileTap={{ scale: 0.95 }} className="flex items-center gap-2 text-zinc-400 hover:text-white transition-colors outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 focus:ring-offset-zinc-950 rounded-lg px-2 py-1">
|
||||
<ArrowLeft size={20} />
|
||||
<span>Back to Editor</span>
|
||||
</button>
|
||||
</motion.button>
|
||||
|
||||
<div className="flex flex-col sm:flex-row items-center gap-6">
|
||||
|
||||
{/* Font List */}
|
||||
<div className="flex items-center gap-2 text-sm text-zinc-500">
|
||||
<span className="hidden md:inline">Fonts:</span>
|
||||
<div className="flex gap-2">
|
||||
{usedFonts.map(font => (
|
||||
<a
|
||||
key={font}
|
||||
href={`https://fonts.google.com/specimen/${font.replace(/\s+/g, '+')}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="px-2 py-1 bg-zinc-900 border border-zinc-800 hover:border-zinc-600 rounded text-zinc-300 hover:text-white transition-all flex items-center gap-1.5 text-xs font-medium"
|
||||
title={`Download ${font} from Google Fonts`}
|
||||
>
|
||||
{font}
|
||||
<ExternalLink size={10} />
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<FontList fonts={usedFonts} />
|
||||
<div className="h-4 w-px bg-zinc-800 hidden sm:block" />
|
||||
<ZoomControl zoom={uiZoom} onZoomChange={onZoomChange} />
|
||||
<div className="h-4 w-px bg-zinc-800 hidden sm:block" />
|
||||
|
||||
<div className="flex items-center gap-4">
|
||||
<span className="text-zinc-500 text-sm hidden sm:inline">
|
||||
Format: {paperSize}
|
||||
</span>
|
||||
<button
|
||||
onClick={() => {
|
||||
// Ensure we pass a string for styleId
|
||||
const sid = selectedStyleId || 'swiss-grid';
|
||||
generateDocx(sid);
|
||||
}}
|
||||
<span className="text-zinc-500 text-sm hidden sm:inline">Format: {paperSize}</span>
|
||||
<motion.button
|
||||
ref={saveButtonRef}
|
||||
onClick={handleSave}
|
||||
onFocus={() => setFocusedElement('save')}
|
||||
disabled={isExporting}
|
||||
className={`flex items-center gap-2 px-5 py-2.5 rounded-lg font-semibold transition-colors shadow-lg
|
||||
${successMsg ? 'bg-emerald-600 text-white' : 'bg-blue-600 text-white hover:bg-blue-500'}
|
||||
${isExporting ? 'opacity-50 cursor-wait' : ''}`}
|
||||
whileHover={{ scale: 1.05, boxShadow: '0 0 20px rgba(59, 130, 246, 0.4)' }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
className={`flex items-center gap-2 px-5 py-2.5 rounded-lg font-semibold transition-colors shadow-lg ${successMsg ? 'bg-emerald-600 text-white' : 'bg-blue-600 text-white hover:bg-blue-500'} ${isExporting ? 'opacity-50 cursor-wait' : ''}`}
|
||||
>
|
||||
{successMsg ? (
|
||||
<><CheckCircle2 size={18} /><span>Downloaded!</span></>
|
||||
) : (
|
||||
<><FileText size={18} /><span>{isExporting ? 'Generating...' : 'Download Word Doc'}</span></>
|
||||
)}
|
||||
</button>
|
||||
<AnimatePresence mode="wait">
|
||||
{successMsg ? (
|
||||
<motion.div key="success" initial={{ scale: 0 }} animate={{ scale: 1 }} exit={{ scale: 0 }} className="flex items-center gap-2">
|
||||
<CheckCircle2 size={18} />
|
||||
<span>Saved!</span>
|
||||
</motion.div>
|
||||
) : (
|
||||
<motion.div key="default" initial={{ scale: 0 }} animate={{ scale: 1 }} exit={{ scale: 0 }} className="flex items-center gap-2">
|
||||
{isExporting ? <Loader2 size={18} className="animate-spin" /> : <FileText size={18} />}
|
||||
<span>{isExporting ? 'Generating...' : 'Save Word Doc'}</span>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</motion.button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
<div className="flex-grow relative bg-zinc-950 overflow-hidden preview-container">
|
||||
<iframe ref={iframeRef} className="w-full h-full border-0 block" title="Report Preview" />
|
||||
</div>
|
||||
|
||||
<div className="flex-grow relative bg-zinc-800 overflow-hidden">
|
||||
<iframe
|
||||
ref={iframeRef}
|
||||
className="w-full h-full border-0 block"
|
||||
title="Report Preview"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<ExportOptionsModal
|
||||
isOpen={showExportModal}
|
||||
onClose={() => setShowExportModal(false)}
|
||||
onExport={handleExportConfirm}
|
||||
/>
|
||||
</motion.div>
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,111 +1,281 @@
|
||||
import React, { useState, useMemo, useRef, useEffect } from 'react';
|
||||
import { TYPOGRAPHY_STYLES } from '../constants';
|
||||
import { StyleOption, PaperSize, StyleCategory } from '../types';
|
||||
import { Check, Type, Printer, Search } from 'lucide-react';
|
||||
import { PaperSize, StyleOption } from '../types';
|
||||
import { Check, Type, Printer, Search, Heart } from 'lucide-react';
|
||||
import { motion } from 'motion/react';
|
||||
import { getPreviewCss } from '../services/templateRenderer';
|
||||
|
||||
interface StyleSelectorProps {
|
||||
templates: StyleOption[];
|
||||
categories: string[];
|
||||
selectedStyle: string | null;
|
||||
onSelectStyle: (id: string) => void;
|
||||
selectedPaperSize: PaperSize;
|
||||
onSelectPaperSize: (size: PaperSize) => void;
|
||||
onGenerate: () => void;
|
||||
isLoading?: boolean;
|
||||
error?: string | null;
|
||||
}
|
||||
|
||||
const SAMPLE_CONTENT = `
|
||||
<h1>The Art of Typography</h1>
|
||||
<p>Typography is the art and technique of arranging type to make written language legible, readable, and appealing when displayed. The arrangement of type involves selecting typefaces, point sizes, line lengths, line-spacing, and letter-spacing.</p>
|
||||
<p>Typography is the art and technique of arranging type to make written language <strong>legible</strong>, <em>readable</em>, and <u>appealing</u> when displayed. The arrangement involves selecting typefaces, point sizes, line lengths, and letter-spacing.</p>
|
||||
|
||||
<h2>1. Visual Hierarchy</h2>
|
||||
<p>Visual hierarchy enables the reader to understand the importance of different sections. By using size, weight, and color, we guide the eye through the document in a logical flow.</p>
|
||||
|
||||
<h3>Key Principles</h3>
|
||||
<p>Effective typography follows timeless principles. Each element serves a purpose, creating harmony between form and function.</p>
|
||||
|
||||
<h4>Micro-Typography</h4>
|
||||
<p>The smallest details matter most. Kerning, tracking, and leading work together to create <code>readable</code> text that flows naturally.</p>
|
||||
|
||||
<blockquote>
|
||||
"Design is not just what it looks like and feels like. Design is how it works."
|
||||
"Design is not just what it looks like and feels like. Design is how it works." — Steve Jobs
|
||||
</blockquote>
|
||||
|
||||
<h2>2. Key Elements</h2>
|
||||
<h2>2. Essential Elements</h2>
|
||||
|
||||
<h3>Unordered Principles</h3>
|
||||
<ul>
|
||||
<li><strong>Typeface:</strong> The design of the letters.</li>
|
||||
<li><strong>Contrast:</strong> Distinguishing elements effectively.</li>
|
||||
<li><strong>Consistency:</strong> Maintaining a coherent structure.</li>
|
||||
<li><strong>Typeface:</strong> The personality of your document</li>
|
||||
<li><strong>Contrast:</strong> Distinguishing elements effectively</li>
|
||||
<li><strong>Consistency:</strong> Maintaining a coherent structure</li>
|
||||
<li><strong>Whitespace:</strong> Breathing room for the eyes</li>
|
||||
</ul>
|
||||
|
||||
<p>Good typography is invisible. It should not distract the reader but rather enhance the reading experience, ensuring the message is delivered clearly and effectively.</p>
|
||||
<h3>Process Steps</h3>
|
||||
<ol>
|
||||
<li>Analyze your content and audience</li>
|
||||
<li>Choose appropriate typefaces</li>
|
||||
<li>Establish hierarchy and rhythm</li>
|
||||
<li>Test and refine the layout</li>
|
||||
</ol>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>3. Technical Implementation</h2>
|
||||
<p>When implementing typography in code, precision is essential. Here's a basic example:</p>
|
||||
|
||||
<pre>function applyTypography(element) {
|
||||
element.style.fontFamily = 'Georgia, serif';
|
||||
element.style.lineHeight = '1.6';
|
||||
element.style.letterSpacing = '0.02em';
|
||||
}</pre>
|
||||
|
||||
<h3>Font Properties Comparison</h3>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Property</th>
|
||||
<th>Serif</th>
|
||||
<th>Sans-Serif</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Readability</td>
|
||||
<td>High (print)</td>
|
||||
<td>High (screen)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Personality</td>
|
||||
<td>Classic</td>
|
||||
<td>Modern</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Use Case</td>
|
||||
<td>Body text</td>
|
||||
<td>Headings</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p>Good typography is invisible. It should not distract the reader but enhance the experience. Visit <a href="https://typography.com">typography.com</a> to learn more about professional typesetting.</p>
|
||||
|
||||
<h5>Advanced Techniques</h5>
|
||||
<p>Mastering typography requires understanding both the rules and when to break them creatively.</p>
|
||||
|
||||
<h6>Final Thoughts</h6>
|
||||
<p>Typography transforms ordinary text into extraordinary communication. Every choice matters.</p>
|
||||
`;
|
||||
|
||||
export const StyleSelector: React.FC<StyleSelectorProps> = ({
|
||||
templates,
|
||||
categories,
|
||||
selectedStyle,
|
||||
onSelectStyle,
|
||||
selectedPaperSize,
|
||||
onSelectPaperSize,
|
||||
onGenerate
|
||||
onGenerate,
|
||||
isLoading,
|
||||
error
|
||||
}) => {
|
||||
const [activeCategory, setActiveCategory] = useState<StyleCategory | 'All'>('All');
|
||||
const [activeCategory, setActiveCategory] = useState<string>('All');
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const [favorites, setFavorites] = useState<string[]>(() => {
|
||||
try {
|
||||
const saved = localStorage.getItem('favoriteTemplates');
|
||||
return saved ? JSON.parse(saved) : [];
|
||||
} catch (e) {
|
||||
console.error('Failed to parse favorites', e);
|
||||
return [];
|
||||
}
|
||||
});
|
||||
|
||||
const iframeRef = useRef<HTMLIFrameElement>(null);
|
||||
|
||||
// Dynamically extract categories from styles and sort them
|
||||
const categories = useMemo(() => {
|
||||
const cats = new Set(TYPOGRAPHY_STYLES.map(s => s.category));
|
||||
return Array.from(cats).sort();
|
||||
}, []);
|
||||
// Persist favorites
|
||||
useEffect(() => {
|
||||
localStorage.setItem('favoriteTemplates', JSON.stringify(favorites));
|
||||
}, [favorites]);
|
||||
|
||||
const toggleFavorite = (e: React.MouseEvent, id: string) => {
|
||||
e.stopPropagation();
|
||||
setFavorites(prev =>
|
||||
prev.includes(id) ? prev.filter(fid => fid !== id) : [...prev, id]
|
||||
);
|
||||
};
|
||||
|
||||
const filteredStyles = useMemo(() => {
|
||||
let styles = TYPOGRAPHY_STYLES;
|
||||
if (activeCategory !== 'All') {
|
||||
styles = TYPOGRAPHY_STYLES.filter(style => style.category === activeCategory);
|
||||
let styles = templates;
|
||||
|
||||
// Filter by category
|
||||
if (activeCategory === 'fav') {
|
||||
styles = styles.filter(style => favorites.includes(style.id));
|
||||
} else if (activeCategory !== 'All') {
|
||||
styles = templates.filter(style => style.category === activeCategory);
|
||||
}
|
||||
|
||||
// Filter by search
|
||||
if (searchQuery.trim()) {
|
||||
const query = searchQuery.toLowerCase();
|
||||
styles = styles.filter(style =>
|
||||
style.name.toLowerCase().includes(query) ||
|
||||
style.description.toLowerCase().includes(query) ||
|
||||
style.category.toLowerCase().includes(query)
|
||||
);
|
||||
}
|
||||
|
||||
// Always sort alphabetically by name
|
||||
return [...styles].sort((a, b) => a.name.localeCompare(b.name));
|
||||
}, [activeCategory]);
|
||||
}, [templates, activeCategory, searchQuery, favorites]);
|
||||
|
||||
const currentStyleObj = useMemo(() =>
|
||||
TYPOGRAPHY_STYLES.find(s => s.id === selectedStyle),
|
||||
[selectedStyle]);
|
||||
const currentStyleObj = useMemo(() =>
|
||||
templates.find(s => s.id === selectedStyle),
|
||||
[templates, selectedStyle]);
|
||||
|
||||
// Track blob URL for cleanup
|
||||
const blobUrlRef = useRef<string | null>(null);
|
||||
|
||||
// Update preview when style changes
|
||||
useEffect(() => {
|
||||
if (!iframeRef.current || !currentStyleObj) return;
|
||||
|
||||
const doc = iframeRef.current.contentDocument;
|
||||
if (doc) {
|
||||
const html = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="${currentStyleObj.googleFontsImport}" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
background-color: #ffffff;
|
||||
margin: 0;
|
||||
padding: 40px;
|
||||
/* Inject default body color from config to ensure lists/quotes inherit correctly */
|
||||
color: #${currentStyleObj.wordConfig.body.color};
|
||||
font-family: sans-serif;
|
||||
/* Apply Selected Style CSS */
|
||||
${currentStyleObj.previewCss}
|
||||
}
|
||||
/* Scrollbar styling for the preview iframe */
|
||||
::-webkit-scrollbar { width: 8px; }
|
||||
::-webkit-scrollbar-track { background: #f1f1f1; }
|
||||
::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 4px; }
|
||||
::-webkit-scrollbar-thumb:hover { background: #94a3b8; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
${SAMPLE_CONTENT}
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
doc.open();
|
||||
doc.write(html);
|
||||
doc.close();
|
||||
|
||||
// Cleanup old blob URL
|
||||
if (blobUrlRef.current) {
|
||||
URL.revokeObjectURL(blobUrlRef.current);
|
||||
blobUrlRef.current = null;
|
||||
}
|
||||
}, [currentStyleObj]);
|
||||
|
||||
// Get CSS from template
|
||||
const templateCss = getPreviewCss(currentStyleObj);
|
||||
|
||||
// DEBUG: Specific markdown constructs for StyleSelector
|
||||
console.log('=== STYLESELECTOR DEBUG (h3, strong, table, ul/ol, li) ===');
|
||||
console.log('h3:', JSON.stringify(currentStyleObj.elements?.h3));
|
||||
console.log('strong:', JSON.stringify(currentStyleObj.elements?.strong));
|
||||
console.log('table:', JSON.stringify(currentStyleObj.elements?.table));
|
||||
console.log('th:', JSON.stringify(currentStyleObj.elements?.th));
|
||||
console.log('td:', JSON.stringify(currentStyleObj.elements?.td));
|
||||
console.log('ul:', JSON.stringify(currentStyleObj.elements?.ul));
|
||||
console.log('ol:', JSON.stringify(currentStyleObj.elements?.ol));
|
||||
console.log('li:', JSON.stringify(currentStyleObj.elements?.li));
|
||||
console.log('=== END STYLESELECTOR DEBUG ===');
|
||||
|
||||
const html = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="${currentStyleObj.googleFontsImport}" rel="stylesheet">
|
||||
<style>
|
||||
/* Reset */
|
||||
* { box-sizing: border-box; }
|
||||
html, body { margin: 0; padding: 0; }
|
||||
|
||||
/* App background (dark) */
|
||||
body {
|
||||
background-color: #18181b;
|
||||
padding: 40px;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* Template CSS - includes .page styles */
|
||||
${templateCss}
|
||||
|
||||
/* Page dimensions (not included in template) */
|
||||
.page {
|
||||
width: ${selectedPaperSize === 'A4' ? '210mm' : '8.5in'};
|
||||
min-height: ${selectedPaperSize === 'A4' ? '297mm' : '11in'};
|
||||
margin: 0 auto;
|
||||
padding: 25mm;
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
/* Scrollbar */
|
||||
::-webkit-scrollbar { width: 8px; }
|
||||
::-webkit-scrollbar-track { background: transparent; }
|
||||
::-webkit-scrollbar-thumb { background: #71717a; border-radius: 4px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page">
|
||||
${SAMPLE_CONTENT}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
// Create blob URL for CSP compliance
|
||||
const blob = new Blob([html], { type: 'text/html' });
|
||||
const blobUrl = URL.createObjectURL(blob);
|
||||
blobUrlRef.current = blobUrl;
|
||||
iframeRef.current.src = blobUrl;
|
||||
|
||||
// Cleanup on unmount
|
||||
return () => {
|
||||
if (blobUrlRef.current) {
|
||||
URL.revokeObjectURL(blobUrlRef.current);
|
||||
blobUrlRef.current = null;
|
||||
}
|
||||
};
|
||||
}, [currentStyleObj, selectedPaperSize]);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="w-full h-full flex items-center justify-center">
|
||||
<motion.div className="text-center" initial={{ opacity: 0 }} animate={{ opacity: 1 }}>
|
||||
<motion.div className="w-12 h-12 border-4 border-indigo-500/30 border-t-indigo-500 rounded-full mx-auto mb-4" animate={{ rotate: 360 }} transition={{ duration: 1, repeat: Infinity, ease: "linear" }} />
|
||||
<p className="text-zinc-400">Loading templates...</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="w-full h-full flex flex-col items-center justify-center p-8 text-center">
|
||||
<motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="max-w-md">
|
||||
<div className="w-16 h-16 bg-red-500/10 rounded-full flex items-center justify-center mx-auto mb-4">
|
||||
<span className="text-2xl">⚠️</span>
|
||||
</div>
|
||||
<h3 className="text-xl font-semibold text-white mb-2">Template Error</h3>
|
||||
<p className="text-zinc-400 mb-6">{error}</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-full h-[calc(100vh-140px)] min-h-[600px] flex flex-col gap-6 max-w-[1600px] mx-auto">
|
||||
|
||||
<div className="w-full h-full min-h-[600px] flex flex-col gap-6 max-w-[1600px] mx-auto">
|
||||
|
||||
{/* Top Controls */}
|
||||
<div className="flex flex-col md:flex-row justify-between items-start md:items-center gap-4 px-1">
|
||||
<div className="flex items-center gap-3">
|
||||
@@ -113,26 +283,25 @@ export const StyleSelector: React.FC<StyleSelectorProps> = ({
|
||||
<Type size={24} />
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold text-zinc-100">Select Typography Style</h2>
|
||||
<p className="text-zinc-400 text-sm">Browse {TYPOGRAPHY_STYLES.length} professional templates</p>
|
||||
<h2 className="text-2xl font-bold text-zinc-100">Select Typography Style</h2>
|
||||
<p className="text-zinc-400 text-sm">Browse {templates.length} professional templates</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="flex items-center gap-4 bg-zinc-900/50 p-1.5 rounded-xl border border-zinc-800/50">
|
||||
<div className="flex items-center gap-2 text-zinc-400 px-3">
|
||||
<Printer size={16} />
|
||||
<span className="text-xs font-semibold uppercase tracking-wider">Format</span>
|
||||
</div>
|
||||
<div className="flex gap-1">
|
||||
<div className="flex items-center gap-2 text-zinc-400 px-3">
|
||||
<Printer size={16} />
|
||||
<span className="text-xs font-semibold uppercase tracking-wider">Format</span>
|
||||
</div>
|
||||
<div className="flex gap-1">
|
||||
{(['Letter', 'A4'] as PaperSize[]).map((size) => (
|
||||
<button
|
||||
key={size}
|
||||
onClick={() => onSelectPaperSize(size)}
|
||||
className={`px-3 py-1.5 rounded-lg text-xs font-bold transition-all ${
|
||||
selectedPaperSize === size
|
||||
? 'bg-zinc-700 text-white shadow-sm'
|
||||
: 'text-zinc-500 hover:text-zinc-300 hover:bg-zinc-800'
|
||||
}`}
|
||||
className={`px-3 py-1.5 rounded-lg text-xs font-bold transition-all ${selectedPaperSize === size
|
||||
? 'bg-zinc-700 text-white shadow-sm'
|
||||
: 'text-zinc-500 hover:text-zinc-300 hover:bg-zinc-800'
|
||||
}`}
|
||||
>
|
||||
{size}
|
||||
</button>
|
||||
@@ -143,59 +312,99 @@ export const StyleSelector: React.FC<StyleSelectorProps> = ({
|
||||
|
||||
{/* Main Split Layout */}
|
||||
<div className="flex-1 grid grid-cols-1 lg:grid-cols-12 gap-6 min-h-0">
|
||||
|
||||
|
||||
{/* LEFT COLUMN: Style List */}
|
||||
<div className="lg:col-span-4 flex flex-col gap-4 min-h-0 bg-zinc-900/30 rounded-2xl border border-zinc-800/50 overflow-hidden">
|
||||
|
||||
|
||||
{/* Category Filter Tabs */}
|
||||
<div className="p-4 border-b border-zinc-800/50 overflow-x-auto no-scrollbar">
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={() => setActiveCategory('All')}
|
||||
className={`px-3 py-1.5 rounded-full text-xs font-semibold whitespace-nowrap transition-all ${
|
||||
activeCategory === 'All'
|
||||
? 'bg-white text-black'
|
||||
: 'bg-zinc-800 text-zinc-400 hover:bg-zinc-700 hover:text-zinc-200'
|
||||
}`}
|
||||
>
|
||||
All
|
||||
</button>
|
||||
{categories.map(cat => (
|
||||
<div className="flex flex-col border-b border-zinc-800/50 bg-zinc-900/20">
|
||||
<div className="p-4 overflow-x-auto no-scrollbar pb-2">
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
key={cat}
|
||||
onClick={() => setActiveCategory(cat)}
|
||||
className={`px-3 py-1.5 rounded-full text-xs font-semibold whitespace-nowrap transition-all ${
|
||||
activeCategory === cat
|
||||
? 'bg-indigo-500 text-white shadow-lg shadow-indigo-500/20'
|
||||
: 'bg-zinc-800 text-zinc-400 hover:bg-zinc-700 hover:text-zinc-200'
|
||||
}`}
|
||||
onClick={() => setActiveCategory('fav')}
|
||||
className={`px-3 py-1.5 rounded-full text-xs font-semibold whitespace-nowrap transition-all flex items-center gap-1.5 ${activeCategory === 'fav'
|
||||
? 'bg-rose-500 text-white shadow-lg shadow-rose-500/20'
|
||||
: 'bg-zinc-800 text-zinc-400 hover:bg-zinc-700 hover:text-zinc-200'
|
||||
}`}
|
||||
>
|
||||
{cat}
|
||||
<Heart size={12} className={activeCategory === 'fav' ? 'fill-current' : ''} />
|
||||
fav
|
||||
</button>
|
||||
))}
|
||||
<div className="w-px h-6 bg-zinc-800 mx-1 self-center" />
|
||||
<button
|
||||
onClick={() => setActiveCategory('All')}
|
||||
className={`px-3 py-1.5 rounded-full text-xs font-semibold whitespace-nowrap transition-all ${activeCategory === 'All'
|
||||
? 'bg-white text-black'
|
||||
: 'bg-zinc-800 text-zinc-400 hover:bg-zinc-700 hover:text-zinc-200'
|
||||
}`}
|
||||
>
|
||||
All
|
||||
</button>
|
||||
{categories.map(cat => (
|
||||
<button
|
||||
key={cat}
|
||||
onClick={() => setActiveCategory(cat)}
|
||||
className={`px-3 py-1.5 rounded-full text-xs font-semibold whitespace-nowrap transition-all ${activeCategory === cat
|
||||
? 'bg-indigo-500 text-white shadow-lg shadow-indigo-500/20'
|
||||
: 'bg-zinc-800 text-zinc-400 hover:bg-zinc-700 hover:text-zinc-200'
|
||||
}`}
|
||||
>
|
||||
{cat}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Search Input */}
|
||||
<div className="px-4 pb-4">
|
||||
<div className="relative group">
|
||||
<Search size={14} className="absolute left-3 top-1/2 -translate-y-1/2 text-zinc-500 group-focus-within:text-indigo-400 transition-colors" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search templates..."
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className="w-full bg-zinc-900 border border-zinc-700 rounded-xl py-2 pl-9 pr-4 text-sm text-zinc-200 placeholder:text-zinc-600 focus:outline-none focus:border-indigo-500/50 focus:ring-1 focus:ring-indigo-500/50 transition-all"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Scrollable List */}
|
||||
<div className="flex-1 overflow-y-auto p-4 space-y-3 custom-scrollbar">
|
||||
{filteredStyles.map((style) => (
|
||||
{filteredStyles.length === 0 ? (
|
||||
<div className="text-center py-8 text-zinc-500">
|
||||
<p className="text-sm">No templates found</p>
|
||||
</div>
|
||||
) : filteredStyles.map((style) => (
|
||||
<div
|
||||
key={style.id}
|
||||
onClick={() => onSelectStyle(style.id)}
|
||||
className={`p-4 rounded-xl border transition-all cursor-pointer group relative
|
||||
${selectedStyle === style.id
|
||||
? 'border-indigo-500 bg-indigo-500/10 shadow-[0_0_15px_rgba(99,102,241,0.15)]'
|
||||
${selectedStyle === style.id
|
||||
? 'border-indigo-500 bg-indigo-500/10 shadow-[0_0_15px_rgba(99,102,241,0.15)]'
|
||||
: 'border-zinc-800 bg-zinc-900/40 hover:border-zinc-700 hover:bg-zinc-800'}`}
|
||||
>
|
||||
<div className="flex justify-between items-start mb-1">
|
||||
<h3 className={`font-bold text-sm ${selectedStyle === style.id ? 'text-white' : 'text-zinc-300'}`}>
|
||||
{style.name}
|
||||
</h3>
|
||||
{selectedStyle === style.id && (
|
||||
<div className="bg-indigo-500 rounded-full p-0.5">
|
||||
<Check size={12} className="text-white" />
|
||||
</div>
|
||||
)}
|
||||
<div className="flex justify-between items-start mb-1 gap-2">
|
||||
<h3 className={`font-bold text-sm ${selectedStyle === style.id ? 'text-white' : 'text-zinc-300'}`}>
|
||||
{style.name}
|
||||
</h3>
|
||||
<div className="flex items-center gap-2 shrink-0">
|
||||
<button
|
||||
onClick={(e) => toggleFavorite(e, style.id)}
|
||||
className={`p-1.5 rounded-full transition-all ${favorites.includes(style.id)
|
||||
? 'text-rose-400 bg-rose-500/10 hover:bg-rose-500/20'
|
||||
: 'text-zinc-600 hover:text-zinc-400 hover:bg-zinc-700/50'
|
||||
}`}
|
||||
>
|
||||
<Heart size={14} className={favorites.includes(style.id) ? 'fill-current' : ''} />
|
||||
</button>
|
||||
{selectedStyle === style.id && (
|
||||
<div className="bg-indigo-500 rounded-full p-0.5">
|
||||
<Check size={12} className="text-white" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-xs text-zinc-500 line-clamp-2 leading-relaxed mb-2">{style.description}</p>
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -211,7 +420,7 @@ export const StyleSelector: React.FC<StyleSelectorProps> = ({
|
||||
|
||||
{/* RIGHT COLUMN: Preview Window */}
|
||||
<div className="lg:col-span-8 flex flex-col min-h-0 bg-zinc-950 rounded-2xl border border-zinc-800 shadow-2xl relative overflow-hidden">
|
||||
|
||||
|
||||
{/* Preview Header */}
|
||||
<div className="h-12 border-b border-zinc-800 bg-zinc-900/50 flex items-center px-4 justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -247,17 +456,17 @@ export const StyleSelector: React.FC<StyleSelectorProps> = ({
|
||||
|
||||
{/* Bottom Action Bar */}
|
||||
<div className="p-4 border-t border-zinc-800 bg-zinc-900/50 flex justify-end items-center gap-4">
|
||||
<button
|
||||
onClick={onGenerate}
|
||||
disabled={!selectedStyle}
|
||||
className="flex items-center gap-2 px-6 py-3 bg-indigo-600 hover:bg-indigo-500 text-white font-bold rounded-xl transition-all shadow-lg hover:shadow-indigo-500/25 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
<span>Apply Style & Convert</span>
|
||||
<Printer size={18} />
|
||||
</button>
|
||||
<button
|
||||
onClick={onGenerate}
|
||||
disabled={!selectedStyle}
|
||||
className="flex items-center gap-2 px-6 py-3 bg-indigo-600 hover:bg-indigo-500 text-white font-bold rounded-xl transition-all shadow-lg hover:shadow-indigo-500/25 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
<span>Apply Style & Convert</span>
|
||||
<Printer size={18} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
41
src/components/ZoomControl.tsx
Normal file
41
src/components/ZoomControl.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
import React from 'react';
|
||||
import { motion } from 'motion/react';
|
||||
import { ZoomIn, ZoomOut } from 'lucide-react';
|
||||
|
||||
interface ZoomControlProps {
|
||||
zoom: number;
|
||||
onZoomChange: (zoom: number) => void;
|
||||
}
|
||||
|
||||
export const ZoomControl: React.FC<ZoomControlProps> = ({ zoom, onZoomChange }) => {
|
||||
const decreaseZoom = () => onZoomChange(Math.max(50, zoom - 10));
|
||||
const increaseZoom = () => onZoomChange(Math.min(200, zoom + 10));
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-2 bg-zinc-900/80 rounded-lg border border-zinc-800 px-2 py-1">
|
||||
<motion.button
|
||||
onClick={decreaseZoom}
|
||||
whileHover={{ scale: 1.1 }}
|
||||
whileTap={{ scale: 0.9 }}
|
||||
className="p-1 text-zinc-400 hover:text-white transition-colors"
|
||||
aria-label="Zoom out"
|
||||
>
|
||||
<ZoomOut size={16} />
|
||||
</motion.button>
|
||||
|
||||
<span className="text-xs font-medium text-zinc-300 min-w-[3rem] text-center">
|
||||
{zoom}%
|
||||
</span>
|
||||
|
||||
<motion.button
|
||||
onClick={increaseZoom}
|
||||
whileHover={{ scale: 1.1 }}
|
||||
whileTap={{ scale: 0.9 }}
|
||||
className="p-1 text-zinc-400 hover:text-white transition-colors"
|
||||
aria-label="Zoom in"
|
||||
>
|
||||
<ZoomIn size={16} />
|
||||
</motion.button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,3 +1,48 @@
|
||||
import { ALL_STYLES } from './styles/index';
|
||||
import React from 'react';
|
||||
import { StyleOption } from './types';
|
||||
import {
|
||||
Minus, BookOpen, Building2, Cpu, Palette,
|
||||
Sparkles, Heart, GraduationCap, Factory, Globe,
|
||||
Zap, Coffee, Leaf
|
||||
} from 'lucide-react';
|
||||
|
||||
export const TYPOGRAPHY_STYLES = ALL_STYLES;
|
||||
// Category icons mapping
|
||||
export const CATEGORY_ICONS: Record<string, React.ComponentType<{ size?: number }>> = {
|
||||
'Minimalist': Minus,
|
||||
'Editorial': BookOpen,
|
||||
'Corporate': Building2,
|
||||
'Tech': Cpu,
|
||||
'Creative': Palette,
|
||||
'Vintage': Sparkles,
|
||||
'Academic': GraduationCap,
|
||||
'Lifestyle': Heart,
|
||||
'Industrial': Factory,
|
||||
'Nature': Leaf,
|
||||
'Core': Globe,
|
||||
'Other': Zap
|
||||
};
|
||||
|
||||
// Category display names mapping (for icons)
|
||||
export const getCategoryIcon = (category: string) => {
|
||||
// Try exact match first
|
||||
if (CATEGORY_ICONS[category]) {
|
||||
return CATEGORY_ICONS[category];
|
||||
}
|
||||
|
||||
// Try common variations
|
||||
const normalized = category.toLowerCase();
|
||||
if (normalized.includes('minimal')) return Minus;
|
||||
if (normalized.includes('edit')) return BookOpen;
|
||||
if (normalized.includes('corp')) return Building2;
|
||||
if (normalized.includes('tech')) return Cpu;
|
||||
if (normalized.includes('creat')) return Palette;
|
||||
if (normalized.includes('vint')) return Sparkles;
|
||||
if (normalized.includes('acad')) return GraduationCap;
|
||||
if (normalized.includes('life')) return Heart;
|
||||
if (normalized.includes('indust')) return Factory;
|
||||
|
||||
return Zap;
|
||||
};
|
||||
|
||||
// Templates are now loaded dynamically from TypoGenie-Data/templates/
|
||||
// See README-TEMPLATES.md for documentation on creating custom templates
|
||||
|
||||
196
src/hooks/useKeyboardNavigation.ts
Normal file
196
src/hooks/useKeyboardNavigation.ts
Normal file
@@ -0,0 +1,196 @@
|
||||
import React, { useEffect, useCallback, useRef, useState } from 'react';
|
||||
|
||||
interface UseKeyboardNavOptions {
|
||||
onArrowUp?: () => void;
|
||||
onArrowDown?: () => void;
|
||||
onArrowLeft?: () => void;
|
||||
onArrowRight?: () => void;
|
||||
onEnter?: () => void;
|
||||
onEscape?: () => void;
|
||||
onTab?: () => void;
|
||||
onShiftTab?: () => void;
|
||||
onSpace?: () => void;
|
||||
onHome?: () => void;
|
||||
onEnd?: () => void;
|
||||
onPageUp?: () => void;
|
||||
onPageDown?: () => void;
|
||||
onCtrlEnter?: () => void;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export const useKeyboardNavigation = (options: UseKeyboardNavOptions, deps: React.DependencyList) => {
|
||||
const optionsRef = useRef(options);
|
||||
optionsRef.current = options;
|
||||
|
||||
useEffect(() => {
|
||||
if (optionsRef.current.disabled) return;
|
||||
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
const opts = optionsRef.current;
|
||||
|
||||
// Handle Ctrl+Enter separately
|
||||
if (e.key === 'Enter' && e.ctrlKey) {
|
||||
if (opts.onCtrlEnter) {
|
||||
e.preventDefault();
|
||||
opts.onCtrlEnter();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (e.key) {
|
||||
case 'ArrowUp':
|
||||
if (opts.onArrowUp) {
|
||||
e.preventDefault();
|
||||
opts.onArrowUp();
|
||||
}
|
||||
break;
|
||||
case 'ArrowDown':
|
||||
if (opts.onArrowDown) {
|
||||
e.preventDefault();
|
||||
opts.onArrowDown();
|
||||
}
|
||||
break;
|
||||
case 'ArrowLeft':
|
||||
if (opts.onArrowLeft) {
|
||||
e.preventDefault();
|
||||
opts.onArrowLeft();
|
||||
}
|
||||
break;
|
||||
case 'ArrowRight':
|
||||
if (opts.onArrowRight) {
|
||||
e.preventDefault();
|
||||
opts.onArrowRight();
|
||||
}
|
||||
break;
|
||||
case 'Enter':
|
||||
if (opts.onEnter) {
|
||||
e.preventDefault();
|
||||
opts.onEnter();
|
||||
}
|
||||
break;
|
||||
case 'Escape':
|
||||
if (opts.onEscape) {
|
||||
e.preventDefault();
|
||||
opts.onEscape();
|
||||
}
|
||||
break;
|
||||
case 'Tab':
|
||||
if (e.shiftKey && opts.onShiftTab) {
|
||||
e.preventDefault();
|
||||
opts.onShiftTab();
|
||||
} else if (!e.shiftKey && opts.onTab) {
|
||||
e.preventDefault();
|
||||
opts.onTab();
|
||||
}
|
||||
break;
|
||||
case ' ':
|
||||
if (opts.onSpace) {
|
||||
e.preventDefault();
|
||||
opts.onSpace();
|
||||
}
|
||||
break;
|
||||
case 'Home':
|
||||
if (opts.onHome) {
|
||||
e.preventDefault();
|
||||
opts.onHome();
|
||||
}
|
||||
break;
|
||||
case 'End':
|
||||
if (opts.onEnd) {
|
||||
e.preventDefault();
|
||||
opts.onEnd();
|
||||
}
|
||||
break;
|
||||
case 'PageUp':
|
||||
if (opts.onPageUp) {
|
||||
e.preventDefault();
|
||||
opts.onPageUp();
|
||||
}
|
||||
break;
|
||||
case 'PageDown':
|
||||
if (opts.onPageDown) {
|
||||
e.preventDefault();
|
||||
opts.onPageDown();
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('keydown', handleKeyDown);
|
||||
return () => window.removeEventListener('keydown', handleKeyDown);
|
||||
}, deps);
|
||||
};
|
||||
|
||||
export const useFocusableList = <T extends HTMLElement>(
|
||||
itemCount: number,
|
||||
options: {
|
||||
onSelect?: (index: number) => void;
|
||||
onEscape?: () => void;
|
||||
orientation?: 'horizontal' | 'vertical';
|
||||
wrap?: boolean;
|
||||
} = {}
|
||||
) => {
|
||||
const [focusedIndex, setFocusedIndex] = useState(-1);
|
||||
const itemRefs = useRef<(T | null)[]>([]);
|
||||
const { onSelect, onEscape, orientation = 'vertical', wrap = true } = options;
|
||||
|
||||
const focusItem = useCallback((index: number) => {
|
||||
if (index < 0 || index >= itemCount) return;
|
||||
setFocusedIndex(index);
|
||||
itemRefs.current[index]?.focus();
|
||||
itemRefs.current[index]?.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||
}, [itemCount]);
|
||||
|
||||
const handleArrowNext = useCallback(() => {
|
||||
const nextIndex = focusedIndex + 1;
|
||||
if (nextIndex < itemCount) {
|
||||
focusItem(nextIndex);
|
||||
} else if (wrap) {
|
||||
focusItem(0);
|
||||
}
|
||||
}, [focusedIndex, itemCount, wrap, focusItem]);
|
||||
|
||||
const handleArrowPrev = useCallback(() => {
|
||||
const prevIndex = focusedIndex - 1;
|
||||
if (prevIndex >= 0) {
|
||||
focusItem(prevIndex);
|
||||
} else if (wrap) {
|
||||
focusItem(itemCount - 1);
|
||||
}
|
||||
}, [focusedIndex, itemCount, wrap, focusItem]);
|
||||
|
||||
const handleEnter = useCallback(() => {
|
||||
if (focusedIndex >= 0 && onSelect) {
|
||||
onSelect(focusedIndex);
|
||||
}
|
||||
}, [focusedIndex, onSelect]);
|
||||
|
||||
const handleHome = useCallback(() => {
|
||||
focusItem(0);
|
||||
}, [focusItem]);
|
||||
|
||||
const handleEnd = useCallback(() => {
|
||||
focusItem(itemCount - 1);
|
||||
}, [focusItem, itemCount]);
|
||||
|
||||
const setItemRef = useCallback((index: number) => (el: T | null) => {
|
||||
itemRefs.current[index] = el;
|
||||
}, []);
|
||||
|
||||
useKeyboardNavigation({
|
||||
[orientation === 'vertical' ? 'onArrowDown' : 'onArrowRight']: handleArrowNext,
|
||||
[orientation === 'vertical' ? 'onArrowUp' : 'onArrowLeft']: handleArrowPrev,
|
||||
onEnter: handleEnter,
|
||||
onEscape,
|
||||
onHome: handleHome,
|
||||
onEnd: handleEnd,
|
||||
}, [handleArrowNext, handleArrowPrev, handleEnter, onEscape, handleHome, handleEnd]);
|
||||
|
||||
return {
|
||||
focusedIndex,
|
||||
setFocusedIndex,
|
||||
focusItem,
|
||||
setItemRef,
|
||||
itemRefs,
|
||||
};
|
||||
};
|
||||
86
src/hooks/useSettings.ts
Normal file
86
src/hooks/useSettings.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
|
||||
interface Settings {
|
||||
uiZoom: number;
|
||||
}
|
||||
|
||||
const DEFAULT_SETTINGS: Settings = {
|
||||
uiZoom: 100,
|
||||
};
|
||||
|
||||
export const useSettings = () => {
|
||||
const [settings, setSettings] = useState<Settings>(DEFAULT_SETTINGS);
|
||||
const [isLoaded, setIsLoaded] = useState(false);
|
||||
|
||||
// Load settings from localStorage
|
||||
useEffect(() => {
|
||||
const loadSettings = () => {
|
||||
try {
|
||||
const saved = localStorage.getItem('typogenie-settings');
|
||||
if (saved) {
|
||||
const parsed = JSON.parse(saved);
|
||||
const merged = { ...DEFAULT_SETTINGS, ...parsed };
|
||||
setSettings(merged);
|
||||
// Apply zoom immediately on load
|
||||
applyZoom(merged.uiZoom);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to load settings:', e);
|
||||
}
|
||||
setIsLoaded(true);
|
||||
};
|
||||
loadSettings();
|
||||
}, []);
|
||||
|
||||
// Apply zoom using font-size scaling on root element
|
||||
// This is the most reliable way to scale UI while preserving scrollability
|
||||
const applyZoom = (zoom: number) => {
|
||||
const scale = zoom / 100;
|
||||
const root = document.documentElement;
|
||||
|
||||
// Base font size is 16px, scale it
|
||||
root.style.fontSize = `${16 * scale}px`;
|
||||
|
||||
// Store zoom value as CSS variable for other calculations
|
||||
root.style.setProperty('--ui-zoom', String(scale));
|
||||
root.style.setProperty('--ui-zoom-percent', `${zoom}%`);
|
||||
|
||||
// Adjust the app container
|
||||
const appRoot = document.getElementById('root');
|
||||
if (appRoot) {
|
||||
// Remove any transform-based scaling
|
||||
appRoot.style.transform = 'none';
|
||||
appRoot.style.width = '100%';
|
||||
appRoot.style.height = '100%';
|
||||
}
|
||||
};
|
||||
|
||||
// Save settings when they change
|
||||
const saveSettings = useCallback((newSettings: Partial<Settings>) => {
|
||||
const updated = { ...settings, ...newSettings };
|
||||
setSettings(updated);
|
||||
|
||||
// Apply zoom immediately
|
||||
if (newSettings.uiZoom !== undefined) {
|
||||
applyZoom(newSettings.uiZoom);
|
||||
}
|
||||
|
||||
try {
|
||||
localStorage.setItem('typogenie-settings', JSON.stringify(updated));
|
||||
} catch (e) {
|
||||
console.error('Failed to save settings:', e);
|
||||
}
|
||||
}, [settings]);
|
||||
|
||||
const setUiZoom = useCallback((zoom: number) => {
|
||||
const clamped = Math.max(50, Math.min(200, zoom));
|
||||
saveSettings({ uiZoom: clamped });
|
||||
}, [saveSettings]);
|
||||
|
||||
return {
|
||||
settings,
|
||||
isLoaded,
|
||||
setUiZoom,
|
||||
uiZoom: settings.uiZoom,
|
||||
};
|
||||
};
|
||||
88
src/hooks/useTemplates.ts
Normal file
88
src/hooks/useTemplates.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import { useState, useEffect, useCallback, useMemo } from 'react';
|
||||
import { StyleOption } from '../types';
|
||||
import { loadTemplates, ensureTemplatesFolder, openTemplatesFolder } from '../services/templateLoader';
|
||||
|
||||
interface UseTemplatesReturn {
|
||||
templates: StyleOption[];
|
||||
isLoading: boolean;
|
||||
error: string | null;
|
||||
refresh: () => Promise<void>;
|
||||
openFolder: () => Promise<void>;
|
||||
getTemplate: (id: string) => StyleOption | undefined;
|
||||
categories: string[];
|
||||
templatesByCategory: Map<string, StyleOption[]>;
|
||||
}
|
||||
|
||||
export const useTemplates = (): UseTemplatesReturn => {
|
||||
const [templates, setTemplates] = useState<StyleOption[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const refresh = useCallback(async () => {
|
||||
setIsLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const result = await loadTemplates();
|
||||
setTemplates(result.templates);
|
||||
if (result.error) {
|
||||
setError(result.error);
|
||||
} else if (result.templates.length === 0) {
|
||||
setError('No templates found. Click "Open Templates Folder" to see where they should be.');
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to load templates:', e);
|
||||
const errorMsg = e instanceof Error ? e.message : String(e);
|
||||
setError(`Failed to load templates: ${errorMsg}`);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const openFolder = useCallback(async () => {
|
||||
try {
|
||||
const result = await openTemplatesFolder();
|
||||
if (!result.success && result.error) {
|
||||
setError(`Failed to open folder: ${result.error}`);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to open templates folder:', e);
|
||||
setError('Failed to open templates folder. Try navigating to the folder manually.');
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
refresh();
|
||||
}, [refresh]);
|
||||
|
||||
const getTemplate = useCallback((id: string) => {
|
||||
return templates.find(t => t.id === id);
|
||||
}, [templates]);
|
||||
|
||||
const categories = useMemo(() => {
|
||||
const cats = new Set<string>();
|
||||
templates.forEach(t => cats.add(t.category));
|
||||
return Array.from(cats).sort();
|
||||
}, [templates]);
|
||||
|
||||
const templatesByCategory = useMemo(() => {
|
||||
const map = new Map<string, StyleOption[]>();
|
||||
templates.forEach(t => {
|
||||
if (!map.has(t.category)) {
|
||||
map.set(t.category, []);
|
||||
}
|
||||
map.get(t.category)!.push(t);
|
||||
});
|
||||
return map;
|
||||
}, [templates]);
|
||||
|
||||
return {
|
||||
templates,
|
||||
isLoading,
|
||||
error,
|
||||
refresh,
|
||||
openFolder,
|
||||
getTemplate,
|
||||
categories,
|
||||
templatesByCategory,
|
||||
};
|
||||
};
|
||||
110
src/index.css
Normal file
110
src/index.css
Normal file
@@ -0,0 +1,110 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
/* Custom scrollbar - always visible at consistent size */
|
||||
* {
|
||||
scrollbar-width: 6px;
|
||||
scrollbar-color: #52525b transparent;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-thumb {
|
||||
background: #52525b;
|
||||
border-radius: 3px;
|
||||
min-height: 40px;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-thumb:hover {
|
||||
background: #71717a;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-corner {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Inter', sans-serif;
|
||||
background-color: #09090b;
|
||||
color: #e4e4e7;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#root {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
/* Force custom scrollbars everywhere */
|
||||
html ::-webkit-scrollbar,
|
||||
body ::-webkit-scrollbar,
|
||||
* ::-webkit-scrollbar {
|
||||
width: 6px !important;
|
||||
height: 6px !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
html ::-webkit-scrollbar-track,
|
||||
body ::-webkit-scrollbar-track,
|
||||
* ::-webkit-scrollbar-track {
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
html ::-webkit-scrollbar-thumb,
|
||||
body ::-webkit-scrollbar-thumb,
|
||||
* ::-webkit-scrollbar-thumb {
|
||||
background: #52525b !important;
|
||||
border-radius: 3px !important;
|
||||
min-height: 40px !important;
|
||||
}
|
||||
|
||||
html ::-webkit-scrollbar-thumb:hover,
|
||||
body ::-webkit-scrollbar-thumb:hover,
|
||||
* ::-webkit-scrollbar-thumb:hover {
|
||||
background: #71717a !important;
|
||||
}
|
||||
|
||||
/* Firefox */
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
scrollbar-width: 6px !important;
|
||||
scrollbar-color: #52525b transparent !important;
|
||||
}
|
||||
|
||||
/* No scrollbar utility */
|
||||
.no-scrollbar::-webkit-scrollbar {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.no-scrollbar {
|
||||
-ms-overflow-style: none !important;
|
||||
scrollbar-width: none !important;
|
||||
}
|
||||
|
||||
/* Focus ring spacing */
|
||||
.focus-ring-spacing {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.focus-ring-spacing:focus-within {
|
||||
outline: 2px solid rgba(99, 102, 241, 0.3);
|
||||
outline-offset: -2px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import App from './App';
|
||||
import './index.css';
|
||||
|
||||
const rootElement = document.getElementById('root');
|
||||
if (!rootElement) {
|
||||
@@ -12,4 +13,4 @@ root.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
);
|
||||
);
|
||||
|
||||
74
src/services/defaultTemplates.ts
Normal file
74
src/services/defaultTemplates.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
// Default templates embedded in the app
|
||||
// These are written to disk on first run if no templates exist
|
||||
|
||||
export const defaultTemplates: Record<string, string> = {
|
||||
"academic/research-paper.json": JSON.stringify({
|
||||
"id": "research-paper",
|
||||
"name": "Research Paper",
|
||||
"category": "Academic",
|
||||
"description": "Formal academic formatting for research papers and scholarly articles.",
|
||||
"vibe": "Scholarly, Formal, Precise",
|
||||
"googleFontsImport": "https://fonts.googleapis.com/css2?family=Crimson+Text:ital,wght@0,400;0,600;0,700;1,400&display=swap",
|
||||
"typography": {
|
||||
"fonts": { "heading": "Crimson Text", "body": "Crimson Text", "code": "Consolas, Monaco, monospace" },
|
||||
"colors": { "text": "000000", "textSecondary": "444444", "background": "FFFFFF", "accent": "2F5496", "border": "CCCCCC", "codeBg": "F5F5F5", "blockquoteBorder": "2F5496" }
|
||||
},
|
||||
"elements": {
|
||||
"h1": { "font": "heading", "size": 28, "color": "text", "bold": true, "align": "center", "spacing": { "before": 24, "after": 18, "line": 1.2 } },
|
||||
"h2": { "font": "heading", "size": 14, "color": "text", "bold": true, "align": "left", "spacing": { "before": 18, "after": 8, "line": 1.2 } },
|
||||
"h3": { "font": "heading", "size": 12, "color": "text", "bold": true, "align": "left", "spacing": { "before": 14, "after": 6, "line": 1.2 } },
|
||||
"h4": { "font": "heading", "size": 11, "color": "text", "bold": true, "italic": true, "align": "left", "spacing": { "before": 12, "after": 4, "line": 1.2 } },
|
||||
"p": { "font": "body", "size": 11, "color": "text", "align": "justify", "spacing": { "before": 0, "after": 0, "line": 1.8 }, "indent": 24 },
|
||||
"blockquote": { "font": "body", "size": 10.5, "color": "textSecondary", "italic": true, "spacing": { "before": 12, "after": 12, "line": 1.5 }, "indent": 36, "borderLeft": { "color": "accent", "width": 3, "style": "solid" } },
|
||||
"code": { "font": "code", "size": 9.5, "color": "text", "background": "codeBg" },
|
||||
"pre": { "font": "code", "size": 9, "color": "text", "background": "codeBg", "spacing": { "before": 12, "after": 12 }, "padding": 12, "border": { "color": "border", "width": 1, "style": "solid" } },
|
||||
"ul": { "spacing": { "before": 8, "after": 8 }, "indent": 24, "bullet": "disc" },
|
||||
"ol": { "spacing": { "before": 8, "after": 8 }, "indent": 24, "numbering": "decimal" },
|
||||
"li": { "font": "body", "size": 11, "spacing": { "before": 2, "after": 2 } },
|
||||
"strong": { "font": "body", "bold": true },
|
||||
"em": { "font": "body", "italic": true },
|
||||
"a": { "font": "body", "color": "accent", "underline": true },
|
||||
"table": { "spacing": { "before": 12, "after": 12 }, "border": { "color": "border", "width": 1, "style": "solid" } },
|
||||
"th": { "font": "heading", "size": 10, "bold": true, "background": "F0F0F0", "padding": 8 },
|
||||
"td": { "font": "body", "size": 10, "padding": 8 },
|
||||
"hr": { "border": { "color": "border", "width": 1, "style": "solid" }, "spacing": { "before": 18, "after": 18 } }
|
||||
},
|
||||
"page": { "margins": { "top": 72, "bottom": 72, "left": 72, "right": 72 } }
|
||||
}, null, 2),
|
||||
|
||||
"core/default.json": JSON.stringify({
|
||||
"id": "default",
|
||||
"name": "Default Clean",
|
||||
"category": "Core",
|
||||
"description": "Clean, versatile default style that works for any document type.",
|
||||
"vibe": "Clean, Versatile, Professional",
|
||||
"googleFontsImport": "https://fonts.googleapis.com/css2?family=Source+Sans+3:wght@400;600;700&display=swap",
|
||||
"typography": {
|
||||
"fonts": { "heading": "Source Sans 3", "body": "Source Sans 3", "code": "Source Sans 3" },
|
||||
"colors": { "text": "1A1A1A", "textSecondary": "2D2D2D", "background": "FFFFFF", "accent": "2563EB", "border": "E5E5E5", "codeBg": "F5F5F5", "blockquoteBorder": "2563EB" }
|
||||
},
|
||||
"elements": {
|
||||
"h1": { "font": "heading", "size": 28, "color": "text", "bold": true, "align": "left", "spacing": { "before": 20, "after": 10 } },
|
||||
"h2": { "font": "heading", "size": 15, "color": "textSecondary", "bold": true, "align": "left", "spacing": { "before": 14, "after": 7 } },
|
||||
"h3": { "font": "heading", "size": 13, "color": "textSecondary", "bold": true, "align": "left", "spacing": { "before": 12, "after": 6 } },
|
||||
"p": { "font": "body", "size": 11, "color": "333333", "align": "left", "spacing": { "before": 0, "after": 9, "line": 1.6 } },
|
||||
"blockquote": { "font": "body", "size": 11, "color": "textSecondary", "italic": true, "spacing": { "before": 12, "after": 12 }, "borderLeft": { "color": "accent", "width": 4, "style": "solid" } },
|
||||
"code": { "font": "code", "size": 9.5, "background": "codeBg" },
|
||||
"pre": { "font": "code", "size": 9, "background": "codeBg", "padding": 12 },
|
||||
"ul": { "spacing": { "before": 8, "after": 8 }, "indent": 24 },
|
||||
"ol": { "spacing": { "before": 8, "after": 8 }, "indent": 24 },
|
||||
"li": { "font": "body", "size": 11 },
|
||||
"strong": { "font": "body", "bold": true },
|
||||
"em": { "font": "body", "italic": true },
|
||||
"a": { "font": "body", "color": "accent", "underline": true },
|
||||
"table": { "spacing": { "before": 12, "after": 12 } },
|
||||
"th": { "font": "heading", "size": 10, "bold": true, "background": "F0F0F0" },
|
||||
"td": { "font": "body", "size": 10 },
|
||||
"hr": { "border": { "color": "border", "width": 1, "style": "solid" } }
|
||||
},
|
||||
"page": { "margins": { "top": 72, "bottom": 72, "left": 72, "right": 72 } }
|
||||
}, null, 2)
|
||||
};
|
||||
|
||||
// List of all template paths that should exist
|
||||
export const templatePaths = Object.keys(defaultTemplates);
|
||||
247
src/services/templateLoader.ts
Normal file
247
src/services/templateLoader.ts
Normal file
@@ -0,0 +1,247 @@
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { StyleOption, DocxStyleConfig, ElementStyle, FontConfig, ColorPalette } from '../types';
|
||||
import { generatePreviewCss, generateWordConfig } from './templateRenderer';
|
||||
|
||||
interface RawTemplate {
|
||||
id: string;
|
||||
name: string;
|
||||
category?: string;
|
||||
description?: string;
|
||||
vibe?: string;
|
||||
googleFontsImport?: string;
|
||||
typography?: {
|
||||
fonts?: FontConfig;
|
||||
colors?: ColorPalette;
|
||||
};
|
||||
elements?: Record<string, ElementStyle>;
|
||||
page?: Record<string, any>;
|
||||
wordConfig?: Record<string, any>;
|
||||
previewCss?: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
interface TemplateFile {
|
||||
name: string;
|
||||
content: string;
|
||||
category: string; // Folder-based category from Rust
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a color reference or returns the color directly
|
||||
*/
|
||||
function resolveColor(color: string | undefined, palette: ColorPalette): string {
|
||||
if (!color) return '#000000';
|
||||
if (palette[color as keyof ColorPalette]) {
|
||||
return '#' + palette[color as keyof ColorPalette];
|
||||
}
|
||||
return color.startsWith('#') ? color : '#' + color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a font reference or returns the font directly
|
||||
*/
|
||||
function resolveFont(font: string | undefined, fonts: FontConfig): string {
|
||||
if (!font) return 'serif';
|
||||
if (fonts[font as keyof FontConfig]) {
|
||||
return fonts[font as keyof FontConfig]!;
|
||||
}
|
||||
return font;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates preview CSS from unified template structure
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
|
||||
|
||||
/**
|
||||
* Validate that a parsed object conforms to the StyleOption interface
|
||||
*/
|
||||
function validateTemplate(raw: RawTemplate, filename: string): StyleOption | null {
|
||||
if (!raw.id || typeof raw.id !== 'string') {
|
||||
console.error(`Invalid template in ${filename}: missing or invalid 'id'`);
|
||||
return null;
|
||||
}
|
||||
if (!raw.name || typeof raw.name !== 'string') {
|
||||
console.error(`Invalid template in ${filename}: missing or invalid 'name'`);
|
||||
return null;
|
||||
}
|
||||
|
||||
const hasUnifiedStructure = raw.elements && raw.typography;
|
||||
|
||||
let wordConfig: StyleOption['wordConfig'];
|
||||
let previewCss: string;
|
||||
|
||||
if (hasUnifiedStructure) {
|
||||
const fonts = raw.typography?.fonts || {};
|
||||
const palette = raw.typography?.colors || {};
|
||||
const elements = raw.elements || {};
|
||||
|
||||
// Only generate wordConfig if it's missing or incomplete in the raw template
|
||||
// Prefer the raw wordConfig if it exists (allows manual overrides)
|
||||
if (raw.wordConfig && Object.keys(raw.wordConfig).length > 0) {
|
||||
wordConfig = raw.wordConfig as StyleOption['wordConfig'];
|
||||
} else {
|
||||
// Use the imported generator which now has better logic
|
||||
wordConfig = generateWordConfig(elements, fonts, palette) as StyleOption['wordConfig'];
|
||||
}
|
||||
|
||||
// Similarly for previewCss - prefer explicit override
|
||||
if (raw.previewCss) {
|
||||
previewCss = raw.previewCss;
|
||||
} else {
|
||||
previewCss = generatePreviewCss(elements, fonts, palette);
|
||||
}
|
||||
} else {
|
||||
const defaultHeading1: DocxStyleConfig = {
|
||||
font: 'Arial', size: 24, color: '000000', align: 'left', spacing: { before: 240, after: 120, line: 240 }
|
||||
};
|
||||
const defaultHeading2: DocxStyleConfig = {
|
||||
font: 'Arial', size: 18, color: '333333', align: 'left', spacing: { before: 200, after: 100, line: 240 }
|
||||
};
|
||||
const defaultBody: DocxStyleConfig = {
|
||||
font: 'Arial', size: 11, color: '333333', align: 'left', spacing: { before: 0, after: 120, line: 276 }
|
||||
};
|
||||
|
||||
wordConfig = raw.wordConfig && raw.wordConfig.heading1 && raw.wordConfig.heading2 && raw.wordConfig.body
|
||||
? {
|
||||
heading1: { ...defaultHeading1, ...raw.wordConfig.heading1 },
|
||||
heading2: { ...defaultHeading2, ...raw.wordConfig.heading2 },
|
||||
body: { ...defaultBody, ...raw.wordConfig.body },
|
||||
accentColor: raw.wordConfig.accentColor || '000000'
|
||||
}
|
||||
: {
|
||||
heading1: defaultHeading1,
|
||||
heading2: defaultHeading2,
|
||||
body: defaultBody,
|
||||
accentColor: '000000'
|
||||
};
|
||||
|
||||
previewCss = raw.previewCss || 'font-family: Arial, sans-serif;';
|
||||
}
|
||||
|
||||
const template: StyleOption = {
|
||||
id: raw.id,
|
||||
name: raw.name,
|
||||
category: raw.category || 'Other',
|
||||
description: raw.description || '',
|
||||
vibe: raw.vibe || '',
|
||||
googleFontsImport: raw.googleFontsImport || '',
|
||||
wordConfig,
|
||||
previewCss,
|
||||
// Preserve unified template structure if present
|
||||
...(raw.typography && { typography: raw.typography }),
|
||||
...(raw.elements && { elements: raw.elements }),
|
||||
...(raw.page && { page: raw.page })
|
||||
};
|
||||
|
||||
const extraFields = Object.entries(raw).reduce((acc, [key, val]) => {
|
||||
if (!['id', 'name', 'category', 'description', 'vibe', 'googleFontsImport', 'wordConfig', 'previewCss', 'typography', 'elements', 'page'].includes(key)) {
|
||||
acc[key] = val;
|
||||
}
|
||||
return acc;
|
||||
}, {} as Record<string, any>);
|
||||
|
||||
return { ...template, ...extraFields };
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug function to check paths
|
||||
*/
|
||||
export async function debugPaths(): Promise<string> {
|
||||
try {
|
||||
return await invoke<string>('debug_paths');
|
||||
} catch (e) {
|
||||
return `Error: ${e}`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all templates from the portable folder (next to EXE)
|
||||
* Uses Rust backend for file operations since BaseDirectory.Executable doesn't work in JS
|
||||
*/
|
||||
export async function loadTemplates(): Promise<{ templates: StyleOption[]; error?: string }> {
|
||||
const templates: StyleOption[] = [];
|
||||
let error: string | undefined;
|
||||
|
||||
try {
|
||||
// Use Rust command to read all templates
|
||||
console.log('Calling read_templates command...');
|
||||
const files = await invoke<TemplateFile[]>('read_templates');
|
||||
console.log(`Received ${files.length} templates from Rust`);
|
||||
|
||||
for (const file of files) {
|
||||
try {
|
||||
const raw = JSON.parse(file.content) as RawTemplate;
|
||||
const validated = validateTemplate(raw, file.name);
|
||||
if (validated) {
|
||||
// Use folder-based category from Rust, fallback to 'Other'
|
||||
const category = file.category || 'Other';
|
||||
templates.push({ ...validated, category });
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`Failed to parse template ${file.name}:`, e);
|
||||
}
|
||||
}
|
||||
|
||||
if (templates.length === 0) {
|
||||
error = 'No templates found.';
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error in loadTemplates:', e);
|
||||
error = e instanceof Error ? e.message : String(e);
|
||||
}
|
||||
|
||||
// Sort by category then name
|
||||
templates.sort((a, b) => {
|
||||
const catCompare = a.category.localeCompare(b.category);
|
||||
if (catCompare !== 0) return catCompare;
|
||||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
|
||||
// Deduplicate by ID (in case of duplicate files)
|
||||
const seen = new Set<string>();
|
||||
const deduplicated = templates.filter(t => {
|
||||
if (seen.has(t.id)) {
|
||||
console.warn(`Duplicate template ID found: ${t.id}, skipping duplicate`);
|
||||
return false;
|
||||
}
|
||||
seen.add(t.id);
|
||||
return true;
|
||||
});
|
||||
|
||||
console.log(`Returning ${deduplicated.length} templates (deduplicated from ${templates.length}), error: ${error}`);
|
||||
return { templates: deduplicated, error };
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the templates folder in the system file explorer
|
||||
*/
|
||||
export async function openTemplatesFolder(): Promise<{ success: boolean; error?: string }> {
|
||||
try {
|
||||
await invoke('open_templates_folder');
|
||||
return { success: true };
|
||||
} catch (e) {
|
||||
const errorMsg = e instanceof Error ? e.message : String(e);
|
||||
return { success: false, error: errorMsg };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a single template by ID
|
||||
*/
|
||||
export async function loadTemplateById(id: string): Promise<StyleOption | null> {
|
||||
const { templates } = await loadTemplates();
|
||||
return templates.find(t => t.id === id) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all available categories from templates
|
||||
*/
|
||||
export function getCategories(templates: StyleOption[]): string[] {
|
||||
const categories = new Set<string>();
|
||||
templates.forEach(t => categories.add(t.category));
|
||||
return Array.from(categories).sort();
|
||||
}
|
||||
433
src/services/templateRenderer.ts
Normal file
433
src/services/templateRenderer.ts
Normal file
@@ -0,0 +1,433 @@
|
||||
import { StyleOption, ElementStyle, FontConfig, ColorPalette } from '../types';
|
||||
|
||||
/**
|
||||
* Resolves a color reference (e.g., 'accent', 'background') or returns the color directly
|
||||
*/
|
||||
export function resolveColor(color: string | undefined, palette: ColorPalette): string {
|
||||
if (!color) return '#000000';
|
||||
// Check if it's a palette reference
|
||||
if (palette[color as keyof ColorPalette]) {
|
||||
return '#' + palette[color as keyof ColorPalette];
|
||||
}
|
||||
// Return as-is with # prefix if not already present
|
||||
return color.startsWith('#') ? color : '#' + color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a font reference (e.g., 'heading', 'body', 'code') to actual font name
|
||||
*/
|
||||
export function resolveFont(font: string | undefined, fonts: FontConfig): string {
|
||||
if (!font) return 'serif';
|
||||
// Check if it's a font reference
|
||||
if (fonts[font as keyof FontConfig]) {
|
||||
return fonts[font as keyof FontConfig]!;
|
||||
}
|
||||
// Return as-is (already an actual font name)
|
||||
return font;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts element style to CSS string
|
||||
*/
|
||||
function elementToCss(
|
||||
selector: string,
|
||||
style: ElementStyle | undefined,
|
||||
fonts: FontConfig,
|
||||
palette: ColorPalette
|
||||
): string {
|
||||
if (!style) return '';
|
||||
|
||||
const css: string[] = [];
|
||||
|
||||
if (style.font) css.push(`font-family: ${resolveFont(style.font, fonts)}`);
|
||||
if (style.size) css.push(`font-size: ${style.size}pt`);
|
||||
if (style.color) css.push(`color: ${resolveColor(style.color, palette)}`);
|
||||
if (style.background) css.push(`background: ${resolveColor(style.background, palette)}`);
|
||||
if (style.bold) css.push('font-weight: 700');
|
||||
if (style.italic) css.push('font-style: italic');
|
||||
if (style.underline) css.push('text-decoration: underline');
|
||||
if (style.allCaps) css.push('text-transform: uppercase');
|
||||
if (style.align) css.push(`text-align: ${style.align === 'both' ? 'justify' : style.align}`);
|
||||
if (style.spacing) {
|
||||
if (style.spacing.before) css.push(`margin-top: ${style.spacing.before}pt`);
|
||||
if (style.spacing.after) css.push(`margin-bottom: ${style.spacing.after}pt`);
|
||||
if (style.spacing.line) css.push(`line-height: ${style.spacing.line}`);
|
||||
}
|
||||
if (style.indent) css.push(`text-indent: ${style.indent}pt`);
|
||||
if (style.padding) css.push(`padding: ${style.padding}pt`);
|
||||
if (style.border) {
|
||||
css.push(`border: ${style.border.width}px ${style.border.style} ${resolveColor(style.border.color, palette)}`);
|
||||
}
|
||||
if (style.borderTop) {
|
||||
css.push(`border-top: ${style.borderTop.width}px ${style.borderTop.style} ${resolveColor(style.borderTop.color, palette)}`);
|
||||
}
|
||||
if (style.borderBottom) {
|
||||
css.push(`border-bottom: ${style.borderBottom.width}px ${style.borderBottom.style} ${resolveColor(style.borderBottom.color, palette)}`);
|
||||
}
|
||||
if (style.borderLeft) {
|
||||
css.push(`border-left: ${style.borderLeft.width}px ${style.borderLeft.style} ${resolveColor(style.borderLeft.color, palette)}`);
|
||||
}
|
||||
if (style.borderRight) {
|
||||
css.push(`border-right: ${style.borderRight.width}px ${style.borderRight.style} ${resolveColor(style.borderRight.color, palette)}`);
|
||||
}
|
||||
|
||||
if (css.length === 0) return '';
|
||||
return `${selector} { ${css.join('; ')} }`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates preview CSS from unified template structure
|
||||
* This is the SINGLE SOURCE OF TRUTH for both preview and export styling
|
||||
* All selectors are scoped to .page to avoid affecting the app background
|
||||
*/
|
||||
export function generatePreviewCss(template: StyleOption): string {
|
||||
const fonts = template.typography?.fonts || { heading: 'serif', body: 'serif', code: 'monospace' };
|
||||
const palette = template.typography?.colors || { text: '000000', background: 'FFFFFF' };
|
||||
const elements = template.elements || {};
|
||||
|
||||
const cssParts: string[] = [];
|
||||
|
||||
// .page base styles - scoped to avoid affecting app background
|
||||
const baseStyles: string[] = [];
|
||||
baseStyles.push(`font-family: ${resolveFont('body', fonts)}`);
|
||||
baseStyles.push(`background: ${resolveColor('background', palette)}`);
|
||||
baseStyles.push(`color: ${resolveColor('text', palette)}`);
|
||||
baseStyles.push(`line-height: 1.5`);
|
||||
cssParts.push(`.page { ${baseStyles.join('; ')}; min-height: 100%; }`);
|
||||
cssParts.push(`.page blockquote, .page table, .page img { break-inside: avoid; }`);
|
||||
|
||||
// Headings - scoped to .page
|
||||
cssParts.push(elementToCss('.page h1', elements.h1, fonts, palette));
|
||||
cssParts.push(elementToCss('.page h2', elements.h2, fonts, palette));
|
||||
cssParts.push(elementToCss('.page h3', elements.h3, fonts, palette));
|
||||
cssParts.push(elementToCss('.page h4', elements.h4, fonts, palette));
|
||||
cssParts.push(elementToCss('.page h5', elements.h5, fonts, palette));
|
||||
cssParts.push(elementToCss('.page h6', elements.h6, fonts, palette));
|
||||
|
||||
// Paragraph - scoped to .page
|
||||
cssParts.push(elementToCss('.page p', elements.p, fonts, palette));
|
||||
|
||||
// Blockquote - scoped to .page
|
||||
cssParts.push(elementToCss('.page blockquote', elements.blockquote, fonts, palette));
|
||||
|
||||
// Code - scoped to .page
|
||||
cssParts.push(elementToCss('.page code', elements.code, fonts, palette));
|
||||
cssParts.push(elementToCss('.page pre', elements.pre, fonts, palette));
|
||||
cssParts.push('.page pre code { background: transparent !important; padding: 0 !important }');
|
||||
|
||||
// Lists - scoped to .page
|
||||
cssParts.push(elementToCss('.page ul', elements.ul, fonts, palette));
|
||||
cssParts.push(elementToCss('.page ol', elements.ol, fonts, palette));
|
||||
cssParts.push(elementToCss('.page li', elements.li, fonts, palette));
|
||||
|
||||
// Inline styles - scoped to .page
|
||||
cssParts.push(elementToCss('.page strong', elements.strong, fonts, palette));
|
||||
cssParts.push(elementToCss('.page em', elements.em, fonts, palette));
|
||||
cssParts.push(elementToCss('.page a', elements.a, fonts, palette));
|
||||
|
||||
// Tables - scoped to .page
|
||||
cssParts.push('.page table { border-collapse: collapse; border-spacing: 0; width: 100%; }');
|
||||
cssParts.push(elementToCss('.page table', elements.table, fonts, palette));
|
||||
cssParts.push(elementToCss('.page th', elements.th, fonts, palette));
|
||||
cssParts.push(elementToCss('.page td', elements.td, fonts, palette));
|
||||
|
||||
// Horizontal rule - scoped to .page
|
||||
if (elements.hr?.border) {
|
||||
const borderColor = resolveColor(elements.hr.border.color, palette);
|
||||
cssParts.push(`.page hr { border: none; border-top: ${elements.hr.border.width}px ${elements.hr.border.style} ${borderColor}; margin: ${elements.hr.spacing?.before || 12}pt 0 }`);
|
||||
}
|
||||
|
||||
// Images - scoped to .page
|
||||
if (elements.img?.align) {
|
||||
cssParts.push(`.page img { display: block; text-align: ${elements.img.align}; margin: ${elements.img.spacing?.before || 12}pt auto }`);
|
||||
}
|
||||
|
||||
// Remove empty rules and join
|
||||
return cssParts.filter(part => part.trim()).join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates CSS from legacy wordConfig structure
|
||||
* Used when unified elements/typography structure isn't available
|
||||
* All selectors are scoped to .page to avoid affecting the app background
|
||||
*/
|
||||
function generateCssFromWordConfig(template: StyleOption): string {
|
||||
const cfg = template.wordConfig;
|
||||
if (!cfg) return '.page { font-family: serif; }';
|
||||
|
||||
const cssParts: string[] = [];
|
||||
|
||||
// .page base styles - scoped to avoid affecting app background
|
||||
const pageStyles: string[] = [];
|
||||
if (cfg.body?.font) pageStyles.push(`font-family: ${cfg.body.font}`);
|
||||
if (cfg.body?.size) pageStyles.push(`font-size: ${cfg.body.size}pt`);
|
||||
if (cfg.body?.color) pageStyles.push(`color: #${cfg.body.color}`);
|
||||
if (cfg.body?.align) pageStyles.push(`text-align: ${cfg.body.align === 'both' ? 'justify' : cfg.body.align}`);
|
||||
if (cfg.body?.spacing?.line) {
|
||||
pageStyles.push(`line-height: ${cfg.body.spacing.line / 240}`);
|
||||
}
|
||||
// White background for the document page
|
||||
pageStyles.push('background: #ffffff');
|
||||
cssParts.push(`.page { ${pageStyles.join('; ')} }`);
|
||||
|
||||
// Headings - scoped to .page
|
||||
if (cfg.heading1) {
|
||||
const h1Styles: string[] = [];
|
||||
if (cfg.heading1.font) h1Styles.push(`font-family: ${cfg.heading1.font}`);
|
||||
if (cfg.heading1.size) h1Styles.push(`font-size: ${cfg.heading1.size}pt`);
|
||||
if (cfg.heading1.color) h1Styles.push(`color: #${cfg.heading1.color}`);
|
||||
if (cfg.heading1.bold) h1Styles.push('font-weight: 700');
|
||||
if (cfg.heading1.italic) h1Styles.push('font-style: italic');
|
||||
if (cfg.heading1.allCaps) h1Styles.push('text-transform: uppercase');
|
||||
if (cfg.heading1.align) h1Styles.push(`text-align: ${cfg.heading1.align}`);
|
||||
if (cfg.heading1.spacing?.before) {
|
||||
h1Styles.push(`margin-top: ${cfg.heading1.spacing.before / 20}pt`);
|
||||
}
|
||||
if (cfg.heading1.spacing?.after) {
|
||||
h1Styles.push(`margin-bottom: ${cfg.heading1.spacing.after / 20}pt`);
|
||||
}
|
||||
cssParts.push(`.page h1 { ${h1Styles.join('; ')} }`);
|
||||
}
|
||||
|
||||
if (cfg.heading2) {
|
||||
const h2Styles: string[] = [];
|
||||
if (cfg.heading2.font) h2Styles.push(`font-family: ${cfg.heading2.font}`);
|
||||
if (cfg.heading2.size) h2Styles.push(`font-size: ${cfg.heading2.size}pt`);
|
||||
if (cfg.heading2.color) h2Styles.push(`color: #${cfg.heading2.color}`);
|
||||
if (cfg.heading2.bold) h2Styles.push('font-weight: 700');
|
||||
if (cfg.heading2.italic) h2Styles.push('font-style: italic');
|
||||
if (cfg.heading2.allCaps) h2Styles.push('text-transform: uppercase');
|
||||
if (cfg.heading2.align) h2Styles.push(`text-align: ${cfg.heading2.align}`);
|
||||
if (cfg.heading2.spacing?.before) {
|
||||
h2Styles.push(`margin-top: ${cfg.heading2.spacing.before / 20}pt`);
|
||||
}
|
||||
if (cfg.heading2.spacing?.after) {
|
||||
h2Styles.push(`margin-bottom: ${cfg.heading2.spacing.after / 20}pt`);
|
||||
}
|
||||
cssParts.push(`.page h2 { ${h2Styles.join('; ')} }`);
|
||||
}
|
||||
|
||||
// Paragraph - scoped to .page
|
||||
if (cfg.body) {
|
||||
const pStyles: string[] = [];
|
||||
if (cfg.body.font) pStyles.push(`font-family: ${cfg.body.font}`);
|
||||
if (cfg.body.size) pStyles.push(`font-size: ${cfg.body.size}pt`);
|
||||
if (cfg.body.color) pStyles.push(`color: #${cfg.body.color}`);
|
||||
if (cfg.body.align) pStyles.push(`text-align: ${cfg.body.align === 'both' ? 'justify' : cfg.body.align}`);
|
||||
if (cfg.body.spacing?.line) {
|
||||
pStyles.push(`line-height: ${cfg.body.spacing.line / 240}`);
|
||||
}
|
||||
if (cfg.body.spacing?.after) {
|
||||
pStyles.push(`margin-bottom: ${cfg.body.spacing.after / 20}pt`);
|
||||
}
|
||||
cssParts.push(`.page p { ${pStyles.join('; ')} }`);
|
||||
}
|
||||
|
||||
// All other elements scoped to .page
|
||||
cssParts.push('.page blockquote { border-left: 3px solid #' + (cfg.accentColor || 'cccccc') + '; padding-left: 16px; margin: 16px 0; font-style: italic; }');
|
||||
cssParts.push('.page ul, .page ol { margin: 16px 0; padding-left: 32px; }');
|
||||
cssParts.push('.page li { margin-bottom: 8px; }');
|
||||
cssParts.push('.page strong { font-weight: 700; }');
|
||||
cssParts.push('.page em { font-style: italic; }');
|
||||
cssParts.push('.page code { font-family: monospace; background: #f5f5f5; padding: 2px 4px; border-radius: 3px; }');
|
||||
cssParts.push('.page pre { background: #f5f5f5; padding: 16px; border-radius: 4px; overflow-x: auto; }');
|
||||
cssParts.push('.page table { border-collapse: collapse; width: 100%; margin: 16px 0; }');
|
||||
cssParts.push('.page th, .page td { border: 1px solid #ddd; padding: 8px 12px; text-align: left; }');
|
||||
cssParts.push('.page th { background: #f5f5f5; font-weight: 700; }');
|
||||
cssParts.push('.page hr { border: none; border-top: 1px solid #' + (cfg.accentColor || 'cccccc') + '; margin: 24px 0; }');
|
||||
|
||||
return cssParts.join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets complete CSS for preview
|
||||
* Always generates fresh CSS from unified template structure
|
||||
*/
|
||||
export function getPreviewCss(template: StyleOption): string {
|
||||
// Always generate CSS from unified structure if available
|
||||
if (template.elements && template.typography) {
|
||||
return generatePreviewCss(template);
|
||||
}
|
||||
// Generate CSS from legacy wordConfig structure
|
||||
if (template.wordConfig) {
|
||||
return generateCssFromWordConfig(template);
|
||||
}
|
||||
// Final fallback
|
||||
return 'body { font-family: serif; color: #000000; background: #ffffff; }';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates Word-compatible wordConfig from unified template structure
|
||||
*/
|
||||
// Export this function to be used by templateLoader
|
||||
export function generateWordConfig(
|
||||
elements: Record<string, ElementStyle>,
|
||||
fonts: FontConfig,
|
||||
palette: ColorPalette
|
||||
) {
|
||||
const h1 = elements.h1;
|
||||
const h2 = elements.h2;
|
||||
const body = elements.p;
|
||||
|
||||
const toTwips = (pts?: number) => pts;
|
||||
const toLineTwips = (line?: number) => line;
|
||||
|
||||
// Helper to ensure borders are preserved in the config
|
||||
const mapBorder = (el?: ElementStyle, side?: 'top' | 'bottom' | 'left' | 'right') => {
|
||||
// If specific side border exists
|
||||
let sideBorder;
|
||||
if (side === 'left') sideBorder = el?.borderLeft;
|
||||
else if (side === 'top') sideBorder = el?.borderTop;
|
||||
else if (side === 'bottom') sideBorder = el?.borderBottom;
|
||||
else if (side === 'right') sideBorder = el?.borderRight;
|
||||
|
||||
if (sideBorder) {
|
||||
return {
|
||||
color: resolveColor(sideBorder.color, palette).replace('#', ''),
|
||||
space: 24, // Standard space
|
||||
style: sideBorder.style || 'single',
|
||||
size: (sideBorder.width || 1) * 8
|
||||
};
|
||||
}
|
||||
|
||||
// If global border exists
|
||||
if (el?.border) {
|
||||
return {
|
||||
color: resolveColor(el.border.color, palette).replace('#', ''),
|
||||
space: 24, // Standard space
|
||||
style: el.border.style || 'single',
|
||||
size: (el.border.width || 1) * 8
|
||||
};
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
return {
|
||||
heading1: h1 ? {
|
||||
font: resolveFont(h1.font, fonts),
|
||||
size: h1.size || 24,
|
||||
color: h1.color ? resolveColor(h1.color, palette).replace('#', '') : '000000',
|
||||
bold: h1.bold,
|
||||
italic: h1.italic,
|
||||
allCaps: h1.allCaps,
|
||||
align: h1.align,
|
||||
spacing: h1.spacing ? {
|
||||
before: toTwips(h1.spacing.before) || 0,
|
||||
after: toTwips(h1.spacing.after) || 0,
|
||||
line: toLineTwips(h1.spacing.line) || 240
|
||||
} : undefined,
|
||||
// Map borders specifically for H1 if they exist
|
||||
border: {
|
||||
left: mapBorder(h1, 'left'),
|
||||
bottom: mapBorder(h1, 'bottom'),
|
||||
top: mapBorder(h1, 'top'),
|
||||
right: mapBorder(h1, 'right')
|
||||
},
|
||||
shading: h1.background ? {
|
||||
fill: resolveColor(h1.background, palette).replace('#', ''),
|
||||
type: 'clear', // Always use clear for shading to avoid black blocks
|
||||
color: 'auto'
|
||||
} : undefined
|
||||
} : undefined,
|
||||
heading2: h2 ? {
|
||||
font: resolveFont(h2.font, fonts),
|
||||
size: h2.size || 18,
|
||||
color: h2.color ? resolveColor(h2.color, palette).replace('#', '') : '333333',
|
||||
bold: h2.bold,
|
||||
italic: h2.italic,
|
||||
allCaps: h2.allCaps,
|
||||
align: h2.align,
|
||||
spacing: h2.spacing ? {
|
||||
before: toTwips(h2.spacing.before) || 0,
|
||||
after: toTwips(h2.spacing.after) || 0,
|
||||
line: toLineTwips(h2.spacing.line) || 240
|
||||
} : undefined,
|
||||
shading: h2.background ? {
|
||||
fill: resolveColor(h2.background, palette).replace('#', ''),
|
||||
type: 'clear',
|
||||
color: 'auto'
|
||||
} : undefined
|
||||
} : undefined,
|
||||
body: body ? {
|
||||
font: resolveFont(body.font, fonts),
|
||||
size: body.size || 11,
|
||||
color: body.color ? resolveColor(body.color, palette).replace('#', '') : '000000',
|
||||
align: body.align,
|
||||
spacing: body.spacing ? {
|
||||
before: toTwips(body.spacing.before) || 0,
|
||||
after: toTwips(body.spacing.after) || 0,
|
||||
line: toLineTwips(body.spacing.line) || 1.2
|
||||
} : undefined
|
||||
} : undefined,
|
||||
accentColor: palette.accent || '000000',
|
||||
heading3: elements.h3 ? {
|
||||
font: resolveFont(elements.h3.font, fonts),
|
||||
size: elements.h3.size || 14,
|
||||
color: elements.h3.color ? resolveColor(elements.h3.color, palette).replace('#', '') : '111111',
|
||||
bold: elements.h3.bold,
|
||||
italic: elements.h3.italic,
|
||||
allCaps: elements.h3.allCaps,
|
||||
align: elements.h3.align,
|
||||
spacing: elements.h3.spacing ? {
|
||||
before: toTwips(elements.h3.spacing.before) || 0,
|
||||
after: toTwips(elements.h3.spacing.after) || 0,
|
||||
line: toLineTwips(elements.h3.spacing.line) || 240
|
||||
} : undefined
|
||||
} : undefined,
|
||||
heading4: elements.h4 ? {
|
||||
font: resolveFont(elements.h4.font, fonts),
|
||||
size: elements.h4.size || 12,
|
||||
color: elements.h4.color ? resolveColor(elements.h4.color, palette).replace('#', '') : '111111',
|
||||
bold: elements.h4.bold,
|
||||
italic: elements.h4.italic,
|
||||
align: elements.h4.align,
|
||||
spacing: elements.h4.spacing ? {
|
||||
before: toTwips(elements.h4.spacing.before) || 0,
|
||||
after: toTwips(elements.h4.spacing.after) || 0,
|
||||
line: toLineTwips(elements.h4.spacing.line) || 240
|
||||
} : undefined
|
||||
} : undefined,
|
||||
heading5: elements.h5 ? {
|
||||
font: resolveFont(elements.h5.font, fonts),
|
||||
size: elements.h5.size || 11,
|
||||
color: elements.h5.color ? resolveColor(elements.h5.color, palette).replace('#', '') : '111111',
|
||||
bold: elements.h5.bold,
|
||||
italic: elements.h5.italic,
|
||||
align: elements.h5.align,
|
||||
spacing: elements.h5.spacing ? {
|
||||
before: toTwips(elements.h5.spacing.before) || 0,
|
||||
after: toTwips(elements.h5.spacing.after) || 0,
|
||||
line: toLineTwips(elements.h5.spacing.line) || 240
|
||||
} : undefined
|
||||
} : undefined,
|
||||
heading6: elements.h6 ? {
|
||||
font: resolveFont(elements.h6.font, fonts),
|
||||
size: elements.h6.size || 10,
|
||||
color: elements.h6.color ? resolveColor(elements.h6.color, palette).replace('#', '') : '111111',
|
||||
bold: elements.h6.bold,
|
||||
italic: elements.h6.italic,
|
||||
align: elements.h6.align,
|
||||
spacing: elements.h6.spacing ? {
|
||||
before: toTwips(elements.h6.spacing.before) || 0,
|
||||
after: toTwips(elements.h6.spacing.after) || 0,
|
||||
line: toLineTwips(elements.h6.spacing.line) || 240
|
||||
} : undefined
|
||||
} : undefined
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets complete wordConfig, preferring generated config over legacy
|
||||
*/
|
||||
export function getWordConfig(template: StyleOption) {
|
||||
// If template has unified structure, generate config from it
|
||||
if (template.elements && template.typography) {
|
||||
const fonts = template.typography.fonts || {};
|
||||
const palette = template.typography.colors || {};
|
||||
const elements = template.elements;
|
||||
return generateWordConfig(elements, fonts, palette);
|
||||
}
|
||||
// Fall back to legacy wordConfig
|
||||
return template.wordConfig;
|
||||
}
|
||||
@@ -1,407 +0,0 @@
|
||||
import { StyleOption } from '../types';
|
||||
|
||||
export const academicStyles: StyleOption[] = [
|
||||
{
|
||||
id: 'academic-journal',
|
||||
name: 'Academic Journal',
|
||||
category: 'Academic',
|
||||
description: 'Scholarly and rigorous design for academic papers and research publications. Traditional serif typography optimized for extended reading.',
|
||||
vibe: 'Scholarly, Serious, Traditional',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Libre+Baskerville:wght@400;700&family=Source+Sans+3:wght@400;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Libre Baskerville", size: 18, color: "000000", bold: true, align: 'center',
|
||||
spacing: { before: 360, after: 240, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Libre Baskerville", size: 13, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 280, after: 140, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Libre Baskerville", size: 10, color: "1A1A1A", align: 'both',
|
||||
spacing: { before: 0, after: 140, line: 300 }
|
||||
},
|
||||
accentColor: "800000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Libre Baskerville', serif;
|
||||
h1 { font-size: 18pt; font-weight: 700; color: #000000; text-align: center; margin-bottom: 28px; }
|
||||
h2 { font-size: 13pt; font-weight: 700; color: #000000; margin-top: 28px; margin-bottom: 14px; }
|
||||
p { font-size: 10pt; line-height: 1.7; color: #1A1A1A; margin-bottom: 12px; text-align: justify; }
|
||||
blockquote { padding-left: 40px; margin: 20px 0; font-size: 9pt; color: #333333; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'medical-professional',
|
||||
name: 'Medical Professional',
|
||||
category: 'Healthcare',
|
||||
description: 'Clean, clinical design for healthcare and medical documentation. Emphasizes clarity and professionalism with calming blue accents.',
|
||||
vibe: 'Clinical, Professional, Trustworthy',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Open Sans", size: 20, color: "1565C0", bold: true, align: 'left',
|
||||
spacing: { before: 360, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Open Sans", size: 13, color: "0D47A1", bold: true, align: 'left',
|
||||
spacing: { before: 280, after: 140, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Open Sans", size: 10, color: "37474F", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "1565C0"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
h1 { font-size: 20pt; font-weight: 700; color: #1565C0; margin-bottom: 20px; }
|
||||
h2 { font-size: 13pt; font-weight: 700; color: #0D47A1; margin-top: 28px; margin-bottom: 14px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #37474F; margin-bottom: 14px; }
|
||||
blockquote { background: #E3F2FD; padding: 16px; border-left: 4px solid #1565C0; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'education-friendly',
|
||||
name: 'Education Friendly',
|
||||
category: 'Education',
|
||||
description: 'Approachable and clear design for educational materials. High readability with friendly colors suitable for learning environments.',
|
||||
vibe: 'Friendly, Educational, Accessible',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Nunito", size: 24, color: "5E35B1", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "EDE7F6", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Nunito", size: 14, color: "7E57C2", bold: true, align: 'left',
|
||||
spacing: { before: 300, after: 150, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Nunito", size: 11, color: "424242", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 300 }
|
||||
},
|
||||
accentColor: "5E35B1"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Nunito', sans-serif;
|
||||
h1 { font-size: 24pt; font-weight: 700; color: #5E35B1; background: #EDE7F6; padding: 16px 20px; border-radius: 8px; margin-bottom: 24px; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #7E57C2; margin-top: 30px; margin-bottom: 14px; }
|
||||
p { font-size: 11pt; line-height: 1.7; color: #424242; margin-bottom: 14px; }
|
||||
blockquote { background: #F3E5F5; padding: 16px; border-radius: 8px; border-left: 4px solid #7E57C2; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'scientific-journal',
|
||||
name: 'Scientific Journal',
|
||||
category: 'Academic',
|
||||
description: 'Precise design for scientific publications. Clear hierarchy optimized for data-heavy content and citations.',
|
||||
vibe: 'Scientific, Precise, Academic',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Literata:wght@400;500;700&family=Fira+Sans:wght@400;500;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Literata", size: 18, color: "1A1A1A", bold: true, align: 'left',
|
||||
spacing: { before: 360, after: 200, line: 260 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Fira Sans", size: 12, color: "1A1A1A", bold: true, align: 'left',
|
||||
spacing: { before: 280, after: 120, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Literata", size: 10, color: "262626", align: 'both',
|
||||
spacing: { before: 0, after: 140, line: 280 }
|
||||
},
|
||||
accentColor: "0066CC"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Literata', serif;
|
||||
h1 { font-size: 18pt; font-weight: 700; color: #1A1A1A; margin-bottom: 24px; }
|
||||
h2 { font-family: 'Fira Sans', sans-serif; font-size: 12pt; font-weight: 600; color: #1A1A1A; margin-top: 28px; margin-bottom: 12px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #262626; margin-bottom: 12px; text-align: justify; }
|
||||
blockquote { padding-left: 24px; border-left: 2px solid #0066CC; margin: 16px 0; font-size: 9pt; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'kids-education',
|
||||
name: 'Kids Education',
|
||||
category: 'Education',
|
||||
description: 'Fun and engaging design for children\'s educational content. Rounded typography with bright, cheerful colors.',
|
||||
vibe: 'Educational, Fun, Engaging',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Fredoka:wght@400;500;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Fredoka", size: 32, color: "FF6B6B", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 240, line: 240 },
|
||||
shading: { fill: "FFF9DB", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Fredoka", size: 18, color: "4ECDC4", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Fredoka", size: 12, color: "495057", align: 'left',
|
||||
spacing: { before: 0, after: 180, line: 320 }
|
||||
},
|
||||
accentColor: "FF6B6B"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Fredoka', sans-serif;
|
||||
h1 { font-size: 32pt; font-weight: 600; color: #FF6B6B; text-align: center; background: #FFF9DB; padding: 16px 20px; border-radius: 12px; margin-bottom: 28px; }
|
||||
h2 { font-size: 18pt; font-weight: 500; color: #4ECDC4; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 12pt; line-height: 1.8; color: #495057; margin-bottom: 16px; }
|
||||
blockquote { background: #E3F9F8; padding: 16px; border-radius: 12px; border-left: 6px solid #4ECDC4; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'dark-academia',
|
||||
name: 'Dark Academia',
|
||||
category: 'Academic',
|
||||
description: 'Moody, literary aesthetic. Tweed textures, old libraries, and classic serif typography.',
|
||||
vibe: 'Moody, Scholarly, Literary',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Alegreya:wght@400;700&family=Alegreya+SC:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Alegreya SC", size: 28, color: "3E2723", bold: true, align: 'center',
|
||||
spacing: { before: 480, after: 280, line: 240 },
|
||||
border: { bottom: { color: "5D4037", space: 6, style: "double", size: 12 } }
|
||||
},
|
||||
heading2: {
|
||||
font: "Alegreya", size: 16, color: "4E342E", bold: true, align: 'left',
|
||||
spacing: { before: 360, after: 180, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Alegreya", size: 11, color: "212121", align: 'both',
|
||||
spacing: { before: 0, after: 180, line: 320 }
|
||||
},
|
||||
accentColor: "5D4037"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Alegreya', serif;
|
||||
background: #F5F1E8;
|
||||
h1 { font-family: 'Alegreya SC', serif; font-size: 28pt; font-weight: 700; color: #3E2723; text-align: center; border-bottom: 4px double #5D4037; padding-bottom: 16px; margin-bottom: 32px; }
|
||||
h2 { font-size: 16pt; font-weight: 700; color: #4E342E; margin-top: 36px; margin-bottom: 18px; font-style: italic; }
|
||||
p { font-size: 11pt; line-height: 1.8; color: #212121; margin-bottom: 16px; text-align: justify; }
|
||||
blockquote { border-left: 2px solid #3E2723; padding-left: 20px; margin: 28px 0; font-style: italic; color: #4E342E; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'botanical-textbook',
|
||||
name: 'Botanical Textbook',
|
||||
category: 'Scientific',
|
||||
description: 'Vintage science textbook aesthetic. Academic yet organic, like a 19th-century flora guide.',
|
||||
vibe: 'Vintage, Scientific, Organic',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Alice&family=Gentium+Book+Basic:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Alice", size: 28, color: "33691E", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: { bottom: { color: "827717", space: 6, style: "single", size: 8 } }
|
||||
},
|
||||
heading2: {
|
||||
font: "Gentium Book Basic", size: 14, color: "558B2F", bold: true, align: 'left',
|
||||
spacing: { before: 300, after: 150, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Gentium Book Basic", size: 11, color: "1B1B1B", align: 'both',
|
||||
spacing: { before: 0, after: 160, line: 300 }
|
||||
},
|
||||
accentColor: "827717"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Gentium Book Basic', serif;
|
||||
h1 { font-family: 'Alice', serif; font-size: 28pt; color: #33691E; border-bottom: 2px solid #827717; padding-bottom: 10px; margin-bottom: 24px; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #558B2F; margin-top: 30px; margin-bottom: 14px; font-style: italic; }
|
||||
p { font-size: 11pt; line-height: 1.7; color: #1B1B1B; margin-bottom: 14px; text-align: justify; }
|
||||
blockquote { background: #F9FBE7; padding: 16px; border-left: 4px solid #827717; margin: 20px 0; font-size: 10pt; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'chemistry-lab',
|
||||
name: 'Chemistry Lab',
|
||||
category: 'Scientific',
|
||||
description: 'Clean, molecular design. Modern thin typography suitable for diagrams and formulas.',
|
||||
vibe: 'Scientific, Modern, Molecular',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Advent+Pro:wght@400;600;700&family=Heebo:wght@300;400;500&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Advent Pro", size: 32, color: "00BCD4", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Heebo", size: 16, color: "0097A7", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Heebo", size: 10, color: "37474F", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "00BCD4"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Heebo', sans-serif;
|
||||
h1 { font-family: 'Advent Pro', sans-serif; font-size: 32pt; font-weight: 700; color: #00BCD4; margin-bottom: 24px; }
|
||||
h2 { font-size: 16pt; font-weight: 700; color: #0097A7; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #37474F; margin-bottom: 14px; font-weight: 300; }
|
||||
blockquote { border: 1px solid #00BCD4; padding: 16px; margin: 20px 0; border-radius: 8px; background: #E0F7FA; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'mathematics-paper',
|
||||
name: 'Mathematics Paper',
|
||||
category: 'Academic',
|
||||
description: 'Inspired by LaTeX and Computer Modern. Serif-heavy, precise, and highly legible for academic rigor.',
|
||||
vibe: 'Academic, Rigorous, Formal',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Domine:wght@400;700&family=Noticia+Text:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Domine", size: 24, color: "000000", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 240, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Domine", size: 14, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Noticia Text", size: 11, color: "212121", align: 'both',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Noticia Text', serif;
|
||||
h1 { font-family: 'Domine', serif; font-size: 24pt; font-weight: 700; color: #000000; text-align: center; margin-bottom: 24px; }
|
||||
h2 { font-family: 'Domine', serif; font-size: 14pt; font-weight: 700; color: #000000; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #212121; margin-bottom: 14px; text-align: justify; }
|
||||
blockquote { border-left: 3px solid #000; padding-left: 20px; margin: 24px 0; font-style: italic; background: #F5F5F5; padding: 10px 20px; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'phd-thesis',
|
||||
name: 'PhD Thesis',
|
||||
category: 'Academic',
|
||||
description: 'The pinnacle of academic formatting. Extremely legible serif body, double spacing, and rigorous margin structure.',
|
||||
vibe: 'Formal, Scholarly, Prestigious',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Tinos:wght@400;700&family=Crimson+Text:wght@400;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Tinos", size: 24, color: "000000", bold: true, align: 'center',
|
||||
spacing: { before: 480, after: 240, line: 240 },
|
||||
allCaps: true
|
||||
},
|
||||
heading2: {
|
||||
font: "Tinos", size: 14, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 240, after: 120, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Crimson Text", size: 12, color: "000000", align: 'both',
|
||||
spacing: { before: 0, after: 0, line: 480 } // Double spaced
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Crimson Text', serif;
|
||||
line-height: 2.0;
|
||||
h1 { font-family: 'Tinos', serif; font-size: 24pt; font-weight: 700; text-align: center; text-transform: uppercase; margin-bottom: 24px; }
|
||||
h2 { font-family: 'Tinos', serif; font-size: 14pt; font-weight: 700; margin-top: 24px; margin-bottom: 12px; }
|
||||
p { font-size: 12pt; text-align: justify; margin-bottom: 0; }
|
||||
blockquote { margin-left: 40px; font-style: italic; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'history-textbook',
|
||||
name: 'History Textbook',
|
||||
category: 'Academic',
|
||||
description: 'Classic textbook design. Sepia tones, distinct serif headers, and wide margins for notes.',
|
||||
vibe: 'Classic, Educational, Historical',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Goudy+Bookletter+1911&family=Sorts+Mill+Goudy&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Goudy Bookletter 1911", size: 28, color: "5D4037", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: { bottom: { color: "8D6E63", space: 4, style: "single", size: 8 } }
|
||||
},
|
||||
heading2: {
|
||||
font: "Sorts Mill Goudy", size: 16, color: "3E2723", bold: false, align: 'left',
|
||||
spacing: { before: 300, after: 150, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Sorts Mill Goudy", size: 11, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 300 }
|
||||
},
|
||||
accentColor: "8D6E63"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Sorts Mill Goudy', serif;
|
||||
background: #FFF8E1;
|
||||
h1 { font-family: 'Goudy Bookletter 1911', serif; font-size: 28pt; color: #5D4037; border-bottom: 2px solid #8D6E63; padding-bottom: 10px; margin-bottom: 24px; }
|
||||
h2 { font-size: 16pt; color: #3E2723; margin-top: 30px; margin-bottom: 14px; }
|
||||
p { font-size: 11pt; line-height: 1.7; color: #212121; margin-bottom: 14px; }
|
||||
blockquote { background: #FFF; padding: 16px; border: 1px solid #8D6E63; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'scantron-test',
|
||||
name: 'Scantron Test',
|
||||
category: 'Academic',
|
||||
description: 'Standardized testing sheet. Salmon pinks and greens with bubble-filling aesthetics.',
|
||||
vibe: 'Academic, Retro, Bureaucratic',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Roboto Mono", size: 28, color: "B71C1C", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: { bottom: { color: "EF5350", space: 4, style: "single", size: 12 } }
|
||||
},
|
||||
heading2: {
|
||||
font: "Roboto Mono", size: 14, color: "1B5E20", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
shading: { fill: "E8F5E9", color: "auto", style: "clear" }
|
||||
},
|
||||
body: {
|
||||
font: "Roboto Mono", size: 10, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "EF5350"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Roboto Mono', monospace;
|
||||
background: #FFF3E0; /* Light salmonish tint */
|
||||
h1 { font-size: 28pt; font-weight: 700; color: #B71C1C; border-bottom: 2px solid #EF5350; padding-bottom: 8px; margin-bottom: 24px; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #1B5E20; background: #C8E6C9; display: inline-block; padding: 4px 12px; margin-top: 32px; margin-bottom: 16px; border-radius: 12px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #212121; margin-bottom: 14px; }
|
||||
blockquote { border: 1px solid #B71C1C; padding: 16px; margin: 24px 0; border-radius: 8px; background: #FFEBEE; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'emergency-room',
|
||||
name: 'Emergency Room',
|
||||
category: 'Medical',
|
||||
description: 'Hospital signage. Sterile white, urgent red, and clean blue.',
|
||||
vibe: 'Sterile, Urgent, Clean',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Assistant:wght@400;700&family=Heebo:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Assistant", size: 36, color: "D50000", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: { bottom: { color: "D50000", space: 4, style: "single", size: 12 } }
|
||||
},
|
||||
heading2: {
|
||||
font: "Heebo", size: 18, color: "2962FF", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Heebo", size: 11, color: "424242", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "D50000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Heebo', sans-serif;
|
||||
h1 { font-family: 'Assistant', sans-serif; font-size: 36pt; font-weight: 700; color: #D50000; border-bottom: 4px solid #D50000; padding-bottom: 8px; margin-bottom: 24px; }
|
||||
h2 { font-size: 18pt; font-weight: 700; color: #2962FF; margin-top: 32px; margin-bottom: 16px; text-transform: uppercase; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #424242; margin-bottom: 14px; }
|
||||
blockquote { background: #FFEBEE; border-left: 6px solid #D50000; padding: 16px; margin: 24px 0; }
|
||||
`
|
||||
}
|
||||
];
|
||||
@@ -1 +0,0 @@
|
||||
// Styles have been moved to categorized files.
|
||||
@@ -1,430 +0,0 @@
|
||||
import { StyleOption } from '../types';
|
||||
|
||||
export const corporateStyles: StyleOption[] = [
|
||||
{
|
||||
id: 'tech-memo',
|
||||
name: 'Tech Memorandum',
|
||||
category: 'Corporate',
|
||||
description: 'Modern, functional, and authoritative. Uses shading for headers to create distinct sections.',
|
||||
vibe: 'Corporate, Tech, Strategy',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Roboto", size: 24, color: "0F172A", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "F1F5F9", color: "auto", style: "clear" },
|
||||
border: { left: { color: "2563EB", space: 10, style: "single", size: 48 } }
|
||||
},
|
||||
heading2: {
|
||||
font: "Roboto", size: 14, color: "2563EB", bold: true, align: 'left',
|
||||
spacing: { before: 300, after: 150, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Roboto", size: 10, color: "334155", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "2563EB"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Roboto', sans-serif;
|
||||
h1 { font-size: 24pt; font-weight: 700; background: #F1F5F9; color: #0F172A; padding: 12px 16px; border-left: 8px solid #2563EB; margin-bottom: 20px; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #2563EB; margin-top: 30px; margin-bottom: 12px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #334155; margin-bottom: 14px; }
|
||||
blockquote { background: #EFF6FF; padding: 16px; border-radius: 4px; color: #1E40AF; border-left: 4px solid #2563EB; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'annual-report',
|
||||
name: 'Annual Report',
|
||||
category: 'Corporate',
|
||||
description: 'Trustworthy and substantial. Deep navy blues, clean sans-serifs, and grid-like precision.',
|
||||
vibe: 'Financial, Serious, Trust',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Libre+Franklin:wght@400;700;900&family=Merriweather:wght@300;400&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Libre Franklin", size: 32, color: "0D2B46", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Libre Franklin", size: 16, color: "A0A0A0", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
allCaps: true
|
||||
},
|
||||
body: {
|
||||
font: "Merriweather", size: 10, color: "333333", align: 'both',
|
||||
spacing: { before: 0, after: 160, line: 300 }
|
||||
},
|
||||
accentColor: "0D2B46"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Merriweather', serif;
|
||||
h1 { font-family: 'Libre Franklin', sans-serif; font-size: 32pt; font-weight: 900; color: #0D2B46; margin-bottom: 24px; }
|
||||
h2 { font-family: 'Libre Franklin', sans-serif; font-size: 16pt; font-weight: 700; color: #A0A0A0; text-transform: uppercase; margin-top: 32px; margin-bottom: 16px; border-bottom: 1px solid #CCC; padding-bottom: 4px; }
|
||||
p { font-size: 10pt; line-height: 1.8; color: #333333; margin-bottom: 14px; text-align: justify; }
|
||||
blockquote { border-left: 4px solid #0D2B46; padding-left: 16px; margin: 24px 0; color: #0D2B46; font-style: italic; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'legal-contract',
|
||||
name: 'Legal Contract',
|
||||
category: 'Corporate',
|
||||
description: 'Binding agreement style. Serif fonts, justified text, and numbered section aesthetics.',
|
||||
vibe: 'Legal, Binding, Formal',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Tinos:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Tinos", size: 14, color: "000000", bold: true, align: 'center',
|
||||
spacing: { before: 240, after: 240, line: 240 },
|
||||
allCaps: true
|
||||
},
|
||||
heading2: {
|
||||
font: "Tinos", size: 12, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 240, after: 120, line: 240 },
|
||||
underline: true
|
||||
},
|
||||
body: {
|
||||
font: "Tinos", size: 11, color: "000000", align: 'both',
|
||||
spacing: { before: 0, after: 120, line: 240 }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Tinos', serif;
|
||||
h1 { font-size: 14pt; font-weight: 700; color: #000000; text-align: center; text-transform: uppercase; margin-bottom: 16px; }
|
||||
h2 { font-size: 12pt; font-weight: 700; color: #000000; text-decoration: underline; margin-top: 24px; margin-bottom: 12px; }
|
||||
p { font-size: 11pt; line-height: 1.4; color: #000000; margin-bottom: 12px; text-align: justify; }
|
||||
blockquote { margin: 20px 40px; border: 1px solid #000; padding: 10px; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'corporate-executive',
|
||||
name: 'Corporate Executive',
|
||||
category: 'Corporate',
|
||||
description: 'Authoritative and professional. Designed for board reports, executive summaries, and high-stakes business communications.',
|
||||
vibe: 'Executive, Formal, Trustworthy',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Source+Serif+4:wght@400;600;700&family=Source+Sans+3:wght@400;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Source Serif 4", size: 24, color: "1A237E", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Source Sans 3", size: 14, color: "303F9F", bold: true, align: 'left',
|
||||
spacing: { before: 300, after: 150, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Source Sans 3", size: 10, color: "333333", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "1A237E"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Source Sans 3', sans-serif;
|
||||
h1 { font-family: 'Source Serif 4', serif; font-size: 24pt; font-weight: 700; color: #1A237E; margin-bottom: 24px; border-bottom: 2px solid #1A237E; padding-bottom: 8px; }
|
||||
h2 { font-size: 14pt; font-weight: 600; color: #303F9F; margin-top: 30px; margin-bottom: 12px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #333333; margin-bottom: 14px; }
|
||||
blockquote { border-left: 4px solid #1A237E; padding-left: 16px; color: #1A237E; margin: 20px 0; font-style: italic; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'political-campaign',
|
||||
name: 'Political Campaign',
|
||||
category: 'Professional',
|
||||
description: 'Bold, patriotic design for campaigns. Strong headers with red, white, and blue motifs.',
|
||||
vibe: 'Patriotic, Bold, Official',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Francois+One&family=Cabin:wght@400;600;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Francois One", size: 36, color: "0D47A1", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: { bottom: { color: "D32F2F", space: 8, style: "single", size: 12 } }
|
||||
},
|
||||
heading2: {
|
||||
font: "Cabin", size: 16, color: "D32F2F", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Cabin", size: 11, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "D32F2F"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Cabin', sans-serif;
|
||||
h1 { font-family: 'Francois One', sans-serif; font-size: 36pt; color: #0D47A1; border-bottom: 4px solid #D32F2F; padding-bottom: 12px; margin-bottom: 24px; text-transform: uppercase; }
|
||||
h2 { font-size: 16pt; font-weight: 700; color: #D32F2F; margin-top: 32px; margin-bottom: 16px; text-transform: uppercase; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #212121; margin-bottom: 14px; }
|
||||
blockquote { background: #E3F2FD; padding: 20px; border-left: 8px solid #0D47A1; margin: 24px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'passport-official',
|
||||
name: 'Passport Official',
|
||||
category: 'Government',
|
||||
description: 'International travel document aesthetic. Machine-readable fonts with secure, bureaucratic vibes.',
|
||||
vibe: 'Official, Secure, Monospace',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Martian+Mono:wght@400;700&family=Courier+Prime&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Martian Mono", size: 22, color: "1A237E", bold: true, align: 'left',
|
||||
spacing: { before: 360, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Martian Mono", size: 12, color: "B71C1C", bold: true, align: 'left',
|
||||
spacing: { before: 280, after: 140, line: 240 },
|
||||
allCaps: true
|
||||
},
|
||||
body: {
|
||||
font: "Courier Prime", size: 10, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 140, line: 260 }
|
||||
},
|
||||
accentColor: "B71C1C"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Courier Prime', monospace;
|
||||
h1 { font-family: 'Martian Mono', monospace; font-size: 22pt; font-weight: 700; color: #1A237E; margin-bottom: 24px; letter-spacing: -1px; }
|
||||
h2 { font-family: 'Martian Mono', monospace; font-size: 12pt; font-weight: 700; color: #B71C1C; margin-top: 28px; margin-bottom: 14px; text-transform: uppercase; }
|
||||
p { font-size: 10pt; line-height: 1.5; color: #212121; margin-bottom: 12px; }
|
||||
blockquote { border: 1px dashed #1A237E; padding: 16px; margin: 20px 0; background: #E8EAF6; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'top-secret-redacted',
|
||||
name: 'Top Secret Redacted',
|
||||
category: 'Government',
|
||||
description: 'Declassified document style. Typewriter fonts with "blacked out" highlight effects.',
|
||||
vibe: 'Secret, Classified, Rough',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Special+Elite&family=Courier+Prime:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Special Elite", size: 28, color: "000000", bold: false, align: 'center',
|
||||
spacing: { before: 400, after: 240, line: 240 },
|
||||
border: {
|
||||
top: { color: "000000", space: 6, style: "single", size: 24 },
|
||||
bottom: { color: "000000", space: 6, style: "single", size: 24 }
|
||||
}
|
||||
},
|
||||
heading2: {
|
||||
font: "Courier Prime", size: 14, color: "B71C1C", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
shading: { fill: "000000", color: "auto", style: "clear" } // Red text on black bar
|
||||
},
|
||||
body: {
|
||||
font: "Courier Prime", size: 11, color: "000000", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Courier Prime', monospace;
|
||||
background: #F5F5F5;
|
||||
h1 { font-family: 'Special Elite', cursive; font-size: 28pt; color: #000000; border-top: 4px solid #000; border-bottom: 4px solid #000; padding: 16px 0; text-align: center; margin-bottom: 28px; text-transform: uppercase; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #B71C1C; background: #000000; display: inline-block; padding: 4px 12px; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #000000; margin-bottom: 14px; }
|
||||
blockquote { background: #000; color: #000; padding: 10px; margin: 20px 0; user-select: none; }
|
||||
blockquote:hover { color: #FFF; } /* Easter egg for preview */
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'legal-pleading',
|
||||
name: 'Legal Pleading',
|
||||
category: 'Professional',
|
||||
description: 'Courtroom document style. Rigid framing, double spacing, and traditional serif fonts.',
|
||||
vibe: 'Legal, Strict, Formal',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=EB+Garamond:wght@400;700&family=Courier+Prime&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "EB Garamond", size: 14, color: "000000", bold: true, align: 'center',
|
||||
spacing: { before: 240, after: 240, line: 240 },
|
||||
allCaps: true,
|
||||
// underline: true - using border bottom to simulate
|
||||
border: { bottom: { color: "000000", space: 4, style: "single", size: 4 } }
|
||||
},
|
||||
heading2: {
|
||||
font: "EB Garamond", size: 12, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 240, after: 120, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Courier Prime", size: 12, color: "000000", align: 'both',
|
||||
spacing: { before: 0, after: 0, line: 480 }, // Double Spacing
|
||||
border: { left: { color: "BDBDBD", space: 12, style: "single", size: 4 } } // Simulates line number bar area
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Courier Prime', monospace;
|
||||
line-height: 2.0;
|
||||
h1 { font-family: 'EB Garamond', serif; font-size: 14pt; font-weight: 700; color: #000000; text-align: center; text-decoration: underline; text-transform: uppercase; margin-bottom: 24px; }
|
||||
h2 { font-family: 'EB Garamond', serif; font-size: 12pt; font-weight: 700; color: #000000; margin-top: 24px; margin-bottom: 12px; }
|
||||
p { font-size: 12pt; color: #000000; margin-bottom: 0px; text-align: justify; border-left: 1px solid #BDBDBD; padding-left: 15px; }
|
||||
blockquote { margin-left: 40px; border-left: 1px solid #BDBDBD; padding-left: 15px; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'currency-bill',
|
||||
name: 'Currency Bill',
|
||||
category: 'Official',
|
||||
description: 'Banknote aesthetic. Intricate guilloche-style borders and emerald green serif fonts.',
|
||||
vibe: 'Financial, Secure, Green',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Playfair+Display+SC:wght@700&family=Noto+Serif:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Playfair Display SC", size: 36, color: "1B5E20", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: {
|
||||
top: { color: "2E7D32", space: 6, style: "double", size: 12 },
|
||||
bottom: { color: "2E7D32", space: 6, style: "double", size: 12 }
|
||||
}
|
||||
},
|
||||
heading2: {
|
||||
font: "Noto Serif", size: 16, color: "388E3C", bold: true, align: 'center',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
allCaps: true
|
||||
},
|
||||
body: {
|
||||
font: "Noto Serif", size: 11, color: "1B5E20", align: 'both',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "2E7D32"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Noto Serif', serif;
|
||||
background: #E8F5E9;
|
||||
h1 { font-family: 'Playfair Display SC', serif; font-size: 36pt; font-weight: 700; color: #1B5E20; text-align: center; border-top: 4px double #2E7D32; border-bottom: 4px double #2E7D32; padding: 12px 0; margin-bottom: 24px; letter-spacing: 2px; }
|
||||
h2 { font-size: 16pt; font-weight: 700; color: #388E3C; text-align: center; margin-top: 32px; margin-bottom: 16px; text-transform: uppercase; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #1B5E20; margin-bottom: 14px; text-align: justify; }
|
||||
blockquote { border: 1px solid #2E7D32; padding: 20px; margin: 24px 0; background: #C8E6C9; text-align: center; border-radius: 50%; width: 200px; height: 200px; display: flex; align-items: center; justify-content: center; margin: 0 auto; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'credit-card-platinum',
|
||||
name: 'Credit Card Platinum',
|
||||
category: 'Financial',
|
||||
description: 'Premium card aesthetic. Silver/gradient shading with OCR-style raised numbering fonts.',
|
||||
vibe: 'Premium, Silver, Metallic',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Share+Tech+Mono&family=Krub:wght@400;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Krub", size: 32, color: "E0E0E0", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "424242", color: "auto", style: "clear" } // Dark grey metallic
|
||||
},
|
||||
heading2: {
|
||||
font: "Share Tech Mono", size: 18, color: "C0C0C0", bold: false, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
allCaps: true,
|
||||
tracking: 100 // Wide tracking
|
||||
},
|
||||
body: {
|
||||
font: "Krub", size: 11, color: "616161", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "C0C0C0"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Krub', sans-serif;
|
||||
h1 { font-size: 32pt; font-weight: 700; color: #E0E0E0; background: linear-gradient(135deg, #616161, #212121); padding: 16px; margin-bottom: 24px; border-radius: 12px; }
|
||||
h2 { font-family: 'Share Tech Mono', monospace; font-size: 18pt; color: #757575; margin-top: 32px; margin-bottom: 16px; text-transform: uppercase; letter-spacing: 3px; text-shadow: 1px 1px 0 #FFF; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #616161; margin-bottom: 14px; }
|
||||
blockquote { border-left: 4px solid #C0C0C0; padding-left: 16px; margin: 24px 0; background: #F5F5F5; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'whiteboard-strategy',
|
||||
name: 'Whiteboard Strategy',
|
||||
category: 'Business',
|
||||
description: 'Brainstorming session. Dry-erase marker fonts in standard office colors (Black, Blue, Red).',
|
||||
vibe: 'Corporate, Brainstorm, Sketch',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Architects+Daughter&family=Patrick+Hand&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Architects Daughter", size: 36, color: "D32F2F", bold: true, align: 'center', // Red marker
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: { bottom: { color: "1976D2", space: 4, style: "single", size: 12 } } // Blue underline
|
||||
},
|
||||
heading2: {
|
||||
font: "Patrick Hand", size: 20, color: "1976D2", bold: true, align: 'left', // Blue marker
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Patrick Hand", size: 14, color: "212121", align: 'left', // Black marker
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "D32F2F"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Patrick Hand', cursive;
|
||||
background: #FFFFFF;
|
||||
h1 { font-family: 'Architects Daughter', cursive; font-size: 36pt; font-weight: 700; color: #D32F2F; border-bottom: 3px solid #1976D2; padding-bottom: 10px; margin-bottom: 24px; text-align: center; }
|
||||
h2 { font-size: 20pt; font-weight: 700; color: #1976D2; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 14pt; line-height: 1.5; color: #212121; margin-bottom: 14px; }
|
||||
blockquote { border: 2px solid #388E3C; padding: 16px; margin: 24px 0; border-radius: 16px; color: #388E3C; } /* Green marker box */
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'stock-ticker',
|
||||
name: 'Stock Ticker',
|
||||
category: 'Financial',
|
||||
description: 'LED moving message sign. Dot matrix fonts with bright green/red on black.',
|
||||
vibe: 'Financial, Digital, LED',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=DotGothic16&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "DotGothic16", size: 32, color: "00E676", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "000000", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "DotGothic16", size: 18, color: "FF1744", bold: false, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
shading: { fill: "000000", color: "auto", style: "clear" }
|
||||
},
|
||||
body: {
|
||||
font: "DotGothic16", size: 12, color: "E0E0E0", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 },
|
||||
shading: { fill: "212121", color: "auto", style: "clear" }
|
||||
},
|
||||
accentColor: "00E676"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'DotGothic16', sans-serif;
|
||||
background: #212121;
|
||||
h1 { font-size: 32pt; color: #00E676; background: #000000; padding: 12px; margin-bottom: 24px; border-bottom: 2px solid #333; }
|
||||
h2 { font-size: 18pt; color: #FF1744; background: #000000; padding: 8px; margin-top: 32px; margin-bottom: 16px; display: inline-block; }
|
||||
p { font-size: 12pt; line-height: 1.5; color: #E0E0E0; margin-bottom: 14px; }
|
||||
blockquote { border-left: 4px solid #00E676; padding-left: 16px; margin: 24px 0; color: #B9F6CA; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'police-blotter',
|
||||
name: 'Police Blotter',
|
||||
category: 'Official',
|
||||
description: 'Law enforcement paperwork. Carbon copy blue fonts on stark white forms.',
|
||||
vibe: 'Official, Blue, Bureaucratic',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Courier+Prime&family=Special+Elite&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Special Elite", size: 26, color: "0D47A1", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
allCaps: true
|
||||
},
|
||||
heading2: {
|
||||
font: "Courier Prime", size: 14, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
shading: { fill: "E3F2FD", color: "auto", style: "clear" }
|
||||
},
|
||||
body: {
|
||||
font: "Courier Prime", size: 11, color: "1A237E", align: 'left', // Carbon copy blue
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "0D47A1"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Courier Prime', monospace;
|
||||
h1 { font-family: 'Special Elite', cursive; font-size: 26pt; color: #0D47A1; margin-bottom: 24px; text-transform: uppercase; text-decoration: underline; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #000000; background: #E3F2FD; display: block; padding: 4px; margin-top: 32px; margin-bottom: 16px; border: 1px solid #0D47A1; }
|
||||
p { font-size: 11pt; line-height: 1.5; color: #1A237E; margin-bottom: 14px; }
|
||||
blockquote { border: 1px solid #000; padding: 16px; margin: 24px 0; background: #FAFAFA; }
|
||||
`
|
||||
}
|
||||
];
|
||||
@@ -1,364 +0,0 @@
|
||||
import { StyleOption } from '../types';
|
||||
|
||||
export const creativeStyles: StyleOption[] = [
|
||||
{
|
||||
id: 'brutalist-mono',
|
||||
name: 'Brutalist Lab',
|
||||
category: 'Creative',
|
||||
description: 'Raw, monospaced aesthetic. Boxes, thick outlines, and typewriter vibes.',
|
||||
vibe: 'Code, Industrial, Raw',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Space Mono", size: 24, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: {
|
||||
top: { color: "000000", space: 12, style: "single", size: 24 },
|
||||
bottom: { color: "000000", space: 12, style: "single", size: 24 },
|
||||
left: { color: "000000", space: 12, style: "single", size: 24 },
|
||||
right: { color: "000000", space: 12, style: "single", size: 24 }
|
||||
}
|
||||
},
|
||||
heading2: {
|
||||
font: "Space Mono", size: 14, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
shading: { fill: "E0E0E0", color: "auto", style: "clear" }
|
||||
},
|
||||
body: {
|
||||
font: "Space Mono", size: 10, color: "111111", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Space Mono', monospace;
|
||||
h1 { font-size: 24pt; font-weight: 700; color: #000000; border: 4px solid #000; padding: 16px; margin-bottom: 24px; text-transform: uppercase; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #000000; background: #E0E0E0; padding: 8px; margin-top: 32px; margin-bottom: 16px; display: inline-block; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #111111; margin-bottom: 14px; }
|
||||
blockquote { border-left: 6px solid #000; padding-left: 16px; margin: 24px 0; font-weight: 700; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'bauhaus-poster',
|
||||
name: 'Bauhaus Poster',
|
||||
category: 'Creative',
|
||||
description: 'Geometric minimalism. Primary colors, angled text, and strong diagonal compositions.',
|
||||
vibe: 'Artistic, Geometric, Modernist',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Josefin+Sans:wght@400;700&family=Jost:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Josefin Sans", size: 36, color: "D50000", bold: true, align: 'right',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: { bottom: { color: "000000", space: 8, style: "single", size: 36 } }
|
||||
},
|
||||
heading2: {
|
||||
font: "Jost", size: 16, color: "2962FF", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
shading: { fill: "FFEB3B", color: "auto", style: "clear" }
|
||||
},
|
||||
body: {
|
||||
font: "Jost", size: 11, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "D50000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Jost', sans-serif;
|
||||
h1 { font-family: 'Josefin Sans', sans-serif; font-size: 36pt; font-weight: 700; color: #D50000; text-align: right; border-bottom: 8px solid #000; padding-bottom: 10px; margin-bottom: 24px; text-transform: uppercase; }
|
||||
h2 { font-size: 16pt; font-weight: 700; color: #2962FF; background: #FFEB3B; padding: 8px 16px; margin-top: 32px; margin-bottom: 16px; display: inline-block; transform: rotate(-1deg); }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #212121; margin-bottom: 14px; }
|
||||
blockquote { border-left: 10px solid #D50000; padding-left: 20px; margin: 24px 0; font-style: italic; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'glitch-art',
|
||||
name: 'Glitch Art',
|
||||
category: 'Creative',
|
||||
description: 'Digital distortion aesthetic. Monospaced fonts with neon colors and "broken" styling.',
|
||||
vibe: 'Digital, Glitch, Cyber',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Rubik+Glitch&family=Share+Tech+Mono&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Rubik Glitch", size: 40, color: "D500F9", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "121212", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Share Tech Mono", size: 18, color: "00E5FF", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Share Tech Mono", size: 11, color: "BDBDBD", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 },
|
||||
shading: { fill: "000000", color: "auto", style: "clear" }
|
||||
},
|
||||
accentColor: "00E5FF"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
background: #000000;
|
||||
color: #BDBDBD;
|
||||
h1 { font-family: 'Rubik Glitch', cursive; font-size: 40pt; color: #D500F9; background: #121212; padding: 10px; margin-bottom: 24px; text-shadow: 2px 0 #00E5FF; }
|
||||
h2 { font-size: 18pt; font-weight: 700; color: #00E5FF; margin-top: 32px; margin-bottom: 16px; text-transform: uppercase; letter-spacing: 2px; }
|
||||
p { font-size: 11pt; line-height: 1.5; color: #BDBDBD; margin-bottom: 14px; }
|
||||
blockquote { border: 1px solid #D500F9; padding: 16px; margin: 24px 0; color: #D500F9; box-shadow: 4px 4px 0 #00E5FF; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'vaporwave-aesthetic',
|
||||
name: 'Vaporwave Aesthetic',
|
||||
category: 'Creative',
|
||||
description: 'Nostalgic 80s/90s internet culture. Pink and cyan gradients, wide tracking, and ironic luxury.',
|
||||
vibe: 'Nostalgic, Digital, Surreal',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Varela+Round&family=Montserrat:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Montserrat", size: 32, color: "FF71CE", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
allCaps: true,
|
||||
tracking: 100 // Wide spacing
|
||||
},
|
||||
heading2: {
|
||||
font: "Varela Round", size: 16, color: "01CDFE", bold: false, align: 'center',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Montserrat", size: 10, color: "B967FF", align: 'center',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "01CDFE"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Montserrat', sans-serif;
|
||||
background: #F0F0FF;
|
||||
h1 { font-size: 32pt; font-weight: 700; color: #FF71CE; text-align: center; margin-bottom: 24px; letter-spacing: 4px; text-shadow: 2px 2px #01CDFE; text-transform: uppercase; }
|
||||
h2 { font-family: 'Varela Round', sans-serif; font-size: 16pt; color: #01CDFE; text-align: center; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #B967FF; margin-bottom: 14px; text-align: center; }
|
||||
blockquote { border: 2px solid #FF71CE; padding: 16px; margin: 24px 0; background: #E0FFFF; color: #01CDFE; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'pop-art-comic',
|
||||
name: 'Pop Art Comic',
|
||||
category: 'Creative',
|
||||
description: 'Roy Lichtenstein inspired. Bold black outlines, halftone vibes, and primary colors.',
|
||||
vibe: 'Comic, Bold, Pop',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Bangers&family=Comic+Neue:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Bangers", size: 42, color: "000000", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "FFFF00", color: "auto", style: "clear" } // Yellow back
|
||||
},
|
||||
heading2: {
|
||||
font: "Bangers", size: 24, color: "FFFFFF", bold: false, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
shading: { fill: "FF0000", color: "auto", style: "clear" } // Red back
|
||||
},
|
||||
body: {
|
||||
font: "Comic Neue", size: 12, color: "000000", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Comic Neue', sans-serif;
|
||||
h1 { font-family: 'Bangers', cursive; font-size: 42pt; color: #000000; background: #FFFF00; padding: 10px; border: 4px solid #000; box-shadow: 5px 5px 0 #000; margin-bottom: 24px; display: inline-block; }
|
||||
h2 { font-family: 'Bangers', cursive; font-size: 24pt; color: #FFFFFF; background: #FF0000; padding: 5px 15px; border: 3px solid #000; margin-top: 32px; margin-bottom: 16px; display: inline-block; transform: rotate(-2deg); }
|
||||
p { font-size: 12pt; line-height: 1.5; color: #000000; margin-bottom: 14px; font-weight: 700; }
|
||||
blockquote { background: #FFFFFF; border: 3px solid #000; padding: 20px; border-radius: 50% / 20%; margin: 24px 0; text-align: center; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'grunge-90s',
|
||||
name: 'Grunge 90s',
|
||||
category: 'Creative',
|
||||
description: 'Distressed and edgy. David Carson inspired typography with overlapping elements and grit.',
|
||||
vibe: 'Dirty, Edgy, Chaotic',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Permanent+Marker&family=Special+Elite&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Permanent Marker", size: 36, color: "333333", bold: false, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Special Elite", size: 18, color: "8B0000", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
border: { bottom: { color: "000000", space: 4, style: "dashed", size: 12 } }
|
||||
},
|
||||
body: {
|
||||
font: "Special Elite", size: 11, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "8B0000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Special Elite', cursive;
|
||||
background-color: #F0F0F0;
|
||||
h1 { font-family: 'Permanent Marker', cursive; font-size: 36pt; color: #333333; text-align: center; margin-bottom: 24px; transform: rotate(1deg); opacity: 0.9; }
|
||||
h2 { font-size: 18pt; font-weight: 700; color: #8B0000; margin-top: 32px; margin-bottom: 16px; border-bottom: 2px dashed #000; display: inline-block; transform: skewX(-5deg); }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #212121; margin-bottom: 14px; }
|
||||
blockquote { border: 3px solid #000; padding: 16px; margin: 24px 0; background: #D3D3D3; transform: rotate(-1deg); }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'risograph-print',
|
||||
name: 'Risograph Print',
|
||||
category: 'Creative',
|
||||
description: 'Independent publishing style. Grainy textures, misalignment, and vibrant spot colors (Pink/Teal).',
|
||||
vibe: 'Artistic, Indie, Textured',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Eb+Garamond:ital,wght@0,400;0,700;1,400&family=Karla:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Eb Garamond", size: 42, color: "FF007F", bold: true, align: 'left', // Riso Pink
|
||||
spacing: { before: 400, after: 200, line: 200 },
|
||||
italic: true
|
||||
},
|
||||
heading2: {
|
||||
font: "Karla", size: 14, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
shading: { fill: "00A9FF", color: "auto", style: "clear" } // Riso Blue background
|
||||
},
|
||||
body: {
|
||||
font: "Karla", size: 10, color: "1A1A1A", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "FF007F"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Karla', sans-serif;
|
||||
background: #FFFEF0;
|
||||
h1 { font-family: 'Eb Garamond', serif; font-size: 42pt; font-weight: 700; font-style: italic; color: #FF007F; margin-bottom: 24px; mix-blend-mode: multiply; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #000000; background: #00A9FF; display: inline-block; padding: 4px 10px; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #1A1A1A; margin-bottom: 14px; }
|
||||
blockquote { border-left: 6px solid #FF007F; padding-left: 16px; margin: 24px 0; color: #555; font-style: italic; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'blueprint-cyanotype',
|
||||
name: 'Blueprint Cyanotype',
|
||||
category: 'Creative',
|
||||
description: 'Architectural blueprint style. White lines on a deep cyan blue background.',
|
||||
vibe: 'Technical, Blue, Schematic',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Architects+Daughter&family=Roboto+Mono:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Architects Daughter", size: 32, color: "FFFFFF", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: { bottom: { color: "FFFFFF", space: 4, style: "single", size: 12 } }
|
||||
},
|
||||
heading2: {
|
||||
font: "Roboto Mono", size: 14, color: "FFFFFF", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
allCaps: true
|
||||
},
|
||||
body: {
|
||||
font: "Roboto Mono", size: 10, color: "E0F7FA", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "FFFFFF"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Roboto Mono', monospace;
|
||||
background: #0047AB; /* Cobalt/Blueprint Blue */
|
||||
color: #FFFFFF;
|
||||
h1 { font-family: 'Architects Daughter', cursive; font-size: 32pt; font-weight: 700; color: #FFFFFF; text-align: center; border-bottom: 2px solid #FFFFFF; margin-bottom: 24px; padding-bottom: 8px; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #FFFFFF; margin-top: 32px; margin-bottom: 16px; text-transform: uppercase; border: 1px solid #FFF; display: inline-block; padding: 4px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #E0F7FA; margin-bottom: 14px; }
|
||||
blockquote { border: 1px dashed #FFFFFF; padding: 16px; margin: 24px 0; background: #003380; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'street-art-graffiti',
|
||||
name: 'Street Art Graffiti',
|
||||
category: 'Creative',
|
||||
description: 'Urban street style. Spray paint fonts, dripping effects, and concrete vibes.',
|
||||
vibe: 'Urban, Rebel, Spray',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Permanent+Marker&family=Rock+Salt&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Permanent Marker", size: 48, color: "000000", bold: false, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "FFFF00", color: "auto", style: "clear" } // Hazard Yellow
|
||||
},
|
||||
heading2: {
|
||||
font: "Rock Salt", size: 18, color: "FF0000", bold: false, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Permanent Marker", size: 12, color: "333333", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Permanent Marker', cursive;
|
||||
background: #F0F0F0;
|
||||
h1 { font-size: 48pt; color: #000000; text-align: center; background: #FFFF00; padding: 10px; transform: rotate(-2deg); margin-bottom: 24px; box-shadow: 4px 4px 0 #000; }
|
||||
h2 { font-family: 'Rock Salt', cursive; font-size: 18pt; color: #FF0000; margin-top: 32px; margin-bottom: 16px; transform: rotate(1deg); }
|
||||
p { font-size: 12pt; line-height: 1.6; color: #333333; margin-bottom: 14px; }
|
||||
blockquote { border-left: 5px solid #000; padding-left: 16px; margin: 24px 0; font-family: 'Rock Salt', cursive; font-size: 10pt; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'origami-paper',
|
||||
name: 'Origami Paper',
|
||||
category: 'Creative',
|
||||
description: 'Folded paper aesthetic. Sharp angles, subtle shadows, and crisp typography.',
|
||||
vibe: 'Delicate, Sharp, Paper',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Cormorant+Unicase:wght@400;700&family=Muli:wght@300;400&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Cormorant Unicase", size: 32, color: "37474F", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Cormorant Unicase", size: 16, color: "546E7A", bold: false, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Muli", size: 10, color: "455A64", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "37474F"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Muli', sans-serif;
|
||||
background: #FAFAFA;
|
||||
h1 { font-family: 'Cormorant Unicase', serif; font-size: 32pt; font-weight: 700; color: #37474F; text-align: center; margin-bottom: 24px; text-shadow: 1px 1px 0 #CCC; }
|
||||
h2 { font-family: 'Cormorant Unicase', serif; font-size: 16pt; color: #546E7A; margin-top: 32px; margin-bottom: 16px; border-bottom: 1px solid #CFD8DC; display: inline-block; padding-bottom: 4px; }
|
||||
p { font-size: 10pt; line-height: 1.7; color: #455A64; margin-bottom: 14px; }
|
||||
blockquote { background: #FFF; padding: 20px; border: 1px solid #ECEFF1; box-shadow: 2px 2px 5px rgba(0,0,0,0.05); margin: 24px 0; transform: rotate(1deg); }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'watercolor-wash',
|
||||
name: 'Watercolor Wash',
|
||||
category: 'Creative',
|
||||
description: 'Artistic and fluid. Soft blended colors and painterly fonts.',
|
||||
vibe: 'Artistic, Soft, Fluid',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Kalam:wght@400;700&family=Amatic+SC:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Kalam", size: 36, color: "7986CB", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Amatic SC", size: 24, color: "4DB6AC", bold: true, align: 'center',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Kalam", size: 12, color: "616161", align: 'center',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "7986CB"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Kalam', cursive;
|
||||
h1 { font-size: 36pt; font-weight: 700; color: #7986CB; text-align: center; margin-bottom: 24px; text-shadow: 2px 2px 4px rgba(121, 134, 203, 0.3); }
|
||||
h2 { font-family: 'Amatic SC', cursive; font-size: 24pt; font-weight: 700; color: #4DB6AC; text-align: center; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 12pt; line-height: 1.6; color: #616161; margin-bottom: 14px; text-align: center; }
|
||||
blockquote { border: 2px solid #E0F2F1; background: #E8EAF6; padding: 20px; border-radius: 50% 20% / 10% 40%; margin: 24px 0; text-align: center; }
|
||||
`
|
||||
}
|
||||
];
|
||||
@@ -1,284 +0,0 @@
|
||||
import { StyleOption } from '../types';
|
||||
|
||||
export const editorialStyles: StyleOption[] = [
|
||||
{
|
||||
id: 'ny-editor',
|
||||
name: 'The Editorial',
|
||||
category: 'Editorial',
|
||||
description: 'High-contrast serifs, centered headers, delicate borders. Feels like a premium magazine feature.',
|
||||
vibe: 'Luxury, Fashion, Literature',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,700;1,400&family=Lora:ital,wght@0,400;1,400&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Playfair Display", size: 36, color: "111111", bold: true, italic: true, align: 'center',
|
||||
spacing: { before: 600, after: 400, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Playfair Display", size: 14, color: "444444", bold: true, allCaps: true, tracking: 100, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: { bottom: { color: "DDDDDD", space: 8, style: "single", size: 4 } }
|
||||
},
|
||||
body: {
|
||||
font: "Lora", size: 11, color: "333333", align: 'both',
|
||||
spacing: { before: 0, after: 200, line: 320 }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Lora', serif;
|
||||
h1 { font-family: 'Playfair Display', serif; font-size: 36pt; font-weight: 700; font-style: italic; text-align: center; margin-bottom: 30px; }
|
||||
h2 { font-family: 'Playfair Display', serif; font-size: 14pt; font-weight: 700; text-transform: uppercase; letter-spacing: 3px; text-align: center; border-bottom: 1px solid #ddd; padding-bottom: 10px; margin-top: 40px; color: #444; }
|
||||
p { font-size: 11pt; line-height: 1.8; text-align: justify; margin-bottom: 20px; }
|
||||
blockquote { font-family: 'Playfair Display', serif; font-size: 18pt; font-style: italic; text-align: center; color: #555; margin: 40px 20px; border: none; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'luxury-editorial',
|
||||
name: 'Luxury Editorial',
|
||||
category: 'Editorial',
|
||||
description: 'High-fashion magazine inspired design. Elegant serifs with sophisticated spacing and premium feel for upscale content.',
|
||||
vibe: 'Fashion, Premium, Sophisticated',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Cormorant:wght@400;500;700&family=Montserrat:wght@300;400;500&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Cormorant", size: 36, color: "1C1C1C", bold: false, align: 'center',
|
||||
spacing: { before: 480, after: 280, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Montserrat", size: 11, color: "1C1C1C", bold: true, align: 'left',
|
||||
spacing: { before: 360, after: 180, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Montserrat", size: 10, color: "3A3A3A", align: 'left',
|
||||
spacing: { before: 0, after: 180, line: 300 }
|
||||
},
|
||||
accentColor: "B8860B"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Montserrat', sans-serif;
|
||||
h1 { font-family: 'Cormorant', serif; font-size: 36pt; font-weight: 500; color: #1C1C1C; text-align: center; margin-bottom: 32px; letter-spacing: 2px; }
|
||||
h2 { font-size: 11pt; font-weight: 500; color: #1C1C1C; margin-top: 36px; margin-bottom: 18px; text-transform: uppercase; letter-spacing: 3px; }
|
||||
p { font-size: 10pt; line-height: 1.7; color: #3A3A3A; margin-bottom: 16px; font-weight: 300; }
|
||||
blockquote { border-top: 1px solid #B8860B; border-bottom: 1px solid #B8860B; padding: 24px 0; margin: 32px 0; text-align: center; font-family: 'Cormorant', serif; font-size: 14pt; font-style: italic; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'newspaper-classic',
|
||||
name: 'Newspaper Classic',
|
||||
category: 'Editorial',
|
||||
description: 'Traditional newspaper layout with strong typographic hierarchy. Bold headlines, readable body text, and authoritative presence.',
|
||||
vibe: 'News, Authority, Information',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Playfair+Display:wght@700;900&family=PT+Serif:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Playfair Display", size: 36, color: "000000", bold: true, align: 'center',
|
||||
spacing: { before: 240, after: 160, line: 220 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Playfair Display", size: 16, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 240, after: 120, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "PT Serif", size: 10, color: "1A1A1A", align: 'both',
|
||||
spacing: { before: 0, after: 120, line: 280 }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'PT Serif', serif;
|
||||
h1 { font-family: 'Playfair Display', serif; font-size: 36pt; font-weight: 900; color: #000000; text-align: center; border-bottom: 2px solid #000000; padding-bottom: 12px; margin-bottom: 20px; }
|
||||
h2 { font-family: 'Playfair Display', serif; font-size: 16pt; font-weight: 700; color: #000000; margin-top: 24px; margin-bottom: 12px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #1A1A1A; margin-bottom: 10px; text-align: justify; }
|
||||
blockquote { font-size: 14pt; font-style: italic; text-align: center; margin: 24px 40px; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'newspaper-modern',
|
||||
name: 'Newspaper Modern',
|
||||
category: 'Editorial',
|
||||
description: 'Contemporary newspaper design balancing tradition with modern sensibilities. Clean grid-based layout.',
|
||||
vibe: 'Modern, Editorial, Informative',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=DM+Serif+Display&family=DM+Sans:wght@400;500;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "DM Serif Display", size: 36, color: "1A1A1A", bold: false, align: 'left',
|
||||
spacing: { before: 320, after: 200, line: 220 }
|
||||
},
|
||||
heading2: {
|
||||
font: "DM Sans", size: 12, color: "1A1A1A", bold: true, align: 'left',
|
||||
spacing: { before: 280, after: 140, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "DM Sans", size: 10, color: "333333", align: 'both',
|
||||
spacing: { before: 0, after: 140, line: 280 }
|
||||
},
|
||||
accentColor: "DC2626"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'DM Sans', sans-serif;
|
||||
h1 { font-family: 'DM Serif Display', serif; font-size: 36pt; color: #1A1A1A; margin-bottom: 24px; }
|
||||
h2 { font-size: 12pt; font-weight: 700; color: #1A1A1A; margin-top: 28px; margin-bottom: 14px; text-transform: uppercase; letter-spacing: 1px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #333333; margin-bottom: 12px; text-align: justify; }
|
||||
blockquote { font-size: 16pt; font-style: italic; font-family: 'DM Serif Display', serif; text-align: center; margin: 28px 20px; color: #DC2626; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'newspaper-tabloid',
|
||||
name: 'Newspaper Tabloid',
|
||||
category: 'Editorial',
|
||||
description: 'Sensationalist news design. Condensed, heavy headers with urgent red accents.',
|
||||
vibe: 'Urgent, Bold, Sensational',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Antonio:wght@700&family=Pathway+Extreme:wght@400;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Antonio", size: 42, color: "FFFFFF", bold: true, align: 'left',
|
||||
spacing: { before: 360, after: 200, line: 200 },
|
||||
shading: { fill: "D50000", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Antonio", size: 20, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 280, after: 140, line: 220 }
|
||||
},
|
||||
body: {
|
||||
font: "Pathway Extreme", size: 10, color: "111111", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "D50000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Pathway Extreme', sans-serif;
|
||||
h1 { font-family: 'Antonio', sans-serif; font-size: 42pt; font-weight: 700; color: #FFFFFF; background: #D50000; padding: 12px 16px; margin-bottom: 24px; text-transform: uppercase; line-height: 1; }
|
||||
h2 { font-family: 'Antonio', sans-serif; font-size: 20pt; font-weight: 700; color: #000000; margin-top: 28px; margin-bottom: 14px; text-transform: uppercase; }
|
||||
p { font-size: 10pt; line-height: 1.5; color: #111111; margin-bottom: 14px; }
|
||||
blockquote { font-size: 14pt; font-weight: 700; font-style: italic; color: #000000; border-left: 6px solid #D50000; padding-left: 16px; margin: 24px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'indie-zine',
|
||||
name: 'Indie Zine',
|
||||
category: 'Editorial',
|
||||
description: 'DIY photocopier aesthetic. Typewriter fonts, cut-out look, and rebellious asymmetry.',
|
||||
vibe: 'DIY, Rebellious, Rough',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Special+Elite&family=Rock+Salt&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Rock Salt", size: 28, color: "000000", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "D1C4E9", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Special Elite", size: 14, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
border: { bottom: { color: "000000", space: 4, style: "single", size: 12 } }
|
||||
},
|
||||
body: {
|
||||
font: "Special Elite", size: 10, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Special Elite', cursive;
|
||||
h1 { font-family: 'Rock Salt', cursive; font-size: 28pt; color: #000000; background: #D1C4E9; padding: 10px; transform: rotate(-2deg); margin-bottom: 24px; display: inline-block; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #000000; border-bottom: 2px solid #000; margin-top: 32px; margin-bottom: 16px; width: fit-content; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #212121; margin-bottom: 14px; }
|
||||
blockquote { border: 2px dashed #000; padding: 16px; margin: 24px 0; transform: rotate(1deg); }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'literary-review',
|
||||
name: 'Literary Review',
|
||||
category: 'Editorial',
|
||||
description: 'Classic bookish aesthetic. Dense serif text, elegant headers, perfect for long-form essays.',
|
||||
vibe: 'Intellectual, Dense, Classic',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Crimson+Pro:ital,wght@0,400;0,700;1,400&family=Sorts+Mill+Goudy&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Crimson Pro", size: 30, color: "4A148C", bold: true, align: 'center',
|
||||
spacing: { before: 480, after: 280, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Crimson Pro", size: 14, color: "000000", bold: false, align: 'center',
|
||||
spacing: { before: 360, after: 180, line: 240 },
|
||||
smallCaps: true
|
||||
},
|
||||
body: {
|
||||
font: "Sorts Mill Goudy", size: 11, color: "212121", align: 'both',
|
||||
spacing: { before: 0, after: 160, line: 300 }
|
||||
},
|
||||
accentColor: "4A148C"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Sorts Mill Goudy', serif;
|
||||
h1 { font-family: 'Crimson Pro', serif; font-size: 30pt; font-weight: 700; color: #4A148C; text-align: center; margin-bottom: 32px; }
|
||||
h2 { font-family: 'Crimson Pro', serif; font-size: 14pt; color: #000000; text-align: center; margin-top: 36px; margin-bottom: 18px; font-variant: small-caps; }
|
||||
p { font-size: 11pt; line-height: 1.8; color: #212121; margin-bottom: 16px; text-align: justify; }
|
||||
blockquote { margin: 24px 40px; font-style: italic; color: #4A148C; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'fashion-magazine',
|
||||
name: 'Fashion Magazine',
|
||||
category: 'Editorial',
|
||||
description: 'Trendy and bold. High-contrast typography with oversized lettering and pink accents.',
|
||||
vibe: 'Trendy, Loud, Pink',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Abril+Fatface&family=Raleway:wght@300;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Abril Fatface", size: 48, color: "E91E63", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 200 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Raleway", size: 14, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
allCaps: true,
|
||||
tracking: 200
|
||||
},
|
||||
body: {
|
||||
font: "Raleway", size: 10, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "E91E63"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Raleway', sans-serif;
|
||||
h1 { font-family: 'Abril Fatface', cursive; font-size: 48pt; color: #E91E63; margin-bottom: 24px; line-height: 0.9; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #000000; text-transform: uppercase; letter-spacing: 4px; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #212121; margin-bottom: 14px; font-weight: 300; }
|
||||
blockquote { border-left: 10px solid #E91E63; padding-left: 20px; margin: 24px 0; font-family: 'Abril Fatface', cursive; font-size: 18pt; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'film-script',
|
||||
name: 'Film Script',
|
||||
category: 'Editorial',
|
||||
description: 'Hollywood screenplay format. Courier font, specific margins, and character name centering.',
|
||||
vibe: 'Cinematic, Format, Draft',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Courier+Prime:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Courier Prime", size: 12, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 240, after: 240, line: 240 },
|
||||
allCaps: true,
|
||||
underline: true
|
||||
},
|
||||
heading2: {
|
||||
font: "Courier Prime", size: 12, color: "000000", bold: true, align: 'center',
|
||||
spacing: { before: 480, after: 0, line: 240 },
|
||||
allCaps: true
|
||||
},
|
||||
body: {
|
||||
font: "Courier Prime", size: 12, color: "000000", align: 'left',
|
||||
spacing: { before: 0, after: 0, line: 240 }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Courier Prime', monospace;
|
||||
h1 { font-size: 12pt; font-weight: 700; color: #000000; text-decoration: underline; text-transform: uppercase; margin-bottom: 12px; }
|
||||
h2 { font-size: 12pt; font-weight: 700; color: #000000; text-transform: uppercase; text-align: center; margin-top: 24px; margin-bottom: 0px; }
|
||||
p { font-size: 12pt; line-height: 1; color: #000000; margin-bottom: 12px; }
|
||||
blockquote { margin: 0 40px; text-align: center; }
|
||||
`
|
||||
}
|
||||
];
|
||||
@@ -1,22 +1,8 @@
|
||||
import { StyleOption } from '../types';
|
||||
import { minimalistStyles } from './minimalist';
|
||||
import { editorialStyles } from './editorial';
|
||||
import { corporateStyles } from './corporate';
|
||||
import { techStyles } from './tech';
|
||||
import { creativeStyles } from './creative';
|
||||
import { vintageStyles } from './vintage';
|
||||
import { lifestyleStyles } from './lifestyle';
|
||||
import { academicStyles } from './academic';
|
||||
import { industrialStyles } from './industrial';
|
||||
// Templates are now loaded dynamically from JSON files
|
||||
// See src/services/templateLoader.ts for the loading mechanism
|
||||
// Templates are bundled in src-tauri/templates/ and loaded at runtime
|
||||
|
||||
export const ALL_STYLES: StyleOption[] = [
|
||||
...minimalistStyles,
|
||||
...editorialStyles,
|
||||
...corporateStyles,
|
||||
...techStyles,
|
||||
...creativeStyles,
|
||||
...vintageStyles,
|
||||
...lifestyleStyles,
|
||||
...academicStyles,
|
||||
...industrialStyles
|
||||
];
|
||||
import { StyleOption } from '../types';
|
||||
|
||||
// Export empty array - templates are loaded dynamically
|
||||
export const ALL_STYLES: StyleOption[] = [];
|
||||
|
||||
@@ -1,617 +0,0 @@
|
||||
import { StyleOption } from '../types';
|
||||
|
||||
export const industrialStyles: StyleOption[] = [
|
||||
{
|
||||
id: 'construction-industrial',
|
||||
name: 'Construction Industrial',
|
||||
category: 'Industrial',
|
||||
description: 'Bold and sturdy design for construction and industrial companies. Strong typography with safety-inspired colors.',
|
||||
vibe: 'Strong, Industrial, Professional',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Oswald:wght@400;500;700&family=Roboto:wght@400;500&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Oswald", size: 28, color: "212121", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "FFC107", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Oswald", size: 16, color: "FF8F00", bold: true, align: 'left',
|
||||
spacing: { before: 300, after: 150, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Roboto", size: 10, color: "37474F", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "FF8F00"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Roboto', sans-serif;
|
||||
h1 { font-family: 'Oswald', sans-serif; font-size: 28pt; font-weight: 700; color: #212121; background: #FFC107; padding: 16px 20px; margin-bottom: 24px; text-transform: uppercase; }
|
||||
h2 { font-family: 'Oswald', sans-serif; font-size: 16pt; font-weight: 700; color: #FF8F00; margin-top: 30px; margin-bottom: 14px; text-transform: uppercase; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #37474F; margin-bottom: 14px; }
|
||||
blockquote { background: #FFF8E1; padding: 16px; border-left: 6px solid #FF8F00; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'automotive-bold',
|
||||
name: 'Automotive Bold',
|
||||
category: 'Automotive',
|
||||
description: 'Powerful design for automotive and motorsport industries. Bold typography with dynamic energy and speed.',
|
||||
vibe: 'Powerful, Dynamic, Bold',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Teko:wght@400;500;700&family=Barlow:wght@400;500;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Teko", size: 40, color: "B71C1C", bold: true, align: 'left',
|
||||
spacing: { before: 360, after: 200, line: 200 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Teko", size: 20, color: "212121", bold: true, align: 'left',
|
||||
spacing: { before: 280, after: 140, line: 220 }
|
||||
},
|
||||
body: {
|
||||
font: "Barlow", size: 10, color: "37474F", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "B71C1C"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Barlow', sans-serif;
|
||||
h1 { font-family: 'Teko', sans-serif; font-size: 40pt; font-weight: 700; color: #B71C1C; margin-bottom: 24px; text-transform: uppercase; letter-spacing: 2px; }
|
||||
h2 { font-family: 'Teko', sans-serif; font-size: 20pt; font-weight: 500; color: #212121; margin-top: 28px; margin-bottom: 14px; text-transform: uppercase; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #37474F; margin-bottom: 14px; }
|
||||
blockquote { background: #FFEBEE; padding: 16px; border-left: 6px solid #B71C1C; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'real-estate-premium',
|
||||
name: 'Real Estate Premium',
|
||||
category: 'Real Estate',
|
||||
description: 'Sophisticated design for luxury real estate and property marketing. Elegant typography with premium golden accents.',
|
||||
vibe: 'Luxury, Premium, Sophisticated',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Cinzel:wght@400;600;700&family=Lato:wght@300;400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Cinzel", size: 28, color: "1A1A1A", bold: false, align: 'center',
|
||||
spacing: { before: 480, after: 280, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Cinzel", size: 14, color: "B8860B", bold: false, align: 'left',
|
||||
spacing: { before: 360, after: 180, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Lato", size: 10, color: "4A4A4A", align: 'left',
|
||||
spacing: { before: 0, after: 180, line: 300 }
|
||||
},
|
||||
accentColor: "B8860B"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Lato', sans-serif;
|
||||
h1 { font-family: 'Cinzel', serif; font-size: 28pt; font-weight: 600; color: #1A1A1A; text-align: center; margin-bottom: 32px; letter-spacing: 4px; }
|
||||
h2 { font-family: 'Cinzel', serif; font-size: 14pt; color: #B8860B; margin-top: 36px; margin-bottom: 18px; letter-spacing: 2px; }
|
||||
p { font-size: 10pt; line-height: 1.7; color: #4A4A4A; margin-bottom: 16px; font-weight: 300; }
|
||||
blockquote { border-top: 1px solid #B8860B; border-bottom: 1px solid #B8860B; padding: 24px 0; margin: 32px 0; text-align: center; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'environmental-green',
|
||||
name: 'Environmental Green',
|
||||
category: 'Sustainability',
|
||||
description: 'Nature-inspired design for environmental and sustainability communications. Organic feel with earthy green palette.',
|
||||
vibe: 'Natural, Sustainable, Organic',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Bitter:wght@400;500;700&family=Karla:wght@400;500;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Bitter", size: 26, color: "2E7D32", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Bitter", size: 14, color: "388E3C", bold: true, align: 'left',
|
||||
spacing: { before: 300, after: 150, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Karla", size: 10, color: "3E4A3D", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "2E7D32"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Karla', sans-serif;
|
||||
h1 { font-family: 'Bitter', serif; font-size: 26pt; font-weight: 700; color: #2E7D32; margin-bottom: 24px; }
|
||||
h2 { font-family: 'Bitter', serif; font-size: 14pt; font-weight: 700; color: #388E3C; margin-top: 30px; margin-bottom: 14px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #3E4A3D; margin-bottom: 14px; }
|
||||
blockquote { background: #E8F5E9; padding: 16px; border-left: 4px solid #2E7D32; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'aviation-classic',
|
||||
name: 'Aviation Classic',
|
||||
category: 'Transport',
|
||||
description: 'Vintage aviation inspired design. Classic military typography with heritage color palette.',
|
||||
vibe: 'Heritage, Classic, Aviation',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Stencil&family=Public+Sans:wght@400;500;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Stencil", size: 28, color: "1B4D3E", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Public Sans", size: 13, color: "8B0000", bold: true, align: 'left',
|
||||
spacing: { before: 300, after: 150, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Public Sans", size: 10, color: "363636", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "8B0000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Public Sans', sans-serif;
|
||||
h1 { font-family: 'Stencil', sans-serif; font-size: 28pt; color: #1B4D3E; margin-bottom: 24px; letter-spacing: 3px; }
|
||||
h2 { font-size: 13pt; font-weight: 600; color: #8B0000; margin-top: 30px; margin-bottom: 14px; text-transform: uppercase; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #363636; margin-bottom: 14px; }
|
||||
blockquote { background: #F5F5DC; padding: 16px; border-left: 4px solid #1B4D3E; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'architecture-firm',
|
||||
name: 'Architecture Firm',
|
||||
category: 'Architecture',
|
||||
description: 'Structural precision for architecture and design firms. Clean geometry with sophisticated restraint.',
|
||||
vibe: 'Structural, Precise, Sophisticated',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Fahkwang:wght@400;500;600&family=Manrope:wght@300;400;500&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Fahkwang", size: 28, color: "1A1A1A", bold: false, align: 'left',
|
||||
spacing: { before: 480, after: 280, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Manrope", size: 12, color: "4A4A4A", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Manrope", size: 10, color: "525252", align: 'left',
|
||||
spacing: { before: 0, after: 180, line: 300 }
|
||||
},
|
||||
accentColor: "1A1A1A"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Manrope', sans-serif;
|
||||
h1 { font-family: 'Fahkwang', sans-serif; font-size: 28pt; font-weight: 500; color: #1A1A1A; margin-bottom: 32px; letter-spacing: 1px; }
|
||||
h2 { font-size: 12pt; font-weight: 500; color: #4A4A4A; margin-top: 40px; margin-bottom: 20px; text-transform: uppercase; letter-spacing: 2px; }
|
||||
p { font-size: 10pt; line-height: 1.7; color: #525252; margin-bottom: 16px; font-weight: 300; }
|
||||
blockquote { border-left: 1px solid #1A1A1A; padding-left: 24px; margin: 32px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'electric-vehicle',
|
||||
name: 'Electric Vehicle',
|
||||
category: 'Automotive',
|
||||
description: 'Sustainable tech design for electric vehicle and clean energy content. Eco-modern with electric accents.',
|
||||
vibe: 'Sustainable, Modern, Electric',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Electrolize&family=Mulish:wght@400;600;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Electrolize", size: 28, color: "10B981", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Mulish", size: 14, color: "1E293B", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Mulish", size: 10, color: "475569", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "10B981"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Mulish', sans-serif;
|
||||
h1 { font-family: 'Electrolize', sans-serif; font-size: 28pt; color: #10B981; margin-bottom: 24px; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #1E293B; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #475569; margin-bottom: 14px; }
|
||||
blockquote { background: #ECFDF5; padding: 16px; border-left: 4px solid #10B981; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'industrial-blueprint',
|
||||
name: 'Industrial Blueprint',
|
||||
category: 'Technical',
|
||||
description: 'Engineering-inspired design reminiscent of technical blueprints. Precise typography with drafting aesthetics.',
|
||||
vibe: 'Technical, Precise, Engineering',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Share+Tech+Mono&family=Titillium+Web:wght@400;600;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Titillium Web", size: 24, color: "FFFFFF", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "1A3A5C", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Titillium Web", size: 14, color: "1A3A5C", bold: true, align: 'left',
|
||||
spacing: { before: 300, after: 150, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Share Tech Mono", size: 9, color: "2C4A6B", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 300 }
|
||||
},
|
||||
accentColor: "1A3A5C"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
h1 { font-family: 'Titillium Web', sans-serif; font-size: 24pt; font-weight: 700; color: #FFFFFF; background: #1A3A5C; padding: 16px 20px; margin-bottom: 24px; text-transform: uppercase; }
|
||||
h2 { font-family: 'Titillium Web', sans-serif; font-size: 14pt; font-weight: 700; color: #1A3A5C; margin-top: 30px; margin-bottom: 14px; }
|
||||
p { font-size: 9pt; line-height: 1.7; color: #2C4A6B; margin-bottom: 14px; }
|
||||
blockquote { background: #E8F4FC; padding: 16px; border: 1px dashed #1A3A5C; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'tactical-military',
|
||||
name: 'Tactical Military',
|
||||
category: 'Industrial',
|
||||
description: 'Military-spec aesthetic. Stencil typography with olive drab and technical readouts.',
|
||||
vibe: 'Tactical, Sturdy, Regulated',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Allerta+Stencil&family=Quantico:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Allerta Stencil", size: 28, color: "33691E", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: { bottom: { color: "558B2F", space: 6, style: "single", size: 16 } }
|
||||
},
|
||||
heading2: {
|
||||
font: "Quantico", size: 14, color: "558B2F", bold: true, align: 'left',
|
||||
spacing: { before: 300, after: 150, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Quantico", size: 10, color: "1B1B1B", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "33691E"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Quantico', sans-serif;
|
||||
background: #F1F8E9;
|
||||
h1 { font-family: 'Allerta Stencil', sans-serif; font-size: 28pt; color: #33691E; border-bottom: 4px solid #558B2F; padding-bottom: 12px; margin-bottom: 24px; text-transform: uppercase; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #558B2F; margin-top: 30px; margin-bottom: 14px; text-transform: uppercase; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #1B1B1B; margin-bottom: 14px; }
|
||||
blockquote { border: 2px solid #33691E; padding: 16px; margin: 20px 0; background: #DCEDC8; font-family: 'Quantico', sans-serif; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'logistics-freight',
|
||||
name: 'Logistics Freight',
|
||||
category: 'Industrial',
|
||||
description: 'Shipping and cargo aesthetic. Stenciled, heavy typography with industrial orange and slate blue.',
|
||||
vibe: 'Industrial, Heavy, Shipping',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Saira+Stencil+One&family=Saira:wght@400;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Saira Stencil One", size: 36, color: "E65100", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Saira", size: 16, color: "263238", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Saira", size: 10, color: "455A64", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "E65100"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Saira', sans-serif;
|
||||
h1 { font-family: 'Saira Stencil One', sans-serif; font-size: 36pt; color: #E65100; margin-bottom: 24px; }
|
||||
h2 { font-size: 16pt; font-weight: 600; color: #263238; margin-top: 32px; margin-bottom: 16px; text-transform: uppercase; }
|
||||
p { font-size: 10pt; line-height: 1.5; color: #455A64; margin-bottom: 14px; }
|
||||
blockquote { background: #FFF3E0; padding: 16px; border-left: 8px solid #263238; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'public-transit',
|
||||
name: 'Public Transit',
|
||||
category: 'Urban',
|
||||
description: 'Subway map and transit signage aesthetic. Clean, highly legible sans-serifs with color-coded lines.',
|
||||
vibe: 'Urban, Functional, Color-coded',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Mukta:wght@400;700&family=Hanken+Grotesk:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Hanken Grotesk", size: 32, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: { bottom: { color: "FFC107", space: 8, style: "single", size: 24 } }
|
||||
},
|
||||
heading2: {
|
||||
font: "Mukta", size: 18, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
shading: { fill: "EEEEEE", color: "auto", style: "clear" }
|
||||
},
|
||||
body: {
|
||||
font: "Mukta", size: 11, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "FFC107"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Mukta', sans-serif;
|
||||
h1 { font-family: 'Hanken Grotesk', sans-serif; font-size: 32pt; font-weight: 700; color: #000000; border-bottom: 6px solid #FFC107; padding-bottom: 12px; margin-bottom: 24px; }
|
||||
h2 { font-size: 18pt; font-weight: 700; color: #000000; background: #EEEEEE; padding: 4px 12px; margin-top: 32px; margin-bottom: 16px; display: inline-block; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #212121; margin-bottom: 14px; }
|
||||
blockquote { border-left: 6px solid #F44336; padding-left: 16px; margin: 24px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'industrial-safety',
|
||||
name: 'Industrial Safety',
|
||||
category: 'Industrial',
|
||||
description: 'Construction site signage. Heavy blacks and yellow caution stripes.',
|
||||
vibe: 'Safety, Bold, Construction',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Anton&family=Roboto:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Anton", size: 48, color: "000000", bold: false, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "FFD600", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Roboto", size: 16, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
border: { bottom: { color: "000000", space: 4, style: "thick", size: 24 } },
|
||||
allCaps: true
|
||||
},
|
||||
body: {
|
||||
font: "Roboto", size: 11, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "FFD600"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Roboto', sans-serif;
|
||||
h1 { font-family: 'Anton', sans-serif; font-size: 48pt; color: #000000; background: repeating-linear-gradient(45deg, #FFD600, #FFD600 10px, #FFC400 10px, #FFC400 20px); text-align: center; padding: 20px; margin-bottom: 24px; text-transform: uppercase; border: 4px solid #000; }
|
||||
h2 { font-size: 16pt; font-weight: 700; color: #000000; margin-top: 32px; margin-bottom: 16px; border-bottom: 4px solid #000; text-transform: uppercase; }
|
||||
p { font-size: 11pt; line-height: 1.5; color: #212121; margin-bottom: 14px; }
|
||||
blockquote { border: 2px solid #000; background: #FFF9C4; padding: 16px; margin: 24px 0; font-weight: 700; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'highway-interstate',
|
||||
name: 'Highway Interstate',
|
||||
category: 'Urban',
|
||||
description: 'Road signage aesthetic. Reflective white text on deep highway green backgrounds.',
|
||||
vibe: 'Functional, Travel, Signage',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Overpass:wght@400;700&family=Public+Sans:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Overpass", size: 36, color: "FFFFFF", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "00695C", color: "auto", style: "clear" },
|
||||
border: {
|
||||
bottom: { color: "FFFFFF", space: 4, style: "single", size: 12 },
|
||||
top: { color: "FFFFFF", space: 4, style: "single", size: 12 }
|
||||
}
|
||||
},
|
||||
heading2: {
|
||||
font: "Public Sans", size: 18, color: "004D40", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Public Sans", size: 11, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "00695C"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Public Sans', sans-serif;
|
||||
h1 { font-family: 'Overpass', sans-serif; font-size: 36pt; font-weight: 700; color: #FFFFFF; background: #00695C; padding: 16px; border-top: 2px solid #FFF; border-bottom: 2px solid #FFF; margin-bottom: 24px; border-radius: 8px; }
|
||||
h2 { font-size: 18pt; font-weight: 700; color: #004D40; margin-top: 32px; margin-bottom: 16px; text-transform: uppercase; }
|
||||
p { font-size: 11pt; line-height: 1.5; color: #212121; margin-bottom: 14px; }
|
||||
blockquote { background: #FFEB3B; color: #000; padding: 16px; margin: 24px 0; border: 4px solid #000; transform: skewX(-10deg); width: fit-content; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'furniture-manual',
|
||||
name: 'Furniture Manual',
|
||||
category: 'Instructional',
|
||||
description: 'Flat-pack assembly guide. Clean, heavy line art vibes with friendly sans-serifs.',
|
||||
vibe: 'Clean, Instructional, Neutral',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Varela+Round&family=Hind:wght@300;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Varela Round", size: 32, color: "000000", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Varela Round", size: 16, color: "000000", bold: false, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
border: {
|
||||
bottom: { color: "000000", space: 4, style: "single", size: 12 },
|
||||
left: { color: "000000", space: 4, style: "single", size: 12 }
|
||||
},
|
||||
shading: { fill: "F5F5F5", color: "auto", style: "clear" }
|
||||
},
|
||||
body: {
|
||||
font: "Hind", size: 11, color: "424242", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Hind', sans-serif;
|
||||
h1 { font-family: 'Varela Round', sans-serif; font-size: 32pt; color: #000000; margin-bottom: 24px; }
|
||||
h2 { font-family: 'Varela Round', sans-serif; font-size: 16pt; color: #000000; background: #F5F5F5; padding: 8px; border-left: 4px solid #000; border-bottom: 2px solid #000; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #424242; margin-bottom: 14px; }
|
||||
blockquote { border: 2px solid #000; padding: 20px; margin: 24px 0; border-radius: 50%; width: 50px; height: 50px; line-height: 50px; text-align: center; font-weight: 700; font-size: 24pt; display: inline-block; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'night-vision',
|
||||
name: 'Night Vision',
|
||||
category: 'Tactical',
|
||||
description: 'Military optics style. Grainy bright greens on dark green background.',
|
||||
vibe: 'Tactical, Green, Grainy',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Wallpoet&family=Roboto+Mono:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Wallpoet", size: 32, color: "76FF03", bold: false, align: 'center',
|
||||
spacing: { before: 400, after: 240, line: 240 },
|
||||
shading: { fill: "1B5E20", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Roboto Mono", size: 16, color: "CCFF90", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
border: { bottom: { color: "76FF03", space: 4, style: "dotted", size: 12 } }
|
||||
},
|
||||
body: {
|
||||
font: "Roboto Mono", size: 10, color: "B2FF59", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 },
|
||||
shading: { fill: "000000", color: "auto", style: "clear" }
|
||||
},
|
||||
accentColor: "76FF03"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Roboto Mono', monospace;
|
||||
background: #000000;
|
||||
h1 { font-family: 'Wallpoet', cursive; font-size: 32pt; color: #76FF03; background: #1B5E20; padding: 16px; text-align: center; margin-bottom: 24px; text-shadow: 0 0 10px #76FF03; }
|
||||
h2 { font-size: 16pt; font-weight: 700; color: #CCFF90; margin-top: 32px; margin-bottom: 16px; border-bottom: 2px dotted #76FF03; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #B2FF59; margin-bottom: 14px; }
|
||||
blockquote { border-left: 4px solid #76FF03; padding-left: 16px; margin: 24px 0; color: #64DD17; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'fire-station',
|
||||
name: 'Fire Station',
|
||||
category: 'Service',
|
||||
description: 'Engine company aesthetic. Fire engine red, brass gold, and bold gothic numbers.',
|
||||
vibe: 'Brave, Red, Gold',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Anton&family=Rokkitt:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Anton", size: 40, color: "B71C1C", bold: false, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: {
|
||||
top: { color: "FFD600", space: 6, style: "thick", size: 24 },
|
||||
bottom: { color: "FFD600", space: 6, style: "thick", size: 24 }
|
||||
}
|
||||
},
|
||||
heading2: {
|
||||
font: "Rokkitt", size: 18, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Rokkitt", size: 12, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "B71C1C"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Rokkitt', serif;
|
||||
h1 { font-family: 'Anton', sans-serif; font-size: 40pt; color: #B71C1C; text-align: center; border-top: 6px solid #FFD600; border-bottom: 6px solid #FFD600; padding: 16px 0; margin-bottom: 24px; text-transform: uppercase; }
|
||||
h2 { font-size: 18pt; font-weight: 700; color: #000000; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 12pt; line-height: 1.5; color: #212121; margin-bottom: 14px; }
|
||||
blockquote { background: #FFEBEE; border: 2px solid #B71C1C; padding: 16px; margin: 24px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'taxi-cab',
|
||||
name: 'Taxi Cab',
|
||||
category: 'Urban',
|
||||
description: 'Yellow cab aesthetic. Checkerboard patterns (simulated) and bold black on yellow.',
|
||||
vibe: 'Urban, Yellow, Bold',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Archivo+Black&family=Roboto:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Archivo Black", size: 36, color: "000000", bold: false, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "FFEB3B", color: "auto", style: "clear" },
|
||||
border: {
|
||||
top: { color: "000000", space: 4, style: "dashed", size: 24 }, // Simulates checkers
|
||||
bottom: { color: "000000", space: 4, style: "dashed", size: 24 }
|
||||
}
|
||||
},
|
||||
heading2: {
|
||||
font: "Roboto", size: 18, color: "000000", bold: true, align: 'center',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
shading: { fill: "FFFFFF", color: "auto", style: "clear" }
|
||||
},
|
||||
body: {
|
||||
font: "Roboto", size: 12, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "FFEB3B"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Roboto', sans-serif;
|
||||
background: #212121;
|
||||
padding: 20px;
|
||||
h1 { font-family: 'Archivo Black', sans-serif; font-size: 36pt; color: #000000; background: #FFEB3B; padding: 16px; margin-bottom: 24px; text-align: center; border-top: 6px dashed #000; border-bottom: 6px dashed #000; }
|
||||
h2 { font-size: 18pt; font-weight: 700; color: #000000; background: #FFFFFF; padding: 8px; margin-top: 32px; margin-bottom: 16px; text-align: center; display: inline-block; }
|
||||
p { font-size: 12pt; line-height: 1.5; color: #FFFFFF; margin-bottom: 14px; }
|
||||
blockquote { background: #FFEB3B; color: #000; padding: 16px; margin: 24px 0; font-weight: 700; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'subway-tile',
|
||||
name: 'Subway Tile',
|
||||
category: 'Urban',
|
||||
description: 'Classic station ceramics. Clean white backgrounds, heavy black text, and tile-like framing.',
|
||||
vibe: 'Clean, Ceramic, Urban',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Work+Sans:wght@300;600&family=Lexend:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Lexend", size: 36, color: "000000", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: {
|
||||
top: { color: "000000", space: 12, style: "single", size: 4 },
|
||||
bottom: { color: "000000", space: 12, style: "single", size: 4 },
|
||||
left: { color: "000000", space: 12, style: "single", size: 4 },
|
||||
right: { color: "000000", space: 12, style: "single", size: 4 }
|
||||
}
|
||||
},
|
||||
heading2: {
|
||||
font: "Work Sans", size: 16, color: "212121", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Work Sans", size: 11, color: "424242", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Work Sans', sans-serif;
|
||||
h1 { font-family: 'Lexend', sans-serif; font-size: 36pt; font-weight: 700; color: #000000; border: 4px solid #000000; padding: 16px; margin-bottom: 24px; text-align: center; background: #FFFFFF; }
|
||||
h2 { font-size: 16pt; font-weight: 700; color: #212121; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #424242; margin-bottom: 14px; }
|
||||
blockquote { border-left: 8px solid #000; padding-left: 16px; margin: 24px 0; background: #F5F5F5; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'german-autobahn',
|
||||
name: 'German Autobahn',
|
||||
category: 'Transport',
|
||||
description: 'Precision engineering aesthetic. DIN-style fonts and strict blue/white signage.',
|
||||
vibe: 'German, Precision, Transport',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Barlow:wght@400;700&family=Roboto+Condensed:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Barlow", size: 36, color: "FFFFFF", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "1565C0", color: "auto", style: "clear" } // Autobahn Blue
|
||||
},
|
||||
heading2: {
|
||||
font: "Roboto Condensed", size: 18, color: "0D47A1", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
allCaps: true
|
||||
},
|
||||
body: {
|
||||
font: "Roboto Condensed", size: 11, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "1565C0"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Roboto Condensed', sans-serif;
|
||||
h1 { font-family: 'Barlow', sans-serif; font-size: 36pt; font-weight: 700; color: #FFFFFF; background: #1565C0; padding: 12px 20px; margin-bottom: 24px; border-radius: 4px; }
|
||||
h2 { font-size: 18pt; font-weight: 700; color: #0D47A1; margin-top: 32px; margin-bottom: 16px; text-transform: uppercase; }
|
||||
p { font-size: 11pt; line-height: 1.5; color: #212121; margin-bottom: 14px; }
|
||||
blockquote { border-left: 6px solid #1565C0; padding-left: 16px; margin: 24px 0; background: #E3F2FD; }
|
||||
`
|
||||
}
|
||||
];
|
||||
@@ -1,768 +0,0 @@
|
||||
import { StyleOption } from '../types';
|
||||
|
||||
export const lifestyleStyles: StyleOption[] = [
|
||||
{
|
||||
id: 'food-recipe',
|
||||
name: 'Food & Recipe',
|
||||
category: 'Lifestyle',
|
||||
description: 'Warm and appetizing design for cookbooks and food content. Inviting typography with rustic charm.',
|
||||
vibe: 'Warm, Appetizing, Homestyle',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;600;700&family=Lato:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Playfair Display", size: 32, color: "6D4C41", bold: false, align: 'center',
|
||||
spacing: { before: 400, after: 240, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Playfair Display", size: 16, color: "8D6E63", bold: false, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Lato", size: 10, color: "4E342E", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "D84315"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Lato', sans-serif;
|
||||
h1 { font-family: 'Playfair Display', serif; font-size: 32pt; font-weight: 600; color: #6D4C41; text-align: center; margin-bottom: 28px; }
|
||||
h2 { font-family: 'Playfair Display', serif; font-size: 16pt; color: #8D6E63; margin-top: 32px; margin-bottom: 16px; font-style: italic; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #4E342E; margin-bottom: 14px; }
|
||||
blockquote { background: #FFF3E0; padding: 16px; border-left: 4px solid #D84315; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'wedding-elegant',
|
||||
name: 'Wedding Elegant',
|
||||
category: 'Events',
|
||||
description: 'Romantic and elegant design for wedding stationery and formal events. Delicate typography with sophisticated flourishes.',
|
||||
vibe: 'Romantic, Elegant, Celebratory',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Tangerine:wght@400;700&family=Cormorant+Garamond:wght@300;400;500&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Tangerine", size: 48, color: "5D4037", bold: true, align: 'center',
|
||||
spacing: { before: 480, after: 280, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Cormorant Garamond", size: 14, color: "795548", bold: false, align: 'center',
|
||||
spacing: { before: 360, after: 180, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Cormorant Garamond", size: 11, color: "5D4037", align: 'center',
|
||||
spacing: { before: 0, after: 180, line: 300 }
|
||||
},
|
||||
accentColor: "D4AF37"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Cormorant Garamond', serif;
|
||||
h1 { font-family: 'Tangerine', cursive; font-size: 48pt; font-weight: 700; color: #5D4037; text-align: center; margin-bottom: 32px; }
|
||||
h2 { font-size: 14pt; font-weight: 500; color: #795548; text-align: center; margin-top: 36px; margin-bottom: 18px; letter-spacing: 3px; text-transform: uppercase; }
|
||||
p { font-size: 11pt; line-height: 1.7; color: #5D4037; margin-bottom: 16px; text-align: center; font-weight: 300; }
|
||||
blockquote { border-top: 1px solid #D4AF37; border-bottom: 1px solid #D4AF37; padding: 24px 40px; margin: 32px 0; text-align: center; font-style: italic; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'sports-dynamic',
|
||||
name: 'Sports Dynamic',
|
||||
category: 'Sports',
|
||||
description: 'Energetic and bold design for sports and athletic content. Dynamic typography with high-impact colors.',
|
||||
vibe: 'Energetic, Bold, Athletic',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Bebas+Neue&family=Rubik:wght@400;500;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Bebas Neue", size: 36, color: "D32F2F", bold: false, align: 'left',
|
||||
spacing: { before: 360, after: 200, line: 220 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Rubik", size: 14, color: "1A1A1A", bold: true, align: 'left',
|
||||
spacing: { before: 280, after: 140, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Rubik", size: 10, color: "333333", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "D32F2F"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Rubik', sans-serif;
|
||||
h1 { font-family: 'Bebas Neue', sans-serif; font-size: 36pt; color: #D32F2F; margin-bottom: 24px; letter-spacing: 2px; text-transform: uppercase; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #1A1A1A; margin-top: 28px; margin-bottom: 14px; text-transform: uppercase; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #333333; margin-bottom: 14px; }
|
||||
blockquote { background: #FFEBEE; padding: 16px; border-left: 6px solid #D32F2F; margin: 20px 0; font-weight: 500; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'childrens-playful',
|
||||
name: 'Children\'s Playful',
|
||||
category: 'Children',
|
||||
description: 'Fun and engaging design for children\'s content. Rounded typography with bright, cheerful colors.',
|
||||
vibe: 'Playful, Friendly, Colorful',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Baloo+2:wght@400;600;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Baloo 2", size: 32, color: "6A1B9A", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 240, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Baloo 2", size: 18, color: "00897B", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Baloo 2", size: 11, color: "37474F", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 300 }
|
||||
},
|
||||
accentColor: "FF6B6B"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Baloo 2', cursive;
|
||||
h1 { font-size: 32pt; font-weight: 700; color: #6A1B9A; text-align: center; margin-bottom: 28px; }
|
||||
h2 { font-size: 18pt; font-weight: 700; color: #00897B; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 11pt; line-height: 1.7; color: #37474F; margin-bottom: 14px; }
|
||||
blockquote { background: #FFF3E0; padding: 16px; border-radius: 16px; border-left: 6px solid #FF6F00; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'travel-adventure',
|
||||
name: 'Travel Adventure',
|
||||
category: 'Travel',
|
||||
description: 'Adventurous design for travel and exploration content. Bold typography with earthy, wanderlust-inspiring colors.',
|
||||
vibe: 'Adventurous, Inspiring, Explorer',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Amatic+SC:wght@400;700&family=Josefin+Sans:wght@400;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Amatic SC", size: 48, color: "3E2723", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 240, line: 220 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Josefin Sans", size: 14, color: "5D4037", bold: true, align: 'left',
|
||||
spacing: { before: 300, after: 150, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Josefin Sans", size: 10, color: "4E342E", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "FF7043"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Josefin Sans', sans-serif;
|
||||
h1 { font-family: 'Amatic SC', cursive; font-size: 48pt; font-weight: 700; color: #3E2723; text-align: center; margin-bottom: 28px; letter-spacing: 4px; }
|
||||
h2 { font-size: 14pt; font-weight: 600; color: #5D4037; margin-top: 30px; margin-bottom: 14px; text-transform: uppercase; letter-spacing: 2px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #4E342E; margin-bottom: 14px; }
|
||||
blockquote { background: #FBE9E7; padding: 16px; border-left: 4px solid #FF7043; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'hotel-hospitality',
|
||||
name: 'Hotel Hospitality',
|
||||
category: 'Hospitality',
|
||||
description: 'Welcoming design for hotels and hospitality industry. Elegant yet approachable with warm sophistication.',
|
||||
vibe: 'Welcoming, Elegant, Warm',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Tenor+Sans&family=Nunito+Sans:wght@300;400;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Tenor Sans", size: 28, color: "2C3E50", bold: false, align: 'center',
|
||||
spacing: { before: 400, after: 240, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Tenor Sans", size: 14, color: "8B7355", bold: false, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Nunito Sans", size: 10, color: "4A4A4A", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "8B7355"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Nunito Sans', sans-serif;
|
||||
h1 { font-family: 'Tenor Sans', sans-serif; font-size: 28pt; color: #2C3E50; text-align: center; margin-bottom: 28px; letter-spacing: 2px; }
|
||||
h2 { font-family: 'Tenor Sans', sans-serif; font-size: 14pt; color: #8B7355; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #4A4A4A; margin-bottom: 14px; font-weight: 300; }
|
||||
blockquote { background: #F9F6F1; padding: 20px; border-left: 4px solid #8B7355; margin: 24px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'spa-wellness',
|
||||
name: 'Spa Wellness',
|
||||
category: 'Wellness',
|
||||
description: 'Serene design for spa and wellness industries. Calm typography with soothing, natural colors.',
|
||||
vibe: 'Serene, Calming, Natural',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Philosopher:wght@400;700&family=Questrial&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Philosopher", size: 28, color: "4A6741", bold: false, align: 'center',
|
||||
spacing: { before: 480, after: 280, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Philosopher", size: 14, color: "6B8E63", bold: false, align: 'left',
|
||||
spacing: { before: 360, after: 180, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Questrial", size: 10, color: "5D6D5A", align: 'left',
|
||||
spacing: { before: 0, after: 180, line: 300 }
|
||||
},
|
||||
accentColor: "6B8E63"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Questrial', sans-serif;
|
||||
h1 { font-family: 'Philosopher', serif; font-size: 28pt; color: #4A6741; text-align: center; margin-bottom: 32px; }
|
||||
h2 { font-family: 'Philosopher', serif; font-size: 14pt; color: #6B8E63; margin-top: 36px; margin-bottom: 18px; }
|
||||
p { font-size: 10pt; line-height: 1.7; color: #5D6D5A; margin-bottom: 16px; }
|
||||
blockquote { background: #F1F8E9; padding: 20px; border-radius: 4px; margin: 28px 0; text-align: center; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'parisian-chic',
|
||||
name: 'Parisian Chic',
|
||||
category: 'Fashion',
|
||||
description: 'Sophisticated French aesthetics. Elegant high-contrast serifs with plenty of white space.',
|
||||
vibe: 'Sophisticated, Chic, Minimal',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Bodoni+Moda:ital,opsz,wght@0,6..96,400;0,6..96,700;1,6..96,400&family=Jost:wght@300;400&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Bodoni Moda", size: 36, color: "000000", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 240, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Bodoni Moda", size: 16, color: "333333", bold: true, align: 'center',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
italic: true
|
||||
},
|
||||
body: {
|
||||
font: "Jost", size: 10, color: "1A1A1A", align: 'center',
|
||||
spacing: { before: 0, after: 160, line: 300 }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Jost', sans-serif;
|
||||
h1 { font-family: 'Bodoni Moda', serif; font-size: 36pt; font-weight: 700; color: #000000; text-align: center; margin-bottom: 32px; }
|
||||
h2 { font-family: 'Bodoni Moda', serif; font-size: 16pt; font-weight: 700; color: #333333; text-align: center; margin-top: 36px; margin-bottom: 18px; font-style: italic; }
|
||||
p { font-size: 10pt; line-height: 1.8; color: #1A1A1A; margin-bottom: 16px; text-align: center; font-weight: 300; }
|
||||
blockquote { border-top: 1px solid #000000; border-bottom: 1px solid #000000; padding: 24px; margin: 32px 40px; text-align: center; font-family: 'Bodoni Moda', serif; font-style: italic; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'fine-dining-menu',
|
||||
name: 'Fine Dining Menu',
|
||||
category: 'Hospitality',
|
||||
description: 'High-end restaurant aesthetic. Elegant scripts, centered layouts, and luxurious gold tones.',
|
||||
vibe: 'Elegant, Expensive, Centered',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Great+Vibes&family=Cormorant+Garamond:wght@400;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Great Vibes", size: 42, color: "C5A059", bold: false, align: 'center',
|
||||
spacing: { before: 500, after: 300, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Cormorant Garamond", size: 14, color: "212121", bold: true, align: 'center',
|
||||
spacing: { before: 360, after: 180, line: 240 },
|
||||
allCaps: true
|
||||
},
|
||||
body: {
|
||||
font: "Cormorant Garamond", size: 12, color: "424242", align: 'center',
|
||||
spacing: { before: 0, after: 180, line: 300 }
|
||||
},
|
||||
accentColor: "C5A059"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Cormorant Garamond', serif;
|
||||
background: #FFFAF0;
|
||||
h1 { font-family: 'Great Vibes', cursive; font-size: 42pt; color: #C5A059; text-align: center; margin-bottom: 30px; }
|
||||
h2 { font-size: 14pt; font-weight: 600; color: #212121; text-align: center; margin-top: 36px; margin-bottom: 18px; text-transform: uppercase; letter-spacing: 3px; border-bottom: 1px solid #C5A059; display: inline-block; padding-bottom: 5px; }
|
||||
p { font-size: 12pt; line-height: 1.8; color: #424242; margin-bottom: 16px; text-align: center; font-style: italic; }
|
||||
blockquote { border: 1px solid #C5A059; padding: 24px; margin: 30px 60px; text-align: center; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'cottagecore-journal',
|
||||
name: 'Cottagecore Journal',
|
||||
category: 'Aesthetic',
|
||||
description: 'Whimsical countryside diary. Handwritten fonts with soft sage greens and earthy browns.',
|
||||
vibe: 'Whimsical, Nature, Handmade',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Amatic+SC:wght@400;700&family=Patrick+Hand&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Amatic SC", size: 40, color: "33691E", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Patrick Hand", size: 18, color: "5D4037", bold: true, align: 'center',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Patrick Hand", size: 14, color: "424242", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "33691E"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Patrick Hand', cursive;
|
||||
background: #F1F8E9;
|
||||
h1 { font-family: 'Amatic SC', cursive; font-size: 40pt; font-weight: 700; color: #33691E; text-align: center; margin-bottom: 24px; }
|
||||
h2 { font-size: 18pt; font-weight: 700; color: #5D4037; text-align: center; margin-top: 30px; margin-bottom: 14px; border-bottom: 1px dashed #8D6E63; display: inline-block; }
|
||||
p { font-size: 14pt; line-height: 1.6; color: #424242; margin-bottom: 14px; }
|
||||
blockquote { background: #FFF; border: 1px dotted #33691E; padding: 20px; border-radius: 10px; margin: 24px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'hipster-coffee',
|
||||
name: 'Hipster Coffee',
|
||||
category: 'Modern',
|
||||
description: 'Artisan roaster branding. Clean slab serifs on kraft paper textures.',
|
||||
vibe: 'Artisan, Slab, Kraft',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Zilla+Slab:wght@400;700&family=Lato:wght@300;400&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Zilla Slab", size: 36, color: "3E2723", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Lato", size: 14, color: "000000", bold: true, align: 'center',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
allCaps: true,
|
||||
tracking: 100
|
||||
},
|
||||
body: {
|
||||
font: "Lato", size: 10, color: "4E342E", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "3E2723"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Lato', sans-serif;
|
||||
background: #E0C097;
|
||||
h1 { font-family: 'Zilla Slab', serif; font-size: 36pt; font-weight: 700; color: #3E2723; text-align: center; margin-bottom: 24px; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #000000; text-align: center; margin-top: 32px; margin-bottom: 16px; text-transform: uppercase; letter-spacing: 2px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #4E342E; margin-bottom: 14px; }
|
||||
blockquote { border-top: 1px solid #3E2723; border-bottom: 1px solid #3E2723; padding: 20px; margin: 24px 0; text-align: center; font-style: italic; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'kindergarten-art',
|
||||
name: 'Kindergarten Art',
|
||||
category: 'Playful',
|
||||
description: 'Child-like crayon aesthetic. Primary colors, rounded fonts, and large friendly text.',
|
||||
vibe: 'Childish, Fun, Primary',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Chewy&family=Balsamiq+Sans:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Chewy", size: 40, color: "2962FF", bold: false, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Balsamiq Sans", size: 18, color: "D50000", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Balsamiq Sans", size: 14, color: "111111", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 320 }
|
||||
},
|
||||
accentColor: "FFD600"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Balsamiq Sans', cursive;
|
||||
h1 { font-family: 'Chewy', cursive; font-size: 40pt; color: #2962FF; text-align: center; margin-bottom: 24px; transform: rotate(-2deg); }
|
||||
h2 { font-size: 18pt; font-weight: 700; color: #D50000; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 14pt; line-height: 1.6; color: #111111; margin-bottom: 14px; }
|
||||
blockquote { border: 4px dashed #FFD600; padding: 20px; margin: 24px 0; border-radius: 20px; background: #FFFDE7; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'surf-shop',
|
||||
name: 'Surf Shop',
|
||||
category: 'Lifestyle',
|
||||
description: 'California cool. Relaxed hand-drawn fonts with sea foam blues and sunny yellows.',
|
||||
vibe: 'Relaxed, Beach, Sunny',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Permanent+Marker&family=Kalam:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Permanent Marker", size: 36, color: "0097A7", bold: false, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Kalam", size: 18, color: "FBC02D", bold: true, align: 'center',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Kalam", size: 12, color: "424242", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "0097A7"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Kalam', cursive;
|
||||
h1 { font-family: 'Permanent Marker', cursive; font-size: 36pt; color: #0097A7; text-align: center; margin-bottom: 24px; transform: rotate(-1deg); }
|
||||
h2 { font-size: 18pt; font-weight: 700; color: #FBC02D; text-align: center; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 12pt; line-height: 1.6; color: #424242; margin-bottom: 14px; }
|
||||
blockquote { background: #E0F7FA; border-radius: 16px; padding: 20px; margin: 24px 0; border: 2px solid #0097A7; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'winter-holiday',
|
||||
name: 'Winter Holiday',
|
||||
category: 'Seasonal',
|
||||
description: 'Festive greeting card style. Elegant script, deep reds and forest greens.',
|
||||
vibe: 'Festive, Cozy, Traditional',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Mountains+of+Christmas:wght@400;700&family=Merriweather:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Mountains of Christmas", size: 36, color: "B71C1C", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 240, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Merriweather", size: 16, color: "1B5E20", bold: true, align: 'center',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Merriweather", size: 11, color: "212121", align: 'center',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "B71C1C"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Merriweather', serif;
|
||||
background: #FFEBEE;
|
||||
h1 { font-family: 'Mountains of Christmas', cursive; font-size: 36pt; font-weight: 700; color: #B71C1C; text-align: center; margin-bottom: 24px; }
|
||||
h2 { font-size: 16pt; font-weight: 700; color: #1B5E20; text-align: center; margin-top: 32px; margin-bottom: 16px; border-bottom: 2px dotted #1B5E20; display: inline-block; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #212121; margin-bottom: 14px; text-align: center; }
|
||||
blockquote { border: 2px solid #B71C1C; padding: 16px; margin: 24px 0; border-radius: 8px; background: #FFF; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'recipe-card',
|
||||
name: 'Recipe Card',
|
||||
category: 'Home',
|
||||
description: 'Grandmas index card. Typewriter fonts with red header lines.',
|
||||
vibe: 'Homey, Traditional, Cookery',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Courier+Prime&family=Homemade+Apple&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Courier Prime", size: 24, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 360, after: 200, line: 240 },
|
||||
border: { bottom: { color: "F44336", space: 4, style: "single", size: 12 } }
|
||||
},
|
||||
heading2: {
|
||||
font: "Courier Prime", size: 14, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 280, after: 140, line: 240 },
|
||||
allCaps: true
|
||||
},
|
||||
body: {
|
||||
font: "Courier Prime", size: 11, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "F44336"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Courier Prime', monospace;
|
||||
background: #FFF;
|
||||
border: 1px solid #E0E0E0;
|
||||
padding: 20px;
|
||||
h1 { font-size: 24pt; font-weight: 700; color: #000000; border-bottom: 2px solid #F44336; padding-bottom: 8px; margin-bottom: 20px; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #000000; margin-top: 24px; margin-bottom: 12px; text-transform: uppercase; }
|
||||
p { font-size: 11pt; line-height: 1.5; color: #212121; margin-bottom: 12px; }
|
||||
blockquote { font-family: 'Homemade Apple', cursive; color: #D32F2F; font-size: 14pt; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'national-park-signage',
|
||||
name: 'National Park Signage',
|
||||
category: 'Nature',
|
||||
description: 'Routed wood sign aesthetic. Heavy rounded serifs with earthy brown and cream colors.',
|
||||
vibe: 'Outdoors, Rustic, Official',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Crete+Round:ital@0;1&family=Lato:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Crete Round", size: 32, color: "FFFFFF", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "3E2723", color: "auto", style: "clear" } // Dark brown background
|
||||
},
|
||||
heading2: {
|
||||
font: "Lato", size: 16, color: "3E2723", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
allCaps: true
|
||||
},
|
||||
body: {
|
||||
font: "Lato", size: 11, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "3E2723"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Lato', sans-serif;
|
||||
h1 { font-family: 'Crete Round', serif; font-size: 32pt; color: #FFFFFF; background: #3E2723; padding: 16px; margin-bottom: 24px; border-radius: 8px; border: 2px solid #5D4037; }
|
||||
h2 { font-size: 16pt; font-weight: 700; color: #3E2723; margin-top: 32px; margin-bottom: 16px; text-transform: uppercase; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #212121; margin-bottom: 14px; }
|
||||
blockquote { background: #EFEBE9; border-left: 6px solid #3E2723; padding: 16px; margin: 24px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'supermarket-receipt',
|
||||
name: 'Supermarket Receipt',
|
||||
category: 'Everyday',
|
||||
description: 'Thermal paper aesthetic. Monospaced, slightly faded grey text with narrow alignment.',
|
||||
vibe: 'Disposable, Monospace, Grey',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Fira+Mono&family=Inconsolata:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Fira Mono", size: 24, color: "000000", bold: true, align: 'center',
|
||||
spacing: { before: 300, after: 200, line: 240 },
|
||||
allCaps: true
|
||||
},
|
||||
heading2: {
|
||||
font: "Inconsolata", size: 14, color: "000000", bold: false, align: 'center',
|
||||
spacing: { before: 240, after: 120, line: 240 },
|
||||
border: { bottom: { color: "000000", space: 4, style: "dashed", size: 12 } }
|
||||
},
|
||||
body: {
|
||||
font: "Inconsolata", size: 11, color: "424242", align: 'left', // Dark grey for thermal look
|
||||
spacing: { before: 0, after: 120, line: 240 }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Inconsolata', monospace;
|
||||
background: #FAFAFA;
|
||||
padding: 20px;
|
||||
width: 400px;
|
||||
margin: 0 auto;
|
||||
box-shadow: 0 0 10px rgba(0,0,0,0.1);
|
||||
h1 { font-family: 'Fira Mono', monospace; font-size: 24pt; font-weight: 700; color: #000000; text-align: center; margin-bottom: 20px; text-transform: uppercase; }
|
||||
h2 { font-size: 14pt; font-weight: 400; color: #000000; text-align: center; margin-top: 24px; margin-bottom: 12px; border-bottom: 1px dashed #000; padding-bottom: 5px; }
|
||||
p { font-size: 11pt; line-height: 1.4; color: #424242; margin-bottom: 10px; }
|
||||
blockquote { text-align: center; margin: 20px 0; font-weight: 700; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'varsity-team',
|
||||
name: 'Varsity Team',
|
||||
category: 'Sport',
|
||||
description: 'College sports jersey style. Block lettering with athletic gold and navy.',
|
||||
vibe: 'Athletic, College, Bold',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Graduate&family=Saira:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Graduate", size: 36, color: "FDD835", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 240, line: 240 },
|
||||
shading: { fill: "1A237E", color: "auto", style: "clear" },
|
||||
border: {
|
||||
top: { color: "FDD835", space: 8, style: "single", size: 24 },
|
||||
bottom: { color: "FDD835", space: 8, style: "single", size: 24 }
|
||||
}
|
||||
},
|
||||
heading2: {
|
||||
font: "Saira", size: 20, color: "1A237E", bold: true, align: 'center',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
allCaps: true
|
||||
},
|
||||
body: {
|
||||
font: "Saira", size: 12, color: "212121", align: 'center',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "FDD835"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Saira', sans-serif;
|
||||
h1 { font-family: 'Graduate', serif; font-size: 36pt; color: #FDD835; background: #1A237E; border-top: 4px solid #FDD835; border-bottom: 4px solid #FDD835; padding: 20px; text-align: center; margin-bottom: 24px; }
|
||||
h2 { font-size: 20pt; font-weight: 700; color: #1A237E; text-align: center; margin-top: 32px; margin-bottom: 16px; text-transform: uppercase; }
|
||||
p { font-size: 12pt; line-height: 1.5; color: #212121; margin-bottom: 14px; text-align: center; }
|
||||
blockquote { border: 2px dashed #1A237E; padding: 16px; margin: 24px 0; background: #E8EAF6; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'sticky-note',
|
||||
name: 'Sticky Note',
|
||||
category: 'Casual',
|
||||
description: 'Handwritten reminder aesthetic. Marker fonts on a canary yellow background.',
|
||||
vibe: 'Casual, Handwritten, Yellow',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Permanent+Marker&family=Kalam:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Permanent Marker", size: 32, color: "000000", bold: false, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Kalam", size: 18, color: "D50000", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Kalam", size: 14, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 },
|
||||
shading: { fill: "FFF9C4", color: "auto", style: "clear" } // Yellow paper
|
||||
},
|
||||
accentColor: "D50000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Kalam', cursive;
|
||||
background: #FFF9C4;
|
||||
padding: 30px;
|
||||
box-shadow: 2px 2px 5px rgba(0,0,0,0.1);
|
||||
h1 { font-family: 'Permanent Marker', cursive; font-size: 32pt; color: #000000; text-align: center; margin-bottom: 24px; transform: rotate(-1deg); }
|
||||
h2 { font-size: 18pt; font-weight: 700; color: #D50000; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 14pt; line-height: 1.5; color: #212121; margin-bottom: 14px; }
|
||||
blockquote { border-left: 4px solid #D50000; padding-left: 12px; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'brick-toy',
|
||||
name: 'Brick Toy',
|
||||
category: 'Playful',
|
||||
description: 'Plastic building block aesthetic. Primary red, blue, and yellow with chunky text.',
|
||||
vibe: 'Playful, Primary, Chunky',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Titan+One&family=Nunito:wght@400;800&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Titan One", size: 36, color: "D32F2F", bold: false, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "FFEB3B", color: "auto", style: "clear" } // Yellow background
|
||||
},
|
||||
heading2: {
|
||||
font: "Nunito", size: 18, color: "FFFFFF", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
shading: { fill: "1976D2", color: "auto", style: "clear" } // Blue background
|
||||
},
|
||||
body: {
|
||||
font: "Nunito", size: 12, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "D32F2F"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Nunito', sans-serif;
|
||||
h1 { font-family: 'Titan One', cursive; font-size: 36pt; color: #D32F2F; background: #FFEB3B; padding: 16px; border-radius: 8px; text-align: center; margin-bottom: 24px; border: 4px solid #D32F2F; }
|
||||
h2 { font-size: 18pt; font-weight: 800; color: #FFFFFF; background: #1976D2; padding: 8px 16px; border-radius: 4px; display: inline-block; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 12pt; line-height: 1.6; color: #212121; margin-bottom: 14px; }
|
||||
blockquote { border: 4px dotted #D32F2F; padding: 16px; margin: 24px 0; background: #E3F2FD; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'jungle-explorer',
|
||||
name: 'Jungle Explorer',
|
||||
category: 'Adventure',
|
||||
description: 'Safari expedition style. Khaki, olive drab, and canvas textures.',
|
||||
vibe: 'Adventure, Khaki, Nature',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Stardos+Stencil&family=Domine:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Stardos Stencil", size: 36, color: "33691E", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: { bottom: { color: "827717", space: 6, style: "thick", size: 18 } }
|
||||
},
|
||||
heading2: {
|
||||
font: "Domine", size: 16, color: "558B2F", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Domine", size: 11, color: "1B1B1B", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "827717"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Domine', serif;
|
||||
background: #F0F4C3; /* Khaki tint */
|
||||
h1 { font-family: 'Stardos Stencil', cursive; font-size: 36pt; font-weight: 700; color: #33691E; border-bottom: 4px solid #827717; padding-bottom: 12px; margin-bottom: 24px; }
|
||||
h2 { font-size: 16pt; font-weight: 700; color: #558B2F; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #1B1B1B; margin-bottom: 14px; }
|
||||
blockquote { background: #DCEDC8; padding: 20px; border-left: 6px solid #33691E; margin: 24px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'volcanic-ash',
|
||||
name: 'Volcanic Ash',
|
||||
category: 'Nature',
|
||||
description: 'Geological extreme. Obsidian greys with magma orange cracks.',
|
||||
vibe: 'Dark, Hot, Geological',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Creepster&family=Merriweather+Sans:wght@400;800&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Merriweather Sans", size: 36, color: "FF3D00", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "212121", color: "auto", style: "clear" } // Obsidian
|
||||
},
|
||||
heading2: {
|
||||
font: "Merriweather Sans", size: 16, color: "424242", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
border: { bottom: { color: "FF3D00", space: 4, style: "single", size: 6 } }
|
||||
},
|
||||
body: {
|
||||
font: "Merriweather Sans", size: 11, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "FF3D00"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Merriweather Sans', sans-serif;
|
||||
background: #FAFAFA;
|
||||
h1 { font-size: 36pt; font-weight: 800; color: #FF3D00; background: #212121; padding: 16px; margin-bottom: 24px; border-bottom: 4px solid #DD2C00; }
|
||||
h2 { font-size: 16pt; font-weight: 800; color: #424242; margin-top: 32px; margin-bottom: 16px; border-bottom: 2px solid #FF3D00; display: inline-block; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #212121; margin-bottom: 14px; }
|
||||
blockquote { border-left: 8px solid #212121; padding-left: 16px; margin: 24px 0; background: #FFCCBC; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'desert-sands',
|
||||
name: 'Desert Sands',
|
||||
category: 'Nature',
|
||||
description: 'Dune aesthetic. Warm beige backgrounds with wind-swept, eroded typefaces.',
|
||||
vibe: 'Warm, Sandy, Soft',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Cinzel&family=Fauna+One&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Cinzel", size: 36, color: "5D4037", bold: false, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Fauna One", size: 16, color: "8D6E63", bold: true, align: 'center',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Fauna One", size: 11, color: "4E342E", align: 'center',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "8D6E63"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Fauna One', serif;
|
||||
background: #F3E5AB; /* Sand color */
|
||||
h1 { font-family: 'Cinzel', serif; font-size: 36pt; color: #5D4037; text-align: center; margin-bottom: 24px; letter-spacing: 2px; }
|
||||
h2 { font-size: 16pt; font-weight: 700; color: #8D6E63; text-align: center; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #4E342E; margin-bottom: 14px; text-align: center; }
|
||||
blockquote { border-top: 1px solid #5D4037; border-bottom: 1px solid #5D4037; padding: 20px; margin: 24px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'bistro-chalkboard',
|
||||
name: 'Bistro Chalkboard',
|
||||
category: 'Food',
|
||||
description: 'French cafe menu. White chalk text on slate black.',
|
||||
vibe: 'French, Food, Chalk',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Homemade+Apple&family=Caveat:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Homemade Apple", size: 32, color: "FFFFFF", bold: false, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "212121", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Caveat", size: 20, color: "E0E0E0", bold: true, align: 'center',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Caveat", size: 14, color: "BDBDBD", align: 'center',
|
||||
spacing: { before: 0, after: 160, line: 280 },
|
||||
shading: { fill: "263238", color: "auto", style: "clear" }
|
||||
},
|
||||
accentColor: "FFFFFF"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Caveat', cursive;
|
||||
background: #212121;
|
||||
color: #FFFFFF;
|
||||
h1 { font-family: 'Homemade Apple', cursive; font-size: 32pt; color: #FFFFFF; text-align: center; margin-bottom: 24px; border-bottom: 1px solid #757575; padding-bottom: 12px; }
|
||||
h2 { font-size: 20pt; font-weight: 700; color: #E0E0E0; text-align: center; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 14pt; line-height: 1.5; color: #BDBDBD; margin-bottom: 14px; text-align: center; }
|
||||
blockquote { border: 1px dashed #FFFFFF; padding: 16px; margin: 24px 0; font-style: italic; text-align: center; }
|
||||
`
|
||||
}
|
||||
];
|
||||
@@ -1,354 +0,0 @@
|
||||
import { StyleOption } from '../types';
|
||||
|
||||
export const minimalistStyles: StyleOption[] = [
|
||||
{
|
||||
id: 'swiss-grid',
|
||||
name: 'Swiss International',
|
||||
category: 'Minimalist',
|
||||
description: 'Objective, bold, and asymmetric. Heavy use of black and white, strong grid alignment.',
|
||||
vibe: 'Architecture, Design, Modernism',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;700;900&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Inter", size: 42, color: "000000", bold: true, tracking: -40, align: 'left',
|
||||
spacing: { before: 800, after: 400, line: 240 },
|
||||
border: { top: { color: "000000", space: 24, style: "single", size: 36 } }
|
||||
},
|
||||
heading2: {
|
||||
font: "Inter", size: 16, color: "000000", bold: true, allCaps: true, tracking: 40, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Inter", size: 10, color: "111111", align: 'left',
|
||||
spacing: { before: 0, after: 200, line: 280 }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Inter', sans-serif;
|
||||
h1 { font-size: 42pt; font-weight: 900; letter-spacing: -2px; border-top: 6px solid black; padding-top: 24px; margin-bottom: 24px; line-height: 1; }
|
||||
h2 { font-size: 16pt; font-weight: 700; text-transform: uppercase; letter-spacing: 2px; margin-top: 40px; margin-bottom: 16px; }
|
||||
p { font-size: 10pt; line-height: 1.5; margin-bottom: 16px; max-width: 65ch; }
|
||||
blockquote { border-left: 4px solid black; padding-left: 20px; font-weight: 700; font-style: normal; margin-left: 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'minimalist-white',
|
||||
name: 'Minimalist White',
|
||||
category: 'Minimal',
|
||||
description: 'Ultra-clean design with maximum white space. Less is more philosophy with restrained typography that lets content breathe.',
|
||||
vibe: 'Clean, Modern, Sophisticated',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Work+Sans:wght@300;400;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Work Sans", size: 32, color: "111111", bold: false, align: 'left',
|
||||
spacing: { before: 600, after: 300, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Work Sans", size: 14, color: "444444", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Work Sans", size: 10, color: "555555", align: 'left',
|
||||
spacing: { before: 0, after: 200, line: 320 }
|
||||
},
|
||||
accentColor: "111111"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Work Sans', sans-serif;
|
||||
h1 { font-size: 32pt; font-weight: 300; color: #111111; margin-bottom: 32px; letter-spacing: -1px; }
|
||||
h2 { font-size: 14pt; font-weight: 600; color: #444444; margin-top: 40px; margin-bottom: 20px; }
|
||||
p { font-size: 10pt; line-height: 1.8; color: #555555; margin-bottom: 18px; }
|
||||
blockquote { border-left: 1px solid #DDDDDD; padding-left: 24px; margin: 32px 0; color: #666666; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'scandinavian-clean',
|
||||
name: 'Scandinavian Clean',
|
||||
category: 'Minimal',
|
||||
description: 'Inspired by Nordic design principles. Clean lines, functional typography, and subtle warmth with muted colors.',
|
||||
vibe: 'Nordic, Clean, Warm Minimal',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Poppins", size: 28, color: "2C2C2C", bold: false, align: 'left',
|
||||
spacing: { before: 480, after: 240, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Poppins", size: 14, color: "5D5D5D", bold: true, align: 'left',
|
||||
spacing: { before: 360, after: 180, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Poppins", size: 10, color: "4A4A4A", align: 'left',
|
||||
spacing: { before: 0, after: 180, line: 300 }
|
||||
},
|
||||
accentColor: "E07A5F"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Poppins', sans-serif;
|
||||
h1 { font-size: 28pt; font-weight: 300; color: #2C2C2C; margin-bottom: 28px; }
|
||||
h2 { font-size: 14pt; font-weight: 600; color: #5D5D5D; margin-top: 36px; margin-bottom: 18px; }
|
||||
p { font-size: 10pt; line-height: 1.7; color: #4A4A4A; margin-bottom: 16px; font-weight: 300; }
|
||||
blockquote { border-left: 3px solid #E07A5F; padding-left: 20px; margin: 28px 0; color: #666666; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'minimalist-black',
|
||||
name: 'Minimalist Black',
|
||||
category: 'Minimal',
|
||||
description: 'Ultra-minimal dark design with stark contrasts. High-impact typography on dark backgrounds.',
|
||||
vibe: 'Dark, Minimal, Bold',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Bebas+Neue&family=Work+Sans:wght@300;400;500&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Bebas Neue", size: 48, color: "FFFFFF", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 200 },
|
||||
shading: { fill: "0A0A0A", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Work Sans", size: 12, color: "FFFFFF", bold: false, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
shading: { fill: "1A1A1A", color: "auto", style: "clear" }
|
||||
},
|
||||
body: {
|
||||
font: "Work Sans", size: 10, color: "E0E0E0", align: 'left',
|
||||
spacing: { before: 0, after: 180, line: 300 },
|
||||
shading: { fill: "121212", color: "auto", style: "clear" }
|
||||
},
|
||||
accentColor: "FFFFFF"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Work Sans', sans-serif;
|
||||
background: #0A0A0A;
|
||||
h1 { font-family: 'Bebas Neue', sans-serif; font-size: 48pt; color: #FFFFFF; background: #0A0A0A; padding: 16px 20px; margin-bottom: 24px; letter-spacing: 3px; }
|
||||
h2 { font-size: 12pt; color: #FFFFFF; margin-top: 32px; margin-bottom: 16px; text-transform: uppercase; letter-spacing: 4px; font-weight: 300; }
|
||||
p { font-size: 10pt; line-height: 1.7; color: #E0E0E0; margin-bottom: 16px; font-weight: 300; }
|
||||
blockquote { border-left: 1px solid #FFFFFF; padding-left: 24px; margin: 28px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'japanese-zen',
|
||||
name: 'Japanese Zen',
|
||||
category: 'Minimal',
|
||||
description: 'Inspired by Japanese minimalism and wabi-sabi aesthetics. Peaceful typography with intentional asymmetry.',
|
||||
vibe: 'Zen, Peaceful, Minimal',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Shippori+Mincho:wght@400;600;700&family=Zen+Kaku+Gothic+New:wght@300;400;500&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Shippori Mincho", size: 28, color: "2D2D2D", bold: false, align: 'left',
|
||||
spacing: { before: 560, after: 320, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Zen Kaku Gothic New", size: 12, color: "5C5C5C", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Zen Kaku Gothic New", size: 10, color: "4A4A4A", align: 'left',
|
||||
spacing: { before: 0, after: 200, line: 320 }
|
||||
},
|
||||
accentColor: "C41E3A"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Zen Kaku Gothic New', sans-serif;
|
||||
h1 { font-family: 'Shippori Mincho', serif; font-size: 28pt; color: #2D2D2D; margin-bottom: 36px; }
|
||||
h2 { font-size: 12pt; color: #5C5C5C; margin-top: 40px; margin-bottom: 20px; font-weight: 300; letter-spacing: 2px; }
|
||||
p { font-size: 10pt; line-height: 1.8; color: #4A4A4A; margin-bottom: 18px; font-weight: 300; }
|
||||
blockquote { border-left: 2px solid #C41E3A; padding-left: 24px; margin: 36px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'zen-garden',
|
||||
name: 'Zen Garden',
|
||||
category: 'Minimal',
|
||||
description: 'Inspired by Japanese rock gardens. Extreme minimalism with meditative spacing and natural balance.',
|
||||
vibe: 'Meditative, Balanced, Serene',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Noto+Serif+JP:wght@400;600&family=Noto+Sans+JP:wght@300;400&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Noto Serif JP", size: 26, color: "2C2C2C", bold: false, align: 'left',
|
||||
spacing: { before: 600, after: 360, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Noto Sans JP", size: 11, color: "5C5C5C", bold: false, align: 'left',
|
||||
spacing: { before: 480, after: 240, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Noto Sans JP", size: 10, color: "4A4A4A", align: 'left',
|
||||
spacing: { before: 0, after: 240, line: 360 }
|
||||
},
|
||||
accentColor: "6B8E6B"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Noto Sans JP', sans-serif;
|
||||
h1 { font-family: 'Noto Serif JP', serif; font-size: 26pt; font-weight: 600; color: #2C2C2C; margin-bottom: 40px; }
|
||||
h2 { font-size: 11pt; color: #5C5C5C; margin-top: 48px; margin-bottom: 24px; font-weight: 300; letter-spacing: 2px; }
|
||||
p { font-size: 10pt; line-height: 2; color: #4A4A4A; margin-bottom: 20px; font-weight: 300; }
|
||||
blockquote { border-left: 1px solid #6B8E6B; padding-left: 32px; margin: 40px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'de-stijl',
|
||||
name: 'De Stijl',
|
||||
category: 'Modern',
|
||||
description: 'Inspired by the Dutch movement (Mondrian). Primary colors, thick black lines, and rigid grid geometry.',
|
||||
vibe: 'Abstract, Geometric, Primary',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Geo:wght@400&family=Arimo:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Geo", size: 32, color: "FF0000", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: {
|
||||
bottom: { color: "000000", space: 12, style: "single", size: 24 },
|
||||
left: { color: "000000", space: 12, style: "single", size: 24 }
|
||||
}
|
||||
},
|
||||
heading2: {
|
||||
font: "Arimo", size: 14, color: "0000FF", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
shading: { fill: "FFFF00", color: "auto", style: "clear" }
|
||||
},
|
||||
body: {
|
||||
font: "Arimo", size: 10, color: "000000", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "FF0000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Arimo', sans-serif;
|
||||
h1 { font-family: 'Geo', sans-serif; font-size: 32pt; color: #FF0000; border-bottom: 4px solid #000000; border-left: 4px solid #000000; padding-left: 16px; margin-bottom: 24px; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #0000FF; background: #FFFF00; display: inline-block; padding: 4px 12px; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #000000; margin-bottom: 14px; }
|
||||
blockquote { border: 4px solid #000000; padding: 16px; margin: 24px 0; box-shadow: 8px 8px 0px #0000FF; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'bauhaus-construction',
|
||||
name: 'Bauhaus Construction',
|
||||
category: 'Modernism',
|
||||
description: 'Form follows function. Geometric simplicity using primary colors and heavy structural borders.',
|
||||
vibe: 'Geometric, Functional, Primary',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Jura:wght@400;700&family=Tenor+Sans&display=swap',
|
||||
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Jura", size: 32, color: "111111", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: { left: { color: "D50000", space: 12, style: "single", size: 48 } }
|
||||
},
|
||||
heading2: {
|
||||
font: "Tenor Sans", size: 16, color: "111111", bold: true, align: 'left',
|
||||
spacing: { before: 300, after: 150, line: 240 },
|
||||
shading: { fill: "FFEB3B", color: "auto", style: "clear" }
|
||||
},
|
||||
body: {
|
||||
font: "Tenor Sans", size: 11, color: "212121", align: 'both',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "0000FF"
|
||||
},
|
||||
|
||||
previewCss: `
|
||||
font-family: 'Tenor Sans', sans-serif;
|
||||
h1 { font-family: 'Jura', sans-serif; font-size: 32pt; font-weight: 700; color: #111111; border-left: 12px solid #D50000; padding-left: 16px; margin-bottom: 24px; }
|
||||
h2 { font-size: 16pt; font-weight: 700; color: #111111; background: #FFEB3B; display: inline-block; padding: 4px 12px; margin-top: 30px; margin-bottom: 14px; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #212121; margin-bottom: 14px; text-align: justify; }
|
||||
blockquote { border-top: 4px solid #0000FF; border-bottom: 4px solid #0000FF; padding: 16px 0; margin: 24px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'museum-gallery',
|
||||
name: 'Museum Gallery',
|
||||
category: 'Institutional',
|
||||
description: 'Art gallery placard style. Extremely neutral sans-serifs, high contrast, small but clear text.',
|
||||
vibe: 'Neutral, Institutional, Clean',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Karla:wght@400;700&family=Work+Sans:wght@400;600&display=swap',
|
||||
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Work Sans", size: 24, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 360, after: 180, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Karla", size: 12, color: "616161", bold: true, align: 'left',
|
||||
spacing: { before: 280, after: 140, line: 240 },
|
||||
allCaps: true
|
||||
},
|
||||
body: {
|
||||
font: "Karla", size: 10, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
|
||||
previewCss: `
|
||||
font-family: 'Karla', sans-serif;
|
||||
h1 { font-family: 'Work Sans', sans-serif; font-size: 24pt; font-weight: 700; color: #000000; margin-bottom: 20px; }
|
||||
h2 { font-size: 12pt; font-weight: 700; color: #616161; margin-top: 24px; margin-bottom: 14px; text-transform: uppercase; letter-spacing: 1px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #212121; margin-bottom: 14px; }
|
||||
blockquote { border-left: 2px solid #000; padding-left: 16px; margin: 20px 0; color: #424242; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'wireframe-layout',
|
||||
name: 'Wireframe Layout',
|
||||
category: 'Minimal',
|
||||
description: 'Digital blueprint style. Grey backgrounds, monospaced fonts, and placeholder-like blocks.',
|
||||
vibe: 'Digital, Prototype, Structural',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Redacted+Script&family=Flow+Circular&family=Roboto+Mono&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Roboto Mono", size: 24, color: "0000FF", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "E0E0E0", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Roboto Mono", size: 14, color: "555555", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
border: { bottom: { color: "CCCCCC", space: 4, style: "single", size: 4 } }
|
||||
},
|
||||
body: {
|
||||
font: "Roboto Mono", size: 10, color: "333333", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "0000FF"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Roboto Mono', monospace;
|
||||
h1 { font-size: 24pt; font-weight: 700; color: #0000FF; background: #E0E0E0; padding: 12px; margin-bottom: 24px; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #555555; border-bottom: 1px solid #CCC; margin-top: 32px; margin-bottom: 16px; padding-bottom: 4px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #333333; margin-bottom: 14px; }
|
||||
blockquote { border: 1px dashed #999; padding: 16px; margin: 24px 0; background: #F9F9F9; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'muted-pastel',
|
||||
name: 'Muted Pastel',
|
||||
category: 'Minimal',
|
||||
description: 'Soft and calming. Very light background tints with gentle, rounded typography.',
|
||||
vibe: 'Soft, Calming, Gentle',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Nunito:wght@400;700&family=Quicksand:wght@400;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Nunito", size: 28, color: "7986CB", bold: true, align: 'center',
|
||||
spacing: { before: 480, after: 240, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Quicksand", size: 14, color: "9575CD", bold: true, align: 'center',
|
||||
spacing: { before: 360, after: 180, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Quicksand", size: 11, color: "616161", align: 'center',
|
||||
spacing: { before: 0, after: 180, line: 300 }
|
||||
},
|
||||
accentColor: "9575CD"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Quicksand', sans-serif;
|
||||
background: #FDFBF7;
|
||||
h1 { font-family: 'Nunito', sans-serif; font-size: 28pt; font-weight: 700; color: #7986CB; text-align: center; margin-bottom: 32px; }
|
||||
h2 { font-size: 14pt; font-weight: 600; color: #9575CD; text-align: center; margin-top: 36px; margin-bottom: 18px; }
|
||||
p { font-size: 11pt; line-height: 1.7; color: #616161; margin-bottom: 16px; text-align: center; }
|
||||
blockquote { background: #F3E5F5; padding: 24px; border-radius: 20px; margin: 32px 40px; text-align: center; }
|
||||
`
|
||||
}
|
||||
];
|
||||
@@ -1,957 +0,0 @@
|
||||
import { StyleOption } from '../types';
|
||||
|
||||
export const techStyles: StyleOption[] = [
|
||||
{
|
||||
id: 'tech-startup',
|
||||
name: 'Tech Startup',
|
||||
category: 'Tech',
|
||||
description: 'Modern, energetic design for technology companies and startups. Bold gradients, vibrant colors, and confident typography.',
|
||||
vibe: 'Innovative, Dynamic, Bold',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Plus Jakarta Sans", size: 28, color: "6366F1", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Plus Jakarta Sans", size: 16, color: "1E1E1E", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Plus Jakarta Sans", size: 10, color: "4B5563", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "6366F1"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Plus Jakarta Sans', sans-serif;
|
||||
h1 { font-size: 28pt; font-weight: 700; color: #6366F1; margin-bottom: 24px; }
|
||||
h2 { font-size: 16pt; font-weight: 700; color: #1E1E1E; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #4B5563; margin-bottom: 14px; }
|
||||
blockquote { background: linear-gradient(135deg, #EEF2FF 0%, #E0E7FF 100%); padding: 20px; border-radius: 8px; border-left: 4px solid #6366F1; margin: 24px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'tech-documentation',
|
||||
name: 'Tech Documentation',
|
||||
category: 'Technical',
|
||||
description: 'Clean and functional design for technical documentation. Optimized for code samples and clear instruction.',
|
||||
vibe: 'Technical, Clear, Functional',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600&family=IBM+Plex+Mono:wght@400;500&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "IBM Plex Sans", size: 24, color: "161616", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "IBM Plex Sans", size: 16, color: "161616", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "IBM Plex Sans", size: 10, color: "525252", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "0F62FE"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'IBM Plex Sans', sans-serif;
|
||||
h1 { font-size: 24pt; font-weight: 600; color: #161616; margin-bottom: 24px; }
|
||||
h2 { font-size: 16pt; font-weight: 600; color: #161616; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #525252; margin-bottom: 14px; }
|
||||
blockquote { font-family: 'IBM Plex Mono', monospace; background: #F4F4F4; padding: 16px; margin: 20px 0; font-size: 9pt; border-left: 4px solid #0F62FE; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'industrial-blueprint',
|
||||
name: 'Industrial Blueprint',
|
||||
category: 'Technical',
|
||||
description: 'Engineering-inspired design reminiscent of technical blueprints. Precise typography with drafting aesthetics.',
|
||||
vibe: 'Technical, Precise, Engineering',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Share+Tech+Mono&family=Titillium+Web:wght@400;600;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Titillium Web", size: 24, color: "FFFFFF", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "1A3A5C", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Titillium Web", size: 14, color: "1A3A5C", bold: true, align: 'left',
|
||||
spacing: { before: 300, after: 150, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Share Tech Mono", size: 9, color: "2C4A6B", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 300 }
|
||||
},
|
||||
accentColor: "1A3A5C"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
h1 { font-family: 'Titillium Web', sans-serif; font-size: 24pt; font-weight: 700; color: #FFFFFF; background: #1A3A5C; padding: 16px 20px; margin-bottom: 24px; text-transform: uppercase; }
|
||||
h2 { font-family: 'Titillium Web', sans-serif; font-size: 14pt; font-weight: 700; color: #1A3A5C; margin-top: 30px; margin-bottom: 14px; }
|
||||
p { font-size: 9pt; line-height: 1.7; color: #2C4A6B; margin-bottom: 14px; }
|
||||
blockquote { background: #E8F4FC; padding: 16px; border: 1px dashed #1A3A5C; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'crypto-futurism',
|
||||
name: 'Crypto Futurism',
|
||||
category: 'Tech',
|
||||
description: 'Cutting-edge design for blockchain and cryptocurrency content. Dark themes with electric accents.',
|
||||
vibe: 'Futuristic, Digital, Cutting-edge',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Audiowide&family=Rajdhani:wght@400;500;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Audiowide", size: 26, color: "00D4AA", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "0D1117", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Rajdhani", size: 16, color: "58A6FF", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Rajdhani", size: 10, color: "C9D1D9", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 },
|
||||
shading: { fill: "161B22", color: "auto", style: "clear" }
|
||||
},
|
||||
accentColor: "00D4AA"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Rajdhani', sans-serif;
|
||||
background: #0D1117;
|
||||
h1 { font-family: 'Audiowide', cursive; font-size: 26pt; color: #00D4AA; background: #0D1117; padding: 16px 20px; margin-bottom: 24px; }
|
||||
h2 { font-size: 16pt; font-weight: 600; color: #58A6FF; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #C9D1D9; margin-bottom: 14px; }
|
||||
blockquote { background: #21262D; padding: 16px; border-left: 4px solid #00D4AA; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'aerospace-modern',
|
||||
name: 'Aerospace Modern',
|
||||
category: 'Tech',
|
||||
description: 'Sleek design inspired by aerospace and space exploration. Clean lines with futuristic precision.',
|
||||
vibe: 'Futuristic, Sleek, Precision',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Michroma&family=Saira:wght@300;400;500&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Michroma", size: 22, color: "0B3D91", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Saira", size: 13, color: "FC3D21", bold: true, align: 'left',
|
||||
spacing: { before: 300, after: 150, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Saira", size: 10, color: "2E3A45", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "FC3D21"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Saira', sans-serif;
|
||||
h1 { font-family: 'Michroma', sans-serif; font-size: 22pt; color: #0B3D91; margin-bottom: 24px; letter-spacing: 2px; }
|
||||
h2 { font-size: 13pt; font-weight: 500; color: #FC3D21; margin-top: 30px; margin-bottom: 14px; text-transform: uppercase; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #2E3A45; margin-bottom: 14px; font-weight: 300; }
|
||||
blockquote { background: #E8F0FE; padding: 16px; border-left: 4px solid #0B3D91; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'data-analytics',
|
||||
name: 'Data Analytics',
|
||||
category: 'Tech',
|
||||
description: 'Clean design for data science and analytics content. Precise typography optimized for charts and metrics.',
|
||||
vibe: 'Analytical, Clean, Data-driven',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Overpass:wght@400;600;700&family=Overpass+Mono:wght@400;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Overpass", size: 26, color: "0F172A", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Overpass", size: 14, color: "3730A3", bold: true, align: 'left',
|
||||
spacing: { before: 300, after: 150, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Overpass", size: 10, color: "475569", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "3730A3"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Overpass', sans-serif;
|
||||
h1 { font-size: 26pt; font-weight: 700; color: #0F172A; margin-bottom: 24px; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #3730A3; margin-top: 30px; margin-bottom: 14px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #475569; margin-bottom: 14px; }
|
||||
blockquote { font-family: 'Overpass Mono', monospace; background: #F1F5F9; padding: 16px; border-left: 4px solid #3730A3; margin: 20px 0; font-size: 9pt; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'artificial-intelligence',
|
||||
name: 'Artificial Intelligence',
|
||||
category: 'Tech',
|
||||
description: 'Cutting-edge design for AI and machine learning content. Neural network inspired with gradient accents.',
|
||||
vibe: 'Cutting-edge, Neural, Intelligent',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Oxanium:wght@400;600;700&family=Lexend:wght@300;400;500&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Oxanium", size: 28, color: "7C3AED", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Lexend", size: 14, color: "2563EB", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Lexend", size: 10, color: "334155", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "7C3AED"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Lexend', sans-serif;
|
||||
h1 { font-family: 'Oxanium', sans-serif; font-size: 28pt; font-weight: 700; color: #7C3AED; margin-bottom: 24px; }
|
||||
h2 { font-size: 14pt; font-weight: 500; color: #2563EB; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #334155; margin-bottom: 14px; font-weight: 300; }
|
||||
blockquote { background: linear-gradient(135deg, #EDE9FE 0%, #DBEAFE 100%); padding: 16px; border-radius: 8px; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'marine-biology',
|
||||
name: 'Marine Biology',
|
||||
category: 'Science',
|
||||
description: 'Ocean-inspired design for marine science and aquatic content. Deep blues with flowing elegance.',
|
||||
vibe: 'Oceanic, Scientific, Flowing',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Archivo:wght@400;500;600&family=Lora:wght@400;500&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Lora", size: 26, color: "0C4A6E", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Archivo", size: 13, color: "0369A1", bold: true, align: 'left',
|
||||
spacing: { before: 300, after: 150, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Archivo", size: 10, color: "334155", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "0EA5E9"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Archivo', sans-serif;
|
||||
h1 { font-family: 'Lora', serif; font-size: 26pt; font-weight: 700; color: #0C4A6E; margin-bottom: 24px; }
|
||||
h2 { font-size: 13pt; font-weight: 600; color: #0369A1; margin-top: 30px; margin-bottom: 14px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #334155; margin-bottom: 14px; }
|
||||
blockquote { background: #E0F2FE; padding: 16px; border-left: 4px solid #0EA5E9; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'startup-saas',
|
||||
name: 'Startup SaaS',
|
||||
category: 'Tech',
|
||||
description: 'Modern SaaS product design language. Clean, conversion-focused with trustworthy tech aesthetics.',
|
||||
vibe: 'Modern, Trustworthy, Product',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Inter", size: 32, color: "111827", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Inter", size: 18, color: "4F46E5", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Inter", size: 10, color: "6B7280", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "4F46E5"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Inter', sans-serif;
|
||||
h1 { font-size: 32pt; font-weight: 700; color: #111827; margin-bottom: 24px; letter-spacing: -0.5px; }
|
||||
h2 { font-size: 18pt; font-weight: 600; color: #4F46E5; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #6B7280; margin-bottom: 14px; }
|
||||
blockquote { background: #EEF2FF; padding: 16px; border-radius: 8px; border-left: 4px solid #4F46E5; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'cybersecurity',
|
||||
name: 'Cybersecurity',
|
||||
category: 'Tech',
|
||||
description: 'High-security design for infosec and cybersecurity. Matrix-inspired with threat-level colors.',
|
||||
vibe: 'Secure, Technical, Alert',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Share+Tech+Mono&family=Exo+2:wght@400;500;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Exo 2", size: 26, color: "00E676", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "0D0D0D", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Exo 2", size: 14, color: "00E676", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Share Tech Mono", size: 9, color: "B0BEC5", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 },
|
||||
shading: { fill: "1A1A1A", color: "auto", style: "clear" }
|
||||
},
|
||||
accentColor: "00E676"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
background: #0D0D0D;
|
||||
h1 { font-family: 'Exo 2', sans-serif; font-size: 26pt; font-weight: 600; color: #00E676; background: #0D0D0D; padding: 16px 20px; margin-bottom: 24px; }
|
||||
h2 { font-family: 'Exo 2', sans-serif; font-size: 14pt; font-weight: 600; color: #00E676; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 9pt; line-height: 1.6; color: #B0BEC5; margin-bottom: 14px; }
|
||||
blockquote { background: #1A1A1A; padding: 16px; border-left: 4px solid #00E676; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'astronomy-space',
|
||||
name: 'Astronomy Space',
|
||||
category: 'Science',
|
||||
description: 'Cosmic design for astronomy and space science. Deep space colors with stellar typography.',
|
||||
vibe: 'Cosmic, Scientific, Vast',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Orbitron:wght@400;600;700&family=Space+Grotesk:wght@400;500&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Orbitron", size: 26, color: "FFFFFF", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "0A0A23", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Space Grotesk", size: 14, color: "7C4DFF", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Space Grotesk", size: 10, color: "B0BEC5", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 },
|
||||
shading: { fill: "121225", color: "auto", style: "clear" }
|
||||
},
|
||||
accentColor: "7C4DFF"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Space Grotesk', sans-serif;
|
||||
background: #0A0A23;
|
||||
h1 { font-family: 'Orbitron', sans-serif; font-size: 26pt; font-weight: 700; color: #FFFFFF; background: #0A0A23; padding: 16px 20px; margin-bottom: 24px; }
|
||||
h2 { font-size: 14pt; font-weight: 500; color: #7C4DFF; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #B0BEC5; margin-bottom: 14px; }
|
||||
blockquote { background: #1A1A3E; padding: 16px; border-left: 4px solid #7C4DFF; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'blockchain-protocol',
|
||||
name: 'Blockchain Protocol',
|
||||
category: 'Tech',
|
||||
description: 'Technical blockchain and Web3 design. Decentralized aesthetics with protocol documentation style.',
|
||||
vibe: 'Technical, Decentralized, Protocol',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=Inter:wght@400;500;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Inter", size: 28, color: "6366F1", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Inter", size: 16, color: "1E1E1E", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Inter", size: 10, color: "4B5563", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "6366F1"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Inter', sans-serif;
|
||||
h1 { font-size: 28pt; font-weight: 600; color: #6366F1; margin-bottom: 24px; }
|
||||
h2 { font-size: 16pt; font-weight: 600; color: #1E1E1E; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #4B5563; margin-bottom: 14px; }
|
||||
blockquote { font-family: 'JetBrains Mono', monospace; background: #F3F4F6; padding: 16px; border-radius: 6px; margin: 20px 0; font-size: 9pt; border-left: 4px solid #6366F1; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'smart-home-tech',
|
||||
name: 'Smart Home Tech',
|
||||
category: 'Tech',
|
||||
description: 'Modern IoT and smart home design. Clean, connected typography with ambient intelligence.',
|
||||
vibe: 'Connected, Modern, Ambient',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Poppins", size: 28, color: "00BFA5", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Poppins", size: 15, color: "263238", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Poppins", size: 10, color: "546E7A", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "00BFA5"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Poppins', sans-serif;
|
||||
h1 { font-size: 28pt; font-weight: 600; color: #00BFA5; margin-bottom: 24px; }
|
||||
h2 { font-size: 15pt; font-weight: 600; color: #263238; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #546E7A; margin-bottom: 14px; }
|
||||
blockquote { background: #E0F2F1; padding: 16px; border-radius: 12px; border-left: 4px solid #00BFA5; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'frutiger-aero',
|
||||
name: 'Frutiger Aero',
|
||||
category: 'Tech',
|
||||
description: 'Mid-2000s tech aesthetic. Glossy textures, humanist sans-serifs, and optimistic skeuomorphic blues and greens.',
|
||||
vibe: 'Glossy, Optimistic, 2000s',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Varela+Round&family=M+PLUS+Rounded+1c:wght@400;500;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Varela Round", size: 28, color: "0288D1", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "M PLUS Rounded 1c", size: 15, color: "7CB342", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "M PLUS Rounded 1c", size: 10, color: "546E7A", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "03A9F4"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'M PLUS Rounded 1c', sans-serif;
|
||||
h1 { font-family: 'Varela Round', sans-serif; font-size: 28pt; color: #0288D1; margin-bottom: 24px; background: linear-gradient(to right, #E1F5FE, #FFFFFF); padding: 10px; border-radius: 10px; }
|
||||
h2 { font-size: 15pt; font-weight: 700; color: #7CB342; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #546E7A; margin-bottom: 14px; }
|
||||
blockquote { background: linear-gradient(180deg, #FFFFFF 0%, #E0F7FA 100%); padding: 16px; border-radius: 15px; border: 1px solid #B3E5FC; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'solarpunk',
|
||||
name: 'Solarpunk',
|
||||
category: 'Futuristic',
|
||||
description: 'Nature-meets-technology future. Art Nouveau curves with high-tech sustainable green and gold.',
|
||||
vibe: 'Sustainable, Hopeful, Organic',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Caudex:wght@400;700&family=El+Messiri:wght@400;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "El Messiri", size: 30, color: "2E7D32", bold: true, align: 'left',
|
||||
spacing: { before: 440, after: 260, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Caudex", size: 15, color: "AFB42B", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Caudex", size: 11, color: "33691E", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "FFD700"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Caudex', serif;
|
||||
h1 { font-family: 'El Messiri', sans-serif; font-size: 30pt; font-weight: 700; color: #2E7D32; margin-bottom: 30px; }
|
||||
h2 { font-size: 15pt; font-weight: 700; color: #AFB42B; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #33691E; margin-bottom: 14px; }
|
||||
blockquote { background: #F1F8E9; padding: 16px; border-left: 4px solid #FFD700; border-radius: 0 16px 16px 0; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'biohazard-lab',
|
||||
name: 'Biohazard Lab',
|
||||
category: 'Sci-Fi',
|
||||
description: 'Warning-label aesthetic. Monospace fonts with high-contrast yellow and black caution themes.',
|
||||
vibe: 'Warning, Industrial, Hazardous',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Syne+Mono&family=Azeret+Mono:wght@400;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Syne Mono", size: 32, color: "000000", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 240, line: 240 },
|
||||
shading: { fill: "FFEB3B", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Azeret Mono", size: 14, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
border: { left: { color: "FFEB3B", space: 8, style: "single", size: 24 } }
|
||||
},
|
||||
body: {
|
||||
font: "Azeret Mono", size: 10, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "FFEB3B"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Azeret Mono', monospace;
|
||||
h1 { font-family: 'Syne Mono', monospace; font-size: 32pt; font-weight: 700; color: #000000; background: #FFEB3B; padding: 16px; text-align: center; margin-bottom: 28px; letter-spacing: -1px; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #000000; border-left: 8px solid #FFEB3B; padding-left: 12px; margin-top: 32px; margin-bottom: 16px; text-transform: uppercase; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #212121; margin-bottom: 14px; }
|
||||
blockquote { border: 2px dashed #000000; padding: 16px; margin: 20px 0; background: #FFF9C4; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'code-editor',
|
||||
name: 'Code Editor',
|
||||
category: 'Tech',
|
||||
description: 'Dark mode IDE aesthetic. Monospaced fonts with syntax-highlighting color palette.',
|
||||
vibe: 'Technical, Dark, Coding',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Inconsolata:wght@400;700&family=Source+Code+Pro:wght@400;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Inconsolata", size: 26, color: "61AFEF", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "282C34", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Source Code Pro", size: 14, color: "98C379", bold: true, align: 'left',
|
||||
spacing: { before: 300, after: 150, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Source Code Pro", size: 10, color: "ABB2BF", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 },
|
||||
shading: { fill: "21252B", color: "auto", style: "clear" }
|
||||
},
|
||||
accentColor: "E06C75"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Source Code Pro', monospace;
|
||||
background: #282C34;
|
||||
h1 { font-family: 'Inconsolata', monospace; font-size: 26pt; font-weight: 700; color: #61AFEF; background: #282C34; padding: 16px 20px; margin-bottom: 24px; }
|
||||
h2 { font-size: 14pt; font-weight: 600; color: #98C379; margin-top: 30px; margin-bottom: 14px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #ABB2BF; margin-bottom: 14px; }
|
||||
blockquote { background: #2C313C; padding: 16px; border-left: 4px solid #E06C75; margin: 20px 0; color: #E06C75; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'neon-noir',
|
||||
name: 'Neon Noir',
|
||||
category: 'Futuristic',
|
||||
description: 'High-tech noir aesthetic. Ultra-thin, futuristic typography with glowing neon accents.',
|
||||
vibe: 'Futuristic, Thin, Neon',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Megrim&family=Gruppo&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Megrim", size: 36, color: "D500F9", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "121212", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Gruppo", size: 18, color: "00E5FF", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Gruppo", size: 12, color: "E0E0E0", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 300 },
|
||||
shading: { fill: "1C1C1C", color: "auto", style: "clear" }
|
||||
},
|
||||
accentColor: "D500F9"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Gruppo', sans-serif;
|
||||
background: #121212;
|
||||
h1 { font-family: 'Megrim', cursive; font-size: 36pt; font-weight: 700; color: #D500F9; background: #121212; margin-bottom: 24px; }
|
||||
h2 { font-size: 18pt; font-weight: 700; color: #00E5FF; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 12pt; line-height: 1.6; color: #E0E0E0; margin-bottom: 14px; }
|
||||
blockquote { border: 1px solid #D500F9; padding: 16px; margin: 20px 0; background: #000; color: #D500F9; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: '8-bit-arcade',
|
||||
name: '8-Bit Arcade',
|
||||
category: 'Gaming',
|
||||
description: 'Retro gaming high-score screen. Pixelated fonts on dark backgrounds.',
|
||||
vibe: 'Retro, Gaming, Pixel',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Press+Start+2P&family=VT323&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Press Start 2P", size: 20, color: "76FF03", bold: false, align: 'center',
|
||||
spacing: { before: 400, after: 240, line: 300 },
|
||||
shading: { fill: "212121", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Press Start 2P", size: 12, color: "D500F9", bold: false, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "VT323", size: 14, color: "FFFFFF", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 240 },
|
||||
shading: { fill: "000000", color: "auto", style: "clear" }
|
||||
},
|
||||
accentColor: "76FF03"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'VT323', monospace;
|
||||
background: #000000;
|
||||
h1 { font-family: 'Press Start 2P', cursive; font-size: 20pt; color: #76FF03; background: #212121; text-align: center; padding: 20px; margin-bottom: 28px; line-height: 1.5; }
|
||||
h2 { font-family: 'Press Start 2P', cursive; font-size: 12pt; color: #D500F9; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 14pt; line-height: 1.4; color: #FFFFFF; margin-bottom: 14px; }
|
||||
blockquote { border: 4px dashed #FFFFFF; padding: 16px; margin: 20px 0; color: #FFFF00; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'bsod-blue',
|
||||
name: 'BSOD Blue',
|
||||
category: 'Tech',
|
||||
description: 'The infamous crash screen. Pure white terminal fonts on a deep, error blue background.',
|
||||
vibe: 'Crash, Error, Terminal',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Lucident&family=Fira+Mono&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Lucident", size: 24, color: "FFFFFF", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 240, line: 240 },
|
||||
shading: { fill: "0000AA", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Fira Mono", size: 14, color: "FFFFFF", bold: false, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
shading: { fill: "0000AA", color: "auto", style: "clear" }
|
||||
},
|
||||
body: {
|
||||
font: "Fira Mono", size: 11, color: "FFFFFF", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 },
|
||||
shading: { fill: "0000AA", color: "auto", style: "clear" }
|
||||
},
|
||||
accentColor: "FFFFFF"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Fira Mono', monospace;
|
||||
background: #0000AA;
|
||||
color: #FFFFFF;
|
||||
h1 { font-family: 'Lucident', monospace; font-size: 24pt; font-weight: 700; color: #FFFFFF; margin-bottom: 24px; }
|
||||
h2 { font-size: 14pt; font-weight: 400; color: #FFFFFF; margin-top: 32px; margin-bottom: 16px; text-decoration: underline; }
|
||||
p { font-size: 11pt; line-height: 1.5; color: #FFFFFF; margin-bottom: 14px; }
|
||||
blockquote { border: 2px solid #FFFFFF; padding: 16px; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'amber-monitor',
|
||||
name: 'Amber Monitor',
|
||||
category: 'Retro',
|
||||
description: '1980s monochrome computing. Glowing amber text on a black void.',
|
||||
vibe: 'Retro, Computing, Amber',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=VT323&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "VT323", size: 36, color: "FFB300", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "212121", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "VT323", size: 20, color: "FFCA28", bold: false, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
border: { bottom: { color: "FFB300", space: 4, style: "single", size: 12 } }
|
||||
},
|
||||
body: {
|
||||
font: "VT323", size: 16, color: "FFE082", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 240 },
|
||||
shading: { fill: "000000", color: "auto", style: "clear" }
|
||||
},
|
||||
accentColor: "FFB300"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'VT323', monospace;
|
||||
background: #000000;
|
||||
h1 { font-size: 36pt; color: #FFB300; margin-bottom: 24px; text-shadow: 0 0 5px #FF6F00; }
|
||||
h2 { font-size: 20pt; color: #FFCA28; margin-top: 32px; margin-bottom: 16px; border-bottom: 1px solid #FFB300; }
|
||||
p { font-size: 16pt; line-height: 1.4; color: #FFE082; margin-bottom: 14px; }
|
||||
blockquote { border-left: 4px solid #FFB300; padding-left: 16px; margin: 24px 0; color: #FFECB3; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'game-handheld',
|
||||
name: 'Game Handheld',
|
||||
category: 'Gaming',
|
||||
description: 'Classic 90s handheld console. Four shades of olive green pixel art style.',
|
||||
vibe: 'Pixel, Green, Retro',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Press Start 2P", size: 20, color: "0f380f", bold: false, align: 'center',
|
||||
spacing: { before: 400, after: 240, line: 240 },
|
||||
shading: { fill: "8bac0f", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Press Start 2P", size: 12, color: "306230", bold: false, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Press Start 2P", size: 10, color: "0f380f", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 240 }
|
||||
},
|
||||
accentColor: "306230"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Press Start 2P', cursive;
|
||||
background: #9bbc0f;
|
||||
h1 { font-size: 20pt; color: #0f380f; background: #8bac0f; padding: 20px; text-align: center; border: 4px solid #0f380f; margin-bottom: 24px; }
|
||||
h2 { font-size: 12pt; color: #306230; margin-top: 32px; margin-bottom: 16px; border-bottom: 4px solid #306230; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #0f380f; margin-bottom: 14px; }
|
||||
blockquote { background: #8bac0f; border: 2px solid #306230; padding: 16px; margin: 20px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'weather-radar',
|
||||
name: 'Weather Radar',
|
||||
category: 'Scientific',
|
||||
description: 'Meteorological map aesthetic. Deep map green backgrounds with rainbow radar text colors.',
|
||||
vibe: 'Scientific, Map, Storm',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Chakra+Petch:wght@400;700&family=Sarpanch:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Chakra Petch", size: 32, color: "FF1744", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "263238", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Sarpanch", size: 16, color: "00E676", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
shading: { fill: "37474F", color: "auto", style: "clear" }
|
||||
},
|
||||
body: {
|
||||
font: "Chakra Petch", size: 11, color: "E0F2F1", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 },
|
||||
shading: { fill: "455A64", color: "auto", style: "clear" }
|
||||
},
|
||||
accentColor: "FF1744"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Chakra Petch', sans-serif;
|
||||
background: #455A64;
|
||||
color: #E0F2F1;
|
||||
h1 { font-size: 32pt; font-weight: 700; color: #FF1744; background: #263238; padding: 16px; margin-bottom: 24px; border-left: 8px solid #FF1744; }
|
||||
h2 { font-family: 'Sarpanch', sans-serif; font-size: 16pt; font-weight: 700; color: #00E676; background: #37474F; padding: 8px; margin-top: 32px; margin-bottom: 16px; display: inline-block; }
|
||||
p { font-size: 11pt; line-height: 1.5; color: #E0F2F1; margin-bottom: 14px; }
|
||||
blockquote { border: 2px solid #FFEA00; padding: 16px; margin: 24px 0; background: #263238; color: #FFEA00; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'mars-rover',
|
||||
name: 'Mars Rover',
|
||||
category: 'Space',
|
||||
description: 'Red planet exploration. Dusty orange and terracotta tones with functional technical type.',
|
||||
vibe: 'Space, Dusty, Technical',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Orbitron&family=Exo:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Orbitron", size: 30, color: "BF360C", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: { bottom: { color: "FF7043", space: 6, style: "thick", size: 18 } }
|
||||
},
|
||||
heading2: {
|
||||
font: "Exo", size: 16, color: "E64A19", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
allCaps: true
|
||||
},
|
||||
body: {
|
||||
font: "Exo", size: 11, color: "3E2723", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "FF5722"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Exo', sans-serif;
|
||||
background: #FBE9E7;
|
||||
h1 { font-family: 'Orbitron', sans-serif; font-size: 30pt; font-weight: 700; color: #BF360C; border-bottom: 4px solid #FF7043; padding-bottom: 12px; margin-bottom: 24px; }
|
||||
h2 { font-size: 16pt; font-weight: 700; color: #E64A19; margin-top: 32px; margin-bottom: 16px; text-transform: uppercase; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #3E2723; margin-bottom: 14px; }
|
||||
blockquote { background: #FFCCBC; border-left: 6px solid #BF360C; padding: 16px; margin: 24px 0; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'deep-sea-sub',
|
||||
name: 'Deep Sea Sub',
|
||||
category: 'Nature',
|
||||
description: 'Bioluminescent abyss. Deepest navy backgrounds with glowing cyan/purple text.',
|
||||
vibe: 'Dark, Underwater, Glowing',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Abel&family=Rajdhani:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Rajdhani", size: 36, color: "00E5FF", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 240, line: 240 },
|
||||
shading: { fill: "1A237E", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Abel", size: 20, color: "E040FB", bold: true, align: 'center',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Abel", size: 12, color: "B2EBF2", align: 'center',
|
||||
spacing: { before: 0, after: 160, line: 280 },
|
||||
shading: { fill: "000051", color: "auto", style: "clear" }
|
||||
},
|
||||
accentColor: "00E5FF"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Abel', sans-serif;
|
||||
background: #000051;
|
||||
h1 { font-family: 'Rajdhani', sans-serif; font-size: 36pt; font-weight: 700; color: #00E5FF; background: #1A237E; padding: 20px; border-radius: 50%; width: 100px; height: 100px; line-height: 100px; margin: 0 auto 24px auto; text-align: center; display: block; box-shadow: 0 0 20px #00E5FF; }
|
||||
h2 { font-size: 20pt; font-weight: 700; color: #E040FB; text-align: center; margin-top: 32px; margin-bottom: 16px; text-shadow: 0 0 5px #E040FB; }
|
||||
p { font-size: 12pt; line-height: 1.6; color: #B2EBF2; margin-bottom: 14px; text-align: center; }
|
||||
blockquote { border: 1px solid #00E5FF; padding: 16px; margin: 24px 0; color: #E0F7FA; text-align: center; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'arctic-base',
|
||||
name: 'Arctic Base',
|
||||
category: 'Scientific',
|
||||
description: 'Polar research station. Stark white and ice blues with minimal sterile typography.',
|
||||
vibe: 'Cold, Sterile, Blue',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Iceland&family=Roboto:wght@300;400&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Iceland", size: 36, color: "01579B", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "E1F5FE", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Roboto", size: 18, color: "0277BD", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
allCaps: true
|
||||
},
|
||||
body: {
|
||||
font: "Roboto", size: 11, color: "455A64", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "0288D1"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Roboto', sans-serif;
|
||||
h1 { font-family: 'Iceland', cursive; font-size: 36pt; color: #01579B; background: #E1F5FE; padding: 12px 20px; margin-bottom: 24px; border-left: 4px solid #01579B; }
|
||||
h2 { font-size: 18pt; font-weight: 700; color: #0277BD; margin-top: 32px; margin-bottom: 16px; text-transform: uppercase; letter-spacing: 2px; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #455A64; margin-bottom: 14px; font-weight: 300; }
|
||||
blockquote { border: 1px solid #B3E5FC; padding: 16px; margin: 24px 0; background: #F0F8FF; color: #0277BD; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'schematic-diagram',
|
||||
name: 'Schematic Diagram',
|
||||
category: 'Technical',
|
||||
description: 'Patent drawing style. Thin, precise lines on stark white with serif lettering.',
|
||||
vibe: 'Technical, Precise, Patent',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Courier+Prime&family=Libre+Baskerville:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Libre Baskerville", size: 28, color: "000000", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
allCaps: true
|
||||
},
|
||||
heading2: {
|
||||
font: "Courier Prime", size: 14, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
border: { bottom: { color: "000000", space: 4, style: "single", size: 4 } }
|
||||
},
|
||||
body: {
|
||||
font: "Courier Prime", size: 11, color: "212121", align: 'both',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Courier Prime', monospace;
|
||||
h1 { font-family: 'Libre Baskerville', serif; font-size: 28pt; font-weight: 700; color: #000000; text-align: center; margin-bottom: 24px; text-transform: uppercase; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #000000; margin-top: 32px; margin-bottom: 16px; border-bottom: 1px solid #000; display: inline-block; padding-bottom: 2px; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #212121; margin-bottom: 14px; text-align: justify; }
|
||||
blockquote { border: 1px solid #000; padding: 20px; margin: 24px 0; font-size: 10pt; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'circuit-board',
|
||||
name: 'Circuit Board',
|
||||
category: 'Tech',
|
||||
description: 'PCB aesthetic. Deep forest green background with copper/gold tracks.',
|
||||
vibe: 'Tech, Green, Copper',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Share+Tech+Mono&family=Teko:wght@400;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Teko", size: 36, color: "FFD54F", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: { bottom: { color: "FFB300", space: 4, style: "dotted", size: 12 } }
|
||||
},
|
||||
heading2: {
|
||||
font: "Share Tech Mono", size: 16, color: "A5D6A7", bold: false, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Share Tech Mono", size: 11, color: "C8E6C9", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "FFD54F"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
background: #1B5E20;
|
||||
h1 { font-family: 'Teko', sans-serif; font-size: 36pt; font-weight: 700; color: #FFD54F; margin-bottom: 24px; border-bottom: 4px dotted #FFB300; }
|
||||
h2 { font-size: 16pt; color: #A5D6A7; margin-top: 32px; margin-bottom: 16px; text-transform: uppercase; }
|
||||
p { font-size: 11pt; line-height: 1.5; color: #C8E6C9; margin-bottom: 14px; }
|
||||
blockquote { border: 1px solid #FFD54F; padding: 16px; margin: 24px 0; color: #FFD54F; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'hologram-blue',
|
||||
name: 'Hologram Blue',
|
||||
category: 'Sci-Fi',
|
||||
description: 'Star Wars style communications. Translucent flickering blue text on dark voids.',
|
||||
vibe: 'Holographic, Futuristic, Translucent',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Audiowide&family=Rajdhani:wght@400;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Audiowide", size: 30, color: "00B0FF", bold: false, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "000000", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Rajdhani", size: 18, color: "80D8FF", bold: true, align: 'center',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Rajdhani", size: 12, color: "B3E5FC", align: 'center',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "00B0FF"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Rajdhani', sans-serif;
|
||||
background: #000000;
|
||||
h1 { font-family: 'Audiowide', cursive; font-size: 30pt; color: #00B0FF; text-align: center; margin-bottom: 24px; opacity: 0.8; text-shadow: 0 0 8px #00B0FF; }
|
||||
h2 { font-size: 18pt; font-weight: 700; color: #80D8FF; text-align: center; margin-top: 32px; margin-bottom: 16px; border-top: 1px solid #00B0FF; border-bottom: 1px solid #00B0FF; display: inline-block; padding: 5px 20px; }
|
||||
p { font-size: 12pt; line-height: 1.6; color: #B3E5FC; margin-bottom: 14px; text-align: center; opacity: 0.9; }
|
||||
blockquote { border: 1px dashed #00B0FF; padding: 16px; margin: 24px 0; color: #E1F5FE; text-align: center; }
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'biopunk-lab',
|
||||
name: 'Biopunk Lab',
|
||||
category: 'Sci-Fi',
|
||||
description: 'Organic technology. Slime greens, flesh tones, and rounded organic fonts.',
|
||||
vibe: 'Organic, Gross, Tech',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Creepster&family=Kodchasan:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Creepster", size: 32, color: "2E7D32", bold: false, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "C8E6C9", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Kodchasan", size: 18, color: "1B5E20", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
border: { bottom: { color: "2E7D32", space: 4, style: "wave", size: 12 } }
|
||||
},
|
||||
body: {
|
||||
font: "Kodchasan", size: 11, color: "33691E", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "2E7D32"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Kodchasan', sans-serif;
|
||||
h1 { font-family: 'Creepster', cursive; font-size: 32pt; color: #2E7D32; background: #C8E6C9; padding: 16px; border-radius: 20px; text-align: center; margin-bottom: 24px; }
|
||||
h2 { font-size: 18pt; font-weight: 700; color: #1B5E20; margin-top: 32px; margin-bottom: 16px; text-decoration: underline wavy #2E7D32; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #33691E; margin-bottom: 14px; }
|
||||
blockquote { background: #F1F8E9; border: 2px solid #2E7D32; border-radius: 16px; padding: 16px; margin: 24px 0; }
|
||||
`
|
||||
}
|
||||
];
|
||||
153
src/styles/templates/academic/academic-journal.ts
Normal file
153
src/styles/templates/academic/academic-journal.ts
Normal file
@@ -0,0 +1,153 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const academicJournal: StyleOption = {
|
||||
id: 'academic-journal',
|
||||
name: 'Academic Journal',
|
||||
category: 'Academic',
|
||||
description: 'Scholarly and rigorous design for academic papers and research publications. Traditional serif typography optimized for extended reading.',
|
||||
vibe: 'Scholarly, Serious, Traditional',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Libre+Baskerville:wght@400;700&family=Source+Sans+3:wght@400;600&display=swap',
|
||||
typography: {
|
||||
fonts: {
|
||||
heading: 'Libre Baskerville',
|
||||
body: 'Libre Baskerville',
|
||||
code: 'Source Sans 3'
|
||||
},
|
||||
colors: {
|
||||
text: '1A1A1A',
|
||||
textSecondary: '333333',
|
||||
background: 'FFFFFF',
|
||||
accent: '800000',
|
||||
border: '800000',
|
||||
codeBg: 'F5F5F5',
|
||||
blockquoteBorder: '333333'
|
||||
}
|
||||
},
|
||||
elements: {
|
||||
h1: {
|
||||
font: 'heading',
|
||||
size: 18,
|
||||
color: '000000',
|
||||
bold: true,
|
||||
align: 'center',
|
||||
spacing: { before: 18, after: 12, line: 1.2 }
|
||||
},
|
||||
h2: {
|
||||
font: 'heading',
|
||||
size: 13,
|
||||
color: '000000',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 14, after: 7, line: 1.2 }
|
||||
},
|
||||
h3: {
|
||||
font: 'heading',
|
||||
size: 12,
|
||||
color: '000000',
|
||||
bold: true,
|
||||
italic: true,
|
||||
align: 'left',
|
||||
spacing: { before: 12, after: 6, line: 1.2 }
|
||||
},
|
||||
h4: {
|
||||
font: 'heading',
|
||||
size: 11,
|
||||
color: '333333',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 10, after: 5, line: 1.2 }
|
||||
},
|
||||
h5: {
|
||||
font: 'heading',
|
||||
size: 10,
|
||||
color: '333333',
|
||||
bold: true,
|
||||
italic: true,
|
||||
align: 'left',
|
||||
spacing: { before: 8, after: 4, line: 1.2 }
|
||||
},
|
||||
h6: {
|
||||
font: 'heading',
|
||||
size: 10,
|
||||
color: '333333',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 6, after: 3, line: 1.2 }
|
||||
},
|
||||
p: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '1A1A1A',
|
||||
align: 'both',
|
||||
spacing: { before: 0, after: 7, line: 1.7 }
|
||||
},
|
||||
blockquote: {
|
||||
font: 'body',
|
||||
size: 9,
|
||||
color: '333333',
|
||||
spacing: { before: 10, after: 10, line: 1.5 },
|
||||
padding: 10,
|
||||
borderLeft: { color: '800000', width: 3, style: 'solid' }
|
||||
},
|
||||
code: {
|
||||
font: 'code',
|
||||
size: 9,
|
||||
color: '333333',
|
||||
background: 'F5F5F5'
|
||||
},
|
||||
pre: {
|
||||
font: 'code',
|
||||
size: 9,
|
||||
color: '333333',
|
||||
background: 'F5F5F5',
|
||||
spacing: { before: 12, after: 12, line: 1.4 },
|
||||
padding: 12
|
||||
},
|
||||
ul: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
ol: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
li: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '1A1A1A',
|
||||
spacing: { before: 4, after: 4, line: 1.5 }
|
||||
},
|
||||
strong: {
|
||||
bold: true
|
||||
},
|
||||
em: {
|
||||
italic: true
|
||||
},
|
||||
a: {
|
||||
color: '800000',
|
||||
underline: true
|
||||
},
|
||||
table: {
|
||||
spacing: { before: 12, after: 12, line: 1.4 }
|
||||
},
|
||||
th: {
|
||||
font: 'heading',
|
||||
size: 10,
|
||||
color: '000000',
|
||||
bold: true,
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
td: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '1A1A1A',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
hr: {
|
||||
border: { color: '800000', width: 1, style: 'single' },
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
},
|
||||
img: {
|
||||
align: 'center',
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
}
|
||||
}
|
||||
};
|
||||
157
src/styles/templates/academic/arctic-base.ts
Normal file
157
src/styles/templates/academic/arctic-base.ts
Normal file
@@ -0,0 +1,157 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const arcticBase: StyleOption = {
|
||||
id: 'arctic-base',
|
||||
name: 'Arctic Base',
|
||||
category: 'Scientific',
|
||||
description: 'Polar research station. Stark white and ice blues with minimal sterile typography.',
|
||||
vibe: 'Cold, Sterile, Blue',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Iceland&family=Roboto:wght@300;400&display=swap',
|
||||
typography: {
|
||||
fonts: {
|
||||
heading: 'Iceland',
|
||||
body: 'Roboto',
|
||||
code: 'Roboto'
|
||||
},
|
||||
colors: {
|
||||
text: '455A64',
|
||||
textSecondary: '78909C',
|
||||
background: 'FFFFFF',
|
||||
accent: '0288D1',
|
||||
border: '01579B',
|
||||
codeBg: 'E3F2FD',
|
||||
blockquoteBorder: '0277BD'
|
||||
}
|
||||
},
|
||||
elements: {
|
||||
h1: {
|
||||
font: 'heading',
|
||||
size: 36,
|
||||
color: '01579B',
|
||||
bold: false,
|
||||
align: 'left',
|
||||
background: 'E1F5FE',
|
||||
spacing: { before: 20, after: 10, line: 1.2 },
|
||||
borderLeft: { color: '01579B', width: 4, style: 'solid' },
|
||||
padding: 12
|
||||
},
|
||||
h2: {
|
||||
font: 'body',
|
||||
size: 18,
|
||||
color: '0277BD',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
allCaps: true,
|
||||
spacing: { before: 16, after: 8, line: 1.2 }
|
||||
},
|
||||
h3: {
|
||||
font: 'body',
|
||||
size: 16,
|
||||
color: '0288D1',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 14, after: 7, line: 1.2 }
|
||||
},
|
||||
h4: {
|
||||
font: 'body',
|
||||
size: 14,
|
||||
color: '0288D1',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 12, after: 6, line: 1.2 }
|
||||
},
|
||||
h5: {
|
||||
font: 'body',
|
||||
size: 12,
|
||||
color: '039BE5',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 10, after: 5, line: 1.2 }
|
||||
},
|
||||
h6: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '039BE5',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 8, after: 4, line: 1.2 }
|
||||
},
|
||||
p: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '455A64',
|
||||
align: 'left',
|
||||
spacing: { before: 0, after: 8, line: 1.6 }
|
||||
},
|
||||
blockquote: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '0277BD',
|
||||
spacing: { before: 12, after: 12, line: 1.5 },
|
||||
padding: 16,
|
||||
background: 'F0F8FF',
|
||||
border: { color: 'B3E5FC', width: 1, style: 'solid' }
|
||||
},
|
||||
code: {
|
||||
font: 'code',
|
||||
size: 10,
|
||||
color: '01579B',
|
||||
background: 'E3F2FD'
|
||||
},
|
||||
pre: {
|
||||
font: 'code',
|
||||
size: 10,
|
||||
color: '01579B',
|
||||
background: 'E3F2FD',
|
||||
spacing: { before: 12, after: 12, line: 1.4 },
|
||||
padding: 12
|
||||
},
|
||||
ul: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
ol: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
li: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '455A64',
|
||||
spacing: { before: 4, after: 4, line: 1.5 }
|
||||
},
|
||||
strong: {
|
||||
bold: true
|
||||
},
|
||||
em: {
|
||||
italic: true
|
||||
},
|
||||
a: {
|
||||
color: '0288D1',
|
||||
underline: true
|
||||
},
|
||||
table: {
|
||||
spacing: { before: 12, after: 12, line: 1.4 }
|
||||
},
|
||||
th: {
|
||||
font: 'heading',
|
||||
size: 11,
|
||||
color: '01579B',
|
||||
bold: true,
|
||||
background: 'E1F5FE',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
td: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '455A64',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
hr: {
|
||||
border: { color: '81D4FA', width: 2, style: 'single' },
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
},
|
||||
img: {
|
||||
align: 'center',
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
}
|
||||
}
|
||||
};
|
||||
156
src/styles/templates/academic/botanical-textbook.ts
Normal file
156
src/styles/templates/academic/botanical-textbook.ts
Normal file
@@ -0,0 +1,156 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const botanicalTextbook: StyleOption = {
|
||||
id: 'botanical-textbook',
|
||||
name: 'Botanical Textbook',
|
||||
category: 'Scientific',
|
||||
description: 'Vintage science textbook aesthetic. Academic yet organic, like a 19th-century flora guide.',
|
||||
vibe: 'Vintage, Scientific, Organic',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Alice&family=Gentium+Book+Basic:wght@400;700&display=swap',
|
||||
typography: {
|
||||
fonts: {
|
||||
heading: 'Alice',
|
||||
body: 'Gentium Book Basic',
|
||||
code: 'Gentium Book Basic'
|
||||
},
|
||||
colors: {
|
||||
text: '1B1B1B',
|
||||
textSecondary: '33691E',
|
||||
background: 'FFFFFF',
|
||||
accent: '827717',
|
||||
border: '827717',
|
||||
codeBg: 'F9FBE7',
|
||||
blockquoteBorder: '827717'
|
||||
}
|
||||
},
|
||||
elements: {
|
||||
h1: {
|
||||
font: 'heading',
|
||||
size: 28,
|
||||
color: '33691E',
|
||||
bold: false,
|
||||
align: 'left',
|
||||
spacing: { before: 20, after: 10, line: 1.2 },
|
||||
border: { color: '827717', width: 2, style: 'single' }
|
||||
},
|
||||
h2: {
|
||||
font: 'body',
|
||||
size: 14,
|
||||
color: '558B2F',
|
||||
bold: true,
|
||||
italic: true,
|
||||
align: 'left',
|
||||
spacing: { before: 15, after: 7.5, line: 1.2 }
|
||||
},
|
||||
h3: {
|
||||
font: 'body',
|
||||
size: 13,
|
||||
color: '558B2F',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 12, after: 6, line: 1.2 }
|
||||
},
|
||||
h4: {
|
||||
font: 'body',
|
||||
size: 12,
|
||||
color: '689F38',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 10, after: 5, line: 1.2 }
|
||||
},
|
||||
h5: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '689F38',
|
||||
bold: true,
|
||||
italic: true,
|
||||
align: 'left',
|
||||
spacing: { before: 8, after: 4, line: 1.2 }
|
||||
},
|
||||
h6: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '7CB342',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 6, after: 3, line: 1.2 }
|
||||
},
|
||||
p: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '1B1B1B',
|
||||
align: 'both',
|
||||
spacing: { before: 0, after: 8, line: 1.7 }
|
||||
},
|
||||
blockquote: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '33691E',
|
||||
spacing: { before: 10, after: 10, line: 1.5 },
|
||||
padding: 16,
|
||||
background: 'F9FBE7',
|
||||
borderLeft: { color: '827717', width: 4, style: 'solid' }
|
||||
},
|
||||
code: {
|
||||
font: 'code',
|
||||
size: 10,
|
||||
color: '33691E',
|
||||
background: 'F9FBE7'
|
||||
},
|
||||
pre: {
|
||||
font: 'code',
|
||||
size: 10,
|
||||
color: '33691E',
|
||||
background: 'F9FBE7',
|
||||
spacing: { before: 12, after: 12, line: 1.4 },
|
||||
padding: 12
|
||||
},
|
||||
ul: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
ol: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
li: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '1B1B1B',
|
||||
spacing: { before: 4, after: 4, line: 1.5 }
|
||||
},
|
||||
strong: {
|
||||
bold: true
|
||||
},
|
||||
em: {
|
||||
italic: true
|
||||
},
|
||||
a: {
|
||||
color: '558B2F',
|
||||
underline: true
|
||||
},
|
||||
table: {
|
||||
spacing: { before: 12, after: 12, line: 1.4 }
|
||||
},
|
||||
th: {
|
||||
font: 'heading',
|
||||
size: 11,
|
||||
color: '33691E',
|
||||
bold: true,
|
||||
background: 'F0F4C3',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
td: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '1B1B1B',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
hr: {
|
||||
border: { color: '827717', width: 1, style: 'single' },
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
},
|
||||
img: {
|
||||
align: 'center',
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
}
|
||||
}
|
||||
};
|
||||
153
src/styles/templates/academic/chemistry-lab.ts
Normal file
153
src/styles/templates/academic/chemistry-lab.ts
Normal file
@@ -0,0 +1,153 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const chemistryLab: StyleOption = {
|
||||
id: 'chemistry-lab',
|
||||
name: 'Chemistry Lab',
|
||||
category: 'Scientific',
|
||||
description: 'Clean, molecular design. Modern thin typography suitable for diagrams and formulas.',
|
||||
vibe: 'Scientific, Modern, Molecular',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Advent+Pro:wght@400;600;700&family=Heebo:wght@300;400;500&display=swap',
|
||||
typography: {
|
||||
fonts: {
|
||||
heading: 'Advent Pro',
|
||||
body: 'Heebo',
|
||||
code: 'Advent Pro'
|
||||
},
|
||||
colors: {
|
||||
text: '37474F',
|
||||
textSecondary: '546E7A',
|
||||
background: 'FFFFFF',
|
||||
accent: '00BCD4',
|
||||
border: '00BCD4',
|
||||
codeBg: 'E0F7FA',
|
||||
blockquoteBorder: '00BCD4'
|
||||
}
|
||||
},
|
||||
elements: {
|
||||
h1: {
|
||||
font: 'heading',
|
||||
size: 32,
|
||||
color: '00BCD4',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 20, after: 10, line: 1.2 }
|
||||
},
|
||||
h2: {
|
||||
font: 'body',
|
||||
size: 16,
|
||||
color: '0097A7',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 16, after: 8, line: 1.2 }
|
||||
},
|
||||
h3: {
|
||||
font: 'body',
|
||||
size: 14,
|
||||
color: '00838F',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 14, after: 7, line: 1.2 }
|
||||
},
|
||||
h4: {
|
||||
font: 'body',
|
||||
size: 12,
|
||||
color: '00838F',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 12, after: 6, line: 1.2 }
|
||||
},
|
||||
h5: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '006064',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 10, after: 5, line: 1.2 }
|
||||
},
|
||||
h6: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '006064',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 8, after: 4, line: 1.2 }
|
||||
},
|
||||
p: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '37474F',
|
||||
align: 'left',
|
||||
spacing: { before: 0, after: 8, line: 1.6 }
|
||||
},
|
||||
blockquote: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '0097A7',
|
||||
spacing: { before: 12, after: 12, line: 1.5 },
|
||||
padding: 16,
|
||||
background: 'E0F7FA',
|
||||
border: { color: '00BCD4', width: 1, style: 'solid' }
|
||||
},
|
||||
code: {
|
||||
font: 'code',
|
||||
size: 9,
|
||||
color: '00838F',
|
||||
background: 'E0F7FA'
|
||||
},
|
||||
pre: {
|
||||
font: 'code',
|
||||
size: 9,
|
||||
color: '00838F',
|
||||
background: 'E0F7FA',
|
||||
spacing: { before: 12, after: 12, line: 1.4 },
|
||||
padding: 12
|
||||
},
|
||||
ul: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
ol: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
li: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '37474F',
|
||||
spacing: { before: 4, after: 4, line: 1.5 }
|
||||
},
|
||||
strong: {
|
||||
bold: true
|
||||
},
|
||||
em: {
|
||||
italic: true
|
||||
},
|
||||
a: {
|
||||
color: '00BCD4',
|
||||
underline: true
|
||||
},
|
||||
table: {
|
||||
spacing: { before: 12, after: 12, line: 1.4 }
|
||||
},
|
||||
th: {
|
||||
font: 'heading',
|
||||
size: 10,
|
||||
color: '00BCD4',
|
||||
bold: true,
|
||||
background: 'E0F7FA',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
td: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '37474F',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
hr: {
|
||||
border: { color: 'B2EBF2', width: 2, style: 'single' },
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
},
|
||||
img: {
|
||||
align: 'center',
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
}
|
||||
}
|
||||
};
|
||||
156
src/styles/templates/academic/dark-academia.ts
Normal file
156
src/styles/templates/academic/dark-academia.ts
Normal file
@@ -0,0 +1,156 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const darkAcademia: StyleOption = {
|
||||
id: 'dark-academia',
|
||||
name: 'Dark Academia',
|
||||
category: 'Academic',
|
||||
description: 'Moody, literary aesthetic. Tweed textures, old libraries, and classic serif typography.',
|
||||
vibe: 'Moody, Scholarly, Literary',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Alegreya:wght@400;700&family=Alegreya+SC:wght@400;700&display=swap',
|
||||
typography: {
|
||||
fonts: {
|
||||
heading: 'Alegreya SC',
|
||||
body: 'Alegreya',
|
||||
code: 'Alegreya'
|
||||
},
|
||||
colors: {
|
||||
text: '212121',
|
||||
textSecondary: '4E342E',
|
||||
background: 'F5F1E8',
|
||||
accent: '5D4037',
|
||||
border: '5D4037',
|
||||
codeBg: 'EFEBE9',
|
||||
blockquoteBorder: '3E2723'
|
||||
}
|
||||
},
|
||||
elements: {
|
||||
h1: {
|
||||
font: 'heading',
|
||||
size: 28,
|
||||
color: '3E2723',
|
||||
bold: true,
|
||||
align: 'center',
|
||||
spacing: { before: 24, after: 14, line: 1.2 },
|
||||
border: { color: '5D4037', width: 4, style: 'double' }
|
||||
},
|
||||
h2: {
|
||||
font: 'body',
|
||||
size: 16,
|
||||
color: '4E342E',
|
||||
bold: true,
|
||||
italic: true,
|
||||
align: 'left',
|
||||
spacing: { before: 18, after: 9, line: 1.2 }
|
||||
},
|
||||
h3: {
|
||||
font: 'body',
|
||||
size: 14,
|
||||
color: '4E342E',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 15, after: 7.5, line: 1.2 }
|
||||
},
|
||||
h4: {
|
||||
font: 'body',
|
||||
size: 12,
|
||||
color: '5D4037',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 12, after: 6, line: 1.2 }
|
||||
},
|
||||
h5: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '5D4037',
|
||||
bold: true,
|
||||
italic: true,
|
||||
align: 'left',
|
||||
spacing: { before: 10, after: 5, line: 1.2 }
|
||||
},
|
||||
h6: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '6D4C41',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 8, after: 4, line: 1.2 }
|
||||
},
|
||||
p: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '212121',
|
||||
align: 'both',
|
||||
spacing: { before: 0, after: 9, line: 1.8 }
|
||||
},
|
||||
blockquote: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '4E342E',
|
||||
italic: true,
|
||||
spacing: { before: 14, after: 14, line: 1.6 },
|
||||
padding: 10,
|
||||
borderLeft: { color: '3E2723', width: 2, style: 'solid' }
|
||||
},
|
||||
code: {
|
||||
font: 'code',
|
||||
size: 10,
|
||||
color: '3E2723',
|
||||
background: 'EFEBE9'
|
||||
},
|
||||
pre: {
|
||||
font: 'code',
|
||||
size: 10,
|
||||
color: '3E2723',
|
||||
background: 'EFEBE9',
|
||||
spacing: { before: 12, after: 12, line: 1.4 },
|
||||
padding: 12
|
||||
},
|
||||
ul: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
ol: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
li: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '212121',
|
||||
spacing: { before: 4, after: 4, line: 1.5 }
|
||||
},
|
||||
strong: {
|
||||
bold: true
|
||||
},
|
||||
em: {
|
||||
italic: true
|
||||
},
|
||||
a: {
|
||||
color: '5D4037',
|
||||
underline: true
|
||||
},
|
||||
table: {
|
||||
spacing: { before: 12, after: 12, line: 1.4 }
|
||||
},
|
||||
th: {
|
||||
font: 'heading',
|
||||
size: 11,
|
||||
color: '3E2723',
|
||||
bold: true,
|
||||
background: 'EFEBE9',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
td: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '212121',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
hr: {
|
||||
border: { color: '5D4037', width: 2, style: 'single' },
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
},
|
||||
img: {
|
||||
align: 'center',
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
}
|
||||
}
|
||||
};
|
||||
156
src/styles/templates/academic/education-friendly.ts
Normal file
156
src/styles/templates/academic/education-friendly.ts
Normal file
@@ -0,0 +1,156 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const educationFriendly: StyleOption = {
|
||||
id: 'education-friendly',
|
||||
name: 'Education Friendly',
|
||||
category: 'Education',
|
||||
description: 'Approachable and clear design for educational materials. High readability with friendly colors suitable for learning environments.',
|
||||
vibe: 'Friendly, Educational, Accessible',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700&display=swap',
|
||||
typography: {
|
||||
fonts: {
|
||||
heading: 'Nunito',
|
||||
body: 'Nunito',
|
||||
code: 'Nunito'
|
||||
},
|
||||
colors: {
|
||||
text: '424242',
|
||||
textSecondary: '616161',
|
||||
background: 'FFFFFF',
|
||||
accent: '5E35B1',
|
||||
border: '7E57C2',
|
||||
codeBg: 'EDE7F6',
|
||||
blockquoteBorder: '7E57C2'
|
||||
}
|
||||
},
|
||||
elements: {
|
||||
h1: {
|
||||
font: 'heading',
|
||||
size: 24,
|
||||
color: '5E35B1',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
background: 'EDE7F6',
|
||||
spacing: { before: 20, after: 10, line: 1.2 },
|
||||
padding: 16,
|
||||
border: { color: 'D1C4E9', width: 1, style: 'solid' }
|
||||
},
|
||||
h2: {
|
||||
font: 'heading',
|
||||
size: 14,
|
||||
color: '7E57C2',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 15, after: 7.5, line: 1.2 }
|
||||
},
|
||||
h3: {
|
||||
font: 'heading',
|
||||
size: 13,
|
||||
color: '7E57C2',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 12, after: 6, line: 1.2 }
|
||||
},
|
||||
h4: {
|
||||
font: 'heading',
|
||||
size: 12,
|
||||
color: '9575CD',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 10, after: 5, line: 1.2 }
|
||||
},
|
||||
h5: {
|
||||
font: 'heading',
|
||||
size: 11,
|
||||
color: '9575CD',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 8, after: 4, line: 1.2 }
|
||||
},
|
||||
h6: {
|
||||
font: 'heading',
|
||||
size: 11,
|
||||
color: 'B39DDB',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 6, after: 3, line: 1.2 }
|
||||
},
|
||||
p: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '424242',
|
||||
align: 'left',
|
||||
spacing: { before: 0, after: 8, line: 1.7 }
|
||||
},
|
||||
blockquote: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '5E35B1',
|
||||
spacing: { before: 10, after: 10, line: 1.5 },
|
||||
padding: 16,
|
||||
background: 'F3E5F5',
|
||||
borderLeft: { color: '7E57C2', width: 4, style: 'solid' }
|
||||
},
|
||||
code: {
|
||||
font: 'code',
|
||||
size: 10,
|
||||
color: '5E35B1',
|
||||
background: 'EDE7F6'
|
||||
},
|
||||
pre: {
|
||||
font: 'code',
|
||||
size: 10,
|
||||
color: '5E35B1',
|
||||
background: 'EDE7F6',
|
||||
spacing: { before: 12, after: 12, line: 1.4 },
|
||||
padding: 12
|
||||
},
|
||||
ul: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
ol: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
li: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '424242',
|
||||
spacing: { before: 4, after: 4, line: 1.5 }
|
||||
},
|
||||
strong: {
|
||||
bold: true
|
||||
},
|
||||
em: {
|
||||
italic: true
|
||||
},
|
||||
a: {
|
||||
color: '5E35B1',
|
||||
underline: true
|
||||
},
|
||||
table: {
|
||||
spacing: { before: 12, after: 12, line: 1.4 }
|
||||
},
|
||||
th: {
|
||||
font: 'heading',
|
||||
size: 11,
|
||||
color: '5E35B1',
|
||||
bold: true,
|
||||
background: 'EDE7F6',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
td: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '424242',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
hr: {
|
||||
border: { color: 'D1C4E9', width: 2, style: 'single' },
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
},
|
||||
img: {
|
||||
align: 'center',
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
}
|
||||
}
|
||||
};
|
||||
155
src/styles/templates/academic/emergency-room.ts
Normal file
155
src/styles/templates/academic/emergency-room.ts
Normal file
@@ -0,0 +1,155 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const emergencyRoom: StyleOption = {
|
||||
id: 'emergency-room',
|
||||
name: 'Emergency Room',
|
||||
category: 'Medical',
|
||||
description: 'Hospital signage. Sterile white, urgent red, and clean blue.',
|
||||
vibe: 'Sterile, Urgent, Clean',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Assistant:wght@400;700&family=Heebo:wght@400;700&display=swap',
|
||||
typography: {
|
||||
fonts: {
|
||||
heading: 'Assistant',
|
||||
body: 'Heebo',
|
||||
code: 'Heebo'
|
||||
},
|
||||
colors: {
|
||||
text: '424242',
|
||||
textSecondary: '616161',
|
||||
background: 'FFFFFF',
|
||||
accent: 'D50000',
|
||||
border: 'D50000',
|
||||
codeBg: 'FFEBEE',
|
||||
blockquoteBorder: 'D50000'
|
||||
}
|
||||
},
|
||||
elements: {
|
||||
h1: {
|
||||
font: 'heading',
|
||||
size: 36,
|
||||
color: 'D50000',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 20, after: 10, line: 1.2 },
|
||||
border: { color: 'D50000', width: 4, style: 'single' }
|
||||
},
|
||||
h2: {
|
||||
font: 'body',
|
||||
size: 18,
|
||||
color: '2962FF',
|
||||
bold: true,
|
||||
allCaps: true,
|
||||
align: 'left',
|
||||
spacing: { before: 16, after: 8, line: 1.2 }
|
||||
},
|
||||
h3: {
|
||||
font: 'body',
|
||||
size: 15,
|
||||
color: '2962FF',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 14, after: 7, line: 1.2 }
|
||||
},
|
||||
h4: {
|
||||
font: 'body',
|
||||
size: 13,
|
||||
color: '2979FF',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 12, after: 6, line: 1.2 }
|
||||
},
|
||||
h5: {
|
||||
font: 'body',
|
||||
size: 12,
|
||||
color: '2979FF',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 10, after: 5, line: 1.2 }
|
||||
},
|
||||
h6: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '448AFF',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 8, after: 4, line: 1.2 }
|
||||
},
|
||||
p: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '424242',
|
||||
align: 'left',
|
||||
spacing: { before: 0, after: 8, line: 1.6 }
|
||||
},
|
||||
blockquote: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: 'D50000',
|
||||
spacing: { before: 12, after: 12, line: 1.5 },
|
||||
padding: 16,
|
||||
background: 'FFEBEE',
|
||||
borderLeft: { color: 'D50000', width: 6, style: 'solid' }
|
||||
},
|
||||
code: {
|
||||
font: 'code',
|
||||
size: 10,
|
||||
color: 'D50000',
|
||||
background: 'FFEBEE'
|
||||
},
|
||||
pre: {
|
||||
font: 'code',
|
||||
size: 10,
|
||||
color: 'D50000',
|
||||
background: 'FFEBEE',
|
||||
spacing: { before: 12, after: 12, line: 1.4 },
|
||||
padding: 12
|
||||
},
|
||||
ul: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
ol: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
li: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '424242',
|
||||
spacing: { before: 4, after: 4, line: 1.5 }
|
||||
},
|
||||
strong: {
|
||||
bold: true
|
||||
},
|
||||
em: {
|
||||
italic: true
|
||||
},
|
||||
a: {
|
||||
color: '2962FF',
|
||||
underline: true
|
||||
},
|
||||
table: {
|
||||
spacing: { before: 12, after: 12, line: 1.4 }
|
||||
},
|
||||
th: {
|
||||
font: 'heading',
|
||||
size: 11,
|
||||
color: 'D50000',
|
||||
bold: true,
|
||||
background: 'FFEBEE',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
td: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '424242',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
hr: {
|
||||
border: { color: 'EF5350', width: 3, style: 'single' },
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
},
|
||||
img: {
|
||||
align: 'center',
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
}
|
||||
}
|
||||
};
|
||||
157
src/styles/templates/academic/furniture-manual.ts
Normal file
157
src/styles/templates/academic/furniture-manual.ts
Normal file
@@ -0,0 +1,157 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const furnitureManual: StyleOption = {
|
||||
id: 'furniture-manual',
|
||||
name: 'Furniture Manual',
|
||||
category: 'Instructional',
|
||||
description: 'Flat-pack assembly guide. Clean, heavy line art vibes with friendly sans-serifs.',
|
||||
vibe: 'Clean, Instructional, Neutral',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Varela+Round&family=Hind:wght@300;600&display=swap',
|
||||
typography: {
|
||||
fonts: {
|
||||
heading: 'Varela Round',
|
||||
body: 'Hind',
|
||||
code: 'Hind'
|
||||
},
|
||||
colors: {
|
||||
text: '424242',
|
||||
textSecondary: '616161',
|
||||
background: 'FFFFFF',
|
||||
accent: '000000',
|
||||
border: '000000',
|
||||
codeBg: 'F5F5F5',
|
||||
blockquoteBorder: '000000'
|
||||
}
|
||||
},
|
||||
elements: {
|
||||
h1: {
|
||||
font: 'heading',
|
||||
size: 32,
|
||||
color: '000000',
|
||||
bold: false,
|
||||
align: 'left',
|
||||
spacing: { before: 20, after: 10, line: 1.2 }
|
||||
},
|
||||
h2: {
|
||||
font: 'heading',
|
||||
size: 16,
|
||||
color: '000000',
|
||||
bold: false,
|
||||
align: 'left',
|
||||
background: 'F5F5F5',
|
||||
spacing: { before: 16, after: 8, line: 1.2 },
|
||||
borderLeft: { color: '000000', width: 4, style: 'single' },
|
||||
border: { color: '000000', width: 2, style: 'single' },
|
||||
padding: 8
|
||||
},
|
||||
h3: {
|
||||
font: 'heading',
|
||||
size: 14,
|
||||
color: '000000',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 14, after: 7, line: 1.2 }
|
||||
},
|
||||
h4: {
|
||||
font: 'heading',
|
||||
size: 12,
|
||||
color: '212121',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 12, after: 6, line: 1.2 }
|
||||
},
|
||||
h5: {
|
||||
font: 'heading',
|
||||
size: 11,
|
||||
color: '424242',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 10, after: 5, line: 1.2 }
|
||||
},
|
||||
h6: {
|
||||
font: 'heading',
|
||||
size: 10,
|
||||
color: '616161',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 8, after: 4, line: 1.2 }
|
||||
},
|
||||
p: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '424242',
|
||||
align: 'left',
|
||||
spacing: { before: 0, after: 8, line: 1.6 }
|
||||
},
|
||||
blockquote: {
|
||||
font: 'heading',
|
||||
size: 12,
|
||||
color: '212121',
|
||||
spacing: { before: 12, after: 12, line: 1.5 },
|
||||
padding: 20,
|
||||
background: 'F5F5F5',
|
||||
border: { color: '000000', width: 2, style: 'single' }
|
||||
},
|
||||
code: {
|
||||
font: 'code',
|
||||
size: 10,
|
||||
color: '000000',
|
||||
background: 'F5F5F5'
|
||||
},
|
||||
pre: {
|
||||
font: 'code',
|
||||
size: 10,
|
||||
color: '000000',
|
||||
background: 'F5F5F5',
|
||||
spacing: { before: 12, after: 12, line: 1.4 },
|
||||
padding: 12
|
||||
},
|
||||
ul: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
ol: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
li: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '424242',
|
||||
spacing: { before: 4, after: 4, line: 1.5 }
|
||||
},
|
||||
strong: {
|
||||
bold: true
|
||||
},
|
||||
em: {
|
||||
italic: true
|
||||
},
|
||||
a: {
|
||||
color: '000000',
|
||||
underline: true
|
||||
},
|
||||
table: {
|
||||
spacing: { before: 12, after: 12, line: 1.4 }
|
||||
},
|
||||
th: {
|
||||
font: 'heading',
|
||||
size: 11,
|
||||
color: '000000',
|
||||
bold: true,
|
||||
background: 'F5F5F5',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
td: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '424242',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
hr: {
|
||||
border: { color: '000000', width: 2, style: 'single' },
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
},
|
||||
img: {
|
||||
align: 'center',
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
}
|
||||
}
|
||||
};
|
||||
154
src/styles/templates/academic/history-textbook.ts
Normal file
154
src/styles/templates/academic/history-textbook.ts
Normal file
@@ -0,0 +1,154 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const historyTextbook: StyleOption = {
|
||||
id: 'history-textbook',
|
||||
name: 'History Textbook',
|
||||
category: 'Academic',
|
||||
description: 'Classic textbook design. Sepia tones, distinct serif headers, and wide margins for notes.',
|
||||
vibe: 'Classic, Educational, Historical',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Goudy+Bookletter+1911&family=Sorts+Mill+Goudy&display=swap',
|
||||
typography: {
|
||||
fonts: {
|
||||
heading: 'Goudy Bookletter 1911',
|
||||
body: 'Sorts Mill Goudy',
|
||||
code: 'Sorts Mill Goudy'
|
||||
},
|
||||
colors: {
|
||||
text: '212121',
|
||||
textSecondary: '3E2723',
|
||||
background: 'FFF8E1',
|
||||
accent: '8D6E63',
|
||||
border: '8D6E63',
|
||||
codeBg: 'FFF3E0',
|
||||
blockquoteBorder: '8D6E63'
|
||||
}
|
||||
},
|
||||
elements: {
|
||||
h1: {
|
||||
font: 'heading',
|
||||
size: 28,
|
||||
color: '5D4037',
|
||||
bold: false,
|
||||
align: 'left',
|
||||
spacing: { before: 20, after: 10, line: 1.2 },
|
||||
border: { color: '8D6E63', width: 2, style: 'single' }
|
||||
},
|
||||
h2: {
|
||||
font: 'body',
|
||||
size: 16,
|
||||
color: '3E2723',
|
||||
bold: false,
|
||||
align: 'left',
|
||||
spacing: { before: 15, after: 7.5, line: 1.2 }
|
||||
},
|
||||
h3: {
|
||||
font: 'body',
|
||||
size: 14,
|
||||
color: '4E342E',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 12, after: 6, line: 1.2 }
|
||||
},
|
||||
h4: {
|
||||
font: 'body',
|
||||
size: 12,
|
||||
color: '5D4037',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 10, after: 5, line: 1.2 }
|
||||
},
|
||||
h5: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '6D4C41',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 8, after: 4, line: 1.2 }
|
||||
},
|
||||
h6: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '795548',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 6, after: 3, line: 1.2 }
|
||||
},
|
||||
p: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '212121',
|
||||
align: 'left',
|
||||
spacing: { before: 0, after: 8, line: 1.7 }
|
||||
},
|
||||
blockquote: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '3E2723',
|
||||
spacing: { before: 10, after: 10, line: 1.5 },
|
||||
padding: 16,
|
||||
background: 'FFFFFF',
|
||||
border: { color: '8D6E63', width: 1, style: 'single' }
|
||||
},
|
||||
code: {
|
||||
font: 'code',
|
||||
size: 10,
|
||||
color: '5D4037',
|
||||
background: 'FFF3E0'
|
||||
},
|
||||
pre: {
|
||||
font: 'code',
|
||||
size: 10,
|
||||
color: '5D4037',
|
||||
background: 'FFF3E0',
|
||||
spacing: { before: 12, after: 12, line: 1.4 },
|
||||
padding: 12
|
||||
},
|
||||
ul: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
ol: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
li: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '212121',
|
||||
spacing: { before: 4, after: 4, line: 1.5 }
|
||||
},
|
||||
strong: {
|
||||
bold: true
|
||||
},
|
||||
em: {
|
||||
italic: true
|
||||
},
|
||||
a: {
|
||||
color: '5D4037',
|
||||
underline: true
|
||||
},
|
||||
table: {
|
||||
spacing: { before: 12, after: 12, line: 1.4 }
|
||||
},
|
||||
th: {
|
||||
font: 'heading',
|
||||
size: 11,
|
||||
color: '5D4037',
|
||||
bold: true,
|
||||
background: 'FFF3E0',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
td: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '212121',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
hr: {
|
||||
border: { color: '8D6E63', width: 1, style: 'single' },
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
},
|
||||
img: {
|
||||
align: 'center',
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
}
|
||||
}
|
||||
};
|
||||
36
src/styles/templates/academic/index.ts
Normal file
36
src/styles/templates/academic/index.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
import { academicJournal } from './academic-journal';
|
||||
import { arcticBase } from './arctic-base';
|
||||
import { botanicalTextbook } from './botanical-textbook';
|
||||
import { chemistryLab } from './chemistry-lab';
|
||||
import { darkAcademia } from './dark-academia';
|
||||
import { educationFriendly } from './education-friendly';
|
||||
import { emergencyRoom } from './emergency-room';
|
||||
import { furnitureManual } from './furniture-manual';
|
||||
import { historyTextbook } from './history-textbook';
|
||||
import { kidsEducation } from './kids-education';
|
||||
import { mathematicsPaper } from './mathematics-paper';
|
||||
import { medicalProfessional } from './medical-professional';
|
||||
import { phdThesis } from './phd-thesis';
|
||||
import { scantronTest } from './scantron-test';
|
||||
import { scientificJournal } from './scientific-journal';
|
||||
import { weatherRadar } from './weather-radar';
|
||||
|
||||
export const academicStyles: StyleOption[] = [
|
||||
academicJournal,
|
||||
arcticBase,
|
||||
botanicalTextbook,
|
||||
chemistryLab,
|
||||
darkAcademia,
|
||||
educationFriendly,
|
||||
emergencyRoom,
|
||||
furnitureManual,
|
||||
historyTextbook,
|
||||
kidsEducation,
|
||||
mathematicsPaper,
|
||||
medicalProfessional,
|
||||
phdThesis,
|
||||
scantronTest,
|
||||
scientificJournal,
|
||||
weatherRadar
|
||||
];
|
||||
156
src/styles/templates/academic/kids-education.ts
Normal file
156
src/styles/templates/academic/kids-education.ts
Normal file
@@ -0,0 +1,156 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const kidsEducation: StyleOption = {
|
||||
id: 'kids-education',
|
||||
name: 'Kids Education',
|
||||
category: 'Education',
|
||||
description: 'Fun and engaging design for children\'s educational content. Rounded typography with bright, cheerful colors.',
|
||||
vibe: 'Educational, Fun, Engaging',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Fredoka:wght@400;500;600&display=swap',
|
||||
typography: {
|
||||
fonts: {
|
||||
heading: 'Fredoka',
|
||||
body: 'Fredoka',
|
||||
code: 'Fredoka'
|
||||
},
|
||||
colors: {
|
||||
text: '495057',
|
||||
textSecondary: '6C757D',
|
||||
background: 'FFFFFF',
|
||||
accent: 'FF6B6B',
|
||||
border: 'FF6B6B',
|
||||
codeBg: 'FFF9DB',
|
||||
blockquoteBorder: '4ECDC4'
|
||||
}
|
||||
},
|
||||
elements: {
|
||||
h1: {
|
||||
font: 'heading',
|
||||
size: 32,
|
||||
color: 'FF6B6B',
|
||||
bold: true,
|
||||
align: 'center',
|
||||
background: 'FFF9DB',
|
||||
spacing: { before: 20, after: 12, line: 1.2 },
|
||||
padding: 16,
|
||||
border: { color: 'FFE066', width: 2, style: 'solid' }
|
||||
},
|
||||
h2: {
|
||||
font: 'heading',
|
||||
size: 18,
|
||||
color: '4ECDC4',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 16, after: 8, line: 1.2 }
|
||||
},
|
||||
h3: {
|
||||
font: 'heading',
|
||||
size: 15,
|
||||
color: '45B7D1',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 14, after: 7, line: 1.2 }
|
||||
},
|
||||
h4: {
|
||||
font: 'heading',
|
||||
size: 13,
|
||||
color: '45B7D1',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 12, after: 6, line: 1.2 }
|
||||
},
|
||||
h5: {
|
||||
font: 'heading',
|
||||
size: 12,
|
||||
color: '96CEB4',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 10, after: 5, line: 1.2 }
|
||||
},
|
||||
h6: {
|
||||
font: 'heading',
|
||||
size: 11,
|
||||
color: '96CEB4',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 8, after: 4, line: 1.2 }
|
||||
},
|
||||
p: {
|
||||
font: 'body',
|
||||
size: 12,
|
||||
color: '495057',
|
||||
align: 'left',
|
||||
spacing: { before: 0, after: 9, line: 1.8 }
|
||||
},
|
||||
blockquote: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '4ECDC4',
|
||||
spacing: { before: 10, after: 10, line: 1.6 },
|
||||
padding: 16,
|
||||
background: 'E3F9F8',
|
||||
borderLeft: { color: '4ECDC4', width: 6, style: 'solid' }
|
||||
},
|
||||
code: {
|
||||
font: 'code',
|
||||
size: 11,
|
||||
color: 'FF6B6B',
|
||||
background: 'FFF9DB'
|
||||
},
|
||||
pre: {
|
||||
font: 'code',
|
||||
size: 11,
|
||||
color: 'FF6B6B',
|
||||
background: 'FFF9DB',
|
||||
spacing: { before: 12, after: 12, line: 1.4 },
|
||||
padding: 12
|
||||
},
|
||||
ul: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
ol: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
li: {
|
||||
font: 'body',
|
||||
size: 12,
|
||||
color: '495057',
|
||||
spacing: { before: 4, after: 4, line: 1.5 }
|
||||
},
|
||||
strong: {
|
||||
bold: true
|
||||
},
|
||||
em: {
|
||||
italic: true
|
||||
},
|
||||
a: {
|
||||
color: 'FF6B6B',
|
||||
underline: true
|
||||
},
|
||||
table: {
|
||||
spacing: { before: 12, after: 12, line: 1.4 }
|
||||
},
|
||||
th: {
|
||||
font: 'heading',
|
||||
size: 12,
|
||||
color: 'FF6B6B',
|
||||
bold: true,
|
||||
background: 'FFF9DB',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
td: {
|
||||
font: 'body',
|
||||
size: 12,
|
||||
color: '495057',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
hr: {
|
||||
border: { color: 'FFE066', width: 3, style: 'single' },
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
},
|
||||
img: {
|
||||
align: 'center',
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
}
|
||||
}
|
||||
};
|
||||
154
src/styles/templates/academic/mathematics-paper.ts
Normal file
154
src/styles/templates/academic/mathematics-paper.ts
Normal file
@@ -0,0 +1,154 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const mathematicsPaper: StyleOption = {
|
||||
id: 'mathematics-paper',
|
||||
name: 'Mathematics Paper',
|
||||
category: 'Academic',
|
||||
description: 'Inspired by LaTeX and Computer Modern. Serif-heavy, precise, and highly legible for academic rigor.',
|
||||
vibe: 'Academic, Rigorous, Formal',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Domine:wght@400;700&family=Noticia+Text:wght@400;700&display=swap',
|
||||
typography: {
|
||||
fonts: {
|
||||
heading: 'Domine',
|
||||
body: 'Noticia Text',
|
||||
code: 'Noticia Text'
|
||||
},
|
||||
colors: {
|
||||
text: '212121',
|
||||
textSecondary: '424242',
|
||||
background: 'FFFFFF',
|
||||
accent: '000000',
|
||||
border: '000000',
|
||||
codeBg: 'F5F5F5',
|
||||
blockquoteBorder: '000000'
|
||||
}
|
||||
},
|
||||
elements: {
|
||||
h1: {
|
||||
font: 'heading',
|
||||
size: 24,
|
||||
color: '000000',
|
||||
bold: true,
|
||||
align: 'center',
|
||||
spacing: { before: 20, after: 12, line: 1.2 }
|
||||
},
|
||||
h2: {
|
||||
font: 'heading',
|
||||
size: 14,
|
||||
color: '000000',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 16, after: 8, line: 1.2 }
|
||||
},
|
||||
h3: {
|
||||
font: 'heading',
|
||||
size: 12,
|
||||
color: '000000',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 14, after: 7, line: 1.2 }
|
||||
},
|
||||
h4: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '212121',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 12, after: 6, line: 1.2 }
|
||||
},
|
||||
h5: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '424242',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 10, after: 5, line: 1.2 }
|
||||
},
|
||||
h6: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '616161',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 8, after: 4, line: 1.2 }
|
||||
},
|
||||
p: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '212121',
|
||||
align: 'both',
|
||||
spacing: { before: 0, after: 8, line: 1.6 }
|
||||
},
|
||||
blockquote: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '212121',
|
||||
italic: true,
|
||||
spacing: { before: 12, after: 12, line: 1.5 },
|
||||
padding: 10,
|
||||
background: 'F5F5F5',
|
||||
borderLeft: { color: '000000', width: 3, style: 'solid' }
|
||||
},
|
||||
code: {
|
||||
font: 'code',
|
||||
size: 10,
|
||||
color: '000000',
|
||||
background: 'F5F5F5'
|
||||
},
|
||||
pre: {
|
||||
font: 'code',
|
||||
size: 10,
|
||||
color: '000000',
|
||||
background: 'F5F5F5',
|
||||
spacing: { before: 12, after: 12, line: 1.4 },
|
||||
padding: 12
|
||||
},
|
||||
ul: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
ol: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
li: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '212121',
|
||||
spacing: { before: 4, after: 4, line: 1.5 }
|
||||
},
|
||||
strong: {
|
||||
bold: true
|
||||
},
|
||||
em: {
|
||||
italic: true
|
||||
},
|
||||
a: {
|
||||
color: '000000',
|
||||
underline: true
|
||||
},
|
||||
table: {
|
||||
spacing: { before: 12, after: 12, line: 1.4 }
|
||||
},
|
||||
th: {
|
||||
font: 'heading',
|
||||
size: 11,
|
||||
color: '000000',
|
||||
bold: true,
|
||||
background: 'F5F5F5',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
td: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '212121',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
hr: {
|
||||
border: { color: '000000', width: 1, style: 'single' },
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
},
|
||||
img: {
|
||||
align: 'center',
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
}
|
||||
}
|
||||
};
|
||||
153
src/styles/templates/academic/medical-professional.ts
Normal file
153
src/styles/templates/academic/medical-professional.ts
Normal file
@@ -0,0 +1,153 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const medicalProfessional: StyleOption = {
|
||||
id: 'medical-professional',
|
||||
name: 'Medical Professional',
|
||||
category: 'Healthcare',
|
||||
description: 'Clean, clinical design for healthcare and medical documentation. Emphasizes clarity and professionalism with calming blue accents.',
|
||||
vibe: 'Clinical, Professional, Trustworthy',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600;700&display=swap',
|
||||
typography: {
|
||||
fonts: {
|
||||
heading: 'Open Sans',
|
||||
body: 'Open Sans',
|
||||
code: 'Open Sans'
|
||||
},
|
||||
colors: {
|
||||
text: '37474F',
|
||||
textSecondary: '546E7A',
|
||||
background: 'FFFFFF',
|
||||
accent: '1565C0',
|
||||
border: '0D47A1',
|
||||
codeBg: 'E3F2FD',
|
||||
blockquoteBorder: '1565C0'
|
||||
}
|
||||
},
|
||||
elements: {
|
||||
h1: {
|
||||
font: 'heading',
|
||||
size: 20,
|
||||
color: '1565C0',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 18, after: 10, line: 1.2 }
|
||||
},
|
||||
h2: {
|
||||
font: 'heading',
|
||||
size: 13,
|
||||
color: '0D47A1',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 14, after: 7, line: 1.2 }
|
||||
},
|
||||
h3: {
|
||||
font: 'heading',
|
||||
size: 12,
|
||||
color: '1565C0',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 12, after: 6, line: 1.2 }
|
||||
},
|
||||
h4: {
|
||||
font: 'heading',
|
||||
size: 11,
|
||||
color: '1976D2',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 10, after: 5, line: 1.2 }
|
||||
},
|
||||
h5: {
|
||||
font: 'heading',
|
||||
size: 10,
|
||||
color: '1976D2',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 8, after: 4, line: 1.2 }
|
||||
},
|
||||
h6: {
|
||||
font: 'heading',
|
||||
size: 10,
|
||||
color: '2196F3',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 6, after: 3, line: 1.2 }
|
||||
},
|
||||
p: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '37474F',
|
||||
align: 'left',
|
||||
spacing: { before: 0, after: 8, line: 1.6 }
|
||||
},
|
||||
blockquote: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '1565C0',
|
||||
spacing: { before: 10, after: 10, line: 1.5 },
|
||||
padding: 16,
|
||||
background: 'E3F2FD',
|
||||
borderLeft: { color: '1565C0', width: 4, style: 'solid' }
|
||||
},
|
||||
code: {
|
||||
font: 'code',
|
||||
size: 9,
|
||||
color: '0D47A1',
|
||||
background: 'E3F2FD'
|
||||
},
|
||||
pre: {
|
||||
font: 'code',
|
||||
size: 9,
|
||||
color: '0D47A1',
|
||||
background: 'E3F2FD',
|
||||
spacing: { before: 12, after: 12, line: 1.4 },
|
||||
padding: 12
|
||||
},
|
||||
ul: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
ol: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
li: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '37474F',
|
||||
spacing: { before: 4, after: 4, line: 1.5 }
|
||||
},
|
||||
strong: {
|
||||
bold: true
|
||||
},
|
||||
em: {
|
||||
italic: true
|
||||
},
|
||||
a: {
|
||||
color: '1565C0',
|
||||
underline: true
|
||||
},
|
||||
table: {
|
||||
spacing: { before: 12, after: 12, line: 1.4 }
|
||||
},
|
||||
th: {
|
||||
font: 'heading',
|
||||
size: 10,
|
||||
color: '1565C0',
|
||||
bold: true,
|
||||
background: 'E3F2FD',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
td: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '37474F',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
hr: {
|
||||
border: { color: '90CAF9', width: 1, style: 'single' },
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
},
|
||||
img: {
|
||||
align: 'center',
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
}
|
||||
}
|
||||
};
|
||||
154
src/styles/templates/academic/phd-thesis.ts
Normal file
154
src/styles/templates/academic/phd-thesis.ts
Normal file
@@ -0,0 +1,154 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const phdThesis: StyleOption = {
|
||||
id: 'phd-thesis',
|
||||
name: 'PhD Thesis',
|
||||
category: 'Academic',
|
||||
description: 'The pinnacle of academic formatting. Extremely legible serif body, double spacing, and rigorous margin structure.',
|
||||
vibe: 'Formal, Scholarly, Prestigious',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Tinos:wght@400;700&family=Crimson+Text:wght@400;600&display=swap',
|
||||
typography: {
|
||||
fonts: {
|
||||
heading: 'Tinos',
|
||||
body: 'Crimson Text',
|
||||
code: 'Crimson Text'
|
||||
},
|
||||
colors: {
|
||||
text: '000000',
|
||||
textSecondary: '424242',
|
||||
background: 'FFFFFF',
|
||||
accent: '000000',
|
||||
border: '000000',
|
||||
codeBg: 'F5F5F5',
|
||||
blockquoteBorder: '000000'
|
||||
}
|
||||
},
|
||||
elements: {
|
||||
h1: {
|
||||
font: 'heading',
|
||||
size: 24,
|
||||
color: '000000',
|
||||
bold: true,
|
||||
allCaps: true,
|
||||
align: 'center',
|
||||
spacing: { before: 24, after: 12, line: 1.2 }
|
||||
},
|
||||
h2: {
|
||||
font: 'heading',
|
||||
size: 14,
|
||||
color: '000000',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 12, after: 6, line: 1.2 }
|
||||
},
|
||||
h3: {
|
||||
font: 'heading',
|
||||
size: 12,
|
||||
color: '000000',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 12, after: 6, line: 1.2 }
|
||||
},
|
||||
h4: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '212121',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 10, after: 5, line: 1.2 }
|
||||
},
|
||||
h5: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '424242',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 8, after: 4, line: 1.2 }
|
||||
},
|
||||
h6: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '616161',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 6, after: 3, line: 1.2 }
|
||||
},
|
||||
p: {
|
||||
font: 'body',
|
||||
size: 12,
|
||||
color: '000000',
|
||||
align: 'both',
|
||||
spacing: { before: 0, after: 0, line: 2.0 }
|
||||
},
|
||||
blockquote: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: '000000',
|
||||
italic: true,
|
||||
spacing: { before: 12, after: 12, line: 2.0 },
|
||||
padding: 10,
|
||||
indent: 40
|
||||
},
|
||||
code: {
|
||||
font: 'code',
|
||||
size: 11,
|
||||
color: '000000',
|
||||
background: 'F5F5F5'
|
||||
},
|
||||
pre: {
|
||||
font: 'code',
|
||||
size: 11,
|
||||
color: '000000',
|
||||
background: 'F5F5F5',
|
||||
spacing: { before: 12, after: 12, line: 1.4 },
|
||||
padding: 12
|
||||
},
|
||||
ul: {
|
||||
spacing: { before: 8, after: 8, line: 2.0 }
|
||||
},
|
||||
ol: {
|
||||
spacing: { before: 8, after: 8, line: 2.0 }
|
||||
},
|
||||
li: {
|
||||
font: 'body',
|
||||
size: 12,
|
||||
color: '000000',
|
||||
spacing: { before: 4, after: 4, line: 2.0 }
|
||||
},
|
||||
strong: {
|
||||
bold: true
|
||||
},
|
||||
em: {
|
||||
italic: true
|
||||
},
|
||||
a: {
|
||||
color: '000000',
|
||||
underline: true
|
||||
},
|
||||
table: {
|
||||
spacing: { before: 12, after: 12, line: 1.4 }
|
||||
},
|
||||
th: {
|
||||
font: 'heading',
|
||||
size: 12,
|
||||
color: '000000',
|
||||
bold: true,
|
||||
background: 'F5F5F5',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
td: {
|
||||
font: 'body',
|
||||
size: 12,
|
||||
color: '000000',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
hr: {
|
||||
border: { color: '000000', width: 1, style: 'single' },
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
},
|
||||
img: {
|
||||
align: 'center',
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
}
|
||||
}
|
||||
};
|
||||
156
src/styles/templates/academic/scantron-test.ts
Normal file
156
src/styles/templates/academic/scantron-test.ts
Normal file
@@ -0,0 +1,156 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const scantronTest: StyleOption = {
|
||||
id: 'scantron-test',
|
||||
name: 'Scantron Test',
|
||||
category: 'Academic',
|
||||
description: 'Standardized testing sheet. Salmon pinks and greens with bubble-filling aesthetics.',
|
||||
vibe: 'Academic, Retro, Bureaucratic',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400;700&display=swap',
|
||||
typography: {
|
||||
fonts: {
|
||||
heading: 'Roboto Mono',
|
||||
body: 'Roboto Mono',
|
||||
code: 'Roboto Mono'
|
||||
},
|
||||
colors: {
|
||||
text: '212121',
|
||||
textSecondary: '424242',
|
||||
background: 'FFF3E0',
|
||||
accent: 'EF5350',
|
||||
border: 'B71C1C',
|
||||
codeBg: 'FFEBEE',
|
||||
blockquoteBorder: 'B71C1C'
|
||||
}
|
||||
},
|
||||
elements: {
|
||||
h1: {
|
||||
font: 'heading',
|
||||
size: 28,
|
||||
color: 'B71C1C',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 20, after: 10, line: 1.2 },
|
||||
border: { color: 'EF5350', width: 2, style: 'single' }
|
||||
},
|
||||
h2: {
|
||||
font: 'heading',
|
||||
size: 14,
|
||||
color: '1B5E20',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
background: 'C8E6C9',
|
||||
spacing: { before: 16, after: 8, line: 1.2 },
|
||||
padding: 4
|
||||
},
|
||||
h3: {
|
||||
font: 'heading',
|
||||
size: 12,
|
||||
color: '2E7D32',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 14, after: 7, line: 1.2 }
|
||||
},
|
||||
h4: {
|
||||
font: 'heading',
|
||||
size: 11,
|
||||
color: '388E3C',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 12, after: 6, line: 1.2 }
|
||||
},
|
||||
h5: {
|
||||
font: 'heading',
|
||||
size: 10,
|
||||
color: '43A047',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 10, after: 5, line: 1.2 }
|
||||
},
|
||||
h6: {
|
||||
font: 'heading',
|
||||
size: 10,
|
||||
color: '4CAF50',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 8, after: 4, line: 1.2 }
|
||||
},
|
||||
p: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '212121',
|
||||
align: 'left',
|
||||
spacing: { before: 0, after: 8, line: 1.6 }
|
||||
},
|
||||
blockquote: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: 'B71C1C',
|
||||
spacing: { before: 12, after: 12, line: 1.5 },
|
||||
padding: 16,
|
||||
background: 'FFEBEE',
|
||||
border: { color: 'B71C1C', width: 1, style: 'solid' }
|
||||
},
|
||||
code: {
|
||||
font: 'code',
|
||||
size: 9,
|
||||
color: 'B71C1C',
|
||||
background: 'FFEBEE'
|
||||
},
|
||||
pre: {
|
||||
font: 'code',
|
||||
size: 9,
|
||||
color: 'B71C1C',
|
||||
background: 'FFEBEE',
|
||||
spacing: { before: 12, after: 12, line: 1.4 },
|
||||
padding: 12
|
||||
},
|
||||
ul: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
ol: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
li: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '212121',
|
||||
spacing: { before: 4, after: 4, line: 1.5 }
|
||||
},
|
||||
strong: {
|
||||
bold: true
|
||||
},
|
||||
em: {
|
||||
italic: true
|
||||
},
|
||||
a: {
|
||||
color: 'B71C1C',
|
||||
underline: true
|
||||
},
|
||||
table: {
|
||||
spacing: { before: 12, after: 12, line: 1.4 }
|
||||
},
|
||||
th: {
|
||||
font: 'heading',
|
||||
size: 10,
|
||||
color: 'B71C1C',
|
||||
bold: true,
|
||||
background: 'FFEBEE',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
td: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '212121',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
hr: {
|
||||
border: { color: 'EF5350', width: 2, style: 'single' },
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
},
|
||||
img: {
|
||||
align: 'center',
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
}
|
||||
}
|
||||
};
|
||||
152
src/styles/templates/academic/scientific-journal.ts
Normal file
152
src/styles/templates/academic/scientific-journal.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const scientificJournal: StyleOption = {
|
||||
id: 'scientific-journal',
|
||||
name: 'Scientific Journal',
|
||||
category: 'Academic',
|
||||
description: 'Precise design for scientific publications. Clear hierarchy optimized for data-heavy content and citations.',
|
||||
vibe: 'Scientific, Precise, Academic',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Literata:wght@400;500;700&family=Fira+Sans:wght@400;500;600&display=swap',
|
||||
typography: {
|
||||
fonts: {
|
||||
heading: 'Literata',
|
||||
body: 'Literata',
|
||||
code: 'Fira Sans'
|
||||
},
|
||||
colors: {
|
||||
text: '262626',
|
||||
textSecondary: '4A4A4A',
|
||||
background: 'FFFFFF',
|
||||
accent: '0066CC',
|
||||
border: '0066CC',
|
||||
codeBg: 'F5F5F5',
|
||||
blockquoteBorder: '0066CC'
|
||||
}
|
||||
},
|
||||
elements: {
|
||||
h1: {
|
||||
font: 'heading',
|
||||
size: 18,
|
||||
color: '1A1A1A',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 18, after: 10, line: 1.3 }
|
||||
},
|
||||
h2: {
|
||||
font: 'code',
|
||||
size: 12,
|
||||
color: '1A1A1A',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 14, after: 6, line: 1.2 }
|
||||
},
|
||||
h3: {
|
||||
font: 'code',
|
||||
size: 11,
|
||||
color: '262626',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 12, after: 6, line: 1.2 }
|
||||
},
|
||||
h4: {
|
||||
font: 'code',
|
||||
size: 10,
|
||||
color: '333333',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 10, after: 5, line: 1.2 }
|
||||
},
|
||||
h5: {
|
||||
font: 'code',
|
||||
size: 10,
|
||||
color: '424242',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 8, after: 4, line: 1.2 }
|
||||
},
|
||||
h6: {
|
||||
font: 'code',
|
||||
size: 9,
|
||||
color: '4A4A4A',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 6, after: 3, line: 1.2 }
|
||||
},
|
||||
p: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '262626',
|
||||
align: 'both',
|
||||
spacing: { before: 0, after: 7, line: 1.6 }
|
||||
},
|
||||
blockquote: {
|
||||
font: 'body',
|
||||
size: 9,
|
||||
color: '4A4A4A',
|
||||
spacing: { before: 8, after: 8, line: 1.4 },
|
||||
padding: 10,
|
||||
borderLeft: { color: '0066CC', width: 2, style: 'solid' }
|
||||
},
|
||||
code: {
|
||||
font: 'code',
|
||||
size: 9,
|
||||
color: '0066CC',
|
||||
background: 'F5F5F5'
|
||||
},
|
||||
pre: {
|
||||
font: 'code',
|
||||
size: 9,
|
||||
color: '0066CC',
|
||||
background: 'F5F5F5',
|
||||
spacing: { before: 12, after: 12, line: 1.4 },
|
||||
padding: 12
|
||||
},
|
||||
ul: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
ol: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
li: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '262626',
|
||||
spacing: { before: 4, after: 4, line: 1.5 }
|
||||
},
|
||||
strong: {
|
||||
bold: true
|
||||
},
|
||||
em: {
|
||||
italic: true
|
||||
},
|
||||
a: {
|
||||
color: '0066CC',
|
||||
underline: true
|
||||
},
|
||||
table: {
|
||||
spacing: { before: 12, after: 12, line: 1.4 }
|
||||
},
|
||||
th: {
|
||||
font: 'heading',
|
||||
size: 10,
|
||||
color: '1A1A1A',
|
||||
bold: true,
|
||||
background: 'F5F5F5',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
td: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: '262626',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
hr: {
|
||||
border: { color: '0066CC', width: 1, style: 'single' },
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
},
|
||||
img: {
|
||||
align: 'center',
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
}
|
||||
}
|
||||
};
|
||||
159
src/styles/templates/academic/weather-radar.ts
Normal file
159
src/styles/templates/academic/weather-radar.ts
Normal file
@@ -0,0 +1,159 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const weatherRadar: StyleOption = {
|
||||
id: 'weather-radar',
|
||||
name: 'Weather Radar',
|
||||
category: 'Scientific',
|
||||
description: 'Meteorological map aesthetic. Deep map green backgrounds with rainbow radar text colors.',
|
||||
vibe: 'Scientific, Map, Storm',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Chakra+Petch:wght@400;700&family=Sarpanch:wght@400;700&display=swap',
|
||||
typography: {
|
||||
fonts: {
|
||||
heading: 'Chakra Petch',
|
||||
body: 'Chakra Petch',
|
||||
code: 'Sarpanch'
|
||||
},
|
||||
colors: {
|
||||
text: 'E0F2F1',
|
||||
textSecondary: 'B2DFDB',
|
||||
background: '455A64',
|
||||
accent: 'FF1744',
|
||||
border: 'FF1744',
|
||||
codeBg: '37474F',
|
||||
blockquoteBorder: 'FFEA00'
|
||||
}
|
||||
},
|
||||
elements: {
|
||||
h1: {
|
||||
font: 'heading',
|
||||
size: 32,
|
||||
color: 'FF1744',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
background: '263238',
|
||||
spacing: { before: 20, after: 10, line: 1.2 },
|
||||
borderLeft: { color: 'FF1744', width: 8, style: 'solid' },
|
||||
padding: 16
|
||||
},
|
||||
h2: {
|
||||
font: 'code',
|
||||
size: 16,
|
||||
color: '00E676',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
background: '37474F',
|
||||
spacing: { before: 16, after: 8, line: 1.2 },
|
||||
padding: 8
|
||||
},
|
||||
h3: {
|
||||
font: 'code',
|
||||
size: 14,
|
||||
color: '69F0AE',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 14, after: 7, line: 1.2 }
|
||||
},
|
||||
h4: {
|
||||
font: 'code',
|
||||
size: 12,
|
||||
color: '69F0AE',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 12, after: 6, line: 1.2 }
|
||||
},
|
||||
h5: {
|
||||
font: 'code',
|
||||
size: 11,
|
||||
color: 'B9F6CA',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 10, after: 5, line: 1.2 }
|
||||
},
|
||||
h6: {
|
||||
font: 'code',
|
||||
size: 10,
|
||||
color: 'B9F6CA',
|
||||
bold: true,
|
||||
align: 'left',
|
||||
spacing: { before: 8, after: 4, line: 1.2 }
|
||||
},
|
||||
p: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: 'E0F2F1',
|
||||
align: 'left',
|
||||
spacing: { before: 0, after: 8, line: 1.5 }
|
||||
},
|
||||
blockquote: {
|
||||
font: 'body',
|
||||
size: 10,
|
||||
color: 'FFEA00',
|
||||
spacing: { before: 12, after: 12, line: 1.5 },
|
||||
padding: 16,
|
||||
background: '263238',
|
||||
border: { color: 'FFEA00', width: 2, style: 'solid' }
|
||||
},
|
||||
code: {
|
||||
font: 'code',
|
||||
size: 10,
|
||||
color: 'FFEA00',
|
||||
background: '37474F'
|
||||
},
|
||||
pre: {
|
||||
font: 'code',
|
||||
size: 10,
|
||||
color: 'FFEA00',
|
||||
background: '37474F',
|
||||
spacing: { before: 12, after: 12, line: 1.4 },
|
||||
padding: 12
|
||||
},
|
||||
ul: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
ol: {
|
||||
spacing: { before: 8, after: 8, line: 1.5 }
|
||||
},
|
||||
li: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: 'E0F2F1',
|
||||
spacing: { before: 4, after: 4, line: 1.5 }
|
||||
},
|
||||
strong: {
|
||||
bold: true
|
||||
},
|
||||
em: {
|
||||
italic: true
|
||||
},
|
||||
a: {
|
||||
color: 'FFEA00',
|
||||
underline: true
|
||||
},
|
||||
table: {
|
||||
spacing: { before: 12, after: 12, line: 1.4 }
|
||||
},
|
||||
th: {
|
||||
font: 'heading',
|
||||
size: 11,
|
||||
color: 'FF1744',
|
||||
bold: true,
|
||||
background: '263238',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
td: {
|
||||
font: 'body',
|
||||
size: 11,
|
||||
color: 'E0F2F1',
|
||||
background: '37474F',
|
||||
spacing: { before: 6, after: 6, line: 1.4 }
|
||||
},
|
||||
hr: {
|
||||
border: { color: 'FFEA00', width: 2, style: 'single' },
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
},
|
||||
img: {
|
||||
align: 'center',
|
||||
spacing: { before: 12, after: 12, line: 1 }
|
||||
}
|
||||
}
|
||||
};
|
||||
33
src/styles/templates/core/circus-sideshow.ts
Normal file
33
src/styles/templates/core/circus-sideshow.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const circusSideshow: StyleOption = {
|
||||
id: 'circus-sideshow',
|
||||
name: 'Circus Sideshow',
|
||||
category: 'Entertainment',
|
||||
description: 'Big top aesthetic. Ornamental fonts with red and cream stripe vibes.',
|
||||
vibe: 'Fun, Ornamental, Striped',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Rye&family=Sancreek&family=Roboto+Slab&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Sancreek", size: 40, color: "D32F2F", bold: false, align: 'center',
|
||||
spacing: { before: 400, after: 240, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Rye", size: 18, color: "1A237E", bold: false, align: 'center',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Roboto Slab", size: 11, color: "212121", align: 'center',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "D32F2F"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Roboto Slab', serif;
|
||||
background: #FFF8E1;
|
||||
h1 { font-family: 'Sancreek', cursive; font-size: 40pt; color: #D32F2F; text-align: center; margin-bottom: 24px; text-shadow: 2px 2px 0px #FBC02D; }
|
||||
h2 { font-family: 'Rye', serif; font-size: 18pt; color: #1A237E; text-align: center; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #212121; margin-bottom: 14px; text-align: center; }
|
||||
blockquote { border: 4px double #D32F2F; padding: 20px; margin: 24px auto; background: #FFF; border-radius: 16px; font-family: 'Sancreek', cursive; font-size: 14pt; color: #1A237E; text-align: center; max-width: 80%; }
|
||||
`
|
||||
};
|
||||
32
src/styles/templates/core/environmental-green.ts
Normal file
32
src/styles/templates/core/environmental-green.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const environmentalGreen: StyleOption = {
|
||||
id: 'environmental-green',
|
||||
name: 'Environmental Green',
|
||||
category: 'Sustainability',
|
||||
description: 'Nature-inspired design for environmental and sustainability communications. Organic feel with earthy green palette.',
|
||||
vibe: 'Natural, Sustainable, Organic',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Bitter:wght@400;500;700&family=Karla:wght@400;500;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Bitter", size: 26, color: "2E7D32", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Bitter", size: 14, color: "388E3C", bold: true, align: 'left',
|
||||
spacing: { before: 300, after: 150, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Karla", size: 10, color: "3E4A3D", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "2E7D32"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Karla', sans-serif;
|
||||
h1 { font-family: 'Bitter', serif; font-size: 26pt; font-weight: 700; color: #2E7D32; margin-bottom: 24px; }
|
||||
h2 { font-family: 'Bitter', serif; font-size: 14pt; font-weight: 700; color: #388E3C; margin-top: 30px; margin-bottom: 14px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #3E4A3D; margin-bottom: 14px; }
|
||||
blockquote { background: #E8F5E9; padding: 16px; border-left: 4px solid #2E7D32; margin: 20px 0; }
|
||||
`
|
||||
};
|
||||
37
src/styles/templates/core/highway-interstate.ts
Normal file
37
src/styles/templates/core/highway-interstate.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const highwayInterstate: StyleOption = {
|
||||
id: 'highway-interstate',
|
||||
name: 'Highway Interstate',
|
||||
category: 'Urban',
|
||||
description: 'Road signage aesthetic. Reflective white text on deep highway green backgrounds.',
|
||||
vibe: 'Functional, Travel, Signage',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Overpass:wght@400;700&family=Public+Sans:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Overpass", size: 36, color: "FFFFFF", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "00695C", color: "auto", style: "clear" },
|
||||
border: {
|
||||
bottom: { color: "FFFFFF", space: 4, style: "single", size: 12 },
|
||||
top: { color: "FFFFFF", space: 4, style: "single", size: 12 }
|
||||
}
|
||||
},
|
||||
heading2: {
|
||||
font: "Public Sans", size: 18, color: "004D40", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Public Sans", size: 11, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "00695C"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Public Sans', sans-serif;
|
||||
h1 { font-family: 'Overpass', sans-serif; font-size: 36pt; font-weight: 700; color: #FFFFFF; background: #00695C; padding: 16px; border-top: 2px solid #FFF; border-bottom: 2px solid #FFF; margin-bottom: 24px; border-radius: 8px; }
|
||||
h2 { font-size: 18pt; font-weight: 700; color: #004D40; margin-top: 32px; margin-bottom: 16px; text-transform: uppercase; }
|
||||
p { font-size: 11pt; line-height: 1.5; color: #212121; margin-bottom: 14px; }
|
||||
blockquote { background: #FFEB3B; color: #000; padding: 16px; margin: 24px 0; border: 4px solid #000; transform: skewX(-10deg); width: fit-content; }
|
||||
`
|
||||
};
|
||||
26
src/styles/templates/core/index.ts
Normal file
26
src/styles/templates/core/index.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
import { circusSideshow } from './circus-sideshow';
|
||||
import { environmentalGreen } from './environmental-green';
|
||||
import { highwayInterstate } from './highway-interstate';
|
||||
import { jungleExplorer } from './jungle-explorer';
|
||||
import { publicTransit } from './public-transit';
|
||||
import { silentFilmIntertitle } from './silent-film-intertitle';
|
||||
import { sportsDynamic } from './sports-dynamic';
|
||||
import { steampunkInventor } from './steampunk-inventor';
|
||||
import { subwayTile } from './subway-tile';
|
||||
import { taxiCab } from './taxi-cab';
|
||||
import { varsityTeam } from './varsity-team';
|
||||
|
||||
export const coreStyles: StyleOption[] = [
|
||||
circusSideshow,
|
||||
environmentalGreen,
|
||||
highwayInterstate,
|
||||
jungleExplorer,
|
||||
publicTransit,
|
||||
silentFilmIntertitle,
|
||||
sportsDynamic,
|
||||
steampunkInventor,
|
||||
subwayTile,
|
||||
taxiCab,
|
||||
varsityTeam
|
||||
];
|
||||
34
src/styles/templates/core/jungle-explorer.ts
Normal file
34
src/styles/templates/core/jungle-explorer.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const jungleExplorer: StyleOption = {
|
||||
id: 'jungle-explorer',
|
||||
name: 'Jungle Explorer',
|
||||
category: 'Adventure',
|
||||
description: 'Safari expedition style. Khaki, olive drab, and canvas textures.',
|
||||
vibe: 'Adventure, Khaki, Nature',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Stardos+Stencil&family=Domine:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Stardos Stencil", size: 36, color: "33691E", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: { bottom: { color: "827717", space: 6, style: "thick", size: 18 } }
|
||||
},
|
||||
heading2: {
|
||||
font: "Domine", size: 16, color: "558B2F", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Domine", size: 11, color: "1B1B1B", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "827717"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Domine', serif;
|
||||
background: #F0F4C3; /* Khaki tint */
|
||||
h1 { font-family: 'Stardos Stencil', cursive; font-size: 36pt; font-weight: 700; color: #33691E; border-bottom: 4px solid #827717; padding-bottom: 12px; margin-bottom: 24px; }
|
||||
h2 { font-size: 16pt; font-weight: 700; color: #558B2F; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #1B1B1B; margin-bottom: 14px; }
|
||||
blockquote { background: #DCEDC8; padding: 20px; border-left: 6px solid #33691E; margin: 24px 0; }
|
||||
`
|
||||
};
|
||||
34
src/styles/templates/core/public-transit.ts
Normal file
34
src/styles/templates/core/public-transit.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const publicTransit: StyleOption = {
|
||||
id: 'public-transit',
|
||||
name: 'Public Transit',
|
||||
category: 'Urban',
|
||||
description: 'Subway map and transit signage aesthetic. Clean, highly legible sans-serifs with color-coded lines.',
|
||||
vibe: 'Urban, Functional, Color-coded',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Mukta:wght@400;700&family=Hanken+Grotesk:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Hanken Grotesk", size: 32, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: { bottom: { color: "FFC107", space: 8, style: "single", size: 24 } }
|
||||
},
|
||||
heading2: {
|
||||
font: "Mukta", size: 18, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
shading: { fill: "EEEEEE", color: "auto", style: "clear" }
|
||||
},
|
||||
body: {
|
||||
font: "Mukta", size: 11, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "FFC107"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Mukta', sans-serif;
|
||||
h1 { font-family: 'Hanken Grotesk', sans-serif; font-size: 32pt; font-weight: 700; color: #000000; border-bottom: 6px solid #FFC107; padding-bottom: 12px; margin-bottom: 24px; }
|
||||
h2 { font-size: 18pt; font-weight: 700; color: #000000; background: #EEEEEE; padding: 4px 12px; margin-top: 32px; margin-bottom: 16px; display: inline-block; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #212121; margin-bottom: 14px; }
|
||||
blockquote { border-left: 6px solid #F44336; padding-left: 16px; margin: 24px 0; }
|
||||
`
|
||||
};
|
||||
36
src/styles/templates/core/silent-film-intertitle.ts
Normal file
36
src/styles/templates/core/silent-film-intertitle.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const silentFilmIntertitle: StyleOption = {
|
||||
id: 'silent-film-intertitle',
|
||||
name: 'Silent Film Intertitle',
|
||||
category: 'Cinema',
|
||||
description: '1920s cinema cards. White decorative text on black backgrounds with ornate borders.',
|
||||
vibe: 'Cinema, Vintage, Dramatic',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Gye-Gye&family=Sorts+Mill+Goudy&display=swap',
|
||||
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Gye-Gye", size: 32, color: "FFFFFF", bold: false, align: 'center',
|
||||
spacing: { before: 400, after: 240, line: 240 },
|
||||
shading: { fill: "000000", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Sorts Mill Goudy", size: 18, color: "EEEEEE", bold: false, align: 'center',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
shading: { fill: "212121", color: "auto", style: "clear" }
|
||||
},
|
||||
body: {
|
||||
font: "Sorts Mill Goudy", size: 14, color: "000000", align: 'center',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
|
||||
previewCss: `
|
||||
font-family: 'Sorts Mill Goudy', serif;
|
||||
h1 { font-family: 'Gye-Gye', sans-serif; font-size: 32pt; color: #FFFFFF; background: #000000; padding: 20px; text-align: center; margin-bottom: 24px; border: 4px double #FFF; }
|
||||
h2 { font-size: 18pt; color: #EEEEEE; background: #212121; display: inline-block; padding: 10px 20px; margin-top: 30px; margin-bottom: 16px; border-radius: 8px; }
|
||||
p { font-size: 14pt; line-height: 1.6; color: #000000; margin-bottom: 14px; text-align: center; }
|
||||
blockquote { border: 2px solid #000; padding: 20px; margin: 24px 0; font-style: italic; text-align: center; }
|
||||
`
|
||||
};
|
||||
32
src/styles/templates/core/sports-dynamic.ts
Normal file
32
src/styles/templates/core/sports-dynamic.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const sportsDynamic: StyleOption = {
|
||||
id: 'sports-dynamic',
|
||||
name: 'Sports Dynamic',
|
||||
category: 'Sports',
|
||||
description: 'Energetic and bold design for sports and athletic content. Dynamic typography with high-impact colors.',
|
||||
vibe: 'Energetic, Bold, Athletic',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Bebas+Neue&family=Rubik:wght@400;500;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Bebas Neue", size: 36, color: "D32F2F", bold: false, align: 'left',
|
||||
spacing: { before: 360, after: 200, line: 220 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Rubik", size: 14, color: "1A1A1A", bold: true, align: 'left',
|
||||
spacing: { before: 280, after: 140, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Rubik", size: 10, color: "333333", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "D32F2F"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Rubik', sans-serif;
|
||||
h1 { font-family: 'Bebas Neue', sans-serif; font-size: 36pt; color: #D32F2F; margin-bottom: 24px; letter-spacing: 2px; text-transform: uppercase; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #1A1A1A; margin-top: 28px; margin-bottom: 14px; text-transform: uppercase; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #333333; margin-bottom: 14px; }
|
||||
blockquote { background: #FFEBEE; padding: 16px; border-left: 6px solid #D32F2F; margin: 20px 0; font-weight: 500; }
|
||||
`
|
||||
};
|
||||
37
src/styles/templates/core/steampunk-inventor.ts
Normal file
37
src/styles/templates/core/steampunk-inventor.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const steampunkInventor: StyleOption = {
|
||||
id: 'steampunk-inventor',
|
||||
name: 'Steampunk Inventor',
|
||||
category: 'Fantasy',
|
||||
description: 'Brass and gear aesthetic. Victorian fonts with industrial metallic colors.',
|
||||
vibe: 'Mechanical, Brass, Victorian',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Rye&family=Lora:wght@400;700&display=swap',
|
||||
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Rye", size: 30, color: "5D4037", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 240, line: 240 },
|
||||
border: { bottom: { color: "B8860B", space: 8, style: "single", size: 24 } }
|
||||
},
|
||||
heading2: {
|
||||
font: "Lora", size: 16, color: "8D6E63", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
allCaps: true
|
||||
},
|
||||
body: {
|
||||
font: "Lora", size: 11, color: "3E2723", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "B8860B"
|
||||
},
|
||||
|
||||
previewCss: `
|
||||
font-family: 'Lora', serif;
|
||||
background: #EFEBE9;
|
||||
h1 { font-family: 'Rye', serif; font-size: 30pt; color: #5D4037; border-bottom: 6px double #B8860B; padding-bottom: 12px; margin-bottom: 24px; }
|
||||
h2 { font-size: 16pt; font-weight: 700; color: #8D6E63; margin-top: 30px; margin-bottom: 14px; text-transform: uppercase; letter-spacing: 1px; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #3E2723; margin-bottom: 14px; }
|
||||
blockquote { background: #D7CCC8; padding: 16px; border: 2px solid #5D4037; border-radius: 4px; margin: 24px 0; }
|
||||
`
|
||||
};
|
||||
38
src/styles/templates/core/subway-tile.ts
Normal file
38
src/styles/templates/core/subway-tile.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const subwayTile: StyleOption = {
|
||||
id: 'subway-tile',
|
||||
name: 'Subway Tile',
|
||||
category: 'Urban',
|
||||
description: 'Classic station ceramics. Clean white backgrounds, heavy black text, and tile-like framing.',
|
||||
vibe: 'Clean, Ceramic, Urban',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Work+Sans:wght@300;600&family=Lexend:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Lexend", size: 36, color: "000000", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: {
|
||||
top: { color: "000000", space: 12, style: "single", size: 4 },
|
||||
bottom: { color: "000000", space: 12, style: "single", size: 4 },
|
||||
left: { color: "000000", space: 12, style: "single", size: 4 },
|
||||
right: { color: "000000", space: 12, style: "single", size: 4 }
|
||||
}
|
||||
},
|
||||
heading2: {
|
||||
font: "Work Sans", size: 16, color: "212121", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Work Sans", size: 11, color: "424242", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Work Sans', sans-serif;
|
||||
h1 { font-family: 'Lexend', sans-serif; font-size: 36pt; font-weight: 700; color: #000000; border: 4px solid #000000; padding: 16px; margin-bottom: 24px; text-align: center; background: #FFFFFF; }
|
||||
h2 { font-size: 16pt; font-weight: 700; color: #212121; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #424242; margin-bottom: 14px; }
|
||||
blockquote { border-left: 8px solid #000; padding-left: 16px; margin: 24px 0; background: #F5F5F5; }
|
||||
`
|
||||
};
|
||||
40
src/styles/templates/core/taxi-cab.ts
Normal file
40
src/styles/templates/core/taxi-cab.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const taxiCab: StyleOption = {
|
||||
id: 'taxi-cab',
|
||||
name: 'Taxi Cab',
|
||||
category: 'Urban',
|
||||
description: 'Yellow cab aesthetic. Checkerboard patterns (simulated) and bold black on yellow.',
|
||||
vibe: 'Urban, Yellow, Bold',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Archivo+Black&family=Roboto:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Archivo Black", size: 36, color: "000000", bold: false, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "FFEB3B", color: "auto", style: "clear" },
|
||||
border: {
|
||||
top: { color: "000000", space: 4, style: "dashed", size: 24 }, // Simulates checkers
|
||||
bottom: { color: "000000", space: 4, style: "dashed", size: 24 }
|
||||
}
|
||||
},
|
||||
heading2: {
|
||||
font: "Roboto", size: 18, color: "000000", bold: true, align: 'center',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
shading: { fill: "FFFFFF", color: "auto", style: "clear" }
|
||||
},
|
||||
body: {
|
||||
font: "Roboto", size: 12, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "FFEB3B"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Roboto', sans-serif;
|
||||
background: #212121;
|
||||
padding: 20px;
|
||||
h1 { font-family: 'Archivo Black', sans-serif; font-size: 36pt; color: #000000; background: #FFEB3B; padding: 16px; margin-bottom: 24px; text-align: center; border-top: 6px dashed #000; border-bottom: 6px dashed #000; }
|
||||
h2 { font-size: 18pt; font-weight: 700; color: #000000; background: #FFFFFF; padding: 8px; margin-top: 32px; margin-bottom: 16px; text-align: center; display: inline-block; }
|
||||
p { font-size: 12pt; line-height: 1.5; color: #FFFFFF; margin-bottom: 14px; }
|
||||
blockquote { background: #FFEB3B; color: #000; padding: 16px; margin: 24px 0; font-weight: 700; }
|
||||
`
|
||||
};
|
||||
38
src/styles/templates/core/varsity-team.ts
Normal file
38
src/styles/templates/core/varsity-team.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const varsityTeam: StyleOption = {
|
||||
id: 'varsity-team',
|
||||
name: 'Varsity Team',
|
||||
category: 'Sport',
|
||||
description: 'College sports jersey style. Block lettering with athletic gold and navy.',
|
||||
vibe: 'Athletic, College, Bold',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Graduate&family=Saira:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Graduate", size: 36, color: "FDD835", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 240, line: 240 },
|
||||
shading: { fill: "1A237E", color: "auto", style: "clear" },
|
||||
border: {
|
||||
top: { color: "FDD835", space: 8, style: "single", size: 24 },
|
||||
bottom: { color: "FDD835", space: 8, style: "single", size: 24 }
|
||||
}
|
||||
},
|
||||
heading2: {
|
||||
font: "Saira", size: 20, color: "1A237E", bold: true, align: 'center',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
allCaps: true
|
||||
},
|
||||
body: {
|
||||
font: "Saira", size: 12, color: "212121", align: 'center',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "FDD835"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Saira', sans-serif;
|
||||
h1 { font-family: 'Graduate', serif; font-size: 36pt; color: #FDD835; background: #1A237E; border-top: 4px solid #FDD835; border-bottom: 4px solid #FDD835; padding: 20px; text-align: center; margin-bottom: 24px; }
|
||||
h2 { font-size: 20pt; font-weight: 700; color: #1A237E; text-align: center; margin-top: 32px; margin-bottom: 16px; text-transform: uppercase; }
|
||||
p { font-size: 12pt; line-height: 1.5; color: #212121; margin-bottom: 14px; text-align: center; }
|
||||
blockquote { border: 2px dashed #1A237E; padding: 16px; margin: 24px 0; background: #E8EAF6; }
|
||||
`
|
||||
};
|
||||
33
src/styles/templates/corporate/annual-report.ts
Normal file
33
src/styles/templates/corporate/annual-report.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const annualReport: StyleOption = {
|
||||
id: 'annual-report',
|
||||
name: 'Annual Report',
|
||||
category: 'Corporate',
|
||||
description: 'Trustworthy and substantial. Deep navy blues, clean sans-serifs, and grid-like precision.',
|
||||
vibe: 'Financial, Serious, Trust',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Libre+Franklin:wght@400;700;900&family=Merriweather:wght@300;400&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Libre Franklin", size: 32, color: "0D2B46", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Libre Franklin", size: 16, color: "A0A0A0", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
allCaps: true
|
||||
},
|
||||
body: {
|
||||
font: "Merriweather", size: 10, color: "333333", align: 'both',
|
||||
spacing: { before: 0, after: 160, line: 300 }
|
||||
},
|
||||
accentColor: "0D2B46"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Merriweather', serif;
|
||||
h1 { font-family: 'Libre Franklin', sans-serif; font-size: 32pt; font-weight: 900; color: #0D2B46; margin-bottom: 24px; }
|
||||
h2 { font-family: 'Libre Franklin', sans-serif; font-size: 16pt; font-weight: 700; color: #A0A0A0; text-transform: uppercase; margin-top: 32px; margin-bottom: 16px; border-bottom: 1px solid #CCC; padding-bottom: 4px; }
|
||||
p { font-size: 10pt; line-height: 1.8; color: #333333; margin-bottom: 14px; text-align: justify; }
|
||||
blockquote { border-left: 4px solid #0D2B46; padding-left: 16px; margin: 24px 0; color: #0D2B46; font-style: italic; }
|
||||
`
|
||||
};
|
||||
32
src/styles/templates/corporate/corporate-executive.ts
Normal file
32
src/styles/templates/corporate/corporate-executive.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const corporateExecutive: StyleOption = {
|
||||
id: 'corporate-executive',
|
||||
name: 'Corporate Executive',
|
||||
category: 'Corporate',
|
||||
description: 'Authoritative and professional. Designed for board reports, executive summaries, and high-stakes business communications.',
|
||||
vibe: 'Executive, Formal, Trustworthy',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Source+Serif+4:wght@400;600;700&family=Source+Sans+3:wght@400;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Source Serif 4", size: 24, color: "1A237E", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Source Sans 3", size: 14, color: "303F9F", bold: true, align: 'left',
|
||||
spacing: { before: 300, after: 150, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Source Sans 3", size: 10, color: "333333", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "1A237E"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Source Sans 3', sans-serif;
|
||||
h1 { font-family: 'Source Serif 4', serif; font-size: 24pt; font-weight: 700; color: #1A237E; margin-bottom: 24px; border-bottom: 2px solid #1A237E; padding-bottom: 8px; }
|
||||
h2 { font-size: 14pt; font-weight: 600; color: #303F9F; margin-top: 30px; margin-bottom: 12px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #333333; margin-bottom: 14px; }
|
||||
blockquote { border-left: 4px solid #1A237E; padding-left: 16px; color: #1A237E; margin: 20px 0; font-style: italic; }
|
||||
`
|
||||
};
|
||||
35
src/styles/templates/corporate/credit-card-platinum.ts
Normal file
35
src/styles/templates/corporate/credit-card-platinum.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const creditCardPlatinum: StyleOption = {
|
||||
id: 'credit-card-platinum',
|
||||
name: 'Credit Card Platinum',
|
||||
category: 'Financial',
|
||||
description: 'Premium card aesthetic. Silver/gradient shading with OCR-style raised numbering fonts.',
|
||||
vibe: 'Premium, Silver, Metallic',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Share+Tech+Mono&family=Krub:wght@400;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Krub", size: 32, color: "E0E0E0", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "424242", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Share Tech Mono", size: 18, color: "C0C0C0", bold: false, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
allCaps: true,
|
||||
tracking: 100
|
||||
},
|
||||
body: {
|
||||
font: "Krub", size: 11, color: "616161", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "C0C0C0"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Krub', sans-serif;
|
||||
h1 { font-size: 32pt; font-weight: 700; color: #E0E0E0; background: linear-gradient(135deg, #616161, #212121); padding: 16px; margin-bottom: 24px; border-radius: 12px; }
|
||||
h2 { font-family: 'Share Tech Mono', monospace; font-size: 18pt; color: #757575; margin-top: 32px; margin-bottom: 16px; text-transform: uppercase; letter-spacing: 3px; text-shadow: 1px 1px 0 #FFF; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #616161; margin-bottom: 14px; }
|
||||
blockquote { border-left: 4px solid #C0C0C0; padding-left: 16px; margin: 24px 0; background: #F5F5F5; }
|
||||
`
|
||||
};
|
||||
38
src/styles/templates/corporate/currency-bill.ts
Normal file
38
src/styles/templates/corporate/currency-bill.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const currencyBill: StyleOption = {
|
||||
id: 'currency-bill',
|
||||
name: 'Currency Bill',
|
||||
category: 'Official',
|
||||
description: 'Banknote aesthetic. Intricate guilloche-style borders and emerald green serif fonts.',
|
||||
vibe: 'Financial, Secure, Green',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Playfair+Display+SC:wght@700&family=Noto+Serif:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Playfair Display SC", size: 36, color: "1B5E20", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: {
|
||||
top: { color: "2E7D32", space: 6, style: "double", size: 12 },
|
||||
bottom: { color: "2E7D32", space: 6, style: "double", size: 12 }
|
||||
}
|
||||
},
|
||||
heading2: {
|
||||
font: "Noto Serif", size: 16, color: "388E3C", bold: true, align: 'center',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
allCaps: true
|
||||
},
|
||||
body: {
|
||||
font: "Noto Serif", size: 11, color: "1B5E20", align: 'both',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "2E7D32"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Noto Serif', serif;
|
||||
background: #E8F5E9;
|
||||
h1 { font-family: 'Playfair Display SC', serif; font-size: 36pt; font-weight: 700; color: #1B5E20; text-align: center; border-top: 4px double #2E7D32; border-bottom: 4px double #2E7D32; padding: 12px 0; margin-bottom: 24px; letter-spacing: 2px; }
|
||||
h2 { font-size: 16pt; font-weight: 700; color: #388E3C; text-align: center; margin-top: 32px; margin-bottom: 16px; text-transform: uppercase; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #1B5E20; margin-bottom: 14px; text-align: justify; }
|
||||
blockquote { border: 1px solid #2E7D32; padding: 20px; margin: 24px 0; background: #C8E6C9; text-align: center; border-radius: 50%; width: 200px; height: 200px; display: flex; align-items: center; justify-content: center; margin: 0 auto; }
|
||||
`
|
||||
};
|
||||
30
src/styles/templates/corporate/index.ts
Normal file
30
src/styles/templates/corporate/index.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
import { annualReport } from './annual-report';
|
||||
import { corporateExecutive } from './corporate-executive';
|
||||
import { creditCardPlatinum } from './credit-card-platinum';
|
||||
import { currencyBill } from './currency-bill';
|
||||
import { legalContract } from './legal-contract';
|
||||
import { legalPleading } from './legal-pleading';
|
||||
import { passportOfficial } from './passport-official';
|
||||
import { policeBlotter } from './police-blotter';
|
||||
import { politicalCampaign } from './political-campaign';
|
||||
import { stockTicker } from './stock-ticker';
|
||||
import { techMemo } from './tech-memo';
|
||||
import { topSecretRedacted } from './top-secret-redacted';
|
||||
import { whiteboardStrategy } from './whiteboard-strategy';
|
||||
|
||||
export const corporateStyles: StyleOption[] = [
|
||||
annualReport,
|
||||
corporateExecutive,
|
||||
creditCardPlatinum,
|
||||
currencyBill,
|
||||
legalContract,
|
||||
legalPleading,
|
||||
passportOfficial,
|
||||
policeBlotter,
|
||||
politicalCampaign,
|
||||
stockTicker,
|
||||
techMemo,
|
||||
topSecretRedacted,
|
||||
whiteboardStrategy
|
||||
];
|
||||
34
src/styles/templates/corporate/legal-contract.ts
Normal file
34
src/styles/templates/corporate/legal-contract.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const legalContract: StyleOption = {
|
||||
id: 'legal-contract',
|
||||
name: 'Legal Contract',
|
||||
category: 'Corporate',
|
||||
description: 'Binding agreement style. Serif fonts, justified text, and numbered section aesthetics.',
|
||||
vibe: 'Legal, Binding, Formal',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Tinos:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Tinos", size: 14, color: "000000", bold: true, align: 'center',
|
||||
spacing: { before: 240, after: 240, line: 240 },
|
||||
allCaps: true
|
||||
},
|
||||
heading2: {
|
||||
font: "Tinos", size: 12, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 240, after: 120, line: 240 },
|
||||
underline: true
|
||||
},
|
||||
body: {
|
||||
font: "Tinos", size: 11, color: "000000", align: 'both',
|
||||
spacing: { before: 0, after: 120, line: 240 }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Tinos', serif;
|
||||
h1 { font-size: 14pt; font-weight: 700; color: #000000; text-align: center; text-transform: uppercase; margin-bottom: 16px; }
|
||||
h2 { font-size: 12pt; font-weight: 700; color: #000000; text-decoration: underline; margin-top: 24px; margin-bottom: 12px; }
|
||||
p { font-size: 11pt; line-height: 1.4; color: #000000; margin-bottom: 12px; text-align: justify; }
|
||||
blockquote { margin: 20px 40px; border: 1px solid #000; padding: 10px; }
|
||||
`
|
||||
};
|
||||
36
src/styles/templates/corporate/legal-pleading.ts
Normal file
36
src/styles/templates/corporate/legal-pleading.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const legalPleading: StyleOption = {
|
||||
id: 'legal-pleading',
|
||||
name: 'Legal Pleading',
|
||||
category: 'Professional',
|
||||
description: 'Courtroom document style. Rigid framing, double spacing, and traditional serif fonts.',
|
||||
vibe: 'Legal, Strict, Formal',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=EB+Garamond:wght@400;700&family=Courier+Prime&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "EB Garamond", size: 14, color: "000000", bold: true, align: 'center',
|
||||
spacing: { before: 240, after: 240, line: 240 },
|
||||
allCaps: true,
|
||||
border: { bottom: { color: "000000", space: 4, style: "single", size: 4 } }
|
||||
},
|
||||
heading2: {
|
||||
font: "EB Garamond", size: 12, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 240, after: 120, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Courier Prime", size: 12, color: "000000", align: 'both',
|
||||
spacing: { before: 0, after: 0, line: 480 },
|
||||
border: { left: { color: "BDBDBD", space: 12, style: "single", size: 4 } }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Courier Prime', monospace;
|
||||
line-height: 2.0;
|
||||
h1 { font-family: 'EB Garamond', serif; font-size: 14pt; font-weight: 700; color: #000000; text-align: center; text-decoration: underline; text-transform: uppercase; margin-bottom: 24px; }
|
||||
h2 { font-family: 'EB Garamond', serif; font-size: 12pt; font-weight: 700; color: #000000; margin-top: 24px; margin-bottom: 12px; }
|
||||
p { font-size: 12pt; color: #000000; margin-bottom: 0px; text-align: justify; border-left: 1px solid #BDBDBD; padding-left: 15px; }
|
||||
blockquote { margin-left: 40px; border-left: 1px solid #BDBDBD; padding-left: 15px; }
|
||||
`
|
||||
};
|
||||
33
src/styles/templates/corporate/passport-official.ts
Normal file
33
src/styles/templates/corporate/passport-official.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const passportOfficial: StyleOption = {
|
||||
id: 'passport-official',
|
||||
name: 'Passport Official',
|
||||
category: 'Government',
|
||||
description: 'International travel document aesthetic. Machine-readable fonts with secure, bureaucratic vibes.',
|
||||
vibe: 'Official, Secure, Monospace',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Martian+Mono:wght@400;700&family=Courier+Prime&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Martian Mono", size: 22, color: "1A237E", bold: true, align: 'left',
|
||||
spacing: { before: 360, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Martian Mono", size: 12, color: "B71C1C", bold: true, align: 'left',
|
||||
spacing: { before: 280, after: 140, line: 240 },
|
||||
allCaps: true
|
||||
},
|
||||
body: {
|
||||
font: "Courier Prime", size: 10, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 140, line: 260 }
|
||||
},
|
||||
accentColor: "B71C1C"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Courier Prime', monospace;
|
||||
h1 { font-family: 'Martian Mono', monospace; font-size: 22pt; font-weight: 700; color: #1A237E; margin-bottom: 24px; letter-spacing: -1px; }
|
||||
h2 { font-family: 'Martian Mono', monospace; font-size: 12pt; font-weight: 700; color: #B71C1C; margin-top: 28px; margin-bottom: 14px; text-transform: uppercase; }
|
||||
p { font-size: 10pt; line-height: 1.5; color: #212121; margin-bottom: 12px; }
|
||||
blockquote { border: 1px dashed #1A237E; padding: 16px; margin: 20px 0; background: #E8EAF6; }
|
||||
`
|
||||
};
|
||||
34
src/styles/templates/corporate/police-blotter.ts
Normal file
34
src/styles/templates/corporate/police-blotter.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const policeBlotter: StyleOption = {
|
||||
id: 'police-blotter',
|
||||
name: 'Police Blotter',
|
||||
category: 'Official',
|
||||
description: 'Law enforcement paperwork. Carbon copy blue fonts on stark white forms.',
|
||||
vibe: 'Official, Blue, Bureaucratic',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Courier+Prime&family=Special+Elite&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Special Elite", size: 26, color: "0D47A1", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
allCaps: true
|
||||
},
|
||||
heading2: {
|
||||
font: "Courier Prime", size: 14, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
shading: { fill: "E3F2FD", color: "auto", style: "clear" }
|
||||
},
|
||||
body: {
|
||||
font: "Courier Prime", size: 11, color: "1A237E", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "0D47A1"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Courier Prime', monospace;
|
||||
h1 { font-family: 'Special Elite', cursive; font-size: 26pt; color: #0D47A1; margin-bottom: 24px; text-transform: uppercase; text-decoration: underline; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #000000; background: #E3F2FD; display: block; padding: 4px; margin-top: 32px; margin-bottom: 16px; border: 1px solid #0D47A1; }
|
||||
p { font-size: 11pt; line-height: 1.5; color: #1A237E; margin-bottom: 14px; }
|
||||
blockquote { border: 1px solid #000; padding: 16px; margin: 24px 0; background: #FAFAFA; }
|
||||
`
|
||||
};
|
||||
33
src/styles/templates/corporate/political-campaign.ts
Normal file
33
src/styles/templates/corporate/political-campaign.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const politicalCampaign: StyleOption = {
|
||||
id: 'political-campaign',
|
||||
name: 'Political Campaign',
|
||||
category: 'Professional',
|
||||
description: 'Bold, patriotic design for campaigns. Strong headers with red, white, and blue motifs.',
|
||||
vibe: 'Patriotic, Bold, Official',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Francois+One&family=Cabin:wght@400;600;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Francois One", size: 36, color: "0D47A1", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: { bottom: { color: "D32F2F", space: 8, style: "single", size: 12 } }
|
||||
},
|
||||
heading2: {
|
||||
font: "Cabin", size: 16, color: "D32F2F", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Cabin", size: 11, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "D32F2F"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Cabin', sans-serif;
|
||||
h1 { font-family: 'Francois One', sans-serif; font-size: 36pt; color: #0D47A1; border-bottom: 4px solid #D32F2F; padding-bottom: 12px; margin-bottom: 24px; text-transform: uppercase; }
|
||||
h2 { font-size: 16pt; font-weight: 700; color: #D32F2F; margin-top: 32px; margin-bottom: 16px; text-transform: uppercase; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #212121; margin-bottom: 14px; }
|
||||
blockquote { background: #E3F2FD; padding: 20px; border-left: 8px solid #0D47A1; margin: 24px 0; }
|
||||
`
|
||||
};
|
||||
36
src/styles/templates/corporate/stock-ticker.ts
Normal file
36
src/styles/templates/corporate/stock-ticker.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const stockTicker: StyleOption = {
|
||||
id: 'stock-ticker',
|
||||
name: 'Stock Ticker',
|
||||
category: 'Financial',
|
||||
description: 'LED moving message sign. Dot matrix fonts with bright green/red on black.',
|
||||
vibe: 'Financial, Digital, LED',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=DotGothic16&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "DotGothic16", size: 32, color: "00E676", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "000000", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "DotGothic16", size: 18, color: "FF1744", bold: false, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
shading: { fill: "000000", color: "auto", style: "clear" }
|
||||
},
|
||||
body: {
|
||||
font: "DotGothic16", size: 12, color: "E0E0E0", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 },
|
||||
shading: { fill: "212121", color: "auto", style: "clear" }
|
||||
},
|
||||
accentColor: "00E676"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'DotGothic16', sans-serif;
|
||||
background: #212121;
|
||||
h1 { font-size: 32pt; color: #00E676; background: #000000; padding: 12px; margin-bottom: 24px; border-bottom: 2px solid #333; }
|
||||
h2 { font-size: 18pt; color: #FF1744; background: #000000; padding: 8px; margin-top: 32px; margin-bottom: 16px; display: inline-block; }
|
||||
p { font-size: 12pt; line-height: 1.5; color: #E0E0E0; margin-bottom: 14px; }
|
||||
blockquote { border-left: 4px solid #00E676; padding-left: 16px; margin: 24px 0; color: #B9F6CA; }
|
||||
`
|
||||
};
|
||||
34
src/styles/templates/corporate/tech-memo.ts
Normal file
34
src/styles/templates/corporate/tech-memo.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const techMemo: StyleOption = {
|
||||
id: 'tech-memo',
|
||||
name: 'Tech Memorandum',
|
||||
category: 'Corporate',
|
||||
description: 'Modern, functional, and authoritative. Uses shading for headers to create distinct sections.',
|
||||
vibe: 'Corporate, Tech, Strategy',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Roboto", size: 24, color: "0F172A", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "F1F5F9", color: "auto", style: "clear" },
|
||||
border: { left: { color: "2563EB", space: 10, style: "single", size: 48 } }
|
||||
},
|
||||
heading2: {
|
||||
font: "Roboto", size: 14, color: "2563EB", bold: true, align: 'left',
|
||||
spacing: { before: 300, after: 150, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Roboto", size: 10, color: "334155", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "2563EB"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Roboto', sans-serif;
|
||||
h1 { font-size: 24pt; font-weight: 700; background: #F1F5F9; color: #0F172A; padding: 12px 16px; border-left: 8px solid #2563EB; margin-bottom: 20px; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #2563EB; margin-top: 30px; margin-bottom: 12px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #334155; margin-bottom: 14px; }
|
||||
blockquote { background: #EFF6FF; padding: 16px; border-radius: 4px; color: #1E40AF; border-left: 4px solid #2563EB; margin: 20px 0; }
|
||||
`
|
||||
};
|
||||
39
src/styles/templates/corporate/top-secret-redacted.ts
Normal file
39
src/styles/templates/corporate/top-secret-redacted.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const topSecretRedacted: StyleOption = {
|
||||
id: 'top-secret-redacted',
|
||||
name: 'Top Secret Redacted',
|
||||
category: 'Government',
|
||||
description: 'Declassified document style. Typewriter fonts with "blacked out" highlight effects.',
|
||||
vibe: 'Secret, Classified, Rough',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Special+Elite&family=Courier+Prime:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Special Elite", size: 28, color: "000000", bold: false, align: 'center',
|
||||
spacing: { before: 400, after: 240, line: 240 },
|
||||
border: {
|
||||
top: { color: "000000", space: 6, style: "single", size: 24 },
|
||||
bottom: { color: "000000", space: 6, style: "single", size: 24 }
|
||||
}
|
||||
},
|
||||
heading2: {
|
||||
font: "Courier Prime", size: 14, color: "B71C1C", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
shading: { fill: "000000", color: "auto", style: "clear" }
|
||||
},
|
||||
body: {
|
||||
font: "Courier Prime", size: 11, color: "000000", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Courier Prime', monospace;
|
||||
background: #F5F5F5;
|
||||
h1 { font-family: 'Special Elite', cursive; font-size: 28pt; color: #000000; border-top: 4px solid #000; border-bottom: 4px solid #000; padding: 16px 0; text-align: center; margin-bottom: 28px; text-transform: uppercase; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #B71C1C; background: #000000; display: inline-block; padding: 4px 12px; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #000000; margin-bottom: 14px; }
|
||||
blockquote { background: #000; color: #000; padding: 10px; margin: 20px 0; user-select: none; }
|
||||
blockquote:hover { color: #FFF; }
|
||||
`
|
||||
};
|
||||
34
src/styles/templates/corporate/whiteboard-strategy.ts
Normal file
34
src/styles/templates/corporate/whiteboard-strategy.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const whiteboardStrategy: StyleOption = {
|
||||
id: 'whiteboard-strategy',
|
||||
name: 'Whiteboard Strategy',
|
||||
category: 'Business',
|
||||
description: 'Brainstorming session. Dry-erase marker fonts in standard office colors (Black, Blue, Red).',
|
||||
vibe: 'Corporate, Brainstorm, Sketch',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Architects+Daughter&family=Patrick+Hand&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Architects Daughter", size: 36, color: "D32F2F", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: { bottom: { color: "1976D2", space: 4, style: "single", size: 12 } }
|
||||
},
|
||||
heading2: {
|
||||
font: "Patrick Hand", size: 20, color: "1976D2", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Patrick Hand", size: 14, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "D32F2F"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Patrick Hand', cursive;
|
||||
background: #FFFFFF;
|
||||
h1 { font-family: 'Architects Daughter', cursive; font-size: 36pt; font-weight: 700; color: #D32F2F; border-bottom: 3px solid #1976D2; padding-bottom: 10px; margin-bottom: 24px; text-align: center; }
|
||||
h2 { font-size: 20pt; font-weight: 700; color: #1976D2; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 14pt; line-height: 1.5; color: #212121; margin-bottom: 14px; }
|
||||
blockquote { border: 2px solid #388E3C; padding: 16px; margin: 24px 0; border-radius: 16px; color: #388E3C; }
|
||||
`
|
||||
};
|
||||
34
src/styles/templates/creative/bauhaus-poster.ts
Normal file
34
src/styles/templates/creative/bauhaus-poster.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const bauhausPoster: StyleOption = {
|
||||
id: 'bauhaus-poster',
|
||||
name: 'Bauhaus Poster',
|
||||
category: 'Creative',
|
||||
description: 'Geometric minimalism. Primary colors, angled text, and strong diagonal compositions.',
|
||||
vibe: 'Artistic, Geometric, Modernist',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Josefin+Sans:wght@400;700&family=Jost:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Josefin Sans", size: 36, color: "D50000", bold: true, align: 'right',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: { bottom: { color: "000000", space: 8, style: "single", size: 36 } }
|
||||
},
|
||||
heading2: {
|
||||
font: "Jost", size: 16, color: "2962FF", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
shading: { fill: "FFEB3B", color: "auto", style: "clear" }
|
||||
},
|
||||
body: {
|
||||
font: "Jost", size: 11, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "D50000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Jost', sans-serif;
|
||||
h1 { font-family: 'Josefin Sans', sans-serif; font-size: 36pt; font-weight: 700; color: #D50000; text-align: right; border-bottom: 8px solid #000; padding-bottom: 10px; margin-bottom: 24px; text-transform: uppercase; }
|
||||
h2 { font-size: 16pt; font-weight: 700; color: #2962FF; background: #FFEB3B; padding: 8px 16px; margin-top: 32px; margin-bottom: 16px; display: inline-block; transform: rotate(-1deg); }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #212121; margin-bottom: 14px; }
|
||||
blockquote { border-left: 10px solid #D50000; padding-left: 20px; margin: 24px 0; font-style: italic; }
|
||||
`
|
||||
};
|
||||
36
src/styles/templates/creative/blueprint-cyanotype.ts
Normal file
36
src/styles/templates/creative/blueprint-cyanotype.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const blueprintCyanotype: StyleOption = {
|
||||
id: 'blueprint-cyanotype',
|
||||
name: 'Blueprint Cyanotype',
|
||||
category: 'Creative',
|
||||
description: 'Architectural blueprint style. White lines on a deep cyan blue background.',
|
||||
vibe: 'Technical, Blue, Schematic',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Architects+Daughter&family=Roboto+Mono:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Architects Daughter", size: 32, color: "FFFFFF", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: { bottom: { color: "FFFFFF", space: 4, style: "single", size: 12 } }
|
||||
},
|
||||
heading2: {
|
||||
font: "Roboto Mono", size: 14, color: "FFFFFF", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
allCaps: true
|
||||
},
|
||||
body: {
|
||||
font: "Roboto Mono", size: 10, color: "E0F7FA", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "FFFFFF"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Roboto Mono', monospace;
|
||||
background: #0047AB; /* Cobalt/Blueprint Blue */
|
||||
color: #FFFFFF;
|
||||
h1 { font-family: 'Architects Daughter', cursive; font-size: 32pt; font-weight: 700; color: #FFFFFF; text-align: center; border-bottom: 2px solid #FFFFFF; margin-bottom: 24px; padding-bottom: 8px; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #FFFFFF; margin-top: 32px; margin-bottom: 16px; text-transform: uppercase; border: 1px solid #FFF; display: inline-block; padding: 4px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #E0F7FA; margin-bottom: 14px; }
|
||||
blockquote { border: 1px dashed #FFFFFF; padding: 16px; margin: 24px 0; background: #003380; }
|
||||
`
|
||||
};
|
||||
34
src/styles/templates/creative/brick-toy.ts
Normal file
34
src/styles/templates/creative/brick-toy.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const brickToy: StyleOption = {
|
||||
id: 'brick-toy',
|
||||
name: 'Brick Toy',
|
||||
category: 'Playful',
|
||||
description: 'Plastic building block aesthetic. Primary red, blue, and yellow with chunky text.',
|
||||
vibe: 'Playful, Primary, Chunky',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Titan+One&family=Nunito:wght@400;800&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Titan One", size: 36, color: "D32F2F", bold: false, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "FFEB3B", color: "auto", style: "clear" } // Yellow background
|
||||
},
|
||||
heading2: {
|
||||
font: "Nunito", size: 18, color: "FFFFFF", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
shading: { fill: "1976D2", color: "auto", style: "clear" } // Blue background
|
||||
},
|
||||
body: {
|
||||
font: "Nunito", size: 12, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "D32F2F"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Nunito', sans-serif;
|
||||
h1 { font-family: 'Titan One', cursive; font-size: 36pt; color: #D32F2F; background: #FFEB3B; padding: 16px; border-radius: 8px; text-align: center; margin-bottom: 24px; border: 4px solid #D32F2F; }
|
||||
h2 { font-size: 18pt; font-weight: 800; color: #FFFFFF; background: #1976D2; padding: 8px 16px; border-radius: 4px; display: inline-block; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 12pt; line-height: 1.6; color: #212121; margin-bottom: 14px; }
|
||||
blockquote { border: 4px dotted #D32F2F; padding: 16px; margin: 24px 0; background: #E3F2FD; }
|
||||
`
|
||||
};
|
||||
39
src/styles/templates/creative/brutalist-mono.ts
Normal file
39
src/styles/templates/creative/brutalist-mono.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const brutalistMono: StyleOption = {
|
||||
id: 'brutalist-mono',
|
||||
name: 'Brutalist Lab',
|
||||
category: 'Creative',
|
||||
description: 'Raw, monospaced aesthetic. Boxes, thick outlines, and typewriter vibes.',
|
||||
vibe: 'Code, Industrial, Raw',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Space Mono", size: 24, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: {
|
||||
top: { color: "000000", space: 12, style: "single", size: 24 },
|
||||
bottom: { color: "000000", space: 12, style: "single", size: 24 },
|
||||
left: { color: "000000", space: 12, style: "single", size: 24 },
|
||||
right: { color: "000000", space: 12, style: "single", size: 24 }
|
||||
}
|
||||
},
|
||||
heading2: {
|
||||
font: "Space Mono", size: 14, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
shading: { fill: "E0E0E0", color: "auto", style: "clear" }
|
||||
},
|
||||
body: {
|
||||
font: "Space Mono", size: 10, color: "111111", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Space Mono', monospace;
|
||||
h1 { font-size: 24pt; font-weight: 700; color: #000000; border: 4px solid #000; padding: 16px; margin-bottom: 24px; text-transform: uppercase; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #000000; background: #E0E0E0; padding: 8px; margin-top: 32px; margin-bottom: 16px; display: inline-block; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #111111; margin-bottom: 14px; }
|
||||
blockquote { border-left: 6px solid #000; padding-left: 16px; margin: 24px 0; font-weight: 700; }
|
||||
`
|
||||
};
|
||||
36
src/styles/templates/creative/glitch-art.ts
Normal file
36
src/styles/templates/creative/glitch-art.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const glitchArt: StyleOption = {
|
||||
id: 'glitch-art',
|
||||
name: 'Glitch Art',
|
||||
category: 'Creative',
|
||||
description: 'Digital distortion aesthetic. Monospaced fonts with neon colors and "broken" styling.',
|
||||
vibe: 'Digital, Glitch, Cyber',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Rubik+Glitch&family=Share+Tech+Mono&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Rubik Glitch", size: 40, color: "D500F9", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "121212", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Share Tech Mono", size: 18, color: "00E5FF", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Share Tech Mono", size: 11, color: "BDBDBD", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 },
|
||||
shading: { fill: "000000", color: "auto", style: "clear" }
|
||||
},
|
||||
accentColor: "00E5FF"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
background: #000000;
|
||||
color: #BDBDBD;
|
||||
h1 { font-family: 'Rubik Glitch', cursive; font-size: 40pt; color: #D500F9; background: #121212; padding: 10px; margin-bottom: 24px; text-shadow: 2px 0 #00E5FF; }
|
||||
h2 { font-size: 18pt; font-weight: 700; color: #00E5FF; margin-top: 32px; margin-bottom: 16px; text-transform: uppercase; letter-spacing: 2px; }
|
||||
p { font-size: 11pt; line-height: 1.5; color: #BDBDBD; margin-bottom: 14px; }
|
||||
blockquote { border: 1px solid #D500F9; padding: 16px; margin: 24px 0; color: #D500F9; box-shadow: 4px 4px 0 #00E5FF; }
|
||||
`
|
||||
};
|
||||
34
src/styles/templates/creative/grunge-90s.ts
Normal file
34
src/styles/templates/creative/grunge-90s.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const grunge90s: StyleOption = {
|
||||
id: 'grunge-90s',
|
||||
name: 'Grunge 90s',
|
||||
category: 'Creative',
|
||||
description: 'Distressed and edgy. David Carson inspired typography with overlapping elements and grit.',
|
||||
vibe: 'Dirty, Edgy, Chaotic',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Permanent+Marker&family=Special+Elite&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Permanent Marker", size: 36, color: "333333", bold: false, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Special Elite", size: 18, color: "8B0000", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
border: { bottom: { color: "000000", space: 4, style: "dashed", size: 12 } }
|
||||
},
|
||||
body: {
|
||||
font: "Special Elite", size: 11, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "8B0000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Special Elite', cursive;
|
||||
background-color: #F0F0F0;
|
||||
h1 { font-family: 'Permanent Marker', cursive; font-size: 36pt; color: #333333; text-align: center; margin-bottom: 24px; transform: rotate(1deg); opacity: 0.9; }
|
||||
h2 { font-size: 18pt; font-weight: 700; color: #8B0000; margin-top: 32px; margin-bottom: 16px; border-bottom: 2px dashed #000; display: inline-block; transform: skewX(-5deg); }
|
||||
p { font-size: 11pt; line-height: 1.6; color: #212121; margin-bottom: 14px; }
|
||||
blockquote { border: 3px solid #000; padding: 16px; margin: 24px 0; background: #D3D3D3; transform: rotate(-1deg); }
|
||||
`
|
||||
};
|
||||
30
src/styles/templates/creative/index.ts
Normal file
30
src/styles/templates/creative/index.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
import { bauhausPoster } from './bauhaus-poster';
|
||||
import { blueprintCyanotype } from './blueprint-cyanotype';
|
||||
import { brickToy } from './brick-toy';
|
||||
import { brutalistMono } from './brutalist-mono';
|
||||
import { glitchArt } from './glitch-art';
|
||||
import { grunge90s } from './grunge-90s';
|
||||
import { kindergartenArt } from './kindergarten-art';
|
||||
import { origamiPaper } from './origami-paper';
|
||||
import { popArtComic } from './pop-art-comic';
|
||||
import { risographPrint } from './risograph-print';
|
||||
import { streetArtGraffiti } from './street-art-graffiti';
|
||||
import { vaporwaveAesthetic } from './vaporwave-aesthetic';
|
||||
import { watercolorWash } from './watercolor-wash';
|
||||
|
||||
export const creativeStyles: StyleOption[] = [
|
||||
bauhausPoster,
|
||||
blueprintCyanotype,
|
||||
brickToy,
|
||||
brutalistMono,
|
||||
glitchArt,
|
||||
grunge90s,
|
||||
kindergartenArt,
|
||||
origamiPaper,
|
||||
popArtComic,
|
||||
risographPrint,
|
||||
streetArtGraffiti,
|
||||
vaporwaveAesthetic,
|
||||
watercolorWash
|
||||
];
|
||||
32
src/styles/templates/creative/kindergarten-art.ts
Normal file
32
src/styles/templates/creative/kindergarten-art.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const kindergartenArt: StyleOption = {
|
||||
id: 'kindergarten-art',
|
||||
name: 'Kindergarten Art',
|
||||
category: 'Playful',
|
||||
description: 'Child-like crayon aesthetic. Primary colors, rounded fonts, and large friendly text.',
|
||||
vibe: 'Childish, Fun, Primary',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Chewy&family=Balsamiq+Sans:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Chewy", size: 40, color: "2962FF", bold: false, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Balsamiq Sans", size: 18, color: "D50000", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Balsamiq Sans", size: 14, color: "111111", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 320 }
|
||||
},
|
||||
accentColor: "FFD600"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Balsamiq Sans', cursive;
|
||||
h1 { font-family: 'Chewy', cursive; font-size: 40pt; color: #2962FF; text-align: center; margin-bottom: 24px; transform: rotate(-2deg); }
|
||||
h2 { font-size: 18pt; font-weight: 700; color: #D50000; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 14pt; line-height: 1.6; color: #111111; margin-bottom: 14px; }
|
||||
blockquote { border: 4px dashed #FFD600; padding: 20px; margin: 24px 0; border-radius: 20px; background: #FFFDE7; }
|
||||
`
|
||||
};
|
||||
33
src/styles/templates/creative/origami-paper.ts
Normal file
33
src/styles/templates/creative/origami-paper.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const origamiPaper: StyleOption = {
|
||||
id: 'origami-paper',
|
||||
name: 'Origami Paper',
|
||||
category: 'Creative',
|
||||
description: 'Folded paper aesthetic. Sharp angles, subtle shadows, and crisp typography.',
|
||||
vibe: 'Delicate, Sharp, Paper',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Cormorant+Unicase:wght@400;700&family=Muli:wght@300;400&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Cormorant Unicase", size: 32, color: "37474F", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Cormorant Unicase", size: 16, color: "546E7A", bold: false, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Muli", size: 10, color: "455A64", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "37474F"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Muli', sans-serif;
|
||||
background: #FAFAFA;
|
||||
h1 { font-family: 'Cormorant Unicase', serif; font-size: 32pt; font-weight: 700; color: #37474F; text-align: center; margin-bottom: 24px; text-shadow: 1px 1px 0 #CCC; }
|
||||
h2 { font-family: 'Cormorant Unicase', serif; font-size: 16pt; color: #546E7A; margin-top: 32px; margin-bottom: 16px; border-bottom: 1px solid #CFD8DC; display: inline-block; padding-bottom: 4px; }
|
||||
p { font-size: 10pt; line-height: 1.7; color: #455A64; margin-bottom: 14px; }
|
||||
blockquote { background: #FFF; padding: 20px; border: 1px solid #ECEFF1; box-shadow: 2px 2px 5px rgba(0,0,0,0.05); margin: 24px 0; transform: rotate(1deg); }
|
||||
`
|
||||
};
|
||||
34
src/styles/templates/creative/pop-art-comic.ts
Normal file
34
src/styles/templates/creative/pop-art-comic.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const popArtComic: StyleOption = {
|
||||
id: 'pop-art-comic',
|
||||
name: 'Pop Art Comic',
|
||||
category: 'Creative',
|
||||
description: 'Roy Lichtenstein inspired. Bold black outlines, halftone vibes, and primary colors.',
|
||||
vibe: 'Comic, Bold, Pop',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Bangers&family=Comic+Neue:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Bangers", size: 42, color: "000000", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "FFFF00", color: "auto", style: "clear" } // Yellow back
|
||||
},
|
||||
heading2: {
|
||||
font: "Bangers", size: 24, color: "FFFFFF", bold: false, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
shading: { fill: "FF0000", color: "auto", style: "clear" } // Red back
|
||||
},
|
||||
body: {
|
||||
font: "Comic Neue", size: 12, color: "000000", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Comic Neue', sans-serif;
|
||||
h1 { font-family: 'Bangers', cursive; font-size: 42pt; color: #000000; background: #FFFF00; padding: 10px; border: 4px solid #000; box-shadow: 5px 5px 0 #000; margin-bottom: 24px; display: inline-block; }
|
||||
h2 { font-family: 'Bangers', cursive; font-size: 24pt; color: #FFFFFF; background: #FF0000; padding: 5px 15px; border: 3px solid #000; margin-top: 32px; margin-bottom: 16px; display: inline-block; transform: rotate(-2deg); }
|
||||
p { font-size: 12pt; line-height: 1.5; color: #000000; margin-bottom: 14px; font-weight: 700; }
|
||||
blockquote { background: #FFFFFF; border: 3px solid #000; padding: 20px; border-radius: 50% / 20%; margin: 24px 0; text-align: center; }
|
||||
`
|
||||
};
|
||||
35
src/styles/templates/creative/risograph-print.ts
Normal file
35
src/styles/templates/creative/risograph-print.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const risographPrint: StyleOption = {
|
||||
id: 'risograph-print',
|
||||
name: 'Risograph Print',
|
||||
category: 'Creative',
|
||||
description: 'Independent publishing style. Grainy textures, misalignment, and vibrant spot colors (Pink/Teal).',
|
||||
vibe: 'Artistic, Indie, Textured',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Eb+Garamond:ital,wght@0,400;0,700;1,400&family=Karla:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Eb Garamond", size: 42, color: "FF007F", bold: true, align: 'left', // Riso Pink
|
||||
spacing: { before: 400, after: 200, line: 200 },
|
||||
italic: true
|
||||
},
|
||||
heading2: {
|
||||
font: "Karla", size: 14, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
shading: { fill: "00A9FF", color: "auto", style: "clear" } // Riso Blue background
|
||||
},
|
||||
body: {
|
||||
font: "Karla", size: 10, color: "1A1A1A", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "FF007F"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Karla', sans-serif;
|
||||
background: #FFFEF0;
|
||||
h1 { font-family: 'Eb Garamond', serif; font-size: 42pt; font-weight: 700; font-style: italic; color: #FF007F; margin-bottom: 24px; mix-blend-mode: multiply; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #000000; background: #00A9FF; display: inline-block; padding: 4px 10px; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #1A1A1A; margin-bottom: 14px; }
|
||||
blockquote { border-left: 6px solid #FF007F; padding-left: 16px; margin: 24px 0; color: #555; font-style: italic; }
|
||||
`
|
||||
};
|
||||
34
src/styles/templates/creative/street-art-graffiti.ts
Normal file
34
src/styles/templates/creative/street-art-graffiti.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const streetArtGraffiti: StyleOption = {
|
||||
id: 'street-art-graffiti',
|
||||
name: 'Street Art Graffiti',
|
||||
category: 'Creative',
|
||||
description: 'Urban street style. Spray paint fonts, dripping effects, and concrete vibes.',
|
||||
vibe: 'Urban, Rebel, Spray',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Permanent+Marker&family=Rock+Salt&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Permanent Marker", size: 48, color: "000000", bold: false, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "FFFF00", color: "auto", style: "clear" } // Hazard Yellow
|
||||
},
|
||||
heading2: {
|
||||
font: "Rock Salt", size: 18, color: "FF0000", bold: false, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Permanent Marker", size: 12, color: "333333", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Permanent Marker', cursive;
|
||||
background: #F0F0F0;
|
||||
h1 { font-size: 48pt; color: #000000; text-align: center; background: #FFFF00; padding: 10px; transform: rotate(-2deg); margin-bottom: 24px; box-shadow: 4px 4px 0 #000; }
|
||||
h2 { font-family: 'Rock Salt', cursive; font-size: 18pt; color: #FF0000; margin-top: 32px; margin-bottom: 16px; transform: rotate(1deg); }
|
||||
p { font-size: 12pt; line-height: 1.6; color: #333333; margin-bottom: 14px; }
|
||||
blockquote { border-left: 5px solid #000; padding-left: 16px; margin: 24px 0; font-family: 'Rock Salt', cursive; font-size: 10pt; }
|
||||
`
|
||||
};
|
||||
35
src/styles/templates/creative/vaporwave-aesthetic.ts
Normal file
35
src/styles/templates/creative/vaporwave-aesthetic.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const vaporwaveAesthetic: StyleOption = {
|
||||
id: 'vaporwave-aesthetic',
|
||||
name: 'Vaporwave Aesthetic',
|
||||
category: 'Creative',
|
||||
description: 'Nostalgic 80s/90s internet culture. Pink and cyan gradients, wide tracking, and ironic luxury.',
|
||||
vibe: 'Nostalgic, Digital, Surreal',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Varela+Round&family=Montserrat:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Montserrat", size: 32, color: "FF71CE", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
allCaps: true,
|
||||
tracking: 100 // Wide spacing
|
||||
},
|
||||
heading2: {
|
||||
font: "Varela Round", size: 16, color: "01CDFE", bold: false, align: 'center',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Montserrat", size: 10, color: "B967FF", align: 'center',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "01CDFE"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Montserrat', sans-serif;
|
||||
background: #F0F0FF;
|
||||
h1 { font-size: 32pt; font-weight: 700; color: #FF71CE; text-align: center; margin-bottom: 24px; letter-spacing: 4px; text-shadow: 2px 2px #01CDFE; text-transform: uppercase; }
|
||||
h2 { font-family: 'Varela Round', sans-serif; font-size: 16pt; color: #01CDFE; text-align: center; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #B967FF; margin-bottom: 14px; text-align: center; }
|
||||
blockquote { border: 2px solid #FF71CE; padding: 16px; margin: 24px 0; background: #E0FFFF; color: #01CDFE; }
|
||||
`
|
||||
};
|
||||
32
src/styles/templates/creative/watercolor-wash.ts
Normal file
32
src/styles/templates/creative/watercolor-wash.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const watercolorWash: StyleOption = {
|
||||
id: 'watercolor-wash',
|
||||
name: 'Watercolor Wash',
|
||||
category: 'Creative',
|
||||
description: 'Artistic and fluid. Soft blended colors and painterly fonts.',
|
||||
vibe: 'Artistic, Soft, Fluid',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Kalam:wght@400;700&family=Amatic+SC:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Kalam", size: 36, color: "7986CB", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Amatic SC", size: 24, color: "4DB6AC", bold: true, align: 'center',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Kalam", size: 12, color: "616161", align: 'center',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "7986CB"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Kalam', cursive;
|
||||
h1 { font-size: 36pt; font-weight: 700; color: #7986CB; text-align: center; margin-bottom: 24px; text-shadow: 2px 2px 4px rgba(121, 134, 203, 0.3); }
|
||||
h2 { font-family: 'Amatic SC', cursive; font-size: 24pt; font-weight: 700; color: #4DB6AC; text-align: center; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 12pt; line-height: 1.6; color: #616161; margin-bottom: 14px; text-align: center; }
|
||||
blockquote { border: 2px solid #E0F2F1; background: #E8EAF6; padding: 20px; border-radius: 50% 20% / 10% 40%; margin: 24px 0; text-align: center; }
|
||||
`
|
||||
};
|
||||
33
src/styles/templates/editorial/art-nouveau-organic.ts
Normal file
33
src/styles/templates/editorial/art-nouveau-organic.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const artNouveauOrganic: StyleOption = {
|
||||
id: 'art-nouveau-organic',
|
||||
name: 'Art Nouveau Organic',
|
||||
category: 'Classic',
|
||||
description: 'Inspired by the Art Nouveau movement (1890-1910). Flowing organic lines with nature-inspired elegance and whiplash curves.',
|
||||
vibe: 'Organic, Flowing, Decorative',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Sorts+Mill+Goudy:wght@400&family=Fanwood+Text:wght@400&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Sorts Mill Goudy", size: 32, color: "4A5D23", bold: false, align: 'center',
|
||||
spacing: { before: 480, after: 280, line: 240 },
|
||||
border: { bottom: { color: "8FA876", space: 10, style: "single", size: 8 } }
|
||||
},
|
||||
heading2: {
|
||||
font: "Sorts Mill Goudy", size: 16, color: "6B7F4A", bold: false, align: 'left',
|
||||
spacing: { before: 360, after: 180, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Fanwood Text", size: 11, color: "3D4A2D", align: 'both',
|
||||
spacing: { before: 0, after: 180, line: 320 }
|
||||
},
|
||||
accentColor: "8FA876"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Fanwood Text', serif;
|
||||
h1 { font-family: 'Sorts Mill Goudy', serif; font-size: 32pt; color: #4A5D23; text-align: center; border-bottom: 2px solid #8FA876; padding-bottom: 16px; margin-bottom: 32px; }
|
||||
h2 { font-family: 'Sorts Mill Goudy', serif; font-size: 16pt; color: #6B7F4A; margin-top: 36px; margin-bottom: 18px; font-style: italic; }
|
||||
p { font-size: 11pt; line-height: 1.8; color: #3D4A2D; margin-bottom: 16px; text-align: justify; }
|
||||
blockquote { background: #F4F7F0; padding: 20px; border-left: 3px solid #8FA876; margin: 28px 0; font-style: italic; }
|
||||
`
|
||||
};
|
||||
35
src/styles/templates/editorial/arts-crafts-heritage.ts
Normal file
35
src/styles/templates/editorial/arts-crafts-heritage.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const artsCraftsHeritage: StyleOption = {
|
||||
id: 'arts-crafts-heritage',
|
||||
name: 'Arts & Crafts Heritage',
|
||||
category: 'Classic',
|
||||
description: 'Inspired by William Morris and the Arts & Crafts movement (1880s-1900). Emphasizes craftsmanship, natural forms, and medieval aesthetics with readable typography.',
|
||||
vibe: 'Artisan, Literary, Handcrafted',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@400;600;700&family=EB+Garamond:wght@400;500&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Cormorant Garamond", size: 28, color: "2F4F4F", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 240, line: 240 },
|
||||
border: {
|
||||
bottom: { color: "556B2F", space: 8, style: "single", size: 8 }
|
||||
}
|
||||
},
|
||||
heading2: {
|
||||
font: "Cormorant Garamond", size: 16, color: "556B2F", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "EB Garamond", size: 11, color: "3C3C3C", align: 'both',
|
||||
spacing: { before: 0, after: 160, line: 320 }
|
||||
},
|
||||
accentColor: "556B2F"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'EB Garamond', serif;
|
||||
h1 { font-family: 'Cormorant Garamond', serif; font-size: 28pt; font-weight: 700; color: #2F4F4F; text-align: center; border-bottom: 2px solid #556B2F; padding-bottom: 16px; margin-bottom: 28px; }
|
||||
h2 { font-family: 'Cormorant Garamond', serif; font-size: 16pt; font-weight: 700; color: #556B2F; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 11pt; line-height: 1.8; color: #3C3C3C; margin-bottom: 14px; text-align: justify; }
|
||||
blockquote { background: #F5F5DC; padding: 20px; border-left: 4px solid #556B2F; margin: 24px 0; font-style: italic; }
|
||||
`
|
||||
};
|
||||
32
src/styles/templates/editorial/baroque-splendor.ts
Normal file
32
src/styles/templates/editorial/baroque-splendor.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const baroqueSplendor: StyleOption = {
|
||||
id: 'baroque-splendor',
|
||||
name: 'Baroque Splendor',
|
||||
category: 'Classic',
|
||||
description: 'Heavy, dramatic 17th-century luxury. Deep golds and crimsons with deeply flourished script.',
|
||||
vibe: 'Luxurious, Dramatic, Heavy',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Mrs+Saint+Delafield&family=Mate:wght@400;500&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Mrs Saint Delafield", size: 48, color: "800000", bold: false, align: 'center',
|
||||
spacing: { before: 520, after: 320, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Mate", size: 16, color: "B8860B", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Mate", size: 12, color: "3D2B1F", align: 'both',
|
||||
spacing: { before: 0, after: 180, line: 320 }
|
||||
},
|
||||
accentColor: "B8860B"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Mate', serif;
|
||||
h1 { font-family: 'Mrs Saint Delafield', cursive; font-size: 48pt; color: #800000; text-align: center; margin-bottom: 36px; }
|
||||
h2 { font-size: 16pt; font-weight: 700; color: #B8860B; text-align: center; margin-top: 40px; margin-bottom: 20px; text-transform: uppercase; letter-spacing: 2px; }
|
||||
p { font-size: 12pt; line-height: 1.8; color: #3D2B1F; margin-bottom: 16px; text-align: justify; }
|
||||
blockquote { background: #FFF8E7; border: 2px double #B8860B; padding: 24px; margin: 32px 0; text-align: center; font-style: italic; }
|
||||
`
|
||||
};
|
||||
33
src/styles/templates/editorial/cottagecore-journal.ts
Normal file
33
src/styles/templates/editorial/cottagecore-journal.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const cottagecoreJournal: StyleOption = {
|
||||
id: 'cottagecore-journal',
|
||||
name: 'Cottagecore Journal',
|
||||
category: 'Aesthetic',
|
||||
description: 'Whimsical countryside diary. Handwritten fonts with soft sage greens and earthy browns.',
|
||||
vibe: 'Whimsical, Nature, Handmade',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Amatic+SC:wght@400;700&family=Patrick+Hand&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Amatic SC", size: 40, color: "33691E", bold: true, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Patrick Hand", size: 18, color: "5D4037", bold: true, align: 'center',
|
||||
spacing: { before: 320, after: 160, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Patrick Hand", size: 14, color: "424242", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "33691E"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Patrick Hand', cursive;
|
||||
background: #F1F8E9;
|
||||
h1 { font-family: 'Amatic SC', cursive; font-size: 40pt; font-weight: 700; color: #33691E; text-align: center; margin-bottom: 24px; }
|
||||
h2 { font-size: 18pt; font-weight: 700; color: #5D4037; text-align: center; margin-top: 30px; margin-bottom: 14px; border-bottom: 1px dashed #8D6E63; display: inline-block; }
|
||||
p { font-size: 14pt; line-height: 1.6; color: #424242; margin-bottom: 14px; }
|
||||
blockquote { background: #FFF; border: 1px dotted #33691E; padding: 20px; border-radius: 10px; margin: 24px 0; }
|
||||
`
|
||||
};
|
||||
32
src/styles/templates/editorial/dutch-golden-age.ts
Normal file
32
src/styles/templates/editorial/dutch-golden-age.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const dutchGoldenAge: StyleOption = {
|
||||
id: 'dutch-golden-age',
|
||||
name: 'Dutch Golden Age',
|
||||
category: 'Classic',
|
||||
description: 'Inspired by 17th century Dutch art and typography. Rich, painterly aesthetics with Rembrandt-era elegance.',
|
||||
vibe: 'Classical, Rich, Painterly',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Pirata+One&family=Gentium+Book+Plus:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Pirata One", size: 32, color: "3E2723", bold: false, align: 'center',
|
||||
spacing: { before: 480, after: 280, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Gentium Book Plus", size: 14, color: "5D4037", bold: true, align: 'left',
|
||||
spacing: { before: 360, after: 180, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Gentium Book Plus", size: 11, color: "4E342E", align: 'both',
|
||||
spacing: { before: 0, after: 180, line: 320 }
|
||||
},
|
||||
accentColor: "BF8040"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Gentium Book Plus', serif;
|
||||
h1 { font-family: 'Pirata One', cursive; font-size: 32pt; color: #3E2723; text-align: center; margin-bottom: 32px; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #5D4037; margin-top: 36px; margin-bottom: 18px; }
|
||||
p { font-size: 11pt; line-height: 1.8; color: #4E342E; margin-bottom: 16px; text-align: justify; }
|
||||
blockquote { background: #EFEBE9; padding: 20px; border: 1px solid #BF8040; margin: 28px 0; }
|
||||
`
|
||||
};
|
||||
34
src/styles/templates/editorial/fashion-magazine.ts
Normal file
34
src/styles/templates/editorial/fashion-magazine.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const fashionMagazine: StyleOption = {
|
||||
id: 'fashion-magazine',
|
||||
name: 'Fashion Magazine',
|
||||
category: 'Editorial',
|
||||
description: 'Trendy and bold. High-contrast typography with oversized lettering and pink accents.',
|
||||
vibe: 'Trendy, Loud, Pink',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Abril+Fatface&family=Raleway:wght@300;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Abril Fatface", size: 48, color: "E91E63", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 200 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Raleway", size: 14, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
allCaps: true,
|
||||
tracking: 200
|
||||
},
|
||||
body: {
|
||||
font: "Raleway", size: 10, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "E91E63"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Raleway', sans-serif;
|
||||
h1 { font-family: 'Abril Fatface', cursive; font-size: 48pt; color: #E91E63; margin-bottom: 24px; line-height: 0.9; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #000000; text-transform: uppercase; letter-spacing: 4px; margin-top: 32px; margin-bottom: 16px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #212121; margin-bottom: 14px; font-weight: 300; }
|
||||
blockquote { border-left: 10px solid #E91E63; padding-left: 20px; margin: 24px 0; font-family: 'Abril Fatface', cursive; font-size: 18pt; }
|
||||
`
|
||||
};
|
||||
35
src/styles/templates/editorial/film-script.ts
Normal file
35
src/styles/templates/editorial/film-script.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const filmScript: StyleOption = {
|
||||
id: 'film-script',
|
||||
name: 'Film Script',
|
||||
category: 'Editorial',
|
||||
description: 'Hollywood screenplay format. Courier font, specific margins, and character name centering.',
|
||||
vibe: 'Cinematic, Format, Draft',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Courier+Prime:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Courier Prime", size: 12, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 240, after: 240, line: 240 },
|
||||
allCaps: true,
|
||||
underline: true
|
||||
},
|
||||
heading2: {
|
||||
font: "Courier Prime", size: 12, color: "000000", bold: true, align: 'center',
|
||||
spacing: { before: 480, after: 0, line: 240 },
|
||||
allCaps: true
|
||||
},
|
||||
body: {
|
||||
font: "Courier Prime", size: 12, color: "000000", align: 'left',
|
||||
spacing: { before: 0, after: 0, line: 240 }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Courier Prime', monospace;
|
||||
h1 { font-size: 12pt; font-weight: 700; color: #000000; text-decoration: underline; text-transform: uppercase; margin-bottom: 12px; }
|
||||
h2 { font-size: 12pt; font-weight: 700; color: #000000; text-transform: uppercase; text-align: center; margin-top: 24px; margin-bottom: 0px; }
|
||||
p { font-size: 12pt; line-height: 1; color: #000000; margin-bottom: 12px; }
|
||||
blockquote { margin: 0 40px; text-align: center; }
|
||||
`
|
||||
};
|
||||
38
src/styles/templates/editorial/index.ts
Normal file
38
src/styles/templates/editorial/index.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
import { artNouveauOrganic } from './art-nouveau-organic';
|
||||
import { artsCraftsHeritage } from './arts-crafts-heritage';
|
||||
import { baroqueSplendor } from './baroque-splendor';
|
||||
import { cottagecoreJournal } from './cottagecore-journal';
|
||||
import { dutchGoldenAge } from './dutch-golden-age';
|
||||
import { fashionMagazine } from './fashion-magazine';
|
||||
import { filmScript } from './film-script';
|
||||
import { indieZine } from './indie-zine';
|
||||
import { literaryReview } from './literary-review';
|
||||
import { luxuryEditorial } from './luxury-editorial';
|
||||
import { neoGothicRevival } from './neo-gothic-revival';
|
||||
import { newspaperClassic } from './newspaper-classic';
|
||||
import { newspaperModern } from './newspaper-modern';
|
||||
import { newspaperTabloid } from './newspaper-tabloid';
|
||||
import { nyEditor } from './ny-editor';
|
||||
import { rococoRomance } from './rococo-romance';
|
||||
import { victorianOrnate } from './victorian-ornate';
|
||||
|
||||
export const editorialStyles: StyleOption[] = [
|
||||
artNouveauOrganic,
|
||||
artsCraftsHeritage,
|
||||
baroqueSplendor,
|
||||
cottagecoreJournal,
|
||||
dutchGoldenAge,
|
||||
fashionMagazine,
|
||||
filmScript,
|
||||
indieZine,
|
||||
literaryReview,
|
||||
luxuryEditorial,
|
||||
neoGothicRevival,
|
||||
newspaperClassic,
|
||||
newspaperModern,
|
||||
newspaperTabloid,
|
||||
nyEditor,
|
||||
rococoRomance,
|
||||
victorianOrnate
|
||||
];
|
||||
34
src/styles/templates/editorial/indie-zine.ts
Normal file
34
src/styles/templates/editorial/indie-zine.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const indieZine: StyleOption = {
|
||||
id: 'indie-zine',
|
||||
name: 'Indie Zine',
|
||||
category: 'Editorial',
|
||||
description: 'DIY photocopier aesthetic. Typewriter fonts, cut-out look, and rebellious asymmetry.',
|
||||
vibe: 'DIY, Rebellious, Rough',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Special+Elite&family=Rock+Salt&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Rock Salt", size: 28, color: "000000", bold: false, align: 'left',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
shading: { fill: "D1C4E9", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Special Elite", size: 14, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 320, after: 160, line: 240 },
|
||||
border: { bottom: { color: "000000", space: 4, style: "single", size: 12 } }
|
||||
},
|
||||
body: {
|
||||
font: "Special Elite", size: 10, color: "212121", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Special Elite', cursive;
|
||||
h1 { font-family: 'Rock Salt', cursive; font-size: 28pt; color: #000000; background: #D1C4E9; padding: 10px; transform: rotate(-2deg); margin-bottom: 24px; display: inline-block; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #000000; border-bottom: 2px solid #000; margin-top: 32px; margin-bottom: 16px; width: fit-content; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #212121; margin-bottom: 14px; }
|
||||
blockquote { border: 2px dashed #000; padding: 16px; margin: 24px 0; transform: rotate(1deg); }
|
||||
`
|
||||
};
|
||||
33
src/styles/templates/editorial/literary-review.ts
Normal file
33
src/styles/templates/editorial/literary-review.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const literaryReview: StyleOption = {
|
||||
id: 'literary-review',
|
||||
name: 'Literary Review',
|
||||
category: 'Editorial',
|
||||
description: 'Classic bookish aesthetic. Dense serif text, elegant headers, perfect for long-form essays.',
|
||||
vibe: 'Intellectual, Dense, Classic',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Crimson+Pro:ital,wght@0,400;0,700;1,400&family=Sorts+Mill+Goudy&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Crimson Pro", size: 30, color: "4A148C", bold: true, align: 'center',
|
||||
spacing: { before: 480, after: 280, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Crimson Pro", size: 14, color: "000000", bold: false, align: 'center',
|
||||
spacing: { before: 360, after: 180, line: 240 },
|
||||
smallCaps: true
|
||||
},
|
||||
body: {
|
||||
font: "Sorts Mill Goudy", size: 11, color: "212121", align: 'both',
|
||||
spacing: { before: 0, after: 160, line: 300 }
|
||||
},
|
||||
accentColor: "4A148C"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Sorts Mill Goudy', serif;
|
||||
h1 { font-family: 'Crimson Pro', serif; font-size: 30pt; font-weight: 700; color: #4A148C; text-align: center; margin-bottom: 32px; }
|
||||
h2 { font-family: 'Crimson Pro', serif; font-size: 14pt; color: #000000; text-align: center; margin-top: 36px; margin-bottom: 18px; font-variant: small-caps; }
|
||||
p { font-size: 11pt; line-height: 1.8; color: #212121; margin-bottom: 16px; text-align: justify; }
|
||||
blockquote { margin: 24px 40px; font-style: italic; color: #4A148C; }
|
||||
`
|
||||
};
|
||||
32
src/styles/templates/editorial/luxury-editorial.ts
Normal file
32
src/styles/templates/editorial/luxury-editorial.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const luxuryEditorial: StyleOption = {
|
||||
id: 'luxury-editorial',
|
||||
name: 'Luxury Editorial',
|
||||
category: 'Editorial',
|
||||
description: 'High-fashion magazine inspired design. Elegant serifs with sophisticated spacing and premium feel for upscale content.',
|
||||
vibe: 'Fashion, Premium, Sophisticated',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Cormorant:wght@400;500;700&family=Montserrat:wght@300;400;500&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Cormorant", size: 36, color: "1C1C1C", bold: false, align: 'center',
|
||||
spacing: { before: 480, after: 280, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Montserrat", size: 11, color: "1C1C1C", bold: true, align: 'left',
|
||||
spacing: { before: 360, after: 180, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Montserrat", size: 10, color: "3A3A3A", align: 'left',
|
||||
spacing: { before: 0, after: 180, line: 300 }
|
||||
},
|
||||
accentColor: "B8860B"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Montserrat', sans-serif;
|
||||
h1 { font-family: 'Cormorant', serif; font-size: 36pt; font-weight: 500; color: #1C1C1C; text-align: center; margin-bottom: 32px; letter-spacing: 2px; }
|
||||
h2 { font-size: 11pt; font-weight: 500; color: #1C1C1C; margin-top: 36px; margin-bottom: 18px; text-transform: uppercase; letter-spacing: 3px; }
|
||||
p { font-size: 10pt; line-height: 1.7; color: #3A3A3A; margin-bottom: 16px; font-weight: 300; }
|
||||
blockquote { border-top: 1px solid #B8860B; border-bottom: 1px solid #B8860B; padding: 24px 0; margin: 32px 0; text-align: center; font-family: 'Cormorant', serif; font-size: 14pt; font-style: italic; }
|
||||
`
|
||||
};
|
||||
36
src/styles/templates/editorial/neo-gothic-revival.ts
Normal file
36
src/styles/templates/editorial/neo-gothic-revival.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const neoGothicRevival: StyleOption = {
|
||||
id: 'neo-gothic-revival',
|
||||
name: 'Neo-Gothic Revival',
|
||||
category: 'Classic',
|
||||
description: 'Inspired by Gothic architecture and medieval manuscripts. Dark, dramatic typography with ecclesiastical gravitas.',
|
||||
vibe: 'Medieval, Dramatic, Historic',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Cinzel+Decorative:wght@400;700&family=Spectral:wght@400;500;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Cinzel Decorative", size: 28, color: "1A1A1A", bold: true, align: 'center',
|
||||
spacing: { before: 480, after: 280, line: 240 },
|
||||
border: {
|
||||
top: { color: "4A0E0E", space: 12, style: "single", size: 16 },
|
||||
bottom: { color: "4A0E0E", space: 12, style: "single", size: 16 }
|
||||
}
|
||||
},
|
||||
heading2: {
|
||||
font: "Cinzel Decorative", size: 14, color: "4A0E0E", bold: false, align: 'left',
|
||||
spacing: { before: 360, after: 180, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Spectral", size: 11, color: "2C2C2C", align: 'both',
|
||||
spacing: { before: 0, after: 180, line: 320 }
|
||||
},
|
||||
accentColor: "4A0E0E"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Spectral', serif;
|
||||
h1 { font-family: 'Cinzel Decorative', cursive; font-size: 28pt; font-weight: 700; color: #1A1A1A; text-align: center; border-top: 3px solid #4A0E0E; border-bottom: 3px solid #4A0E0E; padding: 20px 0; margin-bottom: 32px; }
|
||||
h2 { font-family: 'Cinzel Decorative', cursive; font-size: 14pt; color: #4A0E0E; margin-top: 36px; margin-bottom: 18px; }
|
||||
p { font-size: 11pt; line-height: 1.8; color: #2C2C2C; margin-bottom: 16px; text-align: justify; }
|
||||
blockquote { background: #F5F5EB; padding: 20px; border-left: 4px solid #4A0E0E; margin: 28px 0; font-style: italic; }
|
||||
`
|
||||
};
|
||||
32
src/styles/templates/editorial/newspaper-classic.ts
Normal file
32
src/styles/templates/editorial/newspaper-classic.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const newspaperClassic: StyleOption = {
|
||||
id: 'newspaper-classic',
|
||||
name: 'Newspaper Classic',
|
||||
category: 'Editorial',
|
||||
description: 'Traditional newspaper layout with strong typographic hierarchy. Bold headlines, readable body text, and authoritative presence.',
|
||||
vibe: 'News, Authority, Information',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Playfair+Display:wght@700;900&family=PT+Serif:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Playfair Display", size: 36, color: "000000", bold: true, align: 'center',
|
||||
spacing: { before: 240, after: 160, line: 220 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Playfair Display", size: 16, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 240, after: 120, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "PT Serif", size: 10, color: "1A1A1A", align: 'both',
|
||||
spacing: { before: 0, after: 120, line: 280 }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'PT Serif', serif;
|
||||
h1 { font-family: 'Playfair Display', serif; font-size: 36pt; font-weight: 900; color: #000000; text-align: center; border-bottom: 2px solid #000000; padding-bottom: 12px; margin-bottom: 20px; }
|
||||
h2 { font-family: 'Playfair Display', serif; font-size: 16pt; font-weight: 700; color: #000000; margin-top: 24px; margin-bottom: 12px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #1A1A1A; margin-bottom: 10px; text-align: justify; }
|
||||
blockquote { font-size: 14pt; font-style: italic; text-align: center; margin: 24px 40px; }
|
||||
`
|
||||
};
|
||||
32
src/styles/templates/editorial/newspaper-modern.ts
Normal file
32
src/styles/templates/editorial/newspaper-modern.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const newspaperModern: StyleOption = {
|
||||
id: 'newspaper-modern',
|
||||
name: 'Newspaper Modern',
|
||||
category: 'Editorial',
|
||||
description: 'Contemporary newspaper design balancing tradition with modern sensibilities. Clean grid-based layout.',
|
||||
vibe: 'Modern, Editorial, Informative',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=DM+Serif+Display&family=DM+Sans:wght@400;500;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "DM Serif Display", size: 36, color: "1A1A1A", bold: false, align: 'left',
|
||||
spacing: { before: 320, after: 200, line: 220 }
|
||||
},
|
||||
heading2: {
|
||||
font: "DM Sans", size: 12, color: "1A1A1A", bold: true, align: 'left',
|
||||
spacing: { before: 280, after: 140, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "DM Sans", size: 10, color: "333333", align: 'both',
|
||||
spacing: { before: 0, after: 140, line: 280 }
|
||||
},
|
||||
accentColor: "DC2626"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'DM Sans', sans-serif;
|
||||
h1 { font-family: 'DM Serif Display', serif; font-size: 36pt; color: #1A1A1A; margin-bottom: 24px; }
|
||||
h2 { font-size: 12pt; font-weight: 700; color: #1A1A1A; margin-top: 28px; margin-bottom: 14px; text-transform: uppercase; letter-spacing: 1px; }
|
||||
p { font-size: 10pt; line-height: 1.6; color: #333333; margin-bottom: 12px; text-align: justify; }
|
||||
blockquote { font-size: 16pt; font-style: italic; font-family: 'DM Serif Display', serif; text-align: center; margin: 28px 20px; color: #DC2626; }
|
||||
`
|
||||
};
|
||||
33
src/styles/templates/editorial/newspaper-tabloid.ts
Normal file
33
src/styles/templates/editorial/newspaper-tabloid.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const newspaperTabloid: StyleOption = {
|
||||
id: 'newspaper-tabloid',
|
||||
name: 'Newspaper Tabloid',
|
||||
category: 'Editorial',
|
||||
description: 'Sensationalist news design. Condensed, heavy headers with urgent red accents.',
|
||||
vibe: 'Urgent, Bold, Sensational',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Antonio:wght@700&family=Pathway+Extreme:wght@400;600&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Antonio", size: 42, color: "FFFFFF", bold: true, align: 'left',
|
||||
spacing: { before: 360, after: 200, line: 200 },
|
||||
shading: { fill: "D50000", color: "auto", style: "clear" }
|
||||
},
|
||||
heading2: {
|
||||
font: "Antonio", size: 20, color: "000000", bold: true, align: 'left',
|
||||
spacing: { before: 280, after: 140, line: 220 }
|
||||
},
|
||||
body: {
|
||||
font: "Pathway Extreme", size: 10, color: "111111", align: 'left',
|
||||
spacing: { before: 0, after: 160, line: 280 }
|
||||
},
|
||||
accentColor: "D50000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Pathway Extreme', sans-serif;
|
||||
h1 { font-family: 'Antonio', sans-serif; font-size: 42pt; font-weight: 700; color: #FFFFFF; background: #D50000; padding: 12px 16px; margin-bottom: 24px; text-transform: uppercase; line-height: 1; }
|
||||
h2 { font-family: 'Antonio', sans-serif; font-size: 20pt; font-weight: 700; color: #000000; margin-top: 28px; margin-bottom: 14px; text-transform: uppercase; }
|
||||
p { font-size: 10pt; line-height: 1.5; color: #111111; margin-bottom: 14px; }
|
||||
blockquote { font-size: 14pt; font-weight: 700; font-style: italic; color: #000000; border-left: 6px solid #D50000; padding-left: 16px; margin: 24px 0; }
|
||||
`
|
||||
};
|
||||
33
src/styles/templates/editorial/ny-editor.ts
Normal file
33
src/styles/templates/editorial/ny-editor.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const nyEditor: StyleOption = {
|
||||
id: 'ny-editor',
|
||||
name: 'The Editorial',
|
||||
category: 'Editorial',
|
||||
description: 'High-contrast serifs, centered headers, delicate borders. Feels like a premium magazine feature.',
|
||||
vibe: 'Luxury, Fashion, Literature',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,700;1,400&family=Lora:ital,wght@0,400;1,400&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Playfair Display", size: 36, color: "111111", bold: true, italic: true, align: 'center',
|
||||
spacing: { before: 600, after: 400, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Playfair Display", size: 14, color: "444444", bold: true, allCaps: true, tracking: 100, align: 'center',
|
||||
spacing: { before: 400, after: 200, line: 240 },
|
||||
border: { bottom: { color: "DDDDDD", space: 8, style: "single", size: 4 } }
|
||||
},
|
||||
body: {
|
||||
font: "Lora", size: 11, color: "333333", align: 'both',
|
||||
spacing: { before: 0, after: 200, line: 320 }
|
||||
},
|
||||
accentColor: "000000"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Lora', serif;
|
||||
h1 { font-family: 'Playfair Display', serif; font-size: 36pt; font-weight: 700; font-style: italic; text-align: center; margin-bottom: 30px; }
|
||||
h2 { font-family: 'Playfair Display', serif; font-size: 14pt; font-weight: 700; text-transform: uppercase; letter-spacing: 3px; text-align: center; border-bottom: 1px solid #ddd; padding-bottom: 10px; margin-top: 40px; color: #444; }
|
||||
p { font-size: 11pt; line-height: 1.8; text-align: justify; margin-bottom: 20px; }
|
||||
blockquote { font-family: 'Playfair Display', serif; font-size: 18pt; font-style: italic; text-align: center; color: #555; margin: 40px 20px; border: none; }
|
||||
`
|
||||
};
|
||||
32
src/styles/templates/editorial/rococo-romance.ts
Normal file
32
src/styles/templates/editorial/rococo-romance.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { StyleOption } from '../../../types';
|
||||
|
||||
export const rococoRomance: StyleOption = {
|
||||
id: 'rococo-romance',
|
||||
name: 'Rococo Romance',
|
||||
category: 'Classic',
|
||||
description: 'Inspired by 18th-century Rococo. Light, playful, and intricate with pastel tones and swirling elegance.',
|
||||
vibe: 'Romantic, Ornate, Pastel',
|
||||
googleFontsImport: 'https://fonts.googleapis.com/css2?family=Pinyon+Script&family=Playfair+Display+SC:wght@400;700&display=swap',
|
||||
wordConfig: {
|
||||
heading1: {
|
||||
font: "Pinyon Script", size: 36, color: "D87093", bold: false, align: 'center',
|
||||
spacing: { before: 480, after: 280, line: 240 }
|
||||
},
|
||||
heading2: {
|
||||
font: "Playfair Display SC", size: 14, color: "C0A080", bold: true, align: 'center',
|
||||
spacing: { before: 360, after: 180, line: 240 }
|
||||
},
|
||||
body: {
|
||||
font: "Playfair Display SC", size: 10, color: "555555", align: 'center',
|
||||
spacing: { before: 0, after: 180, line: 320 }
|
||||
},
|
||||
accentColor: "FFB6C1"
|
||||
},
|
||||
previewCss: `
|
||||
font-family: 'Playfair Display SC', serif;
|
||||
h1 { font-family: 'Pinyon Script', cursive; font-size: 36pt; color: #D87093; text-align: center; margin-bottom: 32px; }
|
||||
h2 { font-size: 14pt; font-weight: 700; color: #C0A080; text-align: center; margin-top: 36px; margin-bottom: 18px; letter-spacing: 2px; }
|
||||
p { font-size: 10pt; line-height: 1.8; color: #555555; margin-bottom: 16px; text-align: center; }
|
||||
blockquote { border: 1px solid #FFB6C1; padding: 20px; border-radius: 50% 50% 50% 50% / 10% 10% 10% 10%; margin: 28px 40px; text-align: center; }
|
||||
`
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user