aboutsummaryrefslogtreecommitdiff
path: root/src/view/table.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/table.ts')
-rw-r--r--src/view/table.ts102
1 files changed, 102 insertions, 0 deletions
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'
+ }
+}