Skip to content

Commit 8fb0004

Browse files
committed
Update Octokit dependency and improve GitHub feed fetch
Replaces `@octokit/core` with `@octokit/rest` for improved GitHub API interaction. Refactors the `fetchGitHubActivity` function to utilize the more specific `rest.activity.listPublicEventsForUser` method. Introduces explicit type casting for payload properties to enhance type safety. Implements a `per_page` parameter for the API call to fetch a controlled number of events. Adds a `fetchGitHubActivity` function for better code organization and readability. Adjusts the `event` loop to handle potential nullish values for `created_at` and `id`. Enhances the hover effect on GitHub feed items with `scale` and `duration` for a smoother visual experience. Adds a check for `repo` existence in the GitHub feed loop to prevent potential errors.
1 parent 3682d3f commit 8fb0004

3 files changed

Lines changed: 322 additions & 324 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"@formkit/auto-animate": "^0.8.2",
2020
"@iconify-json/fa6-brands": "^1.2.5",
2121
"@iconify-json/mdi": "^1.2.2",
22-
"@octokit/core": "^7.0.6",
22+
"@octokit/rest": "^22.0.1",
2323
"@types/react": "^18.3.3",
2424
"@types/react-dom": "^18.3.0",
2525
"@types/whois-json": "^2.0.4",

src/components/DiscordStatus.tsx

Lines changed: 126 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { useState, useEffect, useMemo } from 'react';
2-
import { useLanyard } from 'use-lanyard';
3-
import { useAutoAnimate } from '@formkit/auto-animate/react';
4-
import rawGames from '../assets/gameList.json';
1+
import { useState, useEffect, useMemo } from "react";
2+
import { useLanyard } from "use-lanyard";
3+
import { useAutoAnimate } from "@formkit/auto-animate/react";
4+
import rawGames from "../assets/gameList.json";
55

66
const gameList = rawGames as { [key: string]: string };
77

@@ -10,141 +10,132 @@ const INTERNAL_ICONS_LINK = "https://cdn.discordapp.com/app-icons/";
1010
const EXTERNAL_ASSETS_LINK = "https://media.discordapp.net/external/";
1111

1212
const formatTime = (milliseconds: number) => {
13-
const totalSeconds = Math.floor(milliseconds / 1000);
14-
const hours = Math.floor(totalSeconds / 3600);
15-
const minutes = Math.floor((totalSeconds % 3600) / 60);
16-
const seconds = totalSeconds % 60;
13+
const totalSeconds = Math.floor(milliseconds / 1000);
14+
const hours = Math.floor(totalSeconds / 3600);
15+
const minutes = Math.floor((totalSeconds % 3600) / 60);
16+
const seconds = totalSeconds % 60;
1717

18-
const paddedMinutes = minutes < 10 ? `0${minutes}` : minutes;
19-
const paddedSeconds = seconds < 10 ? `0${seconds}` : seconds;
18+
const paddedMinutes = minutes < 10 ? `0${minutes}` : minutes;
19+
const paddedSeconds = seconds < 10 ? `0${seconds}` : seconds;
2020

21-
if (hours > 0) return `${hours}:${paddedMinutes}:${paddedSeconds}`;
22-
return `${paddedMinutes}:${paddedSeconds}`;
21+
if (hours > 0) return `${hours}:${paddedMinutes}:${paddedSeconds}`;
22+
return `${paddedMinutes}:${paddedSeconds}`;
2323
};
2424

