Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 44 additions & 13 deletions static/css/daw.css
Original file line number Diff line number Diff line change
Expand Up @@ -1726,6 +1726,14 @@ input, textarea { font-family: inherit; }
border-radius: 6px;
min-width: 0;
}
/* The rule separates the row's label from its controls. It sits after the
label, so "All" reads as the first of four buttons rather than as part of
the words describing them. */
.daw-panel-toggles-label {
margin-right: 2px;
padding-right: 6px;
border-right: 1px solid var(--border-strong);
}
.daw-panel-toggles-label,
.daw-panel-toggles-sep {
font-size: 8px;
Expand Down Expand Up @@ -2383,13 +2391,6 @@ input, textarea { font-family: inherit; }
display: flex; align-items: center; flex-wrap: nowrap; gap: 8px;
min-height: 34px;
}
.alpha-badge {
padding: 1px 5px; border-radius: 4px;
background: rgba(74,140,255,0.16); border: 1px solid rgba(74,140,255,0.4);
color: #4a8cff; font-size: 8.5px; font-weight: 700; letter-spacing: 0.05em;
text-transform: uppercase;
}

/* Tier 3: the timeline. Full-bleed rather than an inset rounded panel -- its
left edge has to land exactly on the lane waveforms' left edge, and a side
border would offset the canvas by its own width. Top and bottom rules only,
Expand Down Expand Up @@ -2513,7 +2514,18 @@ input, textarea { font-family: inherit; }

/* Position group: elapsed / total time, then the loop controls that act on
that position (design 1b groups them together, not with the transport). */
.footer-group-position .footer-group-body { gap: 4px; }
/* The loop column is three rows tall while the rest of this group is one, so
centring it left the two bounds hanging below the elapsed/total readout they
belong to. Aligning to the bottom puts the fields on the readout's line and
lets the button and its hint stack up out of the way. */
.footer-group-position .footer-group-body { gap: 4px; align-items: flex-end; }
.footer-group-position .footer-elapsed,
.footer-group-position .footer-total,
.footer-group-position .footer-time-sep {
/* Match the fields' box height so the baselines land together, rather than
the text bottom meeting the border bottom. */
line-height: 22px;
}
.footer-elapsed {
font-size: 18px; font-weight: 500; letter-spacing: -0.02em; color: var(--fg);
}
Expand All @@ -2523,9 +2535,22 @@ input, textarea { font-family: inherit; }
.footer-time-sep { font-size: 12px; color: var(--muted-2); }

/* Exact loop start/end inputs (inline, right of the loop button) */
/* The hint stacks over the two fields rather than beside them: the footer row
is already full, and a note about the fields belongs with the fields. Sized
to sit inside the width the two boxes already take, so it does not widen the
Position group. */
.footer-loop-times-wrap {
display: flex; flex-direction: column; align-items: stretch; gap: 2px;
margin-left: 6px;
}
.footer-loop-hint {
font-size: 7.5px; font-weight: 600; letter-spacing: 0.02em;
text-transform: uppercase; color: var(--muted);
line-height: 1; white-space: nowrap; text-align: center; user-select: none;
}
.footer-loop-times {
display: flex; align-items: center; gap: 5px;
margin-left: 4px; cursor: default; user-select: none;
display: flex; align-items: center; justify-content: center; gap: 5px;
cursor: default; user-select: none;
}
.loop-times-sep { font-size: 12px; color: var(--muted); flex-shrink: 0; }
.loop-time-input {
Expand All @@ -2536,7 +2561,8 @@ input, textarea { font-family: inherit; }
color: var(--fg); font-family: inherit; font-size: 12px; font-weight: 600;
font-variant-numeric: tabular-nums; text-align: center;
}
.loop-time-input:focus { border-color: var(--accent); }
.loop-time-input { cursor: ns-resize; }
.loop-time-input:focus { cursor: text; border-color: var(--accent); }
.loop-time-input:disabled { opacity: 0.45; cursor: not-allowed; }

