Files
SkyArtShop/website/admin/settings.html

1488 lines
46 KiB
HTML
Raw Normal View History

2026-01-18 02:22:05 -06:00
<!doctype html>
2025-12-14 01:54:40 -06:00
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
2026-01-18 02:22:05 -06:00
<title>Settings - Sky Art Shop Admin</title>
2025-12-14 01:54:40 -06:00
<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" />
2026-01-18 02:22:05 -06:00
<link rel="stylesheet" href="/admin/css/media-library.css" />
2025-12-14 01:54:40 -06:00
<style>
2026-01-18 02:22:05 -06:00
: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 {
2025-12-14 01:54:40 -06:00
background: white;
2026-01-18 02:22:05 -06:00
border: 2px solid #e2e8f0;
2025-12-14 01:54:40 -06:00
border-radius: 12px;
2026-01-18 02:22:05 -06:00
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;
2025-12-14 01:54:40 -06:00
}
2026-01-18 02:22:05 -06:00
.settings-card-header {
background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
padding: 20px 24px;
border-bottom: 1px solid #e2e8f0;
2025-12-14 01:54:40 -06:00
display: flex;
align-items: center;
2026-01-18 02:22:05 -06:00
gap: 12px;
2025-12-14 01:54:40 -06:00
}
2026-01-18 02:22:05 -06:00
.settings-card-header .icon-box {
width: 44px;
height: 44px;
background: var(--accent-gradient);
color: white;
border-radius: 10px;
2025-12-14 01:54:40 -06:00
display: flex;
align-items: center;
justify-content: center;
2026-01-18 02:22:05 -06:00
font-size: 1.2rem;
2025-12-14 01:54:40 -06:00
}
2026-01-18 02:22:05 -06:00
.settings-card-header h5 {
margin: 0;
font-weight: 600;
color: #334155;
2025-12-14 01:54:40 -06:00
}
2026-01-18 02:22:05 -06:00
.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;
2025-12-14 01:54:40 -06:00
display: flex;
align-items: center;
2026-01-18 02:22:05 -06:00
gap: 8px;
2025-12-14 01:54:40 -06:00
}
2026-01-18 02:22:05 -06:00
.form-label .badge {
font-size: 0.7rem;
font-weight: 500;
2025-12-14 01:54:40 -06:00
}
2026-01-18 02:22:05 -06:00
.form-control,
.form-select {
border-radius: 10px;
border: 2px solid #e2e8f0;
padding: 12px 16px;
transition: var(--transition);
2025-12-14 01:54:40 -06:00
}
2026-01-18 02:22:05 -06:00
.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;
2025-12-14 01:54:40 -06:00
border-radius: 12px;
2026-01-18 02:22:05 -06:00
padding: 30px;
2025-12-14 01:54:40 -06:00
text-align: center;
cursor: pointer;
2026-01-18 02:22:05 -06:00
transition: var(--transition);
background: #f8fafc;
2025-12-14 01:54:40 -06:00
}
2026-01-18 02:22:05 -06:00
.upload-box:hover {
2025-12-14 01:54:40 -06:00
border-color: #667eea;
2026-01-18 02:22:05 -06:00
background: rgba(102, 126, 234, 0.05);
2025-12-14 01:54:40 -06:00
}
2026-01-18 02:22:05 -06:00
.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;
2025-12-14 01:54:40 -06:00
}
2026-01-18 02:22:05 -06:00
.upload-box .change-text {
color: #667eea;
font-size: 0.85rem;
margin-top: 8px;
2025-12-14 01:54:40 -06:00
}
2026-01-18 02:22:05 -06:00
/* Color Picker */
2025-12-14 01:54:40 -06:00
.color-picker-wrapper {
display: flex;
align-items: center;
2026-01-18 02:22:05 -06:00
gap: 12px;
2025-12-14 01:54:40 -06:00
}
.color-preview {
width: 50px;
height: 50px;
2026-01-18 02:22:05 -06:00
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);
}
2025-12-14 01:54:40 -06:00
}
</style>
</head>
<body>
<div class="sidebar">
2026-01-18 02:22:05 -06:00
<div class="sidebar-brand">Sky Art Shop</div>
2025-12-14 01:54:40 -06:00
<ul class="sidebar-menu">
<li>
2026-01-01 22:24:30 -06:00
<a href="/admin/dashboard"
2025-12-14 01:54:40 -06:00
><i class="bi bi-speedometer2"></i> Dashboard</a
>
</li>
<li>
2026-01-01 22:24:30 -06:00
<a href="/admin/homepage"
2025-12-14 01:54:40 -06:00
><i class="bi bi-house"></i> Homepage Editor</a
>
</li>
<li>
2026-01-01 22:24:30 -06:00
<a href="/admin/products"><i class="bi bi-box"></i> Products</a>
2025-12-14 01:54:40 -06:00
</li>
<li>
2026-01-18 02:22:05 -06:00
<a href="/admin/portfolio"><i class="bi bi-easel"></i> Portfolio</a>
2025-12-14 01:54:40 -06:00
</li>
<li>
2026-01-01 22:24:30 -06:00
<a href="/admin/blog"><i class="bi bi-newspaper"></i> Blog</a>
2025-12-14 01:54:40 -06:00
</li>
<li>
2026-01-01 22:24:30 -06:00
<a href="/admin/pages"
2025-12-14 01:54:40 -06:00
><i class="bi bi-file-text"></i> Custom Pages</a
>
</li>
<li>
2026-01-01 22:24:30 -06:00
<a href="/admin/media-library"
2025-12-14 01:54:40 -06:00
><i class="bi bi-images"></i> Media Library</a
>
</li>
<li>
2026-01-01 22:24:30 -06:00
<a href="/admin/menu"><i class="bi bi-list"></i> Menu</a>
2025-12-14 01:54:40 -06:00
</li>
<li>
2026-01-01 22:24:30 -06:00
<a href="/admin/settings" class="active"
2025-12-14 01:54:40 -06:00
><i class="bi bi-gear"></i> Settings</a
>
</li>
<li>
2026-01-01 22:24:30 -06:00
<a href="/admin/users"><i class="bi bi-people"></i> Users</a>
2025-12-14 01:54:40 -06:00
</li>
2026-01-18 02:22:05 -06:00
<li>
<a href="/admin/customers"
><i class="bi bi-person-hearts"></i> Customers</a
>
</li>
2025-12-14 01:54:40 -06:00
</ul>
</div>
<div class="main-content">
<div class="top-bar">
<div>
2026-01-18 02:22:05 -06:00
<h3><i class="bi bi-gear me-2"></i>Settings</h3>
<p class="mb-0 text-muted">Configure your store settings</p>
2025-12-14 01:54:40 -06:00
</div>
<div>
<button class="btn-logout" onclick="logout()">
<i class="bi bi-box-arrow-right"></i> Logout
</button>
</div>
</div>
2026-01-18 02:22:05 -06:00
<!-- 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>
2025-12-14 01:54:40 -06:00
2026-01-18 02:22:05 -06:00
<!-- 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>
2025-12-14 01:54:40 -06:00
</div>
2026-01-18 02:22:05 -06:00
<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>
2025-12-24 00:13:23 -06:00
</div>
2026-01-18 02:22:05 -06:00
<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>
2025-12-14 01:54:40 -06:00
</div>
2026-01-18 02:22:05 -06:00
<div class="form-group mb-0">
<label class="form-label">Store Address</label>
<textarea
2025-12-24 00:13:23 -06:00
class="form-control"
2026-01-18 02:22:05 -06:00
id="storeAddress"
rows="2"
placeholder="123 Main Street, City, Country"
></textarea>
2025-12-14 01:54:40 -06:00
</div>
</div>
</div>
2026-01-18 02:22:05 -06:00
<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>
2025-12-14 01:54:40 -06:00
</div>
</div>
2026-01-18 02:22:05 -06:00
<!-- 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>
2025-12-14 01:54:40 -06:00
</div>
2026-01-18 02:22:05 -06:00
</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>
2025-12-14 01:54:40 -06:00
</div>
</div>
</div>
2026-01-18 02:22:05 -06:00
<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>
2025-12-14 01:54:40 -06:00
</div>
2026-01-18 02:22:05 -06:00
<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>
2025-12-14 01:54:40 -06:00
</div>
</div>
</div>
2026-01-18 02:22:05 -06:00
<!-- 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>
2025-12-14 01:54:40 -06:00
</div>
2026-01-18 02:22:05 -06:00
<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>
2025-12-14 01:54:40 -06:00
</div>
</div>
2026-01-18 02:22:05 -06:00
<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>
2025-12-14 01:54:40 -06:00
</div>
2026-01-18 02:22:05 -06:00
<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>
2025-12-14 01:54:40 -06:00
</div>
</div>
</div>
2026-01-18 02:22:05 -06:00
<!-- 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>
2025-12-14 01:54:40 -06:00
</div>
2026-01-18 02:22:05 -06:00
<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>
2025-12-14 01:54:40 -06:00
</div>
</div>
2026-01-18 02:22:05 -06:00
</div>
2025-12-14 01:54:40 -06:00
2026-01-18 02:22:05 -06:00
<!-- 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>
2025-12-14 01:54:40 -06:00
</div>
2026-01-18 02:22:05 -06:00
<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>
2025-12-14 01:54:40 -06:00
</div>
</div>
2026-01-18 02:22:05 -06:00
<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>
2025-12-14 01:54:40 -06:00
</div>
2026-01-18 02:22:05 -06:00
</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 &lt;/head&gt; tag. Use for analytics, fonts, etc.
</div>
2025-12-14 01:54:40 -06:00
</div>
2026-01-18 02:22:05 -06:00
<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 &lt;/body&gt; tag. Use for tracking scripts.
</div>
2025-12-14 01:54:40 -06:00
</div>
</div>
</div>
2026-01-18 02:22:05 -06:00
<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>
2025-12-14 01:54:40 -06:00
</div>
</div>
</div>
2026-01-18 02:22:05 -06:00
<!-- 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
2025-12-14 01:54:40 -06:00
</button>
</div>
</div>
2025-12-24 00:13:23 -06:00
<!-- Media Library Modal -->
2026-01-18 02:22:05 -06:00
<div id="mediaLibraryModal"></div>
<!-- Toast Container -->
2025-12-24 00:13:23 -06:00
<div
2026-01-18 02:22:05 -06:00
class="toast-container position-fixed bottom-0 end-0 p-3"
id="toastContainer"
></div>
2025-12-24 00:13:23 -06:00
2026-01-18 02:22:05 -06:00
<!-- Scripts -->
2025-12-14 01:54:40 -06:00
<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>
2026-01-18 02:22:05 -06:00
<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>
2025-12-14 01:54:40 -06:00
</body>
</html>