- DashcamScreen: Download + Delete as IconButton with Icons.Filled - DownloadsScreen: CloudUpload + Delete as IconButton - No text labels, just clean Material icons
182 lines
9.4 KiB
HTML
182 lines
9.4 KiB
HTML
<!DOCTYPE html>
|
||
<html data-bs-theme="light" lang="en">
|
||
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
||
<title>{% block title %}Yaris OBD – Remote{% endblock %}</title>
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link href="https://fonts.googleapis.com/css2?family=Racing+Sans+One&display=swap" rel="stylesheet">
|
||
<link rel="stylesheet" href="{{ url_for('static', filename='bootstrap/css/bootstrap.min.css') }}">
|
||
<link rel="stylesheet" href="{{ url_for('static', filename='yaris.css') }}">
|
||
<link rel="stylesheet" href="{{ url_for('static', filename='fonts/fontawesome-all.min.css') }}">
|
||
<style>
|
||
/* Remote server badge: hide text when sidebar is collapsed */
|
||
.app-sidebar.collapsed .sidebar-env-badge { display: none; }
|
||
/* User footer: hide text, keep icon centered */
|
||
.sidebar-user-text { transition: opacity .15s; white-space: nowrap; }
|
||
.app-sidebar.collapsed .sidebar-user-text { opacity: 0; pointer-events: none; width: 0; overflow: hidden; }
|
||
.app-sidebar.collapsed .sidebar-user-footer { justify-content: center; padding: .5rem 0; }
|
||
</style>
|
||
{% block styles %}{% endblock %}
|
||
</head>
|
||
|
||
<body id="page-top">
|
||
|
||
{# ── Desktop sidebar ─────────────────────────────────────────────────── #}
|
||
<nav id="app-sidebar" class="app-sidebar d-none d-md-flex flex-column">
|
||
<a class="sidebar-brand" href="{{ url_for('portal_index') }}" aria-label="Home">
|
||
<span class="sidebar-brand-logo">YARIS-OBD</span>
|
||
</a>
|
||
<div class="px-3 pb-1 sidebar-env-badge">
|
||
<span class="badge bg-warning text-dark w-100 text-center" style="font-size:.65rem;letter-spacing:.04em;">
|
||
<i class="fas fa-cloud fa-fw"></i> Remote server
|
||
</span>
|
||
</div>
|
||
<hr class="sidebar-divider">
|
||
<ul class="nav flex-column flex-grow-1">
|
||
<li class="nav-item">
|
||
<a class="nav-link{% if request.endpoint == 'portal_index' %} active{% endif %}" href="{{ url_for('portal_index') }}">
|
||
<i class="fas fa-chart-line fa-fw"></i><span>Overview</span>
|
||
</a>
|
||
</li>
|
||
<li class="nav-item">
|
||
<a class="nav-link{% if request.endpoint == 'portal_history' %} active{% endif %}" href="{{ url_for('portal_history') }}">
|
||
<i class="fas fa-route fa-fw"></i><span>Trip history</span>
|
||
</a>
|
||
</li>
|
||
<li class="nav-item">
|
||
<a class="nav-link{% if request.endpoint == 'portal_dashcam' %} active{% endif %}" href="{{ url_for('portal_dashcam') }}">
|
||
<i class="fas fa-video fa-fw"></i><span>Dashcam archive</span>
|
||
</a>
|
||
</li>
|
||
<li class="nav-item">
|
||
<a class="nav-link{% if request.endpoint == 'portal_dtc_page' %} active{% endif %}" href="{{ url_for('portal_dtc_page') }}">
|
||
<i class="fas fa-exclamation-triangle fa-fw"></i><span>DTC history</span>
|
||
</a>
|
||
</li>
|
||
<li class="nav-item">
|
||
<a class="nav-link{% if request.endpoint == 'portal_device_settings_page' %} active{% endif %}" href="{{ url_for('portal_device_settings_page') }}">
|
||
<i class="fas fa-sliders-h fa-fw"></i><span>Device settings</span>
|
||
</a>
|
||
</li>
|
||
</ul>
|
||
<div class="px-3 pb-2 mt-auto text-muted d-flex align-items-center gap-1 sidebar-user-footer" style="font-size:.75rem;">
|
||
<i class="fas fa-user fa-fw flex-shrink-0"></i>
|
||
<span class="sidebar-user-text">
|
||
{{ current_user.username }}
|
||
·
|
||
<a href="{{ url_for('change_password_page') }}" class="text-muted">Password</a>
|
||
·
|
||
<a href="{{ url_for('logout') }}" class="text-muted">Logout</a>
|
||
</span>
|
||
</div>
|
||
<button class="sidebar-collapse-btn" id="sidebarToggle" type="button" aria-label="Collapse sidebar">
|
||
<i class="fas fa-chevron-left"></i>
|
||
</button>
|
||
</nav>
|
||
|
||
{# ── Main content area ────────────────────────────────────────────────── #}
|
||
<div id="content-wrapper">
|
||
|
||
{# Top bar #}
|
||
<nav class="topbar navbar navbar-light bg-white shadow-sm">
|
||
<div class="container-fluid px-3 gap-2">
|
||
<a class="navbar-brand d-flex d-md-none align-items-center gap-2 text-decoration-none" href="{{ url_for('portal_index') }}">
|
||
<span style="font-family:'Racing Sans One','Arial Black',sans-serif;font-size:1.3rem;font-style:italic;color:#1c1c1e;">YARIS-OBD</span>
|
||
<span class="badge bg-warning text-dark ms-1" style="font-size:.6rem;">Remote</span>
|
||
</a>
|
||
<div class="d-flex align-items-center gap-2">
|
||
<select class="form-select form-select-sm" id="portal-device-selector" style="width:auto;min-width:10rem;" aria-label="Select device">
|
||
<option value="">Loading…</option>
|
||
</select>
|
||
</div>
|
||
<div class="d-flex align-items-center gap-2">
|
||
<span class="text-muted small d-none d-sm-inline">{{ current_user.username }}</span>
|
||
<a href="{{ url_for('logout') }}" class="btn btn-outline-secondary btn-sm" title="Logout">
|
||
<i class="fas fa-sign-out-alt fa-fw"></i>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</nav>
|
||
|
||
<main class="container-fluid px-3 px-md-4 main-content">
|
||
{% block content %}{% endblock %}
|
||
</main>
|
||
|
||
<footer class="bg-white border-top text-center py-3 small text-muted d-none d-md-block">
|
||
© vroom vroom yaris de course 2023 — remote server
|
||
</footer>
|
||
</div>
|
||
|
||
{# ── Mobile bottom navigation ──────────────────────────────────────────── #}
|
||
<nav class="mobile-bottom-nav d-flex d-md-none" aria-label="Main navigation">
|
||
<a class="mobile-nav-item{% if request.endpoint == 'portal_index' %} active{% endif %}" href="{{ url_for('portal_index') }}">
|
||
<i class="fas fa-chart-line"></i>
|
||
<span>Overview</span>
|
||
</a>
|
||
<a class="mobile-nav-item{% if request.endpoint == 'portal_history' %} active{% endif %}" href="{{ url_for('portal_history') }}">
|
||
<i class="fas fa-route"></i>
|
||
<span>History</span>
|
||
</a>
|
||
<a class="mobile-nav-item{% if request.endpoint == 'portal_dashcam' %} active{% endif %}" href="{{ url_for('portal_dashcam') }}">
|
||
<i class="fas fa-video"></i>
|
||
<span>Dashcam</span>
|
||
</a>
|
||
<a class="mobile-nav-item{% if request.endpoint == 'portal_device_settings_page' %} active{% endif %}" href="{{ url_for('portal_device_settings_page') }}">
|
||
<i class="fas fa-sliders-h"></i>
|
||
<span>Device</span>
|
||
</a>
|
||
<a class="mobile-nav-item{% if request.endpoint == 'portal_dtc_page' %} active{% endif %}" href="{{ url_for('portal_dtc_page') }}">
|
||
<i class="fas fa-exclamation-triangle"></i>
|
||
<span>DTC</span>
|
||
</a>
|
||
<a class="mobile-nav-item" href="{{ url_for('logout') }}">
|
||
<i class="fas fa-sign-out-alt"></i>
|
||
<span>Logout</span>
|
||
</a>
|
||
</nav>
|
||
|
||
<script src="{{ url_for('static', filename='bootstrap/js/bootstrap.min.js') }}"></script>
|
||
<script src="{{ url_for('static', filename='js/bs-init.js') }}"></script>
|
||
<script src="{{ url_for('static', filename='js/theme.js') }}"></script>
|
||
|
||
{# ── Device selector ─────────────────────────────────────────────────── #}
|
||
<script>
|
||
(function () {
|
||
const sel = document.getElementById("portal-device-selector");
|
||
if (!sel) return;
|
||
async function load() {
|
||
const r = await fetch("/api/v1/portal/select-device");
|
||
if (!r.ok) return;
|
||
const d = await r.json();
|
||
sel.innerHTML = d.devices.map(dev =>
|
||
'<option value="' + dev.id + '"' + (dev.id === d.selected_device_id ? " selected" : "") + ">" +
|
||
(dev.device_name || dev.name) + (dev.portal_default ? " (default)" : "") +
|
||
"</option>"
|
||
).join("");
|
||
if (!d.devices.length) sel.innerHTML = '<option value="">No devices</option>';
|
||
}
|
||
load();
|
||
sel.addEventListener("change", async function () {
|
||
const id = sel.value ? parseInt(sel.value) : null;
|
||
await fetch("/api/v1/portal/select-device", {
|
||
method: "POST",
|
||
headers: {"Content-Type": "application/json"},
|
||
body: JSON.stringify({device_id: id}),
|
||
});
|
||
location.reload();
|
||
});
|
||
})();
|
||
</script>
|
||
<script>
|
||
window.confirmDelete = function(message) {
|
||
return Promise.resolve(window.confirm(message));
|
||
};
|
||
</script>
|
||
{% block scripts %}{% endblock %}
|
||
</body>
|
||
|
||
</html>
|