@vixoniccom/menu-daily 0.1.2-dev.1 → 0.2.0-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/.claude/settings.local.json +31 -0
  2. package/.vscode/settings.json +3 -0
  3. package/CHANGELOG.md +14 -0
  4. package/build/index.html +1 -0
  5. package/build/main.js +2 -0
  6. package/build/main.js.LICENSE.txt +39 -0
  7. package/build/test/downloads/1234.ttf +0 -0
  8. package/build/test/downloads/background.jpg +0 -0
  9. package/build/test/downloads/futura-font.ttf +0 -0
  10. package/build/test/parameters.json +38 -0
  11. package/build/test/services.json +871 -0
  12. package/build.zip +0 -0
  13. package/configuration/appearanceGroup/AppearanceInputs.ts +94 -0
  14. package/configuration/appearanceGroup/index.ts +8 -0
  15. package/configuration/dataGroup/DataInputs.ts +21 -0
  16. package/configuration/dataGroup/index.ts +8 -0
  17. package/configuration/index.ts +7 -0
  18. package/configuration.json +43 -78
  19. package/package.json +13 -12
  20. package/src/global.d.ts +15 -51
  21. package/src/main.ts +0 -5
  22. package/src/parameters.d.ts +31 -0
  23. package/src/scenes/App.tsx +25 -38
  24. package/src/scenes/components/FontLoader.tsx +3 -16
  25. package/src/scenes/components/FormattedText.tsx +3 -4
  26. package/src/scenes/components/Grid/Grid.tsx +8 -8
  27. package/src/scenes/components/Grid/GridItem.tsx +1 -0
  28. package/src/scenes/components/Grid/animation.ts +69 -55
  29. package/src/scenes/components/MealContainer/components/OptionItem.tsx +1 -2
  30. package/src/scenes/components/MealContainer/components/Title/index.tsx +17 -20
  31. package/src/scenes/components/MealContainer/components/Title/styles/Framed.tsx +19 -28
  32. package/src/scenes/components/MealContainer/components/Title/styles/Modern.tsx +15 -24
  33. package/src/scenes/components/MealContainer/components/Title/styles/index.tsx +25 -1
  34. package/src/scenes/components/MealContainer/index.tsx +31 -31
  35. package/src/test/parameters.json +7 -5
  36. package/src/test/services.json +871 -0
  37. package/tsconfig.json +9 -17
  38. package/src/dataLoader.ts +0 -169
