Refresh tabs/presets UI and add a mobile menu.

This improves navigation and profile workflows on smaller screens.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-02-08 13:51:09 +13:00
parent 6c6ed22dbe
commit d907ca37ad
6 changed files with 917 additions and 379 deletions

View File

@@ -9,27 +9,39 @@
<body>
<div class="app-container">
<header>
<h1>LED Controller - Tab Mode</h1>
<div class="header-actions">
<button class="btn btn-secondary" id="tabs-btn">Tabs</button>
<button class="btn btn-secondary" id="color-palette-btn">Color Palette</button>
<button class="btn btn-secondary" id="presets-btn">Presets</button>
<button class="btn btn-secondary" id="patterns-btn">Patterns</button>
<button class="btn btn-secondary" id="profiles-btn">Profiles</button>
<button class="btn btn-secondary" id="settings-btn">Settings</button>
<button class="btn btn-secondary" id="help-btn">Help</button>
</div>
</header>
<div class="main-content">
<div class="tabs-container">
<div id="tabs-list">
Loading tabs...
</div>
</div>
<div class="header-actions">
<button class="btn btn-secondary" id="tabs-btn">Tabs</button>
<button class="btn btn-secondary" id="color-palette-btn">Color Palette</button>
<button class="btn btn-secondary" id="presets-btn">Presets</button>
<button class="btn btn-secondary" id="send-profile-presets-btn">Send Presets</button>
<button class="btn btn-secondary" id="patterns-btn">Patterns</button>
<button class="btn btn-secondary" id="profiles-btn">Profiles</button>
<button class="btn btn-secondary" id="settings-btn">Settings</button>
<button class="btn btn-secondary" id="help-btn">Help</button>
</div>
<div class="header-menu-mobile">
<button class="btn btn-secondary" id="main-menu-btn">Menu</button>
<div id="main-menu-dropdown" class="main-menu-dropdown">
<button type="button" data-target="tabs-btn">Tabs</button>
<button type="button" data-target="color-palette-btn">Color Palette</button>
<button type="button" data-target="presets-btn">Presets</button>
<button type="button" data-target="send-profile-presets-btn">Send Presets</button>
<button type="button" data-target="patterns-btn">Patterns</button>
<button type="button" data-target="profiles-btn">Profiles</button>
<button type="button" data-target="settings-btn">Settings</button>
<button type="button" data-target="help-btn">Help</button>
</div>
</div>
</header>
<div class="main-content">
<div id="tab-content" class="tab-content">
<div style="padding: 2rem; text-align: center; color: #aaa;">
<div class="tab-content-placeholder">
Select a tab to get started
</div>
</div>
@@ -58,14 +70,16 @@
<h2>Edit Tab</h2>
<form id="edit-tab-form">
<input type="hidden" id="edit-tab-id">
<div class="modal-actions" style="margin-bottom: 1rem;">
<button type="submit" class="btn btn-primary">Save</button>
<button type="button" class="btn btn-secondary" onclick="document.getElementById('edit-tab-modal').classList.remove('active')">Close</button>
</div>
<label>Tab Name:</label>
<input type="text" id="edit-tab-name" placeholder="Enter tab name" required>
<label>Device IDs (comma-separated):</label>
<input type="text" id="edit-tab-ids" placeholder="1,2,3" required>
<div class="modal-actions">
<button type="submit" class="btn btn-primary">Save</button>
<button type="button" class="btn btn-secondary" onclick="document.getElementById('edit-tab-modal').classList.remove('active')">Cancel</button>
</div>
<label style="margin-top: 1rem;">Add presets to this tab</label>
<div id="edit-tab-presets-list" class="profiles-list" style="max-height: 200px; overflow-y: auto; margin-bottom: 1rem;"></div>
</form>
</div>
</div>
@@ -111,17 +125,17 @@
</div>
<label>Colors</label>
<div id="preset-colors-container" class="preset-colors-container"></div>
<div class="profiles-actions" style="margin-top: 0.5rem;">
<div class="profiles-actions">
<input type="color" id="preset-new-color" value="#ffffff">
<button class="btn btn-secondary btn-small" id="preset-add-color-btn">Add Color</button>
<button class="btn btn-secondary btn-small" id="preset-add-from-palette-btn">Add from Palette</button>
</div>
<div class="profiles-actions">
<div style="flex: 1; display: flex; flex-direction: column;">
<div class="preset-editor-field">
<label for="preset-brightness-input">Brightness (0255)</label>
<input type="number" id="preset-brightness-input" placeholder="Brightness" min="0" max="255" value="0">
</div>
<div style="flex: 1; display: flex; flex-direction: column;">
<div class="preset-editor-field">
<label for="preset-delay-input">Delay (ms)</label>
<input type="number" id="preset-delay-input" placeholder="Delay" min="0" max="10000" value="0">
</div>
@@ -207,7 +221,7 @@
<ul>
<li><strong>Select tab</strong>: left-click a tab button in the top bar.</li>
<li><strong>Edit tab</strong>: right-click a tab button, or click <strong>Edit</strong> in the Tabs modal.</li>
<li><strong>Send all presets</strong>: use the <strong>Send Presets</strong> button in the tab header to push every preset used in that tab to all devices.</li>
<li><strong>Send all presets</strong>: open the <strong>Tabs</strong> menu and click <strong>Send Presets</strong> next to the tab to push every preset used in that tab to all devices.</li>
</ul>
<h3>Presets in a tab</h3>
@@ -233,11 +247,11 @@
<!-- Settings Modal -->
<div id="settings-modal" class="modal">
<div class="modal-content" style="max-width: 900px; max-height: 90vh; overflow-y: auto;">
<div class="modal-content">
<h2>Device Settings</h2>
<p class="muted-text" style="margin-bottom: 1rem;">Configure WiFi and device settings.</p>
<p class="muted-text">Configure WiFi and device settings.</p>
<div id="settings-message" class="message" style="display:none;"></div>
<div id="settings-message" class="message"></div>
<!-- Device Name -->
<div class="settings-section">
@@ -297,7 +311,7 @@
</div>
<!-- WiFi Access Point Settings -->
<div class="settings-section" style="margin-top: 1.5rem;">
<div class="settings-section ap-settings-section">
<h3>WiFi Access Point</h3>
<div id="ap-status" class="status-info">
@@ -336,180 +350,7 @@
</div>
</div>
<style>
.modal {
display: none;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.7);
}
.modal.active {
display: flex;
align-items: center;
justify-content: center;
}
.modal-content {
background-color: #2e2e2e;
padding: 2rem;
border-radius: 8px;
min-width: 400px;
max-width: 600px;
}
.modal-content label {
display: block;
margin-top: 1rem;
margin-bottom: 0.5rem;
}
.modal-content input[type="text"] {
width: 100%;
padding: 0.5rem;
background-color: #3a3a3a;
border: 1px solid #4a4a4a;
border-radius: 4px;
color: white;
}
.profiles-actions {
display: flex;
gap: 0.5rem;
margin-top: 1rem;
}
.profiles-actions input[type="text"] {
flex: 1;
}
.profiles-list {
display: flex;
flex-direction: column;
gap: 0.5rem;
margin-top: 1rem;
max-height: 50vh;
overflow-y: auto;
}
.profiles-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.5rem;
padding: 0.5rem;
background-color: #3a3a3a;
border-radius: 4px;
}
/* Hide any text content in palette rows - only show color swatches */
#palette-container .profiles-row {
font-size: 0; /* Hide any text nodes */
}
#palette-container .profiles-row > * {
font-size: 1rem; /* Restore font size for buttons */
}
#palette-container .profiles-row > span:not(.btn),
#palette-container .profiles-row > label,
#palette-container .profiles-row::before,
#palette-container .profiles-row::after {
display: none !important;
content: none !important;
}
/* Preset colors container */
#preset-colors-container {
min-height: 80px;
padding: 0.5rem;
background-color: #2a2a2a;
border-radius: 4px;
margin-bottom: 0.5rem;
}
#preset-colors-container .muted-text {
color: #888;
font-size: 0.9rem;
padding: 1rem;
text-align: center;
}
.muted-text {
text-align: center;
color: #888;
}
.modal-actions {
display: flex;
gap: 0.5rem;
margin-top: 1.5rem;
justify-content: flex-end;
}
.error {
color: #d32f2f;
padding: 0.5rem;
background-color: #3a1a1a;
border-radius: 4px;
margin-top: 0.5rem;
}
/* Drag and drop styles for presets */
.draggable-preset {
cursor: move;
transition: opacity 0.2s, transform 0.2s;
}
.draggable-preset.dragging {
opacity: 0.5;
transform: scale(0.95);
}
.draggable-preset:hover {
opacity: 0.8;
}
/* Drag and drop styles for color swatches */
.draggable-color-swatch {
transition: opacity 0.2s, transform 0.2s;
}
.draggable-color-swatch.dragging-color {
opacity: 0.5;
transform: scale(0.9);
}
.draggable-color-swatch.drag-over-color {
transform: scale(1.1);
}
.color-swatches-container {
min-height: 80px;
}
/* Ensure presets list uses grid layout */
#presets-list-tab {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
gap: 0.75rem;
width: 100%;
}
/* Help modal readability */
#help-modal .modal-content {
max-width: 720px;
line-height: 1.6;
font-size: 0.95rem;
}
#help-modal .modal-content h2 {
margin-bottom: 0.75rem;
}
#help-modal .modal-content h3 {
margin-top: 1.25rem;
margin-bottom: 0.4rem;
font-size: 1.05rem;
font-weight: 600;
}
#help-modal .modal-content p {
text-align: left;
margin-bottom: 0.5rem;
}
#help-modal .modal-content ul {
margin-top: 0.25rem;
margin-left: 1.25rem;
padding-left: 0;
text-align: left;
}
#help-modal .modal-content li {
margin: 0.2rem 0;
line-height: 1.5;
}
#help-modal .muted-text {
text-align: left;
color: #bbb;
font-size: 0.9rem;
}
</style>
<!-- Styles moved to /static/style.css -->
<script src="/static/tabs.js"></script>
<script src="/static/help.js"></script>
<script src="/static/color_palette.js"></script>