davidpomerenke commited on
Commit
e8341d2
·
verified ·
1 Parent(s): a73f888

Upload from GitHub Actions: Fix linter problems in frontend

Browse files
frontend/src/App.js CHANGED
@@ -302,6 +302,7 @@ function App () {
302
  <LanguagePlot data={data} width={windowWidth * 0.7} height={windowHeight * 0.6} />,
303
  <SpeakerPlot data={data} width={windowWidth * 0.7} height={windowHeight * 0.6} />,
304
  <HistoryPlot data={data} width={windowWidth * 0.7} height={windowHeight * 0.6} />,
 
305
  ]}
306
  numScroll={1}
307
  numVisible={1}
 
302
  <LanguagePlot data={data} width={windowWidth * 0.7} height={windowHeight * 0.6} />,
303
  <SpeakerPlot data={data} width={windowWidth * 0.7} height={windowHeight * 0.6} />,
304
  <HistoryPlot data={data} width={windowWidth * 0.7} height={windowHeight * 0.6} />,
305
+ <CostPlot data={data} />,
306
  ]}
307
  numScroll={1}
308
  numVisible={1}
frontend/src/components/AutoComplete.js CHANGED
@@ -8,36 +8,58 @@ const AutoComplete = ({ languages, onComplete }) => {
8
  const dropdownRef = useRef(null)
9
  const inputRef = useRef(null)
10
 
11
- // Most spoken languages (by number of speakers) - you can adjust this list
12
- const mostSpokenCodes = ['en', 'zh', 'hi', 'es', 'ar', 'bn', 'pt', 'ru', 'ja', 'pa', 'de', 'jv', 'ko', 'fr', 'te', 'mr', 'tr', 'ta', 'vi', 'ur']
13
-
14
  useEffect(() => {
15
  if (!languages) return
16
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  if (searchTerm.trim() === '') {
18
  // Show most spoken languages first, then others
19
  const mostSpoken = mostSpokenCodes
20
  .map(code => languages.find(lang => lang.bcp_47 === code))
21
  .filter(Boolean)
22
-
23
  const others = languages
24
  .filter(lang => !mostSpokenCodes.includes(lang.bcp_47))
25
  .sort((a, b) => a.language_name.localeCompare(b.language_name))
26
-
27
  setFilteredLanguages([...mostSpoken, ...others])
28
  } else {
29
  const query = searchTerm.toLowerCase()
30
- const matches = languages.filter(language =>
31
- language.language_name.toLowerCase().includes(query) ||
32
- language.autonym.toLowerCase().includes(query) ||
33
- language.bcp_47.toLowerCase().includes(query)
 
34
  )
35
  setFilteredLanguages(matches)
36
  }
37
- }, [searchTerm, languages, mostSpokenCodes])
38
 
39
  useEffect(() => {
40
- const handleClickOutside = (event) => {
41
  if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
42
  setIsOpen(false)
43
  setSearchTerm('')
@@ -48,14 +70,14 @@ const AutoComplete = ({ languages, onComplete }) => {
48
  return () => document.removeEventListener('mousedown', handleClickOutside)
49
  }, [])
50
 
51
- const handleSelect = (language) => {
52
  setSelectedLanguage(language)
53
  setIsOpen(false)
54
  setSearchTerm('')
55
  onComplete([language])
56
  }
57
 
58
- const handleClear = (e) => {
59
  e.stopPropagation()
60
  setSelectedLanguage(null)
61
  onComplete([])
@@ -68,7 +90,7 @@ const AutoComplete = ({ languages, onComplete }) => {
68
  }
69
  }
70
 
71
- const handleInputChange = (e) => {
72
  // If user starts typing while a language is selected, clear the selection to enable search
73
  if (selectedLanguage && e.target.value.length > 0) {
74
  setSelectedLanguage(null)
@@ -77,7 +99,7 @@ const AutoComplete = ({ languages, onComplete }) => {
77
  setSearchTerm(e.target.value)
78
  }
79
 
80
- const handleKeyDown = (e) => {
81
  if (e.key === 'Escape') {
82
  setIsOpen(false)
83
  setSearchTerm('')
@@ -159,15 +181,15 @@ const AutoComplete = ({ languages, onComplete }) => {
159
 
160
  return (
161
  <div style={containerStyle} ref={dropdownRef}>
162
- <div
163
  style={buttonStyle}
164
  onClick={handleContainerClick}
165
- onMouseEnter={(e) => {
166
  if (!selectedLanguage) {
167
  e.target.style.borderColor = '#bbb'
168
  }
169
  }}
170
- onMouseLeave={(e) => {
171
  e.target.style.borderColor = '#ddd'
172
  }}
173
  >
@@ -179,13 +201,13 @@ const AutoComplete = ({ languages, onComplete }) => {
179
  <button
180
  style={clearButtonStyle}
181
  onClick={handleClear}
182
- onMouseEnter={(e) => {
183
  e.target.style.backgroundColor = '#f0f0f0'
184
  }}
185
- onMouseLeave={(e) => {
186
  e.target.style.backgroundColor = 'transparent'
187
  }}
188
- title="View overall leaderboard"
189
  >
190
  ×
191
  </button>
@@ -194,13 +216,17 @@ const AutoComplete = ({ languages, onComplete }) => {
194
  <input
195
  ref={inputRef}
196
  style={inputStyle}
197
- placeholder={selectedLanguage ? "Type to search other languages..." : "Type to search languages..."}
 
 
 
 
198
  value={searchTerm}
199
  onChange={handleInputChange}
200
  onKeyDown={handleKeyDown}
201
  />
202
  ) : (
203
- <span>Search for language-specific leaderboards...</span>
204
  )}
205
  {(!selectedLanguage || isOpen) && (
206
  <span style={{ color: '#999', fontSize: '12px' }}>
@@ -221,10 +247,10 @@ const AutoComplete = ({ languages, onComplete }) => {
221
  key={language.bcp_47}
222
  style={itemStyle}
223
  onClick={() => handleSelect(language)}
224
- onMouseEnter={(e) => {
225
  e.target.style.backgroundColor = '#f8f9fa'
226
  }}
227
- onMouseLeave={(e) => {
228
  e.target.style.backgroundColor = 'transparent'
229
  }}
230
  >
@@ -243,8 +269,15 @@ const AutoComplete = ({ languages, onComplete }) => {
243
  ))
244
  )}
245
  {filteredLanguages.length > 20 && (
246
- <div style={{ ...itemStyle, color: '#999', cursor: 'default', fontStyle: 'italic' }}>
247
- ... and {filteredLanguages.length - 20} more languages
 
 
 
 
 
 
 
248
  </div>
249
  )}
250
  </div>
 
8
  const dropdownRef = useRef(null)
9
  const inputRef = useRef(null)
10
 
 
 
 
11
  useEffect(() => {
12
  if (!languages) return
13
+
14
+ // Most spoken languages (by number of speakers) - you can adjust this list
15
+ const mostSpokenCodes = [
16
+ 'en',
17
+ 'zh',
18
+ 'hi',
19
+ 'es',
20
+ 'ar',
21
+ 'bn',
22
+ 'pt',
23
+ 'ru',
24
+ 'ja',
25
+ 'pa',
26
+ 'de',
27
+ 'jv',
28
+ 'ko',
29
+ 'fr',
30
+ 'te',
31
+ 'mr',
32
+ 'tr',
33
+ 'ta',
34
+ 'vi',
35
+ 'ur'
36
+ ]
37
+
38
  if (searchTerm.trim() === '') {
39
  // Show most spoken languages first, then others
40
  const mostSpoken = mostSpokenCodes
41
  .map(code => languages.find(lang => lang.bcp_47 === code))
42
  .filter(Boolean)
43
+
44
  const others = languages
45
  .filter(lang => !mostSpokenCodes.includes(lang.bcp_47))
46
  .sort((a, b) => a.language_name.localeCompare(b.language_name))
47
+
48
  setFilteredLanguages([...mostSpoken, ...others])
49
  } else {
50
  const query = searchTerm.toLowerCase()
51
+ const matches = languages.filter(
52
+ language =>
53
+ language.language_name.toLowerCase().includes(query) ||
54
+ language.autonym.toLowerCase().includes(query) ||
55
+ language.bcp_47.toLowerCase().includes(query)
56
  )
57
  setFilteredLanguages(matches)
58
  }
59
+ }, [searchTerm, languages])
60
 
61
  useEffect(() => {
62
+ const handleClickOutside = event => {
63
  if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
64
  setIsOpen(false)
65
  setSearchTerm('')
 
70
  return () => document.removeEventListener('mousedown', handleClickOutside)
71
  }, [])
72
 
73
+ const handleSelect = language => {
74
  setSelectedLanguage(language)
75
  setIsOpen(false)
76
  setSearchTerm('')
77
  onComplete([language])
78
  }
79
 
80
+ const handleClear = e => {
81
  e.stopPropagation()
82
  setSelectedLanguage(null)
83
  onComplete([])
 
90
  }
91
  }
92
 
93
+ const handleInputChange = e => {
94
  // If user starts typing while a language is selected, clear the selection to enable search
95
  if (selectedLanguage && e.target.value.length > 0) {
96
  setSelectedLanguage(null)
 
99
  setSearchTerm(e.target.value)
100
  }
101
 
102
+ const handleKeyDown = e => {
103
  if (e.key === 'Escape') {
104
  setIsOpen(false)
105
  setSearchTerm('')
 
181
 
182
  return (
183
  <div style={containerStyle} ref={dropdownRef}>
184
+ <div
185
  style={buttonStyle}
186
  onClick={handleContainerClick}
187
+ onMouseEnter={e => {
188
  if (!selectedLanguage) {
189
  e.target.style.borderColor = '#bbb'
190
  }
191
  }}
192
+ onMouseLeave={e => {
193
  e.target.style.borderColor = '#ddd'
194
  }}
195
  >
 
201
  <button
202
  style={clearButtonStyle}
203
  onClick={handleClear}
204
+ onMouseEnter={e => {
205
  e.target.style.backgroundColor = '#f0f0f0'
206
  }}
207
+ onMouseLeave={e => {
208
  e.target.style.backgroundColor = 'transparent'
209
  }}
210
+ title='View overall leaderboard'
211
  >
212
  ×
213
  </button>
 
216
  <input
217
  ref={inputRef}
218
  style={inputStyle}
219
+ placeholder={
220
+ selectedLanguage
221
+ ? 'Type to search other languages...'
222
+ : 'Type to search languages...'
223
+ }
224
  value={searchTerm}
225
  onChange={handleInputChange}
226
  onKeyDown={handleKeyDown}
227
  />
228
  ) : (
229
+ <span>Go to leaderboard for specific language...</span>
230
  )}
231
  {(!selectedLanguage || isOpen) && (
232
  <span style={{ color: '#999', fontSize: '12px' }}>
 
247
  key={language.bcp_47}
248
  style={itemStyle}
249
  onClick={() => handleSelect(language)}
250
+ onMouseEnter={e => {
251
  e.target.style.backgroundColor = '#f8f9fa'
252
  }}
253
+ onMouseLeave={e => {
254
  e.target.style.backgroundColor = 'transparent'
255
  }}
256
  >
 
269
  ))
270
  )}
271
  {filteredLanguages.length > 20 && (
272
+ <div
273
+ style={{
274
+ ...itemStyle,
275
+ color: '#999',
276
+ cursor: 'default',
277
+ fontStyle: 'italic'
278
+ }}
279
+ >
280
+ Type to search for more languages...
281
  </div>
282
  )}
283
  </div>
frontend/src/components/CostPlot.js CHANGED
@@ -1,7 +1,7 @@
1
  import { useRef, useEffect } from 'react'
2
  import * as Plot from '@observablehq/plot'
3
 
4
- const HistoryPlot = ({ data, width = 750, height = 500 }) => {
5
  const containerRef = useRef()
6
  useEffect(() => {
7
  const models = [...data.model_table] // sort copy, not in place
@@ -55,12 +55,12 @@ const HistoryPlot = ({ data, width = 750, height = 500 }) => {
55
  ...models.filter(d => d.newRecord),
56
  {
57
  cost: models.map(d => d.cost).reduce((a, b) => Math.max(a, b), 0),
58
- maxAverage: models[models.length - 1].maxAverage
59
  }
60
  ],
61
  {
62
  x: d => d.cost,
63
- y: d => d.maxAverage,
64
  curve: 'catmull-rom',
65
  strokeOpacity: 0.3
66
  }
@@ -69,7 +69,7 @@ const HistoryPlot = ({ data, width = 750, height = 500 }) => {
69
  })
70
  containerRef.current.append(plot)
71
  return () => plot.remove()
72
- }, [data])
73
 
74
  return (
75
  <div
@@ -85,4 +85,4 @@ const HistoryPlot = ({ data, width = 750, height = 500 }) => {
85
  )
86
  }
87
 
88
- export default HistoryPlot
 
1
  import { useRef, useEffect } from 'react'
2
  import * as Plot from '@observablehq/plot'
3
 
4
+ const CostPlot = ({ data, width = 750, height = 500 }) => {
5
  const containerRef = useRef()
6
  useEffect(() => {
7
  const models = [...data.model_table] // sort copy, not in place
 
55
  ...models.filter(d => d.newRecord),
56
  {
57
  cost: models.map(d => d.cost).reduce((a, b) => Math.max(a, b), 0),
58
+ maxAverage: models[models.length - 1]?.maxAverage || 0
59
  }
60
  ],
61
  {
62
  x: d => d.cost,
63
+ y: d => d?.maxAverage || 0,
64
  curve: 'catmull-rom',
65
  strokeOpacity: 0.3
66
  }
 
69
  })
70
  containerRef.current.append(plot)
71
  return () => plot.remove()
72
+ }, [data, width, height])
73
 
74
  return (
75
  <div
 
85
  )
86
  }
87
 
88
+ export default CostPlot
frontend/src/components/DatasetTable.js CHANGED
@@ -23,7 +23,7 @@ const DatasetTable = ({ data }) => {
23
 
24
  const authorBodyTemplate = rowData => {
25
  const url = rowData.author_url?.replace('https://', '')
26
- const img = url ? <img src={`https://favicone.com/${url}`} style={{borderRadius: '50%'}}/> : <></>
27
  return <div style={{ display: 'flex', alignItems: 'center' }}>
28
  <div style={{ width: '16px', height: '16px', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>{img}</div>
29
  <div style={{ marginLeft: '0.5rem' }}>{rowData.author}</div>
@@ -41,7 +41,7 @@ const DatasetTable = ({ data }) => {
41
  }
42
 
43
  const linkBodyTemplate = rowData => {
44
- return <a href={rowData.url} target='_blank' style={{ textDecoration: 'none', color: 'inherit' }}><i className='pi pi-external-link' style={{ fontSize: '0.8rem' }} /></a>
45
  }
46
 
47
  const translationBodyTemplate = rowData => {
 
23
 
24
  const authorBodyTemplate = rowData => {
25
  const url = rowData.author_url?.replace('https://', '')
26
+ const img = url ? <img src={`https://favicone.com/${url}`} style={{borderRadius: '50%'}} alt="Thumbnail of the author's website"/> : <></>
27
  return <div style={{ display: 'flex', alignItems: 'center' }}>
28
  <div style={{ width: '16px', height: '16px', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>{img}</div>
29
  <div style={{ marginLeft: '0.5rem' }}>{rowData.author}</div>
 
41
  }
42
 
43
  const linkBodyTemplate = rowData => {
44
+ return <a href={rowData.url} target='_blank' rel='noopener noreferrer' style={{ textDecoration: 'none', color: 'inherit' }}><i className='pi pi-external-link' style={{ fontSize: '0.8rem' }} /></a>
45
  }
46
 
47
  const translationBodyTemplate = rowData => {
frontend/src/components/HistoryPlot.js CHANGED
@@ -64,7 +64,7 @@ const HistoryPlot = ({ data, width = 750, height = 500 }) => {
64
  })
65
  containerRef.current.append(plot)
66
  return () => plot.remove()
67
- }, [])
68
 
69
  return (
70
  <div
 
64
  })
65
  containerRef.current.append(plot)
66
  return () => plot.remove()
67
+ }, [models, width, height])
68
 
69
  return (
70
  <div
frontend/src/components/LanguagePlot.js CHANGED
@@ -4,7 +4,6 @@ import * as Plot from '@observablehq/plot'
4
  const LanguagePlot = ({ data, width = 750, height = 500 }) => {
5
  const containerRef = useRef()
6
  const languages = data.language_table.filter(a => a.average > 0)
7
- const families = [...new Set(languages.map(a => a.family))]
8
 
9
  useEffect(() => {
10
  const plot = Plot.plot({
@@ -46,7 +45,7 @@ const LanguagePlot = ({ data, width = 750, height = 500 }) => {
46
  })
47
  containerRef.current.append(plot)
48
  return () => plot.remove()
49
- }, [])
50
 
51
  return (
52
  <div
 
4
  const LanguagePlot = ({ data, width = 750, height = 500 }) => {
5
  const containerRef = useRef()
6
  const languages = data.language_table.filter(a => a.average > 0)
 
7
 
8
  useEffect(() => {
9
  const plot = Plot.plot({
 
45
  })
46
  containerRef.current.append(plot)
47
  return () => plot.remove()
48
+ }, [languages, width, height])
49
 
50
  return (
51
  <div
frontend/src/components/SpeakerPlot.js CHANGED
@@ -81,7 +81,7 @@ const SpeakerPlot = ({ data, width = 750, height = 500 }) => {
81
  })
82
  containerRef.current.append(plot)
83
  return () => plot.remove()
84
- }, [])
85
 
86
  return (
87
  <div
 
81
  })
82
  containerRef.current.append(plot)
83
  return () => plot.remove()
84
+ }, [languages, width, height])
85
 
86
  return (
87
  <div
frontend/src/components/WorldMap.js CHANGED
@@ -65,7 +65,7 @@ const WorldMap = ({ data, width = 750, height = 500 }) => {
65
  unknown: 'gray',
66
  label: 'Score',
67
  legend: true,
68
- domain: [0, 0.7]
69
  },
70
  style: {
71
  fontFamily: 'monospace'
@@ -73,7 +73,7 @@ const WorldMap = ({ data, width = 750, height = 500 }) => {
73
  })
74
  containerRef.current.append(plot)
75
  return () => plot.remove()
76
- }, [mapData, data])
77
 
78
  return (
79
  <div
 
65
  unknown: 'gray',
66
  label: 'Score',
67
  legend: true,
68
+ domain: [0, 1]
69
  },
70
  style: {
71
  fontFamily: 'monospace'
 
73
  })
74
  containerRef.current.append(plot)
75
  return () => plot.remove()
76
+ }, [mapData, data, width, height])
77
 
78
  return (
79
  <div