package/build.zip CHANGED
Binary file
@@ -0,0 +1,94 @@
1
+ import { ColorPicker, Label, NumberInput, NumberRangeValue, SelectAssetKna, SelectInput, TextFormat, TextInput } from '@vixoniccom/modules'
2
+
3
+ export const appearanceInputs = [
4
+ new Label({ label: 'Animación' }),
5
+ new NumberInput({
6
+ id: 'animationDuration',
7
+ label: 'Duración',
8
+ description: 'En segundos. Por defecto 15s.',
9
+ }),
10
+ new SelectInput({
11
+ id: 'animationMode',
12
+ label: 'Modo',
13
+ items: [
14
+ { label: 'Fundido', value: 'fade' },
15
+ { label: 'Izquieda-derecha', value: 'slideRight' },
16
+ { label: 'Derecha-izquierda', value: 'slideLeft' },
17
+ ],
18
+ defaultValue: 'fade',
19
+ }),
20
+
21
+ new Label({ label: 'Contenedor General' }),
22
+ new NumberInput({
23
+ id: 'containerGridColumns',
24
+ label: 'Columnas',
25
+ range: new NumberRangeValue(1, 99),
26
+ }),
27
+ new NumberInput({
28
+ id: 'containerGridColumnsGap',
29
+ label: 'Separación',
30
+ description: 'En porcentaje',
31
+ range: new NumberRangeValue(0, 100),
32
+ }),
33
+ new NumberInput({
34
+ id: 'containerGridRows',
35
+ label: 'Filas',
36
+ range: new NumberRangeValue(1, 99),
37
+ }),
38
+ new NumberInput({
39
+ id: 'containerGridRowsGap',
40
+ label: 'Separación',
41
+ description: 'En porcentaje',
42
+ range: new NumberRangeValue(0, 100),
43
+ }),
44
+ new TextInput({
45
+ id: 'containerGridMargins',
46
+ label: 'Margenes',
47
+ description: 'En formato CSS.',
48
+ }),
49
+ new SelectAssetKna({
50
+ id: 'backgroundImage',
51
+ label: 'Imagen de fondo',
52
+ }),
53
+
54
+ new Label({ label: 'Contenedor de comida' }),
55
+ new NumberInput({
56
+ id: 'itemGridRows',
57
+ label: 'Filas',
58
+ }),
59
+ new TextInput({
60
+ id: 'itemGridMargins',
61
+ label: 'Margenes',
62
+ description: 'En formato CSS.',
63
+ }),
64
+ new NumberInput({
65
+ id: 'itemAnimationDuration',
66
+ label: 'Duración de animación',
67
+ description: 'En segundos. Por defecto calcula automaticamente.',
68
+ }),
69
+
70
+ new Label({ label: 'Comida' }),
71
+ new TextFormat({
72
+ id: 'itemTitleTextFormat',
73
+ label: 'Formato del título',
74
+ }),
75
+ new ColorPicker({
76
+ id: 'itemTitleBackgroundColor',
77
+ label: 'Fondo',
78
+ description: 'Color de fondo del título',
79
+ }),
80
+ new TextFormat({
81
+ id: 'itemOptionsTextFormat',
82
+ label: 'Formato de las opciones',
83
+ }),
84
+ new SelectInput({
85
+ id: 'itemStyle',
86
+ label: 'Estilo',
87
+ items: [
88
+ { label: 'Estandard', value: 'standard' },
89
+ { label: 'Moderno', value: 'modern' },
90
+ { label: 'Enmarcado', value: 'framed' },
91
+ ],
92
+ defaultValue: 'standard',
93
+ }),
94
+ ]
@@ -0,0 +1,8 @@
1
+ import { Group } from '@vixoniccom/modules'
2
+ import { appearanceInputs } from './AppearanceInputs'
3
+
4
+ export const appearanceGroup = new Group({
5
+ id: 'appearanceGroup',
6
+ label: 'Apariencia',
7
+ items: [...appearanceInputs],
8
+ })
@@ -0,0 +1,21 @@
1
+ import { ServiceInput, TextInput } from '@vixoniccom/modules'
2
+
3
+ export const dataInputs = [
4
+ new ServiceInput({
5
+ id: 'menuService',
6
+ label: 'Hoja de cálculo de Google Sheets con el menú',
7
+ serviceType: 'MenuAppService',
8
+ required: true,
9
+ }),
10
+ new TextInput({
11
+ id: 'mealType',
12
+ label: 'Tipo de comida',
13
+ description: 'El nombre de la pestaña a mostrar (No requerido)',
14
+ required: false
15
+ }),
16
+ new TextInput({
17
+ id: 'msj0',
18
+ label: 'Sin menú',
19
+ description: 'Mensaje cuando no hay menú',
20
+ }),
21
+ ]
@@ -0,0 +1,8 @@
1
+ import { Group } from '@vixoniccom/modules'
2
+ import { dataInputs } from './DataInputs'
3
+
4
+ export const dataGroup = new Group({
5
+ id: 'dataGroup',
6
+ label: 'Datos',
7
+ items: [...dataInputs],
8
+ })
@@ -0,0 +1,7 @@
1
+ import { Configuration } from '@vixoniccom/modules'
2
+ import { dataGroup } from './dataGroup'
3
+ import { appearanceGroup } from './appearanceGroup'
4
+
5
+ export const configuration = new Configuration({
6
+ schema: [dataGroup, appearanceGroup],
7
+ })
@@ -1,88 +1,51 @@
1
1
  {
2
2
  "schema": [
3
3
  {
4
- "type": "group",
5
- "id": "data",
4
+ "id": "dataGroup",
6
5
  "label": "Datos",
6
+ "type": "group",
7
7
  "items": [
8
8
  {
9
- "type": "text-input",
10
- "id": "url",
11
- "label": "Enlace",
12
- "description": "Dirección donde se encuentran los datos en formato excel.",
13
- "required": true
14
- },
15
- {
16
- "type": "select-input",
17
- "id": "pollingInterval",
18
- "label": "Actualización",
19
- "description": "Frecuencia de consulta de los datos.",
20
- "items": [
21
- {
22
- "label": "5 minutos",
23
- "value": 300000
24
- },
25
- {
26
- "label": "15 minutos",
27
- "value": 900000
28
- },
29
- {
30
- "label": "30 minutos",
31
- "value": 1.8e+6
32
- },
33
- {
34
- "label": "1 hora",
35
- "value": 3.6e+6
36
- },
37
- {
38
- "label": "6 horas",
39
- "value": 2.16e+7
40
- },
41
- {
42
- "label": "12 horas",
43
- "value": 4.32e+7
44
- },
45
- {
46
- "label": "Diaria",
47
- "value": 8.64e+7
48
- }
49
- ],
50
- "defaultValue": 900000,
9
+ "id": "menuService",
10
+ "label": "Hoja de cálculo de Google Sheets con el menú",
11
+ "type": "service-input",
12
+ "serviceType": "MenuAppService",
51
13
  "required": true
52
14
  },
53
15
  {
54
- "type": "text-input",
55
16
  "id": "mealType",
56
17
  "label": "Tipo de comida",
57
- "description": "El nombre de la pestaña en el excel. No requerido."
18
+ "type": "text-input",
19
+ "description": "El nombre de la pestaña a mostrar (No requerido)",
20
+ "required": false
58
21
  },
59
22
  {
60
- "type": "text-input",
61
23
  "id": "msj0",
62
24
  "label": "Sin menú",
63
- "description": "Mensaje cuando no hay menu."
25
+ "type": "text-input",
26
+ "description": "Mensaje cuando no hay menú"
64
27
  }
65
28
  ]
66
29
  },
67
30
  {
68
- "type": "group",
69
- "id": "design",
31
+ "id": "appearanceGroup",
70
32
  "label": "Apariencia",
33
+ "type": "group",
71
34
  "items": [
72
35
  {
73
36
  "type": "label",
74
37
  "label": "Animación"
75
38
  },
76
39
  {
77
- "type": "number-input",
78
40
  "id": "animationDuration",
79
41
  "label": "Duración",
80
- "description": "En segundos. Por defecto 15s."
42
+ "type": "number-input",
43
+ "description": "En segundos. Por defecto 15s."
81
44
  },
82
45
  {
83
- "type": "select-input",
84
46
  "id": "animationMode",
85
47
  "label": "Modo",
48
+ "type": "select-input",
86
49
  "items": [
87
50
  {
88
51
  "label": "Fundido",
@@ -104,87 +67,89 @@
104
67
  "label": "Contenedor General"
105
68
  },
106
69
  {
107
- "type": "number-input",
108
70
  "id": "containerGridColumns",
109
71
  "label": "Columnas",
110
- "range": "[1:99]"
72
+ "type": "number-input",
73
+ "range": "[1:99:]"
111
74
  },
112
75
  {
113
- "type": "number-input",
114
76
  "id": "containerGridColumnsGap",
115
77
  "label": "Separación",
116
- "description": "En porcentaje",
117
- "range": "[0:100]"
78
+ "type": "number-input",
79
+ "range": "[0:100:]",
80
+ "description": "En porcentaje"
118
81
  },
119
82
  {
120
- "type": "number-input",
121
83
  "id": "containerGridRows",
122
84
  "label": "Filas",
123
- "range": "[1:99]"
85
+ "type": "number-input",
86
+ "range": "[1:99:]"
124
87
  },
125
88
  {
126
- "type": "number-input",
127
89
  "id": "containerGridRowsGap",
128
90
  "label": "Separación",
129
- "description": "En porcentaje",
130
- "range": "[0:100]"
91
+ "type": "number-input",
92
+ "range": "[0:100:]",
93
+ "description": "En porcentaje"
131
94
  },
132
95
  {
133
- "type": "text-input",
134
96
  "id": "containerGridMargins",
135
97
  "label": "Margenes",
98
+ "type": "text-input",
136
99
  "description": "En formato CSS."
137
100
  },
138
101
  {
139
- "type": "select-asset-kna-input",
140
102
  "id": "backgroundImage",
141
- "label": "Imagen de fondo"
103
+ "label": "Imagen de fondo",
104
+ "type": "select-asset-kna-input",
105
+ "multiple": false
142
106
  },
143
107
  {
144
108
  "type": "label",
145
109
  "label": "Contenedor de comida"
146
110
  },
147
111
  {
148
- "type": "number-input",
149
112
  "id": "itemGridRows",
150
- "label": "Filas"
113
+ "label": "Filas",
114
+ "type": "number-input"
151
115
  },
152
116
  {
153
- "type": "text-input",
154
117
  "id": "itemGridMargins",
155
118
  "label": "Margenes",
119
+ "type": "text-input",
156
120
  "description": "En formato CSS."
157
121
  },
158
122
  {
159
- "type": "number-input",
160
123
  "id": "itemAnimationDuration",
161
124
  "label": "Duración de animación",
162
- "description": "En segundos. Por defecto calcula automaticamente."
125
+ "type": "number-input",
126
+ "description": "En segundos. Por defecto calcula automaticamente."
163
127
  },
164
128
  {
165
129
  "type": "label",
166
130
  "label": "Comida"
167
131
  },
168
132
  {
169
- "type": "text-format",
170
133
  "id": "itemTitleTextFormat",
171
- "label": "Formato del título"
134
+ "label": "Formato del título",
135
+ "type": "text-format"
172
136
  },
173
137
  {
174
- "type": "color-picker",
175
138
  "id": "itemTitleBackgroundColor",
176
139
  "label": "Fondo",
177
- "description": "Color de fondo del título"
140
+ "type": "color-picker",
141
+ "description": "Color de fondo del título",
142
+ "output": "auto"
178
143
  },
179
144
  {
180
- "type": "text-format",
181
145
  "id": "itemOptionsTextFormat",
182
- "label": "Formato de las opciones"
146
+ "label": "Formato de las opciones",
147
+ "type": "text-format"
183
148
  },
184
149
  {
185
- "type": "select-input",
186
150
  "id": "itemStyle",
187
151
  "label": "Estilo",
152
+ "type": "select-input",
188
153
  "items": [
189
154
  {
190
155
  "label": "Estandard",
package/package.json CHANGED
@@ -10,27 +10,28 @@
10
10
  "author": {
11
11
  "name": ""
12
12
  },
13
- "version": "0.1.2-dev.1",
13
+ "version": "0.2.0-dev.0",
14
14
  "scripts": {
15
15
  "prepublish": "vixonic-module-packager --mode build",
16
16
  "watch": "vixonic-module-packager --mode watch",
17
17
  "run": "vixonic-module-packager --mode run",
18
+ "configuration": "vixonic-module-packager --mode generate-configuration",
19
+ "configuration:validate": "vixonic-module-packager --mode validate-configuration",
18
20
  "release": "standard-version",
19
21
  "prerelease-beta": "standard-version --prerelease beta",
20
22
  "prerelease-dev": "standard-version --prerelease dev"
21
23
  },
22
- "devDependencies": {
23
- "standard-version": "^9.5.0",
24
- "@types/node": "^14.18.63",
25
- "@types/react": "^17.0.35",
26
- "@types/react-dom": "^17.0.11",
27
- "@vixoniccom/module-packager": "^2.10.0"
28
- },
29
24
  "dependencies": {
30
25
  "animejs": "^3.2.2",
31
- "localforage": "^1.5.0",
32
- "react": "^17.0.2",
33
- "react-dom": "^17.0.2",
34
- "xlsx": "^0.17.5"
26
+ "react": "^18.3.1",
27
+ "react-dom": "^18.3.1"
28
+ },
29
+ "devDependencies": {
30
+ "@types/animejs": "^3.1.13",
31
+ "@types/react": "^18.3.23",
32
+ "@types/react-dom": "^18.3.7",
33
+ "@vixoniccom/module-packager": "^2.13.0",
34
+ "@vixoniccom/modules": "^2.25.0-dev.23",
35
+ "standard-version": "^9.5.0"
35
36
  }
36
37
  }
package/src/global.d.ts CHANGED
@@ -1,59 +1,23 @@
1
- declare type VixonicData = {
2
- downloadsPath: string
3
- parameters: VixonicParameters
1
+ declare type VixonicTextFormat = {
2
+ fontSize?: number
3
+ fontColor?: string
4
+ alignment?: { horizontal?: 'left' | 'right' | 'center' }
5
+ font?: { filename: string; id: string; __isAsset: true }
4
6
  }
5
7
 
6
- declare type VixonicFile = Partial<{
7
- filename: string
8
- }>
9
-
10
- declare type VixonicTextFormat = Partial<{
11
- fontSize: number,
12
- fontColor: string,
13
- alignment: {
14
- horizontal: 'left' | 'right' | 'center'
15
- }
16
- font: VixonicFile
17
- }>
18
-
19
- declare type VixonicParameters = Partial<{
20
- url: string
21
- pollingInterval: number
22
- mealType: string
23
- animationDuration: number
24
- animationMode: 'fade' | 'slideLeft' | 'slideRight'
25
- containerGridColumns: number
26
- containerGridColumnsGap: number
27
- containerGridRows: number
28
- containerGridRowsGap: number
29
- containerGridMargins: number
30
- backgroundImage: VixonicFile
31
- msj0: string
32
- itemStyle: 'standard' | 'modern' | 'framed'
33
- itemTitleTextFormat: VixonicTextFormat
34
- itemTitleBackgroundColor: string
35
- itemAnimationDuration: number
36
- itemGridMargins: string
37
- itemGridRows: number
38
- itemOptionsTextFormat: VixonicTextFormat
39
- }>
40
-
41
- declare type CacheData = {
42
- updateTime: number
43
- menuData: MenuData
8
+ declare type Meal = {
9
+ type: string
10
+ options: string[]
44
11
  }
45
12
 
46
- declare type MenuData = {
47
- [type: string]: MenuByDate
48
- }
13
+ declare type Menu = Meal[]
49
14
 
50
- declare type MenuByDate = {
51
- [date: number]: Menu
15
+ declare type MenuDay = {
16
+ date: number
17
+ meals: Meal[]
52
18
  }
53
19
 
54
- declare type Menu = Meal[]
55
-
56
- declare type Meal = {
57
- type: string
58
- options: string[]
20
+ declare type MenuAppServiceData = {
21
+ menus: { [mealType: string]: MenuDay[] }
22
+ errors?: string
59
23
  }
package/src/main.ts CHANGED
@@ -10,11 +10,6 @@ let { ipcRenderer } = require('electron')
10
10
  let start = false
11
11
  let vixonicData: VixonicData
12
12
 
13
- type VixonicData = {
14
- downloadsPath: string,
15
- parameters: VixonicParameters
16
- }
17
-
18
13
  ipcRenderer.on('preload', (_event: any, _data: VixonicData) => {
19
14
  // Preload command
20
15
  logger.log('Preload', _data)
@@ -0,0 +1,31 @@
1
+ declare type VixonicData = {
2
+ downloadsPath: string
3
+ services: { [key: string]: { data?: any; updatedAt?: number } }
4
+ parameters: VixonicParameters
5
+ }
6
+
7
+ declare type VixonicParameters = Partial<{
8
+ menuService: { id: string }
9
+ mealType: string
10
+ msj0: string
11
+ animationDuration: number
12
+ animationMode: 'fade' | 'slideRight' | 'slideLeft'
13
+ containerGridColumns: number
14
+ containerGridColumnsGap: number
15
+ containerGridRows: number
16
+ containerGridRowsGap: number
17
+ containerGridMargins: string
18
+ backgroundImage: { id?: string; filename?: string; extension?: string }
19
+ itemGridRows: number
20
+ itemGridMargins: string
21
+ itemAnimationDuration: number
22
+ itemTitleTextFormat: { fontSize?: number; fontColor?: string; alignment?: { horizontal?: 'left' | 'right' | 'center' }; font?: { filename: string; id: string; __isAsset: true } }
23
+ itemTitleBackgroundColor: string
24
+ itemOptionsTextFormat: {
25
+ fontSize?: number
26
+ fontColor?: string
27
+ alignment?: { horizontal?: 'left' | 'right' | 'center' }
28
+ font?: { filename: string; id: string; __isAsset: true }
29
+ }
30
+ itemStyle: 'standard' | 'modern' | 'framed'
31
+ }>
@@ -1,6 +1,4 @@
1
1
  import * as React from 'react'
2
-
3
- import { DataLoader } from '../dataLoader'
4
2
  import Grid from './components/Grid'
5
3
  import MealContainer from './components/MealContainer'
6
4
  import FontLoader, { fontParser } from './components/FontLoader'
@@ -11,48 +9,38 @@ export type AppProps = {
11
9
  vixonicData: VixonicData
12
10
  }
13
11
 
14
- export type AppState = {
15
- loading: boolean
16
- updateTime?: number
12
+ type TodayMenu = {
13
+ status: 'loading' | 'ready'
17
14
  data?: Menu
15
+ error?: string
18
16
  }
19
17
 
20
- class App extends React.Component<AppProps, AppState> {
21
- private readonly dataLoader: DataLoader
18
+ const resolveTodayMenu = (vixonicData: VixonicData): TodayMenu => {
19
+ const { parameters, services } = vixonicData
20
+ const serviceId = parameters.menuService?.id
21
+ const serviceData = serviceId ? (services?.[serviceId]?.data as MenuAppServiceData | undefined) : undefined
22
22
 
23
- constructor (props: AppProps) {
24
- super(props)
25
- let { parameters } = props.vixonicData
26
- this.state = {
27
- loading: true
28
- }
29
- this.dataLoader = new DataLoader(parameters.url, parameters.pollingInterval)
30
- }
23
+ if (!serviceData) return { status: 'loading' }
24
+ if (serviceData.errors) return { status: 'ready', error: serviceData.errors }
31
25
 
32
- componentDidMount () {
33
- this.dataLoader.onUpdate = (data) => {
34
- const { mealType } = this.props.vixonicData.parameters
35
- const today = new Date()
36
- today.setHours(0,0,0,0)
37
- const menu = mealType && data[mealType.toUpperCase()] || data[Object.keys(data)[0]]
38
- this.setState({loading: false, data: menu[today.getTime()]})
39
- }
26
+ const menus = serviceData.menus || {}
27
+ const sheet = (parameters.mealType && menus[parameters.mealType.toUpperCase()]) || menus[Object.keys(menus)[0]]
28
+ if (!sheet) return { status: 'ready' }
40
29
 
41
- this.dataLoader.onError = (e) => {
42
- console.error(e)
43
- }
44
- }
45
-
46
- componentWillReceiveProps (nextProps: AppProps) {
47
- if (this.props.vixonicData.parameters.url !== nextProps.vixonicData.parameters.url) {
48
- let { parameters } = nextProps.vixonicData
49
- parameters.url && this.dataLoader.setup(parameters.url, parameters.pollingInterval)
50
- }
51
- }
30
+ const now = new Date()
31
+ const todayKey = Date.UTC(now.getFullYear(), now.getMonth(), now.getDate())
32
+ const day = sheet.find((d) => d.date === todayKey)
33
+ const meals = day?.meals.filter((meal) => meal.options.length > 0)
34
+ return { status: 'ready', data: meals }
35
+ }
52
36
 
37
+ class App extends React.Component<AppProps> {
53
38
  render () {
54
39
  const { parameters, downloadsPath } = this.props.vixonicData
55
40
  let cycle = parameters.animationDuration && parameters.animationDuration * 1000 || 15000
41
+ const { status, data, error } = resolveTodayMenu(this.props.vixonicData)
42
+ const placeholder = error || (status === 'loading' ? 'Cargando...' : parameters.msj0 || 'No hay menu.')
43
+
56
44
  return <div style={{
57
45
  position: 'absolute',
58
46
  top: 0, right: 0, bottom: 0, left: 0,
@@ -62,11 +50,10 @@ class App extends React.Component<AppProps, AppState> {
62
50
  padding: parameters.containerGridMargins
63
51
  }}>
64
52
  {
65
- this.state.loading || !this.state.data || !this.state.data[0] ?
53
+ !data?.[0] ?
66
54
  <div style={{width: '100%', height: '100%', display: 'flex', fontSize: `${100 / (parameters.itemGridRows || 1)}vmin`, justifyContent: 'center', alignItems: 'center'}}>
67
55
  <FormattedText
68
- text={this.state.loading ? 'Cargando...' : parameters.msj0 || 'No hay menu.'}
69
- downloadsPath={downloadsPath}
56
+ text={placeholder}
70
57
  defaults={{
71
58
  alignment: 'center',
72
59
  fontColor: 'black',
@@ -80,7 +67,7 @@ class App extends React.Component<AppProps, AppState> {
80
67
  id='container'
81
68
  animate={this.props.start}
82
69
  style={{width: '100%', height: '100%'}}
83
- items={this.state.data.map((meal) => (<MealContainer data={meal} interval={cycle} vixonicData={this.props.vixonicData} />))}
70
+ items={data.map((meal) => (<MealContainer key={meal.type} data={meal} interval={cycle} vixonicData={this.props.vixonicData} />))}
84
71
  animation={{
85
72
  mode: parameters.animationMode || 'fade',
86
73
  duration: cycle
@@ -15,7 +15,7 @@ class FontLoader extends React.Component<Props> {
15
15
  src: url("${parseFontUrl(this.props.downloadPath, font)}");
16
16
  }
17
17
  `
18
- } catch (err) {
18
+ } catch {
19
19
  return ''
20
20
  }
21
21
  })
@@ -24,21 +24,8 @@ class FontLoader extends React.Component<Props> {
24
24
  }
25
25
 
26
26
  export function fontParser (parameters: VixonicParameters): string[] {
27
- let initArr: string[] = []
28
- return Object.keys(parameters).reduce(
29
- (fonts, param) => {
30
- switch (param) {
31
- case 'itemTitleTextFormat':
32
- case 'itemOptionsTextFormat':
33
- if (parameters[param] && parameters[param]!.font && parameters[param]!.font!.filename) {
34
- fonts.push((parameters[param]!.font!.filename || ''))
35
- return fonts
36
- } else return fonts
37
- default:
38
- return fonts
39
- }
40
- }, initArr
41
- )
27
+ const keys = ['itemTitleTextFormat', 'itemOptionsTextFormat'] as const
28
+ return keys.map(key => parameters[key]?.font?.filename).filter((filename): filename is string => !!filename)
42
29
  }
43
30
 
44
31
  export const parseFontName = (filename: string): string => {