feat: Add complete Docker deployment with web-based setup wizard

Major additions:
- Web-based setup wizard (setup.php, setup_wizard.php, setup-wizard.js)
- Production Docker configuration (docker-compose.prod.yml, .env.production)
- Database initialization SQL files (deploy/init_settings.sql)
- Template builder system with drag-and-drop UI
- Advanced features (OAuth, CDN, enhanced analytics, monetization)
- Comprehensive documentation (deployment guides, quick start, feature docs)
- Design system with accessibility and responsive layout
- Deployment automation scripts (deploy.ps1, generate-secrets.ps1)

Setup wizard allows customization of:
- Platform name and branding
- Domain configuration
- Membership tiers and pricing
- Admin credentials
- Feature toggles

Database includes 270+ tables for complete video streaming platform with
advanced features for analytics, moderation, template building, and monetization.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
SamiAhmed7777
2025-10-26 01:42:31 -07:00
parent 0b7e2d0a5b
commit d22b3e1c0d
90 changed files with 22329 additions and 268 deletions

View File

@@ -0,0 +1,377 @@
{* Template Manager - List View *}
<div class="template-manager-container">
<div class="tm-header">
<h1>My Templates</h1>
<a href="/f_modules/m_backend/template_manager.php?action=new" class="btn btn-primary">
<i class="icon-plus"></i> Create New Template
</a>
</div>
{if $message}
<div class="alert alert-{$message_type}">
{$message}
</div>
{/if}
{if $templates|@count > 0}
<div class="tm-grid">
{foreach $templates as $template}
<div class="tm-card {if $template.is_active}active{/if}">
<div class="tm-card-preview">
{if $template.preview_image}
<img src="{$template.preview_image}" alt="{$template.template_name}" />
{else}
<div class="tm-preview-placeholder">
<i class="icon-layout"></i>
<span>{$template.template_type}</span>
</div>
{/if}
{if $template.is_active}
<span class="tm-badge tm-badge-active">Active</span>
{/if}
</div>
<div class="tm-card-content">
<h3 class="tm-card-title">{$template.template_name}</h3>
<div class="tm-card-meta">
<span class="tm-meta-item">
<i class="icon-type"></i>
{$template.template_type|replace:'_':' '|ucwords}
</span>
<span class="tm-meta-item">
<i class="icon-eye"></i>
{$template.views} views
</span>
<span class="tm-meta-item">
<i class="icon-clock"></i>
{$template.updated_at|date_format:"%b %d, %Y"}
</span>
</div>
</div>
<div class="tm-card-actions">
<a href="/f_modules/m_backend/template_manager.php?action=edit&id={$template.template_id}"
class="btn btn-sm btn-secondary">
<i class="icon-edit"></i> Edit
</a>
<button class="btn btn-sm btn-secondary dropdown-toggle" data-toggle="dropdown">
<i class="icon-more-vertical"></i>
</button>
<div class="dropdown-menu">
<a href="/f_modules/m_frontend/templatebuilder_ajax.php?action=preview&template_id={$template.template_id}"
target="_blank" class="dropdown-item">
<i class="icon-eye"></i> Preview
</a>
<a href="/f_modules/m_backend/template_manager.php?action=duplicate&id={$template.template_id}"
class="dropdown-item">
<i class="icon-copy"></i> Duplicate
</a>
<a href="/f_modules/m_backend/template_manager.php?action=toggle_active&id={$template.template_id}&is_active={if $template.is_active}0{else}1{/if}"
class="dropdown-item">
<i class="icon-{if $template.is_active}eye-off{else}eye{/if}"></i>
{if $template.is_active}Deactivate{else}Activate{/if}
</a>
<div class="dropdown-divider"></div>
<a href="/f_modules/m_backend/template_manager.php?action=delete&id={$template.template_id}"
class="dropdown-item text-danger"
onclick="return confirm('Are you sure you want to delete this template?')">
<i class="icon-trash"></i> Delete
</a>
</div>
</div>
</div>
{/foreach}
</div>
{else}
<div class="tm-empty">
<i class="icon-layout"></i>
<h3>No templates yet</h3>
<p>Create your first custom template to get started</p>
<a href="/f_modules/m_backend/template_manager.php?action=new" class="btn btn-primary">
<i class="icon-plus"></i> Create Template
</a>
</div>
{/if}
</div>
<style>
.template-manager-container {
padding: 30px;
max-width: 1400px;
margin: 0 auto;
}
.tm-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30px;
}
.tm-header h1 {
margin: 0;
font-size: 28px;
font-weight: 600;
}
.tm-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
gap: 24px;
}
.tm-card {
background: white;
border: 1px solid #e5e7eb;
border-radius: 8px;
overflow: hidden;
transition: all 0.2s ease;
}
.tm-card:hover {
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
transform: translateY(-2px);
}
.tm-card.active {
border-color: #10b981;
}
.tm-card-preview {
height: 200px;
background: #f3f4f6;
position: relative;
overflow: hidden;
}
.tm-card-preview img {
width: 100%;
height: 100%;
object-fit: cover;
}
.tm-preview-placeholder {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: #9ca3af;
}
.tm-preview-placeholder i {
font-size: 48px;
margin-bottom: 10px;
}
.tm-badge {
position: absolute;
top: 12px;
right: 12px;
padding: 4px 12px;
border-radius: 20px;
font-size: 12px;
font-weight: 600;
}
.tm-badge-active {
background: #10b981;
color: white;
}
.tm-card-content {
padding: 16px;
}
.tm-card-title {
margin: 0 0 12px;
font-size: 18px;
font-weight: 600;
}
.tm-card-meta {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.tm-meta-item {
display: flex;
align-items: center;
gap: 4px;
font-size: 13px;
color: #6b7280;
}
.tm-meta-item i {
font-size: 14px;
}
.tm-card-actions {
padding: 12px 16px;
border-top: 1px solid #e5e7eb;
display: flex;
gap: 8px;
position: relative;
}
.tm-empty {
text-align: center;
padding: 80px 40px;
color: #6b7280;
}
.tm-empty i {
font-size: 64px;
margin-bottom: 16px;
opacity: 0.5;
}
.tm-empty h3 {
margin: 0 0 8px;
font-size: 24px;
color: #111827;
}
.tm-empty p {
margin: 0 0 24px;
font-size: 16px;
}
.alert {
padding: 16px;
border-radius: 8px;
margin-bottom: 24px;
}
.alert-success {
background: #d1fae5;
color: #065f46;
border: 1px solid #10b981;
}
.alert-error {
background: #fee2e2;
color: #991b1b;
border: 1px solid #ef4444;
}
.dropdown-menu {
display: none;
position: absolute;
right: 0;
top: 100%;
background: white;
border: 1px solid #e5e7eb;
border-radius: 6px;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
min-width: 180px;
z-index: 10;
margin-top: 4px;
}
.dropdown-toggle:focus + .dropdown-menu,
.dropdown-toggle:active + .dropdown-menu,
.dropdown-menu:hover {
display: block;
}
.dropdown-item {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 16px;
color: #374151;
text-decoration: none;
font-size: 14px;
transition: background 0.2s;
}
.dropdown-item:hover {
background: #f3f4f6;
}
.dropdown-item.text-danger {
color: #ef4444;
}
.dropdown-divider {
height: 1px;
background: #e5e7eb;
margin: 4px 0;
}
.btn {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 8px 16px;
border: none;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
text-decoration: none;
transition: all 0.2s;
}
.btn-primary {
background: #3b82f6;
color: white;
}
.btn-primary:hover {
background: #2563eb;
}
.btn-secondary {
background: #f3f4f6;
color: #374151;
border: 1px solid #e5e7eb;
}
.btn-secondary:hover {
background: #e5e7eb;
}
.btn-sm {
padding: 6px 12px;
font-size: 13px;
}
</style>
<script>
// Simple dropdown toggle
document.querySelectorAll('.dropdown-toggle').forEach(toggle => {
toggle.addEventListener('click', function(e) {
e.stopPropagation();
const menu = this.nextElementSibling;
// Close all other dropdowns
document.querySelectorAll('.dropdown-menu').forEach(m => {
if (m !== menu) m.style.display = 'none';
});
// Toggle current
menu.style.display = menu.style.display === 'block' ? 'none' : 'block';
});
});
// Close dropdowns when clicking outside
document.addEventListener('click', () => {
document.querySelectorAll('.dropdown-menu').forEach(m => {
m.style.display = 'none';
});
});
</script>

View File

@@ -0,0 +1,319 @@
{* Template Builder Main Interface *}
<div id="template-builder-app" class="template-builder" data-theme="{$theme_name}">
<!-- Builder Header -->
<div class="tb-header">
<div class="tb-header-left">
<button id="tb-back-btn" class="tb-btn tb-btn-secondary">
<i class="icon-arrow-left"></i> Back
</button>
<input type="text" id="tb-template-name" class="tb-template-name-input"
value="{$template.template_name|default:'Untitled Template'}"
placeholder="Template Name" />
</div>
<div class="tb-header-center">
<div class="tb-device-preview">
<button class="tb-device-btn active" data-device="desktop" title="Desktop Preview">
<i class="icon-desktop"></i>
</button>
<button class="tb-device-btn" data-device="tablet" title="Tablet Preview">
<i class="icon-tablet"></i>
</button>
<button class="tb-device-btn" data-device="mobile" title="Mobile Preview">
<i class="icon-mobile"></i>
</button>
</div>
</div>
<div class="tb-header-right">
<button id="tb-undo-btn" class="tb-btn tb-btn-icon" title="Undo" disabled>
<i class="icon-undo"></i>
</button>
<button id="tb-redo-btn" class="tb-btn tb-btn-icon" title="Redo" disabled>
<i class="icon-redo"></i>
</button>
<button id="tb-preview-btn" class="tb-btn tb-btn-secondary">
<i class="icon-eye"></i> Preview
</button>
<button id="tb-save-btn" class="tb-btn tb-btn-primary">
<i class="icon-save"></i> Save
</button>
<button id="tb-publish-btn" class="tb-btn tb-btn-success">
<i class="icon-check"></i> Publish
</button>
</div>
</div>
<!-- Builder Main Content -->
<div class="tb-main">
<!-- Left Sidebar - Components Panel -->
<div class="tb-sidebar tb-sidebar-left" id="components-panel">
<div class="tb-sidebar-header">
<h3>Components</h3>
<button class="tb-sidebar-toggle" data-target="components-panel">
<i class="icon-chevron-left"></i>
</button>
</div>
<div class="tb-sidebar-content">
<!-- Search Components -->
<div class="tb-search-box">
<input type="text" id="component-search" placeholder="Search components..." />
<i class="icon-search"></i>
</div>
<!-- Component Categories -->
<div class="tb-component-categories">
<button class="tb-category-btn active" data-category="all">All</button>
<button class="tb-category-btn" data-category="header">Headers</button>
<button class="tb-category-btn" data-category="hero">Heroes</button>
<button class="tb-category-btn" data-category="video_grid">Video Grids</button>
<button class="tb-category-btn" data-category="video_list">Video Lists</button>
<button class="tb-category-btn" data-category="sidebar">Sidebars</button>
<button class="tb-category-btn" data-category="text">Text</button>
<button class="tb-category-btn" data-category="image">Images</button>
<button class="tb-category-btn" data-category="custom">Custom</button>
</div>
<!-- Components List -->
<div class="tb-components-list" id="components-list">
{* Components will be loaded via JavaScript *}
<div class="tb-loading">Loading components...</div>
</div>
</div>
</div>
<!-- Center Canvas - Preview Area -->
<div class="tb-canvas-container">
<div class="tb-canvas-toolbar">
<div class="tb-zoom-controls">
<button class="tb-btn tb-btn-sm" id="zoom-out">
<i class="icon-minus"></i>
</button>
<span class="tb-zoom-level">100%</span>
<button class="tb-btn tb-btn-sm" id="zoom-in">
<i class="icon-plus"></i>
</button>
<button class="tb-btn tb-btn-sm" id="zoom-fit">Fit</button>
</div>
<div class="tb-canvas-options">
<label class="tb-checkbox">
<input type="checkbox" id="show-grid" checked />
<span>Show Grid</span>
</label>
<label class="tb-checkbox">
<input type="checkbox" id="show-guides" checked />
<span>Show Guides</span>
</label>
</div>
</div>
<div class="tb-canvas-wrapper" id="canvas-wrapper">
<div class="tb-canvas" id="builder-canvas" data-device="desktop">
<!-- Drop Zone Hint -->
<div class="tb-drop-hint" id="drop-hint">
<div class="tb-drop-hint-content">
<i class="icon-plus-circle"></i>
<p>Drag components here to start building</p>
</div>
</div>
<!-- Sections Container -->
<div class="tb-sections-container" id="sections-container">
{* Sections will be added here *}
</div>
</div>
</div>
</div>
<!-- Right Sidebar - Properties Panel -->
<div class="tb-sidebar tb-sidebar-right" id="properties-panel">
<div class="tb-sidebar-header">
<h3>Properties</h3>
<button class="tb-sidebar-toggle" data-target="properties-panel">
<i class="icon-chevron-right"></i>
</button>
</div>
<div class="tb-sidebar-content" id="properties-content">
<!-- No Selection State -->
<div class="tb-no-selection" id="no-selection">
<i class="icon-cursor"></i>
<p>Select an element to edit its properties</p>
</div>
<!-- Page Settings (when nothing selected) -->
<div class="tb-properties-section" id="page-settings" style="display: none;">
<h4>Page Settings</h4>
<div class="tb-form-group">
<label>Template Type</label>
<select id="template-type" class="tb-select">
<option value="custom_page">Custom Page</option>
<option value="homepage">Homepage</option>
<option value="channel">Channel Page</option>
<option value="browse">Browse Page</option>
<option value="landing">Landing Page</option>
</select>
</div>
<div class="tb-form-group">
<label>Max Width (px)</label>
<input type="number" id="page-max-width" class="tb-input" value="1200" min="800" max="2000" step="50" />
</div>
<div class="tb-form-group">
<label>Layout Type</label>
<select id="page-layout-type" class="tb-select">
<option value="flex">Flexible</option>
<option value="grid">Grid</option>
<option value="boxed">Boxed</option>
</select>
</div>
</div>
<!-- Component Properties (when component selected) -->
<div class="tb-properties-section" id="component-settings" style="display: none;">
<div class="tb-properties-header">
<h4 id="selected-component-name">Component Settings</h4>
<button class="tb-btn tb-btn-danger tb-btn-sm" id="delete-component">
<i class="icon-trash"></i>
</button>
</div>
<div id="component-settings-fields">
{* Dynamic fields will be inserted here *}
</div>
<!-- Advanced Settings -->
<div class="tb-collapsible">
<button class="tb-collapsible-header">
<i class="icon-chevron-down"></i> Advanced
</button>
<div class="tb-collapsible-content">
<div class="tb-form-group">
<label>Custom CSS Class</label>
<input type="text" id="component-custom-class" class="tb-input" placeholder="custom-class" />
</div>
<div class="tb-form-group">
<label>Custom ID</label>
<input type="text" id="component-custom-id" class="tb-input" placeholder="custom-id" />
</div>
</div>
</div>
</div>
<!-- Section Properties (when section selected) -->
<div class="tb-properties-section" id="section-settings" style="display: none;">
<div class="tb-properties-header">
<h4>Section Settings</h4>
<button class="tb-btn tb-btn-danger tb-btn-sm" id="delete-section">
<i class="icon-trash"></i>
</button>
</div>
<div class="tb-form-group">
<label>Columns</label>
<select id="section-columns" class="tb-select">
<option value="1">1 Column</option>
<option value="2">2 Columns</option>
<option value="3">3 Columns</option>
<option value="4">4 Columns</option>
</select>
</div>
<div class="tb-form-group">
<label>Column Gap (px)</label>
<input type="number" id="section-gap" class="tb-input" value="20" min="0" max="100" step="5" />
</div>
<div class="tb-form-group">
<label>Background Color</label>
<input type="color" id="section-bg-color" class="tb-input" />
</div>
<div class="tb-form-group">
<label>Padding (px)</label>
<div class="tb-spacing-grid">
<input type="number" placeholder="Top" id="section-padding-top" class="tb-input tb-input-sm" min="0" />
<input type="number" placeholder="Right" id="section-padding-right" class="tb-input tb-input-sm" min="0" />
<input type="number" placeholder="Bottom" id="section-padding-bottom" class="tb-input tb-input-sm" min="0" />
<input type="number" placeholder="Left" id="section-padding-left" class="tb-input tb-input-sm" min="0" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Preview Modal -->
<div class="tb-modal" id="preview-modal" style="display: none;">
<div class="tb-modal-overlay"></div>
<div class="tb-modal-content tb-modal-large">
<div class="tb-modal-header">
<h3>Preview</h3>
<button class="tb-modal-close" data-modal="preview-modal">
<i class="icon-close"></i>
</button>
</div>
<div class="tb-modal-body">
<iframe id="preview-iframe" style="width: 100%; height: 600px; border: none;"></iframe>
</div>
</div>
</div>
<!-- Save Template Modal -->
<div class="tb-modal" id="save-modal" style="display: none;">
<div class="tb-modal-overlay"></div>
<div class="tb-modal-content">
<div class="tb-modal-header">
<h3>Save Template</h3>
<button class="tb-modal-close" data-modal="save-modal">
<i class="icon-close"></i>
</button>
</div>
<div class="tb-modal-body">
<div class="tb-form-group">
<label>Template Name</label>
<input type="text" id="save-template-name" class="tb-input" value="{$template.template_name|default:''}" />
</div>
<div class="tb-form-group">
<label>Change Note (Optional)</label>
<textarea id="save-change-note" class="tb-textarea" rows="3" placeholder="What did you change?"></textarea>
</div>
</div>
<div class="tb-modal-footer">
<button class="tb-btn tb-btn-secondary" data-modal-close="save-modal">Cancel</button>
<button class="tb-btn tb-btn-primary" id="confirm-save">Save</button>
</div>
</div>
</div>
<!-- Hidden input for template data -->
<input type="hidden" id="template-id" value="{$template.template_id|default:0}" />
<input type="hidden" id="template-data" value='{$template_json|default:"{}"}' />
{* Include Builder CSS *}
<link rel="stylesheet" href="{$styles_url}/builder/builder.css" />
{* Include Builder JavaScript *}
<script src="{$javascript_url}/builder/builder-core.js"></script>
<script>
// Initialize Template Builder
document.addEventListener('DOMContentLoaded', function() {
const templateData = JSON.parse(document.getElementById('template-data').value || '{}');
const templateId = document.getElementById('template-id').value;
window.TemplateBuilder = new TemplateBuilderApp({
templateId: templateId,
templateData: templateData,
apiUrl: '{$main_url}/f_modules/m_frontend/templatebuilder_ajax.php',
themeMode: '{$theme_name}'.indexOf('dark') !== -1 ? 'dark' : 'light'
});
});
</script>

View File

@@ -0,0 +1,319 @@
{* Template Builder Main Interface *}
<div id="template-builder-app" class="template-builder" data-theme="{$theme_name}">
<!-- Builder Header -->
<div class="tb-header">
<div class="tb-header-left">
<button id="tb-back-btn" class="tb-btn tb-btn-secondary">
<i class="icon-arrow-left"></i> Back
</button>
<input type="text" id="tb-template-name" class="tb-template-name-input"
value="{$template.template_name|default:'Untitled Template'}"
placeholder="Template Name" />
</div>
<div class="tb-header-center">
<div class="tb-device-preview">
<button class="tb-device-btn active" data-device="desktop" title="Desktop Preview">
<i class="icon-desktop"></i>
</button>
<button class="tb-device-btn" data-device="tablet" title="Tablet Preview">
<i class="icon-tablet"></i>
</button>
<button class="tb-device-btn" data-device="mobile" title="Mobile Preview">
<i class="icon-mobile"></i>
</button>
</div>
</div>
<div class="tb-header-right">
<button id="tb-undo-btn" class="tb-btn tb-btn-icon" title="Undo" disabled>
<i class="icon-undo"></i>
</button>
<button id="tb-redo-btn" class="tb-btn tb-btn-icon" title="Redo" disabled>
<i class="icon-redo"></i>
</button>
<button id="tb-preview-btn" class="tb-btn tb-btn-secondary">
<i class="icon-eye"></i> Preview
</button>
<button id="tb-save-btn" class="tb-btn tb-btn-primary">
<i class="icon-save"></i> Save
</button>
<button id="tb-publish-btn" class="tb-btn tb-btn-success">
<i class="icon-check"></i> Publish
</button>
</div>
</div>
<!-- Builder Main Content -->
<div class="tb-main">
<!-- Left Sidebar - Components Panel -->
<div class="tb-sidebar tb-sidebar-left" id="components-panel">
<div class="tb-sidebar-header">
<h3>Components</h3>
<button class="tb-sidebar-toggle" data-target="components-panel">
<i class="icon-chevron-left"></i>
</button>
</div>
<div class="tb-sidebar-content">
<!-- Search Components -->
<div class="tb-search-box">
<input type="text" id="component-search" placeholder="Search components..." />
<i class="icon-search"></i>
</div>
<!-- Component Categories -->
<div class="tb-component-categories">
<button class="tb-category-btn active" data-category="all">All</button>
<button class="tb-category-btn" data-category="header">Headers</button>
<button class="tb-category-btn" data-category="hero">Heroes</button>
<button class="tb-category-btn" data-category="video_grid">Video Grids</button>
<button class="tb-category-btn" data-category="video_list">Video Lists</button>
<button class="tb-category-btn" data-category="sidebar">Sidebars</button>
<button class="tb-category-btn" data-category="text">Text</button>
<button class="tb-category-btn" data-category="image">Images</button>
<button class="tb-category-btn" data-category="custom">Custom</button>
</div>
<!-- Components List -->
<div class="tb-components-list" id="components-list">
{* Components will be loaded via JavaScript *}
<div class="tb-loading">Loading components...</div>
</div>
</div>
</div>
<!-- Center Canvas - Preview Area -->
<div class="tb-canvas-container">
<div class="tb-canvas-toolbar">
<div class="tb-zoom-controls">
<button class="tb-btn tb-btn-sm" id="zoom-out">
<i class="icon-minus"></i>
</button>
<span class="tb-zoom-level">100%</span>
<button class="tb-btn tb-btn-sm" id="zoom-in">
<i class="icon-plus"></i>
</button>
<button class="tb-btn tb-btn-sm" id="zoom-fit">Fit</button>
</div>
<div class="tb-canvas-options">
<label class="tb-checkbox">
<input type="checkbox" id="show-grid" checked />
<span>Show Grid</span>
</label>
<label class="tb-checkbox">
<input type="checkbox" id="show-guides" checked />
<span>Show Guides</span>
</label>
</div>
</div>
<div class="tb-canvas-wrapper" id="canvas-wrapper">
<div class="tb-canvas" id="builder-canvas" data-device="desktop">
<!-- Drop Zone Hint -->
<div class="tb-drop-hint" id="drop-hint">
<div class="tb-drop-hint-content">
<i class="icon-plus-circle"></i>
<p>Drag components here to start building</p>
</div>
</div>
<!-- Sections Container -->
<div class="tb-sections-container" id="sections-container">
{* Sections will be added here *}
</div>
</div>
</div>
</div>
<!-- Right Sidebar - Properties Panel -->
<div class="tb-sidebar tb-sidebar-right" id="properties-panel">
<div class="tb-sidebar-header">
<h3>Properties</h3>
<button class="tb-sidebar-toggle" data-target="properties-panel">
<i class="icon-chevron-right"></i>
</button>
</div>
<div class="tb-sidebar-content" id="properties-content">
<!-- No Selection State -->
<div class="tb-no-selection" id="no-selection">
<i class="icon-cursor"></i>
<p>Select an element to edit its properties</p>
</div>
<!-- Page Settings (when nothing selected) -->
<div class="tb-properties-section" id="page-settings" style="display: none;">
<h4>Page Settings</h4>
<div class="tb-form-group">
<label>Template Type</label>
<select id="template-type" class="tb-select">
<option value="custom_page">Custom Page</option>
<option value="homepage">Homepage</option>
<option value="channel">Channel Page</option>
<option value="browse">Browse Page</option>
<option value="landing">Landing Page</option>
</select>
</div>
<div class="tb-form-group">
<label>Max Width (px)</label>
<input type="number" id="page-max-width" class="tb-input" value="1200" min="800" max="2000" step="50" />
</div>
<div class="tb-form-group">
<label>Layout Type</label>
<select id="page-layout-type" class="tb-select">
<option value="flex">Flexible</option>
<option value="grid">Grid</option>
<option value="boxed">Boxed</option>
</select>
</div>
</div>
<!-- Component Properties (when component selected) -->
<div class="tb-properties-section" id="component-settings" style="display: none;">
<div class="tb-properties-header">
<h4 id="selected-component-name">Component Settings</h4>
<button class="tb-btn tb-btn-danger tb-btn-sm" id="delete-component">
<i class="icon-trash"></i>
</button>
</div>
<div id="component-settings-fields">
{* Dynamic fields will be inserted here *}
</div>
<!-- Advanced Settings -->
<div class="tb-collapsible">
<button class="tb-collapsible-header">
<i class="icon-chevron-down"></i> Advanced
</button>
<div class="tb-collapsible-content">
<div class="tb-form-group">
<label>Custom CSS Class</label>
<input type="text" id="component-custom-class" class="tb-input" placeholder="custom-class" />
</div>
<div class="tb-form-group">
<label>Custom ID</label>
<input type="text" id="component-custom-id" class="tb-input" placeholder="custom-id" />
</div>
</div>
</div>
</div>
<!-- Section Properties (when section selected) -->
<div class="tb-properties-section" id="section-settings" style="display: none;">
<div class="tb-properties-header">
<h4>Section Settings</h4>
<button class="tb-btn tb-btn-danger tb-btn-sm" id="delete-section">
<i class="icon-trash"></i>
</button>
</div>
<div class="tb-form-group">
<label>Columns</label>
<select id="section-columns" class="tb-select">
<option value="1">1 Column</option>
<option value="2">2 Columns</option>
<option value="3">3 Columns</option>
<option value="4">4 Columns</option>
</select>
</div>
<div class="tb-form-group">
<label>Column Gap (px)</label>
<input type="number" id="section-gap" class="tb-input" value="20" min="0" max="100" step="5" />
</div>
<div class="tb-form-group">
<label>Background Color</label>
<input type="color" id="section-bg-color" class="tb-input" />
</div>
<div class="tb-form-group">
<label>Padding (px)</label>
<div class="tb-spacing-grid">
<input type="number" placeholder="Top" id="section-padding-top" class="tb-input tb-input-sm" min="0" />
<input type="number" placeholder="Right" id="section-padding-right" class="tb-input tb-input-sm" min="0" />
<input type="number" placeholder="Bottom" id="section-padding-bottom" class="tb-input tb-input-sm" min="0" />
<input type="number" placeholder="Left" id="section-padding-left" class="tb-input tb-input-sm" min="0" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Preview Modal -->
<div class="tb-modal" id="preview-modal" style="display: none;">
<div class="tb-modal-overlay"></div>
<div class="tb-modal-content tb-modal-large">
<div class="tb-modal-header">
<h3>Preview</h3>
<button class="tb-modal-close" data-modal="preview-modal">
<i class="icon-close"></i>
</button>
</div>
<div class="tb-modal-body">
<iframe id="preview-iframe" style="width: 100%; height: 600px; border: none;"></iframe>
</div>
</div>
</div>
<!-- Save Template Modal -->
<div class="tb-modal" id="save-modal" style="display: none;">
<div class="tb-modal-overlay"></div>
<div class="tb-modal-content">
<div class="tb-modal-header">
<h3>Save Template</h3>
<button class="tb-modal-close" data-modal="save-modal">
<i class="icon-close"></i>
</button>
</div>
<div class="tb-modal-body">
<div class="tb-form-group">
<label>Template Name</label>
<input type="text" id="save-template-name" class="tb-input" value="{$template.template_name|default:''}" />
</div>
<div class="tb-form-group">
<label>Change Note (Optional)</label>
<textarea id="save-change-note" class="tb-textarea" rows="3" placeholder="What did you change?"></textarea>
</div>
</div>
<div class="tb-modal-footer">
<button class="tb-btn tb-btn-secondary" data-modal-close="save-modal">Cancel</button>
<button class="tb-btn tb-btn-primary" id="confirm-save">Save</button>
</div>
</div>
</div>
<!-- Hidden input for template data -->
<input type="hidden" id="template-id" value="{$template.template_id|default:0}" />
<input type="hidden" id="template-data" value='{$template_json|default:"{}"}' />
{* Include Builder CSS *}
<link rel="stylesheet" href="{$styles_url}/builder/builder.css" />
{* Include Builder JavaScript *}
<script src="{$javascript_url}/builder/builder-core.js"></script>
<script>
// Initialize Template Builder
document.addEventListener('DOMContentLoaded', function() {
const templateData = JSON.parse(document.getElementById('template-data').value || '{}');
const templateId = document.getElementById('template-id').value;
window.TemplateBuilder = new TemplateBuilderApp({
templateId: templateId,
templateData: templateData,
apiUrl: '{$main_url}/f_modules/m_frontend/templatebuilder_ajax.php',
themeMode: '{$theme_name}'.indexOf('dark') !== -1 ? 'dark' : 'light'
});
});
</script>

View File

@@ -26,20 +26,20 @@
<div class="user-actions">
<h2>What would you like to do today?</h2>
<div class="action-grid">
<a href="{$main_url}/{href_entry key="upload"}" class="action-card upload-card">
<a href="/upload" class="action-card upload-card">
<i class="icon-upload"></i>
<h3>Upload Content</h3>
<p>Share your videos, images, audio, and documents</p>
</a>
<a href="{$main_url}/{href_entry key="browse"}" class="action-card browse-card">
<a href="/browse" class="action-card browse-card">
<i class="icon-video"></i>
<h3>Browse Videos</h3>
<p>Discover trending and popular content</p>
</a>
<a href="{$main_url}/{href_entry key="channels"}" class="action-card channels-card">
<i class="icon-users"></i>
<h3>Explore Channels</h3>
<p>Find and follow your favorite creators</p>
<a href="/search" class="action-card channels-card">
<i class="icon-search"></i>
<h3>Search Videos</h3>
<p>Find specific content you're looking for</p>
</a>
</div>
</div>
@@ -47,8 +47,8 @@
<div class="guest-actions">
<h2>Join the EasyStream Community</h2>
<div class="auth-buttons">
<a href="{$main_url}/{href_entry key="signup"}" class="btn-primary">Get Started</a>
<a href="{$main_url}/{href_entry key="signin"}" class="btn-secondary">Sign In</a>
<a href="/register" class="btn-primary">Get Started</a>
<a href="/signin" class="btn-secondary">Sign In</a>
</div>
<p class="auth-description">Create an account to upload content, follow channels, and join the community</p>
</div>