/** * VisualEditor - Hostinger-Style Website Builder */ import React, { useState, useRef, useCallback } from 'react'; import { Canvas } from './Canvas'; import { StylePanel } from './StylePanel'; import { useVisualEditor } from '../hooks/useVisualEditor'; // Section templates for drag and drop const SECTION_TEMPLATES = { hero: `

Build Your Dream Website

Create stunning websites in minutes with our intuitive drag-and-drop builder. No coding required.

`, features: `

Why Choose Us

Everything you need to build a professional website

Lightning Fast

Optimized for speed with automatic performance enhancements.

🎨

Beautiful Design

Professionally designed templates you can customize.

🔒

Secure Hosting

Enterprise-grade security with free SSL certificates.

`, testimonials: `

What Our Users Say

"This builder transformed how we create websites. What used to take weeks now takes hours. The drag-and-drop interface is incredibly intuitive."

SJ
Sarah Johnson
Marketing Director

"Finally, a website builder that doesn't require a computer science degree. I built our company site in a weekend and it looks amazing."

MR
Mike Reynolds
Small Business Owner
`, cta: `

Ready to Get Started?

Join thousands of happy customers building amazing websites.

`, footer: ``, gallery: `

Our Work

Project 1 Project 2 Project 3
`, pricing: `

Simple Pricing

Choose the plan that's right for you

Starter
$9/mo
  • ✓ 1 Website
  • ✓ 10GB Storage
  • ✓ Free SSL
POPULAR
Professional
$29/mo
  • ✓ 10 Websites
  • ✓ 100GB Storage
  • ✓ Priority Support
Enterprise
$99/mo
  • ✓ Unlimited Sites
  • ✓ 1TB Storage
  • ✓ Dedicated Support
` }; // Element templates const ELEMENT_TEMPLATES = { heading: '

Your Heading Here

', paragraph: '

Add your text here. Click to edit this paragraph and make it your own.

', button: '', image: 'Image', divider: '
', spacer: '
', video: '
Video Placeholder
', form: `
` }; type DeviceMode = 'desktop' | 'tablet' | 'mobile'; type LeftPanelTab = 'add' | 'pages' | 'theme'; // SVG Icons const Icons = { desktop: , tablet: , mobile: , undo: , redo: , plus: , layers: , pages: , theme: , preview: , chevronDown: , chevronRight: , drag: , text: , image: , button: , video: , form: , divider: , spacer: }; export const VisualEditor: React.FC = () => { const { selectedElement, showSpacing, showDimensions, selectElement, deselectElement, applyStyle, canUndo, canRedo, undo, redo } = useVisualEditor(); const [deviceMode, setDeviceMode] = useState('desktop'); const [leftTab, setLeftTab] = useState('add'); const [expandedSections, setExpandedSections] = useState>(new Set(['sections', 'elements'])); const [zoom, setZoom] = useState(100); const [pageName, setPageName] = useState('Home'); const [draggedItem, setDraggedItem] = useState(null); const canvasRef = useRef<{ addElement: (html: string) => void }>(null); const toggleSection = (section: string) => { setExpandedSections(prev => { const next = new Set(prev); if (next.has(section)) next.delete(section); else next.add(section); return next; }); }; const handleDragStart = (e: React.DragEvent, type: string, template: string) => { setDraggedItem(type); e.dataTransfer.setData('text/html', template); e.dataTransfer.effectAllowed = 'copy'; }; const handleDragEnd = () => { setDraggedItem(null); }; // Get canvas width based on device mode const getCanvasWidth = () => { switch (deviceMode) { case 'tablet': return 768; case 'mobile': return 375; default: return '100%'; } }; return (
{/* ===== TOP HEADER ===== */}
W
WebBuilder
setPageName(e.target.value)} style={styles.pageNameInput} />
{(['desktop', 'tablet', 'mobile'] as DeviceMode[]).map(mode => ( ))}
{zoom}%
{/* ===== MAIN CONTENT ===== */}
{/* ===== LEFT PANEL ===== */} {/* ===== CANVAS AREA ===== */}
{/* ===== RIGHT PANEL (Style Panel) ===== */}
); }; // ===== STYLES ===== const styles: { [key: string]: React.CSSProperties } = { container: { display: 'flex', flexDirection: 'column', height: '100vh', width: '100vw', overflow: 'hidden', background: '#0c0c0c', fontFamily: "'Inter', -apple-system, BlinkMacSystemFont, sans-serif" }, // Header header: { height: '56px', background: '#161616', borderBottom: '1px solid #2a2a2a', display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 16px', flexShrink: 0 }, headerLeft: { display: 'flex', alignItems: 'center', gap: '16px' }, logo: { display: 'flex', alignItems: 'center', gap: '10px', color: '#fff', fontWeight: '600', fontSize: '15px' }, logoIcon: { width: '28px', height: '28px', background: 'linear-gradient(135deg, #6366f1, #8b5cf6)', borderRadius: '8px', display: 'flex', alignItems: 'center', justifyContent: 'center', fontWeight: '700', fontSize: '14px' }, dividerV: { width: '1px', height: '24px', background: '#333' }, pageNameInput: { background: '#222', border: '1px solid #333', borderRadius: '6px', padding: '8px 12px', color: '#fff', fontSize: '13px', width: '140px', outline: 'none' }, headerCenter: { display: 'flex', alignItems: 'center', gap: '16px' }, deviceToggle: { display: 'flex', background: '#222', borderRadius: '8px', padding: '4px' }, deviceBtn: { background: 'none', border: 'none', color: '#666', padding: '8px 12px', borderRadius: '6px', cursor: 'pointer', display: 'flex', alignItems: 'center', transition: 'all 0.15s' }, deviceBtnActive: { background: '#6366f1', color: '#fff' }, zoomControl: { display: 'flex', alignItems: 'center', gap: '4px', background: '#222', borderRadius: '6px', padding: '4px' }, zoomBtn: { background: 'none', border: 'none', color: '#888', width: '28px', height: '28px', borderRadius: '4px', cursor: 'pointer', fontSize: '16px', display: 'flex', alignItems: 'center', justifyContent: 'center' }, zoomValue: { color: '#888', fontSize: '12px', minWidth: '40px', textAlign: 'center' }, headerRight: { display: 'flex', alignItems: 'center', gap: '8px' }, headerBtn: { background: '#222', border: '1px solid #333', color: '#aaa', padding: '8px 12px', borderRadius: '6px', cursor: 'pointer', display: 'flex', alignItems: 'center', gap: '6px', fontSize: '13px', transition: 'all 0.15s' }, publishBtn: { background: 'linear-gradient(135deg, #6366f1, #8b5cf6)', border: 'none', color: '#fff', padding: '10px 20px', borderRadius: '6px', cursor: 'pointer', fontWeight: '600', fontSize: '13px' }, // Main main: { display: 'flex', flex: 1, overflow: 'hidden' }, // Left Panel leftPanel: { width: '280px', background: '#161616', borderRight: '1px solid #2a2a2a', display: 'flex', flexDirection: 'column', flexShrink: 0 }, leftTabs: { display: 'flex', borderBottom: '1px solid #2a2a2a' }, leftTab: { flex: 1, background: 'none', border: 'none', color: '#666', padding: '14px 8px', cursor: 'pointer', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '4px', fontSize: '11px', transition: 'all 0.15s' }, leftTabActive: { color: '#fff', background: '#1e1e1e' }, leftContent: { flex: 1, overflowY: 'auto', padding: '12px' }, // Accordion accordion: { marginBottom: '8px' }, accordionHeader: { width: '100%', background: '#1e1e1e', border: 'none', borderRadius: '8px', padding: '12px 14px', color: '#fff', fontSize: '13px', fontWeight: '500', cursor: 'pointer', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }, accordionBody: { padding: '12px 0' }, // Section Grid sectionGrid: { display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '8px' }, sectionItem: { background: '#1e1e1e', borderRadius: '8px', padding: '16px 8px', textAlign: 'center', cursor: 'grab', border: '1px solid transparent', transition: 'all 0.15s' }, sectionItemDragging: { opacity: 0.5, border: '1px solid #6366f1' }, sectionThumb: { fontSize: '24px', marginBottom: '8px' }, sectionLabel: { color: '#888', fontSize: '11px' }, // Element Item elementItem: { display: 'flex', alignItems: 'center', gap: '12px', padding: '12px', background: '#1e1e1e', borderRadius: '8px', marginBottom: '6px', cursor: 'grab', color: '#aaa', fontSize: '13px', border: '1px solid transparent', transition: 'all 0.15s' }, elementItemDragging: { opacity: 0.5, border: '1px solid #6366f1' }, elementIcon: { color: '#666' }, dragHandle: { marginLeft: 'auto', color: '#444' }, // Pages pagesList: { display: 'flex', flexDirection: 'column', gap: '4px' }, pageItem: { display: 'flex', alignItems: 'center', gap: '10px', padding: '12px', background: '#1e1e1e', borderRadius: '8px', color: '#aaa', fontSize: '13px', cursor: 'pointer' }, addPageBtn: { display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '8px', padding: '12px', background: 'none', border: '1px dashed #333', borderRadius: '8px', color: '#666', fontSize: '13px', cursor: 'pointer', marginTop: '8px' }, // Theme themePanel: { display: 'flex', flexDirection: 'column', gap: '20px' }, themeSection: {}, themeSectionTitle: { color: '#888', fontSize: '11px', fontWeight: '600', textTransform: 'uppercase', letterSpacing: '0.5px', marginBottom: '12px' }, colorGrid: { display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: '8px' }, colorSwatch: { aspectRatio: '1', borderRadius: '8px', cursor: 'pointer', border: '2px solid transparent' }, themeSelect: { width: '100%', background: '#1e1e1e', border: '1px solid #333', borderRadius: '6px', padding: '10px 12px', color: '#fff', fontSize: '13px', cursor: 'pointer' }, // Canvas canvasWrapper: { flex: 1, background: '#0c0c0c', display: 'flex', justifyContent: 'center', alignItems: 'flex-start', overflow: 'auto', padding: '24px' }, canvasContainer: { background: '#fff', borderRadius: '8px', overflow: 'hidden', boxShadow: '0 0 0 1px rgba(255,255,255,0.1), 0 30px 100px rgba(0,0,0,0.5)', minHeight: '100%' } }; export default VisualEditor;