Skip to content

Commit 399e6b7

Browse files
committed
style profile and stattistics component
1 parent af1a69d commit 399e6b7

File tree

6 files changed

+164
-66
lines changed

6 files changed

+164
-66
lines changed

src/components/DifficultyStatistics.tsx

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
11
import React from 'react';
22
import { Stack, Text } from '@mantine/core';
33

4-
const DifficultyStatistics: React.FC<{ text: string; color: string }> = ({
5-
text,
6-
color
7-
}) => {
4+
const DifficultyStatistics: React.FC<{
5+
text: string;
6+
color: string;
7+
solved: number;
8+
total: number;
9+
onHover: () => void;
10+
onLeave: () => void;
11+
}> = ({ text, color, solved, total, onHover, onLeave }) => {
812
return (
9-
<Stack>
10-
<Text tt="capitalize">{text}</Text>
13+
<Stack bg="#FAFAFA" onMouseOver={onHover} onMouseLeave={onLeave} gap={0}>
14+
<Text tt="capitalize" c={color} size="xs" ta="center" fw="bolder">
15+
{text}
16+
</Text>
17+
<Text size="xs" fw="bold" ta="center">
18+
{solved}/{total}
19+
</Text>
1120
</Stack>
1221
);
1322
};

src/components/LeetCodeMain.tsx

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
11
import React, { useEffect, useState } from 'react';
22
import { IDocumentManager } from '@jupyterlab/docmanager';
33
import { Notification } from '@jupyterlab/apputils';
4-
import { Container, Group, Stack } from '@mantine/core';
4+
import { Container, Group, PaperProps, Stack } from '@mantine/core';
55
import { getProfile } from '../services/leetcode';
66
import { LeetCodeProfile } from '../types/leetcode';
77
import Profile from './Profile';
88
import Statistics from './Statistics';
99
import QuestionTable from './QuestionTable';
1010

11+
const MainHeaderPaperProps: PaperProps = {
12+
shadow: 'md',
13+
radius: 'md',
14+
withBorder: true,
15+
p: 'sm',
16+
bg: 'var(--mantine-color-body)'
17+
};
18+
1119
const LeetCodeMain: React.FC<{ docManager: IDocumentManager }> = ({
1220
docManager
1321
}) => {
@@ -46,9 +54,12 @@ const LeetCodeMain: React.FC<{ docManager: IDocumentManager }> = ({
4654
return (
4755
<Container fluid={true} h="100%" p="lg" id="jll-main">
4856
<Stack>
49-
<Group id="jll-profile" h={146}>
50-
{profile && <Profile profile={profile} />}
51-
{profile && <Statistics username={profile.username} />}
57+
<Group id="jll-profile" align="stretch">
58+
<Profile paperProps={MainHeaderPaperProps} profile={profile} />
59+
<Statistics
60+
paperProps={MainHeaderPaperProps}
61+
username={profile?.username}
62+
/>
5263
</Group>
5364
<QuestionTable openNotebook={openNoteBook} height={calcHeight()} />
5465
</Stack>
File renamed without changes.

src/components/Profile.tsx

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,29 @@
11
import React from 'react';
2-
import { Avatar, Paper, Text } from '@mantine/core';
2+
import { Avatar, Center, Paper, PaperProps, Stack, Text } from '@mantine/core';
33
import { LeetCodeProfile } from '../types/leetcode';
44

55
const Profile: React.FC<{
6-
profile: LeetCodeProfile;
7-
}> = ({ profile }) => {
6+
profile: LeetCodeProfile | null;
7+
paperProps: PaperProps;
8+
}> = ({ profile, paperProps }) => {
89
return (
910
<Paper
10-
shadow="md"
11-
radius="md"
12-
withBorder
13-
p="sm"
1411
miw="20%"
1512
maw="40%"
16-
bg="var(--mantine-color-body)"
13+
{...paperProps}
14+
style={{ alignContent: 'center' }}
1715
>
18-
<Avatar src={profile.avatar} size={60} radius={60} mx="auto" />
19-
<Text ta="center" fz="md" fw={500} mt="xs">
20-
{profile.realName}
21-
</Text>
22-
<Text ta="center" c="dimmed" fz="xs">
23-
{profile.username}
24-
</Text>
16+
<Center>
17+
<Stack gap={0}>
18+
<Avatar src={profile?.avatar} size="md" radius="xl" mx="auto" />
19+
<Text ta="center" fz="md" fw={500} mt="xs">
20+
{profile?.realName}
21+
</Text>
22+
<Text ta="center" c="dimmed" fz="xs">
23+
{profile?.username}
24+
</Text>
25+
</Stack>
26+
</Center>
2527
</Paper>
2628
);
2729
};

src/components/Statistics.tsx

Lines changed: 115 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,20 @@
11
import React, { useEffect, useState } from 'react';
2-
import { Center, Group, Paper, RingProgress, Stack, Text } from '@mantine/core';
2+
import {
3+
Center,
4+
Group,
5+
Paper,
6+
PaperProps,
7+
RingProgress,
8+
RingProgressProps,
9+
Stack,
10+
Text
11+
} from '@mantine/core';
312
import { Notification } from '@jupyterlab/apputils';
413
import { getStatistics } from '../services/leetcode';
514
import { LeetCodeStatistics } from '../types/leetcode';
615
import DifficultyStatistics from './DifficultyStatistics';
16+
import { IconCheck } from '@tabler/icons-react';
17+
import { StatusColors } from './QuestionItem';
718

819
export const DifficultyColors: Record<string, string> = {
920
easy: '#1CBBBA',
@@ -12,58 +23,72 @@ export const DifficultyColors: Record<string, string> = {
1223
};
1324

1425
const Statistics: React.FC<{
15-
username: string;
16-
}> = ({ username }) => {
26+
username?: string;
27+
paperProps: PaperProps;
28+
}> = ({ username, paperProps }) => {
1729
const [statistics, setStatistics] = useState<LeetCodeStatistics | null>(null);
18-
const [all, setAll] = useState<Map<string, number> | null>(null);
19-
const [accepted, setAccepted] = useState<Map<string, number> | null>(null);
20-
const [__beats, setBeats] = useState<Map<string, number> | null>(null);
30+
const [isHovering, setIsHovering] = useState(false);
31+
const [difficultySections, setDifficultySections] = useState<
32+
RingProgressProps['sections'] | null
33+
>(null);
34+
const [beats, setBeats] = useState<number | null>(null);
2135

2236
useEffect(() => {
37+
if (!username) {
38+
return;
39+
}
2340
getStatistics(username)
24-
.then(d => {
25-
setStatistics(d);
26-
})
41+
.then(d => setStatistics(d))
2742
.catch(e => Notification.error(e.message, { autoClose: 3000 }));
28-
}, []);
43+
}, [username]);
2944

30-
useEffect(() => {
45+
const getAllQuestions = () => {
3146
if (!statistics?.userSessionProgress) {
3247
return;
3348
}
3449

3550
const { userSessionProgress: sp } = statistics;
36-
setAll(
37-
new Map(
38-
sp.allQuestionsCount.map(o => [o.difficulty.toLowerCase(), o.count])
39-
)
51+
return new Map(
52+
sp.allQuestionsCount.map(o => [o.difficulty.toLowerCase(), o.count])
4053
);
41-
}, [statistics?.userSessionProgress]);
54+
};
4255

43-
useEffect(() => {
56+
const getAcceptedQuestions = () => {
4457
const up =
4558
statistics?.userProfileUserQuestionProgressV2
4659
.userProfileUserQuestionProgressV2;
4760
if (!up) {
4861
return;
4962
}
5063

51-
setAccepted(
52-
new Map(
53-
up.numAcceptedQuestions.map(o => [o.difficulty.toLowerCase(), o.count])
54-
)
64+
return new Map(
65+
up.numAcceptedQuestions.map(o => [o.difficulty.toLowerCase(), o.count])
5566
);
67+
};
5668

57-
const b = new Map(
69+
const getBeats = () => {
70+
const up =
71+
statistics?.userProfileUserQuestionProgressV2
72+
.userProfileUserQuestionProgressV2;
73+
if (!up) {
74+
return;
75+
}
76+
return new Map(
5877
up.userSessionBeatsPercentage.map(o => [
5978
o.difficulty.toLowerCase(),
6079
o.percentage
6180
])
6281
);
63-
setBeats(b);
64-
}, [statistics?.userProfileUserQuestionProgressV2]);
82+
};
83+
84+
const all = getAllQuestions();
85+
const accepted = getAcceptedQuestions();
86+
const totalBeats =
87+
statistics?.userProfileUserQuestionProgressV2
88+
.userProfileUserQuestionProgressV2.totalQuestionBeatsPercentage ?? 0;
89+
const difficultyBeats = getBeats();
6590

66-
const getSections = () => {
91+
const getProgressSections = () => {
6792
if (!all || !accepted) {
6893
return [];
6994
}
@@ -81,31 +106,82 @@ const Statistics: React.FC<{
81106
const getTotalCount = () => all?.get('all') || 0;
82107

83108
return (
84-
<Paper
85-
shadow="md"
86-
radius="md"
87-
withBorder
88-
p="sm"
89-
bg="var(--mantine-color-body)"
90-
>
109+
<Paper {...paperProps}>
91110
<Group>
92111
<RingProgress
93112
size={120}
94113
thickness={8}
95114
roundCaps
96-
sections={getSections()}
115+
sections={
116+
isHovering && difficultySections
117+
? difficultySections
118+
: getProgressSections()
119+
}
97120
label={
98121
<Center>
99-
<Text fw={500} fz="md">
100-
{getTotalAc()}
101-
</Text>
102-
<Text fz="sm">/{getTotalCount()}</Text>
122+
<Stack gap={0} align="center">
123+
{isHovering ? (
124+
<>
125+
<Text fz="xs">Beats</Text>
126+
<Group gap={0}>
127+
<Text fw="bolder" fz="lg">
128+
{Math.floor(beats ?? totalBeats)}
129+
</Text>
130+
<Text fz="sm">
131+
.{(beats ?? totalBeats).toFixed(2).split('.')[1]}%
132+
</Text>
133+
</Group>
134+
</>
135+
) : (
136+
<>
137+
<Group gap={0}>
138+
<Text fw="bolder" fz="lg">
139+
{getTotalAc()}
140+
</Text>
141+
<Text fz="sm">/{getTotalCount()}</Text>
142+
</Group>
143+
<Group gap={0}>
144+
<IconCheck
145+
size={12}
146+
stroke={1.5}
147+
color={StatusColors['SOLVED']}
148+
/>
149+
<Text fz="xs">Solved</Text>
150+
</Group>
151+
</>
152+
)}
153+
</Stack>
103154
</Center>
104155
}
156+
onMouseOver={() => setIsHovering(true)}
157+
onMouseLeave={() => setIsHovering(false)}
105158
/>
106-
<Stack>
159+
<Stack gap="xs" w="5em">
107160
{Object.entries(DifficultyColors).map(([d, c]) => (
108-
<DifficultyStatistics key={d} text={d} color={c} />
161+
<DifficultyStatistics
162+
key={d}
163+
text={d}
164+
color={c}
165+
solved={accepted?.get(d) ?? 0}
166+
total={all?.get(d) ?? 0}
167+
onHover={() => {
168+
setIsHovering(true);
169+
setBeats(difficultyBeats?.get(d) ?? 0);
170+
setDifficultySections([
171+
{
172+
value: Math.round(
173+
((accepted?.get(d) ?? 0) / (all?.get(d) ?? 0)) * 100
174+
),
175+
color: c
176+
}
177+
]);
178+
}}
179+
onLeave={() => {
180+
setIsHovering(false);
181+
setBeats(null);
182+
setDifficultySections(null);
183+
}}
184+
/>
109185
))}
110186
</Stack>
111187
</Group>

src/widget.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
MantineThemeOverride
99
} from '@mantine/core';
1010
import JupyterMainArea from './components/JupyterMainArea';
11-
import LeetCodeNotebookToolbar from './components/LeetCodeNotebookToolbar';
11+
import NotebookToolbar from './components/NotebookToolbar';
1212

1313
export class JupyterMainWidget extends ReactWidget {
1414
docManager: IDocumentManager;
@@ -46,7 +46,7 @@ export class LeetCodeToolbarWidget extends ReactWidget {
4646
render(): JSX.Element {
4747
return (
4848
<StrictMode>
49-
<LeetCodeNotebookToolbar notebook={this.notebook} />
49+
<NotebookToolbar notebook={this.notebook} />
5050
</StrictMode>
5151
);
5252
}

0 commit comments

Comments
 (0)