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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ StemDeck is free and **does not accept any money, sponsorship, or funding** fro
| Music & Karaoke Technology | Seratone | TV-based karaoke system | [seratone.audio](https://seratone.audio/) |
| Media & Community | slashCAM | Camera, video, and post-production media | [@slashcam.de](https://www.instagram.com/slashcam.de) |
| Media & Community | r/bass | Bass-player community | [r/Bass](https://www.reddit.com/r/Bass) |
| Media & Community | Not Another Audio Podcast | Audio, music and tech industry podcast by working professionals | [Libsyn](https://directory.libsyn.com/shows/view/id/20f5a1e3-6fea-4d41-8cdf-451ce6fc6cda) |
| Writers & Storytellers | Alexandre Borges | Portuguese writer, screenwriter, and cultural commentator | [Books & author profile](https://www.instagram.com/alexgram_b/) |


Expand Down
136 changes: 128 additions & 8 deletions static/css/daw.css
Original file line number Diff line number Diff line change
Expand Up @@ -4467,7 +4467,18 @@ input, textarea { font-family: inherit; }
position: relative;
grid-column: 2;
grid-row: 1 / 3;
justify-self: stretch;
/* As wide as the track it is naming, not as wide as the window.
It was stretched to fill its column, so a spare 400px of bar became 400px
of card with the same text sitting in it. It sizes to its content now and
stops; a long title clips with an ellipsis at the cap rather than dragging
the card out to meet it. */
justify-self: start;
/* A real ceiling, not a percentage of the column: 100% just meant "as wide
as the bar allows", so the card was 422px at 1600 and 460 at 1920 with the
same text in it. 460 is what the meta line needs at its longest, duration
through to the extracted date, so the card is the same size at every
window width and a long title clips rather than pushing it wider. */
max-width: min(100%, 460px);
align-self: stretch;
/* .footer-track-slot is `width: var(--daw-col-w)`, which is the gutter width
it was built to fill in the footer. Here the column decides the width, so
Expand Down Expand Up @@ -4678,13 +4689,6 @@ input, textarea { font-family: inherit; }
@media (max-width: 1460px) {
.daw-composer > #nowPlayingPanel { display: none; }
}
@media (max-width: 1320px) {
.daw-composer > .daw-panel-toggles {
grid-column: 1 / -1;
grid-row: 3;
justify-self: end;
}
}

/* The click-track options with nothing to act on.
*
Expand All @@ -4695,3 +4699,119 @@ input, textarea { font-family: inherit; }
opacity: 0.4;
pointer-events: none;
}

/* Vocals and its two mode buttons, as one thing.
*
* Grouped by proximity, not by a box. A frame around them needed padding and
* borders of its own, which made the group 38px tall in a row of 30px chips:
* it hung 8px below everything beside it. Joining them instead costs no height
* at all, and a segmented control is what this is.
*
* So the chip and the toggle touch, their facing corners square off, and the
* gap that used to sit between them moves to the outside of the pair. */
.stem-group {
display: inline-flex;
align-items: center;
gap: 0;
margin-right: 5px;
}
.stem-group:not(:has(.vocal-mode-toggle:not(.hidden))) {
margin-right: 0;
}
/* Facing edges square, and only one border between them. */
.stem-group:has(.vocal-mode-toggle:not(.hidden)) .stem-choice[data-stem="vocals"] {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.stem-group .vocal-mode-toggle {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border-left: none;
}
/* The mode buttons take the Vocals chip's border, and only its border, so one
outline runs round the three of them.
*
* The outline is the grouping cue; the fill is not available for it. Tinting
* the whole toggle made "Lead + Backing" look selected when it is not, and
* left the active mode barely distinguishable from the inactive one, because
* that mode's own 16% was sitting on top of the group's 14%. Inside the
* outline the three states stay readable: Vocals is tinted because the stem is
* selected, the active mode is tinted because it is the mode, and the other
* one is plain.
*
* Keyed off the chip's pressed state, because the toggle is only on screen
* while Vocals is selected and should not be left as the one thing still
* wearing the colour if that ever changes. */
.stem-group:has(.stem-choice[data-stem="vocals"][aria-pressed="true"]) .vocal-mode-toggle {
--color: var(--vocals);
border-color: color-mix(in srgb, var(--color) 60%, transparent);
}
/* The divider between All and Lead + Backing comes from the same colour, so it
reads as an internal seam rather than a second frame. */
.stem-group:has(.stem-choice[data-stem="vocals"][aria-pressed="true"]) .vocal-mode-btn + .vocal-mode-btn {
border-left: 1px solid color-mix(in srgb, var(--color) 60%, transparent);
}

/* ── The Extract chips, and what happens when they stop fitting ───────────
The row never wraps and the bar never gets taller. As the window narrows,
whichever chips no longer fit move into a panel behind a three-dot button,
one at a time, from the end of the row. The button sits after the row, on the
side the chips are leaving from, and is hidden entirely while everything
fits.

Wrapping was the alternative and it is the wrong one here: the composer went
from 96px tall to 168 and then 236 as the chips spilled onto further lines,
so the bar grew exactly as the window shrank, and the controls on the right
were left stranded at the top of a column stretched by chips they have
nothing to do with.

The measuring is in fitStemChips in main.js; this is only what it looks
like.
───────────────────────────────────────────────────────────────────────── */
.stem-more-btn {
display: inline-flex;
align-items: center;
justify-content: center;
flex: none;
width: 34px;
height: 30px;
margin-left: 5px;
border: 1px solid var(--border);
border-radius: 6px;
background: none;
color: var(--muted-2);
cursor: pointer;
transition: background var(--t-fast), border-color var(--t-fast), color var(--t-fast);
}
.stem-more-btn[hidden] { display: none; }
.stem-more-btn:hover { background: var(--panel-2); color: var(--fg); }
.stem-more-btn[aria-expanded="true"] { border-color: var(--accent); color: var(--accent); }

/* One line, always. Overflow hidden so a chip mid-move is never half drawn,
and so this element's clientWidth is the honest budget fitStemChips
measures against. */
.daw-composer .daw-stem-chips {
flex: 1 1 auto;
min-width: 0;
flex-wrap: nowrap;
overflow: hidden;
}

/* Fixed rather than absolute, for the same reason the footer's options panel
is: it has to escape the bar it is anchored in. JS sets left/top from the
button's own rect. */
.stem-overflow {
position: fixed;
z-index: 320;
display: none;
flex-wrap: wrap;
align-items: center;
gap: 6px;
max-width: min(560px, calc(100vw - 32px));
padding: 10px;
background: var(--panel);
border: 1px solid var(--border-strong);
border-radius: 10px;
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.42);
}
.stem-overflow.open { display: flex; }
Binary file added static/img/friends/not-another-audio-podcast.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
69 changes: 40 additions & 29 deletions static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -90,17 +90,22 @@
<!-- Stem selection -->
<div class="daw-stem-section">
<span class="daw-extract-label" data-i18n="extract.label">Extract</span>
<div class="daw-stem-chips">
<div class="daw-stem-chips" id="stemChips">
<button class="stem-choice stem-choice-all" type="button" id="stemAllBtn" aria-pressed="true" data-i18n="extract.all">All</button>
<button class="stem-choice" type="button" data-stem="vocals" aria-pressed="true" style="--color:var(--vocals)">
<span data-i18n="stem.vocals">Vocals</span>
</button>
<!-- On-demand lead/backing vocal split (#275). Shown only while
Vocals is selected above; toggling "Lead + Backing" auto-runs
the split once the import finishes (see main.js/job.js). -->
<div class="vocal-mode-toggle hidden" id="vocalModeToggle" role="group" aria-label="Vocals mode" data-i18n-aria-label="vocalMode.groupAria">
<button type="button" class="vocal-mode-btn" data-mode="all" aria-pressed="true" data-i18n="vocalMode.all">All</button>
<button type="button" class="vocal-mode-btn" data-mode="split" aria-pressed="false" data-i18n="vocalMode.split">Lead + Backing</button>
<!-- Vocals and the two things that describe it, in one group.
Loose in the row, the mode buttons read as peers of Drums and
Bass rather than as a choice about the chip beside them. -->
<div class="stem-group stem-group-vocals">
<button class="stem-choice" type="button" data-stem="vocals" aria-pressed="true" style="--color:var(--vocals)">
<span data-i18n="stem.vocals">Vocals</span>
</button>
<!-- On-demand lead/backing vocal split (#275). Shown only while
Vocals is selected above; toggling "Lead + Backing" auto-runs
the split once the import finishes (see main.js/job.js). -->
<div class="vocal-mode-toggle hidden" id="vocalModeToggle" role="group" aria-label="Vocals mode" data-i18n-aria-label="vocalMode.groupAria">
<button type="button" class="vocal-mode-btn" data-mode="all" aria-pressed="true" data-i18n="vocalMode.all">All</button>
<button type="button" class="vocal-mode-btn" data-mode="split" aria-pressed="false" data-i18n="vocalMode.split">Lead + Backing</button>
</div>
</div>
<button class="stem-choice" type="button" data-stem="drums" aria-pressed="true" style="--color:var(--drums)">
<span data-i18n="stem.drums">Drums</span>
Expand All @@ -118,6 +123,18 @@
<span data-i18n="stem.other">Other</span>
</button>
</div>
<button class="stem-more-btn" id="stemMoreBtn" type="button" aria-haspopup="true" aria-expanded="false"
aria-controls="stemOverflow" title="More stems" data-i18n-title="extract.moreAria"
aria-label="More stems" data-i18n-aria-label="extract.moreAria" hidden>
<svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true">
<circle cx="5" cy="12" r="1.8"/><circle cx="12" cy="12" r="1.8"/><circle cx="19" cy="12" r="1.8"/>
</svg>
</button>
<!-- Holds whichever chips no longer fit, and nothing else. It
appears the moment the first one has to move and grows as the
window narrows, so the row never wraps and the bar never gets
taller. See fitStemChips in main.js. -->
<div class="stem-overflow" id="stemOverflow" role="group" aria-label="More stems" data-i18n-aria-label="extract.moreAria"></div>
</div>

<!-- Experimental automatic song-structure detection. Off makes the
Expand Down Expand Up @@ -193,26 +210,20 @@
stub costs most of what collapsing the smaller ones returns. -->
<div class="daw-panel-toggles">
<!-- "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 three are.

The library is not one of them, and not by omission: "All" used
to collapse it too, and nothing in this row could put it back
(#588). Its control lives in the rail. -->
after it: everything to its right is a button. The label is one
word because the row has no width for a sentence.

There was an "All" here, one press to put every panel away. It
governed two panels by the end, so it saved a single press, and
it was another control in this bar wearing a word that already
means something else two rows up. The panels it governed each
have their own button, which is the only way back from a
collapsed one.

The library was never among them, and not by omission: it used to
be, and nothing in this row could put it back (#588). Its control
lives in the rail. -->
<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" 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
7 changes: 7 additions & 0 deletions static/js/catalog.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,13 @@ const FRIEND_GROUPS = [
roleKey: "friends.role.rbass",
url: "https://www.reddit.com/r/Bass/",
},
{
name: "Not Another Audio Podcast",
roleKey: "friends.role.notAnotherAudioPodcast",
url: "https://directory.libsyn.com/shows/view/id/20f5a1e3-6fea-4d41-8cdf-451ce6fc6cda",
logo: "/img/friends/not-another-audio-podcast.jpg",
avatar: true,
},
],
},
{
Expand Down
Loading
Loading