v1.0.1-beta

This commit is contained in:
Ubuntu 2025-09-08 05:15:31 +05:30
parent 0f7a887d50
commit e51c79d402
15 changed files with 8295 additions and 1387 deletions

328
.deploy_last.json Normal file
View File

@ -0,0 +1,328 @@
{
"status": 0,
"result": {
"checkOnly": false,
"completedDate": "2025-09-07T02:50:58.000Z",
"createdBy": "005a3000000Uv2T",
"createdByName": "Property Master",
"createdDate": "2025-09-07T02:50:52.000Z",
"details": {
"componentSuccesses": [
{
"changed": false,
"componentType": "CustomField",
"created": false,
"createdDate": "2025-09-07T02:50:56.000Z",
"deleted": false,
"fileName": "objects/Property_Template__c.object",
"fullName": "Property_Template__c.Description__c",
"id": "00NFV000001x1kH2AQ",
"success": true
},
{
"changed": false,
"componentType": "CustomField",
"created": false,
"createdDate": "2025-09-07T02:50:56.000Z",
"deleted": false,
"fileName": "objects/Property_Template__c.object",
"fullName": "Property_Template__c.Is_Active__c",
"id": "00NFV000001x1kI2AQ",
"success": true
},
{
"changed": false,
"componentType": "CustomField",
"created": false,
"createdDate": "2025-09-07T02:50:56.000Z",
"deleted": false,
"fileName": "objects/Property_Template__c.object",
"fullName": "Property_Template__c.Preview_Image_URL__c",
"id": "00NFV000001x1kJ2AQ",
"success": true
},
{
"changed": false,
"componentType": "CustomField",
"created": false,
"createdDate": "2025-09-07T02:50:56.000Z",
"deleted": false,
"fileName": "objects/Property_Template__c.object",
"fullName": "Property_Template__c.Tags__c",
"id": "00NFV000001x1kK2AQ",
"success": true
},
{
"changed": false,
"componentType": "CustomField",
"created": false,
"createdDate": "2025-09-07T02:50:56.000Z",
"deleted": false,
"fileName": "objects/Property_Template__c.object",
"fullName": "Property_Template__c.Template_Definition__c",
"id": "00NFV000001x1kL2AQ",
"success": true
},
{
"changed": false,
"componentType": "ApexClass",
"created": false,
"createdDate": "2025-09-07T02:50:57.000Z",
"deleted": false,
"fileName": "classes/PdfApiController.cls",
"fullName": "PdfApiController",
"id": "01pFV000001hBIzYAM",
"success": true
},
{
"changed": false,
"componentType": "ApexClass",
"created": false,
"createdDate": "2025-09-07T02:50:57.000Z",
"deleted": false,
"fileName": "classes/PropertyDataController.cls",
"fullName": "PropertyDataController",
"id": "01pFV000001hATNYA2",
"success": true
},
{
"changed": false,
"componentType": "ApexClass",
"created": false,
"createdDate": "2025-09-07T02:50:57.000Z",
"deleted": false,
"fileName": "classes/PropertyPdfGeneratorController.cls",
"fullName": "PropertyPdfGeneratorController",
"id": "01pFV000001hDhNYAU",
"success": true
},
{
"changed": false,
"componentType": "ApexClass",
"created": false,
"createdDate": "2025-09-07T02:50:57.000Z",
"deleted": false,
"fileName": "classes/PropertyTemplateController.cls",
"fullName": "PropertyTemplateController",
"id": "01pFV000001hAA1YAM",
"success": true
},
{
"changed": true,
"componentType": "LightningComponentBundle",
"created": false,
"createdDate": "2025-09-07T02:50:58.000Z",
"deleted": false,
"fileName": "lwc/propertyTemplateSelector",
"fullName": "propertyTemplateSelector",
"id": "0RbFV0000008L7J0AU",
"success": true
},
{
"changed": true,
"componentType": "CustomObject",
"created": false,
"createdDate": "2025-09-07T02:50:58.000Z",
"deleted": false,
"fileName": "objects/Property_Template__c.object",
"fullName": "Property_Template__c",
"id": "01IFV000000CbQP2A0",
"success": true
},
{
"changed": true,
"componentType": "CspTrustedSite",
"created": false,
"createdDate": "2025-09-07T02:50:58.000Z",
"deleted": false,
"fileName": "cspTrustedSites/PDF_API_Trusted_Site.cspTrustedSite",
"fullName": "PDF_API_Trusted_Site",
"id": "08yFV0000000U1JYAU",
"success": true
},
{
"changed": true,
"componentType": "",
"created": false,
"createdDate": "2025-09-07T02:50:58.000Z",
"deleted": false,
"fileName": "package.xml",
"fullName": "package.xml",
"success": true
}
],
"runTestResult": {
"numFailures": 0,
"numTestsRun": 0,
"totalTime": 0,
"codeCoverage": [],
"codeCoverageWarnings": [],
"failures": [],
"flowCoverage": [],
"flowCoverageWarnings": [],
"successes": []
},
"componentFailures": []
},
"done": true,
"id": "0AfFV000003mAxp0AE",
"ignoreWarnings": false,
"lastModifiedDate": "2025-09-07T02:50:58.000Z",
"numberComponentErrors": 0,
"numberComponentsDeployed": 12,
"numberComponentsTotal": 12,
"numberFiles": "24",
"numberTestErrors": 0,
"numberTestsCompleted": 0,
"numberTestsTotal": 0,
"rollbackOnError": true,
"runTestsEnabled": false,
"startDate": "2025-09-07T02:50:53.000Z",
"status": "Succeeded",
"success": true,
"zipSize": 286681,
"files": [
{
"fullName": "PdfApiController",
"type": "ApexClass",
"state": "Unchanged",
"filePath": "/home/ubuntu/salesforce/PDF_Generation_and_Automation/force-app/main/default/classes/PdfApiController.cls"
},
{
"fullName": "PdfApiController",
"type": "ApexClass",
"state": "Unchanged",
"filePath": "/home/ubuntu/salesforce/PDF_Generation_and_Automation/force-app/main/default/classes/PdfApiController.cls-meta.xml"
},
{
"fullName": "PropertyDataController",
"type": "ApexClass",
"state": "Unchanged",
"filePath": "/home/ubuntu/salesforce/PDF_Generation_and_Automation/force-app/main/default/classes/PropertyDataController.cls"
},
{
"fullName": "PropertyDataController",
"type": "ApexClass",
"state": "Unchanged",
"filePath": "/home/ubuntu/salesforce/PDF_Generation_and_Automation/force-app/main/default/classes/PropertyDataController.cls-meta.xml"
},
{
"fullName": "PropertyPdfGeneratorController",
"type": "ApexClass",
"state": "Unchanged",
"filePath": "/home/ubuntu/salesforce/PDF_Generation_and_Automation/force-app/main/default/classes/PropertyPdfGeneratorController.cls"
},
{
"fullName": "PropertyPdfGeneratorController",
"type": "ApexClass",
"state": "Unchanged",
"filePath": "/home/ubuntu/salesforce/PDF_Generation_and_Automation/force-app/main/default/classes/PropertyPdfGeneratorController.cls-meta.xml"
},
{
"fullName": "PropertyTemplateController",
"type": "ApexClass",
"state": "Unchanged",
"filePath": "/home/ubuntu/salesforce/PDF_Generation_and_Automation/force-app/main/default/classes/PropertyTemplateController.cls"
},
{
"fullName": "PropertyTemplateController",
"type": "ApexClass",
"state": "Unchanged",
"filePath": "/home/ubuntu/salesforce/PDF_Generation_and_Automation/force-app/main/default/classes/PropertyTemplateController.cls-meta.xml"
},
{
"fullName": "PDF_API_Trusted_Site",
"type": "CspTrustedSite",
"state": "Changed",
"filePath": "/home/ubuntu/salesforce/PDF_Generation_and_Automation/force-app/main/default/cspTrustedSites/PDF_API_Trusted_Site.cspTrustedSite-meta.xml"
},
{
"fullName": "Property_Template__c.Description__c",
"type": "CustomField",
"state": "Unchanged",
"filePath": "/home/ubuntu/salesforce/PDF_Generation_and_Automation/force-app/main/default/objects/Property_Template__c/fields/Description__c.field-meta.xml"
},
{
"fullName": "Property_Template__c.Is_Active__c",
"type": "CustomField",
"state": "Unchanged",
"filePath": "/home/ubuntu/salesforce/PDF_Generation_and_Automation/force-app/main/default/objects/Property_Template__c/fields/Is_Active__c.field-meta.xml"
},
{
"fullName": "Property_Template__c.Preview_Image_URL__c",
"type": "CustomField",
"state": "Unchanged",
"filePath": "/home/ubuntu/salesforce/PDF_Generation_and_Automation/force-app/main/default/objects/Property_Template__c/fields/Preview_Image_URL__c.field-meta.xml"
},
{
"fullName": "Property_Template__c.Tags__c",
"type": "CustomField",
"state": "Unchanged",
"filePath": "/home/ubuntu/salesforce/PDF_Generation_and_Automation/force-app/main/default/objects/Property_Template__c/fields/Tags__c.field-meta.xml"
},
{
"fullName": "Property_Template__c.Template_Definition__c",
"type": "CustomField",
"state": "Unchanged",
"filePath": "/home/ubuntu/salesforce/PDF_Generation_and_Automation/force-app/main/default/objects/Property_Template__c/fields/Template_Definition__c.field-meta.xml"
},
{
"fullName": "Property_Template__c",
"type": "CustomObject",
"state": "Changed",
"filePath": "/home/ubuntu/salesforce/PDF_Generation_and_Automation/force-app/main/default/objects/Property_Template__c/Property_Template__c.object-meta.xml"
},
{
"fullName": "propertyTemplateSelector",
"type": "LightningComponentBundle",
"state": "Changed",
"filePath": "/home/ubuntu/salesforce/PDF_Generation_and_Automation/force-app/main/default/lwc/propertyTemplateSelector/production-config.js"
},
{
"fullName": "propertyTemplateSelector",
"type": "LightningComponentBundle",
"state": "Changed",
"filePath": "/home/ubuntu/salesforce/PDF_Generation_and_Automation/force-app/main/default/lwc/propertyTemplateSelector/propertyTemplateSelector.css"
},
{
"fullName": "propertyTemplateSelector",
"type": "LightningComponentBundle",
"state": "Changed",
"filePath": "/home/ubuntu/salesforce/PDF_Generation_and_Automation/force-app/main/default/lwc/propertyTemplateSelector/propertyTemplateSelector.css.backup"
},
{
"fullName": "propertyTemplateSelector",
"type": "LightningComponentBundle",
"state": "Changed",
"filePath": "/home/ubuntu/salesforce/PDF_Generation_and_Automation/force-app/main/default/lwc/propertyTemplateSelector/propertyTemplateSelector.html"
},
{
"fullName": "propertyTemplateSelector",
"type": "LightningComponentBundle",
"state": "Changed",
"filePath": "/home/ubuntu/salesforce/PDF_Generation_and_Automation/force-app/main/default/lwc/propertyTemplateSelector/propertyTemplateSelector.html.backup"
},
{
"fullName": "propertyTemplateSelector",
"type": "LightningComponentBundle",
"state": "Changed",
"filePath": "/home/ubuntu/salesforce/PDF_Generation_and_Automation/force-app/main/default/lwc/propertyTemplateSelector/propertyTemplateSelector.js"
},
{
"fullName": "propertyTemplateSelector",
"type": "LightningComponentBundle",
"state": "Changed",
"filePath": "/home/ubuntu/salesforce/PDF_Generation_and_Automation/force-app/main/default/lwc/propertyTemplateSelector/propertyTemplateSelector.js-meta.xml"
},
{
"fullName": "propertyTemplateSelector",
"type": "LightningComponentBundle",
"state": "Changed",
"filePath": "/home/ubuntu/salesforce/PDF_Generation_and_Automation/force-app/main/default/lwc/propertyTemplateSelector/propertyTemplateSelector.js.backup"
}
],
"zipFileCount": 19,
"deployUrl": "https://tso3--r1.sandbox.my.salesforce.com/lightning/setup/DeployStatus/page?address=%2Fchangemgmt%2FmonitorDeploymentsDetails.apexp%3FasyncId%3D0AfFV000003mAxp0AE%26retURL%3D%252Fchangemgmt%252FmonitorDeployment.apexp"
},
"warnings": []
}

View File

@ -8,9 +8,6 @@ public with sharing class PDFGenerationProxy {
throw new AuraHandledException('HTML content cannot be empty. Please provide valid HTML content.');
}
System.debug('=== PDF GENERATION DEBUG ===');
System.debug('HTML Content Length: ' + htmlContent.length());
System.debug('Page Size: ' + pageSize);
// Call the Node.js API with return_download_link: true
Http http = new Http();
@ -22,24 +19,43 @@ public with sharing class PDFGenerationProxy {
request.setHeader('Content-Type', 'application/json');
request.setTimeout(120000); // 2 minutes timeout
// Ensure relative resource URLs resolve to Salesforce domain by injecting <base>
String modifiedHtml = htmlContent;
String baseUrl = null;
try {
baseUrl = URL.getOrgDomainUrl().toExternalForm();
if (modifiedHtml != null && !modifiedHtml.toLowerCase().contains('<base ')) {
String lower = modifiedHtml.toLowerCase();
Integer headIdx = lower.indexOf('<head>');
if (headIdx >= 0) {
Integer insertPos = headIdx + 6; // after <head>
modifiedHtml = modifiedHtml.substring(0, insertPos) + '<base href=\'' + baseUrl + '/\' />' + modifiedHtml.substring(insertPos);
} else {
// Prepend base if no head tag found
modifiedHtml = '<head><base href=\'' + baseUrl + '/\' /></head>' + modifiedHtml;
}
}
} catch (Exception e) {
// best-effort only
}
// Prepare the request body
Map<String, Object> requestBody = new Map<String, Object>();
requestBody.put('input', htmlContent);
requestBody.put('input', modifiedHtml);
requestBody.put('return_download_link', true);
if (String.isNotBlank(pageSize)) {
requestBody.put('page_size', pageSize);
}
// Use 'format' for the Node API, keep page_size for backward-compat
String formatVal = String.isNotBlank(pageSize) ? pageSize : 'A4';
requestBody.put('format', formatVal);
requestBody.put('page_size', formatVal);
String jsonBody = JSON.serialize(requestBody);
request.setBody(jsonBody);
System.debug('Request body: ' + jsonBody);
// Make the HTTP call
HttpResponse response = http.send(request);
System.debug('Response status: ' + response.getStatusCode());
System.debug('Response body: ' + response.getBody());
if (response.getStatusCode() == 200) {
// Parse the response
@ -63,8 +79,6 @@ public with sharing class PDFGenerationProxy {
}
} catch (Exception e) {
System.debug('Exception in generatePDFFromHTML: ' + e.getMessage());
System.debug('Exception stack trace: ' + e.getStackTraceString());
Map<String, Object> errorResult = new Map<String, Object>();
errorResult.put('success', false);
@ -84,9 +98,6 @@ public with sharing class PDFGenerationProxy {
throw new AuraHandledException('HTML content cannot be empty. Please provide valid HTML content.');
}
System.debug('=== COMPRESSED PDF GENERATION DEBUG ===');
System.debug('HTML Content Length: ' + htmlContent.length());
System.debug('Page Size: ' + pageSize);
// Call the Node.js API with return_download_link: true
Http http = new Http();
@ -109,13 +120,10 @@ public with sharing class PDFGenerationProxy {
String jsonBody = JSON.serialize(requestBody);
request.setBody(jsonBody);
System.debug('Request body: ' + jsonBody);
// Make the HTTP call
HttpResponse response = http.send(request);
System.debug('Response status: ' + response.getStatusCode());
System.debug('Response body: ' + response.getBody());
if (response.getStatusCode() == 200) {
// Parse the response
@ -142,8 +150,6 @@ public with sharing class PDFGenerationProxy {
}
} catch (Exception e) {
System.debug('Exception in generateCompressedPDF: ' + e.getMessage());
System.debug('Exception stack trace: ' + e.getStackTraceString());
Map<String, Object> errorResult = new Map<String, Object>();
errorResult.put('success', false);

View File

@ -0,0 +1,234 @@
.development-page {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
z-index: 9999;
overflow-y: auto;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
color: #ffffff;
}
.dev-header {
background: rgba(0, 0, 0, 0.8);
padding: 20px;
text-align: center;
border-bottom: 2px solid #ff6b6b;
position: sticky;
top: 0;
z-index: 10000;
}
.dev-header h1 {
margin: 0;
font-size: 2.5rem;
color: #ff6b6b;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
}
.dev-warning {
margin: 10px 0;
font-size: 1.2rem;
color: #ffd93d;
font-weight: bold;
text-transform: uppercase;
letter-spacing: 2px;
}
.dev-instruction {
margin: 10px 0;
font-size: 1rem;
color: #74b9ff;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 1px;
}
.close-dev-btn {
position: absolute;
top: 20px;
right: 20px;
background: #ff4757;
color: white;
border: none;
border-radius: 50%;
width: 40px;
height: 40px;
font-size: 1.5rem;
cursor: pointer;
transition: all 0.3s ease;
}
.close-dev-btn:hover {
background: #ff3742;
transform: scale(1.1);
}
.dev-content {
padding: 30px;
max-width: 1200px;
margin: 0 auto;
}
.dev-section {
background: rgba(255, 255, 255, 0.1);
border-radius: 15px;
padding: 25px;
margin-bottom: 25px;
border: 1px solid rgba(255, 255, 255, 0.2);
backdrop-filter: blur(10px);
}
.dev-section h2 {
margin: 0 0 20px 0;
color: #74b9ff;
font-size: 1.8rem;
border-bottom: 2px solid #74b9ff;
padding-bottom: 10px;
}
.dev-tools {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
}
.dev-btn {
background: linear-gradient(45deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 8px;
padding: 15px 20px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
text-transform: uppercase;
letter-spacing: 1px;
}
.dev-btn:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
}
.dev-btn.primary {
background: linear-gradient(45deg, #00b894 0%, #00a085 100%);
}
.dev-btn.primary:hover {
box-shadow: 0 5px 15px rgba(0, 184, 148, 0.4);
}
.dev-btn.secondary {
background: linear-gradient(45deg, #6c5ce7 0%, #a29bfe 100%);
}
.dev-btn.secondary:hover {
box-shadow: 0 5px 15px rgba(108, 92, 231, 0.4);
}
.dev-btn.warning {
background: linear-gradient(45deg, #e17055 0%, #d63031 100%);
}
.dev-btn.warning:hover {
box-shadow: 0 5px 15px rgba(225, 112, 85, 0.4);
}
.status-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 15px;
}
.status-item {
background: rgba(255, 255, 255, 0.05);
border-radius: 8px;
padding: 15px;
display: flex;
justify-content: space-between;
align-items: center;
border-left: 4px solid #74b9ff;
}
.status-label {
font-weight: 600;
color: #ddd;
}
.status-value {
font-weight: bold;
padding: 5px 10px;
border-radius: 20px;
font-size: 0.9rem;
}
.status-value.success {
background: rgba(0, 184, 148, 0.2);
color: #00b894;
border: 1px solid #00b894;
}
.debug-info {
background: rgba(0, 0, 0, 0.3);
border-radius: 8px;
padding: 20px;
font-family: 'Courier New', monospace;
}
.debug-info p {
margin: 8px 0;
color: #ddd;
}
.debug-info strong {
color: #74b9ff;
}
.quick-actions {
display: flex;
gap: 15px;
flex-wrap: wrap;
}
/* Responsive design */
@media (max-width: 768px) {
.dev-content {
padding: 15px;
}
.dev-header h1 {
font-size: 2rem;
}
.dev-tools {
grid-template-columns: 1fr;
}
.quick-actions {
flex-direction: column;
}
.status-grid {
grid-template-columns: 1fr;
}
}
/* Animation for page entrance */
@keyframes slideInFromTop {
from {
transform: translateY(-100%);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
.development-page {
animation: slideInFromTop 0.5s ease-out;
}

View File

@ -0,0 +1,53 @@
<template>
<div class="development-page" if:true={showDevPage}>
<div class="dev-header">
<h1>🚧 Development Area 🚧</h1>
<p class="dev-warning">UNDER DEVELOPMENT - DO NOT TEST</p>
</div>
<div class="dev-content">
<div class="dev-section">
<h2>📊 System Status</h2>
<div class="status-grid">
<div class="status-item">
<span class="status-label">LWC Status:</span>
<span class="status-value success">✅ Active</span>
</div>
<div class="status-item">
<span class="status-label">PDF Service:</span>
<span class="status-value success">✅ Connected</span>
</div>
<div class="status-item">
<span class="status-label">Templates:</span>
<span class="status-value success">✅ Loaded</span>
</div>
<div class="status-item">
<span class="status-label">Property Data:</span>
<span class="status-value success">✅ Available</span>
</div>
</div>
</div>
<div class="dev-section">
<h2>🐛 Debug Information</h2>
<div class="debug-info">
<p><strong>Current Step:</strong> {currentStep}</p>
<p><strong>Selected Template:</strong> {selectedTemplateId}</p>
<p><strong>Selected Property:</strong> {selectedPropertyId}</p>
<p><strong>Page Size:</strong> {selectedPageSize}</p>
<p><strong>Timestamp:</strong> {currentTimestamp}</p>
</div>
</div>
<div class="dev-section">
<h2>⚙️ Quick Actions</h2>
<div class="quick-actions">
<button class="dev-btn primary" onclick={forceReload}>Force Reload</button>
<button class="dev-btn secondary" onclick={toggleDebugMode}>Toggle Debug Mode</button>
<button class="dev-btn warning" onclick={clearCache}>Clear Cache</button>
</div>
</div>
</div>
</div>
</template>

View File

@ -0,0 +1,162 @@
import { LightningElement, track } from 'lwc';
export default class DevelopmentPage extends LightningElement {
@track showDevPage = true;
@track currentStep = 1;
@track selectedTemplateId = '';
@track selectedPropertyId = '';
@track selectedPageSize = 'A4';
@track currentTimestamp = '';
@track debugMode = false;
// V-key click counter
vKeyCount = 0;
vKeyTimeout = null;
connectedCallback() {
this.updateTimestamp();
this.addKeyListener();
}
disconnectedCallback() {
this.removeKeyListener();
if (this.vKeyTimeout) {
clearTimeout(this.vKeyTimeout);
}
}
addKeyListener() {
document.addEventListener('keydown', this.handleKeyPress.bind(this));
}
removeKeyListener() {
document.removeEventListener('keydown', this.handleKeyPress.bind(this));
}
handleKeyPress(event) {
// Only listen for 'V' key (case insensitive)
if (event.key.toLowerCase() === 'v') {
this.vKeyCount++;
// Clear any existing timeout
if (this.vKeyTimeout) {
clearTimeout(this.vKeyTimeout);
}
// Reset counter after 3 seconds of inactivity
this.vKeyTimeout = setTimeout(() => {
this.vKeyCount = 0;
}, 3000);
// Hide dev page after 4 V key presses
if (this.vKeyCount >= 4) {
this.showDevPage = false;
this.vKeyCount = 0; // Reset counter
}
}
}
closeDevPage() {
this.showDevPage = false;
this.vKeyCount = 0;
if (this.vKeyTimeout) {
clearTimeout(this.vKeyTimeout);
}
}
updateTimestamp() {
this.currentTimestamp = new Date().toLocaleString();
}
// Development actions
clearAllData() {
if (confirm('Are you sure you want to clear all data? This action cannot be undone.')) {
// Clear all component data
this.currentStep = 1;
this.selectedTemplateId = '';
this.selectedPropertyId = '';
this.selectedPageSize = 'A4';
this.updateTimestamp();
// Dispatch event to parent component
this.dispatchEvent(new CustomEvent('cleardata'));
}
}
resetTemplates() {
if (confirm('Reset all templates to default state?')) {
// Dispatch event to parent component
this.dispatchEvent(new CustomEvent('resettemplates'));
}
}
exportDebugInfo() {
const debugData = {
timestamp: this.currentTimestamp,
currentStep: this.currentStep,
selectedTemplateId: this.selectedTemplateId,
selectedPropertyId: this.selectedPropertyId,
selectedPageSize: this.selectedPageSize,
userAgent: navigator.userAgent,
url: window.location.href
};
const blob = new Blob([JSON.stringify(debugData, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `debug-info-${Date.now()}.json`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
testPdfGeneration() {
// Dispatch event to parent component
this.dispatchEvent(new CustomEvent('testpdf'));
}
forceReload() {
if (confirm('Force reload the entire application?')) {
window.location.reload();
}
}
toggleDebugMode() {
this.debugMode = !this.debugMode;
// Dispatch event to parent component
this.dispatchEvent(new CustomEvent('toggledebug', {
detail: { debugMode: this.debugMode }
}));
}
clearCache() {
if (confirm('Clear browser cache and localStorage?')) {
// Clear localStorage
localStorage.clear();
sessionStorage.clear();
// Clear any cached data
if ('caches' in window) {
caches.keys().then(names => {
names.forEach(name => {
caches.delete(name);
});
});
}
alert('Cache cleared successfully!');
}
}
// Method to update data from parent component
updateData(data) {
if (data.currentStep !== undefined) this.currentStep = data.currentStep;
if (data.selectedTemplateId !== undefined) this.selectedTemplateId = data.selectedTemplateId;
if (data.selectedPropertyId !== undefined) this.selectedPropertyId = data.selectedPropertyId;
if (data.selectedPageSize !== undefined) this.selectedPageSize = data.selectedPageSize;
this.updateTimestamp();
}
}

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>58.0</apiVersion>
<isExposed>false</isExposed>
<targets>
<target>lightning__AppPage</target>
<target>lightning__RecordPage</target>
<target>lightning__HomePage</target>
</targets>
</LightningComponentBundle>

View File

@ -0,0 +1,560 @@
/* Professional Editor Styles */
.professional-editor-container {
display: flex;
flex-direction: column;
height: 100%;
background: #ffffff;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
/* Editor Header */
.editor-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 24px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.editor-title {
display: flex;
align-items: center;
gap: 12px;
}
.editor-title h3 {
margin: 0;
font-size: 1.25rem;
font-weight: 600;
}
.editor-actions {
display: flex;
gap: 12px;
}
.header-btn {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
background: rgba(255, 255, 255, 0.2);
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 6px;
color: white;
font-size: 0.875rem;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
}
.header-btn:hover {
background: rgba(255, 255, 255, 0.3);
transform: translateY(-1px);
}
.header-btn.save {
background: rgba(46, 204, 113, 0.8);
border-color: rgba(46, 204, 113, 0.9);
}
.header-btn.save:hover {
background: rgba(46, 204, 113, 1);
}
/* Editor Layout */
.editor-layout {
display: flex;
flex: 1;
min-height: 0;
}
/* Professional Sidebar */
.editor-sidebar {
width: 320px;
background: #f8f9fa;
border-right: 1px solid #e9ecef;
display: flex;
flex-direction: column;
transition: width 0.3s ease;
}
.editor-sidebar.collapsed {
width: 60px;
}
.sidebar-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 20px;
background: #ffffff;
border-bottom: 1px solid #e9ecef;
}
.sidebar-header h4 {
margin: 0;
font-size: 1rem;
font-weight: 600;
color: #495057;
}
.sidebar-toggle {
background: none;
border: none;
color: #6c757d;
cursor: pointer;
padding: 4px;
border-radius: 4px;
transition: all 0.2s ease;
}
.sidebar-toggle:hover {
background: #e9ecef;
color: #495057;
}
.sidebar-content {
flex: 1;
overflow-y: auto;
padding: 16px;
}
/* Tool Sections */
.tool-section {
margin-bottom: 24px;
background: #ffffff;
border-radius: 8px;
border: 1px solid #e9ecef;
overflow: hidden;
}
.section-header {
display: flex;
align-items: center;
gap: 8px;
padding: 12px 16px;
background: #f8f9fa;
border-bottom: 1px solid #e9ecef;
font-size: 0.875rem;
font-weight: 600;
color: #495057;
}
.tool-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
padding: 16px;
}
.tool-btn {
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
padding: 12px 8px;
background: #ffffff;
border: 1px solid #e9ecef;
border-radius: 6px;
color: #495057;
font-size: 0.75rem;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
text-align: center;
}
.tool-btn:hover {
background: #f8f9fa;
border-color: #667eea;
color: #667eea;
transform: translateY(-1px);
}
.tool-btn.primary {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border-color: #667eea;
}
.tool-btn.primary:hover {
background: linear-gradient(135deg, #5a6fd8 0%, #6a4190 100%);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
}
.tool-btn.secondary {
background: #f8f9fa;
border-color: #dee2e6;
}
.tool-btn.secondary:hover {
background: #e9ecef;
border-color: #adb5bd;
}
/* Formatting Controls */
.formatting-controls {
padding: 16px;
border-bottom: 1px solid #e9ecef;
}
.control-group {
margin-bottom: 12px;
}
.control-group:last-child {
margin-bottom: 0;
}
.control-group label {
display: block;
margin-bottom: 4px;
font-size: 0.75rem;
font-weight: 600;
color: #6c757d;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.control-select {
width: 100%;
padding: 8px 12px;
border: 1px solid #e9ecef;
border-radius: 4px;
background: #ffffff;
font-size: 0.875rem;
color: #495057;
transition: border-color 0.2s ease;
}
.control-select:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
/* Style Buttons */
.style-buttons {
display: flex;
gap: 8px;
padding: 16px;
justify-content: center;
}
.style-btn {
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
background: #ffffff;
border: 1px solid #e9ecef;
border-radius: 6px;
color: #495057;
font-size: 0.875rem;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
}
.style-btn:hover {
background: #f8f9fa;
border-color: #667eea;
color: #667eea;
transform: translateY(-1px);
}
.style-btn.active {
background: #667eea;
border-color: #667eea;
color: white;
}
.highlight-icon {
background: #ffd93d;
color: #333;
padding: 2px 4px;
border-radius: 2px;
font-weight: bold;
}
/* Alignment & List Buttons */
.alignment-buttons, .list-buttons {
display: flex;
gap: 8px;
padding: 16px;
justify-content: center;
}
.align-btn, .list-btn {
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
background: #ffffff;
border: 1px solid #e9ecef;
border-radius: 6px;
color: #495057;
cursor: pointer;
transition: all 0.2s ease;
}
.align-btn:hover, .list-btn:hover {
background: #f8f9fa;
border-color: #667eea;
color: #667eea;
transform: translateY(-1px);
}
/* Media Buttons */
.media-buttons {
display: flex;
flex-direction: column;
gap: 8px;
padding: 16px;
}
.media-btn {
display: flex;
align-items: center;
gap: 8px;
padding: 12px 16px;
background: #ffffff;
border: 1px solid #e9ecef;
border-radius: 6px;
color: #495057;
font-size: 0.875rem;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
}
.media-btn:hover {
background: #f8f9fa;
border-color: #667eea;
color: #667eea;
transform: translateY(-1px);
}
/* Action Buttons */
.action-buttons {
display: flex;
flex-direction: column;
gap: 8px;
padding: 16px;
}
.action-btn {
display: flex;
align-items: center;
gap: 8px;
padding: 12px 16px;
background: #ffffff;
border: 1px solid #e9ecef;
border-radius: 6px;
color: #495057;
font-size: 0.875rem;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
}
.action-btn:hover {
background: #f8f9fa;
border-color: #667eea;
color: #667eea;
transform: translateY(-1px);
}
.action-btn.undo {
border-color: #ffc107;
color: #856404;
}
.action-btn.undo:hover {
background: #fff3cd;
border-color: #ffb300;
}
.action-btn.redo {
border-color: #17a2b8;
color: #0c5460;
}
.action-btn.redo:hover {
background: #d1ecf1;
border-color: #138496;
}
.action-btn.save {
background: #28a745;
border-color: #28a745;
color: white;
}
.action-btn.save:hover {
background: #218838;
border-color: #1e7e34;
}
.action-btn.reset {
border-color: #dc3545;
color: #721c24;
}
.action-btn.reset:hover {
background: #f8d7da;
border-color: #c82333;
}
/* Professional Viewport */
.editor-viewport {
flex: 1;
display: flex;
flex-direction: column;
background: #f8f9fa;
}
.viewport-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 20px;
background: #ffffff;
border-bottom: 1px solid #e9ecef;
}
.viewport-controls {
display: flex;
align-items: center;
gap: 12px;
}
.viewport-btn {
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
background: #ffffff;
border: 1px solid #e9ecef;
border-radius: 4px;
color: #495057;
cursor: pointer;
transition: all 0.2s ease;
}
.viewport-btn:hover {
background: #f8f9fa;
border-color: #667eea;
color: #667eea;
}
.zoom-level {
font-size: 0.875rem;
font-weight: 500;
color: #495057;
min-width: 40px;
text-align: center;
}
.viewport-info {
display: flex;
align-items: center;
gap: 8px;
}
.page-size {
padding: 4px 8px;
background: #e9ecef;
border-radius: 4px;
font-size: 0.75rem;
font-weight: 600;
color: #495057;
}
.viewport-content {
flex: 1;
padding: 20px;
overflow: auto;
display: flex;
justify-content: center;
align-items: flex-start;
}
.editor-canvas {
background: #ffffff;
border-radius: 8px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
overflow: hidden;
min-width: 800px;
max-width: 100%;
}
.enhanced-editor-content {
min-height: 600px;
padding: 40px;
outline: none;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
color: #333;
}
.enhanced-editor-content:focus {
box-shadow: inset 0 0 0 2px #667eea;
}
/* Responsive Design */
@media (max-width: 1200px) {
.editor-sidebar {
width: 280px;
}
.tool-grid {
grid-template-columns: 1fr;
}
}
@media (max-width: 768px) {
.editor-layout {
flex-direction: column;
}
.editor-sidebar {
width: 100%;
height: auto;
max-height: 300px;
}
.editor-canvas {
min-width: 100%;
}
.enhanced-editor-content {
padding: 20px;
min-height: 400px;
}
}
/* Animation for smooth transitions */
.tool-section {
animation: slideInUp 0.3s ease-out;
}
@keyframes slideInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}

View File

@ -0,0 +1,231 @@
<!-- Professional Editor Section -->
<div class="professional-editor-container">
<!-- Editor Header -->
<div class="editor-header">
<div class="editor-title">
<lightning-icon icon-name="utility:edit" size="small"></lightning-icon>
<h3>Template Editor</h3>
</div>
<div class="editor-actions">
<button class="header-btn preview" onclick={togglePreview} title="Toggle Preview">
<lightning-icon icon-name="utility:preview" size="x-small"></lightning-icon>
Preview
</button>
<button class="header-btn save" onclick={handleSave} title="Save Template">
<lightning-icon icon-name="utility:save" size="x-small"></lightning-icon>
Save
</button>
</div>
</div>
<!-- Editor Layout -->
<div class="editor-layout">
<!-- Professional Sidebar -->
<div class="editor-sidebar">
<div class="sidebar-header">
<h4>Tools</h4>
<button class="sidebar-toggle" onclick={toggleSidebar}>
<lightning-icon icon-name="utility:chevronleft" size="x-small"></lightning-icon>
</button>
</div>
<div class="sidebar-content">
<!-- Property Data Insert -->
<div class="tool-section">
<div class="section-header">
<lightning-icon icon-name="utility:insert_template" size="x-small"></lightning-icon>
<span>Property Data</span>
</div>
<div class="tool-grid">
<button class="tool-btn primary" onclick={insertPropertyName} title="Property Name">
<lightning-icon icon-name="utility:home" size="x-small"></lightning-icon>
Name
</button>
<button class="tool-btn primary" onclick={insertPropertyLocation} title="Location">
<lightning-icon icon-name="utility:location" size="x-small"></lightning-icon>
Location
</button>
<button class="tool-btn primary" onclick={insertPropertyPrice} title="Price">
<lightning-icon icon-name="utility:currency" size="x-small"></lightning-icon>
Price
</button>
<button class="tool-btn primary" onclick={insertPropertyType} title="Type">
<lightning-icon icon-name="utility:building" size="x-small"></lightning-icon>
Type
</button>
<button class="tool-btn secondary" onclick={insertPropertyBedrooms} title="Bedrooms">
<lightning-icon icon-name="utility:bed" size="x-small"></lightning-icon>
Bedrooms
</button>
<button class="tool-btn secondary" onclick={insertPropertyBathrooms} title="Bathrooms">
<lightning-icon icon-name="utility:bath" size="x-small"></lightning-icon>
Bathrooms
</button>
<button class="tool-btn secondary" onclick={insertPropertyArea} title="Area">
<lightning-icon icon-name="utility:expand" size="x-small"></lightning-icon>
Area
</button>
<button class="tool-btn secondary" onclick={insertPropertyDescription} title="Description">
<lightning-icon icon-name="utility:text" size="x-small"></lightning-icon>
Description
</button>
</div>
</div>
<!-- Text Formatting -->
<div class="tool-section">
<div class="section-header">
<lightning-icon icon-name="utility:text" size="x-small"></lightning-icon>
<span>Text Formatting</span>
</div>
<div class="formatting-controls">
<div class="control-group">
<label>Font Family</label>
<select class="control-select" onchange={handleFontFamilyChange}>
<option value="Arial">Arial</option>
<option value="Times New Roman">Times New Roman</option>
<option value="Helvetica">Helvetica</option>
<option value="Georgia">Georgia</option>
<option value="Verdana">Verdana</option>
</select>
</div>
<div class="control-group">
<label>Font Size</label>
<select class="control-select" onchange={handleFontSizeChange}>
<option value="12px">12px</option>
<option value="14px">14px</option>
<option value="16px">16px</option>
<option value="18px">18px</option>
<option value="20px">20px</option>
<option value="24px">24px</option>
<option value="28px">28px</option>
<option value="32px">32px</option>
</select>
</div>
</div>
<div class="style-buttons">
<button class="style-btn" onclick={handleBold} title="Bold">
<strong>B</strong>
</button>
<button class="style-btn" onclick={handleItalic} title="Italic">
<em>I</em>
</button>
<button class="style-btn" onclick={handleUnderline} title="Underline">
<u>U</u>
</button>
<button class="style-btn" onclick={handleHighlight} title="Highlight">
<span class="highlight-icon">H</span>
</button>
</div>
</div>
<!-- Alignment & Lists -->
<div class="tool-section">
<div class="section-header">
<lightning-icon icon-name="utility:align" size="x-small"></lightning-icon>
<span>Alignment & Lists</span>
</div>
<div class="alignment-buttons">
<button class="align-btn" onclick={handleAlignLeft} title="Align Left">
<lightning-icon icon-name="utility:left_align_text" size="x-small"></lightning-icon>
</button>
<button class="align-btn" onclick={handleAlignCenter} title="Align Center">
<lightning-icon icon-name="utility:center_align_text" size="x-small"></lightning-icon>
</button>
<button class="align-btn" onclick={handleAlignRight} title="Align Right">
<lightning-icon icon-name="utility:right_align_text" size="x-small"></lightning-icon>
</button>
</div>
<div class="list-buttons">
<button class="list-btn" onclick={handleBulletList} title="Bullet List">
<lightning-icon icon-name="utility:bullet_list" size="x-small"></lightning-icon>
</button>
<button class="list-btn" onclick={handleNumberList} title="Numbered List">
<lightning-icon icon-name="utility:numbered_list" size="x-small"></lightning-icon>
</button>
<button class="list-btn" onclick={handleIndent} title="Indent">
<lightning-icon icon-name="utility:indent" size="x-small"></lightning-icon>
</button>
<button class="list-btn" onclick={handleOutdent} title="Outdent">
<lightning-icon icon-name="utility:outdent" size="x-small"></lightning-icon>
</button>
</div>
</div>
<!-- Media & Tables -->
<div class="tool-section">
<div class="section-header">
<lightning-icon icon-name="utility:image" size="x-small"></lightning-icon>
<span>Media & Tables</span>
</div>
<div class="media-buttons">
<button class="media-btn" onclick={insertImage} title="Insert Image">
<lightning-icon icon-name="utility:image" size="x-small"></lightning-icon>
Image
</button>
<button class="media-btn" onclick={insertTable} title="Insert Table">
<lightning-icon icon-name="utility:table" size="x-small"></lightning-icon>
Table
</button>
</div>
</div>
<!-- Document Actions -->
<div class="tool-section">
<div class="section-header">
<lightning-icon icon-name="utility:settings" size="x-small"></lightning-icon>
<span>Document Actions</span>
</div>
<div class="action-buttons">
<button class="action-btn undo" onclick={undo} title="Undo">
<lightning-icon icon-name="utility:undo" size="x-small"></lightning-icon>
Undo
</button>
<button class="action-btn redo" onclick={redo} title="Redo">
<lightning-icon icon-name="utility:redo" size="x-small"></lightning-icon>
Redo
</button>
<button class="action-btn save" onclick={handleSave} title="Save">
<lightning-icon icon-name="utility:save" size="x-small"></lightning-icon>
Save
</button>
<button class="action-btn reset" onclick={handleReset} title="Reset">
<lightning-icon icon-name="utility:refresh" size="x-small"></lightning-icon>
Reset
</button>
</div>
</div>
</div>
</div>
<!-- Professional Editor Viewport -->
<div class="editor-viewport">
<div class="viewport-header">
<div class="viewport-controls">
<button class="viewport-btn" onclick={zoomOut} title="Zoom Out">
<lightning-icon icon-name="utility:zoomout" size="x-small"></lightning-icon>
</button>
<span class="zoom-level">100%</span>
<button class="viewport-btn" onclick={zoomIn} title="Zoom In">
<lightning-icon icon-name="utility:zoomin" size="x-small"></lightning-icon>
</button>
</div>
<div class="viewport-info">
<span class="page-size">{selectedPageSize}</span>
</div>
</div>
<div class="viewport-content">
<div class="editor-canvas">
<div class="enhanced-editor-content" contenteditable="true"
onkeyup={handleContentChange}
onpaste={handleContentChange}
ondragover={handleEditorDragOver}
ondrop={handleEditorDrop}>
{htmlContent}
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -1,6 +1,14 @@
<template>
<!-- Development Page (Hidden) -->
<c-development-page
oncleardata={handleClearData}
onresettemplates={handleResetTemplates}
ontestpdf={handleTestPdf}
ontoggledebug={handleToggleDebug}>
</c-development-page>
<div class="property-brochure-generator">
<!-- Header Section - Editable -->
<!-- <template if:true={showHeader}>
@ -22,11 +30,32 @@
</div>
</template>
<!-- Step Progress Stepper -->
<div class="step-stepper-container">
<div class="step-stepper">
<div class="step-item" data-step="1" onclick={goToStep}>
<div class="step-circle {step1NavClass}" style={step1NavStyle}>
<span class="step-number">1</span>
</div>
</div>
<div class="step-connector"></div>
<div class="step-item" data-step="2" onclick={goToStep}>
<div class="step-circle {step2NavClass}" style={step2NavStyle}>
<span class="step-number">2</span>
</div>
</div>
<div class="step-connector"></div>
<div class="step-item" data-step="3" onclick={goToStep}>
<div class="step-circle {step3NavClass}" style={step3NavStyle}>
<span class="step-number">3</span>
</div>
</div>
</div>
</div>
<!-- Step 1: Template Selection -->
<div class={step1Class} data-step="1">
<div class="step-inner-container">
<!-- Template Grid - Professional Black & White Design -->
<div class="template-grid" id="all-templates">
<!-- Blank Template -->
@ -46,7 +75,7 @@
<p>Design every element from scratch. Perfect for unique branding, creative layouts, and
personalized property showcases with your own design vision.</p>
<div class="cta-buttons">
<button class="cta-btn">CREATE NOW</button>
<button class="cta-btn" style="background:#ffffff;color:#000000;">CREATE NOW</button>
</div>
</div>
</div>
@ -64,12 +93,12 @@
onclick={handleTemplateSelect}>
<div class="template-content modern-home-preview">
<!-- Hero Section -->
<div class="hero">
<div class="hero" style="background-image: url('https://images.unsplash.com/photo-1600585154340-be6161a56a0c?ixlib=rb-4.0.3&q=85&fm=jpg&crop=entropy&cs=srgb&w=1200'); background-size: cover; background-position: center;">
<div class="hero-overlay">
<h1 class="property-name" style="color: white !important;">Modern Villa</h1>
<p class="property-address" style="color: white !important;">123 Luxury Lane, Prestige City, PC 45678</p>
<div class="hero-details">
<div class="price" style="color: white !important;">$2,500,000</div>
<div class="price" style="color: white !important;">AED 2,500,000</div>
<div class="stats">
<span class="stat-item" style="color: white !important;"><i class="fa-solid fa-bed"></i> 4 Beds</span>
<span class="stat-item" style="color: white !important;"><i class="fa-solid fa-bath"></i> 3 Baths</span>
@ -102,7 +131,7 @@
<div class="agent-footer">
<div class="agent-info">
<h3>Sarah Johnson</h3>
<h3 style="font-size: 0.95rem;">Sarah Johnson</h3>
<p>Your Real Estate Professional</p>
</div>
<div class="agent-contact-details">
@ -114,7 +143,7 @@
<footer class="page-footer">
<div class="reference-id">
<strong>Reference ID:</strong> MH-2024-001
<strong>Property:</strong> Modern Villa
</div>
<div class="owner-info">
<strong>Owner Info:</strong> John Smith, (555) 987-6543
@ -131,10 +160,10 @@
</div>
<!-- The Grand Oak Villa Template -->
<div class="template-card template-asgar1 template-tall" data-template-id="asgar-1-template"
<div class="template-card template-grand-oak template-tall" data-template-id="grand-oak-villa-template"
onclick={handleTemplateSelect}>
<div class="template-content asgar1-preview">
<!-- Cover Page -->
<div class="template-content grand-oak-preview">
<!-- Static HTML Preview from preview-grand-oak.html -->
<div class="brochure-page cover-page">
<div class="cover-overlay"></div>
<header class="cover-header">
@ -142,8 +171,10 @@
<div class="property-status">FOR SALE</div>
</header>
<main class="cover-content">
<h1 class="cover-title" style="color: #C0A062 !important;">The Grand Oak Villa</h1>
<p class="cover-address"><i class="fa-solid fa-location-dot"></i> 123 Luxury Lane, Prestige City, PC 45678</p>
<h1 class="cover-title">The Grand Oak Villa</h1>
<p class="cover-address">
<i class="fa-solid fa-location-dot"></i> 123 Luxury Lane, Prestige City, PC 45678
</p>
</main>
<footer class="cover-footer">
<div class="feature-item">
@ -165,51 +196,72 @@
</footer>
</div>
<!-- Content Page -->
<div class="brochure-page">
<div class="content-body">
<header class="page-header">
<h1 class="title">Property <span>Overview</span></h1>
<span class="property-name" style="color: #C0A062 !important;">The Grand Oak Villa</span>
<span class="property-name">The Grand Oak Villa</span>
</header>
<main class="main-content details-grid">
<div>
<h2 class="section-title" style="color: white !important;">Description</h2>
<h2 class="section-title">Description</h2>
<div class="description">
<p style="color: white !important;">Nestled in the heart of Prestige City, The Grand Oak Villa is a masterpiece of modern architecture and timeless elegance.</p>
<p>Nestled in the heart of Prestige City, The Grand Oak Villa is a masterpiece of modern architecture and timeless elegance. This expansive 6,200 sq. ft. residence offers unparalleled luxury and privacy.</p>
</div>
</div>
<div class="specs-and-amenities">
<div>
<h2 class="section-title" style="color: white !important;">Specifications</h2>
<h2 class="section-title">Specifications</h2>
<div class="spec-list">
<div class="item"><span class="key" style="color: white !important;">Status:</span> <span class="value" style="color: white !important;">For Sale</span></div>
<div class="item"><span class="key" style="color: white !important;">Type:</span> <span class="value" style="color: white !important;">Villa</span></div>
<div class="item"><span class="key" style="color: white !important;">Year Built:</span> <span class="value" style="color: white !important;">2023</span></div>
<div class="item"><span class="key" style="color: white !important;">Parking:</span> <span class="value" style="color: white !important;">3-Car</span></div>
<div class="item">
<span class="key">Status:</span>
<span class="value">For Sale</span>
</div>
<div class="item">
<span class="key">Type:</span>
<span class="value">Villa</span>
</div>
<div class="item">
<span class="key">Year Built:</span>
<span class="value">2023</span>
</div>
<div class="item">
<span class="key">Parking:</span>
<span class="value">3-Car</span>
</div>
<div class="item">
<span class="key">Floor:</span>
<span class="value">2 Levels</span>
</div>
<div class="item">
<span class="key">Furnishing:</span>
<span class="value">Partially</span>
</div>
</div>
</div>
<div>
<h2 class="section-title" style="color: white !important;">Amenities</h2>
<h2 class="section-title">Amenities</h2>
<ul class="amenities-list">
<li style="color: white !important;"><i class="fa-solid fa-check"></i> Infinity Pool</li>
<li style="color: white !important;"><i class="fa-solid fa-check"></i> Home Theater</li>
<li style="color: white !important;"><i class="fa-solid fa-check"></i> Wine Cellar</li>
<li style="color: white !important;"><i class="fa-solid fa-check"></i> Smart Home</li>
<li><i class="fa-solid fa-check"></i> Infinity Pool</li>
<li><i class="fa-solid fa-check"></i> Home Theater</li>
<li><i class="fa-solid fa-check"></i> Wine Cellar</li>
<li><i class="fa-solid fa-check"></i> Smart Home</li>
<li><i class="fa-solid fa-check"></i> Spa & Sauna</li>
<li><i class="fa-solid fa-check"></i> Landscaped Gardens</li>
</ul>
</div>
</div>
</main>
</div>
<footer class="page-footer">
<div style="color: white !important;"><strong style="color: white !important;">Agent:</strong> Olivia Sterling | (555) 987-6543</div>
<div style="color: white !important;"><strong style="color: white !important;">Owner:</strong> John & Jane Doe</div>
<div><strong>Agent:</strong> Olivia Sterling | (555) 987-6543</div>
<div><strong>Owner:</strong> John & Jane Doe</div>
</footer>
</div>
</div>
<template if:true={isAsgar1TemplateSelected}>
<template if:true={isGrandOakVillaTemplateSelected}>
<div class="selected-indicator">
<span class="selected-icon"></span>
<span class="selected-text">Selected</span>
@ -217,11 +269,11 @@
</template>
</div>
<!-- The Serenity House Template -->
<!-- The Serenity House Template (4th Grid) -->
<div class="template-card template-sample template-medium" data-template-id="serenity-house-template"
onclick={handleTemplateSelect}>
<div class="template-content sample-preview">
<!-- Page 1: Cover -->
<div class="template-content serenity-preview">
<!-- Static HTML Preview from preview-serenity-house.html -->
<div class="brochure-page">
<div class="p1-container">
<div class="p1-image-side"></div>
@ -237,12 +289,17 @@
An architectural marvel of curated living space.
<br>
<strong>Offered at $4,500,000</strong>
<div class="contact-info">
<div class="contact-name">Sarah Johnson</div>
<div class="contact-phone">(555) 123-4567</div>
<div class="contact-title">Your Real Estate Professional</div>
<div class="contact-email">sarah@realestate.com</div>
</div>
</footer>
</div>
</div>
</div>
<!-- Page 2: Content -->
<div class="brochure-page">
<div class="page-layout">
<span class="page-number">02</span>
@ -268,15 +325,16 @@
</template>
</div>
<!-- The Vertice Template -->
<!-- The Vertice Template (5th Grid) -->
<div class="template-card template-luxury template-tall" data-template-id="luxury-mansion-template"
onclick={handleTemplateSelect}>
<div class="template-content luxury-preview">
<div class="template-content vertice-preview">
<!-- Static HTML Preview from preview-vertice.html -->
<div class="brochure-page cover-page">
<div class="cover-overlay"></div>
<div class="cover-content">
<div class="subtitle">An Urban Oasis</div>
<h1 class="main-title" style="color: white !important;">THE VERTICE</h1>
<h1 class="main-title">THE VERTICE</h1>
<div class="address">18 Skyline Avenue, Metropolis Centre, MC 90210</div>
</div>
<div class="cover-footer">
@ -300,7 +358,7 @@
<div class="vision-image"></div>
</main>
<footer class="page-footer-bar">
<span class="property-name" style="color: white !important;">THE VERTICE</span>
<span class="property-name">THE VERTICE</span>
<span>Page 02 / 06</span>
</footer>
</div>
@ -320,7 +378,7 @@
<div class="gallery-item g-item-5"><span>Private Balcony Views</span></div>
</main>
<footer class="page-footer-bar">
<span class="property-name" style="color: white !important;">THE VERTICE</span>
<span class="property-name">THE VERTICE</span>
<span>Page 03 / 06</span>
</footer>
</div>
@ -334,6 +392,8 @@
</div>
</template>
</div>
</div>
</div>
<!-- Step 1 Navigation -->
@ -369,7 +429,7 @@
<option value="">-- Select a Property --</option>
<template for:each={properties} for:item="property">
<option key={property.Id} value={property.Id}>
{property.Name} - {property.pcrm__Property_Type__c} -
{property.Name} - {property.pcrm__Title_English__c} - {property.pcrm__Property_Type__c} -
{property.pcrm__City_Bayut_Dubizzle__c}
</option>
</template>
@ -449,10 +509,6 @@
<span class="label">Status:</span>
<span class="value">{propertyData.status}</span>
</div>
<div class="property-field">
<span class="label">Reference Number:</span>
<span class="value">{propertyData.referenceNumber}</span>
</div>
</div>
</div>
@ -706,38 +762,15 @@
<!-- Image Review Section -->
<template if:true={selectedPropertyId}>
<div class="image-review-section">
<h3>Property Images by Category</h3>
<p>Review and select images for your brochure by category</p>
<h3>Property Image</h3>
<p>Review and select images for your brochure</p>
<!-- Category Navigation -->
<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">
Interior
</button>
<button class="category-btn-step2" onclick={selectCategory} data-category="Exterior">
Exterior
</button>
<button class="category-btn-step2" onclick={selectCategory} data-category="Kitchen">
Kitchen
</button>
<button class="category-btn-step2" onclick={selectCategory} data-category="Bedroom">
Bedroom
</button>
<button class="category-btn-step2" onclick={selectCategory} data-category="Living Area">
Living Area
</button>
<button class="category-btn-step2" onclick={selectCategory} data-category="Parking">
Parking
</button>
<button class="category-btn-step2" onclick={selectCategory} data-category="Anchor">
Anchor
</button>
<button class="category-btn-step2" onclick={selectCategory} data-category="Maps">
Maps
</button>
<!-- Offering Type Display -->
<div class="offering-type-display">
<div class="offering-type-badge">
<span class="offering-type-label">Offering Type:</span>
<span class="offering-type-value">{propertyData.offeringType}</span>
</div>
</div>
<!-- Image Display Area -->
@ -749,7 +782,7 @@
</template>
<template if:false={currentImage}>
<div class="no-image-message-step2">
<p>No images found for {selectedCategory}</p>
<p>No images found</p>
</div>
</template>
</div>
@ -784,7 +817,7 @@
<!-- Step 3: HTML Editor -->
<div class={step3Class} data-step="3">
<div class="step-inner-container">
<!-- Editor Container with Sidebar Layout -->
<div class="editor-container">
<!-- Left Sidebar: Toolbox -->
@ -1062,13 +1095,35 @@
</div>
</div>
<!-- Enhanced Content Editor -->
<!-- Viewport Toolbar - Removed for cleaner interface -->
<!-- PDF Viewport -->
<div class="pdf-viewport">
<div class="pdf-canvas" style={pdfCanvasStyle} data-page-size={selectedPageSize}>
<!-- Pages will be dynamically generated here -->
<template if:true={previewPages}>
<template for:each={previewPages} for:item="page" for:index="pageIndex">
<div key={page.id} class="preview-page" data-page-size={selectedPageSize} data-page-number={pageIndex}>
<div class="enhanced-editor-content" contenteditable="true" onkeyup={handleContentChange}
onpaste={handleContentChange} ondragover={handleEditorDragOver} ondrop={handleEditorDrop}>
{page.content}
</div>
</div>
</template>
</template>
<template if:false={previewPages}>
<div class="preview-page" data-page-size={selectedPageSize} data-page-number="1">
<div class="enhanced-editor-content" contenteditable="true" onkeyup={handleContentChange}
onpaste={handleContentChange} ondragover={handleEditorDragOver} ondrop={handleEditorDrop}>
<!-- Template content will be loaded here -->
{htmlContent}
</div>
</div>
</template>
</div>
</div>
</div>
</div>
</div>
</div>
@ -1108,7 +1163,7 @@
</template>
<template if:false={currentImage}>
<div class="no-image-message">
<p>No images found for {selectedCategory}</p>
<p>No images found</p>
</div>
</template>
</div>
@ -1178,9 +1233,16 @@
<!-- Local Upload Tab -->
<div if:true={showLocalUploadTab} class="local-upload-section">
<div class="upload-area">
<div class="upload-area"
ondragover={handleDragOver}
ondragleave={handleDragLeave}
ondrop={handleDrop}>
<input type="file" class="image-upload-input" accept="image/*" onchange={handleImageUpload} style="display: none;">
<div class="upload-dropzone" onclick={triggerFileUpload}>
<div class="upload-dropzone"
onclick={triggerImageReplacementFileUpload}
ondragover={handleDragOver}
ondragleave={handleDragLeave}
ondrop={handleDrop}>
<div class="upload-icon">📁</div>
<div class="upload-text">
<h4>Choose Image File</h4>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -88,7 +88,14 @@
}
.feature-item { border-right: 1px solid var(--color-border); }
.feature-item:last-child { border-right: none; }
.feature-item .value {
font-size: 1.2rem; font-weight: 600;
color: var(--color-white); margin-bottom: 4px;
}
.feature-item .label {
font-size: 0.7rem; color: var(--color-text-secondary);
text-transform: uppercase; letter-spacing: 0.5px;
}
.content-body {
background-color: var(--color-dark-charcoal); color: var(--color-text-primary);
@ -187,20 +194,20 @@
<div class="cover-overlay"></div>
<header class="cover-header"><div class="logo">Elysian</div><div class="property-status">FOR SALE</div></header>
<main class="cover-content">
<h1 class="cover-title" style="color: white;">Modern Villa</h1>
<p class="cover-address" style="color: white;"><i class="fa-solid fa-location-dot"></i> 123 Luxury Lane, Prestige City, PC 45678</p>
<h1 class="cover-title">The Grand Oak Villa</h1>
<p class="cover-address"><i class="fa-solid fa-location-dot"></i> 123 Luxury Lane, Prestige City, PC 45678</p>
</main>
<footer class="cover-footer">
<div class="feature-item"><div style="font-size: 1.2rem; font-weight: 600; color: white; margin-bottom: 4px;">4</div><div style="font-size: 0.7rem; color: #888888; text-transform: uppercase; letter-spacing: 0.5px;">Beds</div></div>
<div class="feature-item"><div style="font-size: 1.2rem; font-weight: 600; color: white; margin-bottom: 4px;">3</div><div style="font-size: 0.7rem; color: #888888; text-transform: uppercase; letter-spacing: 0.5px;">Baths</div></div>
<div class="feature-item"><div style="font-size: 1.2rem; font-weight: 600; color: white; margin-bottom: 4px;">6,200</div><div style="font-size: 0.7rem; color: #888888; text-transform: uppercase; letter-spacing: 0.5px;">Sq. Ft.</div></div>
<div class="feature-item"><div style="font-size: 1.2rem; font-weight: 600; color: white; margin-bottom: 4px;">$2,500,000</div><div style="font-size: 0.7rem; color: #888888; text-transform: uppercase; letter-spacing: 0.5px;">Price</div></div>
<div class="feature-item"><div class="value">5</div><div class="label">Bedrooms</div></div>
<div class="feature-item"><div class="value">6</div><div class="label">Bathrooms</div></div>
<div class="feature-item"><div class="value">6,200</div><div class="label">Sq. Ft.</div></div>
<div class="feature-item"><div class="value">$4.5M</div><div class="label">Price</div></div>
</footer>
</div>
<div class="brochure-page">
<div class="content-body">
<header class="page-header"><h1 class="title">Property <span>Overview</span></h1><span class="property-name" style="color: #C0A062;">The Grand Oak Villa</span></header>
<header class="page-header"><h1 class="title">Property <span>Overview</span></h1><span class="property-name">The Grand Oak Villa</span></header>
<main class="main-content details-grid">
<div>
<h2 class="section-title">Description</h2>

View File

@ -0,0 +1,401 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Prestige Real Estate Brochure - 4 Page</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;600;700&family=Playfair+Display:wght@700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
<style>
/* --- DESIGN SYSTEM & VARIABLES --- */
:root {
/* Color Palette */
--color-dark-charcoal: #121212;
--color-light-gray: #F5F5F5;
--color-text-primary: #D1D1D1;
--color-text-secondary: #888888;
--color-accent-gold: #C0A062;
--color-white: #FFFFFF;
--color-border: #2a2a2a;
/* Typography */
--font-primary: 'Montserrat', sans-serif;
--font-secondary: 'Playfair Display', serif;
/* Spacing */
--padding-page: 60px;
}
/* --- GLOBAL & BODY STYLES --- */
body {
font-family: var(--font-primary);
background-color: #e0e0e0;
display: flex;
flex-direction: column;
align-items: center;
padding: 50px;
margin: 0;
gap: 50px;
}
.brochure-page {
width: 210mm;
height: 297mm;
background-color: var(--color-white);
box-shadow: 0 15px 40px rgba(0, 0, 0, 0.2);
display: flex;
flex-direction: column;
overflow: hidden;
}
/* --- PAGE 1: FRONT COVER --- */
.cover-page {
position: relative;
background-image: url('https://images.unsplash.com/photo-1580587771525-78b9dba3b914?ixlib=rb-4.0.3&q=85&fm=jpg&crop=entropy&cs=srgb&w=1200');
background-size: cover;
background-position: center;
color: var(--color-white);
justify-content: space-between;
}
.cover-overlay {
position: absolute; top: 0; left: 0; width: 100%; height: 100%;
background: linear-gradient(180deg, rgba(18, 18, 18, 0.8) 0%, rgba(18, 18, 18, 0.3) 100%);
}
.cover-header {
position: relative; padding: var(--padding-page); display: flex;
justify-content: space-between; align-items: center;
}
.logo {
font-family: var(--font-secondary); font-size: 1.5rem; font-weight: 700;
letter-spacing: 2px; border: 2px solid var(--color-white); padding: 8px 15px;
}
.property-status {
background-color: var(--color-accent-gold); color: var(--color-dark-charcoal);
padding: 10px 20px; font-weight: 600; font-size: 0.9rem; text-transform: uppercase;
}
.cover-content { position: relative; padding: var(--padding-page); max-width: 65%; }
.cover-title {
font-family: var(--font-secondary); font-size: 4.5rem; font-weight: 700;
line-height: 1.1; margin: 0 0 10px 0; color: var(--color-white);
}
.cover-address {
font-size: 1.2rem; font-weight: 400; display: flex;
align-items: center; gap: 10px; color: var(--color-text-primary);
}
.cover-address i { color: var(--color-accent-gold); }
.cover-footer {
position: relative; background-color: rgba(18, 18, 18, 0.9);
padding: 30px var(--padding-page); display: grid; grid-template-columns: repeat(4, 1fr);
gap: 20px; text-align: center;
}
.feature-item { border-right: 1px solid var(--color-border); }
.feature-item:last-child { border-right: none; }
.feature-item .value {
font-size: 1.5rem; font-weight: 600;
color: var(--color-white); margin-bottom: 5px;
}
.feature-item .label {
font-size: 0.8rem; color: var(--color-text-secondary);
text-transform: uppercase; letter-spacing: 1px;
}
/* --- SHARED STYLES for Content Pages --- */
.content-body {
background-color: var(--color-dark-charcoal); color: var(--color-text-primary);
flex-grow: 1; padding: var(--padding-page); display: flex; flex-direction: column;
}
.page-header {
display: flex; justify-content: space-between; align-items: baseline;
padding-bottom: 20px; margin-bottom: 30px; border-bottom: 1px solid var(--color-border);
}
.page-header .title {
font-family: var(--font-secondary); font-size: 2.2rem; color: var(--color-white);
}
.page-header .title span { color: var(--color-accent-gold); }
.page-header .property-name {
font-size: 1rem; font-weight: 600; color: var(--color-text-secondary);
}
.section-title {
font-weight: 600; font-size: 1rem; color: var(--color-white);
margin: 0 0 25px 0; text-transform: uppercase; letter-spacing: 2px;
position: relative; padding-bottom: 10px;
}
.section-title::after {
content: ''; position: absolute; bottom: 0; left: 0;
width: 50px; height: 3px; background-color: var(--color-accent-gold);
}
.main-content { flex-grow: 1; }
.page-footer {
background-color: #0A0A0A;
padding: 20px var(--padding-page);
font-size: 0.9rem; color: var(--color-text-secondary);
border-top: 1px solid var(--color-border);
display: flex;
justify-content: space-between;
align-items: center;
}
.page-footer strong { color: var(--color-accent-gold); font-weight: 600; }
/* --- PAGE 2: DETAILS --- */
.details-grid {
display: flex;
flex-direction: column;
gap: 30px;
}
.description p {
font-size: 0.95rem;
line-height: 1.8;
margin: 0 0 15px 0;
color: var(--color-text-primary);
}
.specs-and-amenities {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 50px;
}
.spec-list .item {
display: flex;
justify-content: space-between;
font-size: 0.9rem;
padding: 12px 0;
border-bottom: 1px solid var(--color-border);
}
.spec-list .item:first-child { padding-top: 0; }
.spec-list .item .key { font-weight: 600; color: var(--color-text-secondary); }
.spec-list .item .value { font-weight: 400; color: var(--color-white); }
.amenities-list { list-style: none; padding: 0; margin: 0; columns: 2; gap: 15px; }
.amenities-list li { font-size: 0.9rem; margin-bottom: 15px; display: flex; align-items: center; }
.amenities-list i { color: var(--color-accent-gold); margin-right: 12px; font-size: 1.1rem; }
/* --- PAGE 3: LOCATION (NEW LAYOUT) --- */
.location-body { padding: 0; } /* Override default padding */
.location-map-container {
height: 45%;
background-image: url('https://images.unsplash.com/photo-1549880181-56a44cf4a9a5?ixlib=rb-4.0.3&q=85&fm=jpg&crop=entropy&cs=srgb&w=1200');
background-size: cover;
background-position: center 75%;
position: relative;
}
.location-map-container::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 70%;
background: linear-gradient(180deg, rgba(18, 18, 18, 0) 0%, var(--color-dark-charcoal) 90%);
}
.location-content { padding: var(--padding-page); }
.poi-grid {
display: grid; grid-template-columns: repeat(4, 1fr);
gap: 30px; margin-top: 40px;
}
.poi-item { text-align: center; }
.poi-item .icon {
font-size: 2.5rem; color: var(--color-accent-gold); margin-bottom: 15px;
}
.poi-item .title {
font-weight: 600; font-size: 1rem; color: var(--color-white); margin-bottom: 5px;
}
.poi-item .details { font-size: 0.9rem; color: var(--color-text-secondary); }
/* --- PAGE 4: LAYOUT & LIFESTYLE (REVISED) --- */
.page-split-layout {
display: grid;
grid-template-columns: 1.6fr 1fr;
gap: 50px;
height: 100%;
}
.gallery-section, .additional-info-section {
display: flex;
flex-direction: column;
}
.additional-info-section .spec-list {
margin-top: 25px;
}
.photo-grid {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
gap: 20px;
margin-top: 25px;
flex-grow: 1;
}
.photo-item {
border-radius: 8px;
overflow: hidden;
border: 1px solid var(--color-border);
background-size: cover;
background-position: center;
}
.photo-item-1 {
grid-column: 1 / -1; /* Span full width */
background-image: url('https://images.unsplash.com/photo-1600585154340-be6161a56a0c?ixlib=rb-4.0.3&q=85&fm=jpg&crop=entropy&cs=srgb&w=1200');
}
.photo-item-2 {
background-image: url('https://images.unsplash.com/photo-1600585152225-3579fe9d7ae2?ixlib=rb-4.0.3&q=85&fm=jpg&crop=entropy&cs=srgb&w=1200');
}
.photo-item-3 {
background-image: url('https://images.unsplash.com/photo-1600585153325-1a75f8a4f631?ixlib=rb-4.0.3&q=85&fm=jpg&crop=entropy&cs=srgb&w=1200');
}
</style>
</head>
<body>
<div class="brochure-page cover-page">
<div class="cover-overlay"></div>
<header class="cover-header"><div class="logo">Elysian</div><div class="property-status">FOR SALE</div></header>
<main class="cover-content">
<h1 class="cover-title">The Grand Oak Villa</h1>
<p class="cover-address"><i class="fa-solid fa-location-dot"></i> 123 Luxury Lane, Prestige City, PC 45678</p>
</main>
<footer class="cover-footer">
<div class="feature-item"><div class="value">5</div><div class="label">Bedrooms</div></div>
<div class="feature-item"><div class="value">6</div><div class="label">Bathrooms</div></div>
<div class="feature-item"><div class="value">6,200</div><div class="label">Sq. Ft.</div></div>
<div class="feature-item"><div class="value">$4,500,000</div><div class="label">Price</div></div>
</footer>
</div>
<div class="brochure-page">
<div class="content-body">
<header class="page-header"><h1 class="title">Property <span>Overview</span></h1><span class="property-name">The Grand Oak Villa</span></header>
<main class="main-content details-grid">
<div>
<h2 class="section-title">Description</h2>
<div class="description">
<p>Nestled in the heart of Prestige City, The Grand Oak Villa is a masterpiece of modern architecture and timeless elegance. This expansive 6,200 sq. ft. residence offers unparalleled luxury and privacy.</p>
<p>With soaring ceilings, bespoke finishes, and panoramic views from every room, this home is designed for those who appreciate the finer things in life. The open-plan living space is perfect for entertaining, featuring a gourmet chef's kitchen, a formal dining area, and a grand living room with a statement fireplace.</p>
</div>
</div>
<div class="specs-and-amenities">
<div>
<h2 class="section-title">Specifications</h2>
<div class="spec-list">
<div class="item"><span class="key">Reference ID:</span> <span class="value">[Reference ID]</span></div>
<div class="item"><span class="key">Status:</span> <span class="value">[Status]</span></div>
<div class="item"><span class="key">Type:</span> <span class="value">[Property Type]</span></div>
<div class="item"><span class="key">Year Built:</span> <span class="value">[Year Built]</span></div>
<div class="item"><span class="key">Floor:</span> <span class="value">[Floor]</span></div>
<div class="item"><span class="key">Parking:</span> <span class="value">[Parking]</span></div>
<div class="item"><span class="key">Furnishing:</span> <span class="value">[Furnishing]</span></div>
<div class="item"><span class="key">Maintenance Fee:</span> <span class="value">[Maintenance Fee]</span></div>
<div class="item"><span class="key">Service Charge:</span> <span class="value">[Service Charge]</span></div>
</div>
</div>
<div>
<h2 class="section-title">Amenities & Features</h2>
<ul class="amenities-list">
<li><i class="fa-solid fa-check"></i> Infinity Pool</li><li><i class="fa-solid fa-check"></i> Private Home Theater</li><li><i class="fa-solid fa-check"></i> Gourmet Chef's Kitchen</li><li><i class="fa-solid fa-check"></i> Wine Cellar</li><li><i class="fa-solid fa-check"></i> Smart Home Automation</li><li><i class="fa-solid fa-check"></i> Spa & Sauna Room</li><li><i class="fa-solid fa-check"></i> Landscaped Gardens</li><li><i class="fa-solid fa-check"></i> Outdoor Fire Pit</li>
</ul>
</div>
</div>
</main>
</div>
<footer class="page-footer">
<div><strong>Agent:</strong> [Agent Name] | [Agent Phone] | [Agent Email]</div>
<div><strong>Owner:</strong> [Owner Name] | [Owner Phone] | [Owner Email]</div>
</footer>
</div>
<div class="brochure-page">
<div class="content-body location-body">
<div class="location-map-container"></div>
<div class="location-content">
<header class="page-header" style="margin-bottom: 0;">
<h1 class="title">An Unrivaled <span>Setting</span></h1>
<span class="property-name">123 Luxury Lane, Prestige City</span>
</header>
<div class="poi-grid">
<div class="poi-item">
<div class="icon"><i class="fa-solid fa-school"></i></div>
<div class="title">Schools</div>
<div class="details">[Schools]</div>
</div>
<div class="poi-item">
<div class="icon"><i class="fa-solid fa-shopping-cart"></i></div>
<div class="title">Shopping</div>
<div class="details">[Shopping Centers]</div>
</div>
<div class="poi-item">
<div class="icon"><i class="fa-solid fa-plane"></i></div>
<div class="title">Airport</div>
<div class="details">[Airport Distance]</div>
</div>
<div class="poi-item">
<div class="icon"><i class="fa-solid fa-landmark"></i></div>
<div class="title">Landmarks</div>
<div class="details">[Nearby Landmarks]</div>
</div>
<div class="poi-item">
<div class="icon"><i class="fa-solid fa-bus"></i></div>
<div class="title">Transportation</div>
<div class="details">[Transportation]</div>
</div>
<div class="poi-item">
<div class="icon"><i class="fa-solid fa-hospital"></i></div>
<div class="title">Hospitals</div>
<div class="details">[Hospitals]</div>
</div>
<div class="poi-item">
<div class="icon"><i class="fa-solid fa-umbrella-beach"></i></div>
<div class="title">Beach</div>
<div class="details">[Beach Distance]</div>
</div>
<div class="poi-item">
<div class="icon"><i class="fa-solid fa-subway"></i></div>
<div class="title">Metro</div>
<div class="details">[Metro Distance]</div>
</div>
</div>
</div>
</div>
<footer class="page-footer">
<div><strong>Agent:</strong> [Agent Name] | [Agent Phone] | [Agent Email]</div>
<div><strong>Owner:</strong> [Owner Name] | [Owner Phone] | [Owner Email]</div>
</footer>
</div>
<div class="brochure-page">
<div class="content-body">
<header class="page-header">
<h1 class="title">Layout & <span>Lifestyle</span></h1>
<span class="property-name">The Grand Oak Villa</span>
</header>
<main class="main-content page-split-layout">
<section class="gallery-section">
<h2 class="section-title">A Glimpse Inside</h2>
<div class="photo-grid">
<div class="photo-item photo-item-1"></div>
<div class="photo-item photo-item-2"></div>
<div class="photo-item photo-item-3"></div>
</div>
</section>
<section class="additional-info-section">
<h2 class="section-title">Additional Information</h2>
<div class="spec-list">
<div class="item"><span class="key">Pet Friendly:</span> <span class="value">[Pet Friendly Status]</span></div>
<div class="item"><span class="key">Smoking:</span> <span class="value">[Smoking Allowed]</span></div>
<div class="item"><span class="key">Available From:</span> <span class="value">[Available From Date]</span></div>
<div class="item"><span class="key">Minimum Contract:</span> <span class="value">[Minimum Contract Duration]</span></div>
<div class="item"><span class="key">Security Deposit:</span> <span class="value">[Security Deposit]</span></div>
<div class="item"><span class="key">Utilities Included:</span> <span class="value">[Utilities Included]</span></div>
<div class="item"><span class="key">Internet Included:</span> <span class="value">[Internet Included]</span></div>
<div class="item"><span class="key">Cable Included:</span> <span class="value">[Cable Included]</span></div>
</div>
</section>
</main>
</div>
<footer class="page-footer">
<div><strong>Agent:</strong> [Agent Name] | [Agent Phone] | [Agent Email]</div>
<div><strong>Owner:</strong> [Owner Name] | [Owner Phone] | [Owner Email]</div>
</footer>
</div>
</body>
</html>

View File

@ -0,0 +1,426 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Editorial Real Estate Brochure - Updated</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Lato:wght@300;400;700&family=Cormorant+Garamond:wght@400;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
<style>
/* --- DESIGN SYSTEM & VARIABLES --- */
:root {
/* Color Palette */
--color-bg: #FFFFFF;
--color-off-white: #F8F7F5;
--color-text-primary: #333333;
--color-text-secondary: #777777;
--color-accent-beige: #D4C7B8;
--color-border: #EAEAEA;
/* Typography */
--font-serif: 'Cormorant Garamond', serif;
--font-sans: 'Lato', sans-serif;
}
/* --- GLOBAL & BODY STYLES --- */
body {
font-family: var(--font-sans);
background-color: #d8d8d8;
display: flex;
flex-direction: column;
align-items: center;
padding: 50px;
margin: 0;
gap: 50px;
}
.brochure-page {
width: 210mm;
height: 297mm;
background-color: var(--color-bg);
box-shadow: 0 15px 40px rgba(0, 0, 0, 0.15);
display: flex;
flex-direction: column;
overflow: hidden;
position: relative;
}
/* --- PAGE 1: FRONT COVER --- */
.p1-container {
display: flex;
height: 100%;
}
.p1-image-side {
flex: 1.2;
background-image: url('https://images.unsplash.com/photo-1600585154340-be6161a56a0c?ixlib=rb-4.0.3&q=85&fm=jpg&crop=entropy&cs=srgb&w=1200');
background-size: cover;
background-position: center;
}
.p1-content-side {
flex: 1;
padding: 70px 60px;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.p1-header .collection {
font-size: 0.9rem;
letter-spacing: 3px;
color: var(--color-text-secondary);
text-transform: uppercase;
}
.p1-main-title {
font-family: var(--font-serif);
font-size: 5rem;
font-weight: 600;
line-height: 1.1;
color: var(--color-text-primary);
margin: 20px 0;
}
.p1-address {
font-size: 1rem;
color: var(--color-text-secondary);
border-left: 3px solid var(--color-accent-beige);
padding-left: 20px;
}
.p1-ref-id {
font-size: 0.9rem;
color: var(--color-text-secondary);
margin-top: 15px;
padding-left: 23px;
}
.p1-footer {
font-size: 0.9rem;
color: var(--color-text-secondary);
}
.p1-footer strong {
color: var(--color-text-primary);
}
.p1-footer .area {
font-size: 1rem;
color: var(--color-text-primary);
font-weight: 700;
margin-bottom: 10px;
}
/* --- SHARED STYLES for Content Pages --- */
.page-layout {
padding: 70px;
display: flex;
flex-direction: column;
height: 100%;
box-sizing: border-box;
}
.page-number {
position: absolute;
top: 70px; right: 70px;
font-family: var(--font-serif);
font-size: 1.2rem;
color: var(--color-text-secondary);
}
.page-title-main {
font-family: var(--font-serif);
font-size: 3.5rem;
font-weight: 600;
color: var(--color-text-primary);
margin: 0 0 15px 0;
line-height: 1;
}
.page-title-sub {
font-size: 1rem;
color: var(--color-text-secondary);
margin-bottom: 50px;
}
.content-divider {
border: 0;
height: 1px;
background-color: var(--color-border);
margin: 30px 0;
}
.section-title {
font-family: var(--font-serif);
font-size: 1.5rem;
font-weight: 600;
color: var(--color-text-primary);
margin-bottom: 20px;
margin-top: 0;
}
/* --- PAGE 2: INTRODUCTION & NARRATIVE --- */
.p2-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 60px;
flex-grow: 1;
}
.p2-image {
background-image: url('https://images.unsplash.com/photo-1618221195710-dd6b41faaea6?ixlib=rb-4.0.3&q=85&fm=jpg&crop=entropy&cs=srgb&w=800');
background-size: cover;
background-position: center;
}
.p2-text p {
font-size: 1rem;
line-height: 1.8;
color: var(--color-text-secondary);
}
.p2-text p:first-of-type::first-letter {
font-family: var(--font-serif);
font-size: 4rem;
float: left;
line-height: 1;
margin-right: 15px;
color: var(--color-accent-beige);
}
.pull-quote {
border-left: 3px solid var(--color-accent-beige);
padding-left: 25px;
margin: 30px 0;
font-family: var(--font-serif);
font-size: 1.5rem;
font-style: italic;
color: var(--color-text-primary);
}
/* --- PAGE 3: DETAILS & AMENITIES --- */
.p3-main-content { flex-grow: 1; }
.spec-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 30px;
padding: 30px;
background-color: var(--color-off-white);
}
.spec-item { text-align: center; }
.spec-item .value {
font-size: 2rem;
font-weight: 700;
color: var(--color-text-primary);
}
.spec-item .label {
font-size: 0.8rem;
text-transform: uppercase;
letter-spacing: 1px;
color: var(--color-text-secondary);
}
.details-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 15px 40px;
}
.details-item {
display: flex;
justify-content: space-between;
border-bottom: 1px solid var(--color-border);
padding-bottom: 10px;
font-size: 0.9rem;
}
.details-item .label { color: var(--color-text-secondary); }
.details-item .value { color: var(--color-text-primary); font-weight: 700; }
.amenities-list { list-style: none; padding: 0; column-count: 2; column-gap: 40px;}
.amenities-list li {
margin-bottom: 12px;
color: var(--color-text-secondary);
display: flex;
align-items: center;
font-size: 0.9rem;
-webkit-column-break-inside: avoid;
page-break-inside: avoid;
break-inside: avoid;
}
.amenities-list li i { color: var(--color-accent-beige); margin-right: 12px; }
/* --- PAGE 4: REVISED LAYOUT --- */
.p4-section-title {
font-size: 1rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 2px;
color: var(--color-text-primary);
margin: 0 0 20px 0;
}
.p4-floorplan-container {
height: 320px;
background-color: var(--color-off-white);
border: 1px solid var(--color-border);
background-image: url('https://cdn.shopify.com/s/files/1/0024/0495/3953/files/Architect_s_floor_plan_for_a_house_in_black_and_white_large.jpg');
background-size: contain;
background-position: center;
background-repeat: no-repeat;
margin-bottom: 40px;
}
.p4-info-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 60px;
margin-bottom: 40px;
}
.info-list .info-item, .location-list .item {
display: flex;
justify-content: space-between;
padding: 10px 0;
border-bottom: 1px solid var(--color-border);
font-size: 0.9rem;
color: var(--color-text-secondary);
}
.info-list .info-item strong, .location-list .item strong {
color: var(--color-text-primary);
margin-right: 15px;
}
.p4-contact-row {
display: flex;
gap: 40px;
justify-content: center;
margin-top: auto;
}
.contact-card {
background-color: var(--color-off-white);
padding: 20px;
text-align: center;
flex: 1;
max-width: 300px;
}
.contact-card .title {
font-size: 0.8rem;
text-transform: uppercase;
letter-spacing: 1px;
color: var(--color-text-secondary);
margin-bottom: 8px;
}
.contact-card .name { font-family: var(--font-serif); font-size: 1.5rem; font-weight: 600; }
.contact-card .phone, .contact-card .email { font-size: 0.9rem; margin: 4px 0; color: var(--color-text-secondary); }
</style>
</head>
<body>
<div class="brochure-page">
<div class="p1-container">
<div class="p1-image-side"></div>
<div class="p1-content-side">
<header class="p1-header">
<div class="collection">Elysian Estates Collection</div>
<h1 class="p1-main-title">The Serenity House</h1>
<p class="p1-address">123 Luxury Lane, Prestige City, PC 45678</p>
<p class="p1-ref-id">Reference ID: ES-8821</p>
</header>
<footer class="p1-footer">
<div class="area">6,200 Sq. Ft. • 5 Bedrooms • 6 Bathrooms</div>
An architectural marvel of curated living space.
<br>
<strong>Offered at $4,500,000</strong>
</footer>
</div>
</div>
</div>
<div class="brochure-page">
<div class="page-layout">
<span class="page-number">02</span>
<h1 class="page-title-main">A Sanctuary of Modern Design</h1>
<p class="page-title-sub">Where light, space, and nature converge to create an unparalleled living experience.</p>
<div class="p2-grid">
<div class="p2-text">
<p>Designed by the world-renowned architect, Helena Vance, The Serenity House is more than a home; it is a living sculpture. Every line, material, and detail has been thoughtfully considered to evoke a sense of peace and connection with the surrounding landscape. Soaring ceilings and floor-to-ceiling glass walls dissolve the boundaries between inside and out, flooding the space with natural light.</p>
<p class="pull-quote">A timeless residence built not just for living, but for thriving.</p>
<p>The interior palette is a harmonious blend of natural oak, Italian travertine, and warm bronze accents, creating an atmosphere of understated luxury. This property represents a unique opportunity to own a piece of architectural history.</p>
</div>
<div class="p2-image"></div>
</div>
</div>
</div>
<div class="brochure-page">
<div class="page-layout">
<span class="page-number">03</span>
<h1 class="page-title-main">Property Specifications</h1>
<p class="page-title-sub">A comprehensive overview of the propertys features, details, and amenities.</p>
<div class="p3-main-content">
<div class="spec-grid">
<div class="spec-item"><div class="value">5</div><div class="label">Bedrooms</div></div>
<div class="spec-item"><div class="value">6</div><div class="label">Bathrooms</div></div>
<div class="spec-item"><div class="value">6,200</div><div class="label">Square Feet</div></div>
<div class="spec-item"><div class="value">0.75</div><div class="label">Acres</div></div>
</div>
<hr class="content-divider">
<h3 class="section-title">Property Details</h3>
<div class="details-grid">
<div class="details-item"><span class="label">Status</span><span class="value">For Sale</span></div>
<div class="details-item"><span class="label">Year Built</span><span class="value">2023</span></div>
<div class="details-item"><span class="label">Type</span><span class="value">Single-Family Home</span></div>
<div class="details-item"><span class="label">Furnishing</span><span class="value">Partially Furnished</span></div>
<div class="details-item"><span class="label">Floor</span><span class="value">2 Levels</span></div>
<div class="details-item"><span class="label">Maintenance Fee</span><span class="value">$1,200 / month</span></div>
<div class="details-item"><span class="label">Parking</span><span class="value">3-Car Garage</span></div>
<div class="details-item"><span class="label">Service Charge</span><span class="value">Included</span></div>
</div>
<hr class="content-divider">
<h3 class="section-title">Amenities & Features</h3>
<ul class="amenities-list">
<li><i class="fa-solid fa-check"></i> Primary Suite with Spa-Bath</li>
<li><i class="fa-solid fa-check"></i> Radiant Heated Flooring</li>
<li><i class="fa-solid fa-check"></i> Custom Walk-in Closets</li>
<li><i class="fa-solid fa-check"></i> Smart Home Automation</li>
<li><i class="fa-solid fa-check"></i> Infinity Edge Saline Pool</li>
<li><i class="fa-solid fa-check"></i> Private Cinema Room</li>
<li><i class="fa-solid fa-check"></i> Temperature-Controlled Wine Cellar</li>
<li><i class="fa-solid fa-check"></i> Landscaped Gardens & Terrace</li>
<li><i class="fa-solid fa-check"></i> Gourmet Chef's Kitchen</li>
<li><i class="fa-solid fa-check"></i> Floor-to-Ceiling Glass Walls</li>
</ul>
</div>
</div>
</div>
<div class="brochure-page">
<div class="page-layout">
<span class="page-number">04</span>
<h1 class="page-title-main" style="margin-bottom: 30px;">Floor Plan & Details</h1>
<div class="p4-info-grid">
<div class="location-list">
<h2 class="p4-section-title">Location & Nearby</h2>
<div class="item"><strong>Schools</strong> <span>5 min drive</span></div>
<div class="item"><strong>Shopping</strong> <span>10 min drive</span></div>
<div class="item"><strong>Hospitals</strong> <span>12 min drive</span></div>
<div class="item"><strong>Country Club</strong> <span>8 min drive</span></div>
<div class="item"><strong>Airport</strong> <span>20 min drive</span></div>
</div>
<div class="info-list">
<h2 class="p4-section-title">Additional Information</h2>
<div class="info-item"><strong>Pet-Friendly</strong> <span>By Approval</span></div>
<div class="info-item"><strong>Smoking</strong> <span>Not Permitted</span></div>
<div class="info-item"><strong>Availability</strong> <span>Immediate</span></div>
<div class="info-item"><strong>Utilities</strong> <span>Not Included</span></div>
</div>
</div>
<hr class="content-divider">
<h2 class="p4-section-title">Floor Plan & Location</h2>
<div class="p4-floorplan-container"></div>
<div class="p4-contact-row">
<div class="contact-card">
<div class="title">Owner Information</div>
<div class="name">John & Jane Doe</div>
<p class="phone">(555) 111-2222</p>
<p class="email">owner.serenity@email.com</p>
</div>
<div class="contact-card">
<div class="title">Agent Information</div>
<div class="name">Olivia Sterling</div>
<p class="phone">(555) 987-6543</p>
<p class="email">olivia@elysianestates.com</p>
</div>
</div>
</div>
</div>
</body>
</html>