aboutsummaryrefslogtreecommitdiff
path: root/src/view/table.ts
blob: 171300dfc01ddbdc6bd85dd15f6fc6a3cd295496 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
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'
  }
}