Initial commit: DashCaddy v1.0
Full codebase including API server (32 modules + routes), dashboard frontend, DashCA certificate distribution, installer script, and deployment skills.
This commit is contained in:
528
status/index.html
Normal file
528
status/index.html
Normal file
@@ -0,0 +1,528 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>DashCaddy</title>
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
|
||||
<meta http-equiv="Pragma" content="no-cache" />
|
||||
<meta http-equiv="Expires" content="0" />
|
||||
|
||||
<link rel="icon" href="/assets/dashcaddy-favicon.ico" sizes="any">
|
||||
<link rel="icon" type="image/png" sizes="192x192" href="/assets/icon-192.png">
|
||||
<link rel="icon" type="image/png" sizes="512x512" href="/assets/icon-512.png">
|
||||
<link rel="apple-touch-icon" href="/assets/apple-touch-icon.png">
|
||||
<link rel="manifest" href="/assets/site.webmanifest">
|
||||
<link rel="stylesheet" href="/assets/fonts.css">
|
||||
<link rel="preload" href="/assets/icons.svg" as="image" type="image/svg+xml">
|
||||
<link rel="preload" href="/assets/fonts/sami-grotesk/SamiGrotesk-Regular.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="/assets/fonts/sami-grotesk/SamiGrotesk-Medium.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="/assets/fonts/sami-grotesk/SamiGrotesk-Bold.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<meta name="theme-color" content="#0e1116">
|
||||
|
||||
<link rel="stylesheet" href="/css/themes.css">
|
||||
<link rel="stylesheet" href="/css/dashboard.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- TOTP Login Overlay -->
|
||||
<div id="totp-overlay">
|
||||
<div class="totp-card">
|
||||
<img class="totp-logo totp-logo-dark" src="/assets/dashcaddy-logo-dark.png" alt="DashCaddy" onerror="this.style.display='none'">
|
||||
<img class="totp-logo totp-logo-light" src="/assets/dashcaddy-logo-light.png" alt="DashCaddy" onerror="this.style.display='none'">
|
||||
<p class="subtitle">Enter your 6-digit authentication code</p>
|
||||
<div class="totp-digits" id="totp-digits">
|
||||
<input type="text" maxlength="1" inputmode="numeric" pattern="[0-9]" autocomplete="one-time-code">
|
||||
<input type="text" maxlength="1" inputmode="numeric" pattern="[0-9]">
|
||||
<input type="text" maxlength="1" inputmode="numeric" pattern="[0-9]">
|
||||
<input type="text" maxlength="1" inputmode="numeric" pattern="[0-9]">
|
||||
<input type="text" maxlength="1" inputmode="numeric" pattern="[0-9]">
|
||||
<input type="text" maxlength="1" inputmode="numeric" pattern="[0-9]">
|
||||
</div>
|
||||
<div class="totp-error" id="totp-error"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Top bar with logo and weather on same line, tools below -->
|
||||
<div class="bar">
|
||||
<div class="top-row">
|
||||
<!-- Logo and Weather grouped together -->
|
||||
<div class="brand-weather-group">
|
||||
<div id="brand" title="Click to customize logo and position">
|
||||
<img class="brand-logo-top brand-logo-dark" src="/assets/dashcaddy-logo-dark.png" alt="DashCaddy" loading="eager" decoding="sync" />
|
||||
<img class="brand-logo-top brand-logo-light" src="/assets/dashcaddy-logo-light.png" alt="DashCaddy" loading="eager" decoding="sync" />
|
||||
</div>
|
||||
|
||||
<!-- Weather widget directly next to logo -->
|
||||
<div class="weather-widget-container">
|
||||
<div id="weather-widget" class="weather-widget">
|
||||
<div class="weather-content">
|
||||
<div class="weather-icon">🌤️</div>
|
||||
<div class="weather-info">
|
||||
<div class="weather-location">--</div>
|
||||
<div class="weather-temp">--°</div>
|
||||
<div class="weather-condition">--</div>
|
||||
<div class="weather-wind">--</div>
|
||||
<button id="weather-settings" class="weather-settings-btn-bottom" aria-label="Weather settings">⚙️</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Digital Clock widget -->
|
||||
<div class="clock-widget-container">
|
||||
<div id="clock-widget" class="clock-widget">
|
||||
<div id="clock-render"></div>
|
||||
<button id="clock-settings" class="clock-settings-btn" aria-label="Clock settings">⚙️</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- License status + Reload Caddy Button - top right corner -->
|
||||
<div class="reload-caddy-container">
|
||||
<div class="theme-toggle-group">
|
||||
<button id="theme" class="theme-toggle-btn" aria-label="Cycle theme" title="Click to cycle themes">
|
||||
<span id="theme-icon">🎨</span> <span id="theme-label">Dark</span>
|
||||
</button>
|
||||
<button id="theme-customize-btn" class="theme-customize-link" title="Customize theme colors">Customize Theme</button>
|
||||
</div>
|
||||
<div id="license-status-topbar" class="license-status-topbar free" title="Click to manage license">
|
||||
<span id="license-topbar-icon">☆</span>
|
||||
<span id="license-topbar-text">FREE TIER</span>
|
||||
<span id="license-topbar-time"></span>
|
||||
</div>
|
||||
<button id="reload-caddy-top" aria-label="Reload Caddy configuration" style="padding: 10px 20px; font-size: 0.95rem; font-weight: 600; background: linear-gradient(135deg, #3498db 0%, #2980b9 100%); border: none; border-radius: 6px; color: white; cursor: pointer; box-shadow: 0 2px 6px rgba(52, 152, 219, 0.3); transition: all 0.2s ease;">
|
||||
🔄 Reload Caddy
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tools row below logo and weather -->
|
||||
<div class="tools-row">
|
||||
<!-- Primary actions (always visible) -->
|
||||
<div class="tools tools-primary">
|
||||
<div class="chip muted" id="stamp">last check: —</div>
|
||||
<button id="refresh"><span class="brand-spinner" aria-hidden="true"></span>Refresh</button>
|
||||
</div>
|
||||
|
||||
<!-- Collapsible sections -->
|
||||
<div class="tools-sections">
|
||||
<div class="tools-section" data-section="status">
|
||||
<button class="tools-section-header" aria-expanded="false">
|
||||
<span class="tools-section-arrow">▸</span>
|
||||
<span class="tools-section-label">Status</span>
|
||||
</button>
|
||||
<div class="tools-section-items">
|
||||
<button id="container-stats-btn" aria-label="Container resource monitor">📊 Monitor</button>
|
||||
<button id="health-check-btn" aria-label="Service health dashboard">🏥 Health</button>
|
||||
<button id="updates-btn" aria-label="Container updates">⬆️ Updates</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tools-section" data-section="tools">
|
||||
<button class="tools-section-header" aria-expanded="false">
|
||||
<span class="tools-section-arrow">▸</span>
|
||||
<span class="tools-section-label">Tools</span>
|
||||
</button>
|
||||
<div class="tools-section-items">
|
||||
<button id="view-error-logs" aria-label="View error logs">📋 Logs</button>
|
||||
<button id="manage-notifications" aria-label="Manage notifications">🔔 Alerts</button>
|
||||
<button id="audit-log-btn" aria-label="Audit log">📜 Audit</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tools-section" data-section="admin">
|
||||
<button class="tools-section-header" aria-expanded="false">
|
||||
<span class="tools-section-arrow">▸</span>
|
||||
<span class="tools-section-label">Admin</span>
|
||||
</button>
|
||||
<div class="tools-section-items">
|
||||
<button id="manage-tokens" aria-label="Manage API tokens">🔑 Tokens</button>
|
||||
<button id="export-dashboard" aria-label="Export dashboard configuration">📤 Export</button>
|
||||
<button id="import-dashboard" aria-label="Import dashboard configuration">📥 Import</button>
|
||||
<button id="backup-restore-btn" aria-label="Backup and restore">💾 Backup</button>
|
||||
<button id="license-btn" aria-label="License management" onclick="window.openLicenseModal && window.openLicenseModal()">🔑 License</button>
|
||||
<button id="api-docs-btn" aria-label="API documentation" onclick="window.open('/api/docs', '_blank')">📖 API</button>
|
||||
<button id="help-errors-btn" aria-label="Troubleshooting guide" onclick="window.open('/help-errors.html', '_blank')">❓ Help</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Top Anchor Row -->
|
||||
<div class="top">
|
||||
<!-- DNS cards rendered dynamically from config by renderDnsCards() -->
|
||||
|
||||
<div class="card" data-app="internet" data-status="off">
|
||||
<span id="internet-dot" class="dot bad at-bl"></span>
|
||||
<div class="row">
|
||||
<div class="logo-wrap">
|
||||
<svg viewBox="0 0 24 24" class="service-icon">
|
||||
<circle cx="12" cy="12" r="10" fill="#27ae60"/>
|
||||
<path d="M12 2c-2.5 4-2.5 14 0 18M12 2c2.5 4 2.5 14 0 18M2 12h20" stroke="white" stroke-width="1.5"/>
|
||||
<path d="M4.5 7.5c3-1.5 6-1.5 9 0M4.5 16.5c3 1.5 6 1.5 9 0" stroke="white" stroke-width="1"/>
|
||||
<path d="M10.5 7.5c3-1.5 6-1.5 9 0M10.5 16.5c3 1.5 6 1.5 9 0" stroke="white" stroke-width="1"/>
|
||||
</svg>
|
||||
</div>
|
||||
<span class="name">Internet</span>
|
||||
<span class="spacer"></span>
|
||||
<span id="internet-pill" class="badge off">OFF</span>
|
||||
</div>
|
||||
<div class="response-row">
|
||||
<span id="internet-time" class="response-time">--</span>
|
||||
</div>
|
||||
<div class="btn-row"><!-- No button for Internet --></div>
|
||||
</div>
|
||||
|
||||
<div class="card" data-app="auth" data-status="off" id="auth-card">
|
||||
<span id="auth-dot" class="dot bad at-bl"></span>
|
||||
<div class="row">
|
||||
<div class="logo-wrap">
|
||||
<svg viewBox="0 0 24 24" class="service-icon">
|
||||
<rect x="6" y="10" width="12" height="10" rx="2" fill="#8FD6FF"/>
|
||||
<path d="M8 10V7a4 4 0 0 1 8 0v3" stroke="#e8ecf5" stroke-width="2" fill="none"/>
|
||||
<circle cx="12" cy="15" r="1.5" fill="#0b0f1a"/>
|
||||
<line x1="12" y1="16.5" x2="12" y2="18" stroke="#0b0f1a" stroke-width="1.5" stroke-linecap="round"/>
|
||||
</svg>
|
||||
</div>
|
||||
<span class="name">Auth</span>
|
||||
<span class="spacer"></span>
|
||||
<span id="auth-pill" class="badge off">NO</span>
|
||||
</div>
|
||||
<div class="response-row">
|
||||
<span id="auth-status-text" class="response-time" style="font-size: 0.7rem;">Not configured</span>
|
||||
</div>
|
||||
<div class="btn-row">
|
||||
<button id="auth-settings-btn">Settings</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card" data-app="ca" data-status="off">
|
||||
<span id="dot-ca-grid" class="dot bad at-bl"></span>
|
||||
<div class="row">
|
||||
<div class="logo-wrap">
|
||||
<span style="font-size: 28px; display: flex; align-items: center; justify-content: center; width: 100%; height: 100%;">🔐</span>
|
||||
</div>
|
||||
<span class="name">DashCA</span>
|
||||
<span class="spacer"></span>
|
||||
<span id="badge-ca" class="badge off">OFF</span>
|
||||
</div>
|
||||
<div class="response-row">
|
||||
<span id="time-ca" class="response-time">--</span>
|
||||
</div>
|
||||
<div class="health-row" id="health-ca">
|
||||
<span id="uptime-ca" class="uptime-chip">--</span>
|
||||
<div class="uptime-mini-bar"><div class="fill" id="uptime-bar-ca" style="width: 0%"></div></div>
|
||||
</div>
|
||||
<div class="btn-row">
|
||||
<button class="creds-btn" id="creds-btn-ca" title="Auto-login credentials">🔑</button>
|
||||
<button class="options-btn" id="options-btn-ca" title="Edit service settings">⚙️</button>
|
||||
<button class="delete-btn" id="delete-btn-ca" title="Delete this service">🗑️</button>
|
||||
<button id="ca-open">Open</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- App/service grid -->
|
||||
<div id="cards" class="grid"></div>
|
||||
|
||||
<!-- App Selector Button -->
|
||||
<div style="text-align: center; margin: 32px 0; display: flex; justify-content: center; gap: 16px; flex-wrap: wrap;">
|
||||
<button id="add-service-btn" style="padding: 12px 32px; font-size: 1.1rem; font-weight: 600;">📱 App Selector</button>
|
||||
<button id="add-service" style="padding: 12px 32px; font-size: 1.1rem; font-weight: 600;" aria-label="Add new app manually">+ Add App Manually</button>
|
||||
<button id="arr-setup-btn" style="padding: 12px 32px; font-size: 1.1rem; font-weight: 600; background: linear-gradient(135deg, #e74c3c 0%, #9b59b6 100%); border: none;">🎬 Smart Arr Connect</button>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Initial Setup Wizard -->
|
||||
<div id="setup-wizard" class="setup-wizard" style="display: none;">
|
||||
<div class="setup-wizard-content">
|
||||
<!-- Step 1: Welcome -->
|
||||
<div class="setup-step" id="setup-step-1" style="display: block;">
|
||||
<h2 style="margin: 0 0 16px; text-align: center;">Welcome to DashCaddy! 🎉</h2>
|
||||
<p style="text-align: center; color: var(--muted); margin-bottom: 32px;">
|
||||
Let's set up your self-hosted app dashboard. This will only take a few minutes.
|
||||
</p>
|
||||
|
||||
<!-- Timezone (universal, applies to all config types) -->
|
||||
<div style="margin-bottom: 24px; padding: 16px; background: var(--card-bg); border-radius: 8px; border: 1px solid var(--border);">
|
||||
<label class="form-label-accent" for="setup-timezone">Your Timezone</label>
|
||||
<select id="setup-timezone" class="form-input-lg" style="width: 100%;">
|
||||
<!-- Populated by setup-wizard.js with IANA timezones, auto-detected -->
|
||||
</select>
|
||||
<div class="form-hint">
|
||||
Auto-detected from your browser. All deployed apps will use this timezone.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 class="heading-accent-lg">Choose your configuration:</h3>
|
||||
|
||||
<div class="setup-options">
|
||||
<label class="setup-option" data-preset="simple">
|
||||
<input type="radio" name="config-type" value="simple" />
|
||||
<div class="setup-option-content">
|
||||
<div class="setup-option-icon">🚀</div>
|
||||
<div class="setup-option-title">Simple</div>
|
||||
<div class="setup-option-desc">Access apps via IP:Port only. No DNS or SSL setup needed.</div>
|
||||
<div class="setup-option-example">Example: http://<your-ip>:8080</div>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<label class="setup-option" data-preset="homelab">
|
||||
<input type="radio" name="config-type" value="homelab" checked />
|
||||
<div class="setup-option-content">
|
||||
<div class="setup-option-icon">🏠</div>
|
||||
<div class="setup-option-title">Professional Home Lab</div>
|
||||
<div class="setup-option-desc">Custom TLD + Private DNS + Internal CA. Full HTTPS with your own certificate authority.</div>
|
||||
<div class="setup-option-example">Example: https://uptime.home</div>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<label class="setup-option" data-preset="public">
|
||||
<input type="radio" name="config-type" value="public" />
|
||||
<div class="setup-option-content">
|
||||
<div class="setup-option-icon">🌍</div>
|
||||
<div class="setup-option-title">Public Server</div>
|
||||
<div class="setup-option-desc">Real domain + Public DNS + Let's Encrypt. Internet-accessible with trusted SSL.</div>
|
||||
<div class="setup-option-example">Example: https://cloud.example.com</div>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<label class="setup-option" data-preset="custom">
|
||||
<input type="radio" name="config-type" value="custom" />
|
||||
<div class="setup-option-content">
|
||||
<div class="setup-option-icon">⚙️</div>
|
||||
<div class="setup-option-title">Custom</div>
|
||||
<div class="setup-option-desc">I'll configure everything myself. Show me all options.</div>
|
||||
<div class="setup-option-example">Full control over every setting</div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="setup-wizard-buttons">
|
||||
<button id="setup-skip" style="margin-right: auto; background: transparent; border: 1px solid var(--muted); color: var(--muted);">Skip Setup</button>
|
||||
<button id="setup-step-1-next" class="setup-btn-primary">Continue →</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 2: Home Lab Configuration -->
|
||||
<div class="setup-step" id="setup-step-homelab" style="display: none;">
|
||||
<h2 style="margin: 0 0 8px;">Professional Home Lab Setup</h2>
|
||||
<p class="setup-desc">Configure your custom TLD and certificate authority</p>
|
||||
|
||||
<div style="display: grid; gap: 24px;">
|
||||
<!-- Custom TLD -->
|
||||
<div>
|
||||
<label class="form-label-accent">
|
||||
🌐 Custom Top-Level Domain (TLD)
|
||||
</label>
|
||||
<input type="text" id="setup-tld" value=".home" placeholder=".home"
|
||||
class="form-input-lg" />
|
||||
<div class="form-hint">
|
||||
Your apps will use this TLD. Examples: .sami, .home, .lab, .local, .internal
|
||||
</div>
|
||||
<div style="font-size: 0.85rem; color: var(--accent); margin-top: 8px; font-weight: 500;">
|
||||
📱 Preview: uptime<span id="tld-preview">.home</span>, nextcloud<span id="tld-preview-2">.home</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Certificate Authority Name -->
|
||||
<div>
|
||||
<label class="form-label-accent">
|
||||
🔒 Certificate Authority Name
|
||||
</label>
|
||||
<input type="text" id="setup-ca-name" value="" placeholder="My Home Lab Root CA"
|
||||
class="form-input-lg" />
|
||||
<div class="form-hint">
|
||||
This name appears in browser certificate details. Make it memorable!
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- DNS Server Configuration -->
|
||||
<div>
|
||||
<label class="form-label-accent">
|
||||
🗂️ DNS Server (Technitium)
|
||||
</label>
|
||||
<div style="display: grid; grid-template-columns: 1fr auto; gap: 8px;">
|
||||
<input type="text" id="setup-dns-ip" value="" placeholder="DNS server IP"
|
||||
style="padding: 12px; background: var(--card-bg); color: var(--fg); border: 1px solid var(--border); border-radius: 6px; font-size: 1rem;" />
|
||||
<input type="number" id="setup-dns-port" value="5380" placeholder="5380"
|
||||
style="width: 100px; padding: 12px; background: var(--card-bg); color: var(--fg); border: 1px solid var(--border); border-radius: 6px; font-size: 1rem;" />
|
||||
</div>
|
||||
<div class="form-hint">
|
||||
DashCaddy will automatically create DNS records for your apps
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- DNS Admin Token -->
|
||||
<div>
|
||||
<label class="form-label-accent">
|
||||
🔑 Technitium Admin Token
|
||||
</label>
|
||||
<input type="password" id="setup-dns-token" placeholder="Paste your admin token here"
|
||||
class="form-input-lg" />
|
||||
<details style="margin-top: 8px;">
|
||||
<summary style="cursor: pointer; color: var(--muted); font-size: 0.85rem;">ℹ️ How to get your token</summary>
|
||||
<div style="margin-top: 8px; padding: 12px; background: color-mix(in srgb, var(--accent) 5%, transparent); border-radius: 6px; font-size: 0.85rem;">
|
||||
<ol style="margin: 0; padding-left: 20px; color: var(--muted);">
|
||||
<li>Open Technitium DNS web panel</li>
|
||||
<li>Go to <strong>Settings → API</strong></li>
|
||||
<li>Create a new token with <strong>"Administration"</strong> permission</li>
|
||||
<li>Copy the token and paste it here</li>
|
||||
</ol>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="setup-wizard-buttons">
|
||||
<button id="setup-homelab-back">← Back</button>
|
||||
<button id="setup-homelab-next" class="setup-btn-primary">Continue →</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 3: Simple Configuration -->
|
||||
<div class="setup-step" id="setup-step-simple" style="display: none;">
|
||||
<h2 style="margin: 0 0 8px;">Simple Setup</h2>
|
||||
<p class="setup-desc">Access your apps directly via IP addresses and ports</p>
|
||||
|
||||
<div style="padding: 24px; background: color-mix(in srgb, var(--accent) 5%, transparent); border-radius: 12px; border: 1px solid var(--border);">
|
||||
<h3 style="margin: 0 0 16px; color: var(--accent);">✓ What you'll have:</h3>
|
||||
<ul style="margin: 0; padding-left: 20px; line-height: 1.8;">
|
||||
<li>Direct access via IP:Port (e.g., http://<your-ip>:8080)</li>
|
||||
<li>No DNS configuration needed</li>
|
||||
<li>No SSL/certificate setup</li>
|
||||
<li>Apps work immediately after deployment</li>
|
||||
</ul>
|
||||
|
||||
<h3 class="heading-accent-lg">⚠️ Limitations:</h3>
|
||||
<ul style="margin: 0; padding-left: 20px; line-height: 1.8; color: var(--muted);">
|
||||
<li>Must remember IP:Port for each app</li>
|
||||
<li>No pretty URLs</li>
|
||||
<li>HTTP only (no HTTPS encryption)</li>
|
||||
<li>Not recommended for sensitive data</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 24px; padding: 16px; background: var(--card-bg); border-radius: 8px; border: 1px solid var(--border);">
|
||||
<label style="display: block; margin-bottom: 8px; font-weight: 500;">
|
||||
Default Server IP Address
|
||||
</label>
|
||||
<input type="text" id="setup-simple-ip" value="localhost" placeholder="Your LAN IP"
|
||||
style="width: 100%; padding: 10px; background: var(--bg); color: var(--fg); border: 1px solid var(--border); border-radius: 6px;" />
|
||||
<div class="form-hint">
|
||||
Use "localhost" for same-host deployments, or your server's IP
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="setup-wizard-buttons">
|
||||
<button id="setup-simple-back">← Back</button>
|
||||
<button id="setup-simple-next" class="setup-btn-primary">Continue →</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 4: Public Server Configuration -->
|
||||
<div class="setup-step" id="setup-step-public" style="display: none;">
|
||||
<h2 style="margin: 0 0 8px;">Public Server Setup</h2>
|
||||
<p class="setup-desc">Configure for internet-accessible apps with Let's Encrypt SSL</p>
|
||||
|
||||
<div style="display: grid; gap: 20px;">
|
||||
<div>
|
||||
<label class="form-label-accent">
|
||||
🌍 Your Domain
|
||||
</label>
|
||||
<input type="text" id="setup-public-domain" placeholder="example.com"
|
||||
class="form-input-lg" />
|
||||
<div class="form-hint">
|
||||
Your registered domain name (must point to this server)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label-accent">
|
||||
📧 Email for Let's Encrypt
|
||||
</label>
|
||||
<input type="email" id="setup-public-email" placeholder="admin@example.com"
|
||||
class="form-input-lg" />
|
||||
<div class="form-hint">
|
||||
Required for Let's Encrypt certificate renewal notifications
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="padding: 16px; background: color-mix(in srgb, var(--accent) 5%, transparent); border-radius: 8px; border: 1px solid var(--accent);">
|
||||
<h4 class="heading-accent-md">⚠️ Requirements:</h4>
|
||||
<ul style="margin: 0; padding-left: 20px; font-size: 0.9rem; line-height: 1.6;">
|
||||
<li>Port 80 and 443 must be open to the internet</li>
|
||||
<li>Domain DNS must point to this server's public IP</li>
|
||||
<li>Server must be reachable from the internet</li>
|
||||
<li>You'll need to configure DNS manually for each subdomain</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="setup-wizard-buttons">
|
||||
<button id="setup-public-back">← Back</button>
|
||||
<button id="setup-public-next" class="setup-btn-primary">Continue →</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 5: Summary & Confirmation -->
|
||||
<div class="setup-step" id="setup-step-summary" style="display: none;">
|
||||
<h2 style="margin: 0 0 8px;">Review Your Configuration</h2>
|
||||
<p class="setup-desc">Make sure everything looks correct before finishing</p>
|
||||
|
||||
<div id="setup-summary-content" style="padding: 24px; background: var(--card-bg); border-radius: 12px; border: 1px solid var(--border);">
|
||||
<!-- Will be filled dynamically -->
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 24px; padding: 16px; background: color-mix(in srgb, var(--ok-fg) 10%, transparent); border-radius: 8px; border: 1px solid var(--ok-fg);">
|
||||
<strong style="color: var(--ok-fg);">✓ You can change these settings later</strong>
|
||||
<div style="font-size: 0.85rem; margin-top: 4px; color: var(--muted);">
|
||||
Go to Settings → System Configuration to edit your setup anytime
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="setup-wizard-buttons">
|
||||
<button id="setup-summary-back">← Back</button>
|
||||
<button id="setup-finish" class="setup-btn-primary" style="background: var(--ok-bg); border-color: var(--ok-fg); color: var(--ok-fg);">✓ Finish Setup</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dashboard Widget Visibility (load before paint) -->
|
||||
<script>
|
||||
(function() {
|
||||
var widgets = [
|
||||
{ id: 'weather', selector: '.weather-widget-container' },
|
||||
{ id: 'digital-clock', selector: '.clock-widget-container' }
|
||||
];
|
||||
for (var i = 0; i < widgets.length; i++) {
|
||||
var key = 'widget-' + widgets[i].id + '-enabled';
|
||||
var val = localStorage.getItem(key);
|
||||
// Default to enabled if never set
|
||||
if (val === 'false') {
|
||||
var el = document.querySelector(widgets[i].selector);
|
||||
if (el) el.style.display = 'none';
|
||||
}
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<!-- Clock rendering is handled by the bundled clock.js module -->
|
||||
|
||||
<footer class="dashcaddy-footer">
|
||||
<span class="footer-copy">© <script>document.write(new Date().getFullYear())</script></span>
|
||||
<img src="/assets/sami7777-logo.png" alt="samiahmed7777" class="footer-logo">
|
||||
</footer>
|
||||
|
||||
<!-- Bundled JS (built with: npm run build) -->
|
||||
<script src="/dist/core.js" defer></script>
|
||||
<script src="/dist/features.js" defer></script>
|
||||
<script src="/dist/onboarding.js" defer></script>
|
||||
<script src="/dist/init.js" defer></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user