aboutsummaryrefslogtreecommitdiff
path: root/src/view
diff options
context:
space:
mode:
Diffstat (limited to 'src/view')
-rw-r--r--src/view/form.ts55
-rw-r--r--src/view/layout.ts13
-rw-r--r--src/view/options.ts24
-rw-r--r--src/view/play.ts48
4 files changed, 140 insertions, 0 deletions
diff --git a/src/view/form.ts b/src/view/form.ts
new file mode 100644
index 0000000..a74a7de
--- /dev/null
+++ b/src/view/form.ts
@@ -0,0 +1,55 @@
+import h, { classNames } from 'lib/h'
+import * as dom from 'lib/dom'
+import * as play from 'view/play'
+import * as layout from 'view/layout'
+import * as chord from 'chord'
+import * as options from 'view/options'
+
+// View
+
+export function view(): Element[] {
+ let opts = options.load()
+
+ return layout.view(
+ h('form',
+ {
+ className: 'g-Form',
+ onsubmit
+ },
+ labelInput({ type: 'checkbox', name: 'major', label: 'Major', checked: opts.major }),
+ labelInput({ type: 'checkbox', name: 'minor', label: 'Minor', checked: opts.minor }),
+ labelInput({ type: 'number', name: 'bpm', label: 'BPM', value: opts.bpm.toString() }),
+ labelInput({ type: 'number', name: 'beatsPerChord', label: 'Beats per Chord', value: opts.beatsPerChord.toString() }),
+ h('input', { type: 'submit', value: 'Play' })
+ )
+ )
+}
+
+function onsubmit(event: Event): void {
+ event.preventDefault()
+ let input = (name: String) => document.querySelector(`input[name="${name}"]`) as HTMLInputElement
+ let opts = {
+ major: input('major').checked,
+ minor: input('minor').checked,
+ bpm: parseInt(input('bpm').value),
+ beatsPerChord: parseInt(input('beatsPerChord').value)
+ }
+ options.save(opts)
+ dom.show(play.view(opts))
+}
+
+type LabelInputParams = {
+ type: string,
+ name: string,
+ label: string,
+ checked?: boolean,
+ value?: string
+}
+
+function labelInput({ type, name, label, checked, value }: LabelInputParams) {
+ return h('label',
+ {},
+ h('input', { type, name, checked, value }),
+ label
+ )
+}
diff --git a/src/view/layout.ts b/src/view/layout.ts
new file mode 100644
index 0000000..ac62290
--- /dev/null
+++ b/src/view/layout.ts
@@ -0,0 +1,13 @@
+import h from 'lib/h'
+import * as dom from 'lib/dom'
+import * as form from 'view/form'
+
+export function view(main: Element): Element[] {
+ return [
+ h('header',
+ { onclick: () => dom.show(form.view()) },
+ 'Chords'
+ ),
+ main
+ ]
+}
diff --git a/src/view/options.ts b/src/view/options.ts
new file mode 100644
index 0000000..4c71be2
--- /dev/null
+++ b/src/view/options.ts
@@ -0,0 +1,24 @@
+export type Options = {
+ major: boolean,
+ minor: boolean,
+ bpm: number,
+ beatsPerChord: number
+}
+
+let defaultOptions: Options = {
+ major: true,
+ minor: false,
+ bpm: 90,
+ beatsPerChord: 4
+}
+
+let key: string = 'options'
+
+export function load(): Options {
+ let str = localStorage[key]
+ return str && JSON.parse(str) || defaultOptions
+}
+
+export function save(options: Options): void {
+ localStorage[key] = JSON.stringify(options)
+}
diff --git a/src/view/play.ts b/src/view/play.ts
new file mode 100644
index 0000000..26558cd
--- /dev/null
+++ b/src/view/play.ts
@@ -0,0 +1,48 @@
+import h, { classNames } from 'lib/h'
+import * as dom from 'lib/dom'
+import { Options } from 'view/options'
+import * as chord from 'chord'
+import * as layout from 'view/layout'
+
+export function view(options: Options): Element[] {
+ let chords = h('div',
+ { className: 'g-Play' },
+ chordNode(),
+ chordNode(),
+ chordNode(options),
+ chordNode(options)
+ )
+
+ let chordBeat = 1
+
+ dom.triggerAnimation(chords as HTMLElement, 'g-Play--Shift')
+ dom.triggerAnimation(chords.children[2] as HTMLElement, 'g-Chord--Beat')
+ setInterval(() => {
+ if (chordBeat == options.beatsPerChord) {
+ shiftChords(chords, options)
+ chords.children[0].classList.remove('g-Chord--Beat')
+ dom.triggerAnimation(chords as HTMLElement, 'g-Play--Shift')
+ dom.triggerAnimation(chords.children[2] as HTMLElement, 'g-Chord--Beat')
+ chordBeat = 1
+ } else {
+ dom.triggerAnimation(chords.children[2] as HTMLElement, 'g-Chord--Beat')
+ chordBeat += 1
+ }
+ }, 60 / options.bpm * 1000)
+
+ return layout.view(chords)
+}
+
+/* Shift chords and generate a new random one.
+ */
+function shiftChords(chords: Element, options: Options) {
+ chords.removeChild(chords.children[0])
+ chords.appendChild(chordNode(options))
+}
+
+function chordNode(options?: Options): Element {
+ return h('div',
+ { className: 'g-Chord' },
+ options ? chord.generate(options) : ''
+ )
+}