/* Transport group: stop square + a play key wide enough to be the obvious
Expand Down Expand Up @@ -2572,7 +2598,12 @@ input, textarea { font-family: inherit; }
/* Loop sits in the Position group and reads as a modifier on the readout next
to it, so it is a short labelled pill rather than a full-height control. */
.footer-group-position .daw-iconbtn.btn-transport.loop {
width: auto; height: 26px; padding: 0 9px; gap: 6px; margin-left: 6px;
/* A tall narrow pill beside the fields, not a bar over them. align-self
overrides the group's flex-end so it fills the two rows the hint and the
bounds take, which is what keeps the footer one line high. */
flex-direction: column; justify-content: center;
width: 46px; height: auto; align-self: stretch;
padding: 3px 4px; gap: 1px; margin-left: 4px;
border-radius: 7px;
background: var(--panel-2); border: 1px solid var(--border-strong);
color: var(--fg-2);
Expand All @@ -2581,7 +2612,7 @@ input, textarea { font-family: inherit; }
.footer-group-position .btn-transport.loop:hover {
background: var(--panel-3); color: var(--fg);
}
.loop-btn-label { font-size: 11px; font-weight: 500; white-space: nowrap; }
.loop-btn-label { font-size: 9.5px; font-weight: 500; white-space: nowrap; line-height: 1; }
.footer-group-position .btn-transport.loop.active,
.footer-group-position .btn-transport.loop.active:hover {
background: rgba(74,140,255,0.16);
Expand Down
42 changes: 34 additions & 8 deletions static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,23 @@
control on each panel would need that panel to keep a stub, and the
stub costs most of what collapsing the smaller ones returns. -->
<div class="daw-panel-toggles">
<span class="daw-panel-toggles-label" data-i18n="panels.clickToCollapse">Click to collapse</span>
<!-- "Collapse" labels the row and is not a control, so the rule sits
after it: everything to its right is a button. "All" belongs with
the three panel names rather than with the label, because it is
the same kind of thing, one press that puts something away.
The label is one word because the row has no width for a sentence.

Its pressed state means what the row's state means, greyed and
struck once everything is away. The trap is the threshold: read
as "is anything hidden" it struck itself through the moment you
hid Analysis on its own, which looks like you pressed it. It is
off only when all four are. -->
<span class="daw-panel-toggles-label" data-i18n="panels.collapse">Collapse</span>
<button class="daw-panel-toggle daw-panel-toggle-all" type="button" data-panel-all aria-pressed="true"
title="Show or hide every panel and the library" data-i18n-title="panels.allTitle" data-i18n-aria-label="panels.allTitle">
<span data-i18n="panels.all">All</span>
</button>
<span class="daw-panel-toggles-sep" aria-hidden="true">-</span>
<button class="daw-panel-toggle" type="button" data-panel="analysis" aria-pressed="true"
title="Show or hide the track analysis" data-i18n-title="panels.analysisTitle" data-i18n-aria-label="panels.analysisTitle">
<span data-i18n="panels.analysis">Analysis</span>
Expand Down Expand Up @@ -675,16 +691,26 @@
<span class="num footer-elapsed" id="footer-time-elapsed">0:00</span>
<span class="footer-time-sep">/</span>
<span class="num footer-total" id="footer-time-total">0:00</span>
<!-- Loop stands beside the two bounds rather than over them. As a
row of its own it stretched the footer bar to three lines for
one button; as a column it fills the height the fields and
their hint already take. -->
<button class="daw-iconbtn btn-transport loop" id="t-loop" type="button" title="Loop the selected position (L)" aria-label="Loop" data-i18n-title="position.loopTitle">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path d="M17 2l4 4-4 4 M3 12V8a2 2 0 0 1 2-2h16 M7 22l-4-4 4-4 M21 12v4a2 2 0 0 1-2 2H3"/>
</svg>
<span class="loop-btn-label" data-i18n="position.loopLabel">Loop position</span>
<span class="loop-btn-label" data-i18n="position.loopLabel">Loop</span>
</button>
<div class="footer-loop-times" title="Exact loop start / end (mm:ss.mmm or seconds)" data-i18n-title="position.loopExactTitle">
<input type="text" id="t-loop-start" class="loop-time-input num" inputmode="decimal" spellcheck="false" autocomplete="off" aria-label="Loop start" data-i18n-aria-label="position.loopStartAria" value="00:00.000">
<span class="loop-times-sep" aria-hidden="true">-</span>
<input type="text" id="t-loop-end" class="loop-time-input num" inputmode="decimal" spellcheck="false" autocomplete="off" aria-label="Loop end" data-i18n-aria-label="position.loopEndAria" value="00:00.000">
<div class="footer-loop-times-wrap">
<!-- The hint sits with the fields it describes: wheel
adjustment is invisible until you try it. It is a label,
not a control, so nothing here looks pressable. -->
<span class="footer-loop-hint" data-i18n="position.loopScrollHint">Scroll up/down to adjust</span>
<div class="footer-loop-times" title="Exact loop start / end (mm:ss.mmm or seconds)" data-i18n-title="position.loopExactTitle">
<input type="text" id="t-loop-start" class="loop-time-input num" inputmode="decimal" spellcheck="false" autocomplete="off" aria-label="Loop start" data-i18n-aria-label="position.loopStartAria" value="00:00.000">
<span class="loop-times-sep" aria-hidden="true">-</span>
<input type="text" id="t-loop-end" class="loop-time-input num" inputmode="decimal" spellcheck="false" autocomplete="off" aria-label="Loop end" data-i18n-aria-label="position.loopEndAria" value="00:00.000">
</div>
</div>
</div>
</div>
Expand Down Expand Up @@ -718,7 +744,7 @@
<span class="footer-divider" aria-hidden="true"></span>

<div class="footer-group footer-group-click" id="t-metro-wrap">
<span class="footer-group-label"><span data-i18n="click.group">Click track</span> <span class="alpha-badge" data-i18n="click.alpha">Alpha</span></span>
<span class="footer-group-label" data-i18n="click.group">Click track</span>
<div class="footer-group-body">
<button class="click-toggle-btn" id="t-metro" type="button" title="Click track (K)" aria-label="Click track" data-i18n-title="click.toggleTitle" data-i18n-aria-label="click.toggleAria" aria-pressed="false" disabled>
<svg class="click-metro-icon" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" aria-hidden="true">
Expand Down
40 changes: 29 additions & 11 deletions static/js/catalog.js
Original file line number Diff line number Diff line change
Expand Up @@ -623,11 +623,10 @@ function moveTrackToTrash(trackId) {

function setCatalogView(view) {
catalogView = ["trash", "favorites", "queue"].includes(view) ? view : "library";
const app = document.querySelector(".app");
if (catalogView !== "library") {
app?.classList.remove("cat-collapsed");
localStorage.setItem("stemdeck.catalog.collapsed", "0");
}
// Switching to Trash, Favourites or Queue is a request to look at the
// sidebar, so a collapsed one comes back. Through the shared helper, or the
// collapse button's aria-expanded is left claiming the sidebar is still shut.
if (catalogView !== "library") setSidebarCollapsed(false);
render();
}

Expand Down Expand Up @@ -1986,6 +1985,31 @@ function applyQueueDecorations(snap = getQueueSnapshot()) {

// ─── Catalog panel collapse ───

/** Collapse or restore the library sidebar.
*
* Exported because the "All" panel toggle puts the library away along with
* the three panels around the mixer. The state is one class on .app plus one
* localStorage flag, and a second writer reproducing those by hand is exactly
* the kind of pair that drifts the first time either changes.
*/
export function setSidebarCollapsed(isCollapsed) {
const app = document.querySelector(".app");
if (!app) return;
app.classList.toggle("cat-collapsed", isCollapsed);
document
.getElementById("sidebarCollapseBtn")
?.setAttribute("aria-expanded", String(!isCollapsed));
try {
localStorage.setItem("stemdeck.catalog.collapsed", isCollapsed ? "1" : "0");
} catch (e) {
console.warn("[catalog] could not persist sidebar state:", e);
}
}

export function isSidebarCollapsed() {
return !!document.querySelector(".app")?.classList.contains("cat-collapsed");
}

function wireCatalogToggle() {
const toggle = document.getElementById("catalogToggle");
const collapseBtn = document.getElementById("sidebarCollapseBtn");
Expand All @@ -1998,12 +2022,6 @@ function wireCatalogToggle() {
collapseBtn?.setAttribute("aria-expanded", "false");
}

function setSidebarCollapsed(isCollapsed) {
app.classList.toggle("cat-collapsed", isCollapsed);
collapseBtn?.setAttribute("aria-expanded", String(!isCollapsed));
localStorage.setItem("stemdeck.catalog.collapsed", isCollapsed ? "1" : "0");
}

collapseBtn?.addEventListener("click", () => {
setSidebarCollapsed(!app.classList.contains("cat-collapsed"));
});
Expand Down
Loading
Loading