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:
377
f_templates/tpl_backend/tpl_template_manager.tpl
Normal file
377
f_templates/tpl_backend/tpl_template_manager.tpl
Normal 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>
|
||||
319
f_templates/tpl_frontend/tpl_builder/tpl_builder.tpl
Normal file
319
f_templates/tpl_frontend/tpl_builder/tpl_builder.tpl
Normal 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>
|
||||
319
f_templates/tpl_frontend/tpl_builder/tpl_builder_main.tpl
Normal file
319
f_templates/tpl_frontend/tpl_builder/tpl_builder_main.tpl
Normal 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>
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user