Files
yaris-obd/server/templates/base.html
T

182 lines
9.4 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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 }}
&nbsp;·&nbsp;
<a href="{{ url_for('change_password_page') }}" class="text-muted">Password</a>
&nbsp;·&nbsp;
<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 class="sidebar-brand-logo" style="font-size:1.2rem;color:#fff;">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">
&copy; vroom vroom yaris de course 2023 &mdash; 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>