1c5b728e8b
FastAPI web server with REST + WebSocket, 5 Jinja2 HTML pages, mobile-friendly dark theme CSS, page-specific JS controllers, and Avahi mDNS service advertisement for pedal.local. Files: src/web/server.py — FastAPI app with 17 REST endpoints + /ws WebSocket src/web/__init__.py — Package init with WebServer, WebServerDeps exports src/web/templates/*.html — Dashboard, Presets, Models, IRs, Settings (base) src/web/static/style.css — Dark mobile-first CSS (80-82% max-width) src/web/static/websocket.js — Auto-reconnecting WebSocket manager src/web/static/app.js — Dashboard live updates + REST helpers src/web/static/presets.js — Bank/preset CRUD modal UI src/web/static/models.js — NAM model list/load/upload src/web/static/irs.js — IR file list/load/upload etc/avahi/pi-multifx-pedal.service — Avahi service advertisement scripts/setup-mdns.sh — One-shot mDNS setup (avahi, hostname, restart) main.py — Wire WebServer into boot/shutdown requirements.txt — Add fastapi, uvicorn, jinja2, python-multipart tests/test_web.py — 36 tests (pages, REST, WebSocket, errors) All 36 tests pass.
37 lines
1.8 KiB
HTML
37 lines
1.8 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
|
<title>{% block title %}Pi Multi-FX Pedal{% endblock %}</title>
|
|
<link rel="stylesheet" href="/static/style.css">
|
|
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><text y='28' font-size='28'>🎸</text></svg>">
|
|
</head>
|
|
<body>
|
|
<div class="app-container">
|
|
<header class="app-header">
|
|
<div class="header-left">
|
|
<a href="/" class="logo">🎸 Pi Pedal</a>
|
|
</div>
|
|
<nav class="header-nav">
|
|
<a href="/" class="nav-link {% if request.url.path == '/' %}active{% endif %}">Dashboard</a>
|
|
<a href="/presets" class="nav-link {% if request.url.path == '/presets' %}active{% endif %}">Presets</a>
|
|
<a href="/models" class="nav-link {% if request.url.path == '/models' %}active{% endif %}">Models</a>
|
|
<a href="/irs" class="nav-link {% if request.url.path == '/irs' %}active{% endif %}">IRs</a>
|
|
<a href="/settings" class="nav-link {% if request.url.path == '/settings' %}active{% endif %}">Settings</a>
|
|
</nav>
|
|
<div class="header-right">
|
|
<span class="connection-indicator" id="connection-status">Disconnected</span>
|
|
</div>
|
|
</header>
|
|
<main class="app-main">
|
|
{% block content %}{% endblock %}
|
|
</main>
|
|
</div>
|
|
<script src="/static/websocket.js"></script>
|
|
<script src="/static/app.js"></script>
|
|
{% block scripts %}{% endblock %}
|
|
</body>
|
|
</html> |