From d48cafebb277e4ad4b31e883cbe4f55eef9ea4a4 Mon Sep 17 00:00:00 2001 From: Joris Date: Sat, 29 May 2021 19:24:41 +0200 Subject: Rewrite in TypeScript --- src/view/table.ts | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 src/view/table.ts (limited to 'src/view/table.ts') diff --git a/src/view/table.ts b/src/view/table.ts new file mode 100644 index 0000000..171300d --- /dev/null +++ b/src/view/table.ts @@ -0,0 +1,102 @@ +import h from 'lib/h' +import * as Format from 'lib/format' +import * as Dom from 'lib/dom' +import * as Function from 'lib/function' +import * as Food from 'food' +import * as Sort from 'view/sort' + +export function view(): Element { + const maxGlycemicLoad: number = Math.max(...Food.all.map(Food.glycemicLoad)) + const aliments = h('div', + { className: 'g-Aliments' }, + ...Food.all.sort((a1, a2) => Sort.aliments(a1, a2, Sort.init)).map(aliment => line(aliment, maxGlycemicLoad)) + ) + + return h('div', + { className: 'g-Page' }, + header( + (search: string, sort: Sort.Sort) => { + const lines = Food + .search(search) + .sort((a1, a2) => Sort.aliments(a1, a2, sort)) + .map(aliment => line(aliment, maxGlycemicLoad)) + Dom.replaceChildren(aliments, ...lines) + } + ), + aliments + ) +} + +function header( + onUpdateTable: (search: string, sort: Sort.Sort) => void +): Element { + let search = '' + let sort = Sort.init + + const alimentHeader = h('button', { className: 'g-Header--Sorted' }, 'Aliment') + const glycemicIndexHeader = h('button', {}, 'Index glycémique') + const carbohydratesHeader = h('button', {}, 'Glucides pour 100 g') + const glycemicLoadHeader = h('button', {}, 'Charge glycémique') + + const onSort = (field: Sort.Field) => () => { + sort = Sort.toggle(sort, field) + onUpdateTable(search, sort) + alimentHeader.className = field === Sort.Field.Name ? 'g-Header--Sorted' : '' + glycemicIndexHeader.className = field === Sort.Field.GlycemicIndex ? 'g-Header--Sorted' : '' + carbohydratesHeader.className = field === Sort.Field.Carbohydrates ? 'g-Header--Sorted' : '' + glycemicLoadHeader.className = field === Sort.Field.GlycemicLoad ? 'g-Header--Sorted' : '' + } + + alimentHeader.addEventListener('click', onSort(Sort.Field.Name)) + glycemicIndexHeader.addEventListener('click', onSort(Sort.Field.GlycemicIndex)) + carbohydratesHeader.addEventListener('click', onSort(Sort.Field.Carbohydrates)) + glycemicLoadHeader.addEventListener('click', onSort(Sort.Field.GlycemicLoad)) + + return h('header', + { className: 'g-Header' }, + h('div', + { className: 'g-Title g-Line' }, + alimentHeader, + glycemicIndexHeader, + carbohydratesHeader, + glycemicLoadHeader, + ), + h('input', + { className: 'g-Search g-Line', + placeholder: 'Rechercher…', + oninput: Function.debounce((e: Event) => { + search = (e.target as HTMLInputElement).value + onUpdateTable(search, sort) + }) + } + ) + ) +} + +function line(aliment: Food.Aliment, maxGlycemicLoad: number): Element { + return h('div', + { className: 'g-Aliment g-Line' }, + h('div', {}, aliment.name), + h('div', { className: 'g-Number' }, aliment.glycemicIndex), + h('div', { className: 'g-Number' }, `${Math.round(aliment.carbohydrates)} g`), + h('div', { className: 'g-Number' }, formatGlycemicLoad(aliment, maxGlycemicLoad)) + ) +} + +function formatGlycemicLoad(aliment: Food.Aliment, maxGlycemicLoad: number): Element { + const glycemicLoad = Food.glycemicLoad(aliment) + return h('div', + { className: `number ${glycemicLoadNumberClass(glycemicLoad)}` }, + Format.decimal(glycemicLoad) + ) +} + +function glycemicLoadNumberClass(index: number): string { + if (index < 8) { + return 'g-Number--Low' + } else if (index < 20) { + return 'g-Number--Middle' + } else { + return 'g-Number--High' + } +} -- cgit v1.2.3