pg-create-002 / index.html
usezivvy's picture
<!DOCTYPE html>
1f42ded verified
Raw
History Blame Contribute Delete
48.8 kB
<!DOCTYPE html>
<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>