From 6274d68d3da81a544ab9fc5de374dd39b4c0f34b Mon Sep 17 00:00:00 2001 From: Chris <26607885+chrisglein@users.noreply.github.com> Date: Sat, 11 Jul 2026 22:56:52 -0700 Subject: [PATCH 1/3] Add lean songbook UI, move ABC editing behind Advanced (#46) Redesign the home page for a songbook+ audience: a tight top toolbar now leads with a song picker (labeled with the current title), compact icon toggles for lyrics/trumpet/tab, and a transpose control that's a key dropdown showing the current key with each destination key's semitone offset. The ABC textarea, "No errors" indicator, ABC-notation link, GitHub "add a song" link, PDF/QR block, and commit-hash link move into a hidden #advanced panel, revealed by a gear toggle or ?advanced=true. Also fix a latent bug where trumpet fingering never displayed (filter checked #show-trumpt instead of #show-trumpet). --- src/index.pug | 211 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 145 insertions(+), 66 deletions(-) diff --git a/src/index.pug b/src/index.pug index b1a9f16..696656b 100644 --- a/src/index.pug +++ b/src/index.pug @@ -15,66 +15,101 @@ append head } body { padding: 1em } #paper { width: 100% } - .item { - margin-left: 1em; + .item { white-space: nowrap } + + /* lean toolbar */ + #toolbar { gap: .45rem; margin-top: .6rem } + #toolbar .btn .bi { vertical-align: -.15em } + #toolbar .btn .bi + span, + #toolbar .btn .bi + * { margin-left: .35em } + #toolbar .btn-group-toggle .btn .bi { margin-right: .35em } + #toolbar #songLabel { + display: inline-block; + max-width: 45vw; + overflow: hidden; + text-overflow: ellipsis; + vertical-align: bottom; white-space: nowrap; } + #toolbar .dropdown-menu { max-height: 60vh; overflow-y: auto } + #key-menu { min-width: 7rem } - button { margin-right: 1ex } + /* advanced panel (power-user / editing) */ + #advanced { display: none; margin-top: 1rem } + #advanced > * { margin-bottom: .8rem } @media print { .noprint { display: none !important } } append body + //- inline Bootstrap-icons style glyph (no extra deps): pass an array of {d, fr?} + mixin bi(paths) + svg.bi(xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16" aria-hidden="true" focusable="false") + each p in paths + if p.fr + path(fill-rule=p.fr d=p.d) + else + path(d=p.d) + + #toolbar.noprint.d-flex.flex-wrap.align-items-center + //- Song picker (primary action) + .dropdown + button.btn.btn-primary.dropdown-toggle#songFile(type="button" data-toggle="dropdown" title="Choose a song") + +bi([{d:'M6 13c0 1.105-1.12 2-2.5 2S1 14.105 1 13c0-1.104 1.12-2 2.5-2s2.5.896 2.5 2zm9-2c0 1.105-1.12 2-2.5 2S10 12.105 10 11c0-1.104 1.12-2 2.5-2s2.5.896 2.5 2z'},{fr:'evenodd',d:'M14 11V2h1v9h-1zM6 3v10H5V3h1z'},{d:'M5 2.905a1 1 0 0 1 .9-.995l8-.8a1 1 0 0 1 1.1.995V3L5 4V2.905z'}]) + span#songLabel Pick a song + .dropdown-menu#song-menu(aria-labelledby="songFile") + - var keys = Object.keys(src['by-title.json']) + - keys.sort() + each k in keys + a.dropdown-item(href="#")= k + + //- View toggles + .btn-group.btn-group-toggle.btn-group-sm#viewToggles(data-toggle="buttons") + label.btn.btn-outline-secondary.active(title="Show lyrics") + input#show-lyrics(type="checkbox" checked autocomplete="off") + +bi([{d:'M14.5 3a.5.5 0 0 1 .5.5v9a.5.5 0 0 1-.5.5h-13a.5.5 0 0 1-.5-.5v-9a.5.5 0 0 1 .5-.5h13zm-13-1A1.5 1.5 0 0 0 0 3.5v9A1.5 1.5 0 0 0 1.5 14h13a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 14.5 2h-13z'},{d:'M3 5.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zM3 8a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9A.5.5 0 0 1 3 8zm0 2.5a.5.5 0 0 1 .5-.5h6a.5.5 0 0 1 0 1h-6a.5.5 0 0 1-.5-.5z'}]) + | Lyrics + label.btn.btn-outline-secondary(title="Show trumpet fingering") + input#show-trumpet(type="checkbox" autocomplete="off") + svg.bi(xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16" aria-hidden="true" focusable="false") + circle(cx="3.6" cy="8" r="2.1") + circle(cx="8" cy="8" r="2.1") + circle(cx="12.4" cy="8" r="2.1") + | Trumpet + label.btn.btn-outline-secondary(title="Show guitar tab") + input#show-gtab(type="checkbox" autocomplete="off") + svg.bi(xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.3" viewBox="0 0 16 16" aria-hidden="true" focusable="false") + path(d="M1 3.5h14M1 6.5h14M1 9.5h14M1 12.5h14") + | Tab + + //- Transpose: pick the destination key (offset shown) + .dropdown + button.btn.btn-outline-secondary.btn-sm.dropdown-toggle#keyBtn(type="button" data-toggle="dropdown" title="Transpose: choose a key") + +bi([{fr:'evenodd',d:'M11.5 15a.5.5 0 0 0 .5-.5V2.707l3.146 3.147a.5.5 0 0 0 .708-.708l-4-4a.5.5 0 0 0-.708 0l-4 4a.5.5 0 1 0 .708.708L11 2.707V14.5a.5.5 0 0 0 .5.5zm-7-14a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L4 13.293V1.5a.5.5 0 0 1 .5-.5z'}]) + span#keyLabel – + .dropdown-menu.dropdown-menu-right#key-menu(aria-labelledby="keyBtn") + + //- Advanced / edit ABC (power users) + button.btn.btn-outline-secondary.btn-sm.ml-auto#advancedToggle(type="button" title="Advanced / edit ABC" aria-pressed="false") + +bi([{d:'M8 4.754a3.246 3.246 0 1 0 0 6.492 3.246 3.246 0 0 0 0-6.492zM5.754 8a2.246 2.246 0 1 1 4.492 0 2.246 2.246 0 0 1-4.492 0z'},{d:'M9.796 1.343c-.527-1.79-3.065-1.79-3.592 0l-.094.319a.873.873 0 0 1-1.255.52l-.292-.16c-1.64-.892-3.433.902-2.54 2.541l.159.292a.873.873 0 0 1-.52 1.255l-.319.094c-1.79.527-1.79 3.065 0 3.592l.319.094a.873.873 0 0 1 .52 1.255l-.16.292c-.892 1.64.901 3.434 2.541 2.54l.292-.159a.873.873 0 0 1 1.255.52l.094.319c.527 1.79 3.065 1.79 3.592 0l.094-.319a.873.873 0 0 1 1.255-.52l.292.16c1.64.893 3.434-.902 2.54-2.541l-.159-.292a.873.873 0 0 1 .52-1.255l.319-.094c1.79-.527 1.79-3.065 0-3.592l-.319-.094a.873.873 0 0 1-.52-1.255l.16-.292c.893-1.64-.902-3.434-2.541-2.54l-.292.159a.873.873 0 0 1-1.255-.52l-.094-.319zm-2.633.283c.246-.835 1.428-.835 1.674 0l.094.319a1.873 1.873 0 0 0 2.693 1.115l.291-.16c.764-.415 1.6.42 1.184 1.185l-.159.292a1.873 1.873 0 0 0 1.116 2.692l.318.094c.835.246.835 1.428 0 1.674l-.319.094a1.873 1.873 0 0 0-1.115 2.693l.16.291c.415.764-.42 1.6-1.185 1.184l-.291-.159a1.873 1.873 0 0 0-2.693 1.116l-.094.318c-.246.835-1.428.835-1.674 0l-.094-.319a1.873 1.873 0 0 0-2.692-1.115l-.292.16c-.764.415-1.6-.42-1.184-1.185l.159-.291A1.873 1.873 0 0 0 1.945 8.93l-.319-.094c-.835-.246-.835-1.428 0-1.674l.319-.094A1.873 1.873 0 0 0 3.06 4.377l-.16-.292c-.415-.764.42-1.6 1.185-1.184l.292.159a1.873 1.873 0 0 0 2.692-1.115l.094-.319z'}]) + #paper - .noprint.d-flex.flex-wrap.align-items-center + + #advanced.noprint .item - span Enter some + span Enter some a(href="https://github.com/brewingcode/shanties/blob/master/README.md" target="_blank") ABC notation - .item - span or - .dropdown.d-inline-block - button.btn.dropdown-toggle(type="button" id="songFile" data-toggle="dropdown") Pick a song - .dropdown-menu(aria-labelledby="songFile") - - var keys = Object.keys(src['by-title.json']) - - keys.sort() - each k in keys - a.dropdown-item(href="#")= k - .item - span or + span , or a(href="https://github.com/brewingcode/shanties/tree/master/songs") - svg(xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16") - path(d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.012 8.012 0 0 0 16 8c0-4.42-3.58-8-8-8z") - span add a song - - .noprint: textarea#abc(spellcheck="false") - .noprint: #warnings - .noprint#settings - label - span Show lyrics - input#show-lyrics(type="checkbox" checked) - span - label - span Show trumpet fingering - input#show-trumpet(type="checkbox") - span - label - span Show guitar tab - input#show-gtab(type="checkbox") - span - label - span Transpose: - input#transpose(type="number" min="-24" max="24" step="1" value="0") - span - span#fromKey - span -> - span#toKey - .noprint + +bi([{d:'M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.012 8.012 0 0 0 16 8c0-4.42-3.58-8-8-8z'}]) + span add a song + textarea#abc(spellcheck="false") + #warnings p The Songbook PDF can be found at this link, or via this QR code: img(src="qr-code.svg" alt="https://brewingcode.github.io/shanties/Songbook.pdf" width="200" height="200") - .noprint - a(href="https://github.com/brewingcode/shanties/commit/" + src['GIT_HEAD'])= src['GIT_HEAD'] + div + a(href="https://github.com/brewingcode/shanties/commit/" + src['GIT_HEAD'])= src['GIT_HEAD'] script. var songs = !{JSON.stringify(src['songs.json'])}; var byTitle = !{JSON.stringify(src['by-title.json'])}; @@ -96,6 +131,39 @@ append body else k.root + CHROMATIC = ['C', 'D♭', 'D', 'E♭', 'E', 'F', 'G♭', 'G', 'A♭', 'A', 'B♭', 'B'] + prevStep = 0 + origPc = null + + keyToPc = (name) -> + return null unless name + base = { C: 0, D: 2, E: 4, F: 5, G: 7, A: 9, B: 11 } + pc = base[name.charAt(0)] + return null unless pc? + pc += 1 if name.indexOf('#') >= 0 or name.indexOf('♯') >= 0 + pc -= 1 if name.indexOf('♭') >= 0 + ((pc % 12) + 12) % 12 + + updateKeyLabel = -> + k = displayKey() or '–' + k += " (#{if prevStep > 0 then '+' else ''}#{prevStep})" unless prevStep is 0 + $('#keyLabel').text k + $('#key-menu .dropdown-item').each -> + $(this).toggleClass 'active', +$(this).attr('data-offset') is prevStep + + buildKeyMenu = -> + menu = $('#key-menu').empty() + return unless origPc? + for d in [-5..6] + pc = (((origPc + d) % 12) + 12) % 12 + label = CHROMATIC[pc] + label += " (#{if d > 0 then '+' else ''}#{d})" unless d is 0 + $('') + .attr('data-offset', d) + .text(label) + .appendTo menu + updateKeyLabel() + setSong = (song) -> s = song .split /\n/ @@ -104,7 +172,7 @@ append body lyrics = m[1] if lyrics.match /^[\s\d\?]+$/ # all digits are trumpet fingering, keep those - return $('#show-trumpt').is(':checked') + return $('#show-trumpet').is(':checked') else return $('#show-lyrics').is(':checked') else @@ -114,10 +182,10 @@ append body document.title = Object.entries(byTitle) .find ([k,v]) -> v is song ?.at(0) or 'YEEAAARGH' + prevStep = 0 setTimeout -> - k = displayKey() - $('#fromKey').text(k) - $('#toKey').text(k) + origPc = keyToPc displayKey() + buildKeyMenu() , 500 updateUrl = (title) -> @@ -126,37 +194,38 @@ append body window.history.replaceState {}, '', "#{window.location.pathname}?#{params}" addEditButton = -> - $('#settings > button').remove() - $('#settings').prepend """ - """ - $('#settings > button').on 'click', (e) -> - $(e.target).remove() + $('#advanced > .edit-btn').remove() + btn = $('') + btn.on 'click', -> + btn.remove() $('#abc').prop('disabled', false) .focus() - .on 'blur', (e) -> + .on 'blur', -> $('#abc').prop 'disabled', true addEditButton() + $('#advanced').prepend btn window.onload = -> - prevStep = 0 window.editor = new ABCJS.Editor 'abc', canvas_id: 'paper', warnings_id: 'warnings' abcjsParams: abcjsParams - $('.dropdown-menu a').click -> - setSong byTitle[$(this).text()] - updateUrl $(this).text() + $('#song-menu a.dropdown-item').click (e) -> + e.preventDefault() + title = $(this).text() + setSong byTitle[title] + $('#songLabel').text title + updateUrl title - $('#transpose').on 'change', -> - tv = +$('#transpose').val() - $('#fromKey').text $('#toKey').text() + $('#key-menu').on 'click', '.dropdown-item', (e) -> + e.preventDefault() + tv = +$(this).attr('data-offset') + return if tv is prevStep newTunes = ABCJS.strTranspose $('#abc').val(), window.editor.tunes, tv - prevStep - window.editor.editarea.setString(newTunes) + window.editor.editarea.setString newTunes prevStep = tv - setTimeout -> - $('#toKey').text displayKey() - , 500 + setTimeout updateKeyLabel, 500 $('#show-lyrics, #show-trumpet').on 'change', -> setSong byTitle[document.title] @@ -172,16 +241,26 @@ append body }] } + $('#advancedToggle').on 'click', -> + shown = $('#advanced').toggle().is(':visible') + $(this).toggleClass('active', shown).attr 'aria-pressed', shown + params = new URLSearchParams(window.location.search) file = params.get('file') title = params.get('title') if file and songs[file] setSong songs[file] + $('#songLabel').text(document.title) unless document.title is 'YEEAAARGH' else if title and byTitle[title] setSong byTitle[title] + $('#songLabel').text title else setSong "%%notelabels 1\nB c d e | ff | c'd' | EE E | =D^D" + if params.get('advanced') is 'true' + $('#advanced').show() + $('#advancedToggle').addClass('active').attr 'aria-pressed', true + if navigator.userAgent.match /i(Pad|Phone)/i $('#abc').prop 'disabled', true addEditButton() From 7b8ecacc4da0d544746668d4ec89b58044395161 Mon Sep 17 00:00:00 2001 From: Chris <26607885+chrisglein@users.noreply.github.com> Date: Sun, 12 Jul 2026 06:41:23 -0700 Subject: [PATCH 2/3] Add Staff toggle & note-render toggles, emoji icons, songbook dialog (#46, #27) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refine the lean home UI: - New Staff toggle: hides the whole notation image (abcjs couples staff/notes/lyrics/tab and can't reflow), surfacing the song's extended W: verses as text. Pure-CSS via body.no-staff, overriding abcjs's inline padding-bottom so width is kept and the staff re-renders crisply when shown again. Color/Labels auto-disable when the staff is hidden. - Note color & note labels are now UI toggles (issue #27): removed the hardcoded %%notecolors/%%notelabels from all 26 songs/*.txt and the default snippet; they're injected before rendering based on the Color/Labels toggles (default on, so the look is unchanged). - Icons switched to emoji (song 🎶, staff 🎼, color 🎨, labels 🔤, lyrics 🗣️, trumpet 🎺, guitar 🎸, songbook 📄, edit 🖊️). - Rename "Tab" -> "Guitar"; Key control now reads "Key: E♭ (+2)". - Edit button is a pen (was a gear); the advanced panel is now ABC-only (links, textarea, warnings). - Songbook PDF + QR moved into a modal launched by 📄, with the commit hash relocated to its footer as the version, separating it from the ABC-editing controls. --- songs/all-for-me-grog.txt | 2 - songs/ballad-of-the-mer.txt | 2 - songs/barretts-privateers.txt | 1 - songs/bosun-bill.txt | 2 - songs/bully-boys.txt | 2 - songs/bully-in-the-alley.txt | 2 - songs/deck-the-halls.txt | 2 - songs/drunken-sailor.txt | 2 - songs/health-to-the-company.txt | 2 - songs/joli-rouge.txt | 2 - songs/leave-her-johnny.txt | 2 - songs/lifeboat-prayer.txt | 1 - songs/mario.txt | 2 - songs/mercy-mercy-mercy.txt | 2 - songs/mingulay-boat-song.txt | 2 - songs/old-maui.txt | 1 - songs/randy-dandy-o.txt | 2 - songs/roll-the-old-chariot-along.txt | 2 - songs/skipper-jan-rebec.txt | 1 - songs/song-of-storms.txt | 2 - songs/south-australia.txt | 2 - songs/the-last-shanty.txt | 2 - songs/toss-a-coin-to-your-witcher.txt | 2 - songs/we-wish-you-a-merry-xmas.txt | 2 - songs/wellerman.txt | 2 - songs/whiskey-johnny.txt | 2 - src/index.pug | 126 ++++++++++++++++++++------ 27 files changed, 99 insertions(+), 75 deletions(-) diff --git a/songs/all-for-me-grog.txt b/songs/all-for-me-grog.txt index 03c57a2..629a6e8 100644 --- a/songs/all-for-me-grog.txt +++ b/songs/all-for-me-grog.txt @@ -1,8 +1,6 @@ X: 1 T: All For Me Grog %%vocalfont times 10 -%%notecolors 1 -%%notelabels 1 M: 4/4 L: 1/8 K: C diff --git a/songs/ballad-of-the-mer.txt b/songs/ballad-of-the-mer.txt index 7891d93..0f6a0bd 100644 --- a/songs/ballad-of-the-mer.txt +++ b/songs/ballad-of-the-mer.txt @@ -1,7 +1,5 @@ T: Ballad of the Mer %%vocalfont times 10 -%%notecolors 1 -%%notelabels 1 L:1/4 K: Eb M: 3/4 diff --git a/songs/barretts-privateers.txt b/songs/barretts-privateers.txt index 10c6501..3ebf0ef 100644 --- a/songs/barretts-privateers.txt +++ b/songs/barretts-privateers.txt @@ -1,7 +1,6 @@ T: Barrett's Privateers K: C L: 1/8 -%%notelabels 1 P: Verse C3 E | "C" G2 G2 "F" FF E2 | "G"DD D2 "C"C2 GG | GG3 "F"A2 A2 | "C"G2 G2 | "G"D4 z2 A2 | w: Oh, the year was se-ven-teen sev-en-ty eight, how I wish I was in Sher-brooke now! A diff --git a/songs/bosun-bill.txt b/songs/bosun-bill.txt index 2e558ff..6f5c3f4 100644 --- a/songs/bosun-bill.txt +++ b/songs/bosun-bill.txt @@ -1,8 +1,6 @@ X: 1 T: Bosun Bill %%vocalfont times 10 -%%notecolors 1 -%%notelabels 1 M: 2/4 L: 1/16 K: Eb diff --git a/songs/bully-boys.txt b/songs/bully-boys.txt index a938f4d..8559f67 100644 --- a/songs/bully-boys.txt +++ b/songs/bully-boys.txt @@ -1,8 +1,6 @@ X: 1 T: Bully Boys %%vocalfont times 10 -%%notecolors 1 -%%notelabels 1 M: 6/8 K: C Q: 1/4=140 diff --git a/songs/bully-in-the-alley.txt b/songs/bully-in-the-alley.txt index 2722bd6..2e8523c 100644 --- a/songs/bully-in-the-alley.txt +++ b/songs/bully-in-the-alley.txt @@ -1,8 +1,6 @@ X: 1 T: Bully in the Alley %%vocalfont times 10 -%%notecolors 1 -%%notelabels 1 K: G M: 4/4 Q: 1/4=150 diff --git a/songs/deck-the-halls.txt b/songs/deck-the-halls.txt index 221c527..b869459 100644 --- a/songs/deck-the-halls.txt +++ b/songs/deck-the-halls.txt @@ -1,6 +1,4 @@ T: Deck the Halls -%%notecolors 1 -%%notelabels 1 K: D L: 1/8 "D"A3 G "A"F2 E2 | "D"D2 E2 "D_"F2 D2 | "A7"EFGE "D"F3 E | "A7"D2 C2 "D"D4 | diff --git a/songs/drunken-sailor.txt b/songs/drunken-sailor.txt index 650fa72..d9cfadb 100644 --- a/songs/drunken-sailor.txt +++ b/songs/drunken-sailor.txt @@ -1,7 +1,5 @@ T: Drunken Sailor %%vocalfont times 10 -%%notecolors 1 -%%notelabels 1 K: Dm M: 4/4 "Dm"a2 aa a2 aa | a2 d2 f2 a2 | "C"g2 gg g2 gg | g2 c2 e2 g2 | diff --git a/songs/health-to-the-company.txt b/songs/health-to-the-company.txt index 8a4d149..03b1696 100644 --- a/songs/health-to-the-company.txt +++ b/songs/health-to-the-company.txt @@ -1,7 +1,5 @@ T: Health to the Company %%vocalfont times 10 -%%notecolors 1 -%%notelabels 1 M: 3/4 L: 1/8 Q: 1/4=110 diff --git a/songs/joli-rouge.txt b/songs/joli-rouge.txt index 79accfd..1fb48d3 100644 --- a/songs/joli-rouge.txt +++ b/songs/joli-rouge.txt @@ -1,8 +1,6 @@ X: 1 T: Joli Rouge %%vocalfont times 10 -%%notecolors 1 -%%notelabels 1 M: 6/8 K: Dm "Dm" D3 [F2A] [FA] | "Am" A,3 [C3E] | "Dm" D3 [F2A] [FA] | "Am" A,3 [C3E] | "Dm" D3 [F2A] [FA] | "Am" A,3 [C3EG] | diff --git a/songs/leave-her-johnny.txt b/songs/leave-her-johnny.txt index 598e904..bf6d574 100644 --- a/songs/leave-her-johnny.txt +++ b/songs/leave-her-johnny.txt @@ -1,7 +1,5 @@ T: Leave Her Johnny %%vocalfont times 10 -%%notecolors 1 -%%notelabels 1 K: C M: 4/4 cd | "C"e2 e2 e2 cd | e2 d2 c4 | "G"d2 d2 d3 c | "C"e2 g4 diff --git a/songs/lifeboat-prayer.txt b/songs/lifeboat-prayer.txt index fcfdb7c..1d18611 100644 --- a/songs/lifeboat-prayer.txt +++ b/songs/lifeboat-prayer.txt @@ -1,7 +1,6 @@ T: Lifeboat Prayer K: D L: 1/8 -%%notelabels 1 "D" A3A F3 D "G" G3 A "D" F3 D "G" G3 A "D" FE D "A" E3 F E3 w: Those who ven-ture on the sea to ply their trade _ up-on the deep w: When the call for res-cue comes, from those in per- _ il on this day diff --git a/songs/mario.txt b/songs/mario.txt index 0b3959d..dbd1ca8 100644 --- a/songs/mario.txt +++ b/songs/mario.txt @@ -1,7 +1,5 @@ X: 1 T: Mario Bros. Theme -%%notecolors 1 -%%notelabels 1 M: 4/4 L: 1/16 K: G diff --git a/songs/mercy-mercy-mercy.txt b/songs/mercy-mercy-mercy.txt index aec5bed..eb349ed 100644 --- a/songs/mercy-mercy-mercy.txt +++ b/songs/mercy-mercy-mercy.txt @@ -1,7 +1,5 @@ T: Mercy, Mercy, Mercy %%vocalfont times 10 -%%notecolors 1 -%%notelabels 1 K: F M: 4/4 "C7" z2 A G2 "C7/E" EEC | "F" DCCA, "G7sus" C2 D2 diff --git a/songs/mingulay-boat-song.txt b/songs/mingulay-boat-song.txt index e97e91a..b39b579 100644 --- a/songs/mingulay-boat-song.txt +++ b/songs/mingulay-boat-song.txt @@ -1,7 +1,5 @@ T: Mingulay Boat Song %%vocalfont times 10 -%%notecolors 1 -%%notelabels 1 M: 3/4 Q: 1/4=140 K: G diff --git a/songs/old-maui.txt b/songs/old-maui.txt index 1fe3110..d9a3d95 100644 --- a/songs/old-maui.txt +++ b/songs/old-maui.txt @@ -1,6 +1,5 @@ T: Old Maui K: G -%%notelabels 1 P: Verse BB | "Em"e2 e2 "B"^d2 BB | "G"g2 fe "D"f2 (ba) | "Em"(gf) e2 "B"f2 de | "Em"e4 BB | w:It's a damn tough life full of toil and ~ strife we ~ wha-ler-men un-der - go, and we diff --git a/songs/randy-dandy-o.txt b/songs/randy-dandy-o.txt index 8797680..1c07669 100644 --- a/songs/randy-dandy-o.txt +++ b/songs/randy-dandy-o.txt @@ -1,7 +1,5 @@ T: Randy Dandy-O %%vocalfont times 10 -%%notecolors 1 -%%notelabels 1 K: C M: 6/8 L: 1/16 diff --git a/songs/roll-the-old-chariot-along.txt b/songs/roll-the-old-chariot-along.txt index c92910e..6c9b04a 100644 --- a/songs/roll-the-old-chariot-along.txt +++ b/songs/roll-the-old-chariot-along.txt @@ -1,7 +1,5 @@ T: Roll the Old Chariot Along %%vocalfont times 10 -%%notecolors 1 -%%notelabels 1 K: Dm M: 4/4 Q: 1/4=140 diff --git a/songs/skipper-jan-rebec.txt b/songs/skipper-jan-rebec.txt index 93ecd70..f1f52b8 100644 --- a/songs/skipper-jan-rebec.txt +++ b/songs/skipper-jan-rebec.txt @@ -1,5 +1,4 @@ T: Skipper Jan Rebec -%%notelabels 1 K: Eb "Eb"GGGEB,"Bb"CE "Eb"E EE"F"DEF "Eb"GGEE"Bb"AAA| A"Eb"GE"F"FD"Eb"E EFGEB,EEE | GE"F"FFF | "Eb"GE"Bb"AAAA | "Eb"GE"F"FD"Eb"E \ No newline at end of file diff --git a/songs/song-of-storms.txt b/songs/song-of-storms.txt index b5cd15d..7a5ef91 100644 --- a/songs/song-of-storms.txt +++ b/songs/song-of-storms.txt @@ -1,6 +1,4 @@ T: Song of Storms -%%notecolors 1 -%%notelabels 1 K: Dm L: 1/4 M: 6/8 diff --git a/songs/south-australia.txt b/songs/south-australia.txt index 8033e76..ab53f11 100644 --- a/songs/south-australia.txt +++ b/songs/south-australia.txt @@ -1,7 +1,5 @@ T: South Australia %%vocalfont times 10 -%%notecolors 1 -%%notelabels 1 M: 4/4 K: E P: Part A diff --git a/songs/the-last-shanty.txt b/songs/the-last-shanty.txt index 5cb1a72..562cec2 100644 --- a/songs/the-last-shanty.txt +++ b/songs/the-last-shanty.txt @@ -1,8 +1,6 @@ X: 1 T: The Last Shanty %%vocalfont times 10 -%%notecolors 1 -%%notelabels 1 K: A F E "D"D D D E D A, A, D D D E D w: Well me fa-ther oft-en told me when I was just a lad diff --git a/songs/toss-a-coin-to-your-witcher.txt b/songs/toss-a-coin-to-your-witcher.txt index a01807a..fa28d88 100644 --- a/songs/toss-a-coin-to-your-witcher.txt +++ b/songs/toss-a-coin-to-your-witcher.txt @@ -1,7 +1,5 @@ T: Toss a Coin to Your Witcher %%vocalfont times 10 -%%notecolors 1 -%%notelabels 1 K: Db M:4/4 "Bbm" z4 DCB,A, | "Eb" B,4 DEDC | diff --git a/songs/we-wish-you-a-merry-xmas.txt b/songs/we-wish-you-a-merry-xmas.txt index 2161ce4..2c9ea24 100644 --- a/songs/we-wish-you-a-merry-xmas.txt +++ b/songs/we-wish-you-a-merry-xmas.txt @@ -1,6 +1,4 @@ T: We Wish You a Merry Christmas -%%notelabels 1 -%%notecolors 1 L: 1/8 G2 | "C"c2 cd cB | "F"A2 A2 A2 | "D7"d2 de dc | "G"B2 G2 G2 | "E"e2 ef ed | "Am"c2 A2 "C"GG | "F"A2 d2 "G"B2 | "C"c4 G2 | diff --git a/songs/wellerman.txt b/songs/wellerman.txt index b928aad..b49e5a5 100644 --- a/songs/wellerman.txt +++ b/songs/wellerman.txt @@ -1,8 +1,6 @@ X: 1 T: Wellerman %%vocalfont times 10 -%%notecolors 1 -%%notelabels 1 M: 4/4 L: 1/8 K: Eb diff --git a/songs/whiskey-johnny.txt b/songs/whiskey-johnny.txt index 4915a57..ff9976a 100644 --- a/songs/whiskey-johnny.txt +++ b/songs/whiskey-johnny.txt @@ -1,8 +1,6 @@ X: 1 T: Whiskey Johnny %%vocalfont times 10 -%%notecolors 1 -%%notelabels 1 M: 4/4 L: 1/4 K: A diff --git a/src/index.pug b/src/index.pug index 696656b..5a46ad6 100644 --- a/src/index.pug +++ b/src/index.pug @@ -19,10 +19,15 @@ append head /* lean toolbar */ #toolbar { gap: .45rem; margin-top: .6rem } + #toolbar .ico { + font-style: normal; + font-size: 1.05em; + line-height: 1; + vertical-align: -.05em; + } #toolbar .btn .bi { vertical-align: -.15em } - #toolbar .btn .bi + span, - #toolbar .btn .bi + * { margin-left: .35em } - #toolbar .btn-group-toggle .btn .bi { margin-right: .35em } + #toolbar .btn > .ico, + #toolbar .btn > .bi { margin-right: .3em } #toolbar #songLabel { display: inline-block; max-width: 45vw; @@ -34,7 +39,14 @@ append head #toolbar .dropdown-menu { max-height: 60vh; overflow-y: auto } #key-menu { min-width: 7rem } - /* advanced panel (power-user / editing) */ + /* staff hidden: keep #paper width (abcjs is responsive) but collapse its height. + abcjs sets an inline padding-bottom aspect-ratio, so override it with !important. */ + body.no-staff #paper { height: 0 !important; padding-bottom: 0 !important; overflow: hidden } + #verses { display: none; margin-top: 1rem } + #verses p { margin-bottom: .8rem } + body.no-staff #verses { display: block } + + /* advanced panel (ABC editing) */ #advanced { display: none; margin-top: 1rem } #advanced > * { margin-bottom: .8rem } @@ -56,7 +68,7 @@ append body //- Song picker (primary action) .dropdown button.btn.btn-primary.dropdown-toggle#songFile(type="button" data-toggle="dropdown" title="Choose a song") - +bi([{d:'M6 13c0 1.105-1.12 2-2.5 2S1 14.105 1 13c0-1.104 1.12-2 2.5-2s2.5.896 2.5 2zm9-2c0 1.105-1.12 2-2.5 2S10 12.105 10 11c0-1.104 1.12-2 2.5-2s2.5.896 2.5 2z'},{fr:'evenodd',d:'M14 11V2h1v9h-1zM6 3v10H5V3h1z'},{d:'M5 2.905a1 1 0 0 1 .9-.995l8-.8a1 1 0 0 1 1.1.995V3L5 4V2.905z'}]) + span.ico 🎶 span#songLabel Pick a song .dropdown-menu#song-menu(aria-labelledby="songFile") - var keys = Object.keys(src['by-title.json']) @@ -64,38 +76,55 @@ append body each k in keys a.dropdown-item(href="#")= k - //- View toggles + //- Staff + note options + .btn-group.btn-group-toggle.btn-group-sm#staffToggles(data-toggle="buttons") + label.btn.btn-outline-secondary.active(title="Show the music staff") + input#show-staff(type="checkbox" checked autocomplete="off") + span.ico 🎼 + | Staff + label.btn.btn-outline-secondary.active(title="Color notes by pitch") + input#show-notecolors(type="checkbox" checked autocomplete="off") + span.ico 🎨 + | Color + label.btn.btn-outline-secondary.active(title="Label notes with letter names") + input#show-notelabels(type="checkbox" checked autocomplete="off") + span.ico 🔤 + | Labels + + //- Lyrics & instrument layers .btn-group.btn-group-toggle.btn-group-sm#viewToggles(data-toggle="buttons") label.btn.btn-outline-secondary.active(title="Show lyrics") input#show-lyrics(type="checkbox" checked autocomplete="off") - +bi([{d:'M14.5 3a.5.5 0 0 1 .5.5v9a.5.5 0 0 1-.5.5h-13a.5.5 0 0 1-.5-.5v-9a.5.5 0 0 1 .5-.5h13zm-13-1A1.5 1.5 0 0 0 0 3.5v9A1.5 1.5 0 0 0 1.5 14h13a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 14.5 2h-13z'},{d:'M3 5.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zM3 8a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9A.5.5 0 0 1 3 8zm0 2.5a.5.5 0 0 1 .5-.5h6a.5.5 0 0 1 0 1h-6a.5.5 0 0 1-.5-.5z'}]) + span.ico 🗣️ | Lyrics label.btn.btn-outline-secondary(title="Show trumpet fingering") input#show-trumpet(type="checkbox" autocomplete="off") - svg.bi(xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16" aria-hidden="true" focusable="false") - circle(cx="3.6" cy="8" r="2.1") - circle(cx="8" cy="8" r="2.1") - circle(cx="12.4" cy="8" r="2.1") + span.ico 🎺 | Trumpet label.btn.btn-outline-secondary(title="Show guitar tab") input#show-gtab(type="checkbox" autocomplete="off") - svg.bi(xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.3" viewBox="0 0 16 16" aria-hidden="true" focusable="false") - path(d="M1 3.5h14M1 6.5h14M1 9.5h14M1 12.5h14") - | Tab + span.ico 🎸 + | Guitar //- Transpose: pick the destination key (offset shown) .dropdown button.btn.btn-outline-secondary.btn-sm.dropdown-toggle#keyBtn(type="button" data-toggle="dropdown" title="Transpose: choose a key") +bi([{fr:'evenodd',d:'M11.5 15a.5.5 0 0 0 .5-.5V2.707l3.146 3.147a.5.5 0 0 0 .708-.708l-4-4a.5.5 0 0 0-.708 0l-4 4a.5.5 0 1 0 .708.708L11 2.707V14.5a.5.5 0 0 0 .5.5zm-7-14a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L4 13.293V1.5a.5.5 0 0 1 .5-.5z'}]) - span#keyLabel – + span#keyLabel Key: – .dropdown-menu.dropdown-menu-right#key-menu(aria-labelledby="keyBtn") - //- Advanced / edit ABC (power users) - button.btn.btn-outline-secondary.btn-sm.ml-auto#advancedToggle(type="button" title="Advanced / edit ABC" aria-pressed="false") - +bi([{d:'M8 4.754a3.246 3.246 0 1 0 0 6.492 3.246 3.246 0 0 0 0-6.492zM5.754 8a2.246 2.246 0 1 1 4.492 0 2.246 2.246 0 0 1-4.492 0z'},{d:'M9.796 1.343c-.527-1.79-3.065-1.79-3.592 0l-.094.319a.873.873 0 0 1-1.255.52l-.292-.16c-1.64-.892-3.433.902-2.54 2.541l.159.292a.873.873 0 0 1-.52 1.255l-.319.094c-1.79.527-1.79 3.065 0 3.592l.319.094a.873.873 0 0 1 .52 1.255l-.16.292c-.892 1.64.901 3.434 2.541 2.54l.292-.159a.873.873 0 0 1 1.255.52l.094.319c.527 1.79 3.065 1.79 3.592 0l.094-.319a.873.873 0 0 1 1.255-.52l.292.16c1.64.893 3.434-.902 2.54-2.541l-.159-.292a.873.873 0 0 1 .52-1.255l.319-.094c1.79-.527 1.79-3.065 0-3.592l-.319-.094a.873.873 0 0 1-.52-1.255l.16-.292c.893-1.64-.902-3.434-2.541-2.54l-.292.159a.873.873 0 0 1-1.255-.52l-.094-.319zm-2.633.283c.246-.835 1.428-.835 1.674 0l.094.319a1.873 1.873 0 0 0 2.693 1.115l.291-.16c.764-.415 1.6.42 1.184 1.185l-.159.292a1.873 1.873 0 0 0 1.116 2.692l.318.094c.835.246.835 1.428 0 1.674l-.319.094a1.873 1.873 0 0 0-1.115 2.693l.16.291c.415.764-.42 1.6-1.185 1.184l-.291-.159a1.873 1.873 0 0 0-2.693 1.116l-.094.318c-.246.835-1.428.835-1.674 0l-.094-.319a1.873 1.873 0 0 0-2.692-1.115l-.292.16c-.764.415-1.6-.42-1.184-1.185l.159-.291A1.873 1.873 0 0 0 1.945 8.93l-.319-.094c-.835-.246-.835-1.428 0-1.674l.319-.094A1.873 1.873 0 0 0 3.06 4.377l-.16-.292c-.415-.764.42-1.6 1.185-1.184l.292.159a1.873 1.873 0 0 0 2.692-1.115l.094-.319z'}]) + //- Songbook PDF / QR (document dialog) + button.btn.btn-outline-secondary.btn-sm.ml-auto#songbookBtn(type="button" data-toggle="modal" data-target="#songbookModal" title="Songbook PDF & QR code") + span.ico 📄 + + //- Edit the ABC source + button.btn.btn-outline-secondary.btn-sm#advancedToggle(type="button" title="Edit ABC notation" aria-pressed="false") + span.ico 🖊️ #paper + #verses + #advanced.noprint .item span Enter some @@ -106,10 +135,23 @@ append body span add a song textarea#abc(spellcheck="false") #warnings - p The Songbook PDF can be found at this link, or via this QR code: - img(src="qr-code.svg" alt="https://brewingcode.github.io/shanties/Songbook.pdf" width="200" height="200") - div - a(href="https://github.com/brewingcode/shanties/commit/" + src['GIT_HEAD'])= src['GIT_HEAD'] + + //- Songbook PDF + QR code dialog + #songbookModal.modal.fade.noprint(tabindex="-1" role="dialog" aria-labelledby="songbookModalLabel" aria-hidden="true") + .modal-dialog.modal-dialog-centered(role="document") + .modal-content + .modal-header + h5.modal-title#songbookModalLabel Songbook + button.close(type="button" data-dismiss="modal" aria-label="Close") + span(aria-hidden="true") × + .modal-body.text-center + p Download the printable songbook: Songbook.pdf + p.text-muted or scan to open it on another device: + img(src="qr-code.svg" alt="Songbook.pdf QR code" width="200" height="200") + .modal-footer.justify-content-center + small.text-muted + span version + a(href="https://github.com/brewingcode/shanties/commit/" + src['GIT_HEAD'])= src['GIT_HEAD'] script. var songs = !{JSON.stringify(src['songs.json'])}; var byTitle = !{JSON.stringify(src['by-title.json'])}; @@ -134,6 +176,7 @@ append body CHROMATIC = ['C', 'D♭', 'D', 'E♭', 'E', 'F', 'G♭', 'G', 'A♭', 'A', 'B♭', 'B'] prevStep = 0 origPc = null + currentSong = '' keyToPc = (name) -> return null unless name @@ -147,7 +190,7 @@ append body updateKeyLabel = -> k = displayKey() or '–' k += " (#{if prevStep > 0 then '+' else ''}#{prevStep})" unless prevStep is 0 - $('#keyLabel').text k + $('#keyLabel').text "Key: #{k}" $('#key-menu .dropdown-item').each -> $(this).toggleClass 'active', +$(this).attr('data-offset') is prevStep @@ -164,7 +207,25 @@ append body .appendTo menu updateKeyLabel() + esc = (s) -> $('
#{para.join('
')}