1488 lines
46 KiB
HTML
1488 lines
46 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>Settings - Sky Art Shop Admin</title>
|
|
<link
|
|
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
|
|
rel="stylesheet"
|
|
/>
|
|
<link
|
|
rel="stylesheet"
|
|
href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css"
|
|
/>
|
|
<link rel="stylesheet" href="/admin/css/admin-style.css" />
|
|
<link rel="stylesheet" href="/admin/css/media-library.css" />
|
|
<style>
|
|
:root {
|
|
--accent-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
--card-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
|
|
--hover-shadow: 0 8px 30px rgba(102, 126, 234, 0.2);
|
|
--border-radius: 16px;
|
|
--transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
}
|
|
|
|
/* Settings Navigation */
|
|
.settings-nav {
|
|
display: flex;
|
|
gap: 12px;
|
|
margin-bottom: 30px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.settings-nav-item {
|
|
background: white;
|
|
border: 2px solid #e2e8f0;
|
|
border-radius: 12px;
|
|
padding: 12px 20px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
cursor: pointer;
|
|
transition: var(--transition);
|
|
text-decoration: none;
|
|
color: #64748b;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.settings-nav-item:hover {
|
|
border-color: #667eea;
|
|
color: #667eea;
|
|
}
|
|
|
|
.settings-nav-item.active {
|
|
background: var(--accent-gradient);
|
|
border-color: transparent;
|
|
color: white;
|
|
}
|
|
|
|
.settings-nav-item i {
|
|
font-size: 1.1rem;
|
|
}
|
|
|
|
/* Settings Card */
|
|
.settings-card {
|
|
background: white;
|
|
border-radius: var(--border-radius);
|
|
box-shadow: var(--card-shadow);
|
|
margin-bottom: 24px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.settings-card-header {
|
|
background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
|
|
padding: 20px 24px;
|
|
border-bottom: 1px solid #e2e8f0;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
}
|
|
|
|
.settings-card-header .icon-box {
|
|
width: 44px;
|
|
height: 44px;
|
|
background: var(--accent-gradient);
|
|
color: white;
|
|
border-radius: 10px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 1.2rem;
|
|
}
|
|
|
|
.settings-card-header h5 {
|
|
margin: 0;
|
|
font-weight: 600;
|
|
color: #334155;
|
|
}
|
|
|
|
.settings-card-header p {
|
|
margin: 0;
|
|
font-size: 0.85rem;
|
|
color: #64748b;
|
|
}
|
|
|
|
.settings-card-body {
|
|
padding: 24px;
|
|
}
|
|
|
|
/* Form Styles */
|
|
.form-group {
|
|
margin-bottom: 24px;
|
|
}
|
|
|
|
.form-label {
|
|
font-weight: 500;
|
|
color: #475569;
|
|
margin-bottom: 8px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.form-label .badge {
|
|
font-size: 0.7rem;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.form-control,
|
|
.form-select {
|
|
border-radius: 10px;
|
|
border: 2px solid #e2e8f0;
|
|
padding: 12px 16px;
|
|
transition: var(--transition);
|
|
}
|
|
|
|
.form-control:focus,
|
|
.form-select:focus {
|
|
border-color: #667eea;
|
|
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
|
|
}
|
|
|
|
.form-text {
|
|
margin-top: 6px;
|
|
color: #94a3b8;
|
|
font-size: 0.85rem;
|
|
}
|
|
|
|
/* Image Upload Boxes */
|
|
.upload-box {
|
|
border: 2px dashed #e2e8f0;
|
|
border-radius: 12px;
|
|
padding: 30px;
|
|
text-align: center;
|
|
cursor: pointer;
|
|
transition: var(--transition);
|
|
background: #f8fafc;
|
|
}
|
|
|
|
.upload-box:hover {
|
|
border-color: #667eea;
|
|
background: rgba(102, 126, 234, 0.05);
|
|
}
|
|
|
|
.upload-box.has-image {
|
|
border-style: solid;
|
|
padding: 16px;
|
|
}
|
|
|
|
.upload-box img {
|
|
max-width: 100%;
|
|
max-height: 150px;
|
|
border-radius: 8px;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.upload-box .placeholder-icon {
|
|
font-size: 2.5rem;
|
|
color: #cbd5e1;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.upload-box .upload-text {
|
|
color: #64748b;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.upload-box .change-text {
|
|
color: #667eea;
|
|
font-size: 0.85rem;
|
|
margin-top: 8px;
|
|
}
|
|
|
|
/* Color Picker */
|
|
.color-picker-wrapper {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
}
|
|
|
|
.color-preview {
|
|
width: 50px;
|
|
height: 50px;
|
|
border-radius: 10px;
|
|
border: 2px solid #e2e8f0;
|
|
cursor: pointer;
|
|
transition: var(--transition);
|
|
}
|
|
|
|
.color-preview:hover {
|
|
transform: scale(1.05);
|
|
box-shadow: var(--card-shadow);
|
|
}
|
|
|
|
.color-input {
|
|
position: absolute;
|
|
opacity: 0;
|
|
pointer-events: none;
|
|
}
|
|
|
|
/* Toggle Section */
|
|
.toggle-group {
|
|
background: #f8fafc;
|
|
border-radius: 12px;
|
|
padding: 20px;
|
|
border: 1px solid #e2e8f0;
|
|
}
|
|
|
|
.toggle-item {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 16px 0;
|
|
border-bottom: 1px solid #e2e8f0;
|
|
}
|
|
|
|
.toggle-item:last-child {
|
|
border-bottom: none;
|
|
padding-bottom: 0;
|
|
}
|
|
|
|
.toggle-item:first-child {
|
|
padding-top: 0;
|
|
}
|
|
|
|
.toggle-info h6 {
|
|
margin: 0 0 4px 0;
|
|
font-weight: 600;
|
|
color: #334155;
|
|
}
|
|
|
|
.toggle-info p {
|
|
margin: 0;
|
|
font-size: 0.85rem;
|
|
color: #64748b;
|
|
}
|
|
|
|
.form-switch .form-check-input {
|
|
width: 48px;
|
|
height: 26px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.form-switch .form-check-input:checked {
|
|
background-color: #667eea;
|
|
border-color: #667eea;
|
|
}
|
|
|
|
/* Theme Selector */
|
|
.theme-options {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
|
|
gap: 16px;
|
|
}
|
|
|
|
.theme-option {
|
|
border: 2px solid #e2e8f0;
|
|
border-radius: 12px;
|
|
padding: 16px;
|
|
cursor: pointer;
|
|
transition: var(--transition);
|
|
text-align: center;
|
|
}
|
|
|
|
.theme-option:hover {
|
|
border-color: #667eea;
|
|
}
|
|
|
|
.theme-option.selected {
|
|
border-color: #667eea;
|
|
background: rgba(102, 126, 234, 0.05);
|
|
}
|
|
|
|
.theme-option .theme-preview {
|
|
width: 60px;
|
|
height: 60px;
|
|
border-radius: 50%;
|
|
margin: 0 auto 12px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.theme-option .theme-name {
|
|
font-weight: 600;
|
|
color: #334155;
|
|
}
|
|
|
|
/* Save Button */
|
|
.save-bar {
|
|
position: sticky;
|
|
bottom: 20px;
|
|
background: white;
|
|
border-radius: var(--border-radius);
|
|
box-shadow: 0 -4px 30px rgba(0, 0, 0, 0.1);
|
|
padding: 16px 24px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
z-index: 100;
|
|
}
|
|
|
|
.save-bar .unsaved-text {
|
|
color: #f59e0b;
|
|
font-weight: 500;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.btn-save {
|
|
background: var(--accent-gradient);
|
|
border: none;
|
|
color: white;
|
|
padding: 12px 32px;
|
|
border-radius: 10px;
|
|
font-weight: 600;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
transition: var(--transition);
|
|
}
|
|
|
|
.btn-save:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
|
|
color: white;
|
|
}
|
|
|
|
.btn-save:disabled {
|
|
opacity: 0.6;
|
|
transform: none;
|
|
}
|
|
|
|
/* Section Toggle */
|
|
.settings-section {
|
|
display: none;
|
|
}
|
|
|
|
.settings-section.active {
|
|
display: block;
|
|
}
|
|
|
|
/* Social Links */
|
|
.social-links-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
|
gap: 16px;
|
|
}
|
|
|
|
.social-input-group {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
background: #f8fafc;
|
|
padding: 12px 16px;
|
|
border-radius: 10px;
|
|
border: 1px solid #e2e8f0;
|
|
}
|
|
|
|
.social-input-group i {
|
|
font-size: 1.4rem;
|
|
color: #64748b;
|
|
width: 30px;
|
|
text-align: center;
|
|
}
|
|
|
|
.social-input-group input {
|
|
flex: 1;
|
|
border: none;
|
|
background: transparent;
|
|
padding: 8px 0;
|
|
font-size: 0.95rem;
|
|
}
|
|
|
|
.social-input-group input:focus {
|
|
outline: none;
|
|
}
|
|
|
|
/* Toast Container */
|
|
.toast-container {
|
|
z-index: 1100;
|
|
}
|
|
|
|
/* Loading Spinner */
|
|
.loading-spinner {
|
|
width: 40px;
|
|
height: 40px;
|
|
border: 3px solid #e2e8f0;
|
|
border-top-color: #667eea;
|
|
border-radius: 50%;
|
|
animation: spin 1s linear infinite;
|
|
margin: 40px auto;
|
|
}
|
|
|
|
@keyframes spin {
|
|
to {
|
|
transform: rotate(360deg);
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="sidebar">
|
|
<div class="sidebar-brand">Sky Art Shop</div>
|
|
<ul class="sidebar-menu">
|
|
<li>
|
|
<a href="/admin/dashboard"
|
|
><i class="bi bi-speedometer2"></i> Dashboard</a
|
|
>
|
|
</li>
|
|
<li>
|
|
<a href="/admin/homepage"
|
|
><i class="bi bi-house"></i> Homepage Editor</a
|
|
>
|
|
</li>
|
|
<li>
|
|
<a href="/admin/products"><i class="bi bi-box"></i> Products</a>
|
|
</li>
|
|
<li>
|
|
<a href="/admin/portfolio"><i class="bi bi-easel"></i> Portfolio</a>
|
|
</li>
|
|
<li>
|
|
<a href="/admin/blog"><i class="bi bi-newspaper"></i> Blog</a>
|
|
</li>
|
|
<li>
|
|
<a href="/admin/pages"
|
|
><i class="bi bi-file-text"></i> Custom Pages</a
|
|
>
|
|
</li>
|
|
<li>
|
|
<a href="/admin/media-library"
|
|
><i class="bi bi-images"></i> Media Library</a
|
|
>
|
|
</li>
|
|
<li>
|
|
<a href="/admin/menu"><i class="bi bi-list"></i> Menu</a>
|
|
</li>
|
|
<li>
|
|
<a href="/admin/settings" class="active"
|
|
><i class="bi bi-gear"></i> Settings</a
|
|
>
|
|
</li>
|
|
<li>
|
|
<a href="/admin/users"><i class="bi bi-people"></i> Users</a>
|
|
</li>
|
|
<li>
|
|
<a href="/admin/customers"
|
|
><i class="bi bi-person-hearts"></i> Customers</a
|
|
>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="main-content">
|
|
<div class="top-bar">
|
|
<div>
|
|
<h3><i class="bi bi-gear me-2"></i>Settings</h3>
|
|
<p class="mb-0 text-muted">Configure your store settings</p>
|
|
</div>
|
|
<div>
|
|
<button class="btn-logout" onclick="logout()">
|
|
<i class="bi bi-box-arrow-right"></i> Logout
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Settings Navigation -->
|
|
<nav class="settings-nav">
|
|
<a
|
|
class="settings-nav-item active"
|
|
onclick="showSection('general')"
|
|
data-section="general"
|
|
>
|
|
<i class="bi bi-sliders"></i> General
|
|
</a>
|
|
<a
|
|
class="settings-nav-item"
|
|
onclick="showSection('branding')"
|
|
data-section="branding"
|
|
>
|
|
<i class="bi bi-palette"></i> Branding
|
|
</a>
|
|
<a
|
|
class="settings-nav-item"
|
|
onclick="showSection('homepage')"
|
|
data-section="homepage"
|
|
>
|
|
<i class="bi bi-house"></i> Homepage
|
|
</a>
|
|
<a
|
|
class="settings-nav-item"
|
|
onclick="showSection('social')"
|
|
data-section="social"
|
|
>
|
|
<i class="bi bi-share"></i> Social
|
|
</a>
|
|
<a
|
|
class="settings-nav-item"
|
|
onclick="showSection('advanced')"
|
|
data-section="advanced"
|
|
>
|
|
<i class="bi bi-code-slash"></i> Advanced
|
|
</a>
|
|
</nav>
|
|
|
|
<!-- General Settings -->
|
|
<div class="settings-section active" id="section-general">
|
|
<div class="settings-card">
|
|
<div class="settings-card-header">
|
|
<div class="icon-box"><i class="bi bi-shop"></i></div>
|
|
<div>
|
|
<h5>Store Information</h5>
|
|
<p>Basic details about your store</p>
|
|
</div>
|
|
</div>
|
|
<div class="settings-card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label class="form-label">Store Name</label>
|
|
<input
|
|
type="text"
|
|
class="form-control"
|
|
id="storeName"
|
|
placeholder="My Awesome Store"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label class="form-label">Tagline</label>
|
|
<input
|
|
type="text"
|
|
class="form-control"
|
|
id="storeTagline"
|
|
placeholder="The best products, delivered"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label class="form-label">Contact Email</label>
|
|
<input
|
|
type="email"
|
|
class="form-control"
|
|
id="storeEmail"
|
|
placeholder="hello@store.com"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label class="form-label">Contact Phone</label>
|
|
<input
|
|
type="tel"
|
|
class="form-control"
|
|
id="storePhone"
|
|
placeholder="+1 (555) 123-4567"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="form-group mb-0">
|
|
<label class="form-label">Store Address</label>
|
|
<textarea
|
|
class="form-control"
|
|
id="storeAddress"
|
|
rows="2"
|
|
placeholder="123 Main Street, City, Country"
|
|
></textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="settings-card">
|
|
<div class="settings-card-header">
|
|
<div class="icon-box"><i class="bi bi-globe"></i></div>
|
|
<div>
|
|
<h5>Regional Settings</h5>
|
|
<p>Timezone and localization</p>
|
|
</div>
|
|
</div>
|
|
<div class="settings-card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label class="form-label">Timezone</label>
|
|
<select class="form-select" id="timezone">
|
|
<option value="America/Belize">America/Belize (CST)</option>
|
|
<option value="America/New_York">
|
|
America/New York (EST)
|
|
</option>
|
|
<option value="America/Chicago">
|
|
America/Chicago (CST)
|
|
</option>
|
|
<option value="America/Denver">America/Denver (MST)</option>
|
|
<option value="America/Los_Angeles">
|
|
America/Los Angeles (PST)
|
|
</option>
|
|
<option value="Europe/London">Europe/London (GMT)</option>
|
|
<option value="Europe/Paris">Europe/Paris (CET)</option>
|
|
<option value="Asia/Tokyo">Asia/Tokyo (JST)</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label class="form-label">Currency</label>
|
|
<select class="form-select" id="currency">
|
|
<option value="BZD">BZD - Belize Dollar</option>
|
|
<option value="USD">USD - US Dollar</option>
|
|
<option value="EUR">EUR - Euro</option>
|
|
<option value="GBP">GBP - British Pound</option>
|
|
<option value="CAD">CAD - Canadian Dollar</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Branding Settings -->
|
|
<div class="settings-section" id="section-branding">
|
|
<div class="settings-card">
|
|
<div class="settings-card-header">
|
|
<div class="icon-box"><i class="bi bi-image"></i></div>
|
|
<div>
|
|
<h5>Logo & Favicon</h5>
|
|
<p>Upload your brand images</p>
|
|
</div>
|
|
</div>
|
|
<div class="settings-card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label class="form-label">Site Logo</label>
|
|
<div
|
|
class="upload-box"
|
|
id="logoUpload"
|
|
onclick="selectLogo()"
|
|
>
|
|
<div id="logoPreview">
|
|
<i class="bi bi-image placeholder-icon"></i>
|
|
<div class="upload-text">Click to upload logo</div>
|
|
</div>
|
|
</div>
|
|
<input type="hidden" id="logoUrl" />
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label class="form-label">Favicon</label>
|
|
<div
|
|
class="upload-box"
|
|
id="faviconUpload"
|
|
onclick="selectFavicon()"
|
|
>
|
|
<div id="faviconPreview">
|
|
<i class="bi bi-window placeholder-icon"></i>
|
|
<div class="upload-text">Click to upload favicon</div>
|
|
</div>
|
|
</div>
|
|
<input type="hidden" id="faviconUrl" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="settings-card">
|
|
<div class="settings-card-header">
|
|
<div class="icon-box"><i class="bi bi-palette2"></i></div>
|
|
<div>
|
|
<h5>Brand Colors</h5>
|
|
<p>Customize your store colors</p>
|
|
</div>
|
|
</div>
|
|
<div class="settings-card-body">
|
|
<div class="row">
|
|
<div class="col-md-4">
|
|
<div class="form-group">
|
|
<label class="form-label">Primary Color</label>
|
|
<div class="color-picker-wrapper">
|
|
<div
|
|
class="color-preview"
|
|
id="primaryColorPreview"
|
|
style="background: #667eea"
|
|
onclick="document.getElementById('primaryColor').click()"
|
|
></div>
|
|
<input
|
|
type="color"
|
|
class="color-input"
|
|
id="primaryColor"
|
|
value="#667eea"
|
|
onchange="updateColorPreview('primary')"
|
|
/>
|
|
<input
|
|
type="text"
|
|
class="form-control"
|
|
id="primaryColorHex"
|
|
value="#667eea"
|
|
style="width: 120px"
|
|
onchange="updateColorFromHex('primary')"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="form-group">
|
|
<label class="form-label">Secondary Color</label>
|
|
<div class="color-picker-wrapper">
|
|
<div
|
|
class="color-preview"
|
|
id="secondaryColorPreview"
|
|
style="background: #764ba2"
|
|
onclick="
|
|
document.getElementById('secondaryColor').click()
|
|
"
|
|
></div>
|
|
<input
|
|
type="color"
|
|
class="color-input"
|
|
id="secondaryColor"
|
|
value="#764ba2"
|
|
onchange="updateColorPreview('secondary')"
|
|
/>
|
|
<input
|
|
type="text"
|
|
class="form-control"
|
|
id="secondaryColorHex"
|
|
value="#764ba2"
|
|
style="width: 120px"
|
|
onchange="updateColorFromHex('secondary')"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="form-group">
|
|
<label class="form-label">Accent Color</label>
|
|
<div class="color-picker-wrapper">
|
|
<div
|
|
class="color-preview"
|
|
id="accentColorPreview"
|
|
style="background: #f59e0b"
|
|
onclick="document.getElementById('accentColor').click()"
|
|
></div>
|
|
<input
|
|
type="color"
|
|
class="color-input"
|
|
id="accentColor"
|
|
value="#f59e0b"
|
|
onchange="updateColorPreview('accent')"
|
|
/>
|
|
<input
|
|
type="text"
|
|
class="form-control"
|
|
id="accentColorHex"
|
|
value="#f59e0b"
|
|
style="width: 120px"
|
|
onchange="updateColorFromHex('accent')"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Homepage Settings -->
|
|
<div class="settings-section" id="section-homepage">
|
|
<div class="settings-card">
|
|
<div class="settings-card-header">
|
|
<div class="icon-box"><i class="bi bi-card-image"></i></div>
|
|
<div>
|
|
<h5>Hero Section</h5>
|
|
<p>Configure homepage hero banner</p>
|
|
</div>
|
|
</div>
|
|
<div class="settings-card-body">
|
|
<div class="form-group">
|
|
<label class="form-label">Hero Title</label>
|
|
<input
|
|
type="text"
|
|
class="form-control"
|
|
id="heroTitle"
|
|
placeholder="Welcome to our store"
|
|
/>
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="form-label">Hero Subtitle</label>
|
|
<input
|
|
type="text"
|
|
class="form-control"
|
|
id="heroSubtitle"
|
|
placeholder="Discover amazing products"
|
|
/>
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="form-label">Hero Background</label>
|
|
<div
|
|
class="upload-box"
|
|
id="heroUpload"
|
|
onclick="selectHeroImage()"
|
|
>
|
|
<div id="heroPreview">
|
|
<i class="bi bi-card-image placeholder-icon"></i>
|
|
<div class="upload-text">Click to upload hero image</div>
|
|
</div>
|
|
</div>
|
|
<input type="hidden" id="heroImageUrl" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="settings-card">
|
|
<div class="settings-card-header">
|
|
<div class="icon-box"><i class="bi bi-toggles"></i></div>
|
|
<div>
|
|
<h5>Homepage Sections</h5>
|
|
<p>Show or hide homepage sections</p>
|
|
</div>
|
|
</div>
|
|
<div class="settings-card-body">
|
|
<div class="toggle-group">
|
|
<div class="toggle-item">
|
|
<div class="toggle-info">
|
|
<h6>Featured Products</h6>
|
|
<p>Show featured products carousel</p>
|
|
</div>
|
|
<div class="form-check form-switch">
|
|
<input
|
|
class="form-check-input"
|
|
type="checkbox"
|
|
id="showFeatured"
|
|
checked
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div class="toggle-item">
|
|
<div class="toggle-info">
|
|
<h6>Recent Products</h6>
|
|
<p>Show recently added products</p>
|
|
</div>
|
|
<div class="form-check form-switch">
|
|
<input
|
|
class="form-check-input"
|
|
type="checkbox"
|
|
id="showRecent"
|
|
checked
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div class="toggle-item">
|
|
<div class="toggle-info">
|
|
<h6>Portfolio Gallery</h6>
|
|
<p>Show portfolio section</p>
|
|
</div>
|
|
<div class="form-check form-switch">
|
|
<input
|
|
class="form-check-input"
|
|
type="checkbox"
|
|
id="showPortfolio"
|
|
checked
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div class="toggle-item">
|
|
<div class="toggle-info">
|
|
<h6>Newsletter Signup</h6>
|
|
<p>Show newsletter subscription form</p>
|
|
</div>
|
|
<div class="form-check form-switch">
|
|
<input
|
|
class="form-check-input"
|
|
type="checkbox"
|
|
id="showNewsletter"
|
|
checked
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Social Media Settings -->
|
|
<div class="settings-section" id="section-social">
|
|
<div class="settings-card">
|
|
<div class="settings-card-header">
|
|
<div class="icon-box"><i class="bi bi-share"></i></div>
|
|
<div>
|
|
<h5>Social Media Links</h5>
|
|
<p>Connect your social profiles</p>
|
|
</div>
|
|
</div>
|
|
<div class="settings-card-body">
|
|
<div class="social-links-grid">
|
|
<div class="social-input-group">
|
|
<i class="bi bi-facebook"></i>
|
|
<input
|
|
type="url"
|
|
id="socialFacebook"
|
|
placeholder="https://facebook.com/yourpage"
|
|
/>
|
|
</div>
|
|
<div class="social-input-group">
|
|
<i class="bi bi-instagram"></i>
|
|
<input
|
|
type="url"
|
|
id="socialInstagram"
|
|
placeholder="https://instagram.com/yourpage"
|
|
/>
|
|
</div>
|
|
<div class="social-input-group">
|
|
<i class="bi bi-twitter-x"></i>
|
|
<input
|
|
type="url"
|
|
id="socialTwitter"
|
|
placeholder="https://twitter.com/yourpage"
|
|
/>
|
|
</div>
|
|
<div class="social-input-group">
|
|
<i class="bi bi-youtube"></i>
|
|
<input
|
|
type="url"
|
|
id="socialYoutube"
|
|
placeholder="https://youtube.com/yourchannel"
|
|
/>
|
|
</div>
|
|
<div class="social-input-group">
|
|
<i class="bi bi-pinterest"></i>
|
|
<input
|
|
type="url"
|
|
id="socialPinterest"
|
|
placeholder="https://pinterest.com/yourpage"
|
|
/>
|
|
</div>
|
|
<div class="social-input-group">
|
|
<i class="bi bi-tiktok"></i>
|
|
<input
|
|
type="url"
|
|
id="socialTiktok"
|
|
placeholder="https://tiktok.com/@yourpage"
|
|
/>
|
|
</div>
|
|
<div class="social-input-group">
|
|
<i class="bi bi-whatsapp"></i>
|
|
<input
|
|
type="text"
|
|
id="socialWhatsapp"
|
|
placeholder="+1234567890"
|
|
/>
|
|
</div>
|
|
<div class="social-input-group">
|
|
<i class="bi bi-linkedin"></i>
|
|
<input
|
|
type="url"
|
|
id="socialLinkedin"
|
|
placeholder="https://linkedin.com/company/yourcompany"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Advanced Settings -->
|
|
<div class="settings-section" id="section-advanced">
|
|
<div class="settings-card">
|
|
<div class="settings-card-header">
|
|
<div class="icon-box"><i class="bi bi-search"></i></div>
|
|
<div>
|
|
<h5>SEO Settings</h5>
|
|
<p>Search engine optimization</p>
|
|
</div>
|
|
</div>
|
|
<div class="settings-card-body">
|
|
<div class="form-group">
|
|
<label class="form-label">Default Meta Title</label>
|
|
<input
|
|
type="text"
|
|
class="form-control"
|
|
id="metaTitle"
|
|
placeholder="My Store - Best Products Online"
|
|
/>
|
|
<div class="form-text">
|
|
Appears in browser tabs and search results
|
|
</div>
|
|
</div>
|
|
<div class="form-group mb-0">
|
|
<label class="form-label">Default Meta Description</label>
|
|
<textarea
|
|
class="form-control"
|
|
id="metaDescription"
|
|
rows="3"
|
|
placeholder="Discover our amazing collection of products..."
|
|
></textarea>
|
|
<div class="form-text">
|
|
Brief description for search engines (150-160 characters)
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="settings-card">
|
|
<div class="settings-card-header">
|
|
<div class="icon-box"><i class="bi bi-code-slash"></i></div>
|
|
<div>
|
|
<h5>Custom Code</h5>
|
|
<p>Add custom scripts and styles</p>
|
|
</div>
|
|
</div>
|
|
<div class="settings-card-body">
|
|
<div class="form-group">
|
|
<label class="form-label">
|
|
Header Code
|
|
<span class="badge bg-secondary">Optional</span>
|
|
</label>
|
|
<textarea
|
|
class="form-control font-monospace"
|
|
id="headerCode"
|
|
rows="4"
|
|
placeholder="<!-- Custom scripts or styles for <head> -->"
|
|
></textarea>
|
|
<div class="form-text">
|
|
Added before </head> tag. Use for analytics, fonts, etc.
|
|
</div>
|
|
</div>
|
|
<div class="form-group mb-0">
|
|
<label class="form-label">
|
|
Footer Code
|
|
<span class="badge bg-secondary">Optional</span>
|
|
</label>
|
|
<textarea
|
|
class="form-control font-monospace"
|
|
id="footerCode"
|
|
rows="4"
|
|
placeholder="<!-- Custom scripts for footer -->"
|
|
></textarea>
|
|
<div class="form-text">
|
|
Added before </body> tag. Use for tracking scripts.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="settings-card">
|
|
<div class="settings-card-header">
|
|
<div class="icon-box"><i class="bi bi-shield-check"></i></div>
|
|
<div>
|
|
<h5>Maintenance Mode</h5>
|
|
<p>Take your store offline temporarily</p>
|
|
</div>
|
|
</div>
|
|
<div class="settings-card-body">
|
|
<div class="toggle-group">
|
|
<div class="toggle-item">
|
|
<div class="toggle-info">
|
|
<h6>Enable Maintenance Mode</h6>
|
|
<p>
|
|
Visitors will see a maintenance page. Admin can still
|
|
access.
|
|
</p>
|
|
</div>
|
|
<div class="form-check form-switch">
|
|
<input
|
|
class="form-check-input"
|
|
type="checkbox"
|
|
id="maintenanceMode"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Save Bar -->
|
|
<div class="save-bar" id="saveBar">
|
|
<div
|
|
class="unsaved-text"
|
|
id="unsavedIndicator"
|
|
style="visibility: hidden"
|
|
>
|
|
<i class="bi bi-exclamation-circle"></i>
|
|
You have unsaved changes
|
|
</div>
|
|
<button class="btn btn-save" onclick="saveSettings()" id="saveBtn">
|
|
<i class="bi bi-check-lg"></i>
|
|
Save Settings
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Media Library Modal -->
|
|
<div id="mediaLibraryModal"></div>
|
|
|
|
<!-- Toast Container -->
|
|
<div
|
|
class="toast-container position-fixed bottom-0 end-0 p-3"
|
|
id="toastContainer"
|
|
></div>
|
|
|
|
<!-- Scripts -->
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
|
<script src="/admin/js/auth.js"></script>
|
|
<script src="/admin/js/media-library.js"></script>
|
|
<script>
|
|
// State
|
|
let settings = {};
|
|
let hasChanges = false;
|
|
let imageSelectCallback = null;
|
|
|
|
// Initialize
|
|
document.addEventListener("DOMContentLoaded", () => {
|
|
loadSettings();
|
|
setupChangeTracking();
|
|
});
|
|
|
|
// Show section
|
|
function showSection(section) {
|
|
// Update nav
|
|
document.querySelectorAll(".settings-nav-item").forEach((item) => {
|
|
item.classList.remove("active");
|
|
if (item.dataset.section === section) {
|
|
item.classList.add("active");
|
|
}
|
|
});
|
|
|
|
// Update sections
|
|
document.querySelectorAll(".settings-section").forEach((sec) => {
|
|
sec.classList.remove("active");
|
|
});
|
|
document.getElementById(`section-${section}`).classList.add("active");
|
|
}
|
|
|
|
// Load settings
|
|
async function loadSettings() {
|
|
try {
|
|
const response = await fetch("/api/settings", {
|
|
credentials: "include",
|
|
});
|
|
|
|
if (!response.ok) throw new Error("Failed to load settings");
|
|
|
|
settings = await response.json();
|
|
populateForm();
|
|
} catch (error) {
|
|
console.error("Error loading settings:", error);
|
|
showToast("Failed to load settings", "error");
|
|
}
|
|
}
|
|
|
|
// Populate form with settings
|
|
function populateForm() {
|
|
// General
|
|
document.getElementById("storeName").value = settings.storeName || "";
|
|
document.getElementById("storeTagline").value = settings.tagline || "";
|
|
document.getElementById("storeEmail").value = settings.email || "";
|
|
document.getElementById("storePhone").value = settings.phone || "";
|
|
document.getElementById("storeAddress").value = settings.address || "";
|
|
document.getElementById("timezone").value =
|
|
settings.timezone || "America/Belize";
|
|
document.getElementById("currency").value = settings.currency || "BZD";
|
|
|
|
// Branding
|
|
if (settings.logoUrl) {
|
|
updateImagePreview("logo", settings.logoUrl);
|
|
document.getElementById("logoUrl").value = settings.logoUrl;
|
|
}
|
|
if (settings.faviconUrl) {
|
|
updateImagePreview("favicon", settings.faviconUrl);
|
|
document.getElementById("faviconUrl").value = settings.faviconUrl;
|
|
}
|
|
if (settings.primaryColor) {
|
|
document.getElementById("primaryColor").value = settings.primaryColor;
|
|
document.getElementById("primaryColorHex").value =
|
|
settings.primaryColor;
|
|
document.getElementById("primaryColorPreview").style.background =
|
|
settings.primaryColor;
|
|
}
|
|
if (settings.secondaryColor) {
|
|
document.getElementById("secondaryColor").value =
|
|
settings.secondaryColor;
|
|
document.getElementById("secondaryColorHex").value =
|
|
settings.secondaryColor;
|
|
document.getElementById("secondaryColorPreview").style.background =
|
|
settings.secondaryColor;
|
|
}
|
|
if (settings.accentColor) {
|
|
document.getElementById("accentColor").value = settings.accentColor;
|
|
document.getElementById("accentColorHex").value =
|
|
settings.accentColor;
|
|
document.getElementById("accentColorPreview").style.background =
|
|
settings.accentColor;
|
|
}
|
|
|
|
// Homepage
|
|
document.getElementById("heroTitle").value = settings.heroTitle || "";
|
|
document.getElementById("heroSubtitle").value =
|
|
settings.heroSubtitle || "";
|
|
if (settings.heroImageUrl) {
|
|
updateImagePreview("hero", settings.heroImageUrl);
|
|
document.getElementById("heroImageUrl").value = settings.heroImageUrl;
|
|
}
|
|
document.getElementById("showFeatured").checked =
|
|
settings.showFeatured !== false;
|
|
document.getElementById("showRecent").checked =
|
|
settings.showRecent !== false;
|
|
document.getElementById("showPortfolio").checked =
|
|
settings.showPortfolio !== false;
|
|
document.getElementById("showNewsletter").checked =
|
|
settings.showNewsletter !== false;
|
|
|
|
// Social
|
|
document.getElementById("socialFacebook").value =
|
|
settings.socialFacebook || "";
|
|
document.getElementById("socialInstagram").value =
|
|
settings.socialInstagram || "";
|
|
document.getElementById("socialTwitter").value =
|
|
settings.socialTwitter || "";
|
|
document.getElementById("socialYoutube").value =
|
|
settings.socialYoutube || "";
|
|
document.getElementById("socialPinterest").value =
|
|
settings.socialPinterest || "";
|
|
document.getElementById("socialTiktok").value =
|
|
settings.socialTiktok || "";
|
|
document.getElementById("socialWhatsapp").value =
|
|
settings.socialWhatsapp || "";
|
|
document.getElementById("socialLinkedin").value =
|
|
settings.socialLinkedin || "";
|
|
|
|
// Advanced
|
|
document.getElementById("metaTitle").value = settings.metaTitle || "";
|
|
document.getElementById("metaDescription").value =
|
|
settings.metaDescription || "";
|
|
document.getElementById("headerCode").value = settings.headerCode || "";
|
|
document.getElementById("footerCode").value = settings.footerCode || "";
|
|
document.getElementById("maintenanceMode").checked =
|
|
settings.maintenanceMode === true;
|
|
}
|
|
|
|
// Setup change tracking
|
|
function setupChangeTracking() {
|
|
const inputs = document.querySelectorAll("input, textarea, select");
|
|
inputs.forEach((input) => {
|
|
input.addEventListener("change", markUnsaved);
|
|
input.addEventListener("input", markUnsaved);
|
|
});
|
|
}
|
|
|
|
// Mark as unsaved
|
|
function markUnsaved() {
|
|
hasChanges = true;
|
|
document.getElementById("unsavedIndicator").style.visibility =
|
|
"visible";
|
|
}
|
|
|
|
// Update color preview
|
|
function updateColorPreview(type) {
|
|
const color = document.getElementById(`${type}Color`).value;
|
|
document.getElementById(`${type}ColorPreview`).style.background = color;
|
|
document.getElementById(`${type}ColorHex`).value = color;
|
|
markUnsaved();
|
|
}
|
|
|
|
// Update color from hex
|
|
function updateColorFromHex(type) {
|
|
const hex = document.getElementById(`${type}ColorHex`).value;
|
|
if (/^#[0-9A-Fa-f]{6}$/.test(hex)) {
|
|
document.getElementById(`${type}Color`).value = hex;
|
|
document.getElementById(`${type}ColorPreview`).style.background = hex;
|
|
markUnsaved();
|
|
}
|
|
}
|
|
|
|
// Image selection
|
|
function selectLogo() {
|
|
openMediaLibrary((url) => {
|
|
document.getElementById("logoUrl").value = url;
|
|
updateImagePreview("logo", url);
|
|
markUnsaved();
|
|
});
|
|
}
|
|
|
|
function selectFavicon() {
|
|
openMediaLibrary((url) => {
|
|
document.getElementById("faviconUrl").value = url;
|
|
updateImagePreview("favicon", url);
|
|
markUnsaved();
|
|
});
|
|
}
|
|
|
|
function selectHeroImage() {
|
|
openMediaLibrary((url) => {
|
|
document.getElementById("heroImageUrl").value = url;
|
|
updateImagePreview("hero", url);
|
|
markUnsaved();
|
|
});
|
|
}
|
|
|
|
// Open media library
|
|
function openMediaLibrary(callback) {
|
|
if (typeof MediaLibrary !== "undefined") {
|
|
MediaLibrary.open({
|
|
onSelect: (media) => {
|
|
callback(media.url);
|
|
},
|
|
});
|
|
} else {
|
|
const url = prompt("Enter image URL:");
|
|
if (url) callback(url);
|
|
}
|
|
}
|
|
|
|
// Update image preview
|
|
function updateImagePreview(type, url) {
|
|
const previewId = `${type}Preview`;
|
|
const uploadId = `${type}Upload`;
|
|
|
|
const preview = document.getElementById(previewId);
|
|
const upload = document.getElementById(uploadId);
|
|
|
|
preview.innerHTML = `
|
|
<img src="${url}" alt="${type}" />
|
|
<div class="change-text"><i class="bi bi-pencil me-1"></i>Click to change</div>
|
|
`;
|
|
upload.classList.add("has-image");
|
|
}
|
|
|
|
// Save settings
|
|
async function saveSettings() {
|
|
const btn = document.getElementById("saveBtn");
|
|
btn.disabled = true;
|
|
btn.innerHTML =
|
|
'<span class="spinner-border spinner-border-sm me-2"></span>Saving...';
|
|
|
|
const data = {
|
|
// General
|
|
storeName: document.getElementById("storeName").value,
|
|
tagline: document.getElementById("storeTagline").value,
|
|
email: document.getElementById("storeEmail").value,
|
|
phone: document.getElementById("storePhone").value,
|
|
address: document.getElementById("storeAddress").value,
|
|
timezone: document.getElementById("timezone").value,
|
|
currency: document.getElementById("currency").value,
|
|
|
|
// Branding
|
|
logoUrl: document.getElementById("logoUrl").value,
|
|
faviconUrl: document.getElementById("faviconUrl").value,
|
|
primaryColor: document.getElementById("primaryColor").value,
|
|
secondaryColor: document.getElementById("secondaryColor").value,
|
|
accentColor: document.getElementById("accentColor").value,
|
|
|
|
// Homepage
|
|
heroTitle: document.getElementById("heroTitle").value,
|
|
heroSubtitle: document.getElementById("heroSubtitle").value,
|
|
heroImageUrl: document.getElementById("heroImageUrl").value,
|
|
showFeatured: document.getElementById("showFeatured").checked,
|
|
showRecent: document.getElementById("showRecent").checked,
|
|
showPortfolio: document.getElementById("showPortfolio").checked,
|
|
showNewsletter: document.getElementById("showNewsletter").checked,
|
|
|
|
// Social
|
|
socialFacebook: document.getElementById("socialFacebook").value,
|
|
socialInstagram: document.getElementById("socialInstagram").value,
|
|
socialTwitter: document.getElementById("socialTwitter").value,
|
|
socialYoutube: document.getElementById("socialYoutube").value,
|
|
socialPinterest: document.getElementById("socialPinterest").value,
|
|
socialTiktok: document.getElementById("socialTiktok").value,
|
|
socialWhatsapp: document.getElementById("socialWhatsapp").value,
|
|
socialLinkedin: document.getElementById("socialLinkedin").value,
|
|
|
|
// Advanced
|
|
metaTitle: document.getElementById("metaTitle").value,
|
|
metaDescription: document.getElementById("metaDescription").value,
|
|
headerCode: document.getElementById("headerCode").value,
|
|
footerCode: document.getElementById("footerCode").value,
|
|
maintenanceMode: document.getElementById("maintenanceMode").checked,
|
|
};
|
|
|
|
try {
|
|
const response = await fetch("/api/settings", {
|
|
method: "PUT",
|
|
headers: { "Content-Type": "application/json" },
|
|
credentials: "include",
|
|
body: JSON.stringify(data),
|
|
});
|
|
|
|
if (!response.ok) throw new Error("Failed to save settings");
|
|
|
|
hasChanges = false;
|
|
document.getElementById("unsavedIndicator").style.visibility =
|
|
"hidden";
|
|
showToast("Settings saved successfully!", "success");
|
|
} catch (error) {
|
|
console.error("Error saving settings:", error);
|
|
showToast("Failed to save settings", "error");
|
|
} finally {
|
|
btn.disabled = false;
|
|
btn.innerHTML = '<i class="bi bi-check-lg"></i> Save Settings';
|
|
}
|
|
}
|
|
|
|
// Show toast
|
|
function showToast(message, type = "info") {
|
|
const container = document.getElementById("toastContainer");
|
|
|
|
const bgClass =
|
|
{
|
|
success: "bg-success",
|
|
error: "bg-danger",
|
|
warning: "bg-warning",
|
|
info: "bg-info",
|
|
}[type] || "bg-info";
|
|
|
|
const icon =
|
|
{
|
|
success: "bi-check-circle",
|
|
error: "bi-x-circle",
|
|
warning: "bi-exclamation-triangle",
|
|
info: "bi-info-circle",
|
|
}[type] || "bi-info-circle";
|
|
|
|
const toast = document.createElement("div");
|
|
toast.className = `toast show ${bgClass} text-white`;
|
|
toast.innerHTML = `
|
|
<div class="d-flex align-items-center p-3">
|
|
<i class="bi ${icon} me-2"></i>
|
|
<div class="flex-grow-1">${escapeHtml(message)}</div>
|
|
<button type="button" class="btn-close btn-close-white" onclick="this.parentElement.parentElement.remove()"></button>
|
|
</div>
|
|
`;
|
|
|
|
container.appendChild(toast);
|
|
setTimeout(() => toast.remove(), 4000);
|
|
}
|
|
|
|
// Escape HTML
|
|
function escapeHtml(text) {
|
|
if (!text) return "";
|
|
const div = document.createElement("div");
|
|
div.textContent = text;
|
|
return div.innerHTML;
|
|
}
|
|
|
|
// Logout
|
|
function logout() {
|
|
window.location.href = "/admin/logout";
|
|
}
|
|
|
|
// Warn before leaving with unsaved changes
|
|
window.addEventListener("beforeunload", (e) => {
|
|
if (hasChanges) {
|
|
e.preventDefault();
|
|
e.returnValue = "";
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|