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
66const gameList = rawGames as { [ key : string ] : string } ;
77
@@ -10,141 +10,132 @@ const INTERNAL_ICONS_LINK = "https://cdn.discordapp.com/app-icons/";
1010const EXTERNAL_ASSETS_LINK = "https://media.discordapp.net/external/" ;
1111
1212const 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
2525const 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