-
-
Notifications
You must be signed in to change notification settings - Fork 235
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add most used languages graph (#2158)
- Loading branch information
Showing
9 changed files
with
259 additions
and
53 deletions.
There are no files selected for viewing
134 changes: 134 additions & 0 deletions
134
components/Graphs/MostUsedLanguagesGraph/most-used-languages-graph.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
import { BsFillCircleFill } from "react-icons/bs"; | ||
import Skeleton from "react-loading-skeleton"; | ||
import { useEffect, useRef, useState } from "react"; | ||
import Card from "components/atoms/Card/card"; | ||
import Text from "components/atoms/Typography/text"; | ||
import { ContributorType, ContributorTypeFilter } from "../shared/contributor-type-filter"; | ||
|
||
export interface MostUsedLanguagesGraphProps { | ||
data: { | ||
mainLanguage: string; | ||
data: { | ||
name: string; | ||
value: number; | ||
}[]; | ||
}; | ||
setContributorType: (type: ContributorType) => void; | ||
contributorType: ContributorType; | ||
isLoading?: boolean; | ||
} | ||
|
||
export const MostUsedLanguagesGraph = ({ | ||
data, | ||
setContributorType, | ||
contributorType, | ||
isLoading = false, | ||
}: MostUsedLanguagesGraphProps) => { | ||
const colors = [ | ||
"hsl(53, 91%, 59%)", | ||
"hsl(204, 100%, 40%)", | ||
"hsl(14, 98%, 49%)", | ||
"hsl(267, 36%, 37%)", | ||
"hsl(17, 100%, 50%)", | ||
]; | ||
const percentage = 10; | ||
const { data: languages = [], mainLanguage } = data; | ||
const lastItem = languages.length > 0 ? languages.length - 1 : 0; | ||
const sortedLanguages = languages.sort((a, b) => b.value - a.value); | ||
const languagesRef = useRef<HTMLUListElement>(null); | ||
const [language, setLanguage] = useState<string | null>(); | ||
|
||
useEffect(() => { | ||
if (language) { | ||
const languageElement = languagesRef.current?.querySelector(`[data-language="${language}"]`); | ||
if (languageElement) { | ||
languageElement.classList.add("font-semibold"); | ||
} | ||
} | ||
}, [language]); | ||
|
||
return ( | ||
<Card className="p-5"> | ||
<div className="flex flex-col gap-6"> | ||
<div> | ||
<h2 className="pb-1 font-medium text-lg tracking-tight">Most used languages</h2> | ||
<Text> | ||
{mainLanguage} contributions have been growing on average {percentage}% MoM | ||
</Text> | ||
</div> | ||
<div className="w-max"> | ||
<ContributorTypeFilter setContributorType={setContributorType} contributorType={contributorType} /> | ||
</div> | ||
|
||
<div className="flex h-3 place-content-center"> | ||
{isLoading ? ( | ||
<div className="loading rounded-lg w-max" style={{ width: "100%" }}> | ||
<span className="sr-only">loading most used languages graph</span> | ||
</div> | ||
) : ( | ||
<> | ||
{sortedLanguages.length > 0 ? ( | ||
sortedLanguages.map((item, index) => { | ||
return ( | ||
<button | ||
aria-label={`${item.name} is ${item.value}% of the most used languages for contributors in your list`} | ||
key={item.name} | ||
data-language={item.name} | ||
className={`${index === 0 ? "rounded-l-lg" : ""} ${ | ||
index === lastItem ? "rounded-r-lg" : "" | ||
} transform hover:scale-110 transition-transform hover:z-10`} | ||
style={{ backgroundColor: colors[index], width: `${item.value}%` }} | ||
onMouseOver={(event) => { | ||
const { language } = event.currentTarget.dataset; | ||
setLanguage(language); | ||
}} | ||
onMouseOut={(event) => { | ||
setLanguage(null); | ||
}} | ||
onFocus={(event) => { | ||
const { language } = event.currentTarget.dataset; | ||
setLanguage(language); | ||
}} | ||
onBlur={(event) => { | ||
setLanguage(null); | ||
}} | ||
/> | ||
); | ||
}) | ||
) : ( | ||
<div className="rounded-lg bg-slate-100 w-full" /> | ||
)} | ||
</> | ||
)} | ||
</div> | ||
|
||
{isLoading ? ( | ||
<Skeleton height={24} count={5} className="mt-4 mb-4" /> | ||
) : ( | ||
<ul ref={languagesRef} className="grid grid-cols-1 content-center"> | ||
{sortedLanguages.length > 0 ? ( | ||
sortedLanguages.map((item, index) => ( | ||
<li | ||
key={item.name} | ||
className={`flex justify-between pt-4 pb-4 ${ | ||
index === lastItem ? "" : "border-b-1 border-slate-100" | ||
} ${language === item.name ? "font-semibold" : ""}`} | ||
> | ||
<span | ||
className={`flex gap-2 items-center ${language === item.name ? "text-black" : "text-slate-700"}`} | ||
> | ||
<BsFillCircleFill size={11} style={{ fill: colors[index] }} /> | ||
{item.name} | ||
</span> | ||
<span className={`${language === item.name ? "text-black" : "text-slate-600"}`}>{item.value}%</span> | ||
</li> | ||
)) | ||
) : ( | ||
<p className="text-center">There is no language data</p> | ||
)} | ||
</ul> | ||
)} | ||
</div> | ||
</Card> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import Button from "components/atoms/Button/button"; | ||
import { | ||
DropdownMenu, | ||
DropdownMenuContent, | ||
DropdownMenuItem, | ||
DropdownMenuTrigger, | ||
} from "components/atoms/Dropdown/dropdown"; | ||
import PeopleIcon from "img/icons/people.svg"; | ||
import ChevronDownIcon from "img/chevron-down.svg"; | ||
import SVGIcon from "components/atoms/SVGIcon/svg-icon"; | ||
import Icon from "components/atoms/Icon/icon"; | ||
|
||
interface ContributorTypeFilterProps { | ||
setContributorType: (type: ContributorType) => void; | ||
contributorType: ContributorType; | ||
} | ||
|
||
export type ContributorType = "all" | "active" | "new" | "alumni"; | ||
|
||
const peopleFilters: Record<ContributorType, string> = { | ||
all: "All Contributors", | ||
active: "Active Contributors", | ||
new: "New Contributors", | ||
alumni: "Alumni Contributors", | ||
}; | ||
|
||
export const ContributorTypeFilter = ({ setContributorType, contributorType }: ContributorTypeFilterProps) => { | ||
return ( | ||
<DropdownMenu> | ||
<DropdownMenuTrigger asChild> | ||
<Button variant="default" className="items-center gap-1"> | ||
<SVGIcon IconImage={`${PeopleIcon.src}#icon`} className="w-4 h-4" /> | ||
{peopleFilters[contributorType]} | ||
<Icon IconImage={ChevronDownIcon} className="w-4 h-4" /> | ||
</Button> | ||
</DropdownMenuTrigger> | ||
<DropdownMenuContent align="end" className="flex flex-col gap-2"> | ||
{Object.entries(peopleFilters).map(([key, value]) => ( | ||
<DropdownMenuItem | ||
key={key} | ||
className="rounded-md !cursor-pointer" | ||
onClick={() => setContributorType(key as keyof typeof peopleFilters)} | ||
> | ||
{value} | ||
</DropdownMenuItem> | ||
))} | ||
</DropdownMenuContent> | ||
</DropdownMenu> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { MostUsedLanguagesGraph } from "components/Graphs/MostUsedLanguagesGraph/most-used-languages-graph"; | ||
import type { Meta, StoryObj } from "@storybook/react"; | ||
|
||
type MetaData = Meta<typeof MostUsedLanguagesGraph>; | ||
|
||
const meta: MetaData = { | ||
title: "Components/Graphs/Most Used Languages Graph", | ||
component: MostUsedLanguagesGraph, | ||
}; | ||
|
||
export default meta; | ||
type Story = StoryObj<typeof MostUsedLanguagesGraph>; | ||
|
||
function generateData() { | ||
return { | ||
mainLanguage: "TypeScript", | ||
data: [ | ||
{ | ||
name: "Python", | ||
value: 10, | ||
}, | ||
{ | ||
name: "TypeScript", | ||
value: 25, | ||
}, | ||
{ | ||
name: "JavaScript", | ||
value: 20, | ||
}, | ||
{ | ||
name: "C++", | ||
value: 15, | ||
}, | ||
{ | ||
name: "Zig", | ||
value: 30, | ||
}, | ||
], | ||
}; | ||
} | ||
|
||
export const Default: Story = { | ||
args: { | ||
data: generateData(), | ||
contributorType: "all", | ||
setContributorType(type) { | ||
// eslint-disable-next-line no-console | ||
console.log(type); | ||
}, | ||
}, | ||
}; | ||
|
||
export const Loading: Story = { | ||
args: { | ||
isLoading: true, | ||
data: generateData(), | ||
contributorType: "all", | ||
setContributorType(type) { | ||
// eslint-disable-next-line no-console | ||
console.log(type); | ||
}, | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters