webbuilder1-0 / index.html
Vishau's picture
still i cant drag and get the element on my working area. and properties aslo not usable. please make it working - Follow Up Deployment
d959446 verified
Raw
History Blame Contribute Delete
61.7 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Drag & Drop Website Builder</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.element-item {
transition: all 0.2s ease;
cursor: grab;
user-select: none;
}
.draggable-element {
position: absolute;
z-index: 1;
user-select: none;
}
.element-item:hover {
transform: translateY(-2px);
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.element-item:active {
cursor: grabbing;
}
.canvas-placeholder {
transition: all 0.3s ease;
}
.canvas-placeholder.highlight {
background-color: rgba(59, 130, 246, 0.2);
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.8);
}
.resize-handle {
position: absolute;
width: 10px;
height: 10px;
background-color: #3b82f6;
border-radius: 50%;
z-index: 10;
opacity: 0;
transition: opacity 0.2s;
}
.resize-handle.top-left {
top: -5px;
left: -5px;
cursor: nwse-resize;
}
.resize-handle.top-right {
top: -5px;
right: -5px;
cursor: nesw-resize;
}
.resize-handle.bottom-left {
bottom: -5px;
left: -5px;
cursor: nesw-resize;
}
.resize-handle.bottom-right {
bottom: -5px;
right: -5px;
cursor: nwse-resize;
}
.draggable-element:hover .resize-handle {
opacity: 1;
}
</style>
</head>
<body class="bg-gray-100 font-sans">
<div class="flex flex-col h-screen">
<!-- Header -->
<header class="bg-blue-600 text-white p-4 shadow-md">
<div class="container mx-auto">
<div class="flex justify-between items-center mb-2">
<div class="flex items-center space-x-2">
<i class="fas fa-globe text-2xl"></i>
<h1 class="text-xl font-bold">Drag & Drop Website Builder</h1>
</div>
<button id="export-btn" class="bg-green-500 hover:bg-green-600 text-white px-4 py-2 rounded flex items-center space-x-2 transition-colors">
<i class="fas fa-share-alt"></i>
<span>Export & Share</span>
</button>
</div>
<div class="flex space-x-3">
<select id="theme-selector" class="px-3 py-1 rounded bg-blue-500 text-white border-white border">
<option value="business">Business</option>
<option value="portfolio">Portfolio</option>
<option value="blog">Blog</option>
<option value="education">Education</option>
<option value="personal">Personal</option>
</select>
<button id="apply-theme" class="bg-blue-700 hover:bg-blue-800 text-white px-3 py-1 rounded text-sm">
Apply Theme
</button>
</div>
</div>
<button id="export-btn" class="bg-green-500 hover:bg-green-600 text-white px-4 py-2 rounded flex items-center space-x-2 transition-colors">
<i class="fas fa-share-alt"></i>
<span>Export & Share</span>
</button>
</div>
</header>
<!-- Main Content -->
<div class="flex flex-1 overflow-hidden">
<!-- Elements Panel -->
<div class="w-64 bg-white shadow-md p-4 overflow-y-auto">
<h2 class="text-lg font-semibold mb-4 text-gray-700 border-b pb-2">Elements</h2>
<div class="grid grid-cols-3 gap-3">
<!-- Basic Elements -->
<div class="element-item bg-gray-50 p-3 rounded border border-gray-200 flex flex-col items-center justify-center text-center" draggable="true" data-type="text">
<i class="fas fa-text-height text-blue-500 text-xl mb-2"></i>
<span class="text-sm text-gray-700">Text</span>
</div>
<div class="element-item bg-gray-50 p-3 rounded border border-gray-200 flex flex-col items-center justify-center text-center" draggable="true" data-type="image">
<i class="fas fa-image text-blue-500 text-xl mb-2"></i>
<span class="text-sm text-gray-700">Image</span>
</div>
<div class="element-item bg-gray-50 p-3 rounded border border-gray-200 flex flex-col items-center justify-center text-center" draggable="true" data-type="button">
<i class="fas fa-mouse-pointer text-blue-500 text-xl mb-2"></i>
<span class="text-sm text-gray-700">Button</span>
</div>
<!-- Media Elements -->
<div class="element-item bg-gray-50 p-3 rounded border border-gray-200 flex flex-col items-center justify-center text-center" draggable="true" data-type="gallery">
<i class="fas fa-images text-blue-500 text-xl mb-2"></i>
<span class="text-sm text-gray-700">Gallery</span>
</div>
<div class="element-item bg-gray-50 p-3 rounded border border-gray-200 flex flex-col items-center justify-center text-center" draggable="true" data-type="slideshow">
<i class="fas fa-photo-video text-blue-500 text-xl mb-2"></i>
<span class="text-sm text-gray-700">Slideshow</span>
</div>
<div class="element-item bg-gray-50 p-3 rounded border border-gray-200 flex flex-col items-center justify-center text-center" draggable="true" data-type="video">
<i class="fas fa-video text-blue-500 text-xl mb-2"></i>
<span class="text-sm text-gray-700">HD Video</span>
</div>
<!-- Layout Elements -->
<div class="element-item bg-gray-50 p-3 rounded border border-gray-200 flex flex-col items-center justify-center text-center" draggable="true" data-type="divider">
<i class="fas fa-minus text-blue-500 text-xl mb-2"></i>
<span class="text-sm text-gray-700">Divider</span>
</div>
<div class="element-item bg-gray-50 p-3 rounded border border-gray-200 flex flex-col items-center justify-center text-center" draggable="true" data-type="spacer">
<i class="fas fa-arrows-alt-v text-blue-500 text-xl mb-2"></i>
<span class="text-sm text-gray-700">Spacer</span>
</div>
<!-- Forms -->
<div class="element-item bg-gray-50 p-3 rounded border border-gray-200 flex flex-col items-center justify-center text-center" draggable="true" data-type="contact_form">
<i class="fas fa-envelope text-blue-500 text-xl mb-2"></i>
<span class="text-sm text-gray-700">Contact Form</span>
</div>
<div class="element-item bg-gray-50 p-3 rounded border border-gray-200 flex flex-col items-center justify-center text-center" draggable="true" data-type="newsletter">
<i class="fas fa-newspaper text-blue-500 text-xl mb-2"></i>
<span class="text-sm text-gray-700">Newsletter</span>
</div>
<div class="element-item bg-gray-50 p-3 rounded border border-gray-200 flex flex-col items-center justify-center text-center" draggable="true" data-type="file_upload">
<i class="fas fa-file-upload text-blue-500 text-xl mb-2"></i>
<span class="text-sm text-gray-700">File Upload</span>
</div>
<!-- Other Elements -->
<div class="element-item bg-gray-50 p-3 rounded border border-gray-200 flex flex-col items-center justify-center text-center" draggable="true" data-type="map">
<i class="fas fa-map-marked-alt text-blue-500 text-xl mb-2"></i>
<span class="text-sm text-gray-700">Map</span>
</div>
<div class="element-item bg-gray-50 p-3 rounded border border-gray-200 flex flex-col items-center justify-center text-center" draggable="true" data-type="social">
<i class="fas fa-share-alt text-blue-500 text-xl mb-2"></i>
<span class="text-sm text-gray-700">Social Icons</span>
</div>
<div class="element-item bg-gray-50 p-3 rounded border border-gray-200 flex flex-col items-center justify-center text-center" draggable="true" data-type="quote">
<i class="fas fa-quote-right text-blue-500 text-xl mb-2"></i>
<span class="text-sm text-gray-700">Block Quote</span>
</div>
<div class="element-item bg-gray-50 p-3 rounded border border-gray-200 flex flex-col items-center justify-center text-center" draggable="true" data-type="search">
<i class="fas fa-search text-blue-500 text-xl mb-2"></i>
<span class="text-sm text-gray-700">Search Box</span>
</div>
<div class="element-item bg-gray-50 p-3 rounded border border-gray-200 flex flex-col items-center justify-center text-center" draggable="true" data-type="embed">
<i class="fas fa-code text-blue-500 text-xl mb-2"></i>
<span class="text-sm text-gray-700">Embed Code</span>
</div>
<div class="element-item bg-gray-50 p-3 rounded border border-gray-200 flex flex-col items-center justify-center text-center" draggable="true" data-type="pdf">
<i class="fas fa-file-pdf text-blue-500 text-xl mb-2"></i>
<span class="text-sm text-gray-700">PDF Document</span>
</div>
<div class="element-item bg-gray-50 p-3 rounded border border-gray-200 flex flex-col items-center justify-center text-center" draggable="true" data-type="products">
<i class="fas fa-shopping-bag text-blue-500 text-xl mb-2"></i>
<span class="text-sm text-gray-700">Products</span>
</div>
<div class="element-item bg-gray-50 p-3 rounded border border-gray-200 flex flex-col items-center justify-center text-center" draggable="true" data-type="categories">
<i class="fas fa-tags text-blue-500 text-xl mb-2"></i>
<span class="text-sm text-gray-700">Categories</span>
</div>
</div>
</div>
<!-- Canvas Area -->
<div class="flex-1 bg-gray-100 p-6 overflow-auto flex items-start justify-center">
<div id="canvas" class="bg-white shadow-lg w-full max-w-4xl min-h-[80vh] relative canvas-placeholder">
<div class="absolute inset-0 flex items-center justify-center text-gray-400" id="empty-canvas-msg">
<div class="text-center">
<i class="fas fa-arrow-left text-3xl mb-2"></i>
<p>Drag elements here to build your page</p>
</div>
</div>
</div>
</div>
<!-- Properties Panel -->
<div class="w-64 bg-white shadow-md p-4 overflow-y-auto">
<h2 class="text-lg font-semibold mb-4 text-gray-700 border-b pb-2">Properties</h2>
<div id="properties-panel" class="text-gray-600">
<div class="text-center py-12 text-gray-400" id="no-selection-msg">
<i class="fas fa-hand-pointer text-3xl mb-2"></i>
<p>Select an element to edit properties</p>
</div>
<div id="element-properties" class="hidden space-y-4">
<div class="space-y-2">
<label class="block text-sm font-medium">Element Type</label>
<input type="text" id="prop-type" class="w-full px-3 py-2 border rounded bg-gray-50" readonly>
</div>
<!-- Position & Size -->
<div class="space-y-2">
<label class="block text-sm font-medium">Position & Size</label>
<div class="grid grid-cols-2 gap-2">
<div>
<label class="text-xs block">X</label>
<input type="number" id="prop-x" class="w-full px-2 py-1 border rounded">
</div>
<div>
<label class="text-xs block">Y</label>
<input type="number" id="prop-y" class="w-full px-2 py-1 border rounded">
</div>
<div>
<label class="text-xs block">Width</label>
<input type="number" id="prop-width" class="w-full px-2 py-1 border rounded">
</div>
<div>
<label class="text-xs block">Height</label>
<input type="number" id="prop-height" class="w-full px-2 py-1 border rounded">
</div>
</div>
</div>
<!-- Content Section -->
<div id="content-properties" class="space-y-2 hidden">
<label class="block text-sm font-medium">Content</label>
<textarea id="prop-content" class="w-full px-3 py-2 border rounded" rows="3"></textarea>
</div>
<!-- Style Section -->
<div class="space-y-2">
<label class="block text-sm font-medium">Style</label>
<div>
<label class="text-xs block">Background Color</label>
<input type="color" id="prop-bgcolor" class="w-full h-8">
</div>
<div>
<label class="text-xs block">Text Color</label>
<input type="color" id="prop-color" class="w-full h-8">
</div>
<div>
<label class="text-xs block">Font Size</label>
<select id="prop-fontsize" class="w-full px-2 py-1 border rounded">
<option value="12px">Small</option>
<option value="16px">Medium</option>
<option value="20px">Large</option>
<option value="24px">Extra Large</option>
</select>
</div>
</div>
<div class="pt-4">
<button id="delete-element" class="w-full bg-red-500 text-white py-2 rounded hover:bg-red-600 transition-colors">
<i class="fas fa-trash mr-2"></i>Delete Element
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
<!-- Export Modal -->
<div id="export-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50">
<div class="bg-white rounded-lg shadow-xl w-full max-w-xl">
<div class="p-6">
<div class="flex justify-between items-center mb-4">
<h3 class="text-xl font-semibold">Export Your Website</h3>
<button id="close-export-modal" class="text-gray-500 hover:text-gray-700">
<i class="fas fa-times"></i>
</button>
</div>
<div class="mb-4">
<p class="text-gray-600 mb-4">Here's your website design. You can save it as an image and share it.</p>
<div id="export-preview" class="border border-gray-300 p-4 bg-white"></div>
</div>
<div class="flex justify-end space-x-3">
<button id="download-btn" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded flex items-center space-x-2">
<i class="fas fa-download"></i>
<span>Download</span>
</button>
<button id="whatsapp-share" class="bg-green-500 hover:bg-green-600 text-white px-4 py-2 rounded flex items-center space-x-2">
<i class="fab fa-whatsapp"></i>
<span>Share via WhatsApp</span>
</button>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Element templates
const elementTemplates = {
text: {
html: `<div class="draggable-element bg-white p-4 rounded border border-blue-300 cursor-move relative" data-type="text">
<div class="resize-handle top-left"></div>
<div class="resize-handle top-right"></div>
<div class="resize-handle bottom-left"></div>
<div class="resize-handle bottom-right"></div>
<p class="text-gray-700">Double click to edit this text</p>
</div>`,
width: 200,
height: 100
},
image: {
html: `<div class="draggable-element bg-gray-100 rounded border border-blue-300 cursor-move relative flex items-center justify-center overflow-hidden" data-type="image">
<div class="resize-handle top-left"></div>
<div class="resize-handle top-right"></div>
<div class="resize-handle bottom-left"></div>
<div class="resize-handle bottom-right"></div>
<img src="https://via.placeholder.com/200x150" alt="Placeholder" class="w-full h-full object-cover">
</div>`,
width: 200,
height: 150
},
button: {
html: `<div class="draggable-element bg-white rounded cursor-move relative" data-type="button">
<div class="resize-handle top-left"></div>
<div class="resize-handle top-right"></div>
<div class="resize-handle bottom-left"></div>
<div class="resize-handle bottom-right"></div>
<button class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded transition-colors" style="min-width: 120px;">Click Me</button>
</div>`,
width: 120,
height: 40
},
video: {
html: `<div class="draggable-element bg-gray-900 rounded border border-blue-300 cursor-move relative flex items-center justify-center" data-type="video">
<div class="resize-handle top-left"></div>
<div class="resize-handle top-right"></div>
<div class="resize-handle bottom-left"></div>
<div class="resize-handle bottom-right"></div>
<i class="fas fa-play text-white text-3xl"></i>
</div>`,
width: 300,
height: 200
},
divider: {
html: `<div class="draggable-element cursor-move relative" data-type="divider">
<div class="resize-handle top-left"></div>
<div class="resize-handle top-right"></div>
<div class="resize-handle bottom-left"></div>
<div class="resize-handle bottom-right"></div>
<hr class="border-t-2 border-gray-300">
</div>`,
width: 300,
height: 10
},
contact_form: {
html: `<div class="draggable-element bg-white rounded border border-blue-300 cursor-move relative p-4 space-y-3" data-type="contact_form" style="width: 300px;">
<div class="resize-handle top-left"></div>
<div class="resize-handle top-right"></div>
<div class="resize-handle bottom-left"></div>
<div class="resize-handle bottom-right"></div>
<h3 class="font-medium text-lg">Contact Us</h3>
<input type="text" placeholder="Name" class="w-full px-3 py-2 border rounded">
<input type="email" placeholder="Email" class="w-full px-3 py-2 border rounded">
<textarea placeholder="Message" class="w-full px-3 py-2 border rounded"></textarea>
<button class="bg-blue-500 hover:bg-blue-600 text-white w-full py-2 rounded transition-colors">
Send Message
</button>
</div>`,
width: 300,
height: 250
},
newsletter: {
html: `<div class="draggable-element bg-white rounded border border-blue-300 cursor-move relative p-4" data-type="newsletter" style="width: 300px;">
<div class="resize-handle top-left"></div>
<div class="resize-handle top-right"></div>
<div class="resize-handle bottom-left"></div>
<div class="resize-handle bottom-right"></div>
<h3 class="font-medium text-lg mb-2">Subscribe</h3>
<p class="text-gray-600 text-sm mb-3">Get the latest updates</p>
<input type="email" placeholder="Your email" class="w-full px-3 py-2 border rounded mb-2">
<button class="bg-blue-500 hover:bg-blue-600 text-white w-full py-2 rounded transition-colors">
Subscribe
</button>
</div>`,
width: 300,
height: 180
},
gallery: {
html: `<div class="draggable-element bg-white rounded border border-blue-300 cursor-move relative p-2" data-type="gallery" style="width: 350px;">
<div class="resize-handle top-left"></div>
<div class="resize-handle top-right"></div>
<div class="resize-handle bottom-left"></div>
<div class="resize-handle bottom-right"></div>
<div class="grid grid-cols-2 gap-2">
<img src="https://via.placeholder.com/160x160" class="w-full h-auto rounded">
<img src="https://via.placeholder.com/160x160" class="w-full h-auto rounded">
<img src="https://via.placeholder.com/160x160" class="w-full h-auto rounded">
<img src="https://via.placeholder.com/160x160" class="w-full h-auto rounded">
</div>
</div>`,
width: 350,
height: 350
},
slideshow: {
html: `<div class="draggable-element bg-white rounded border border-blue-300 cursor-move relative overflow-hidden" data-type="slideshow" style="width: 400px; height: 250px;">
<div class="resize-handle top-left"></div>
<div class="resize-handle top-right"></div>
<div class="resize-handle bottom-left"></div>
<div class="resize-handle bottom-right"></div>
<div class="relative w-full h-full">
<img src="https://via.placeholder.com/400x250" class="absolute inset-0 w-full h-full object-cover">
<div class="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/70 to-transparent p-4">
<h3 class="text-white font-medium text-lg">Slide Title</h3>
</div>
<div class="absolute bottom-0 right-0 p-2">
<button class="rounded-full bg-black/50 text-white p-1 mx-1"><i class="fas fa-circle text-xs"></i></button>
<button class="rounded-full bg-black/50 text-white p-1 mx-1"><i class="far fa-circle text-xs"></i></button>
<button class="rounded-full bg-black/50 text-white p-1 mx-1"><i class="far fa-circle text-xs"></i></button>
</div>
</div>
</div>`,
width: 400,
height: 250
},
map: {
html: `<div class="draggable-element bg-gray-200 rounded border border-blue-300 cursor-move relative" data-type="map" style="width: 350px; height: 250px;">
<div class="resize-handle top-left"></div>
<div class="resize-handle top-right"></div>
<div class="resize-handle bottom-left"></div>
<div class="resize-handle bottom-right"></div>
<div class="absolute inset-0 flex items-center justify-center text-blue-500">
<i class="fas fa-map-marked-alt text-4xl"></i>
</div>
<p class="absolute bottom-0 left-0 right-0 bg-white/80 text-center py-1 text-sm">Google Maps will appear here</p>
</div>`,
width: 350,
height: 250
},
social: {
html: `<div class="draggable-element bg-white rounded border border-blue-300 cursor-move relative p-4" data-type="social" style="width: 300px;">
<div class="resize-handle top-left"></div>
<div class="resize-handle top-right"></div>
<div class="resize-handle bottom-left"></div>
<div class="resize-handle bottom-right"></div>
<div class="flex justify-center space-x-4">
<a href="#" class="text-xl text-blue-500 hover:text-blue-700"><i class="fab fa-facebook"></i></a>
<a href="#" class="text-xl text-blue-400 hover:text-blue-600"><i class="fab fa-twitter"></i></a>
<a href="#" class="text-xl text-pink-500 hover:text-pink-700"><i class="fab fa-instagram"></i></a>
<a href="#" class="text-xl text-red-500 hover:text-red-700"><i class="fab fa-youtube"></i></a>
</div>
</div>`,
width: 300,
height: 80
},
quote: {
html: `<div class="draggable-element bg-white rounded border border-blue-300 cursor-move relative p-4" data-type="quote" style="width: 300px;">
<div class="resize-handle top-left"></div>
<div class="resize-handle top-right"></div>
<div class="resize-handle bottom-left"></div>
<div class="resize-handle bottom-right"></div>
<blockquote class="text-gray-700 italic">
<p class="mb-2">"The only way to do great work is to love what you do."</p>
<footer class="text-right text-sm">— Steve Jobs</footer>
</blockquote>
</div>`,
width: 300,
height: 120
},
search: {
html: `<div class="draggable-element bg-white rounded border border-blue-300 cursor-move relative p-3" data-type="search" style="width: 300px;">
<div class="resize-handle top-left"></div>
<div class="resize-handle top-right"></div>
<div class="resize-handle bottom-left"></div>
<div class="resize-handle bottom-right"></div>
<div class="relative">
<input type="text" placeholder="Search..." class="w-full px-4 py-2 border rounded-full">
<button class="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-500">
<i class="fas fa-search"></i>
</button>
</div>
</div>`,
width: 300,
height: 80
},
embed: {
html: `<div class="draggable-element bg-gray-100 rounded border border-blue-300 cursor-move relative p-3" data-type="embed" style="width: 350px;">
<div class="resize-handle top-left"></div>
<div class="resize-handle top-right"></div>
<div class="resize-handle bottom-left"></div>
<div class="resize-handle bottom-right"></div>
<div class="bg-white p-2 rounded border">
<p class="text-sm text-center text-gray-500">Paste your embed code here</p>
</div>
</div>`,
width: 350,
height: 100
},
spacer: {
html: `<div class="draggable-element cursor-move relative" data-type="spacer" style="height: 30px; width: 100%;">
<div class="resize-handle top-left"></div>
<div class="resize-handle top-right"></div>
<div class="resize-handle bottom-left"></div>
<div class="resize-handle bottom-right"></div>
<hr class="border-t border-dashed border-gray-400">
</div>`,
width: 300,
height: 30
},
pdf: {
html: `<div class="draggable-element bg-white rounded border border-blue-300 cursor-move relative p-4" data-type="pdf" style="width: 300px;">
<div class="resize-handle top-left"></div>
<div class="resize-handle top-right"></div>
<div class="resize-handle bottom-left"></div>
<div class="resize-handle bottom-right"></div>
<div class="flex items-center">
<div class="bg-red-100 p-3 rounded-full mr-3">
<i class="fas fa-file-pdf text-red-500 text-xl"></i>
</div>
<div>
<p class="font-medium">Document.pdf</p>
<p class="text-sm text-gray-500">2.4 MB</p>
<button class="mt-1 text-sm text-blue-500 hover:text-blue-700">Download</button>
</div>
</div>
</div>`,
width: 300,
height: 120
},
products: {
html: `<div class="draggable-element bg-white rounded border border-blue-300 cursor-move relative p-3" data-type="products" style="width: 350px;">
<div class="resize-handle top-left"></div>
<div class="resize-handle top-right"></div>
<div class="resize-handle bottom-left"></div>
<div class="resize-handle bottom-right"></div>
<h3 class="font-medium mb-3">Featured Products</h3>
<div class="grid grid-cols-2 gap-3">
<div class="border rounded p-2">
<img src="https://via.placeholder.com/120x80" class="w-full h-auto mb-1">
<p class="text-sm font-medium">Product 1</p>
<p class="text-sm text-green-600">$19.99</p>
</div>
<div class="border rounded p-2">
<img src="https://via.placeholder.com/120x80" class="w-full h-auto mb-1">
<p class="text-sm font-medium">Product 2</p>
<p class="text-sm text-green-600">$24.99</p>
</div>
</div>
</div>`,
width: 350,
height: 200
},
categories: {
html: `<div class="draggable-element bg-white rounded border border-blue-300 cursor-move relative p-3" data-type="categories" style="width: 200px;">
<div class="resize-handle top-left"></div>
<div class="resize-handle top-right"></div>
<div class="resize-handle bottom-left"></div>
<div class="resize-handle bottom-right"></div>
<h3 class="font-medium mb-2">Categories</h3>
<ul class="space-y-1">
<li class="hover:bg-gray-100 px-2 py-1 rounded"><a href="#" class="text-blue-600">All Items</a></li>
<li class="hover:bg-gray-100 px-2 py-1 rounded"><a href="#" class="text-blue-600">Featured</a></li>
<li class="hover:bg-gray-100 px-2 py-1 rounded"><a href="#" class="text-blue-600">Popular</a></li>
<li class="hover:bg-gray-100 px-2 py-1 rounded"><a href="#" class="text-blue-600">New Arrivals</a></li>
</ul>
</div>`,
width: 200,
height: 200
},
file_upload: {
html: `<div class="draggable-element bg-white rounded border border-blue-300 cursor-move relative p-3" data-type="file_upload" style="width: 300px;">
<div class="resize-handle top-left"></div>
<div class="resize-handle top-right"></div>
<div class="resize-handle bottom-left"></div>
<div class="resize-handle bottom-right"></div>
<label class="block text-sm font-medium mb-2">Upload File</label>
<div class="border-2 border-dashed rounded p-4 text-center">
<i class="fas fa-cloud-upload-alt text-gray-400 text-2xl mb-2"></i>
<p class="text-sm text-gray-500 mb-2">Drag & drop files here</p>
<input type="file" class="hidden">
<button class="bg-blue-500 hover:bg-blue-600 text-white px-3 py-1 rounded text-sm">Select Files</button>
</div>
</div>`,
width: 300,
height: 180
}
};
const canvas = document.getElementById('canvas');
const emptyCanvasMsg = document.getElementById('empty-canvas-msg');
const noSelectionMsg = document.getElementById('no-selection-msg');
const elementProperties = document.getElementById('element-properties');
const contentProperties = document.getElementById('content-properties');
let selectedElement = null;
let isDragging = false;
let isResizing = false;
let resizeDirection = '';
let offsetX, offsetY;
let startX, startY;
let currentElement = null;
// Drag and drop functionality for element items
document.querySelectorAll('.element-item').forEach(item => {
item.addEventListener('dragstart', function(e) {
e.dataTransfer.setData('text/plain', this.dataset.type);
});
});
// Canvas drop zone
canvas.addEventListener('dragover', function(e) {
e.preventDefault();
this.classList.add('highlight');
});
canvas.addEventListener('dragleave', function() {
this.classList.remove('highlight');
});
canvas.addEventListener('drop', function(e) {
e.preventDefault();
this.classList.remove('highlight');
const type = e.dataTransfer.getData('text/plain');
if (!type) return;
addElementToCanvas(type, e.offsetX, e.offsetY);
});
function addElementToCanvas(type, x, y) {
emptyCanvasMsg.style.display = 'none';
const template = elementTemplates[type];
const tempDiv = document.createElement('div');
tempDiv.innerHTML = template.html;
const element = tempDiv.firstChild;
element.style.position = 'absolute';
element.style.left = `${x - (template.width / 2)}px`;
element.style.top = `${y - (template.height / 2)}px`;
element.style.width = `${template.width}px`;
element.style.height = `${template.height}px`;
// Make element draggable
element.addEventListener('mousedown', startDrag);
// Make resize handles functional
const handles = element.querySelectorAll('.resize-handle');
handles.forEach(handle => {
handle.addEventListener('mousedown', function(e) {
e.stopPropagation();
startResize(this);
});
});
// Double click to edit content
if (type === 'text') {
element.addEventListener('dblclick', function(e) {
const textElement = this.querySelector('p');
if (textElement.isContentEditable) {
textElement.contentEditable = false;
textElement.blur();
} else {
textElement.contentEditable = true;
textElement.focus();
}
});
}
// Select element on click
element.addEventListener('click', function(e) {
e.stopPropagation();
selectElement(this);
});
canvas.appendChild(element);
// Select the new element
selectElement(element);
}
// Element selection and properties panel
function selectElement(element) {
// Deselect previous element
if (selectedElement) {
selectedElement.style.boxShadow = 'none';
selectedElement.style.borderColor = '#93c5fd';
}
// Select new element
selectedElement = element;
selectedElement.style.boxShadow = '0 0 0 2px #3b82f6';
selectedElement.style.borderColor = '#3b82f6';
// Update properties panel
noSelectionMsg.classList.add('hidden');
elementProperties.classList.remove('hidden');
// Set type
document.getElementById('prop-type').value = element.dataset.type;
// Set position and size
document.getElementById('prop-x').value = parseInt(element.style.left);
document.getElementById('prop-y').value = parseInt(element.style.top);
document.getElementById('prop-width').value = parseInt(element.style.width);
document.getElementById('prop-height').value = parseInt(element.style.height);
// Toggle content properties based on element type
if (element.dataset.type === 'text' || element.dataset.type === 'button') {
contentProperties.classList.remove('hidden');
if (element.dataset.type === 'text') {
document.getElementById('prop-content').value = element.querySelector('p').textContent;
} else {
document.getElementById('prop-content').value = element.querySelector('button').textContent;
}
} else {
contentProperties.classList.add('hidden');
}
// Set style properties
if (element.dataset.type === 'text') {
const textElement = element.querySelector('p');
document.getElementById('prop-color').value = rgb2hex(textElement.style.color || '#374151');
document.getElementById('prop-fontsize').value = textElement.style.fontSize || '16px';
document.getElementById('prop-bgcolor').value = rgb2hex(element.style.backgroundColor || '#ffffff');
} else if (element.dataset.type === 'button') {
const buttonElement = element.querySelector('button');
document.getElementById('prop-color').value = rgb2hex(buttonElement.style.color || '#ffffff');
document.getElementById('prop-fontsize').value = buttonElement.style.fontSize || '16px';
document.getElementById('prop-bgcolor').value = rgb2hex(buttonElement.style.backgroundColor || '#3b82f6');
} else {
document.getElementById('prop-bgcolor').value = rgb2hex(element.style.backgroundColor || (element.dataset.type === 'video' ? '#111827' : '#ffffff'));
}
}
// Deselect element when clicking on empty canvas
canvas.addEventListener('click', function(e) {
if (e.target === canvas) {
deselectElement();
}
});
function deselectElement() {
if (selectedElement) {
selectedElement.style.boxShadow = 'none';
selectedElement.style.borderColor = '#93c5fd';
selectedElement = null;
}
noSelectionMsg.classList.remove('hidden');
elementProperties.classList.add('hidden');
}
// Drag functionality
function startDrag(e) {
if (e.target.classList.contains('resize-handle')) return;
isDragging = true;
currentElement = this;
// Calculate offset from element's top-left corner
const rect = this.getBoundingClientRect();
offsetX = e.clientX - rect.left;
offsetY = e.clientY - rect.top;
// Store element's initial position
startX = parseFloat(this.style.left) || 0;
startY = parseFloat(this.style.top) || 0;
// Apply higher z-index while dragging
this.style.zIndex = '1000';
document.addEventListener('mousemove', drag);
document.addEventListener('mouseup', stopDrag);
e.preventDefault();
e.stopPropagation();
}
function drag(e) {
if (!isDragging) return;
// Calculate new position
const x = e.clientX - canvas.getBoundingClientRect().left - offsetX;
const y = e.clientY - canvas.getBoundingClientRect().top - offsetY;
// Update element position
currentElement.style.left = `${x}px`;
currentElement.style.top = `${y}px`;
// Update properties panel if this element is selected
if (selectedElement === currentElement) {
document.getElementById('prop-x').value = x;
document.getElementById('prop-y').value = y;
}
}
function stopDrag() {
isDragging = false;
if (currentElement) {
currentElement.style.zIndex = '';
}
document.removeEventListener('mousemove', drag);
document.removeEventListener('mouseup', stopDrag);
}
// Resize functionality
function startResize(handle) {
isResizing = true;
currentElement = handle.parentElement;
// Store element's initial dimensions and position
startX = parseFloat(currentElement.style.left) || 0;
startY = parseFloat(currentElement.style.top) || 0;
const startWidth = parseFloat(currentElement.style.width) || currentElement.offsetWidth;
const startHeight = parseFloat(currentElement.style.height) || currentElement.offsetHeight;
// Determine resize direction based on which handle was clicked
if (handle.classList.contains('top-left')) {
resizeDirection = 'top-left';
} else if (handle.classList.contains('top-right')) {
resizeDirection = 'top-right';
} else if (handle.classList.contains('bottom-left')) {
resizeDirection = 'bottom-left';
} else if (handle.classList.contains('bottom-right')) {
resizeDirection = 'bottom-right';
}
document.addEventListener('mousemove', resize);
document.addEventListener('mouseup', stopResize);
}
function resize(e) {
if (!isResizing) return;
const rect = canvas.getBoundingClientRect();
const mouseX = e.clientX - rect.left;
const mouseY = e.clientY - rect.top;
const startWidth = parseFloat(currentElement.style.width) || currentElement.offsetWidth;
const startHeight = parseFloat(currentElement.style.height) || currentElement.offsetHeight;
const startLeft = parseFloat(currentElement.style.left) || 0;
const startTop = parseFloat(currentElement.style.top) || 0;
let newWidth = startWidth;
let newHeight = startHeight;
let newLeft = startLeft;
let newTop = startTop;
switch (resizeDirection) {
case 'top-left':
newWidth = startWidth - (mouseX - startLeft);
newHeight = startHeight - (mouseY - startTop);
newLeft = mouseX;
newTop = mouseY;
break;
case 'top-right':
newWidth = mouseX - startLeft;
newHeight = startHeight - (mouseY - startTop);
newTop = mouseY;
break;
case 'bottom-left':
newWidth = startWidth - (mouseX - startLeft);
newHeight = mouseY - startTop;
newLeft = mouseX;
break;
case 'bottom-right':
newWidth = mouseX - startLeft;
newHeight = mouseY - startTop;
break;
}
// Apply minimum dimensions
const minSize = 30;
if (newWidth < minSize) newWidth = minSize;
if (newHeight < minSize) newHeight = minSize;
// Update element dimensions and position
currentElement.style.width = `${newWidth}px`;
currentElement.style.height = `${newHeight}px`;
currentElement.style.left = `${newLeft}px`;
currentElement.style.top = `${newTop}px`;
// Update properties panel if this element is selected
if (selectedElement === currentElement) {
document.getElementById('prop-x').value = newLeft;
document.getElementById('prop-y').value = newTop;
document.getElementById('prop-width').value = newWidth;
document.getElementById('prop-height').value = newHeight;
}
}
function stopResize() {
isResizing = false;
document.removeEventListener('mousemove', resize);
document.removeEventListener('mouseup', stopResize);
}
// Property panel updates
document.getElementById('prop-x').addEventListener('input', function() {
if (selectedElement) {
selectedElement.style.left = `${this.value}px`;
}
});
document.getElementById('prop-y').addEventListener('input', function() {
if (selectedElement) {
selectedElement.style.top = `${this.value}px`;
}
});
document.getElementById('prop-width').addEventListener('input', function() {
if (selectedElement) {
selectedElement.style.width = `${this.value}px`;
}
});
document.getElementById('prop-height').addEventListener('input', function() {
if (selectedElement) {
selectedElement.style.height = `${this.value}px`;
}
});
document.getElementById('prop-content').addEventListener('input', function() {
if (selectedElement) {
if (selectedElement.dataset.type === 'text') {
selectedElement.querySelector('p').textContent = this.value;
} else if (selectedElement.dataset.type === 'button') {
selectedElement.querySelector('button').textContent = this.value;
}
}
});
document.getElementById('prop-bgcolor').addEventListener('input', function() {
if (selectedElement) {
if (selectedElement.dataset.type === 'text') {
selectedElement.style.backgroundColor = this.value;
} else if (selectedElement.dataset.type === 'button') {
selectedElement.querySelector('button').style.backgroundColor = this.value;
} else {
selectedElement.style.backgroundColor = this.value;
}
}
});
document.getElementById('prop-color').addEventListener('input', function() {
if (selectedElement) {
if (selectedElement.dataset.type === 'text') {
selectedElement.querySelector('p').style.color = this.value;
} else if (selectedElement.dataset.type === 'button') {
selectedElement.querySelector('button').style.color = this.value;
}
}
});
document.getElementById('prop-fontsize').addEventListener('change', function() {
if (selectedElement) {
if (selectedElement.dataset.type === 'text') {
selectedElement.querySelector('p').style.fontSize = this.value;
} else if (selectedElement.dataset.type === 'button') {
selectedElement.querySelector('button').style.fontSize = this.value;
}
}
});
document.getElementById('delete-element').addEventListener('click', function() {
if (selectedElement) {
selectedElement.remove();
deselectElement();
// Show empty canvas message if no elements left
if (canvas.children.length === 1) { // Only the empty message div remains
emptyCanvasMsg.style.display = 'flex';
}
}
});
// Export functionality
const exportBtn = document.getElementById('export-btn');
const exportModal = document.getElementById('export-modal');
const closeExportModal = document.getElementById('close-export-modal');
const downloadBtn = document.getElementById('download-btn');
const whatsappShare = document.getElementById('whatsapp-share');
const exportPreview = document.getElementById('export-preview');
exportBtn.addEventListener('click', function() {
// Clone the canvas without the empty message
const canvasClone = canvas.cloneNode(true);
const emptyMsg = canvasClone.querySelector('#empty-canvas-msg');
if (emptyMsg) emptyMsg.remove();
// Reset any active selections
const selectedElements = canvasClone.querySelectorAll('.draggable-element');
selectedElements.forEach(el => {
el.style.boxShadow = 'none';
el.style.borderColor = '#93c5fd';
});
exportPreview.innerHTML = '';
exportPreview.appendChild(canvasClone);
exportModal.classList.remove('hidden');
});
closeExportModal.addEventListener('click', function() {
exportModal.classList.add('hidden');
});
downloadBtn.addEventListener('click', function() {
// Use html2canvas to convert the preview to an image
html2canvas(exportPreview.firstChild).then(canvas => {
const link = document.createElement('a');
link.download = 'website-design.png';
link.href = canvas.toDataURL('image/png');
link.click();
});
});
whatsappShare.addEventListener('click', function() {
html2canvas(exportPreview.firstChild).then(canvas => {
const image = canvas.toDataURL('image/png').replace(/^data:image\/(png|jpg);base64,/, "");
const message = encodeURIComponent('Check out the website I designed!');
const whatsappUrl = `https://api.whatsapp.com/send?text=${message}&image=${image}`;
window.open(whatsappUrl, '_blank');
});
});
// Helper functions
function rgb2hex(rgb) {
if (rgb.startsWith('#')) return rgb;
const rgbValues = rgb.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*\d+\.?\d*)?\)$/);
if (!rgbValues) return '#000000';
function hex(x) {
return ("0" + parseInt(x).toString(16)).slice(-2);
}
return "#" + hex(rgbValues[1]) + hex(rgbValues[2]) + hex(rgbValues[3]);
}
});
// Theme functionality
document.getElementById('apply-theme').addEventListener('click', function() {
const theme = document.getElementById('theme-selector').value;
let bgColor = '';
let textColor = '';
let primaryColor = '';
switch(theme) {
case 'business':
bgColor = 'gray-50';
textColor = 'gray-800';
primaryColor = 'blue';
break;
case 'portfolio':
bgColor = 'gray-100';
textColor = 'gray-900';
primaryColor = 'indigo';
break;
case 'blog':
bgColor = 'white';
textColor = 'gray-700';
primaryColor = 'green';
break;
case 'education':
bgColor = 'blue-50';
textColor = 'blue-900';
primaryColor = 'blue';
break;
case 'personal':
bgColor = 'pink-50';
textColor = 'gray-800';
primaryColor = 'pink';
break;
default:
bgColor = 'white';
textColor = 'gray-800';
primaryColor = 'blue';
}
const canvas = document.getElementById('canvas');
canvas.className = `bg-${bgColor} text-${textColor} shadow-lg w-full max-w-4xl min-h-[80vh] relative canvas-placeholder`;
canvas.style.backgroundColor = ''; // Clear inline style
// Update all existing elements with the new color scheme
document.querySelectorAll('.draggable-element').forEach(el => {
if(el.querySelector('button')) {
const btn = el.querySelector('button');
btn.className = btn.className.replace(/bg-\w+-500/g, `bg-${primaryColor}-500`)
.replace(/hover:bg-\w+-600/g, `hover:bg-${primaryColor}-600`);
} else if (el.dataset.type === 'text' || el.dataset.type === 'social' || el.dataset.type === 'quote') {
el.style.backgroundColor = ``;
el.classList.add(`bg-${bgColor}`, `text-${textColor}`);
}
});
});
// For the export functionality, we need html2canvas
document.write('<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"><\/script>');
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Vishau/webbuilder1-0" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>