$M4tr@SM@HGD#&Eqwhhm@_$PxzCgi0XordI@gxv?JZY_ZvVNY^dSqE7Sv0$z9c
zoB-R3yRJ1Lg8nq1sZb=!sR?Dm=d-Uks1Z~T;sd-WsIIfdZgZcqRz861jJy$Q(U0cf
zPJEWf*Akiob%he3R!}^|2ZDoOn?O9nQUff
z>l@}FMq}P)b7UuB-yK*!cH_tVn^1S?26PRo0!_d^er*#Cdk*$26k}E+_M4mAd6UCW
z%Z%9pn~5%e0!=}BG86~a5^4l-UFH+Ih0q10`QVEW#Q30$<@3QBpSbZ!+#HB`XTVN}
z-pV!`KA-5#gz(URBW!{uU0-b*HzcH
z8>Lj}b8|7(dAreB-=kh_Hv)ryuIm0R&tHC~PAht65AoHjx{AX+fvUN~2(05*P1h=5
zrM)&d@%PCS8zlc75RE7c+tifpr2t+`{gNWnR_imW*cfbs_
z9s&Atb&PR45LW_mXGbn=*?C|3lfUCmtG5WK`xF6X5%8c*mjP`jKG6OS@U5=%MTd;r
z{m0&Xbz=F|zxRY!SFLv%0eVZ-f2R?t$2srrG@2NC2UTMqs?7hPl*i4-#XFgON0{`U
zwZdveg+*wiRWbtfIcf~eay5USQLWr=%;XSMBfn_M=$wB4qr|r*_M7w@*n>He5vopS
z8-7Mz%nbE-Czj`;*rC=HH-c2({YH>pLfQADDV5d6{YHPip9;=KOY(m_RU%+X
zbw5*1L$o9^EF#Q?>7d#mKwqaC<)GwRILlSLV@9C*Jlm+PyXp%>k-udd5NQeJ!rJj=Q_I_
zG(t@J7WL>d>M#zV(W?#{t=(X;+xV%am%$$#G;He45$tTGS{*g2>2K9XM~$!bo~jhu
zr)R2H=V9Ef)d#2#j-k^d)Kc!7q<&yZse3fvsgUDVk?-r{DD#>+dEAKB
z7pa0d|NAImxLv~&sk?gT=bV;kHrF!S2aZ>N2{7<2WdsWIQBQiMur(aYVRf)rxJD{C
z|3_Y`T%+n&hQtKAnpBGc?lBC`|25c_l$EV^^_a246%Y}IHs`877xKq5P_4UQ)DFu3
z(Ok#e(Uq%}jOu67pWv$MgG0TbyAc$e|4Xw!R`gDobh%81loiFYFo^=)BkAi=D=ZxM
zjjI1eqnc+hu6>0#movuV@Nc?^xm;PD#2z_H&bpV3_WD2ONV|WZHl|wI{Pjk7=?F|k
zE&nHL`M&@|128{rVG;A+8a4GORZ};9*K0XTnhY
z=x6#eUWHvX0!rrp+HKVI^qs|j|8pjqf^KtMH^-~qSB;F|hbYqvbqz>c^Y+go-w*WF
zd)9WJPJgP`SB*g5{2$Vdox8VNfjwoHnDnR?s_HePqnGC`T;{P&y{)ERGh*?j7B}bN
zYet6dwUu89Vatnjw*S!>kETvJmuEQ7AAj2j
zRpH(qHnqglW0f<*>aotG<^*^Yc7EvXF*`t6i(7)#sp1|U>ig;zFLS-HDD|kSB}A3>
o^(btv9TusI_OgVkwuL;3Vw^*2x%~pFO*Ko19Pb8f%)%uZ(Z_v=CXPY2D5
ztWk1qlh>ba@(v14Nr(*ks`j;au5Vi&v7+S1qk8(TZ(8wg>#u8iX*?Fq?_R;OedhXc
zZw9;kLV|oo49^)gASXw2RSyY&o=6F)uE)7XhExlViqf?RP0LNMt7`$!e@5$CN$4rA
z^&w@Q<6?BJI8wJkOF&G#FVK
zBQz}^j)8F44b28@g!YHFEYr-4W2K@Y(CpFECY}QOCh3|T=`?8eumyA}=;}>9=%{`9UnK{FUj>*&vr0I~InK58gogq07n|Ufc49$_+
z2ps~wOww&JYOMHSOHai=Ll;B3GB`CFV|L6h*;CKh8~_|SL$b%Xu9OR?*e%6V;qVce
z!!olqZ8sd*gRh}k@VaDINLYE_kC0@$<|l7x7B($7{O7D)OMCp3`u(bdKM1h8D
zWkZL(RSjK>L(1yPXyLHGh7`|vy9yH>{$C;GK*|TrHXzkp{tc_K5X&z$R8MccvAujv
zUF!o6%@r}rVXISH*Xp}^cS^8l(gL@-R;D>D%WJEiUhqB%+7A>pH+I-l>Ue6ly9yH=
z_6bNO;hc}F5a+)A=Q-P5r0TiC5)MV;hdxG~v+GUly8z<>{n!QD??|Q3sIQ=g6&dWHBwv2b^)l_gXy@?*H(xGg#u@4)%dbdol?S)m}6_%P{dj>1U
zRp3rk>BW)#l~`SChU~g40uB2dsTO96!*vg-c1T%V5qS>1kxDOt471{p->ffUqeI`K
z&Jl)UqjEst+00=}L#msrU~ZxTql2rUaf02qo~LKJE2ERc-V-V8OH^9e&!K;-(o3Pu
znpy&7?}WXaVxG%r>9D_zR8OP~S46tQR=d8grLpsNCoHzY*H!3p=nc%PuMyj2wpmTyv$Cghq`_>y4R~0J4pe^}3#hE^Z6xW~UoW1csQW(%B0hpwD
zfEXoQWU%+$&*^?eXSx|s45Yxkx>gTX5YpHsMVprK(d77@7v(Xl*#_+)&YvZuYXr)5R>5XkW
zLAfas^!9faPSeIuC6RLJ*3AyM<$D?}wCZTTIQ{NXgW+bXX3isPkdS5z^X2G2M$D
z_6|sK+-&9=T8I?K6r~~mNu=0EFY{c;e`=OH
zLDJMbKT*=qP6l;th5%|@eY6G8xL#`?KpW7j<@`T23tl6fnhp9)^cT>~w*i`d8%1xD
z^Ldi~+6R{`I&Km09W>KBp!o%5pXkGK{s=S=Y8HG{^f71~(x>G-H7>W>Ptfe~4QTq`
zl=IZA=XMJixc+K?L9+lI-S>v}fyUKJ3xK9$5Ht%4f#&hQw94wCmo;ZHOx!An8#U_<
zhvtCB$oV+Y^`P<5n&1!pl9>1pP2Lnd0JKWO$R6PoQG
z0?h#(4$c0Jf#&f~&5Fi?Q;&nj7bI;eG%K7A%?f8i^Z38I$-kZO6gW#V{;PKTH_~1I
z-4CAW`tN@Df4?85pG()>=h7{=$|jw@l6>&)#O?`S-<}?m^>Eyr@|_B*Wmed9`a<@r
z>wSyg&uj7Ea!Hlg=Zhz28r6!)e!TMHSJzv8|I0D$qeC@s?zieY9!41{F9Xq5#_hHi?P4GXkdHlf%
zm)^FVh*-Nnf5hT?GvfV+9}6D4Vol`r+1-E0|7&3D`s2eZsVzB{AXR4+DvDRHjzUG_
zMxmkt0*9(G8ld`UfJ51qw(i`~mP0}6^SPF`>g_pzwt4WHtWxK}D`hUgCW5I-pAYbu
zAag#zbhVyf^*n&U1pqTt#sYvI^8t1f%u@a?0G|Z_qg?>A)pmkBf+`CE=Bkkk0S3DO
zP7%yk5sLtV76MFN1mIG~2=)QE;}=`fl5l@usP|4=qVzCz?6jq{HLSL-jx4d%F;C3P
zx3p8apIAD%-#cTuYp6^479ZNV}u
z78iqi5>_3oKN!dQF&I};4ahUt9P20IR};2f@;((-
z3+y3U#j&P8K3Z+abubRKZpAkd=BWcYAcJNAuqTm_6JQ)ro3OgD58)&S)Jqt?yKBdU
zc?*jMJ1)#e7;Xi%j*xH&8;a9fEWZhr<)X*oD-d7!wP0bz!0_SCwH6|*r1;eXD=(~+
zF#NATJ0wHxCk(d}+F@b-!Ww`b0W-gey&w=b0NPP;EG;Yn?3l0sVYoHWP6`VYh8rvG
zl&~_wa1*4R7FJdmzj~b!7Gy>J9EK#wS%Jag*c9xXun=L*z|IQ`71kW=g0OPJT7cyX
z3lr87tUy?KVXfHzivlYMOon5juyA21VAq622x|>?Ls&&&xHHxs3#%loEm(1xrpm(F
zft4WR_*W6w9(GA_tSYPnSSexEz_^0Bi2Q`r5QhKAX#T=#2}=blEv$}|*BNXrw?B?Z
zF!N3z4T&!V))mJtVDE!fhK>@}74{Du>ka#vY~x&EeZbgA9+SY>
z{=Sfg=Ez|DrvkF#evr<9+i&>ynd7%4?*OphWvJ(f-%DUuz_?E4
z3d@AO5sd3(9vSCReFMP8jEDFL+hS(M
zw1L@$eJAX7us~s3g-rx2BWxQOKIYah>lC;Xgq7q%f`sjs%#*-EgzXW(H^4%L?GrW`
ztemg|U|ge9AYsCeir-YQ3c{Sn0XbaLAmIW}2%8QTA?&2EH^C|jJ0%6q0IMYIjQGt2
zt1RrS_{{>VBJ8|}IkmR{s|w7Q%(KC&2`dmb2duiVi^ArD)e!cBuz6rLg|?MN!Ysm8gYkmG!zyeIY+O+IEJQQF*uYO9yq=JGiQlKNdF|lgZD9WC
z_!)#34?5Z<^XIS=5DEK27Xw4XwY88QVEv#=N`YU%UW5krhb|>-9qiY@7;_5Z4Y21j2aaH28)2V@%@7*`%|>s6+=tB&TTcAGf_(}$qiLA<
zxnXCZVn)*n;+F@zKbVs+T;SKRSs=q{gs{!9ry!CrN>&v14eVFICPG&NV`ILB^aEpu
zs(^8{wm`arO@git#w+u8kW{cYprZ`96K;j108WOkFO_VA-Bwrwsbo7?dtnK}c7Syd
z)=2X11ZxF01-da98?y@%55@r2RQz_cxsia3R?P(Nfz2n*j8@IT*t@-uATS1(mSFg3
z`yc^e3@)t!Sjm1!8DZ_fxTp_6N`W!pv={b0Y(Fv%R|m;_5O#4u2BB0ie6&N5`~pZWgGNJhnl3_)!*+B2$H8F5
zKR}Mc=GJ&k*d^GT&=~H53Bn3t_s2AG7fb}>@Lz_!B+LoMN`8dUk2~WH@w*~^WRvN~
z`M(OuML4FW6L;S9TT@p4^*bT7D!e$A(3HGC~w}kx+=48d(
zld}chg3XG_=76!{Um&cQY@YbthRuq}IOH6KI}lb(wm{fj*sPe$CF~w-PWx8Q|3W}k
z@+;&R>}}ACh5ZJb^F;Qxu=}u2AoF%;egS304jPE$oI~CG1bwZ1f)J4~6{&n~f&>SlAQTKf`7m
zSp&^RKZV@lVj=uQ;4?zl3@)DvqxT)y3@)ERbF_3YE>;GYwc=+1V?SR9Oti|iX=CBV42$i5X;5{!$BY>Ti`U|d{`e&2zyF@9hNz!?3u
z3G)a0p5On>kSLj706Zv;JB5`7J0xtEumG^b!gdP_1Un*ZkFYXe92rK~y?Hdq+f3H`z(
zF9Q=7D4DaoWWIvLNr4q4Ga0{h&@o&xUxj^ESOgeX|244l!YYEXa58p?c`JdPL8BSK
z*demYV5j;0&x~LKs{nGi%m^l|D%cU&j9^!URRiNFFoInZRvnCuVF0@>tOghxLv~YG
zO)xfwLG4!2_rF?zXpP3Gc3T|rri|H`J79N(;Vl@mF^p=z3d74TW>8@OyAOt>hButd
zN*Jsjh#%g8G3#KkdL%5G|9{~SGcx@y5HG)&1v0qst`u_)tn1UIsCziSfZ-7+wi68_oDoS{PpbFe_#(2o%X%xz)w
z>cstANmx5!+@`#phSJ+y%UwChLelTw7eAyqjjDJHh6+A-t4m-Z}IB
zQ%e;`F1*^}*cmn(!};RfFO-%hj6=!0U$QRv!)fAZ@a~tDbcM}|*`XL=-Gs42ywRm!
zcOCOjNA{?mz#ihr9`UZ0j_I)3YW9eCuxxZs*bFf25pPVPv={M*0fwxxuwJm4m!0H|
zDf9M*&3ZfQwamLvvywgn*-PGVvf{q5nVCImrAB^&2PUnhj0`!2PH63f^%urIbQCrK
zHrvTQbOwXcUcw)?lPpbGCTuPV_N$Aqfv}mEedy|8PHhkp%uLu#90$W@JK3@BVC>`&
zVeD5=VK2jGf$Udr$@>aymPgh{*iiB72i;d#mg$ELL)cH?FmdE)@E#LN8;(CLkgUJ3
z5wKY?M`(bsk>W@8lCW&p90iVArm!4g9F2iafuoRMf$aGpVWVNQVlsa9gVM&}5B)eA
zLxhcmO+T`ig^h#FiaA2B2zyl+M`Nh4p05dH&$9%M7sg%=6E;B@8#-Lr>%!Qm5yJe|
zaI$dm{Z8%q%vx1l|IE6&Bwuae>n_Ex2#Z_P=FhDmPQE$S1CkEu3E`vDUXb39K9IhU
zevk}Ef5-sHOOQ;+K*%7-V8{^2%aB(fLm^oZK5`un837py$%f=WMnOhH@c7kB8w+Ec
zYP!~1$$uJ5zM;jpy7;D7ntSA0>u_CN`rI1eoQQ@yA-RxAkjaoK5I%$8GY39m;BI7y
z;bx16@EXM^z+KM}!GOzG!gyIpge=Ag@$wV}iH5{MGQdVaMnbY7e5DLKPgPiF4Rj{K
zfm@1iBQ=9GhqQpSgtUSrLs~=HK-xjtLpne@LOMgzATAWR5W+{SOCc*D??d>;);Y*|
z$OT9~qySO~xdOTBgBPgy40bmfum>^|_G}fr-kP8%xVx^m#_CSKl*AX6-h|A6@EHqZ
zDMK7%ZUYFfv!l?l90+$OHy(HM`$)eBX$qT{I=*?fAHpY?-$M>U4nc;Z++mPkVgCks
z0C@;`}Tt{E5UZ$cu35r6M+1OGkfzQU>X=>UFmjZ|A}+4k@9wyRCI?ol$sIbMVA^RYFqi+VJ8Jh_C2*UrNEQ9cI_aseq$g@@rybj+VAy*)UkPSF@Le0*z
zhFTJR)Y?32Lv<_9n&gi9+PX{Ez1$BrTX%Zr~!e>tn
zAx$AoAPpe(Ar45qJ8-9UK)5{)b~ls}t0w(u4b`L6a;WIWAVVR|A>2ESpc5f{1lJKd
z2D&pe`&EE|k)-bZXl+um9`N5tbH`k<4l|rn(UO^v$vF82q$%>Wg*1UM1Wp6vb0prJ
z@EH@IJ@J_o{{zE^SbVrO8^Q-)%=;!ZAC^6ngAd7OLS{htfU6(>vyNk80cI1Ap4>OA
z5hU(2H>_7rsRfU%WmVU0Myk5I)#wm9p{A}?Lg1Kpsh-=hJIXgeugP3ER;caUj9`6(
zx&T$~IQ*)>uOKV^*0jlq8PEM5)l`1ljiC6DTAtrDygR?^=L53N^?2@47iWTzH~LQW
z!P?uueB=3<6xDmX5ga-|vJUv^)kD7TEgkmUVVs%|2fU*5DO9<2@C!#lcRF?-+-dS1
z?YZC4TIv!S5qb+Aq3}2zn_D=0Tk@3W9^R_-4kOm=v>xY9-eEL1^j2!t9#miSYZb4n
zzn1Q54H#q5`@}@X)Q^nTveZ^O6#Y)*1-*6tefOYMaEOkKjf}-&R=@2rYE}9Y%Pj)c
z$}dfFyN$a2YWlOlofiEB&eXt}K-F|FIufN`+-tPdQ`O47MuP663icYYdZ_Z>XAFw}
z&t~}jJrzYiYzYinUb~FtP-D~|8yOwx;M+8x??VHNehKsP;N-_+FC}c22F764RpCCP
zy>3=t#%O?lQ>xbcjY;}pHUEN9raX!$`V~%M)z#5{&E~B%^G2cb+HH00m{CRr9x%cz
ze@3gg14d1|9p6~7LUPBcK?hLo6!)eBMubIQqdHzRg4NxF#$b=V)T7F%Cj~}`a$YnX
zs@GwogPx>5J#5s{e^qA=8>=u5E|I)wu()?ikMYaD325N|U0(X6^Dti>EnW`<-
za^*Y<_=#G=l-aLfb?vATqPvxT40RnZ{d(VN1?XoKCNU;T`qs4f>?t6r;I{ec$!8ZL!?SPUwv
zgb@;2^xL6FtNXW`a;`$I6oz(qCPg>bQ-Iof!LaFu+I<0YQ&Qc#fQ=BU>g4}DQ|^WN
zMrZvW>nHU;mQ=xIqi*GkxCWI#-9^7ZO5WB-jSsAqjauU{tytI(TdJrZjoflY@78T;
zS#^A`2a#V`^ti}qbAiuKRtJAHVk{peFTP?7thWw#RJf4kX06K@oxbZsj;0(rTcd}Y`#mL2Xps=e(aHMaF=l4@b;{&>+=im1Z(EG%D
z9E*PVG-3Ysp5EKSms|9d6!p?oql@o8PoUOPeo#BE8cA-SYbeim+z)2>*4Ec_FZjur
zWYJ@%2i!E=0XJ=FRaNIfw(v!MHXk+DQy#;qUbsQr_z56T?q$pw{0qD!7doyw+KY
hXes6J_li&xgS@
});
export const nezhaFetcher = (url: string) =>
- fetch(url)
- .then((res) => {
- if (!res.ok) {
- throw new Error(res.statusText);
- }
- return res.json();
- })
- .then((data) => data)
- .catch((err) => {
- console.error(err);
- throw err;
- });
-
\ No newline at end of file
+ fetch(url)
+ .then((res) => {
+ if (!res.ok) {
+ throw new Error(res.statusText);
+ }
+ return res.json();
+ })
+ .then((data) => data)
+ .catch((err) => {
+ console.error(err);
+ throw err;
+ });
From 94aa61f5b7bac301e45cf9bfa91ee3c73d1f4b06 Mon Sep 17 00:00:00 2001
From: hamster1963 <1410514192@qq.com>
Date: Sun, 28 Jul 2024 16:05:00 +0800
Subject: [PATCH 2/3] fix: update now time
---
.../ClientComponents/ServerListClient.tsx | 36 ++--
.../ClientComponents/ServerOverviewClient.tsx | 156 ++++++++++--------
app/(main)/footer.tsx | 40 ++---
app/(main)/header.tsx | 33 +++-
app/(main)/nav.tsx | 57 -------
components/ServerCard.tsx | 10 +-
components/ServerList.tsx | 6 +-
components/ServerOverview.tsx | 11 +-
components/SubscribeCard.tsx | 67 --------
lib/prefetch.tsx | 54 ++++++
package.json | 8 +-
11 files changed, 223 insertions(+), 255 deletions(-)
delete mode 100644 app/(main)/nav.tsx
delete mode 100644 components/SubscribeCard.tsx
create mode 100644 lib/prefetch.tsx
diff --git a/app/(main)/ClientComponents/ServerListClient.tsx b/app/(main)/ClientComponents/ServerListClient.tsx
index 2f0765b..d899f4e 100644
--- a/app/(main)/ClientComponents/ServerListClient.tsx
+++ b/app/(main)/ClientComponents/ServerListClient.tsx
@@ -4,33 +4,31 @@ import { ServerApi } from "@/app/types/nezha-api";
import ServerCard from "@/components/ServerCard";
import { nezhaFetcher } from "@/lib/utils";
import useSWR from "swr";
-import { DateTime } from "luxon";
export default function ServerListClient() {
- const { data } = useSWR('/api/server', nezhaFetcher, {
+ const { data } = useSWR("/api/server", nezhaFetcher, {
refreshInterval: 3000,
});
if (!data) return null;
const sortedResult = data.result.sort((a: any, b: any) => a.id - b.id);
+ const timestamp = Date.now() / 1000;
return (
-
- {sortedResult.map(
- (server: any) => (
- 300 ? "offline" : "online"}
- uptime={server.status.Uptime / 86400}
- mem={(server.status.MemUsed / server.host.MemTotal) * 100}
- stg={(server.status.DiskUsed / server.host.DiskTotal) * 100}
- />
- ),
- )}
+
+ {sortedResult.map((server: any) => (
+ 300 ? "offline" : "online"}
+ uptime={server.status.Uptime / 86400}
+ mem={(server.status.MemUsed / server.host.MemTotal) * 100}
+ stg={(server.status.DiskUsed / server.host.DiskTotal) * 100}
+ />
+ ))}
);
}
diff --git a/app/(main)/ClientComponents/ServerOverviewClient.tsx b/app/(main)/ClientComponents/ServerOverviewClient.tsx
index 8ec1b76..d64c1d5 100644
--- a/app/(main)/ClientComponents/ServerOverviewClient.tsx
+++ b/app/(main)/ClientComponents/ServerOverviewClient.tsx
@@ -9,70 +9,94 @@ import { Loader } from "@/components/loading/Loader";
import { ServerApi } from "@/app/types/nezha-api";
export default function ServerOverviewClient() {
- const { data } = useSWR('/api/server', nezhaFetcher, {
- refreshInterval: 30000
- });
+ const { data } = useSWR("/api/server", nezhaFetcher, {
+ refreshInterval: 30000,
+ });
- return (
-
-
-
-
- Total servers
-
-
-
-
- {data ?
{data?.result.length}
:
}
-
-
-
-
-
-
-
- Online servers
-
-
-
-
-
- {data ?
{data?.live_servers}
:
}
-
-
-
-
-
-
-
- Offline servers
-
-
-
-
-
- {data ?
{data?.offline_servers}
:
}
-
-
-
-
-
-
-
-
-
- Total bandwidth
- {data ? {formatBytes(data?.total_bandwidth)}
:
}
-
-
-
-
-
- )
-}
\ No newline at end of file
+ return (
+
+
+
+
+ Total servers
+
+
+
+
+ {data ? (
+
{data?.result.length}
+ ) : (
+
+
+
+ )}
+
+
+
+
+
+
+
+ Online servers
+
+
+
+
+
+ {data ? (
+
{data?.live_servers}
+ ) : (
+
+
+
+ )}
+
+
+
+
+
+
+
+ Offline servers
+
+
+
+
+
+ {data ? (
+
{data?.offline_servers}
+ ) : (
+
+
+
+ )}
+
+
+
+
+
+
+
+ Total bandwidth
+ {data ? (
+
+ {formatBytes(data?.total_bandwidth)}
+
+ ) : (
+
+
+
+ )}
+
+
+
+
+
+ );
+}
diff --git a/app/(main)/footer.tsx b/app/(main)/footer.tsx
index a14f070..2792eb3 100644
--- a/app/(main)/footer.tsx
+++ b/app/(main)/footer.tsx
@@ -1,22 +1,22 @@
export default function Footer() {
- return (
-
- )
+ return (
+
+ );
}
diff --git a/app/(main)/header.tsx b/app/(main)/header.tsx
index f062240..65702ba 100644
--- a/app/(main)/header.tsx
+++ b/app/(main)/header.tsx
@@ -1,6 +1,6 @@
"use client";
-import React, { useEffect, useState } from "react";
+import React, { useEffect, useRef, useState } from "react";
import Image from "next/image";
import { Separator } from "@/components/ui/separator";
import { DateTime } from "luxon";
@@ -36,22 +36,45 @@ function Header() {
);
}
+// https://github.com/streamich/react-use/blob/master/src/useInterval.ts
+const useInterval = (callback: Function, delay?: number | null) => {
+ const savedCallback = useRef(() => { });
+
+ useEffect(() => {
+ savedCallback.current = callback;
+ });
+
+ useEffect(() => {
+ if (delay !== null) {
+ const interval = setInterval(() => savedCallback.current(), delay || 0);
+ return () => clearInterval(interval);
+ }
+
+ return undefined;
+ }, [delay]);
+};
+
function Overview() {
const [mouted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
- const time = DateTime.TIME_SIMPLE;
- time.hour12 = true;
+ const timeOption = DateTime.TIME_SIMPLE;
+ timeOption.hour12 = true;
+ const [timeString, setTimeString] = useState(DateTime.now().setLocale("en-US").toLocaleString(timeOption));
+
+ useInterval(() => {
+ setTimeString(DateTime.now().setLocale("en-US").toLocaleString(timeOption));
+ }, 1000);
return (
-
+
👋 Overview
where the time is
{mouted && (
- {DateTime.now().setLocale("en-US").toLocaleString(time)}
+ {timeString}
)}
diff --git a/app/(main)/nav.tsx b/app/(main)/nav.tsx
deleted file mode 100644
index 3f8b907..0000000
--- a/app/(main)/nav.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-"use client";
-
-import { clsx } from "clsx";
-import Link from "next/link";
-import { usePathname } from "next/navigation";
-import React from "react";
-
-import { cn } from "@/lib/utils";
-
-export const siteUrlList = [
- {
- name: "Home",
- header: "👋 Overview",
- url: "/",
- },
- {
- name: "Service",
- header: "🎛️ Service",
- url: "/service",
- },
-];
-export default function Nav() {
- const nowPath = usePathname();
- return (
-
-
- {siteUrlList.map((site, index) => (
-
- {index !== 0 && (
-
- /
-
- )}
-
- {site.name}
-
-
- ))}
-
-
- );
-}
diff --git a/components/ServerCard.tsx b/components/ServerCard.tsx
index 9397acf..6120137 100644
--- a/components/ServerCard.tsx
+++ b/components/ServerCard.tsx
@@ -40,9 +40,11 @@ export default function ServerCard({
-
+
@@ -90,7 +92,9 @@ export default function ServerCard({
-
+
diff --git a/components/ServerList.tsx b/components/ServerList.tsx
index db72679..14c28d2 100644
--- a/components/ServerList.tsx
+++ b/components/ServerList.tsx
@@ -2,10 +2,6 @@ import React from "react";
import ServerListClient from "@/app/(main)/ClientComponents/ServerListClient";
-
-
export default async function ServerList() {
- return (
-
- );
+ return ;
}
diff --git a/components/ServerOverview.tsx b/components/ServerOverview.tsx
index d5523fa..2e61c79 100644
--- a/components/ServerOverview.tsx
+++ b/components/ServerOverview.tsx
@@ -1,12 +1,5 @@
import ServerOverviewClient from "@/app/(main)/ClientComponents/ServerOverviewClient";
-
-
-
export default async function ServerOverview() {
- return (
-
- )
-
-
-}
\ No newline at end of file
+ return ;
+}
diff --git a/components/SubscribeCard.tsx b/components/SubscribeCard.tsx
deleted file mode 100644
index b52d9fa..0000000
--- a/components/SubscribeCard.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-import React from "react";
-
-import { Loader } from "@/components/loading/Loader";
-import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
-import { Progress } from "@/components/ui/progress";
-
-type SubscribeCardProps = {
- provider: string;
- behavior: string;
- value: number;
- nextBillDay?: number;
- total: number;
- unit: string;
- colorClassName: string;
- isLoading: boolean;
-};
-
-function SubscribeCard({
- provider,
- behavior,
- value,
- total,
- unit,
- nextBillDay,
- colorClassName,
- isLoading,
-}: SubscribeCardProps) {
- return (
-
-
-
- {provider}
-
- {nextBillDay !== -1 && (
-
-
- {nextBillDay}
-
-
|
-
- )}
-
-
-
-
-
-
-
-
- );
-}
-
-export default SubscribeCard;
diff --git a/lib/prefetch.tsx b/lib/prefetch.tsx
new file mode 100644
index 0000000..911edbb
--- /dev/null
+++ b/lib/prefetch.tsx
@@ -0,0 +1,54 @@
+import { NezhaAPI, ServerApi } from "@/app/types/nezha-api";
+import { MakeOptional } from "@/app/types/utils";
+import { error } from "console";
+
+export async function GetNezhaData() {
+ if (!process.env.NezhaBaseUrl) {
+ error("NezhaBaseUrl is not set");
+ return;
+ }
+ // Remove trailing slash
+ var nezhaBaseUrl = process.env.NezhaBaseUrl;
+
+ if (process.env.NezhaBaseUrl[process.env.NezhaBaseUrl.length - 1] === "/") {
+ nezhaBaseUrl = process.env.NezhaBaseUrl.slice(0, -1);
+ }
+ try {
+ const response = await fetch(nezhaBaseUrl + "/api/v1/server/details", {
+ headers: {
+ Authorization: process.env.NezhaAuth as string,
+ },
+ next: {
+ revalidate: 1,
+ },
+ });
+ const nezhaData = (await response.json()).result as NezhaAPI[];
+ const data: ServerApi = {
+ live_servers: 0,
+ offline_servers: 0,
+ total_bandwidth: 0,
+ result: [],
+ };
+ const timestamp = Date.now() / 1000;
+ data.result = nezhaData.map(
+ (element: MakeOptional) => {
+ if (timestamp - element.last_active > 300) {
+ data.offline_servers += 1;
+ } else {
+ data.live_servers += 1;
+ }
+ data.total_bandwidth += element.status.NetOutTransfer;
+
+ delete element.ipv4;
+ delete element.ipv6;
+ delete element.valid_ip;
+
+ return element;
+ },
+ );
+
+ return data;
+ } catch (error) {
+ return error;
+ }
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index 5deab95..9bcef28 100644
--- a/package.json
+++ b/package.json
@@ -4,9 +4,9 @@
"private": true,
"scripts": {
"dev": "next dev -p 3020",
- "build": "next build",
- "start": "next start",
- "lint": "next lint"
+ "start": "node .next/standalone/server.js",
+ "lint": "next lint",
+ "build": "next build && cp -r .next/static .next/standalone/.next/ && cp -r public .next/standalone/"
},
"dependencies": {
"@ducanh2912/next-pwa": "^10.2.6",
@@ -33,7 +33,7 @@
"react-wrap-balancer": "^1.1.0",
"sharp": "^0.33.3",
"sonner": "^1.4.41",
- "swr": "^2.2.6-beta.3",
+ "swr": "^2.2.6-beta.4",
"tailwind-merge": "^2.2.2",
"tailwindcss-animate": "^1.0.7",
"zod": "^3.22.4"
From 9ee938453f9798ee7b578940796023d02c551238 Mon Sep 17 00:00:00 2001
From: hamster1963 <1410514192@qq.com>
Date: Sun, 28 Jul 2024 16:05:08 +0800
Subject: [PATCH 3/3] feat: add Dockerfile
---
Dockerfile | 58 +++++++++++++++++++++++++++++++++++++++++++++++++
next.config.mjs | 5 ++++-
2 files changed, 62 insertions(+), 1 deletion(-)
create mode 100644 Dockerfile
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..a5cfcf0
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,58 @@
+FROM node:21-alpine AS base
+
+FROM base AS deps
+RUN apk add --no-cache libc6-compat
+WORKDIR /app
+
+RUN apk --no-cache add ca-certificates wget
+RUN wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub
+RUN wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.28-r0/glibc-2.28-r0.apk
+RUN apk add --no-cache --force-overwrite glibc-2.28-r0.apk
+
+COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* bun.lockb* ./
+RUN \
+ if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
+ elif [ -f package-lock.json ]; then npm ci; \
+ elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i --frozen-lockfile; \
+ elif [ -f bun.lockb ]; then npm install -g bun && bun install; \
+ else echo "Lockfile not found." && exit 1; \
+ fi
+
+
+FROM base AS builder
+WORKDIR /app
+COPY --from=deps /app/node_modules ./node_modules
+COPY . .
+
+ARG PROD_ENV=""
+# Appends to .env.production
+RUN printf "$PROD_ENV" >> .env.production
+
+RUN yarn build
+
+
+FROM base AS runner
+WORKDIR /app
+
+ENV NODE_ENV production
+ENV NEXT_TELEMETRY_DISABLED 1
+
+RUN addgroup --system --gid 1001 nodejs
+RUN adduser --system --uid 1001 nextjs
+
+COPY --from=builder /app/public ./public
+COPY --from=builder /app/.env.production ./.env.production
+
+COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
+COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
+
+
+
+USER nextjs
+
+EXPOSE 3000
+
+ENV PORT 3000
+ENV HOSTNAME "0.0.0.0"
+
+CMD ["node", "server.js"]
diff --git a/next.config.mjs b/next.config.mjs
index 9b4c182..7e5fcf7 100644
--- a/next.config.mjs
+++ b/next.config.mjs
@@ -18,6 +18,9 @@ const withPWA = withPWAInit({
});
/** @type {import('next').NextConfig} */
-const nextConfig = {};
+const nextConfig = {
+ output: "standalone",
+ reactStrictMode: true,
+};
export default bundleAnalyzer(withPWA(nextConfig));