import type { JSX } from "@char/aftercare/jsx-runtime"; import { projectKey } from "../project/model.ts"; import { project } from "../project/store.ts"; import { palette, prettyRoman, type Relation } from "../theory/analysis.ts"; import { formatNote } from "../theory/pitch.ts"; import { chordName } from "../theory/chord.ts"; import { MODES } from "../theory/key.ts"; import { previewChord, writeChordFromPalette } from "./actions.ts"; import { Circle } from "./circle.tsx"; import { disclosure, help, watch } from "./dom.tsx"; import { mixtureOpen, paletteSevenths } from "./state.ts"; const LABELS: Partial> = { home: "key", sharp: "sharp vertex", flat: "flat vertex", inverse: "inverse vertex", }; /** the diatonic chords of the key, of the other keys on its axis, and of its parallel modes */ export function Palette(): JSX.Element { const keyId = project.derive(p => `${p.key.tonic} ${p.key.mode}`); const rows =
; watch(rows, [keyId, paletteSevenths], () => { const key = projectKey(project.get()); rows.replaceChildren( ...palette(key, paletteSevenths.get()).map( ({ key: rowKey, relation, entries, vertex }) => (
{LABELS[vertex ?? relation] ?? MODES[rowKey.mode].label} {relation !== "parallel" || vertex ? ( {formatNote(rowKey.tonic)} {MODES[rowKey.mode].label} ) : undefined}
{entries.map(({ chord, symbol, diatonic }) => ( ))}
), ), ); }); return (
{disclosure(mixtureOpen, "modal mixture")} {help( "chords to borrow: from the key, from the three keys a minor third and a tritone " + "away, and from the other modes on the same tonic. faded ones are already in the " + "key.\n\nthe circle of fifths turns to put the current chord at the top, with " + "what's a fifth either way of it beside it, and the relative minors inside; " + "it writes after the current chord, if there's room.\n\n" + "click a chord to hear it; double-click to write it at the cursor", )}
{rows}
); }