v1.0.1-beta
This commit is contained in:
parent
3907ae4b7e
commit
de4347330f
93
README.md
93
README.md
@ -1,93 +0,0 @@
|
|||||||
# 🏠 Property Brochure Generator
|
|
||||||
|
|
||||||
Professional PDF generation system for real estate properties with Salesforce integration.
|
|
||||||
|
|
||||||
## 🚀 **Quick Start**
|
|
||||||
|
|
||||||
### **1. Deploy LWC to Salesforce**
|
|
||||||
```bash
|
|
||||||
chmod +x deploy-lwc-production.sh
|
|
||||||
./deploy-lwc-production.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### **2. Deploy PDF API to Your Server**
|
|
||||||
```bash
|
|
||||||
cd python-pdf-generator
|
|
||||||
python3 -m venv venv
|
|
||||||
source venv/bin/activate
|
|
||||||
pip install -r requirements.txt
|
|
||||||
python3 api_server.py
|
|
||||||
```
|
|
||||||
|
|
||||||
### **3. Update LWC with Your API URL**
|
|
||||||
Edit these files with your actual server IP:
|
|
||||||
|
|
||||||
**LWC JavaScript:**
|
|
||||||
```javascript
|
|
||||||
// force-app/main/default/lwc/propertyTemplateSelector/propertyTemplateSelector.js
|
|
||||||
pdfApiBaseUrl = 'https://YOUR-ACTUAL-IP:8000/api';
|
|
||||||
```
|
|
||||||
|
|
||||||
**Apex Controller:**
|
|
||||||
```apex
|
|
||||||
// force-app/main/default/classes/PropertyTemplateController.cls
|
|
||||||
String apiEndpoint = 'https://YOUR-ACTUAL-IP:8000/api/generate-pdf';
|
|
||||||
```
|
|
||||||
|
|
||||||
**Production Config:**
|
|
||||||
```javascript
|
|
||||||
// force-app/main/default/lwc/propertyTemplateSelector/production-config.js
|
|
||||||
PDF_API_BASE_URL: 'https://YOUR-ACTUAL-IP:8000/api'
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📁 **Project Structure**
|
|
||||||
|
|
||||||
```
|
|
||||||
├── force-app/ # Salesforce LWC Components
|
|
||||||
│ └── main/default/
|
|
||||||
│ ├── lwc/propertyTemplateSelector/ # Main LWC Component
|
|
||||||
│ ├── classes/PropertyTemplateController.cls # Apex Controller
|
|
||||||
│ └── objects/ # Custom Objects
|
|
||||||
├── python-pdf-generator/ # PDF Generation API
|
|
||||||
│ ├── api_server.py # FastAPI Server
|
|
||||||
│ ├── property_pdf_generator.py # PDF Generation Logic
|
|
||||||
│ └── requirements.txt # Python Dependencies
|
|
||||||
├── deploy-lwc-production.sh # LWC Deployment Script
|
|
||||||
└── README.md # This File
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔧 **Features**
|
|
||||||
|
|
||||||
- **5-Step Wizard**: Template → Property → Details → Preview → Download
|
|
||||||
- **Multiple Templates**: 1-page, 3-page, 5-page, Luxury, Modern
|
|
||||||
- **Real-time Preview**: Instant customization updates
|
|
||||||
- **Image Management**: Multiple images with room names
|
|
||||||
- **Salesforce Integration**: Direct access to pcrm__Property__c data
|
|
||||||
- **Responsive Design**: Works on all devices
|
|
||||||
|
|
||||||
## 📊 **API Endpoints**
|
|
||||||
|
|
||||||
- **Base URL**: `https://YOUR-IP:8000/api`
|
|
||||||
- **Preview**: `POST /preview`
|
|
||||||
- **Generate PDF**: `POST /generate-pdf`
|
|
||||||
- **Health Check**: `GET /health`
|
|
||||||
- **Templates**: `GET /templates`
|
|
||||||
|
|
||||||
## 🔒 **Security**
|
|
||||||
|
|
||||||
- Configure CORS for your Salesforce domain
|
|
||||||
- Use HTTPS in production
|
|
||||||
- Implement authentication if needed
|
|
||||||
- Configure firewall for port 8000
|
|
||||||
|
|
||||||
## 📞 **Support**
|
|
||||||
|
|
||||||
For issues or questions, check the deployment logs and ensure:
|
|
||||||
- Salesforce CLI is installed
|
|
||||||
- Python dependencies are installed
|
|
||||||
- API server is running on your IP
|
|
||||||
- LWC has correct API URL
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**🎯 Production-ready system for generating professional property brochures!**
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
public with sharing class PDFGenerationProxy {
|
public with sharing class PDFGenerationProxy {
|
||||||
|
|
||||||
@AuraEnabled
|
@AuraEnabled
|
||||||
public static String generatePDFFromHTML(String htmlContent) {
|
public static String generatePDFFromHTML(String htmlContent, String pageSize) {
|
||||||
try {
|
try {
|
||||||
// Prepare the request
|
// Prepare the request
|
||||||
Http http = new Http();
|
Http http = new Http();
|
||||||
@ -10,17 +10,23 @@ public with sharing class PDFGenerationProxy {
|
|||||||
request.setMethod('POST');
|
request.setMethod('POST');
|
||||||
request.setHeader('Content-Type', 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW');
|
request.setHeader('Content-Type', 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW');
|
||||||
|
|
||||||
// Create multipart form data
|
// Create multipart form data with page size
|
||||||
String boundary = '----WebKitFormBoundary7MA4YWxkTrZu0gW';
|
String boundary = '----WebKitFormBoundary7MA4YWxkTrZu0gW';
|
||||||
String body = '';
|
String body = '';
|
||||||
body += '--' + boundary + '\r\n';
|
body += '--' + boundary + '\r\n';
|
||||||
body += 'Content-Disposition: form-data; name="input"; filename="template.html"\r\n';
|
body += 'Content-Disposition: form-data; name="input"; filename="template.html"\r\n';
|
||||||
body += 'Content-Type: text/html\r\n\r\n';
|
body += 'Content-Type: text/html\r\n\r\n';
|
||||||
body += htmlContent + '\r\n';
|
body += htmlContent + '\r\n';
|
||||||
|
body += '--' + boundary + '\r\n';
|
||||||
|
body += 'Content-Disposition: form-data; name="pageSize"\r\n\r\n';
|
||||||
|
body += (pageSize != null ? pageSize : 'A4') + '\r\n';
|
||||||
|
body += '--' + boundary + '\r\n';
|
||||||
|
body += 'Content-Disposition: form-data; name="maxSize"\r\n\r\n';
|
||||||
|
body += '50000000\r\n'; // 50MB size limit
|
||||||
body += '--' + boundary + '--\r\n';
|
body += '--' + boundary + '--\r\n';
|
||||||
|
|
||||||
request.setBody(body);
|
request.setBody(body);
|
||||||
request.setTimeout(120000); // 2 minutes timeout
|
request.setTimeout(120000); // 2 minutes timeout (Salesforce maximum)
|
||||||
|
|
||||||
// Make the callout
|
// Make the callout
|
||||||
HttpResponse response = http.send(request);
|
HttpResponse response = http.send(request);
|
||||||
@ -43,7 +49,7 @@ public with sharing class PDFGenerationProxy {
|
|||||||
try {
|
try {
|
||||||
// Test with simple HTML
|
// Test with simple HTML
|
||||||
String testHtml = '<!DOCTYPE html><html><head><title>Test</title></head><body><h1>Test PDF Generation</h1></body></html>';
|
String testHtml = '<!DOCTYPE html><html><head><title>Test</title></head><body><h1>Test PDF Generation</h1></body></html>';
|
||||||
return generatePDFFromHTML(testHtml);
|
return generatePDFFromHTML(testHtml, 'A4');
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new AuraHandledException('API test failed: ' + e.getMessage());
|
throw new AuraHandledException('API test failed: ' + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -5751,6 +5751,30 @@
|
|||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.doc-action-btn.undo-btn {
|
||||||
|
background: linear-gradient(135deg, #f3f4f6 0%, #e5e7eb 100%);
|
||||||
|
border-color: #9ca3af;
|
||||||
|
color: #374151;
|
||||||
|
}
|
||||||
|
|
||||||
|
.doc-action-btn.undo-btn:hover {
|
||||||
|
background: linear-gradient(135deg, #e5e7eb 0%, #d1d5db 100%);
|
||||||
|
border-color: #6b7280;
|
||||||
|
color: #111827;
|
||||||
|
}
|
||||||
|
|
||||||
|
.doc-action-btn.redo-btn {
|
||||||
|
background: linear-gradient(135deg, #f3f4f6 0%, #e5e7eb 100%);
|
||||||
|
border-color: #9ca3af;
|
||||||
|
color: #374151;
|
||||||
|
}
|
||||||
|
|
||||||
|
.doc-action-btn.redo-btn:hover {
|
||||||
|
background: linear-gradient(135deg, #e5e7eb 0%, #d1d5db 100%);
|
||||||
|
border-color: #6b7280;
|
||||||
|
color: #111827;
|
||||||
|
}
|
||||||
|
|
||||||
/* Generate PDF Section in Template Header */
|
/* Generate PDF Section in Template Header */
|
||||||
.generate-pdf-section {
|
.generate-pdf-section {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -6474,28 +6498,7 @@
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Scroll hint for areas */
|
|
||||||
.scroll-hint {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 10px;
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
background: rgba(102, 126, 234, 0.1);
|
|
||||||
color: #667eea;
|
|
||||||
padding: 4px 12px;
|
|
||||||
border-radius: 12px;
|
|
||||||
font-size: 11px;
|
|
||||||
font-weight: 500;
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity 0.3s ease;
|
|
||||||
pointer-events: none;
|
|
||||||
z-index: 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.enhanced-toolbar:hover .scroll-hint,
|
|
||||||
.editor-right:hover .scroll-hint {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Enhanced visual feedback for scrollable areas */
|
/* Enhanced visual feedback for scrollable areas */
|
||||||
.enhanced-toolbar-scroll:hover,
|
.enhanced-toolbar-scroll:hover,
|
||||||
@ -8131,3 +8134,293 @@ button, .btn, .toolbar-button, .export-pdf-btn {
|
|||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Draggable Table Button Styles */
|
||||||
|
.draggable-table-btn {
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.draggable-table-btn:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
box-shadow: 0 4px 12px rgba(79, 70, 229, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.draggable-table-btn:active {
|
||||||
|
cursor: grabbing;
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
|
|
||||||
|
.draggable-table-btn.dragging {
|
||||||
|
opacity: 0.5;
|
||||||
|
transform: rotate(5deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Editor Drag Over Styles */
|
||||||
|
.enhanced-editor-content.drag-over {
|
||||||
|
background: linear-gradient(45deg, #f0f4ff 25%, transparent 25%),
|
||||||
|
linear-gradient(-45deg, #f0f4ff 25%, transparent 25%),
|
||||||
|
linear-gradient(45deg, transparent 75%, #f0f4ff 75%),
|
||||||
|
linear-gradient(-45deg, transparent 75%, #f0f4ff 75%);
|
||||||
|
background-size: 20px 20px;
|
||||||
|
background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
|
||||||
|
border: 2px dashed #4f46e5;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Table Drop Indicator */
|
||||||
|
.table-drop-indicator {
|
||||||
|
position: absolute;
|
||||||
|
border: 2px dashed #4f46e5;
|
||||||
|
background: rgba(79, 70, 229, 0.1);
|
||||||
|
border-radius: 4px;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 1000;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-drop-indicator.show {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Editable Table Container Styles */
|
||||||
|
.editable-table-container {
|
||||||
|
position: relative;
|
||||||
|
margin: 1rem 0;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
border-radius: 8px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editable-table-container:hover {
|
||||||
|
border-color: #4f46e5;
|
||||||
|
box-shadow: 0 4px 12px rgba(79, 70, 229, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.editable-table-container.dragging {
|
||||||
|
opacity: 0.5;
|
||||||
|
transform: rotate(2deg);
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Table Controls */
|
||||||
|
.table-controls {
|
||||||
|
position: absolute;
|
||||||
|
top: -40px;
|
||||||
|
left: 0;
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 0.5rem;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.2s ease;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editable-table-container:hover .table-controls {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-control-group {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.25rem;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-control-group:not(:last-child) {
|
||||||
|
border-right: 1px solid #e2e8f0;
|
||||||
|
padding-right: 0.5rem;
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-control-btn {
|
||||||
|
background: #f8fafc;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #475569;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
white-space: nowrap;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-control-btn:hover {
|
||||||
|
background: #e2e8f0;
|
||||||
|
border-color: #cbd5e1;
|
||||||
|
color: #334155;
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-control-btn:active {
|
||||||
|
transform: translateY(0);
|
||||||
|
background: #cbd5e1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-control-btn.delete {
|
||||||
|
background: #fef2f2;
|
||||||
|
border-color: #fecaca;
|
||||||
|
color: #dc2626;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-control-btn.delete:hover {
|
||||||
|
background: #fee2e2;
|
||||||
|
border-color: #fca5a5;
|
||||||
|
color: #b91c1c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-control-btn.delete:active {
|
||||||
|
background: #fecaca;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Table Container Drag Styles */
|
||||||
|
.editable-table-container[draggable="true"] {
|
||||||
|
cursor: move;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editable-table-container[draggable="true"]:hover {
|
||||||
|
cursor: grab;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editable-table-container[draggable="true"]:active {
|
||||||
|
cursor: grabbing;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prevent text selection on controls */
|
||||||
|
.table-controls * {
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive table controls */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.table-controls {
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
opacity: 1;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-control-btn {
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
padding: 0.25rem 0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-control-group:not(:last-child) {
|
||||||
|
border-right: none;
|
||||||
|
padding-right: 0;
|
||||||
|
margin-right: 0;
|
||||||
|
border-bottom: 1px solid #e2e8f0;
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Draggable and resizable image styles */
|
||||||
|
img[draggable="true"] {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1000;
|
||||||
|
cursor: move;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-handle {
|
||||||
|
position: absolute;
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
background: #007bff;
|
||||||
|
border: 1px solid white;
|
||||||
|
z-index: 1001;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-handle.resize-nw {
|
||||||
|
top: -4px;
|
||||||
|
left: -4px;
|
||||||
|
cursor: nw-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-handle.resize-ne {
|
||||||
|
top: -4px;
|
||||||
|
right: -4px;
|
||||||
|
cursor: ne-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-handle.resize-sw {
|
||||||
|
bottom: -4px;
|
||||||
|
left: -4px;
|
||||||
|
cursor: sw-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-handle.resize-se {
|
||||||
|
bottom: -4px;
|
||||||
|
right: -4px;
|
||||||
|
cursor: se-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Selector mode styles */
|
||||||
|
.enhanced-editor-content.selector-mode {
|
||||||
|
cursor: crosshair;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-options-panel {
|
||||||
|
position: fixed;
|
||||||
|
top: 10px;
|
||||||
|
right: 10px;
|
||||||
|
background: white;
|
||||||
|
border: 2px solid #007bff;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 15px;
|
||||||
|
box-shadow: 0 4px 20px rgba(0,0,0,0.15);
|
||||||
|
z-index: 10000;
|
||||||
|
min-width: 200px;
|
||||||
|
max-width: 250px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.property-image-popup {
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
background: white;
|
||||||
|
border: 2px solid #007bff;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: 0 4px 20px rgba(0,0,0,0.15);
|
||||||
|
z-index: 10001;
|
||||||
|
max-width: 400px;
|
||||||
|
max-height: 500px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bullet and numbering styles */
|
||||||
|
ul, ol {
|
||||||
|
list-style-type: none;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul li, ol li {
|
||||||
|
margin-left: 20px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul li:before {
|
||||||
|
content: "* ";
|
||||||
|
position: absolute;
|
||||||
|
left: -20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol li:before {
|
||||||
|
content: "1. ";
|
||||||
|
position: absolute;
|
||||||
|
left: -20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,5 @@
|
|||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="property-brochure-generator">
|
<div class="property-brochure-generator">
|
||||||
<!-- Header Section - Editable -->
|
<!-- Header Section - Editable -->
|
||||||
@ -685,6 +687,9 @@
|
|||||||
|
|
||||||
<!-- Category Navigation -->
|
<!-- Category Navigation -->
|
||||||
<div class="category-navigation-step2">
|
<div class="category-navigation-step2">
|
||||||
|
<button class="category-btn-step2" onclick={selectCategory} data-category="None">
|
||||||
|
None
|
||||||
|
</button>
|
||||||
<button class="category-btn-step2" onclick={selectCategory} data-category="Interior">
|
<button class="category-btn-step2" onclick={selectCategory} data-category="Interior">
|
||||||
Interior
|
Interior
|
||||||
</button>
|
</button>
|
||||||
@ -774,7 +779,6 @@
|
|||||||
|
|
||||||
<!-- Enhanced Editor Toolbar -->
|
<!-- Enhanced Editor Toolbar -->
|
||||||
<div class="enhanced-toolbar">
|
<div class="enhanced-toolbar">
|
||||||
<div class="scroll-hint">⬇️ Scroll for more tools</div>
|
|
||||||
<div class="enhanced-toolbar-scroll">
|
<div class="enhanced-toolbar-scroll">
|
||||||
<!-- Property Insert Section -->
|
<!-- Property Insert Section -->
|
||||||
<div class="toolbar-section">
|
<div class="toolbar-section">
|
||||||
@ -814,13 +818,39 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Document Actions -->
|
||||||
|
<div class="toolbar-section">
|
||||||
|
<div class="toolbar-section-title">Document Actions</div>
|
||||||
|
<div class="document-actions-grid">
|
||||||
|
<button class="doc-action-btn undo-btn" onclick={undo} title="Undo (Ctrl+Z)">
|
||||||
|
<lightning-icon icon-name="utility:undo" size="x-small"></lightning-icon>
|
||||||
|
Undo
|
||||||
|
</button>
|
||||||
|
<button class="doc-action-btn redo-btn" onclick={redo} title="Redo (Ctrl+Y)">
|
||||||
|
<lightning-icon icon-name="utility:redo" size="x-small"></lightning-icon>
|
||||||
|
Redo
|
||||||
|
</button>
|
||||||
|
<button class="doc-action-btn save-btn" onclick={handleSave} title="Save Template">
|
||||||
|
<lightning-icon icon-name="utility:save" size="x-small"></lightning-icon>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
<button class="doc-action-btn load-btn" onclick={handleLoad} title="Load Template">
|
||||||
|
<lightning-icon icon-name="utility:upload" size="x-small"></lightning-icon>
|
||||||
|
Load
|
||||||
|
</button>
|
||||||
|
<button class="doc-action-btn reset-btn" onclick={handleReset} title="Reset Template">
|
||||||
|
<lightning-icon icon-name="utility:refresh" size="x-small"></lightning-icon>
|
||||||
|
Reset
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Text Formatting Section -->
|
<!-- Text Formatting Section -->
|
||||||
<div class="toolbar-section">
|
<div class="toolbar-section">
|
||||||
<div class="toolbar-section-title">Text Formatting</div>
|
<div class="toolbar-section-title">Text Formatting</div>
|
||||||
<div class="toolbar-group">
|
<div class="toolbar-group">
|
||||||
<label>Font Family:</label>
|
<label>Font Family:</label>
|
||||||
<select onchange={handleFontFamilyChange}>
|
<select onchange={handleFontFamilyChange}>
|
||||||
<option value="Inter">Inter</option>
|
|
||||||
<option value="Arial">Arial</option>
|
<option value="Arial">Arial</option>
|
||||||
<option value="Times New Roman">Times New Roman</option>
|
<option value="Times New Roman">Times New Roman</option>
|
||||||
<option value="Helvetica">Helvetica</option>
|
<option value="Helvetica">Helvetica</option>
|
||||||
@ -831,6 +861,13 @@
|
|||||||
<div class="toolbar-group">
|
<div class="toolbar-group">
|
||||||
<label>Font Size:</label>
|
<label>Font Size:</label>
|
||||||
<select onchange={handleFontSizeChange}>
|
<select onchange={handleFontSizeChange}>
|
||||||
|
<option value="1px">1px</option>
|
||||||
|
<option value="2px">2px</option>
|
||||||
|
<option value="3px">3px</option>
|
||||||
|
<option value="4px">4px</option>
|
||||||
|
<option value="5px">5px</option>
|
||||||
|
<option value="6px">6px</option>
|
||||||
|
<option value="7px">7px</option>
|
||||||
<option value="8px">8px</option>
|
<option value="8px">8px</option>
|
||||||
<option value="10px">10px</option>
|
<option value="10px">10px</option>
|
||||||
<option value="12px">12px</option>
|
<option value="12px">12px</option>
|
||||||
@ -938,11 +975,30 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="toolbar-group">
|
<div class="toolbar-group">
|
||||||
<button class="toolbar-button" onclick={addShape}>
|
<button class="toolbar-button" onclick={toggleSelectorMode}>
|
||||||
<lightning-icon icon-name="utility:shape" size="x-small"></lightning-icon>
|
<lightning-icon icon-name="utility:target" size="x-small"></lightning-icon>
|
||||||
Shape
|
<span class="selector-mode-text">Selector Mode</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="toolbar-button" onclick={openTableDialog}>
|
</div>
|
||||||
|
<div class="toolbar-group selector-controls" style="display: none;">
|
||||||
|
<button class="toolbar-button" onclick={moveElementUp} title="Move Up">
|
||||||
|
<lightning-icon icon-name="utility:up" size="x-small"></lightning-icon>
|
||||||
|
Move Up
|
||||||
|
</button>
|
||||||
|
<button class="toolbar-button" onclick={moveElementDown} title="Move Down">
|
||||||
|
<lightning-icon icon-name="utility:down" size="x-small"></lightning-icon>
|
||||||
|
Move Down
|
||||||
|
</button>
|
||||||
|
<button class="toolbar-button" onclick={removeSelectedElement} title="Delete Element" style="background: #dc3545; color: white;">
|
||||||
|
<lightning-icon icon-name="utility:delete" size="x-small"></lightning-icon>
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-group">
|
||||||
|
<button class="toolbar-button draggable-table-btn"
|
||||||
|
draggable="true"
|
||||||
|
ondragstart={handleTableDragStart}
|
||||||
|
onclick={openTableDialog}>
|
||||||
<lightning-icon icon-name="utility:table" size="x-small"></lightning-icon>
|
<lightning-icon icon-name="utility:table" size="x-small"></lightning-icon>
|
||||||
Table
|
Table
|
||||||
</button>
|
</button>
|
||||||
@ -951,24 +1007,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Document Actions -->
|
|
||||||
<div class="toolbar-section">
|
|
||||||
<div class="toolbar-section-title">Document Actions</div>
|
|
||||||
<div class="document-actions-grid">
|
|
||||||
<button class="doc-action-btn save-btn" onclick={handleSave} title="Save Template">
|
|
||||||
<lightning-icon icon-name="utility:save" size="x-small"></lightning-icon>
|
|
||||||
Save
|
|
||||||
</button>
|
|
||||||
<button class="doc-action-btn load-btn" onclick={handleLoad} title="Load Template">
|
|
||||||
<lightning-icon icon-name="utility:upload" size="x-small"></lightning-icon>
|
|
||||||
Load
|
|
||||||
</button>
|
|
||||||
<button class="doc-action-btn reset-btn" onclick={handleReset} title="Reset Template">
|
|
||||||
<lightning-icon icon-name="utility:refresh" size="x-small"></lightning-icon>
|
|
||||||
Reset
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div> <!-- Close enhanced-toolbar-scroll -->
|
</div> <!-- Close enhanced-toolbar-scroll -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -1013,7 +1052,7 @@
|
|||||||
|
|
||||||
<!-- Enhanced Content Editor -->
|
<!-- Enhanced Content Editor -->
|
||||||
<div class="enhanced-editor-content" contenteditable="true" onkeyup={handleContentChange}
|
<div class="enhanced-editor-content" contenteditable="true" onkeyup={handleContentChange}
|
||||||
onpaste={handleContentChange}>
|
onpaste={handleContentChange} ondragover={handleEditorDragOver} ondrop={handleEditorDrop}>
|
||||||
<!-- Template content will be loaded here -->
|
<!-- Template content will be loaded here -->
|
||||||
{htmlContent}
|
{htmlContent}
|
||||||
</div>
|
</div>
|
||||||
@ -1034,6 +1073,7 @@
|
|||||||
<div class="image-review-content">
|
<div class="image-review-content">
|
||||||
<!-- Category Navigation -->
|
<!-- Category Navigation -->
|
||||||
<div class="category-navigation">
|
<div class="category-navigation">
|
||||||
|
<button class="category-btn" onclick={selectCategory} data-category="None">None</button>
|
||||||
<button class="category-btn" onclick={selectCategory} data-category="Interior">Interior</button>
|
<button class="category-btn" onclick={selectCategory} data-category="Interior">Interior</button>
|
||||||
<button class="category-btn" onclick={selectCategory} data-category="Exterior">Exterior</button>
|
<button class="category-btn" onclick={selectCategory} data-category="Exterior">Exterior</button>
|
||||||
<button class="category-btn" onclick={selectCategory} data-category="Kitchen">Kitchen</button>
|
<button class="category-btn" onclick={selectCategory} data-category="Kitchen">Kitchen</button>
|
||||||
@ -1098,15 +1138,16 @@
|
|||||||
<!-- Property Images Tab -->
|
<!-- Property Images Tab -->
|
||||||
<div if:true={showPropertyImagesTab} class="property-images-section">
|
<div if:true={showPropertyImagesTab} class="property-images-section">
|
||||||
<!-- Category Navigation -->
|
<!-- Category Navigation -->
|
||||||
<div class="category-navigation-replacement">
|
<div class="category-navigation-step2">
|
||||||
<button class="category-btn-replacement" onclick={selectReplacementCategory} data-category="Interior">Interior</button>
|
<button class="category-btn-step2" onclick={selectReplacementCategory} data-category="None">None</button>
|
||||||
<button class="category-btn-replacement" onclick={selectReplacementCategory} data-category="Exterior">Exterior</button>
|
<button class="category-btn-step2" onclick={selectReplacementCategory} data-category="Interior">Interior</button>
|
||||||
<button class="category-btn-replacement" onclick={selectReplacementCategory} data-category="Kitchen">Kitchen</button>
|
<button class="category-btn-step2" onclick={selectReplacementCategory} data-category="Exterior">Exterior</button>
|
||||||
<button class="category-btn-replacement" onclick={selectReplacementCategory} data-category="Bedroom">Bedroom</button>
|
<button class="category-btn-step2" onclick={selectReplacementCategory} data-category="Kitchen">Kitchen</button>
|
||||||
<button class="category-btn-replacement" onclick={selectReplacementCategory} data-category="Living Area">Living Area</button>
|
<button class="category-btn-step2" onclick={selectReplacementCategory} data-category="Bedroom">Bedroom</button>
|
||||||
<button class="category-btn-replacement" onclick={selectReplacementCategory} data-category="Parking">Parking</button>
|
<button class="category-btn-step2" onclick={selectReplacementCategory} data-category="Living Area">Living Area</button>
|
||||||
<button class="category-btn-replacement" onclick={selectReplacementCategory} data-category="Anchor">Anchor</button>
|
<button class="category-btn-step2" onclick={selectReplacementCategory} data-category="Parking">Parking</button>
|
||||||
<button class="category-btn-replacement" onclick={selectReplacementCategory} data-category="Maps">Maps</button>
|
<button class="category-btn-step2" onclick={selectReplacementCategory} data-category="Anchor">Anchor</button>
|
||||||
|
<button class="category-btn-step2" onclick={selectReplacementCategory} data-category="Maps">Maps</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Image Grid -->
|
<!-- Image Grid -->
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user