feat: v0.3.5 - AdminLTE-style layout, fix channel names in messages
Redesign dashboard and scheduler with AdminLTE-inspired layout: fixed sidebar navigation, top navbar, info-boxes, card-outline styling, table-striped. Fix channel names missing on initial load by sending channels before messages. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
6bfb1595e4
commit
65703b6389
21
CHANGELOG.md
21
CHANGELOG.md
|
|
@ -1,5 +1,26 @@
|
|||
# Changelog
|
||||
|
||||
## [0.3.5] - 2026-02-15
|
||||
### Changed
|
||||
- Dashboard und Scheduler auf AdminLTE-Style umgestellt
|
||||
- Feste Sidebar-Navigation (Dashboard, Scheduler, Karte) mit Active-State
|
||||
- Fixed Top-Navbar mit Branding, Status-Dot und Theme-Toggle
|
||||
- Content-Wrapper mit leicht abgesetztem Hintergrund
|
||||
- Info-Boxes im AdminLTE-Stil (Icon-Spalte + Inhalt) statt Cards
|
||||
- Card-Outline mit farbiger Oberkante (info/warning) statt Borders
|
||||
- Table-Striped fuer bessere Lesbarkeit
|
||||
- Sidebar responsive: auf Mobile als Overlay mit Backdrop
|
||||
- Einheitliches Layout auf Dashboard und Scheduler
|
||||
|
||||
## [0.3.4] - 2026-02-15
|
||||
### Fixed
|
||||
- Kanalnamen in Nachrichten fehlten beim Laden (Channels werden jetzt vor Messages gesendet)
|
||||
|
||||
### Changed
|
||||
- Dashboard deutlich kompakter: weniger Padding, kleinere Schriftgroessen
|
||||
- Stat-Cards, Navbar, Panels und Nachrichten platzsparender
|
||||
- Hover-Animationen und Pulse-Effekt entfernt (schlichter)
|
||||
|
||||
## [0.3.3] - 2026-02-15
|
||||
### Changed
|
||||
- Dashboard-Layout modernisiert: Glassmorphism-Navbar (sticky, blur-Effekt)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
version: "0.3.3"
|
||||
version: "0.3.5"
|
||||
|
||||
bot:
|
||||
name: "MeshDD-Bot"
|
||||
|
|
|
|||
|
|
@ -67,13 +67,13 @@ class WebServer:
|
|||
stats["version"] = config.get("version", "0.0.0")
|
||||
await ws.send_str(json.dumps({"type": "stats_update", "data": stats}))
|
||||
|
||||
messages = await self.db.get_recent_messages(50)
|
||||
await ws.send_str(json.dumps({"type": "initial_messages", "data": messages}))
|
||||
|
||||
if self.bot:
|
||||
channels = self.bot.get_channels()
|
||||
await ws.send_str(json.dumps({"type": "channels", "data": channels}))
|
||||
|
||||
messages = await self.db.get_recent_messages(50)
|
||||
await ws.send_str(json.dumps({"type": "initial_messages", "data": messages}))
|
||||
|
||||
async for msg in ws:
|
||||
pass # We only send, not receive
|
||||
finally:
|
||||
|
|
|
|||
|
|
@ -1,102 +1,189 @@
|
|||
/* Status indicator */
|
||||
/* ── AdminLTE-style Layout ─────────────────────────── */
|
||||
|
||||
/* Top Navbar */
|
||||
.top-navbar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 46px;
|
||||
z-index: 1030;
|
||||
background: var(--bs-body-bg);
|
||||
border-bottom: 1px solid var(--bs-border-color);
|
||||
font-size: .875rem;
|
||||
}
|
||||
|
||||
/* Sidebar */
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
top: 46px;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 200px;
|
||||
background: var(--bs-body-bg);
|
||||
border-right: 1px solid var(--bs-border-color);
|
||||
z-index: 1020;
|
||||
overflow-y: auto;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.sidebar-nav {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
|
||||
.sidebar-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
padding: 0.5rem 1rem;
|
||||
color: var(--bs-body-color);
|
||||
text-decoration: none;
|
||||
font-size: .85rem;
|
||||
border-left: 3px solid transparent;
|
||||
transition: background 0.15s;
|
||||
}
|
||||
|
||||
.sidebar-link:hover {
|
||||
background: rgba(var(--bs-emphasis-color-rgb), 0.06);
|
||||
color: var(--bs-body-color);
|
||||
}
|
||||
|
||||
.sidebar-link.active {
|
||||
background: rgba(var(--bs-info-rgb), 0.08);
|
||||
border-left-color: var(--bs-info);
|
||||
color: var(--bs-info);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.sidebar-link i {
|
||||
font-size: 1rem;
|
||||
width: 1.25rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Mobile sidebar */
|
||||
.sidebar-backdrop {
|
||||
display: none;
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0,0,0,0.4);
|
||||
z-index: 1019;
|
||||
}
|
||||
|
||||
@media (max-width: 991.98px) {
|
||||
.sidebar {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
.sidebar.open {
|
||||
transform: translateX(0);
|
||||
}
|
||||
.sidebar.open ~ .sidebar-backdrop {
|
||||
display: block;
|
||||
}
|
||||
.content-wrapper {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Content wrapper */
|
||||
.content-wrapper {
|
||||
margin-top: 46px;
|
||||
margin-left: 200px;
|
||||
padding: 0.75rem;
|
||||
min-height: calc(100vh - 46px);
|
||||
background: rgba(var(--bs-emphasis-color-rgb), 0.03);
|
||||
}
|
||||
|
||||
/* ── Info Boxes (AdminLTE style) ──────────────────── */
|
||||
|
||||
.info-box {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
background: var(--bs-body-bg);
|
||||
border: 1px solid var(--bs-border-color);
|
||||
border-radius: 0.375rem;
|
||||
min-height: 60px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.info-box-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 56px;
|
||||
font-size: 1.4rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.info-box-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding: 0.4rem 0.75rem;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.info-box-label {
|
||||
font-size: .75rem;
|
||||
color: var(--bs-secondary-color);
|
||||
}
|
||||
|
||||
.info-box-number {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* ── Card outline (AdminLTE style) ────────────────── */
|
||||
|
||||
.card-outline {
|
||||
border-top: 3px solid var(--bs-border-color);
|
||||
}
|
||||
|
||||
.card-outline.card-info {
|
||||
border-top-color: var(--bs-info);
|
||||
}
|
||||
|
||||
.card-outline.card-warning {
|
||||
border-top-color: var(--bs-warning);
|
||||
}
|
||||
|
||||
.card-outline.card-success {
|
||||
border-top-color: var(--bs-success);
|
||||
}
|
||||
|
||||
.card-outline.card-primary {
|
||||
border-top-color: var(--bs-primary);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
font-weight: 600;
|
||||
font-size: .875rem;
|
||||
padding: 0.5rem 0.75rem;
|
||||
}
|
||||
|
||||
/* ── Status dot ──────────────────────────────────── */
|
||||
|
||||
.status-dot {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: var(--bs-danger);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.status-dot.connected {
|
||||
background: var(--bs-success);
|
||||
box-shadow: 0 0 8px var(--bs-success);
|
||||
animation: pulse-dot 2s infinite;
|
||||
box-shadow: 0 0 5px var(--bs-success);
|
||||
}
|
||||
|
||||
@keyframes pulse-dot {
|
||||
0%, 100% { box-shadow: 0 0 4px var(--bs-success); }
|
||||
50% { box-shadow: 0 0 12px var(--bs-success); }
|
||||
}
|
||||
/* ── Messages ────────────────────────────────────── */
|
||||
|
||||
/* Navbar glass effect */
|
||||
.navbar-glass {
|
||||
backdrop-filter: blur(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
background: rgba(var(--bs-body-bg-rgb), 0.85) !important;
|
||||
border-bottom: 1px solid rgba(var(--bs-emphasis-color-rgb), 0.08);
|
||||
}
|
||||
|
||||
/* Scrollbar */
|
||||
.table-responsive::-webkit-scrollbar,
|
||||
.msg-scroll::-webkit-scrollbar {
|
||||
width: 5px;
|
||||
}
|
||||
|
||||
.table-responsive::-webkit-scrollbar-track,
|
||||
.msg-scroll::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.table-responsive::-webkit-scrollbar-thumb,
|
||||
.msg-scroll::-webkit-scrollbar-thumb {
|
||||
background: var(--bs-border-color);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
/* Stat cards */
|
||||
.stat-card {
|
||||
border: none;
|
||||
border-radius: 0.75rem;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
transition: transform 0.15s ease, box-shadow 0.15s ease;
|
||||
}
|
||||
|
||||
.stat-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.stat-card .stat-accent {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 3px;
|
||||
}
|
||||
|
||||
.stat-card .stat-icon {
|
||||
font-size: 1.8rem;
|
||||
opacity: 0.15;
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
/* Panel cards */
|
||||
.panel-card {
|
||||
border: none;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.08);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.panel-card .card-header {
|
||||
background: transparent;
|
||||
border-bottom: 1px solid rgba(var(--bs-emphasis-color-rgb), 0.06);
|
||||
padding: 0.65rem 1rem;
|
||||
}
|
||||
|
||||
/* Messages */
|
||||
.msg-item {
|
||||
padding: 0.5rem 0.75rem;
|
||||
border-bottom: 1px solid rgba(var(--bs-emphasis-color-rgb), 0.04);
|
||||
transition: background 0.15s ease;
|
||||
}
|
||||
|
||||
.msg-item:hover {
|
||||
background: rgba(var(--bs-emphasis-color-rgb), 0.03);
|
||||
padding: 0.35rem 0.65rem;
|
||||
border-bottom: 1px solid var(--bs-border-color-translucent);
|
||||
font-size: .8rem;
|
||||
}
|
||||
|
||||
.msg-item:last-child {
|
||||
|
|
@ -104,42 +191,28 @@
|
|||
}
|
||||
|
||||
.msg-bubble {
|
||||
background: rgba(var(--bs-info-rgb), 0.08);
|
||||
border-radius: 0.5rem 0.5rem 0.5rem 0.1rem;
|
||||
padding: 0.35rem 0.6rem;
|
||||
background: rgba(var(--bs-info-rgb), 0.06);
|
||||
border-radius: 0.3rem;
|
||||
padding: 0.2rem 0.45rem;
|
||||
display: inline-block;
|
||||
max-width: 100%;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
/* Node table rows */
|
||||
.nodes-table tbody tr {
|
||||
transition: background 0.1s ease;
|
||||
/* ── Scrollbar ───────────────────────────────────── */
|
||||
|
||||
.table-responsive::-webkit-scrollbar,
|
||||
.card-body::-webkit-scrollbar {
|
||||
width: 5px;
|
||||
}
|
||||
|
||||
/* Breakdown bar */
|
||||
.breakdown-bar {
|
||||
border: none;
|
||||
border-radius: 0.5rem;
|
||||
background: rgba(var(--bs-primary-rgb), 0.06);
|
||||
.table-responsive::-webkit-scrollbar-track,
|
||||
.card-body::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* Send input */
|
||||
.send-bar {
|
||||
border-top: 1px solid rgba(var(--bs-emphasis-color-rgb), 0.06);
|
||||
background: rgba(var(--bs-emphasis-color-rgb), 0.02);
|
||||
padding: 0.5rem 0.75rem;
|
||||
border-radius: 0 0 0.75rem 0.75rem;
|
||||
}
|
||||
|
||||
.send-bar .form-control:focus,
|
||||
.send-bar .form-select:focus {
|
||||
box-shadow: none;
|
||||
border-color: var(--bs-info);
|
||||
}
|
||||
|
||||
/* Badge pills */
|
||||
.badge-pill {
|
||||
border-radius: 2rem;
|
||||
font-weight: 500;
|
||||
.table-responsive::-webkit-scrollbar-thumb,
|
||||
.card-body::-webkit-scrollbar-thumb {
|
||||
background: var(--bs-border-color);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,97 +9,110 @@
|
|||
<link rel="stylesheet" href="/static/css/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<!-- Navbar -->
|
||||
<nav class="navbar navbar-expand-sm navbar-glass sticky-top">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand d-flex align-items-center gap-2" href="/">
|
||||
<i class="bi bi-broadcast-pin text-info fs-5"></i>
|
||||
<span class="fw-bold">MeshDD-Bot</span>
|
||||
<span class="badge badge-pill bg-body-secondary text-body-secondary fw-normal small" id="versionLabel"></span>
|
||||
</a>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<a href="/scheduler" class="btn btn-outline-info btn-sm rounded-pill px-3">
|
||||
<i class="bi bi-clock-history me-1"></i>Scheduler
|
||||
</a>
|
||||
<a href="/map" target="_blank" class="btn btn-outline-info btn-sm rounded-pill px-3">
|
||||
<i class="bi bi-map me-1"></i>Karte
|
||||
</a>
|
||||
<button class="btn btn-outline-secondary btn-sm rounded-circle" id="themeToggle" title="Theme wechseln" style="width:32px;height:32px;">
|
||||
<i class="bi bi-sun-fill" id="themeIcon"></i>
|
||||
<!-- Top Navbar -->
|
||||
<nav class="top-navbar d-flex align-items-center px-3">
|
||||
<button class="btn btn-link text-body p-0 me-2 d-lg-none" id="sidebarToggle">
|
||||
<i class="bi bi-list fs-5"></i>
|
||||
</button>
|
||||
<span class="badge badge-pill bg-body-secondary d-flex align-items-center gap-2 px-3 py-2" id="statusBadge">
|
||||
<span class="status-dot" id="statusDot"></span>
|
||||
<span class="small" id="statusText">Verbinde...</span>
|
||||
<span class="fw-bold me-auto">
|
||||
<i class="bi bi-broadcast-pin text-info me-1"></i>MeshDD-Bot
|
||||
<small class="text-body-secondary fw-normal" id="versionLabel"></small>
|
||||
</span>
|
||||
</div>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<span class="d-flex align-items-center gap-1">
|
||||
<span class="status-dot" id="statusDot"></span>
|
||||
<small class="text-body-secondary" id="statusText">Verbinde...</small>
|
||||
</span>
|
||||
<button class="btn btn-sm btn-outline-secondary py-0 px-1" id="themeToggle" title="Theme wechseln">
|
||||
<i class="bi bi-sun-fill" id="themeIcon" style="font-size:.75rem"></i>
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container-fluid py-3">
|
||||
<!-- Stats Cards -->
|
||||
<!-- Sidebar -->
|
||||
<aside class="sidebar" id="sidebar">
|
||||
<nav class="sidebar-nav">
|
||||
<a href="/" class="sidebar-link active">
|
||||
<i class="bi bi-speedometer2"></i><span>Dashboard</span>
|
||||
</a>
|
||||
<a href="/scheduler" class="sidebar-link">
|
||||
<i class="bi bi-clock-history"></i><span>Scheduler</span>
|
||||
</a>
|
||||
<a href="/map" target="_blank" class="sidebar-link">
|
||||
<i class="bi bi-map"></i><span>Karte</span>
|
||||
</a>
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
<!-- Backdrop for mobile sidebar -->
|
||||
<div class="sidebar-backdrop" id="sidebarBackdrop"></div>
|
||||
|
||||
<!-- Content -->
|
||||
<main class="content-wrapper">
|
||||
<!-- Info Boxes -->
|
||||
<div class="row g-2 mb-2">
|
||||
<div class="col-4">
|
||||
<div class="card stat-card">
|
||||
<div class="stat-accent" style="background: linear-gradient(90deg, var(--bs-info), transparent);"></div>
|
||||
<i class="bi bi-router stat-icon text-info"></i>
|
||||
<div class="card-body py-2 ps-3">
|
||||
<div class="fs-4 fw-bold text-info" id="statNodes">0</div>
|
||||
<div class="text-body-secondary small">Nodes gesamt</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="info-box">
|
||||
<span class="info-box-icon bg-info bg-opacity-10 text-info">
|
||||
<i class="bi bi-router"></i>
|
||||
</span>
|
||||
<div class="info-box-content">
|
||||
<span class="info-box-label">Nodes gesamt</span>
|
||||
<span class="info-box-number" id="statNodes">0</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<div class="card stat-card">
|
||||
<div class="stat-accent" style="background: linear-gradient(90deg, var(--bs-success), transparent);"></div>
|
||||
<i class="bi bi-activity stat-icon text-success"></i>
|
||||
<div class="card-body py-2 ps-3">
|
||||
<div class="fs-4 fw-bold text-success" id="statNodes24h">0</div>
|
||||
<div class="text-body-secondary small">Aktiv (24h)</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="info-box">
|
||||
<span class="info-box-icon bg-success bg-opacity-10 text-success">
|
||||
<i class="bi bi-activity"></i>
|
||||
</span>
|
||||
<div class="info-box-content">
|
||||
<span class="info-box-label">Aktiv (24h)</span>
|
||||
<span class="info-box-number" id="statNodes24h">0</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<div class="card stat-card">
|
||||
<div class="stat-accent" style="background: linear-gradient(90deg, var(--bs-warning), transparent);"></div>
|
||||
<i class="bi bi-terminal stat-icon text-warning"></i>
|
||||
<div class="card-body py-2 ps-3">
|
||||
<div class="fs-4 fw-bold text-warning" id="statCommands">0</div>
|
||||
<div class="text-body-secondary small">Anfragen</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row g-2 mb-3">
|
||||
<div class="col-12">
|
||||
<div class="card breakdown-bar">
|
||||
<div class="card-body py-2 d-flex align-items-center gap-3 flex-wrap">
|
||||
<span class="text-body-secondary small me-1"><i class="bi bi-bar-chart-fill me-1"></i>Anfragen:</span>
|
||||
<span id="commandBreakdown" class="d-flex gap-2 flex-wrap"></span>
|
||||
<div class="col-sm-4">
|
||||
<div class="info-box">
|
||||
<span class="info-box-icon bg-warning bg-opacity-10 text-warning">
|
||||
<i class="bi bi-terminal"></i>
|
||||
</span>
|
||||
<div class="info-box-content">
|
||||
<span class="info-box-label">Anfragen</span>
|
||||
<span class="info-box-number" id="statCommands">0</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Panels -->
|
||||
<div class="row g-3">
|
||||
<!-- Nodes Table -->
|
||||
<div class="col-lg-7">
|
||||
<div class="card panel-card">
|
||||
<div class="card-header d-flex align-items-center">
|
||||
<i class="bi bi-router me-2 text-info"></i>
|
||||
<span class="fw-semibold">Nodes</span>
|
||||
<span class="badge badge-pill bg-info bg-opacity-25 text-info ms-auto" id="nodeCountBadge">0</span>
|
||||
<!-- Command Breakdown -->
|
||||
<div class="card card-outline mb-2">
|
||||
<div class="card-body py-2 px-3 d-flex align-items-center gap-2 flex-wrap">
|
||||
<small class="text-body-secondary"><i class="bi bi-bar-chart-fill me-1"></i>Anfragen:</small>
|
||||
<span id="commandBreakdown" class="d-flex gap-1 flex-wrap"></span>
|
||||
</div>
|
||||
<div class="card-body p-0 table-responsive" style="max-height: 500px; overflow-y: auto;">
|
||||
<table class="table table-hover table-sm mb-0 align-middle nodes-table">
|
||||
</div>
|
||||
|
||||
<!-- Main Cards -->
|
||||
<div class="row g-2">
|
||||
<!-- Nodes -->
|
||||
<div class="col-lg-7">
|
||||
<div class="card card-outline card-info">
|
||||
<div class="card-header">
|
||||
<i class="bi bi-router me-1"></i>Nodes
|
||||
<span class="badge bg-info float-end" id="nodeCountBadge">0</span>
|
||||
</div>
|
||||
<div class="card-body p-0 table-responsive" style="max-height:520px;overflow-y:auto">
|
||||
<table class="table table-hover table-sm table-striped mb-0 align-middle">
|
||||
<thead class="table-dark sticky-top">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Hardware</th>
|
||||
<th class="text-end px-1">SNR</th>
|
||||
<th class="px-1">Batterie</th>
|
||||
<th class="text-center px-1">Hops</th>
|
||||
<th class="text-end px-1">Zuletzt</th>
|
||||
<th class="text-end">SNR</th>
|
||||
<th>Batterie</th>
|
||||
<th class="text-center">Hops</th>
|
||||
<th class="text-end">Zuletzt</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="nodesTable"></tbody>
|
||||
|
|
@ -110,19 +123,18 @@
|
|||
|
||||
<!-- Messages -->
|
||||
<div class="col-lg-5">
|
||||
<div class="card panel-card">
|
||||
<div class="card-header d-flex align-items-center">
|
||||
<i class="bi bi-chat-dots me-2 text-warning"></i>
|
||||
<span class="fw-semibold">Nachrichten</span>
|
||||
<div class="card card-outline card-warning">
|
||||
<div class="card-header">
|
||||
<i class="bi bi-chat-dots me-1"></i>Nachrichten
|
||||
</div>
|
||||
<div class="card-body p-0 msg-scroll" style="max-height: 500px; overflow-y: auto;">
|
||||
<div class="card-body p-0" style="max-height:520px;overflow-y:auto">
|
||||
<div id="messagesList"></div>
|
||||
</div>
|
||||
<div class="send-bar">
|
||||
<div class="card-footer py-2 px-2">
|
||||
<div class="input-group input-group-sm">
|
||||
<select class="form-select form-select-sm rounded-start-pill" id="sendChannel" style="max-width: 120px;"></select>
|
||||
<select class="form-select form-select-sm" id="sendChannel" style="max-width:110px"></select>
|
||||
<input type="text" class="form-control form-control-sm" id="sendText" placeholder="Nachricht senden...">
|
||||
<button class="btn btn-info btn-sm rounded-end-pill px-3" id="btnSend" type="button">
|
||||
<button class="btn btn-info btn-sm" id="btnSend" type="button">
|
||||
<i class="bi bi-send-fill"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -130,7 +142,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="/static/js/dashboard.js"></script>
|
||||
|
|
|
|||
|
|
@ -209,4 +209,14 @@ themeToggle.addEventListener('click', () => {
|
|||
applyTheme(current === 'dark' ? 'light' : 'dark');
|
||||
});
|
||||
|
||||
// Sidebar toggle (mobile)
|
||||
const sidebarToggle = document.getElementById('sidebarToggle');
|
||||
const sidebar = document.getElementById('sidebar');
|
||||
const sidebarBackdrop = document.getElementById('sidebarBackdrop');
|
||||
|
||||
if (sidebarToggle) {
|
||||
sidebarToggle.addEventListener('click', () => sidebar.classList.toggle('open'));
|
||||
sidebarBackdrop.addEventListener('click', () => sidebar.classList.remove('open'));
|
||||
}
|
||||
|
||||
connectWebSocket();
|
||||
|
|
|
|||
|
|
@ -208,5 +208,15 @@ document.getElementById('btnSaveJob').addEventListener('click', async () => {
|
|||
}
|
||||
});
|
||||
|
||||
// Sidebar toggle (mobile)
|
||||
const sidebarToggle = document.getElementById('sidebarToggle');
|
||||
const sidebar = document.getElementById('sidebar');
|
||||
const sidebarBackdrop = document.getElementById('sidebarBackdrop');
|
||||
|
||||
if (sidebarToggle) {
|
||||
sidebarToggle.addEventListener('click', () => sidebar.classList.toggle('open'));
|
||||
sidebarBackdrop.addEventListener('click', () => sidebar.classList.remove('open'));
|
||||
}
|
||||
|
||||
loadJobs();
|
||||
connectWebSocket();
|
||||
|
|
|
|||
|
|
@ -9,37 +9,48 @@
|
|||
<link rel="stylesheet" href="/static/css/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<!-- Navbar -->
|
||||
<nav class="navbar navbar-expand-sm bg-body-tertiary border-bottom">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="/">
|
||||
<i class="bi bi-broadcast-pin text-info me-2"></i>MeshDD-Bot
|
||||
</a>
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<a href="/" class="btn btn-outline-info btn-sm">
|
||||
<i class="bi bi-speedometer2 me-1"></i>Dashboard
|
||||
</a>
|
||||
<a href="/map" target="_blank" class="btn btn-outline-info btn-sm">
|
||||
<i class="bi bi-map me-1"></i>Karte
|
||||
</a>
|
||||
<button class="btn btn-outline-secondary btn-sm" id="themeToggle" title="Theme wechseln">
|
||||
<i class="bi bi-sun-fill" id="themeIcon"></i>
|
||||
<!-- Top Navbar -->
|
||||
<nav class="top-navbar d-flex align-items-center px-3">
|
||||
<button class="btn btn-link text-body p-0 me-2 d-lg-none" id="sidebarToggle">
|
||||
<i class="bi bi-list fs-5"></i>
|
||||
</button>
|
||||
<span class="fw-bold me-auto">
|
||||
<i class="bi bi-broadcast-pin text-info me-1"></i>MeshDD-Bot
|
||||
</span>
|
||||
<button class="btn btn-sm btn-outline-secondary py-0 px-1" id="themeToggle" title="Theme wechseln">
|
||||
<i class="bi bi-sun-fill" id="themeIcon" style="font-size:.75rem"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container-fluid py-3">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h5 class="mb-0"><i class="bi bi-clock-history me-2 text-info"></i>Scheduler</h5>
|
||||
<!-- Sidebar -->
|
||||
<aside class="sidebar" id="sidebar">
|
||||
<nav class="sidebar-nav">
|
||||
<a href="/" class="sidebar-link">
|
||||
<i class="bi bi-speedometer2"></i><span>Dashboard</span>
|
||||
</a>
|
||||
<a href="/scheduler" class="sidebar-link active">
|
||||
<i class="bi bi-clock-history"></i><span>Scheduler</span>
|
||||
</a>
|
||||
<a href="/map" target="_blank" class="sidebar-link">
|
||||
<i class="bi bi-map"></i><span>Karte</span>
|
||||
</a>
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
<div class="sidebar-backdrop" id="sidebarBackdrop"></div>
|
||||
|
||||
<!-- Content -->
|
||||
<main class="content-wrapper">
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<h6 class="mb-0"><i class="bi bi-clock-history me-1 text-info"></i>Scheduler</h6>
|
||||
<button class="btn btn-info btn-sm" id="btnAddJob">
|
||||
<i class="bi bi-plus-lg me-1"></i>Neuer Job
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card card-outline card-info">
|
||||
<div class="card-body p-0 table-responsive">
|
||||
<table class="table table-hover table-sm mb-0 align-middle">
|
||||
<table class="table table-hover table-sm table-striped mb-0 align-middle">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
|
|
@ -58,7 +69,7 @@
|
|||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- Job Modal -->
|
||||
<div class="modal fade" id="jobModal" tabindex="-1">
|
||||
|
|
|
|||
Loading…
Reference in a new issue