aboutsummaryrefslogtreecommitdiff
path: root/src/view/form.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/form.ts')
-rw-r--r--src/view/form.ts191
1 files changed, 140 insertions, 51 deletions
diff --git a/src/view/form.ts b/src/view/form.ts
index 5547e0c..e499b05 100644
--- a/src/view/form.ts
+++ b/src/view/form.ts
@@ -1,5 +1,6 @@
-import { h, withVar, Html, Rx } from 'lib/rx'
+import { h, withState, Html, Rx, pure, RxAble } from 'lib/rx'
import * as Options from 'view/options'
+import * as Chord from 'chord'
interface Params {
options: Options.Model
@@ -7,7 +8,7 @@ interface Params {
}
export function view({ options, onSubmit }: Params): Html {
- return withVar(options, (opts, updateOptions) =>
+ return withState(options, opts =>
h('form',
{ className: 'g-Form',
onsubmit: opts.map(o =>
@@ -17,58 +18,71 @@ export function view({ options, onSubmit }: Params): Html {
}
)
},
- chordCheckbox({
- label: '',
- checked: opts.map(o => o.major),
- onCheck: (checked => updateOptions(o => {
- o.major = checked
- return o
- }))
- }),
- chordCheckbox({
- label: '-',
- checked: opts.map(o => o.minor),
- onCheck: (checked => updateOptions(o => {
- o.minor = checked
- return o
- }))
- }),
- chordCheckbox({
- label: '7',
- checked: opts.map(o => o.seventh),
- onCheck: (checked => updateOptions(o => {
- o.seventh = checked
- return o
- }))
- }),
- chordCheckbox({
- label: '-7',
- checked: opts.map(o => o.minorSeventh),
- onCheck: (checked => updateOptions(o => {
- o.minorSeventh = checked
- return o
- }))
- }),
- chordCheckbox({
- label: '7',
- checked: opts.map(o => o.majorSeventh),
- onCheck: (checked => updateOptions(o => {
- o.majorSeventh = checked
- return o
- }))
- }),
- numberInput({
- label: 'BPM',
+ h('table',
+ { className: 'g-ChordsTable' },
+ chordsGroup({
+ title: 'Major',
+ chords: opts.map(o => o.major),
+ updateChords: (chords: Chord.Chords) => {
+ opts.update(o => {
+ o.major = chords
+ return o
+ })
+ }
+ }),
+ chordsGroup({
+ title: 'Minor',
+ chords: opts.map(o => o.minor),
+ updateChords: (chords: Chord.Chords) => {
+ opts.update(o => {
+ o.minor = chords
+ return o
+ })
+ }
+ }),
+ chordsGroup({
+ title: '7th',
+ chords: opts.map(o => o.seventh),
+ updateChords: (chords: Chord.Chords) => {
+ opts.update(o => {
+ o.seventh = chords
+ return o
+ })
+ }
+ }),
+ chordsGroup({
+ title: 'Minor 7th',
+ chords: opts.map(o => o.minorSeventh),
+ updateChords: (chords: Chord.Chords) => {
+ opts.update(o => {
+ o.minorSeventh = chords
+ return o
+ })
+ }
+ }),
+ chordsGroup({
+ title: 'Major 7th',
+ chords: opts.map(o => o.majorSeventh),
+ updateChords: (chords: Chord.Chords) => {
+ opts.update(o => {
+ o.majorSeventh = chords
+ return o
+ })
+ }
+ })
+ ),
+ numberInput({
+ label: 'BPM',
value: opts.map(o => o.bpm.toString()),
- onChange: (n => updateOptions(o => {
+ onChange: (n => opts.update(o => {
o.bpm = n
return o
}))
}),
- numberInput({
- label: 'Beats per Chord',
+ numberInput({
+ label: 'Beats per Chord',
value: opts.map(o => o.beatsPerChord.toString()),
- onChange: (n => updateOptions(o => {
+ onChange: (n => opts.update(o => {
o.beatsPerChord = n
return o
}))
@@ -78,10 +92,85 @@ export function view({ options, onSubmit }: Params): Html {
)
}
+interface ChordsGroupParams {
+ title: string,
+ chords: Rx<Chord.Chords>,
+ updateChords: (chords: Chord.Chords) => void
+}
+
+function chordsGroup({ title, chords, updateChords }: ChordsGroupParams): Html {
+ const line =
+ (lineChords: Array<Chord.Chord>, label: (chord: Chord.Chord) => string) =>
+ h('div',
+ { className: 'g-ChordsLine' },
+ chordCheckbox({
+ checked: chords.map(cs => lineChords.every(c => cs.has(c))),
+ onCheck: chords.map(cs =>
+ (checked: boolean) => {
+ if (checked) {
+ lineChords.forEach(c => cs.add(c))
+ } else {
+ lineChords.forEach(c => cs.delete(c))
+ }
+ updateChords(cs)
+ }
+ )
+ }),
+ lineChords.map(chord =>
+ chordCheckbox({
+ label: label(chord),
+ checked: chords.map(cs => cs.has(chord)),
+ onCheck: chords.map(cs =>
+ (checked: boolean) => {
+ if (checked) {
+ cs.add(chord)
+ } else {
+ cs.delete(chord)
+ }
+ updateChords(cs)
+ }
+ )
+ })
+ )
+ )
+
+ return h('tr',
+ h('td',
+ chordCheckbox({
+ label: title,
+ checked: chords.map(cs =>
+ Chord.sharps.every(c => cs.has(c))
+ && Chord.plains.every(c => cs.has(c))
+ && Chord.bemols.every(c => cs.has(c))
+ ),
+ onCheck: chords.map(cs =>
+ (checked: boolean) => {
+ if (checked) {
+ Chord.sharps.forEach(c => cs.add(c))
+ Chord.plains.forEach(c => cs.add(c))
+ Chord.bemols.forEach(c => cs.add(c))
+ } else {
+ Chord.sharps.forEach(c => cs.delete(c))
+ Chord.plains.forEach(c => cs.delete(c))
+ Chord.bemols.forEach(c => cs.delete(c))
+ }
+ updateChords(cs)
+ }
+ )
+ })
+ ),
+ h('td',
+ line(Chord.sharps, () => '♯'),
+ line(Chord.plains, chord => chord),
+ line(Chord.bemols, () => '♭')
+ )
+ )
+}
+
interface ChordCheckboxParams {
- label: string
+ label?: string
checked: Rx<boolean>
- onCheck: (checked: boolean) => void
+ onCheck: Rx<(checked: boolean) => void>
}
function chordCheckbox({ label, checked, onCheck }: ChordCheckboxParams): Html {
@@ -90,7 +179,7 @@ function chordCheckbox({ label, checked, onCheck }: ChordCheckboxParams): Html {
h('input',
{ type: 'checkbox',
checked,
- onchange: (event: Event) => onCheck((event.target as HTMLInputElement).checked)
+ onchange: onCheck.map(f => (event: Event) => f((event.target as HTMLInputElement).checked))
}
),
label