char-slop/chordpad.vibed.software
git clone https://git.t4t.associates/char-slop/chordpad.vibed.software
8aa6d5f
main
1import type { JSX } from "@char/aftercare/jsx-runtime" ; 2import { projectKey } from "../project/model.ts" ; 3import { project } from "../project/store.ts" ; 4import { palette , prettyRoman , type Relation } from "../theory/analysis.ts" ; 5import { formatNote } from "../theory/pitch.ts" ; 6import { chordName } from "../theory/chord.ts" ; 7import { MODES } from "../theory/key.ts" ; 8import { previewChord , writeChordFromPalette } from "./actions.ts" ; 9import { Circle } from "./circle.tsx" ; 10import { disclosure , help , watch } from "./dom.tsx" ; 11import { mixtureOpen , paletteSevenths } from "./state.ts" ; 12 13const LABELS :Partial < Record < Relation , string >> = { 14home :"key" , 15sharp :"sharp vertex" , 16flat :"flat vertex" , 17inverse :"inverse vertex" , 18}; 19 20/** the diatonic chords of the key, of the other keys on its axis, and of its parallel modes */ 21export function Palette () :JSX . Element { 22const keyId = project . derive ( p => ` ${ p . key . tonic } ${ p . key . mode } ` ); 23const rows = < div class = "palette-rows" / >; 24 25watch ( rows , [ keyId , paletteSevenths ], () => { 26const key = projectKey ( project . get ()); 27rows . replaceChildren ( 28 ...palette ( key , paletteSevenths . get ()). map ( 29({ key :rowKey , relation, entries, vertex}) => ( 30< div 31class = { `palette-row ${relation === "parallel" ? `from-${rowKey . mode } ` : `on-${relation } `} `} 32> 33< div class = "palette-mode" > 34{ LABELS [ vertex ?? relation ] ?? MODES [ rowKey . mode ]. label } 35{ relation!== "parallel" || vertex ? ( 36< small > 37{ formatNote ( rowKey . tonic )} { MODES [ rowKey . mode ]. label } 38</ small > 39) : undefined } 40</ div > 41{entries. map (({ chord, symbol, diatonic }) => ( 42< button 43type = "button" 44class = { `chip ${ relation !== "home" && diatonic ? " same" : "" } ` } 45// the second click of a double-click would only preview on top of the write 46_onclick = { e => e . detail < 2 && previewChord ( symbol )} 47_ondblclick = {() => writeChordFromPalette ( symbol )} 48> 49< b >{ prettyRoman ( symbol )}</ b > 50< span >{ chordName ( chord )}</ span > 51</ button > 52))} 53</ div > 54), 55), 56); 57}); 58 59return ( 60< section class = "palette" dataset = {{ open: mixtureOpen . derive ( String ) }}> 61< header > 62{ disclosure ( mixtureOpen , "modal mixture" )} 63{ help ( 64"chords to borrow: from the key, from the three keys a minor third and a tritone " + 65"away, and from the other modes on the same tonic. faded ones are already in the " + 66"key.\n\nthe circle of fifths turns to put the current chord at the top, with " + 67"what's a fifth either way of it beside it, and the relative minors inside; " + 68"it writes after the current chord, if there's room.\n\n" + 69"click a chord to hear it; double-click to write it at the cursor" , 70)} 71< label > 72< input type = "checkbox" checked = { paletteSevenths } /> sevenths 73</ label > 74</ header > 75< div class = "palette-body" > 76{ rows } 77< Circle / > 78</ div > 79< / section > 80); 81}