2525
const LanyardStatus = () => {
26-
const [parent] = useAutoAnimate();
27-
const [visible, setVisible] = useState(false);
28-
const [currentTime, setCurrentTime] = useState(new Date().getTime());
29-
30-
const { data: status } = useLanyard("342874998375186432");
31-
32-
useEffect(() => {
33-
const timer = setTimeout(() => setVisible(true), 500);
34-
35-
const interval = setInterval(() => {
36-
setCurrentTime(new Date().getTime());
37-
}, 1000);
38-
39-
return () => {
40-
clearTimeout(timer);
41-
clearInterval(interval);
42-
};
43-
}, []);
44-
45-
const activity = useMemo(() => {
46-
if (!status?.activities || status.activities.length === 0) return null;
47-
return status.activities[status.activities.length - 1];
48-
}, [status]);
49-
50-
const handleExternalLinks = (image: string | undefined) => {
51-
if (!image) return null;
52-
return image.startsWith("mp:external/")
53-
? `${EXTERNAL_ASSETS_LINK}${image.replace("mp:external/", "")}`
54-
: `${INTERNAL_ASSETS_LINK}${activity?.application_id}/${image}.png`;
55-
};
56-
57-
const largeImage = useMemo(() => {
58-
if (!activity) return null;
59-
return gameList[activity.application_id || ""]
60-
? `${INTERNAL_ICONS_LINK}${activity.application_id}/${gameList[activity.application_id as keyof typeof gameList]}.png`
61-
: handleExternalLinks(activity.assets?.large_image);
62-
}, [activity]);
63-
64-
const smallImage = useMemo(() => {
65-
return handleExternalLinks(activity?.assets?.small_image);
66-
}, [activity]);
67-
68-
if (!status || !visible || !activity) return <div ref={parent} />;
69-
70-
return (
71-
<div ref={parent}>
72-
{status.spotify && status.spotify.timestamps?.end ? (
73-
<div className="m-2 rounded-lg bg-viola-100 p-8 shadow-lg">
74-
<h2 className="mb-2 text-2xl font-bold">Status</h2>
75-
<h3 className="text-md mb-2 font-bold">Listening to Spotify</h3>
76-
77-
<div className="flex items-center space-x-4">
78-
<img src={status.spotify.album_art_url as string} alt="Album Art" className="h-16 w-16 rounded" />
79-
<div>
80-
<h4 className="w-32 truncate text-sm md:w-48 lg:w-32 xl:w-32 2xl:w-48" title={status.spotify.song}>
81-
{status.spotify.song}
82-
</h4>
83-
<p className="w-32 truncate text-xs md:w-48 lg:w-32 xl:w-32 2xl:w-48" title={status.spotify.artist as string}>
84-
by {status.spotify.artist}
85-
</p>
86-
<p className="w-32 truncate text-xs md:w-48 lg:w-32 xl:w-32 2xl:w-48" title={status.spotify.album as string}>
87-
on {status.spotify.album}
88-
</p>
89-
</div>
90-
</div>
91-
92-
<div className="mt-2 flex items-center">
93-
<span className="relative inline-block text-left tabular-nums">
94-
<span aria-hidden="true" className="invisible block">00:00</span>
95-
<span className="absolute inset-0">
96-
{formatTime(Math.min(currentTime - status.spotify.timestamps.start, status.spotify.timestamps.end - status.spotify.timestamps.start))}
97-
</span>
98-
</span>
99-
100-
<div className="mx-1 h-3 flex-1 overflow-hidden rounded-xl bg-slate-300">
101-
<div
102-
className="h-full rounded-xl bg-viola-400"
103-
style={{
104-
width: `${((currentTime - status.spotify.timestamps.start) / (status.spotify.timestamps.end - status.spotify.timestamps.start)) * 100}%`
105-
}}
106-
></div>
107-
</div>
108-
109-
<span className="relative inline-block text-right tabular-nums">
110-
<span aria-hidden="true" className="invisible block">00:00</span>
111-
<span className="absolute inset-0">
112-
{formatTime(status.spotify.timestamps.end - status.spotify.timestamps.start)}
113-
</span>
114-
</span>
115-
</div>
116-
</div>
117-
) : (
118-
// General Activity Layout
119-
<div className="m-2 rounded-lg bg-viola-100 p-8 shadow-lg">
120-
<h2 className="mb-4 text-2xl font-bold">Status</h2>
121-
<div className="flex items-center space-x-4">
122-
<div className="relative flex-shrink-0">
123-
{largeImage && (
124-
<img src={largeImage} alt="Large Activity Icon" className="h-16 w-16 rounded" />
125-
)}
126-
{!largeImage && !smallImage && activity.emoji?.name && (
127-
<span className="text-3xl">{activity.emoji.name}</span>
128-
)}
129-
{smallImage && !largeImage && (
130-
<img src={smallImage} alt="Activity Icon" className="h-16 w-16 rounded" />
131-
)}
132-
{smallImage && largeImage && (
133-
<img src={smallImage} alt="Small Activity Icon" className="ring-3 absolute bottom-0 right-0 h-6 w-6 rounded" />
134-
)}
135-
</div>
136-
137-
<div>
138-
<h3 className="text-sm font-bold">{activity.name}</h3>
139-
<p className="text-xs">{activity.state}</p>
140-
<p className="text-xs">{activity.details}</p>
141-
<p className="text-xs">{formatTime(currentTime - activity.created_at)} elapsed</p>
142-
</div>
143-
</div>
144-
</div>
145-
)}
146-
</div>
147-
);
26+
const [parent] = useAutoAnimate();
27+
const [visible, setVisible] = useState(false);
28+
const [currentTime, setCurrentTime] = useState(new Date().getTime());
29+
30+
const { data: status } = useLanyard("342874998375186432");
31+
32+
useEffect(() => {
33+
const timer = setTimeout(() => setVisible(true), 500);
34+
35+
const interval = setInterval(() => {
36+
setCurrentTime(new Date().getTime());
37+
}, 1000);
38+
39+
return () => {
40+
clearTimeout(timer);
41+
clearInterval(interval);
42+
};
43+
}, []);
44+
45+
const activity = useMemo(() => {
46+
if (!status?.activities || status.activities.length === 0) return null;
47+
return status.activities[status.activities.length - 1];
48+
}, [status]);
49+
50+
const handleExternalLinks = (image: string | undefined) => {
51+
if (!image) return null;
52+
return image.startsWith("mp:external/") ? `${EXTERNAL_ASSETS_LINK}${image.replace("mp:external/", "")}` : `${INTERNAL_ASSETS_LINK}${activity?.application_id}/${image}.png`;
53+
};
54+
55+
const largeImage = useMemo(() => {
56+
if (!activity) return null;
57+
return gameList[activity.application_id || ""]
58+
? `${INTERNAL_ICONS_LINK}${activity.application_id}/${gameList[activity.application_id as keyof typeof gameList]}.png`
59+
: handleExternalLinks(activity.assets?.large_image);
60+
}, [activity]);
61+
62+
const smallImage = useMemo(() => {
63+
return handleExternalLinks(activity?.assets?.small_image);
64+
}, [activity]);
65+
66+
if (!status || !visible || !activity) return <div ref={parent} />;
67+
68+
return (
69+
<div ref={parent}>
70+
{status.spotify && status.spotify.timestamps?.end ? (
71+
<div className="m-2 rounded-lg bg-viola-100 p-8 shadow-lg">
72+
<h2 className="mb-2 text-2xl font-bold">Status</h2>
73+
<h3 className="text-md mb-2 font-bold">Listening to Spotify</h3>
74+
75+
<div className="flex items-center space-x-4">
76+
<img src={status.spotify.album_art_url as string} alt="Album Art" className="h-16 w-16 rounded" />
77+
<div>
78+
<h4 className="w-32 truncate text-sm md:w-48 lg:w-32 xl:w-32 2xl:w-48" title={status.spotify.song}>
79+
{status.spotify.song}
80+
</h4>
81+
<p className="w-32 truncate text-xs md:w-48 lg:w-32 xl:w-32 2xl:w-48" title={status.spotify.artist as string}>
82+
by {status.spotify.artist}
83+
</p>
84+
<p className="w-32 truncate text-xs md:w-48 lg:w-32 xl:w-32 2xl:w-48" title={status.spotify.album as string}>
85+
on {status.spotify.album}
86+
</p>
87+
</div>
88+
</div>
89+
90+
<div className="mt-2 flex items-center">
91+
<span className="relative inline-block text-left tabular-nums">
92+
<span aria-hidden="true" className="invisible block">
93+
00:00
94+
</span>
95+
<span className="absolute inset-0">
96+
{formatTime(Math.min(currentTime - status.spotify.timestamps.start, status.spotify.timestamps.end - status.spotify.timestamps.start))}
97+
</span>
98+
</span>
99+
100+
<div className="mx-1 h-3 flex-1 overflow-hidden rounded-xl bg-slate-300">
101+
<div
102+
className="h-full rounded-xl bg-viola-400"
103+
style={{
104+
width: `${((currentTime - status.spotify.timestamps.start) / (status.spotify.timestamps.end - status.spotify.timestamps.start)) * 100}%`
105+
}}
106+
></div>
107+
</div>
108+
109+
<span className="relative inline-block text-right tabular-nums">
110+
<span aria-hidden="true" className="invisible block">
111+
00:00
112+
</span>
113+
<span className="absolute inset-0">{formatTime(status.spotify.timestamps.end - status.spotify.timestamps.start)}</span>
114+
</span>
115+
</div>
116+
</div>
117+
) : (
118+
<div className="m-2 rounded-lg bg-viola-100 p-8 shadow-lg">
119+
<h2 className="mb-4 text-2xl font-bold">Status</h2>
120+
<div className="flex items-center space-x-4">
121+
<div className="relative flex-shrink-0">
122+
{largeImage && <img src={largeImage} alt="Large Activity Icon" className="h-16 w-16 rounded" />}
123+
{!largeImage && !smallImage && activity.emoji?.name && <span className="text-3xl">{activity.emoji.name}</span>}
124+
{smallImage && !largeImage && <img src={smallImage} alt="Activity Icon" className="h-16 w-16 rounded" />}
125+
{smallImage && largeImage && <img src={smallImage} alt="Small Activity Icon" className="ring-3 absolute bottom-0 right-0 h-6 w-6 rounded" />}
126+
</div>
127+
128+
<div>
129+
<h3 className="text-sm font-bold">{activity.name}</h3>
130+
<p className="text-xs">{activity.state}</p>
131+
<p className="text-xs">{activity.details}</p>
132+
<p className="text-xs">{formatTime(currentTime - activity.created_at)} elapsed</p>
133+
</div>
134+
</div>
135+
</div>
136+
)}
137+
</div>
138+
);
148139
};
149140

150-
export default LanyardStatus;
141+
export default LanyardStatus;

0 commit comments

Comments
 (0)