Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Zivvy Checkout Page Builder</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://unpkg.com/alpinejs@3.14.9/dist/cdn.min.js" defer></script> | |
| <style> | |
| @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap'); | |
| :root { | |
| --zivvy-primary: #256EFF; | |
| --zivvy-success: #10B981; | |
| --zivvy-warning: #F59E0B; | |
| --zivvy-error: #EF4444; | |
| --zivvy-dark: #0A0E27; | |
| --zivvy-background: #F5F7FA; | |
| --zivvy-white: #FFFFFF; | |
| } | |
| body { | |
| font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; | |
| background: var(--zivvy-background); | |
| color: var(--zivvy-dark); | |
| line-height: 1.6; | |
| } | |
| .builder-container { | |
| display: grid; | |
| grid-template-columns: 420px 1fr; | |
| height: 100vh; | |
| } | |
| /* BUILDER SIDEBAR */ | |
| .builder-sidebar { | |
| background: var(--zivvy-white); | |
| border-right: 1px solid #e2e8f0; | |
| overflow-y: auto; | |
| padding: 24px; | |
| } | |
| .builder-header { | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| margin-bottom: 32px; | |
| padding-bottom: 20px; | |
| border-bottom: 2px solid var(--zivvy-background); | |
| } | |
| .builder-logo { | |
| width: 48px; | |
| height: 48px; | |
| background: var(--zivvy-primary); | |
| border-radius: 12px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| color: var(--zivvy-white); | |
| font-weight: 700; | |
| font-size: 20px; | |
| } | |
| .builder-info h1 { | |
| font-size: 20px; | |
| font-weight: 700; | |
| color: var(--zivvy-dark); | |
| margin-bottom: 2px; | |
| } | |
| .builder-subtitle { | |
| font-size: 13px; | |
| color: #64748b; | |
| font-weight: 500; | |
| } | |
| .config-section { | |
| margin-bottom: 28px; | |
| padding: 20px; | |
| background: var(--zivvy-background); | |
| border-radius: 12px; | |
| border: 1px solid #e2e8f0; | |
| } | |
| .config-section h3 { | |
| font-size: 14px; | |
| font-weight: 600; | |
| color: var(--zivvy-dark); | |
| margin-bottom: 16px; | |
| text-transform: uppercase; | |
| letter-spacing: 0.5px; | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| } | |
| .config-field { | |
| margin-bottom: 16px; | |
| } | |
| .config-label { | |
| display: block; | |
| font-size: 13px; | |
| font-weight: 500; | |
| color: #475569; | |
| margin-bottom: 6px; | |
| } | |
| .config-input, .config-textarea, .config-select { | |
| width: 100%; | |
| padding: 10px 12px; | |
| border: 1px solid #d1d5db; | |
| border-radius: 6px; | |
| font-size: 14px; | |
| background: var(--zivvy-white); | |
| transition: all 0.2s; | |
| } | |
| .config-input:focus, .config-textarea:focus, .config-select:focus { | |
| outline: none; | |
| border-color: var(--zivvy-primary); | |
| box-shadow: 0 0 0 3px rgba(37, 110, 255, 0.1); | |
| } | |
| .config-textarea { | |
| resize: vertical; | |
| min-height: 80px; | |
| } | |
| .config-toggle { | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| padding: 12px; | |
| background: var(--zivvy-white); | |
| border-radius: 8px; | |
| border: 1px solid #e2e8f0; | |
| margin-bottom: 12px; | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| } | |
| .config-toggle:hover { | |
| border-color: var(--zivvy-primary); | |
| } | |
| .toggle-label { | |
| font-size: 14px; | |
| font-weight: 500; | |
| color: var(--zivvy-dark); | |
| } | |
| .toggle-switch { | |
| position: relative; | |
| width: 44px; | |
| height: 24px; | |
| background: #d1d5db; | |
| border-radius: 12px; | |
| cursor: pointer; | |
| transition: background 0.2s; | |
| } | |
| .toggle-switch.active { | |
| background: var(--zivvy-primary); | |
| } | |
| .toggle-switch:after { | |
| content: ''; | |
| position: absolute; | |
| top: 2px; | |
| left: 2px; | |
| width: 20px; | |
| height: 20px; | |
| background: var(--zivvy-white); | |
| border-radius: 50%; | |
| transition: transform 0.2s; | |
| box-shadow: 0 1px 3px rgba(0,0,0,0.1); | |
| } | |
| .toggle-switch.active:after { | |
| transform: translateX(20px); | |
| } | |
| /* TAG-STYLE ATTRIBUTE INTERFACE */ | |
| .attribute-list { | |
| margin-bottom: 12px; | |
| } | |
| .attribute-editor { | |
| border: 1px solid #e2e8f0; | |
| border-radius: 8px; | |
| background: var(--zivvy-white); | |
| margin-bottom: 12px; | |
| overflow: hidden; | |
| } | |
| .attribute-header { | |
| display: flex; | |
| gap: 8px; | |
| padding: 12px; | |
| border-bottom: 1px solid #f1f5f9; | |
| align-items: center; | |
| } | |
| .attribute-name-input { | |
| flex: 1; | |
| padding: 8px 10px; | |
| border: 1px solid #d1d5db; | |
| border-radius: 4px; | |
| font-size: 13px; | |
| font-weight: 500; | |
| } | |
| .attribute-options { | |
| padding: 12px; | |
| } | |
| .option-tags { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 6px; | |
| margin-bottom: 8px; | |
| min-height: 20px; | |
| } | |
| .option-tag { | |
| display: flex; | |
| align-items: center; | |
| gap: 4px; | |
| background: var(--zivvy-primary); | |
| color: var(--zivvy-white); | |
| padding: 4px 8px; | |
| border-radius: 12px; | |
| font-size: 12px; | |
| font-weight: 500; | |
| } | |
| .tag-remove { | |
| background: transparent; | |
| border: none; | |
| color: var(--zivvy-white); | |
| cursor: pointer; | |
| font-size: 10px; | |
| font-weight: bold; | |
| width: 14px; | |
| height: 14px; | |
| border-radius: 50%; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| opacity: 0.8; | |
| transition: opacity 0.2s; | |
| } | |
| .tag-remove:hover { | |
| opacity: 1; | |
| background: rgba(255,255,255,0.2); | |
| } | |
| .add-option { | |
| display: flex; | |
| gap: 6px; | |
| align-items: center; | |
| } | |
| .option-input { | |
| flex: 1; | |
| padding: 6px 8px; | |
| border: 1px solid #d1d5db; | |
| border-radius: 4px; | |
| font-size: 12px; | |
| } | |
| .option-input:focus { | |
| outline: none; | |
| border-color: var(--zivvy-primary); | |
| box-shadow: 0 0 0 2px rgba(37, 110, 255, 0.1); | |
| } | |
| .option-add-btn { | |
| background: var(--zivvy-success); | |
| color: var(--zivvy-white); | |
| border: none; | |
| width: 24px; | |
| height: 24px; | |
| border-radius: 4px; | |
| cursor: pointer; | |
| font-size: 12px; | |
| font-weight: bold; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| .remove-btn { | |
| background: var(--zivvy-error); | |
| color: var(--zivvy-white); | |
| border: none; | |
| width: 24px; | |
| height: 24px; | |
| border-radius: 4px; | |
| cursor: pointer; | |
| font-size: 12px; | |
| font-weight: bold; | |
| } | |
| .add-btn { | |
| background: var(--zivvy-success); | |
| color: var(--zivvy-white); | |
| border: none; | |
| padding: 8px 16px; | |
| border-radius: 6px; | |
| cursor: pointer; | |
| font-size: 13px; | |
| font-weight: 500; | |
| width: 100%; | |
| } | |
| .upload-area { | |
| border: 2px dashed #cbd5e1; | |
| border-radius: 8px; | |
| padding: 20px; | |
| text-align: center; | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| background: var(--zivvy-white); | |
| } | |
| .upload-area:hover { | |
| border-color: var(--zivvy-primary); | |
| background: #f0f4ff; | |
| } | |
| .upload-icon { | |
| font-size: 24px; | |
| margin-bottom: 8px; | |
| opacity: 0.6; | |
| } | |
| .upload-text { | |
| font-size: 13px; | |
| color: #64748b; | |
| font-weight: 500; | |
| } | |
| /* BENEFIT STYLES - TWO FIELD STRUCTURE */ | |
| .benefit-list { | |
| margin-bottom: 12px; | |
| } | |
| .benefit-editor { | |
| border: 1px solid #e2e8f0; | |
| border-radius: 8px; | |
| background: var(--zivvy-white); | |
| margin-bottom: 12px; | |
| overflow: hidden; | |
| } | |
| .benefit-preview { | |
| display: flex; | |
| align-items: flex-start; | |
| gap: 8px; | |
| padding: 12px; | |
| border-bottom: 1px solid #f1f5f9; | |
| position: relative; | |
| } | |
| .benefit-bullet { | |
| color: var(--zivvy-primary); | |
| font-weight: bold; | |
| font-size: 14px; | |
| width: 20px; | |
| flex-shrink: 0; | |
| margin-top: 2px; | |
| } | |
| .benefit-content { | |
| flex: 1; | |
| font-size: 13px; | |
| line-height: 1.4; | |
| } | |
| .benefit-title { | |
| font-weight: 600; | |
| color: var(--zivvy-dark); | |
| display: block; | |
| } | |
| .benefit-description { | |
| font-weight: 400; | |
| color: var(--zivvy-dark); | |
| margin-top: 2px; | |
| display: block; | |
| } | |
| .benefit-remove { | |
| background: var(--zivvy-error); | |
| color: var(--zivvy-white); | |
| border: none; | |
| width: 20px; | |
| height: 20px; | |
| border-radius: 50%; | |
| cursor: pointer; | |
| font-size: 10px; | |
| font-weight: bold; | |
| flex-shrink: 0; | |
| } | |
| .benefit-inputs { | |
| padding: 12px; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 8px; | |
| } | |
| .benefit-title-input { | |
| width: 100%; | |
| padding: 8px 10px; | |
| border: 1px solid #d1d5db; | |
| border-radius: 4px; | |
| font-size: 13px; | |
| font-weight: 500; | |
| background: var(--zivvy-white); | |
| } | |
| .benefit-description-input { | |
| width: 100%; | |
| padding: 8px 10px; | |
| border: 1px solid #d1d5db; | |
| border-radius: 4px; | |
| font-size: 13px; | |
| resize: vertical; | |
| background: var(--zivvy-white); | |
| min-height: 60px; | |
| } | |
| .benefit-title-input:focus, .benefit-description-input:focus { | |
| outline: none; | |
| border-color: var(--zivvy-primary); | |
| box-shadow: 0 0 0 2px rgba(37, 110, 255, 0.1); | |
| } | |
| /* BULLET STYLE GRID */ | |
| .bullet-style-grid { | |
| display: grid; | |
| grid-template-columns: repeat(4, 1fr); | |
| gap: 8px; | |
| margin-bottom: 12px; | |
| } | |
| .bullet-style { | |
| padding: 12px 8px; | |
| border: 1px solid #d1d5db; | |
| border-radius: 6px; | |
| cursor: pointer; | |
| text-align: center; | |
| font-size: 16px; | |
| transition: all 0.2s; | |
| background: var(--zivvy-white); | |
| } | |
| .bullet-style.selected { | |
| border-color: var(--zivvy-primary); | |
| background: #f0f4ff; | |
| color: var(--zivvy-primary); | |
| } | |
| /* REDESIGNED TRUST BADGE STYLES */ | |
| .trust-badge-list { | |
| margin-bottom: 16px; | |
| } | |
| .trust-badge-editor { | |
| margin-bottom: 20px; | |
| border: 1px solid #e2e8f0; | |
| border-radius: 12px; | |
| background: var(--zivvy-white); | |
| overflow: hidden; | |
| box-shadow: 0 2px 4px rgba(0,0,0,0.04); | |
| } | |
| .trust-badge-preview { | |
| padding: 20px; | |
| display: flex; | |
| align-items: center; | |
| gap: 16px; | |
| border-bottom: 1px solid #f1f5f9; | |
| position: relative; | |
| background: #f8fafc; | |
| } | |
| .trust-badge-icon-large { | |
| font-size: 32px; | |
| width: 60px; | |
| height: 60px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| background: var(--zivvy-white); | |
| border-radius: 12px; | |
| flex-shrink: 0; | |
| box-shadow: 0 2px 8px rgba(0,0,0,0.08); | |
| border: 2px solid #e2e8f0; | |
| } | |
| .trust-badge-content-large { | |
| flex: 1; | |
| } | |
| .trust-badge-title-large { | |
| font-size: 16px; | |
| font-weight: 600; | |
| color: var(--zivvy-dark); | |
| margin-bottom: 4px; | |
| } | |
| .trust-badge-subtitle-large { | |
| font-size: 14px; | |
| color: #64748b; | |
| } | |
| .trust-badge-remove { | |
| position: absolute; | |
| top: 12px; | |
| right: 12px; | |
| background: var(--zivvy-error); | |
| color: var(--zivvy-white); | |
| border: none; | |
| width: 28px; | |
| height: 28px; | |
| border-radius: 50%; | |
| cursor: pointer; | |
| font-size: 14px; | |
| font-weight: bold; | |
| opacity: 0.8; | |
| transition: all 0.2s; | |
| box-shadow: 0 2px 4px rgba(239, 68, 68, 0.3); | |
| } | |
| .trust-badge-remove:hover { | |
| opacity: 1; | |
| transform: scale(1.05); | |
| } | |
| /* COLOR PICKER */ | |
| .color-section { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 16px; | |
| } | |
| .color-picker { | |
| display: grid; | |
| grid-template-columns: repeat(3, 1fr); | |
| gap: 8px; | |
| margin-bottom: 12px; | |
| } | |
| .color-option { | |
| width: 36px; | |
| height: 36px; | |
| border-radius: 8px; | |
| cursor: pointer; | |
| border: 2px solid transparent; | |
| transition: all 0.2s; | |
| position: relative; | |
| } | |
| .color-option.selected { | |
| border-color: var(--zivvy-dark); | |
| transform: scale(1.1); | |
| } | |
| .color-option.selected:after { | |
| content: '✓'; | |
| position: absolute; | |
| top: 50%; | |
| left: 50%; | |
| transform: translate(-50%, -50%); | |
| color: var(--zivvy-white); | |
| font-weight: bold; | |
| font-size: 12px; | |
| text-shadow: 0 1px 2px rgba(0,0,0,0.5); | |
| } | |
| /* FORM FIELD STYLES */ | |
| .form-field-list { | |
| margin-bottom: 12px; | |
| } | |
| .form-field-editor { | |
| border: 1px solid #e2e8f0; | |
| border-radius: 8px; | |
| background: var(--zivvy-white); | |
| margin-bottom: 8px; | |
| overflow: hidden; | |
| } | |
| .form-field-header { | |
| display: flex; | |
| gap: 8px; | |
| padding: 12px; | |
| align-items: center; | |
| } | |
| .field-label-input { | |
| flex: 1; | |
| padding: 6px 8px; | |
| border: 1px solid #d1d5db; | |
| border-radius: 4px; | |
| font-size: 13px; | |
| } | |
| .field-type-select { | |
| padding: 6px 8px; | |
| border: 1px solid #d1d5db; | |
| border-radius: 4px; | |
| font-size: 12px; | |
| background: var(--zivvy-white); | |
| } | |
| /* PREVIEW AREA */ | |
| .preview-area { | |
| background: #f8fafc; | |
| overflow-y: auto; | |
| padding: 20px; | |
| } | |
| .preview-header { | |
| background: var(--zivvy-white); | |
| padding: 16px 24px; | |
| border-bottom: 1px solid #e2e8f0; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 24px; | |
| border-radius: 8px; | |
| box-shadow: 0 1px 3px rgba(0,0,0,0.05); | |
| } | |
| .preview-title { | |
| font-size: 16px; | |
| font-weight: 600; | |
| color: var(--zivvy-dark); | |
| } | |
| .preview-actions { | |
| display: flex; | |
| gap: 12px; | |
| } | |
| .preview-btn { | |
| padding: 8px 16px; | |
| border: 1px solid #d1d5db; | |
| background: var(--zivvy-white); | |
| border-radius: 6px; | |
| cursor: pointer; | |
| font-size: 13px; | |
| font-weight: 500; | |
| transition: all 0.2s; | |
| } | |
| .preview-btn:hover { | |
| border-color: var(--zivvy-primary); | |
| color: var(--zivvy-primary); | |
| } | |
| .preview-frame { | |
| background: var(--zivvy-white); | |
| border-radius: 12px; | |
| box-shadow: 0 4px 12px rgba(0,0,0,0.1); | |
| overflow: hidden; | |
| transform-origin: top left; | |
| } | |
| .save-button { | |
| width: 100%; | |
| background: linear-gradient(135deg, var(--zivvy-primary), #1d4ed8); | |
| color: var(--zivvy-white); | |
| border: none; | |
| padding: 16px; | |
| border-radius: 8px; | |
| font-weight: 600; | |
| font-size: 16px; | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| margin-top: 20px; | |
| } | |
| .save-button:hover { | |
| transform: translateY(-1px); | |
| box-shadow: 0 4px 12px rgba(37, 110, 255, 0.3); | |
| } | |
| .fade-in-progressive { | |
| animation: fadeInUp 0.5s ease-out; | |
| } | |
| @keyframes fadeInUp { | |
| from { | |
| opacity: 0; | |
| transform: translateY(20px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| } | |
| /* Responsive */ | |
| @media (max-width: 1200px) { | |
| .builder-container { | |
| grid-template-columns: 380px 1fr; | |
| } | |
| } | |
| @media (max-width: 768px) { | |
| .builder-container { | |
| grid-template-columns: 1fr; | |
| grid-template-rows: auto 1fr; | |
| } | |
| .builder-sidebar { | |
| max-height: 50vh; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div x-data="pageBuilder()" class="builder-container"> | |
| <!-- Builder Sidebar --> | |
| <div class="builder-sidebar"> | |
| <div class="builder-header"> | |
| <div class="builder-logo">Z</div> | |
| <div class="builder-info"> | |
| <h1>Page Builder</h1> | |
| <div class="builder-subtitle">Checkout Template Editor</div> | |
| </div> | |
| </div> | |
| <!-- Business Information --> | |
| <div class="config-section"> | |
| <h3>🏢 Business Information</h3> | |
| <div class="config-field"> | |
| <label class="config-label">Business Name</label> | |
| <input type="text" class="config-input" x-model="config.businessName" placeholder="Your Business Name"> | |
| </div> | |
| <div class="config-field"> | |
| <label class="config-label">Business Tagline</label> | |
| <input type="text" class="config-input" x-model="config.businessTagline" placeholder="Your tagline"> | |
| </div> | |
| <div class="config-field"> | |
| <label class="config-label">Logo Upload</label> | |
| <div class="upload-area" @click="uploadLogo()"> | |
| <div class="upload-icon">📷</div> | |
| <div class="upload-text">Click to upload logo</div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Product Settings --> | |
| <div class="config-section"> | |
| <h3>🛍️ Product Information</h3> | |
| <div class="config-field"> | |
| <label class="config-label">Product Name</label> | |
| <input type="text" class="config-input" x-model="config.productName" placeholder="Your Product Name"> | |
| </div> | |
| <div class="config-field"> | |
| <label class="config-label">Product Image</label> | |
| <div class="upload-area" @click="uploadProductImage()"> | |
| <div class="upload-icon">🖼️</div> | |
| <div class="upload-text">Click to upload product image</div> | |
| </div> | |
| </div> | |
| <div class="config-field"> | |
| <label class="config-label">Product Description</label> | |
| <textarea class="config-textarea" x-model="config.productDescription" placeholder="Brief product description"></textarea> | |
| </div> | |
| <!-- Product Attributes with Tag Interface --> | |
| <div class="config-field"> | |
| <label class="config-label">Product Attributes (No Commas!)</label> | |
| <div class="attribute-list"> | |
| <template x-for="(attr, index) in config.attributes" :key="index"> | |
| <div class="attribute-editor"> | |
| <div class="attribute-header"> | |
| <input type="text" x-model="attr.name" placeholder="Attribute name (e.g., Size, Color)" class="attribute-name-input"> | |
| <button class="remove-btn" @click="removeAttribute(index)">×</button> | |
| </div> | |
| <div class="attribute-options"> | |
| <div class="option-tags"> | |
| <template x-for="(option, optIndex) in attr.options" :key="optIndex"> | |
| <div class="option-tag"> | |
| <span x-text="option"></span> | |
| <button class="tag-remove" @click="removeAttributeOption(index, optIndex)">×</button> | |
| </div> | |
| </template> | |
| </div> | |
| <div class="add-option"> | |
| <input type="text" :id="'attr-option-' + index" placeholder="Type option and press Enter" class="option-input" @keyup.enter="addAttributeOption(index, $event.target.value); $event.target.value = ''"> | |
| <button class="option-add-btn" @click="addAttributeOption(index, document.getElementById('attr-option-' + index).value); document.getElementById('attr-option-' + index).value = ''">+</button> | |
| </div> | |
| </div> | |
| </div> | |
| </template> | |
| </div> | |
| <button class="add-btn" @click="addAttribute()">+ Add Attribute</button> | |
| </div> | |
| <!-- Product Benefits - TWO FIELD STRUCTURE --> | |
| <div class="config-field"> | |
| <label class="config-label">Product Benefits</label> | |
| <div class="benefit-list"> | |
| <template x-for="(benefit, index) in config.benefits" :key="index"> | |
| <div class="benefit-editor"> | |
| <div class="benefit-preview"> | |
| <span class="benefit-bullet" x-text="config.bulletStyle"></span> | |
| <div class="benefit-content"> | |
| <span class="benefit-title" x-text="benefit.title || 'Benefit Title'"></span> | |
| <span class="benefit-description" x-text="benefit.description || ''"></span> | |
| </div> | |
| <button class="benefit-remove" @click="removeBenefit(index)">×</button> | |
| </div> | |
| <div class="benefit-inputs"> | |
| <input type="text" x-model="benefit.title" placeholder="Benefit title (will be bold)" class="benefit-title-input"> | |
| <textarea x-model="benefit.description" placeholder="Benefit description (regular text)" class="benefit-description-input"></textarea> | |
| </div> | |
| </div> | |
| </template> | |
| </div> | |
| <button class="add-btn" @click="addBenefit()">+ Add Benefit</button> | |
| </div> | |
| <!-- Bullet Style Selection --> | |
| <div class="config-field"> | |
| <label class="config-label">Bullet Style</label> | |
| <div class="bullet-style-grid"> | |
| <div class="bullet-style" :class="config.bulletStyle === '✓' ? 'selected' : ''" @click="config.bulletStyle = '✓'">✓</div> | |
| <div class="bullet-style" :class="config.bulletStyle === '•' ? 'selected' : ''" @click="config.bulletStyle = '•'">•</div> | |
| <div class="bullet-style" :class="config.bulletStyle === '★' ? 'selected' : ''" @click="config.bulletStyle = '★'">★</div> | |
| <div class="bullet-style" :class="config.bulletStyle === '→' ? 'selected' : ''" @click="config.bulletStyle = '→'">→</div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Pricing Settings --> | |
| <div class="config-section"> | |
| <h3>💰 Pricing & Quantity</h3> | |
| <div class="config-field"> | |
| <label class="config-label">Pricing Type</label> | |
| <select class="config-select" x-model="config.pricingType"> | |
| <option value="simple">Simple Price</option> | |
| <option value="discount">Regular Price / Sale Price</option> | |
| </select> | |
| </div> | |
| <!-- Simple Price Mode --> | |
| <div x-show="config.pricingType === 'simple'" class="fade-in-progressive"> | |
| <div class="config-field"> | |
| <label class="config-label">Price</label> | |
| <input type="number" class="config-input" x-model="config.price" placeholder="297"> | |
| </div> | |
| </div> | |
| <!-- Discount Price Mode --> | |
| <div x-show="config.pricingType === 'discount'" class="fade-in-progressive"> | |
| <div class="config-field"> | |
| <label class="config-label">Regular Price</label> | |
| <input type="number" class="config-input" x-model="config.regularPrice" placeholder="400"> | |
| </div> | |
| <div class="config-field"> | |
| <label class="config-label">Sale Price</label> | |
| <input type="number" class="config-input" x-model="config.salePrice" placeholder="297"> | |
| </div> | |
| </div> | |
| <div class="config-toggle" @click="config.enableQuantity = !config.enableQuantity"> | |
| <span class="toggle-label">Enable Quantity Selection</span> | |
| <div class="toggle-switch" :class="config.enableQuantity ? 'active' : ''"></div> | |
| </div> | |
| </div> | |
| <!-- Ratings & Social Proof --> | |
| <div class="config-section"> | |
| <h3>⭐ Ratings & Reviews</h3> | |
| <div class="config-toggle" @click="config.showRatings = !config.showRatings"> | |
| <span class="toggle-label">Show Ratings</span> | |
| <div class="toggle-switch" :class="config.showRatings ? 'active' : ''"></div> | |
| </div> | |
| <div x-show="config.showRatings" class="fade-in-progressive"> | |
| <div class="config-field"> | |
| <label class="config-label">Rating Score</label> | |
| <input type="number" class="config-input" x-model="config.ratingScore" min="1" max="5" step="0.1" placeholder="4.9"> | |
| </div> | |
| <div class="config-field"> | |
| <label class="config-label">Review Count</label> | |
| <input type="number" class="config-input" x-model="config.reviewCount" placeholder="1247"> | |
| </div> | |
| <div class="config-field"> | |
| <label class="config-label">Rating Text</label> | |
| <input type="text" class="config-input" x-model="config.ratingText" placeholder="member reviews"> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Trust Elements --> | |
| <div class="config-section"> | |
| <h3>🛡️ Trust Elements</h3> | |
| <div class="config-toggle" @click="config.showTrustBadges = !config.showTrustBadges"> | |
| <span class="toggle-label">Show Trust Badges</span> | |
| <div class="toggle-switch" :class="config.showTrustBadges ? 'active' : ''"></div> | |
| </div> | |
| <div x-show="config.showTrustBadges" class="fade-in-progressive"> | |
| <div class="trust-badge-list"> | |
| <template x-for="(badge, index) in config.trustBadges" :key="index"> | |
| <div class="trust-badge-editor"> | |
| <div class="trust-badge-preview"> | |
| <div class="trust-badge-icon-large" x-text="badge.icon || '🛡️'"></div> | |
| <div class="trust-badge-content-large"> | |
| <div class="trust-badge-title-large" x-text="badge.title || 'Badge Title'"></div> | |
| <div class="trust-badge-subtitle-large" x-text="badge.subtitle || 'Badge Subtitle'"></div> | |
| </div> | |
| <button class="trust-badge-remove" @click="removeTrustBadge(index)">×</button> | |
| </div> | |
| <div style="padding: 24px;"> | |
| <!-- Badge Title - Full Width --> | |
| <div style="margin-bottom: 20px;"> | |
| <label style="display: block; font-size: 14px; font-weight: 600; color: var(--zivvy-dark); margin-bottom: 8px;">Badge Title</label> | |
| <input type="text" x-model="badge.title" placeholder="e.g. Lifetime Warranty" style="width: 100%; box-sizing: border-box; padding: 12px 16px; border: 1px solid #d1d5db; border-radius: 8px; font-size: 14px; background: var(--zivvy-white);"> | |
| </div> | |
| <!-- Badge Subtitle - Full Width --> | |
| <div style="margin-bottom: 20px;"> | |
| <label style="display: block; font-size: 14px; font-weight: 600; color: var(--zivvy-dark); margin-bottom: 8px;">Badge Subtitle</label> | |
| <input type="text" x-model="badge.subtitle" placeholder="e.g. Member Guarantee" style="width: 100%; box-sizing: border-box; padding: 12px 16px; border: 1px solid #d1d5db; border-radius: 8px; font-size: 14px; background: var(--zivvy-white);"> | |
| </div> | |
| <!-- Choose Icon - Grid --> | |
| <div style="margin-bottom: 20px;"> | |
| <label style="display: block; font-size: 14px; font-weight: 600; color: var(--zivvy-dark); margin-bottom: 8px;">Choose Icon</label> | |
| <div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; padding: 16px; background: #f8fafc; border-radius: 8px; border: 1px solid #e2e8f0;"> | |
| <div style="padding: 16px; border: 2px solid #d1d5db; border-radius: 8px; cursor: pointer; text-align: center; font-size: 20px; background: var(--zivvy-white); aspect-ratio: 1; display: flex; align-items: center; justify-content: center;" :style="badge.icon === '🛡️' ? 'border-color: var(--zivvy-primary); background: #f0f4ff;' : ''" @click="badge.icon = '🛡️'">🛡️</div> | |
| <div style="padding: 16px; border: 2px solid #d1d5db; border-radius: 8px; cursor: pointer; text-align: center; font-size: 20px; background: var(--zivvy-white); aspect-ratio: 1; display: flex; align-items: center; justify-content: center;" :style="badge.icon === '⭐' ? 'border-color: var(--zivvy-primary); background: #f0f4ff;' : ''" @click="badge.icon = '⭐'">⭐</div> | |
| <div style="padding: 16px; border: 2px solid #d1d5db; border-radius: 8px; cursor: pointer; text-align: center; font-size: 20px; background: var(--zivvy-white); aspect-ratio: 1; display: flex; align-items: center; justify-content: center;" :style="badge.icon === '🏆' ? 'border-color: var(--zivvy-primary); background: #f0f4ff;' : ''" @click="badge.icon = '🏆'">🏆</div> | |
| <div style="padding: 16px; border: 2px solid #d1d5db; border-radius: 8px; cursor: pointer; text-align: center; font-size: 20px; background: var(--zivvy-white); aspect-ratio: 1; display: flex; align-items: center; justify-content: center;" :style="badge.icon === '✓' ? 'border-color: var(--zivvy-primary); background: #f0f4ff;' : ''" @click="badge.icon = '✓'">✓</div> | |
| <div style="padding: 16px; border: 2px solid #d1d5db; border-radius: 8px; cursor: pointer; text-align: center; font-size: 20px; background: var(--zivvy-white); aspect-ratio: 1; display: flex; align-items: center; justify-content: center;" :style="badge.icon === '🔒' ? 'border-color: var(--zivvy-primary); background: #f0f4ff;' : ''" @click="badge.icon = '🔒'">🔒</div> | |
| <div style="padding: 16px; border: 2px solid #d1d5db; border-radius: 8px; cursor: pointer; text-align: center; font-size: 20px; background: var(--zivvy-white); aspect-ratio: 1; display: flex; align-items: center; justify-content: center;" :style="badge.icon === '💯' ? 'border-color: var(--zivvy-primary); background: #f0f4ff;' : ''" @click="badge.icon = '💯'">💯</div> | |
| <div style="padding: 16px; border: 2px solid #d1d5db; border-radius: 8px; cursor: pointer; text-align: center; font-size: 20px; background: var(--zivvy-white); aspect-ratio: 1; display: flex; align-items: center; justify-content: center;" :style="badge.icon === '🥇' ? 'border-color: var(--zivvy-primary); background: #f0f4ff;' : ''" @click="badge.icon = '🥇'">🥇</div> | |
| <div style="padding: 16px; border: 2px solid #d1d5db; border-radius: 8px; cursor: pointer; text-align: center; font-size: 20px; background: var(--zivvy-white); aspect-ratio: 1; display: flex; align-items: center; justify-content: center;" :style="badge.icon === '🎖️' ? 'border-color: var(--zivvy-primary); background: #f0f4ff;' : ''" @click="badge.icon = '🎖️'">🎖️</div> | |
| </div> | |
| </div> | |
| <!-- Custom Icon - Full Width --> | |
| <div style="margin-bottom: 20px;"> | |
| <label style="display: block; font-size: 14px; font-weight: 600; color: var(--zivvy-dark; margin-bottom: 8px;">Custom Icon</label> | |
| <input type="text" x-model="badge.icon" placeholder="Or paste your own icon/emoji" style="width: 100%; box-sizing: border-box; padding: 12px 16px; border: 1px solid #d1d5db; border-radius: 8px; font-size: 14px; background: var(--zivvy-white);"> | |
| </div> | |
| </div> | |
| </div> | |
| </template> | |
| </div> | |
| <button class="add-btn" @click="addTrustBadge()">+ Add Trust Badge</button> | |
| </div> | |
| </div> | |
| <!-- Color Theme --> | |
| <div class="config-section"> | |
| <h3>🎨 Color Theme</h3> | |
| <div class="color-section"> | |
| <div> | |
| <label class="config-label">Primary Color</label> | |
| <div class="color-picker"> | |
| <div class="color-option" style="background: #256EFF;" :class="config.primaryColor === '#256EFF' ? 'selected' : ''" @click="config.primaryColor = '#256EFF'"></div> | |
| <div class="color-option" style="background: #dc2626;" :class="config.primaryColor === '#dc2626' ? 'selected' : ''" @click="config.primaryColor = '#dc2626'"></div> | |
| <div class="color-option" style="background: #059669;" :class="config.primaryColor === '#059669' ? 'selected' : ''" @click="config.primaryColor = '#059669'"></div> | |
| <div class="color-option" style="background: #7c3aed;" :class="config.primaryColor === '#7c3aed' ? 'selected' : ''" @click="config.primaryColor = '#7c3aed'"></div> | |
| <div class="color-option" style="background: #ea580c;" :class="config.primaryColor === '#ea580c' ? 'selected' : ''" @click="config.primaryColor = '#ea580c'"></div> | |
| <div class="color-option" style="background: #0891b2;" :class="config.primaryColor === '#0891b2' ? 'selected' : ''" @click="config.primaryColor = '#0891b2'"></div> | |
| </div> | |
| <input type="color" class="config-input" x-model="config.primaryColor"> | |
| </div> | |
| <div> | |
| <label class="config-label">Secondary Color</label> | |
| <div class="color-picker"> | |
| <div class="color-option" style="background: #6366f1;" :class="config.secondaryColor === '#6366f1' ? 'selected' : ''" @click="config.secondaryColor = '#6366f1'"></div> | |
| <div class="color-option" style="background: #8b5cf6;" :class="config.secondaryColor === '#8b5cf6' ? 'selected' : ''" @click="config.secondaryColor = '#8b5cf6'"></div> | |
| <div class="color-option" style="background: #06b6d4;" :class="config.secondaryColor === '#06b6d4' ? 'selected' : ''" @click="config.secondaryColor = '#06b6d4'"></div> | |
| <div class="color-option" style="background: #10b981;" :class="config.secondaryColor === '#10b981' ? 'selected' : ''" @click="config.secondaryColor = '#10b981'"></div> | |
| <div class="color-option" style="background: #f59e0b;" :class="config.secondaryColor === '#f59e0b' ? 'selected' : ''" @click="config.secondaryColor = '#f59e0b'"></div> | |
| <div class="color-option" style="background: #ef4444;" :class="config.secondaryColor === '#ef4444' ? 'selected' : ''" @click="config.secondaryColor = '#ef4444'"></div> | |
| </div> | |
| <input type="color" class="config-input" x-model="config.secondaryColor"> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Additional Form Fields --> | |
| <div class="config-section"> | |
| <h3>📝 Additional Fields</h3> | |
| <div class="config-field"> | |
| <label class="config-label">Add Form Fields</label> | |
| <select class="config-select" @change="addFormField($event.target.value); $event.target.value = ''"> | |
| <option value="">Select field to add</option> | |
| <option value="company">Company Name</option> | |
| <option value="title">Job Title</option> | |
| <option value="birthdate">Birth Date</option> | |
| <option value="referral">How did you hear about us?</option> | |
| <option value="notes">Special Instructions</option> | |
| </select> | |
| </div> | |
| <div class="form-field-list"> | |
| <template x-for="(field, index) in config.additionalFields" :key="index"> | |
| <div class="form-field-editor"> | |
| <div class="form-field-header"> | |
| <input type="text" x-model="field.label" placeholder="Field Label" class="field-label-input"> | |
| <select x-model="field.type" class="field-type-select"> | |
| <option value="text">Text</option> | |
| <option value="email">Email</option> | |
| <option value="tel">Phone</option> | |
| <option value="textarea">Textarea</option> | |
| <option value="select">Dropdown</option> | |
| </select> | |
| <button class="remove-btn" @click="removeFormField(index)">×</button> | |
| </div> | |
| </div> | |
| </template> | |
| </div> | |
| </div> | |
| <!-- Banner Settings --> | |
| <div class="config-section"> | |
| <h3>🚨 Member Banner</h3> | |
| <div class="config-toggle" @click="config.showMemberBanner = !config.showMemberBanner"> | |
| <span class="toggle-label">Enable Member Exclusive Banner</span> | |
| <div class="toggle-switch" :class="config.showMemberBanner ? 'active' : ''"></div> | |
| </div> | |
| <div x-show="config.showMemberBanner" class="fade-in-progressive"> | |
| <div style="padding: 16px 0;"> | |
| <!-- Banner Title - Full Width --> | |
| <div style="margin-bottom: 16px;"> | |
| <label style="display: block; font-size: 13px; font-weight: 500; color: #475569; margin-bottom: 6px;">Banner Title</label> | |
| <input type="text" x-model="config.bannerTitle" placeholder="e.g. Member Exclusive" style="width: 100%; box-sizing: border-box; padding: 10px 12px; border: 1px solid #d1d5db; border-radius: 6px; font-size: 14px; background: var(--zivvy-white);"> | |
| </div> | |
| <!-- Banner Description - Full Width --> | |
| <div style="margin-bottom: 16px;"> | |
| <label style="display: block; font-size: 13px; font-weight: 500; color: #475569; margin-bottom: 6px;">Banner Description</label> | |
| <input type="text" x-model="config.bannerDescription" placeholder="e.g. Only 12 left at this price!" style="width: 100%; box-sizing: border-box; padding: 10px 12px; border: 1px solid #d1d5db; border-radius: 6px; font-size: 14px; background: var(--zivvy-white);"> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <button class="save-button" @click="savePageConfiguration()"> | |
| 💾 Save & Generate Page | |
| </button> | |
| </div> | |
| <!-- Preview Area --> | |
| <div class="preview-area"> | |
| <div class="preview-header"> | |
| <div class="preview-title">Live Preview</div> | |
| <div class="preview-actions"> | |
| <button class="preview-btn" @click="previewMode = 'desktop'">🖥️ Desktop</button> | |
| <button class="preview-btn" @click="previewMode = 'mobile'">📱 Mobile</button> | |
| <button class="preview-btn" @click="generateCode()">🗂️ Get Code</button> | |
| </div> | |
| </div> | |
| <div class="preview-frame" :style="previewMode === 'mobile' ? 'max-width: 375px; transform: scale(0.8);' : ''"> | |
| <!-- Test Area --> | |
| <div style="padding: 20px; background: #f8fafc;"> | |
| <div style="font-size: 16px; font-weight: 600; margin-bottom: 16px; color: var(--zivvy-dark);">Pricing Configuration:</div> | |
| <pre style="background: white; padding: 12px; border-radius: 6px; font-size: 12px; overflow-x: auto;" x-text="JSON.stringify({ | |
| pricingType: config.pricingType, | |
| price: config.price, | |
| regularPrice: config.regularPrice, | |
| salePrice: config.salePrice | |
| }, null, 2)"></pre> | |
| <div style="margin-top: 20px; font-size: 16px; font-weight: 600; margin-bottom: 16px; color: var(--zivvy-dark);">Member Banner Data:</div> | |
| <pre style="background: white; padding: 12px; border-radius: 6px; font-size: 12px; overflow-x: auto;" x-text="JSON.stringify({bannerTitle: config.bannerTitle, bannerDescription: config.bannerDescription}, null, 2)"></pre> | |
| <div style="margin-top: 20px; font-size: 16px; font-weight: 600; margin-bottom: 16px; color: var(--zivvy-dark);">Benefits Data Structure:</div> | |
| <pre style="background: white; padding: 12px; border-radius: 6px; font-size: 12px; overflow-x: auto;" x-text="JSON.stringify(config.benefits, null, 2)"></pre> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| function pageBuilder() { | |
| return { | |
| previewMode: 'desktop', | |
| config: { | |
| businessName: 'Elite Martial Arts Academy', | |
| businessTagline: 'Forge Your Warrior Spirit • Est. 2010', | |
| showMemberBanner: true, | |
| bannerTitle: 'Member Exclusive', | |
| bannerDescription: 'Only 12 left at this price!', | |
| productName: 'Elite Pro Training Gloves', | |
| productDescription: 'Professional-grade training gloves for serious martial artists', | |
| pricingType: 'discount', | |
| price: 297, | |
| regularPrice: 400, | |
| salePrice: 297, | |
| enableQuantity: true, | |
| showRatings: true, | |
| ratingScore: 4.9, | |
| reviewCount: 1247, | |
| ratingText: 'member reviews', | |
| showTrustBadges: true, | |
| primaryColor: '#256EFF', | |
| secondaryColor: '#6366f1', | |
| bulletStyle: '✓', | |
| attributes: [ | |
| { | |
| name: 'Size', | |
| options: ['XS', 'S', 'M', 'L', 'XL', 'XXL'] | |
| }, | |
| { | |
| name: 'Color', | |
| options: ['Black', 'Red', 'Blue', 'White', 'Gold'] | |
| } | |
| ], | |
| benefits: [ | |
| { | |
| title: 'Superior Grip Technology', | |
| description: 'Advanced palm texture for unbreakable holds' | |
| }, | |
| { | |
| title: 'Maximum Impact Protection', | |
| description: 'Multi-layer padding protects knuckles and wrists' | |
| }, | |
| { | |
| title: 'Professional Grade Materials', | |
| description: 'Premium leather built for years of training' | |
| } | |
| ], | |
| trustBadges: [ | |
| { icon: '🛡️', title: 'Lifetime Warranty', subtitle: 'Member Guarantee' }, | |
| { icon: '🥋', title: 'Perfect Fit', subtitle: 'Exchange Anytime' }, | |
| { icon: '⭐', title: '4.9/5 Stars', subtitle: '1,247 Reviews' }, | |
| { icon: '🏆', title: 'Pro Approved', subtitle: 'Used by Champions' } | |
| ], | |
| additionalFields: [] | |
| }, | |
| addAttribute() { | |
| this.config.attributes.push({ name: '', options: [] }); | |
| }, | |
| removeAttribute(index) { | |
| this.config.attributes.splice(index, 1); | |
| }, | |
| addAttributeOption(attributeIndex, optionValue) { | |
| if (!optionValue || !optionValue.trim()) return; | |
| const trimmedValue = optionValue.trim(); | |
| const attribute = this.config.attributes[attributeIndex]; | |
| if (!attribute.options.includes(trimmedValue)) { | |
| attribute.options.push(trimmedValue); | |
| } | |
| }, | |
| removeAttributeOption(attributeIndex, optionIndex) { | |
| this.config.attributes[attributeIndex].options.splice(optionIndex, 1); | |
| }, | |
| addBenefit() { | |
| this.config.benefits.push({ title: '', description: '' }); | |
| }, | |
| removeBenefit(index) { | |
| this.config.benefits.splice(index, 1); | |
| }, | |
| addTrustBadge() { | |
| this.config.trustBadges.push({ icon: '', title: '', subtitle: '' }); | |
| }, | |
| removeTrustBadge(index) { | |
| this.config.trustBadges.splice(index, 1); | |
| }, | |
| addFormField(fieldType) { | |
| if (!fieldType) return; | |
| const fieldLabels = { | |
| company: 'Company Name', | |
| title: 'Job Title', | |
| birthdate: 'Birth Date', | |
| referral: 'How did you hear about us?', | |
| notes: 'Special Instructions' | |
| }; | |
| const fieldTypes = { | |
| company: 'text', | |
| title: 'text', | |
| birthdate: 'date', | |
| referral: 'select', | |
| notes: 'textarea' | |
| }; | |
| this.config.additionalFields.push({ | |
| label: fieldLabels[fieldType], | |
| type: fieldTypes[fieldType], | |
| required: false | |
| }); | |
| }, | |
| removeFormField(index) { | |
| this.config.additionalFields.splice(index, 1); | |
| }, | |
| uploadProductImage() { | |
| alert('Product image upload functionality would be implemented with your file upload system'); | |
| }, | |
| uploadLogo() { | |
| alert('Logo upload functionality would be implemented with your file upload system'); | |
| }, | |
| generateCode() { | |
| alert('This would generate the complete HTML/CSS/JS code for your customized checkout page'); | |
| }, | |
| savePageConfiguration() { | |
| alert('Page configuration saved! This would integrate with your Zivvy backend to store the settings.'); | |
| console.log('Page Configuration:', this.config); | |
| } | |
| } | |
| } | |
| </script> | |
| </div> | |
| </body> | |
| </html> | |