Skip to content

Commit d3c6f8f

Browse files
committed
add submission calendar
1 parent 35558ba commit d3c6f8f

File tree

11 files changed

+316
-114
lines changed

11 files changed

+316
-114
lines changed

jupyterlab_leetcode/handlers/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from .leetcode_handler import (CreateNotebookHandler, LeetCodeProfileHandler,
66
LeetCodeQuestionHandler,
77
LeetCodeStatisticsHandler,
8+
LeetCodeSubmissionCalendarHandlar,
89
LeetCodeWebSocketSubmitHandler,
910
SubmitNotebookHandler)
1011

@@ -20,6 +21,7 @@ def setup_handlers(web_app):
2021
CreateNotebookHandler,
2122
SubmitNotebookHandler,
2223
LeetCodeWebSocketSubmitHandler,
24+
LeetCodeSubmissionCalendarHandlar,
2325
]
2426

2527
web_app.add_handlers(

jupyterlab_leetcode/handlers/leetcode_handler.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,41 @@ async def get(self):
189189
self.finish(res)
190190

191191

192+
class LeetCodeSubmissionCalendarHandlar(LeetCodeHandler):
193+
route = r"leetcode/submission"
194+
195+
@tornado.web.authenticated
196+
async def get(self):
197+
username = self.get_query_argument("username", "", strip=True)
198+
if not username:
199+
self.set_status(400)
200+
self.finish(json.dumps({"message": "Username parameter is required"}))
201+
return
202+
await self.graphql(
203+
name="submission_calendar",
204+
query={
205+
"query": """query userProfileCalendar($username: String!, $year: Int) {
206+
matchedUser(username: $username) {
207+
userCalendar(year: $year) {
208+
activeYears
209+
streak
210+
totalActiveDays
211+
dccBadges {
212+
timestamp
213+
badge {
214+
name
215+
icon
216+
}
217+
}
218+
submissionCalendar
219+
}
220+
}
221+
}""",
222+
"variables": {"username": username},
223+
},
224+
)
225+
226+
192227
class LeetCodeQuestionHandler(LeetCodeHandler):
193228
route = r"leetcode/questions"
194229

src/components/Actions.tsx

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
Anchor,
3+
Center,
34
Paper,
45
PaperProps,
56
Stack,
@@ -43,23 +44,25 @@ const Actions: React.FC<{
4344
paperProps: PaperProps;
4445
}> = ({ paperProps }) => {
4546
return (
46-
<Paper {...paperProps}>
47-
<Stack gap="xs">
48-
{...Data.map(item => (
49-
<Tooltip label={item.label} key={item.label}>
50-
<Anchor
51-
size="xs"
52-
target="_blank"
53-
underline="never"
54-
href={item.href}
55-
>
56-
<ThemeIcon size="sm" variant="white">
57-
{item.icon}
58-
</ThemeIcon>
59-
</Anchor>
60-
</Tooltip>
61-
))}
62-
</Stack>
47+
<Paper {...paperProps} style={{ alignContent: 'center' }}>
48+
<Center>
49+
<Stack gap="xs">
50+
{Data.map(item => (
51+
<Tooltip label={item.label} key={item.label}>
52+
<Anchor
53+
size="xs"
54+
target="_blank"
55+
underline="never"
56+
href={item.href}
57+
>
58+
<ThemeIcon size="sm" variant="white">
59+
{item.icon}
60+
</ThemeIcon>
61+
</Anchor>
62+
</Tooltip>
63+
))}
64+
</Stack>
65+
</Center>
6366
</Paper>
6467
);
6568
};

src/components/LeetCodeMain.tsx

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Profile from './Profile';
88
import Statistics from './Statistics';
99
import QuestionTable from './QuestionTable';
1010
import Actions from './Actions';
11+
import SubmissionCalendar from './SubmissionCalendar';
1112

1213
const MainHeaderPaperProps: PaperProps = {
1314
shadow: 'md',
@@ -55,13 +56,20 @@ const LeetCodeMain: React.FC<{ docManager: IDocumentManager }> = ({
5556
return (
5657
<Container fluid={true} h="100%" p="lg" id="jll-main">
5758
<Stack>
58-
<Group id="jll-profile" align="stretch">
59-
<Profile paperProps={MainHeaderPaperProps} profile={profile} />
59+
<Group id="jll-profile" wrap="nowrap" align="stretch">
60+
<Profile
61+
paperProps={{ ...MainHeaderPaperProps, w: '15%' }}
62+
profile={profile}
63+
/>
6064
<Statistics
61-
paperProps={MainHeaderPaperProps}
65+
paperProps={{ ...MainHeaderPaperProps, w: '30%' }}
66+
username={profile?.username}
67+
/>
68+
<SubmissionCalendar
69+
paperProps={{ ...MainHeaderPaperProps, w: '50%' }}
6270
username={profile?.username}
6371
/>
64-
<Actions paperProps={MainHeaderPaperProps} />
72+
<Actions paperProps={{ ...MainHeaderPaperProps, w: '5%' }} />
6573
</Group>
6674
<QuestionTable openNotebook={openNoteBook} height={calcHeight()} />
6775
</Stack>

src/components/NotebookToolbar.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,10 @@ const LeetCodeNotebookToolbar: React.FC<{ notebook: NotebookPanel }> = ({
7979
};
8080

8181
const getResultCell = () => {
82-
let resultCellModel: ICellModel | null = null;
8382
const cells = notebook.content.model?.cells ?? [];
84-
for (const cell of cells) {
85-
if (cell.metadata['id'] === 'result') {
86-
resultCellModel = cell;
87-
}
88-
}
83+
let resultCellModel = Array.from(cells).find(
84+
c => c.metadata['id'] === 'result'
85+
);
8986
if (!resultCellModel) {
9087
const activeCellIdx = cells.length ? cells.length - 1 : 0;
9188
notebook.content.activeCellIndex = activeCellIdx;

src/components/Profile.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,10 @@ const Profile: React.FC<{
77
paperProps: PaperProps;
88
}> = ({ profile, paperProps }) => {
99
return (
10-
<Paper
11-
miw="20%"
12-
maw="40%"
13-
{...paperProps}
14-
style={{ alignContent: 'center' }}
15-
>
10+
<Paper {...paperProps} style={{ alignContent: 'center' }}>
1611
<Center>
1712
<Stack gap={0}>
18-
<Avatar src={profile?.avatar} size="md" radius="xl" mx="auto" />
13+
<Avatar src={profile?.avatar} size="lg" radius="xl" mx="auto" />
1914
<Text ta="center" fz="md" fw={500} mt="xs">
2015
{profile?.realName}
2116
</Text>

src/components/Statistics.tsx

Lines changed: 82 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -106,85 +106,88 @@ const Statistics: React.FC<{
106106
const getTotalCount = () => all?.get('all') || 0;
107107

108108
return (
109-
<Paper {...paperProps}>
110-
<Group>
111-
<RingProgress
112-
size={120}
113-
thickness={8}
114-
roundCaps
115-
sections={
116-
isHovering && difficultySections
117-
? difficultySections
118-
: getProgressSections()
119-
}
120-
label={
121-
<Center>
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>
154-
</Center>
155-
}
156-
onMouseOver={() => setIsHovering(true)}
157-
onMouseLeave={() => setIsHovering(false)}
158-
/>
159-
<Stack gap="xs" w="5em">
160-
{Object.entries(DifficultyColors).map(([d, 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-
/>
185-
))}
186-
</Stack>
187-
</Group>
109+
<Paper {...paperProps} style={{ alignContent: 'center' }}>
110+
<Center>
111+
<Group>
112+
<RingProgress
113+
size={120}
114+
thickness={8}
115+
roundCaps
116+
transitionDuration={250}
117+
sections={
118+
isHovering && difficultySections
119+
? difficultySections
120+
: getProgressSections()
121+
}
122+
label={
123+
<Center>
124+
<Stack gap={0} align="center">
125+
{isHovering ? (
126+
<>
127+
<Text fz="xs">Beats</Text>
128+
<Group gap={0}>
129+
<Text fw="bolder" fz="lg">
130+
{Math.floor(beats ?? totalBeats)}
131+
</Text>
132+
<Text fz="sm">
133+
.{(beats ?? totalBeats).toFixed(2).split('.')[1]}%
134+
</Text>
135+
</Group>
136+
</>
137+
) : (
138+
<>
139+
<Group gap={0}>
140+
<Text fw="bolder" fz="lg">
141+
{getTotalAc()}
142+
</Text>
143+
<Text fz="xs">/{getTotalCount()}</Text>
144+
</Group>
145+
<Group gap={0}>
146+
<IconCheck
147+
size={12}
148+
stroke={1.5}
149+
color={StatusColors['SOLVED']}
150+
/>
151+
<Text fz="xs">Solved</Text>
152+
</Group>
153+
</>
154+
)}
155+
</Stack>
156+
</Center>
157+
}
158+
onMouseOver={() => setIsHovering(true)}
159+
onMouseLeave={() => setIsHovering(false)}
160+
/>
161+
<Stack gap="xs" w="5em">
162+
{Object.entries(DifficultyColors).map(([d, c]) => (
163+
<DifficultyStatistics
164+
key={d}
165+
text={d}
166+
color={c}
167+
solved={accepted?.get(d) ?? 0}
168+
total={all?.get(d) ?? 0}
169+
onHover={() => {
170+
setIsHovering(true);
171+
setBeats(difficultyBeats?.get(d) ?? 0);
172+
setDifficultySections([
173+
{
174+
value: Math.round(
175+
((accepted?.get(d) ?? 0) / (all?.get(d) ?? 0)) * 100
176+
),
177+
color: c
178+
}
179+
]);
180+
}}
181+
onLeave={() => {
182+
setIsHovering(false);
183+
setBeats(null);
184+
setDifficultySections(null);
185+
}}
186+
/>
187+
))}
188+
</Stack>
189+
</Group>
190+
</Center>
188191
</Paper>
189192
);
190193
};

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy