feat: Transform to Tauri desktop app
- Initialize Tauri v2 project with Rust backend - Restructure project: move source files to src/ directory - Add Tauri configuration for Windows, macOS, and Linux builds - Update Vite config for Tauri development workflow - Add file system and dialog permissions for native features - Update package.json with desktop build scripts - Update tsconfig.json paths for new src structure - Add Tauri and desktop badges to README - Document desktop build process and architecture
This commit is contained in:
128
src/components/StylePreviewModal.tsx
Normal file
128
src/components/StylePreviewModal.tsx
Normal file
@@ -0,0 +1,128 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { X } from 'lucide-react';
|
||||
import { StyleOption } from '../types';
|
||||
|
||||
interface StylePreviewModalProps {
|
||||
style: StyleOption;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
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>
|
||||
|
||||
<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>
|
||||
|
||||
<blockquote>
|
||||
"Design is not just what it looks like and feels like. Design is how it works."
|
||||
</blockquote>
|
||||
|
||||
<h2>2. Key Elements</h2>
|
||||
<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>
|
||||
</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>
|
||||
`;
|
||||
|
||||
export const StylePreviewModal: React.FC<StylePreviewModalProps> = ({ style, onClose }) => {
|
||||
const iframeRef = useRef<HTMLIFrameElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const handleEscape = (e: KeyboardEvent) => {
|
||||
if (e.key === 'Escape') onClose();
|
||||
};
|
||||
window.addEventListener('keydown', handleEscape);
|
||||
return () => window.removeEventListener('keydown', handleEscape);
|
||||
}, [onClose]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!iframeRef.current) 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="${style.googleFontsImport}" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
background-color: #fff;
|
||||
margin: 0;
|
||||
padding: 40px;
|
||||
/* Inject default body color from config */
|
||||
color: #${style.wordConfig.body.color};
|
||||
/* Apply Sample CSS */
|
||||
${style.previewCss}
|
||||
}
|
||||
/* Override body margins from preview css to fit modal better */
|
||||
body { width: 100%; height: 100%; box-sizing: border-box; overflow-y: auto; }
|
||||
h1 { margin-top: 0 !important; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
${SAMPLE_CONTENT}
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
doc.open();
|
||||
doc.write(html);
|
||||
doc.close();
|
||||
}
|
||||
}, [style]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="fixed inset-0 z-[100] flex items-center justify-center p-4 bg-zinc-950/80 backdrop-blur-sm animate-in fade-in duration-200"
|
||||
onClick={(e) => {
|
||||
// Close if clicking the background overlay directly
|
||||
if (e.target === e.currentTarget) {
|
||||
onClose();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="relative w-full max-w-3xl bg-zinc-900 rounded-2xl border border-zinc-700 shadow-2xl overflow-hidden flex flex-col h-[85vh]">
|
||||
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between p-4 border-b border-zinc-800 bg-zinc-900/50">
|
||||
<div>
|
||||
<h3 className="text-xl font-bold text-white">{style.name}</h3>
|
||||
<p className="text-sm text-zinc-400">{style.description}</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="p-2 text-zinc-400 hover:text-white hover:bg-zinc-800 rounded-full transition-colors"
|
||||
>
|
||||
<X size={24} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="flex-grow bg-zinc-800 p-1 overflow-hidden relative">
|
||||
<div className="w-full h-full bg-white rounded-lg overflow-hidden shadow-inner">
|
||||
<iframe
|
||||
ref={iframeRef}
|
||||
title="Style Preview"
|
||||
className="w-full h-full border-0"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<div className="p-4 border-t border-zinc-800 bg-zinc-900 flex justify-end">
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="px-4 py-2 bg-indigo-600 hover:bg-indigo-500 text-white font-medium rounded-lg transition-colors"
|
||||
>
|
||||
Close Preview
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user