import * as Config from 'config' import h from 'h' import * as Router from 'router' import * as Duration from 'duration' export function view(config: Config.Config, showPage: (route: Router.Route) => void) { const duration = document.createTextNode(Duration.prettyPrint(Config.getDuration(config))) const wd = () => duration.textContent = Duration.prettyPrint(Config.getDuration(config)) return h('div', { className: 'g-Layout__Page' }, h('header', { className: 'g-Layout__Header' }, 'Tabata timer'), h('form', { className: 'g-Form' , onsubmit: (e: Event) => { e.preventDefault() const timerRoute: Router.Route = { name: 'timer', config } history.pushState({}, '', Router.toString(timerRoute)) showPage(timerRoute) }}, h('section', { className: 'g-Form__Section' }, numberInput('Warm Up', 0, config.warmup, n => { config.warmup = n; wd()}) ), h('section', { className: 'g-Form__Section' }, h('h1', { className: 'g-Form__Title' }, 'Tabatas'), h('div', { className: 'g-Form__Line' }, numberInput('Prep', 0, config.prepare, n => { config.prepare = n; wd()}), operator('+'), numberInput('Cycles', 1, config.cycles, n => { config.cycles = n; wd()}), operator('× ('), numberInput('Work', 5, config.work, n => { config.work = n; wd()}), operator('+'), numberInput('Rest', 5, config.rest, n => { config.rest = n; wd()}), operator(')') ), tabatasSection( config.tabatas, (str: string) => { config.tabatas.push(str); wd() }, (index: number, str: string) => { config.tabatas[index] = str; wd() }, (index: number) => { config.tabatas.splice(index, 1); wd() } ) ), h('section', { className: 'g-Form__Section' }, h('h1', { className: 'g-Title' }, 'Duration'), h('div', { className: 'g-Form__Duration' }, duration) ), h('button', { className: 'g-Button' }, 'Start') ) ) } function operator(str: string): Element { return h('span', { className: 'g-Form__Operator' }, str) } function tabatasSection( init: string[], onAdd: (str: string) => void, onUpdate: (index: number, str: string) => void, onRemove: (inedx: number) => void ) { const tabatas = h('ol', { className: 'g-List' }) let counter = init.length let removedIndexes: number[] = [] let adjustIndex = (index: number) => index - removedIndexes.filter(i => i < index).length init.forEach((initStr, index) => { const { tabata } = tabataInput( initStr, (str: string) => onUpdate(adjustIndex(index), str), () => { onRemove(adjustIndex(index)) tabatas.removeChild(tabata) removedIndexes.push(index) } ) tabatas.appendChild(tabata) }) return h('div', { className: 'g-Form__Tabatas' }, tabatas, h('input', { type: 'button', value: 'Add tabata', className: 'g-Button', onclick: (e: Event) => { let index = counter++ const txt = `Exercise ${adjustIndex(index) + 1}` onAdd(txt) let { tabata, textInput } = tabataInput( txt, (str: string) => onUpdate(adjustIndex(index), str), () => { onRemove(adjustIndex(index)) tabatas.removeChild(tabata) removedIndexes.push(index) } ) tabatas.appendChild(tabata) textInput.select() } } ) ) } interface TabataInput { tabata: Element, textInput: HTMLInputElement, } function tabataInput( init: string, onUpdate: (str: string) => void, onRemove: () => void ): TabataInput { const textInput = h('input', { value: init, className: 'g-Input g-Form__TabataInput', required: 'required', oninput: (e: Event) => { if (e.target !== null) { const target = e.target as HTMLInputElement onUpdate(target.value.trim()) } } } ) as HTMLInputElement const tabata = h('li', { className: 'g-Form__Tabata'}, textInput, h('input', { type: 'button', value: 'Remove', className: 'g-Button', onclick: (e: Event) => onRemove() } ) ) return { tabata, textInput } } function numberInput( labelValue: string, min: number, value: number, update: (n: number) => void ): Element { return h('label', { className: 'g-Form__Label', oninput: (e: Event) => { if (e.target !== null) { const target = e.target as HTMLInputElement update(parseInt(target.value) || 0) } } }, labelValue, h('input', { className: 'g-Input g-Form__NumberInput', type: 'number', required: 'required', min, value })) }