-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLanguages.tsx
146 lines (130 loc) · 4.57 KB
/
Languages.tsx
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import CodeIcon from '@mui/icons-material/Code'
import Box from '@mui/material/Box'
import Paper from '@mui/material/Paper'
import { BarSeriesType } from '@mui/x-charts'
import { useCallback, useEffect, useState } from 'react'
import OptionSelector from '~/components/OptionSelector'
import Section from '~/components/Section'
import dataService from '~/services/data'
import { LanguageMap } from '~/types'
import { formatPercentage, getColor } from '~/utils'
import LanguagesChart from './LanguagesChart'
import Loading from './Loading'
import NoData from './NoData'
enum Source {
REPO = 'repo',
SIZE = 'size',
}
const Languages = (): JSX.Element => {
const [loading, setLoading] = useState<boolean>(true)
const [languagesByRepo, setLanguagesByRepo] = useState<LanguageMap>({})
const [languagesBySize, setLanguagesBySize] = useState<LanguageMap>({})
const [noData, setNoData] = useState<boolean>(true)
const [source, setSource] = useState<Source>(Source.REPO)
const [series, setSeries] = useState<BarSeriesType[]>([])
const getSource = useCallback((): LanguageMap => {
return source === Source.REPO ? languagesByRepo : languagesBySize
}, [languagesByRepo, languagesBySize, source])
useEffect(() => {
void dataService.getLanguagesByRepo().then((languages) => {
setLanguagesByRepo(languages)
setNoData(Object.keys(languages).length === 0)
})
void dataService.getLanguagesBySize().then((languages) => {
setLanguagesBySize(languages)
setNoData(Object.keys(languages).length === 0)
})
setLoading(false)
}, [])
useEffect(() => {
const formatBytes = (total: number, bytes: number): string => {
const megaBytes = 1024 * 1024
return `${(bytes / megaBytes).toFixed(2)} MB (${((bytes / total) * 100).toFixed(2)}%)`
}
const formatTooltipText = (value: number): string => {
const total = Object.values(getSource()).reduce((total, items) => total + items, 0)
if (source === Source.REPO) {
const units = value === 1 ? 'repository' : 'repositories'
return formatPercentage(total, units, value)
}
return formatBytes(total, value)
}
const transformSeries = (data: LanguageMap) => {
const languages = Object.keys(data)
const series = languages.map((language) => ({
color: getColor(language) as string,
data: languages.map((key) => (key === language ? data[language] : null)),
highlightScope: {
faded: 'global',
highlighted: 'item',
},
id: language,
label: language,
stack: 'total',
valueFormatter: (value: number | null) => value && formatTooltipText(value),
}))
setSeries(series as BarSeriesType[])
}
transformSeries(getSource())
}, [getSource, source])
const getLabel = (): string => {
return source === Source.REPO ? ' \nRepositories' : ' \nTotal size (megabytes)'
}
const formatAxisValue = (value: string): string => {
if (source === Source.REPO) {
return value.toString()
}
const megaBytes = 1024 * 1024
return `${(parseInt(value, 10) / megaBytes).toFixed(2)}`
}
const handleSourceChange = (newSource: string) => {
setSource(newSource as Source)
}
return (
<Section
description="Top programming languages"
icon={<CodeIcon />}
info={
<span>
<b>Repository</b> displays the share of each language used as the main (majority) language
of a repository.
<br />
<br />
<b>Total size</b> shows the proportion of each language used across all repositories by
the total number of megabytes.
<br />
<br />
Hover over the chart to see the exact number and share of each item.
</span>
}
title="Languages"
>
<Box>
<OptionSelector
disabled={loading || noData}
onChange={handleSourceChange}
options={[
{ label: 'Repository', value: Source.REPO },
{ label: 'Total size', value: Source.SIZE },
]}
value={source}
/>
<Paper
elevation={3}
sx={{ height: '400px', margin: '20px 0px', padding: loading ? '30px' : 0 }}
>
<Loading visible={loading} />
<NoData visible={!loading && noData} />
<LanguagesChart
data={Object.keys(getSource())}
formatAxisValue={formatAxisValue}
label={getLabel()}
series={series}
visible={!loading && !noData}
/>
</Paper>
</Box>
</Section>
)
}
export default Languages