Compare commits
No commits in common. "8d6bcbcccde0ec6ca5929586bb7e32a06ed5ae57" and "30656c192e4ee9d97703cf902183e33b015fcb46" have entirely different histories.
8d6bcbcccd
...
30656c192e
BIN
.github/1-dark.webp
vendored
Before Width: | Height: | Size: 140 KiB |
BIN
.github/1.webp
vendored
Before Width: | Height: | Size: 139 KiB |
BIN
.github/2-dark.webp
vendored
Before Width: | Height: | Size: 328 KiB |
BIN
.github/2.webp
vendored
Before Width: | Height: | Size: 226 KiB |
BIN
.github/3-dark.webp
vendored
Before Width: | Height: | Size: 119 KiB |
BIN
.github/3.webp
vendored
Before Width: | Height: | Size: 115 KiB |
BIN
.github/4-dark.webp
vendored
Before Width: | Height: | Size: 203 KiB |
BIN
.github/4.webp
vendored
Before Width: | Height: | Size: 135 KiB |
BIN
.github/shot-1-dark.png
vendored
Normal file
After Width: | Height: | Size: 604 KiB |
BIN
.github/shot-1.png
vendored
Normal file
After Width: | Height: | Size: 605 KiB |
BIN
.github/shot-2-dark.png
vendored
Normal file
After Width: | Height: | Size: 754 KiB |
BIN
.github/shot-2.png
vendored
Normal file
After Width: | Height: | Size: 750 KiB |
BIN
.github/shot-3-dark.png
vendored
Normal file
After Width: | Height: | Size: 584 KiB |
BIN
.github/shot-3.png
vendored
Normal file
After Width: | Height: | Size: 579 KiB |
BIN
.github/shotOne.png
vendored
Normal file
After Width: | Height: | Size: 597 KiB |
BIN
.github/shotTwo.png
vendored
Normal file
After Width: | Height: | Size: 596 KiB |
14
README.md
@ -24,11 +24,9 @@
|
|||||||
|
|
||||||
[环境变量介绍](https://nezhadash-docs.vercel.app/environment)
|
[环境变量介绍](https://nezhadash-docs.vercel.app/environment)
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|
|
||||||

|
|
||||||
|
@ -4,7 +4,6 @@ import { ServerApi } from "@/app/types/nezha-api";
|
|||||||
import ServerCard from "@/components/ServerCard";
|
import ServerCard from "@/components/ServerCard";
|
||||||
import Switch from "@/components/Switch";
|
import Switch from "@/components/Switch";
|
||||||
import getEnv from "@/lib/env-entry";
|
import getEnv from "@/lib/env-entry";
|
||||||
import { useFilter } from "@/lib/network-filter-context";
|
|
||||||
import { useStatus } from "@/lib/status-context";
|
import { useStatus } from "@/lib/status-context";
|
||||||
import { nezhaFetcher } from "@/lib/utils";
|
import { nezhaFetcher } from "@/lib/utils";
|
||||||
import { GlobeAsiaAustraliaIcon } from "@heroicons/react/20/solid";
|
import { GlobeAsiaAustraliaIcon } from "@heroicons/react/20/solid";
|
||||||
@ -15,7 +14,6 @@ import useSWR from "swr";
|
|||||||
|
|
||||||
export default function ServerListClient() {
|
export default function ServerListClient() {
|
||||||
const { status, setStatus } = useStatus();
|
const { status, setStatus } = useStatus();
|
||||||
const { filter, setFilter } = useFilter();
|
|
||||||
const t = useTranslations("ServerListClient");
|
const t = useTranslations("ServerListClient");
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const defaultTag = "defaultTag";
|
const defaultTag = "defaultTag";
|
||||||
@ -98,17 +96,6 @@ export default function ServerListClient() {
|
|||||||
? filteredServersByStatus
|
? filteredServersByStatus
|
||||||
: filteredServersByStatus.filter((server) => server.tag === tag);
|
: filteredServersByStatus.filter((server) => server.tag === tag);
|
||||||
|
|
||||||
if (filter) {
|
|
||||||
// 根据使用流量进行从高到低排序
|
|
||||||
filteredServers.sort((a, b) => {
|
|
||||||
return (
|
|
||||||
b.status.NetInTransfer +
|
|
||||||
b.status.NetOutTransfer -
|
|
||||||
(a.status.NetInTransfer + b.status.NetOutTransfer)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const tagCountMap: Record<string, number> = {};
|
const tagCountMap: Record<string, number> = {};
|
||||||
filteredServersByStatus.forEach((server) => {
|
filteredServersByStatus.forEach((server) => {
|
||||||
if (server.tag) {
|
if (server.tag) {
|
||||||
@ -122,7 +109,6 @@ export default function ServerListClient() {
|
|||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setStatus("all");
|
setStatus("all");
|
||||||
setFilter(false);
|
|
||||||
router.push(`/?global=true`);
|
router.push(`/?global=true`);
|
||||||
}}
|
}}
|
||||||
className="rounded-[50px] bg-stone-100 p-[10px] transition-all hover:bg-stone-200 dark:hover:bg-stone-700 dark:bg-stone-800"
|
className="rounded-[50px] bg-stone-100 p-[10px] transition-all hover:bg-stone-200 dark:hover:bg-stone-700 dark:bg-stone-800"
|
||||||
|
@ -4,7 +4,6 @@ import { ServerApi } from "@/app/types/nezha-api";
|
|||||||
import { Loader } from "@/components/loading/Loader";
|
import { Loader } from "@/components/loading/Loader";
|
||||||
import { Card, CardContent } from "@/components/ui/card";
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
import getEnv from "@/lib/env-entry";
|
import getEnv from "@/lib/env-entry";
|
||||||
import { useFilter } from "@/lib/network-filter-context";
|
|
||||||
import { useStatus } from "@/lib/status-context";
|
import { useStatus } from "@/lib/status-context";
|
||||||
import { cn, formatBytes, nezhaFetcher } from "@/lib/utils";
|
import { cn, formatBytes, nezhaFetcher } from "@/lib/utils";
|
||||||
import blogMan from "@/public/blog-man.webp";
|
import blogMan from "@/public/blog-man.webp";
|
||||||
@ -15,7 +14,6 @@ import useSWR from "swr";
|
|||||||
|
|
||||||
export default function ServerOverviewClient() {
|
export default function ServerOverviewClient() {
|
||||||
const { status, setStatus } = useStatus();
|
const { status, setStatus } = useStatus();
|
||||||
const { filter, setFilter } = useFilter();
|
|
||||||
const t = useTranslations("ServerOverviewClient");
|
const t = useTranslations("ServerOverviewClient");
|
||||||
const { data, error, isLoading } = useSWR<ServerApi>(
|
const { data, error, isLoading } = useSWR<ServerApi>(
|
||||||
"/api/server",
|
"/api/server",
|
||||||
@ -42,12 +40,7 @@ export default function ServerOverviewClient() {
|
|||||||
<>
|
<>
|
||||||
<section className="grid grid-cols-2 gap-4 lg:grid-cols-4">
|
<section className="grid grid-cols-2 gap-4 lg:grid-cols-4">
|
||||||
<Card
|
<Card
|
||||||
onClick={() => {
|
onClick={() => (global ? null : setStatus("all"))}
|
||||||
setFilter(false);
|
|
||||||
if (!global) {
|
|
||||||
setStatus("all");
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
className="cursor-pointer hover:border-blue-500 transition-all"
|
className="cursor-pointer hover:border-blue-500 transition-all"
|
||||||
>
|
>
|
||||||
<CardContent className="px-6 py-3">
|
<CardContent className="px-6 py-3">
|
||||||
@ -73,12 +66,7 @@ export default function ServerOverviewClient() {
|
|||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
<Card
|
<Card
|
||||||
onClick={() => {
|
onClick={() => (global ? null : setStatus("online"))}
|
||||||
setFilter(false);
|
|
||||||
if (!global) {
|
|
||||||
setStatus("online");
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
className={cn(
|
className={cn(
|
||||||
"cursor-pointer hover:ring-green-500 ring-1 ring-transparent transition-all",
|
"cursor-pointer hover:ring-green-500 ring-1 ring-transparent transition-all",
|
||||||
{
|
{
|
||||||
@ -110,12 +98,7 @@ export default function ServerOverviewClient() {
|
|||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
<Card
|
<Card
|
||||||
onClick={() => {
|
onClick={() => (global ? null : setStatus("offline"))}
|
||||||
setFilter(false);
|
|
||||||
if (!global) {
|
|
||||||
setStatus("offline");
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
className={cn(
|
className={cn(
|
||||||
"cursor-pointer hover:ring-red-500 ring-1 ring-transparent transition-all",
|
"cursor-pointer hover:ring-red-500 ring-1 ring-transparent transition-all",
|
||||||
{
|
{
|
||||||
@ -146,20 +129,7 @@ export default function ServerOverviewClient() {
|
|||||||
</section>
|
</section>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
<Card
|
<Card>
|
||||||
onClick={() => {
|
|
||||||
setStatus("all");
|
|
||||||
if (!global) {
|
|
||||||
setFilter(true);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
className={cn(
|
|
||||||
"cursor-pointer hover:ring-purple-500 ring-1 ring-transparent transition-all",
|
|
||||||
{
|
|
||||||
"ring-purple-500 ring-2 border-transparent": filter === true,
|
|
||||||
},
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<CardContent className="relative px-6 py-3">
|
<CardContent className="relative px-6 py-3">
|
||||||
<section className="flex flex-col gap-1">
|
<section className="flex flex-col gap-1">
|
||||||
<p className="text-sm font-medium md:text-base">
|
<p className="text-sm font-medium md:text-base">
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// @auto-i18n-check. Please do not delete the line.
|
// @auto-i18n-check. Please do not delete the line.
|
||||||
import { MotionProvider } from "@/components/motion/motion-provider";
|
import { MotionProvider } from "@/components/motion/motion-provider";
|
||||||
import getEnv from "@/lib/env-entry";
|
import getEnv from "@/lib/env-entry";
|
||||||
import { FilterProvider } from "@/lib/network-filter-context";
|
|
||||||
import { StatusProvider } from "@/lib/status-context";
|
import { StatusProvider } from "@/lib/status-context";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import "@/styles/globals.css";
|
import "@/styles/globals.css";
|
||||||
@ -80,9 +79,7 @@ export default async function LocaleLayout({
|
|||||||
disableTransitionOnChange
|
disableTransitionOnChange
|
||||||
>
|
>
|
||||||
<NextIntlClientProvider messages={messages}>
|
<NextIntlClientProvider messages={messages}>
|
||||||
<FilterProvider>
|
|
||||||
<StatusProvider>{children}</StatusProvider>
|
<StatusProvider>{children}</StatusProvider>
|
||||||
</FilterProvider>
|
|
||||||
</NextIntlClientProvider>
|
</NextIntlClientProvider>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</MotionProvider>
|
</MotionProvider>
|
||||||
|
229
lib/geo.ts
@ -1,229 +0,0 @@
|
|||||||
// ISO 3166-1 alpha-2 到 alpha-3 的国家代码映射
|
|
||||||
export const countryCodeMapping: { [key: string]: string } = {
|
|
||||||
// 亚洲
|
|
||||||
AF: "AFG", // 阿富汗
|
|
||||||
AM: "ARM", // 亚美尼亚
|
|
||||||
AZ: "AZE", // 阿塞拜疆
|
|
||||||
BD: "BGD", // 孟加拉国
|
|
||||||
BH: "BHR", // 巴林
|
|
||||||
BT: "BTN", // 不丹
|
|
||||||
BN: "BRN", // 文莱
|
|
||||||
KH: "KHM", // 柬埔寨
|
|
||||||
CN: "CHN", // 中国
|
|
||||||
CY: "CYP", // 塞浦路斯
|
|
||||||
GE: "GEO", // 格鲁吉亚
|
|
||||||
IN: "IND", // 印度
|
|
||||||
ID: "IDN", // 印度尼西亚
|
|
||||||
IR: "IRN", // 伊朗
|
|
||||||
IQ: "IRQ", // 伊拉克
|
|
||||||
IL: "ISR", // 以色列
|
|
||||||
JP: "JPN", // 日本
|
|
||||||
JO: "JOR", // 约旦
|
|
||||||
KZ: "KAZ", // 哈萨克斯坦
|
|
||||||
KW: "KWT", // 科威特
|
|
||||||
KG: "KGZ", // 吉尔吉斯斯坦
|
|
||||||
LA: "LAO", // 老挝
|
|
||||||
LB: "LBN", // 黎巴嫩
|
|
||||||
MY: "MYS", // 马来西亚
|
|
||||||
MV: "MDV", // 马尔代夫
|
|
||||||
MN: "MNG", // 蒙古
|
|
||||||
MM: "MMR", // 缅甸
|
|
||||||
NP: "NPL", // 尼泊尔
|
|
||||||
OM: "OMN", // 阿曼
|
|
||||||
PK: "PAK", // 巴基斯坦
|
|
||||||
PH: "PHL", // 菲律宾
|
|
||||||
QA: "QAT", // 卡塔尔
|
|
||||||
SA: "SAU", // 沙特阿拉伯
|
|
||||||
SG: "SGP", // 新加坡
|
|
||||||
KR: "KOR", // 韩国
|
|
||||||
LK: "LKA", // 斯里兰卡
|
|
||||||
SY: "SYR", // 叙利亚
|
|
||||||
TW: "TWN", // 台湾
|
|
||||||
TJ: "TJK", // 塔吉克斯坦
|
|
||||||
TH: "THA", // 泰国
|
|
||||||
TR: "TUR", // 土耳其
|
|
||||||
TM: "TKM", // 土库曼斯坦
|
|
||||||
AE: "ARE", // 阿联酋
|
|
||||||
UZ: "UZB", // 乌兹别克斯坦
|
|
||||||
VN: "VNM", // 越南
|
|
||||||
YE: "YEM", // 也门
|
|
||||||
PS: "PSE", // 巴勒斯坦
|
|
||||||
|
|
||||||
// 欧洲
|
|
||||||
AL: "ALB", // 阿尔巴尼亚
|
|
||||||
AD: "AND", // 安道尔
|
|
||||||
AT: "AUT", // 奥地利
|
|
||||||
BY: "BLR", // 白俄罗斯
|
|
||||||
BE: "BEL", // 比利时
|
|
||||||
BA: "BIH", // 波黑
|
|
||||||
BG: "BGR", // 保加利亚
|
|
||||||
HR: "HRV", // 克罗地亚
|
|
||||||
CZ: "CZE", // 捷克
|
|
||||||
DK: "DNK", // 丹麦
|
|
||||||
EE: "EST", // 爱沙尼亚
|
|
||||||
FI: "FIN", // 芬兰
|
|
||||||
FR: "FRA", // 法国
|
|
||||||
DE: "DEU", // 德国
|
|
||||||
GR: "GRC", // 希腊
|
|
||||||
HU: "HUN", // 匈牙利
|
|
||||||
IS: "ISL", // 冰岛
|
|
||||||
IE: "IRL", // 爱尔兰
|
|
||||||
IT: "ITA", // 意大利
|
|
||||||
LV: "LVA", // 拉脱维亚
|
|
||||||
LI: "LIE", // 列支敦士登
|
|
||||||
LT: "LTU", // 立陶宛
|
|
||||||
LU: "LUX", // 卢森堡
|
|
||||||
MT: "MLT", // 马耳他
|
|
||||||
MD: "MDA", // 摩尔多瓦
|
|
||||||
MC: "MCO", // 摩纳哥
|
|
||||||
ME: "MNE", // 黑山
|
|
||||||
NL: "NLD", // 荷兰
|
|
||||||
NO: "NOR", // 挪威
|
|
||||||
PL: "POL", // 波兰
|
|
||||||
PT: "PRT", // 葡萄牙
|
|
||||||
RO: "ROU", // 罗马尼亚
|
|
||||||
RU: "RUS", // 俄罗斯
|
|
||||||
SM: "SMR", // 圣马力诺
|
|
||||||
RS: "SRB", // 塞尔维亚
|
|
||||||
SK: "SVK", // 斯洛伐克
|
|
||||||
SI: "SVN", // 斯洛文尼亚
|
|
||||||
ES: "ESP", // 西班牙
|
|
||||||
SE: "SWE", // 瑞典
|
|
||||||
CH: "CHE", // 瑞士
|
|
||||||
UA: "UKR", // 乌克兰
|
|
||||||
GB: "GBR", // 英国
|
|
||||||
VA: "VAT", // 梵蒂冈
|
|
||||||
|
|
||||||
// 北美洲
|
|
||||||
AG: "ATG", // 安提瓜和巴布达
|
|
||||||
BS: "BHS", // 巴哈马
|
|
||||||
BB: "BRB", // 巴巴多斯
|
|
||||||
BZ: "BLZ", // 伯利兹
|
|
||||||
CA: "CAN", // 加拿大
|
|
||||||
CR: "CRI", // 哥斯达黎加
|
|
||||||
CU: "CUB", // 古巴
|
|
||||||
DM: "DMA", // 多米尼克
|
|
||||||
DO: "DOM", // 多米尼加共和国
|
|
||||||
SV: "SLV", // 萨尔瓦多
|
|
||||||
GD: "GRD", // 格林纳达
|
|
||||||
GT: "GTM", // 危地马拉
|
|
||||||
HT: "HTI", // 海地
|
|
||||||
HN: "HND", // 洪都拉斯
|
|
||||||
JM: "JAM", // 牙买加
|
|
||||||
MX: "MEX", // 墨西哥
|
|
||||||
NI: "NIC", // 尼加拉瓜
|
|
||||||
PA: "PAN", // 巴拿马
|
|
||||||
KN: "KNA", // 圣基茨和尼维斯
|
|
||||||
LC: "LCA", // 圣卢西亚
|
|
||||||
VC: "VCT", // 圣文森特和格林纳丁斯
|
|
||||||
TT: "TTO", // 特立尼达和多巴哥
|
|
||||||
US: "USA", // 美国
|
|
||||||
|
|
||||||
// 南美洲
|
|
||||||
AR: "ARG", // 阿根廷
|
|
||||||
BO: "BOL", // 玻利维亚
|
|
||||||
BR: "BRA", // 巴西
|
|
||||||
CL: "CHL", // 智利
|
|
||||||
CO: "COL", // 哥伦比亚
|
|
||||||
EC: "ECU", // 厄瓜多尔
|
|
||||||
GY: "GUY", // 圭亚那
|
|
||||||
PY: "PRY", // 巴拉圭
|
|
||||||
PE: "PER", // 秘鲁
|
|
||||||
SR: "SUR", // 苏里南
|
|
||||||
UY: "URY", // 乌拉圭
|
|
||||||
VE: "VEN", // 委内瑞拉
|
|
||||||
|
|
||||||
// 大洋洲
|
|
||||||
AU: "AUS", // 澳大利亚
|
|
||||||
FJ: "FJI", // 斐济
|
|
||||||
KI: "KIR", // 基里巴斯
|
|
||||||
MH: "MHL", // 马绍尔群岛
|
|
||||||
FM: "FSM", // 密克罗尼西亚
|
|
||||||
NR: "NRU", // 瑙鲁
|
|
||||||
NZ: "NZL", // 新西兰
|
|
||||||
PW: "PLW", // 帕劳
|
|
||||||
PG: "PNG", // 巴布亚新几内亚
|
|
||||||
WS: "WSM", // 萨摩亚
|
|
||||||
SB: "SLB", // 所罗门群岛
|
|
||||||
TO: "TON", // 汤加
|
|
||||||
TV: "TUV", // 图瓦卢
|
|
||||||
VU: "VUT", // 瓦努阿图
|
|
||||||
|
|
||||||
// 非洲
|
|
||||||
DZ: "DZA", // 阿尔及利亚
|
|
||||||
AO: "AGO", // 安哥拉
|
|
||||||
BJ: "BEN", // 贝宁
|
|
||||||
BW: "BWA", // 博茨瓦纳
|
|
||||||
BF: "BFA", // 布基纳法索
|
|
||||||
BI: "BDI", // 布隆迪
|
|
||||||
CM: "CMR", // 喀麦隆
|
|
||||||
CV: "CPV", // 佛得角
|
|
||||||
CF: "CAF", // 中非共和国
|
|
||||||
TD: "TCD", // 乍得
|
|
||||||
KM: "COM", // 科摩罗
|
|
||||||
CG: "COG", // 刚果
|
|
||||||
CD: "COD", // 刚果民主共和国
|
|
||||||
CI: "CIV", // 科特迪瓦
|
|
||||||
DJ: "DJI", // 吉布提
|
|
||||||
EG: "EGY", // 埃及
|
|
||||||
GQ: "GNQ", // 赤道几内亚
|
|
||||||
ER: "ERI", // 厄立特里亚
|
|
||||||
ET: "ETH", // 埃塞俄比亚
|
|
||||||
GA: "GAB", // 加蓬
|
|
||||||
GM: "GMB", // 冈比亚
|
|
||||||
GH: "GHA", // 加纳
|
|
||||||
GN: "GIN", // 几内亚
|
|
||||||
GW: "GNB", // 几内亚比绍
|
|
||||||
KE: "KEN", // 肯尼亚
|
|
||||||
LS: "LSO", // 莱索托
|
|
||||||
LR: "LBR", // 利比里亚
|
|
||||||
LY: "LBY", // 利比亚
|
|
||||||
MG: "MDG", // 马达加斯加
|
|
||||||
MW: "MWI", // 马拉维
|
|
||||||
ML: "MLI", // 马里
|
|
||||||
MR: "MRT", // 毛里塔尼亚
|
|
||||||
MU: "MUS", // 毛里求斯
|
|
||||||
MA: "MAR", // 摩洛哥
|
|
||||||
MZ: "MOZ", // 莫桑比克
|
|
||||||
NA: "NAM", // 纳米比亚
|
|
||||||
NE: "NER", // 尼日尔
|
|
||||||
NG: "NGA", // 尼日利亚
|
|
||||||
RW: "RWA", // 卢旺达
|
|
||||||
ST: "STP", // 圣多美和普林西比
|
|
||||||
SN: "SEN", // 塞内加尔
|
|
||||||
SC: "SYC", // 塞舌尔
|
|
||||||
SL: "SLE", // 塞拉利昂
|
|
||||||
SO: "SOM", // 索马里
|
|
||||||
ZA: "ZAF", // 南非
|
|
||||||
SS: "SSD", // 南苏丹
|
|
||||||
SD: "SDN", // 苏丹
|
|
||||||
SZ: "SWZ", // 斯威士兰
|
|
||||||
TZ: "TZA", // 坦桑尼亚
|
|
||||||
TG: "TGO", // 多哥
|
|
||||||
TN: "TUN", // 突尼斯
|
|
||||||
UG: "UGA", // 乌干达
|
|
||||||
EH: "ESH", // 西撒哈拉
|
|
||||||
ZM: "ZMB", // 赞比亚
|
|
||||||
ZW: "ZWE", // 津巴布韦
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将 ISO 3166-1 alpha-2 (2位) 国家代码转换为 ISO 3166-1 alpha-3 (3位) 代码
|
|
||||||
* @param alpha2 2位国家代码
|
|
||||||
* @returns 3位国家代码,如果未找到匹配项则返回原始代码
|
|
||||||
*/
|
|
||||||
export function convertToAlpha3(alpha2: string): string {
|
|
||||||
if (!alpha2) return "";
|
|
||||||
|
|
||||||
const code = alpha2.toUpperCase();
|
|
||||||
return countryCodeMapping[code] || alpha2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 批量转换2位国家代码到3位国家代码
|
|
||||||
* @param alpha2Codes 2位国家代码数组
|
|
||||||
* @returns 3位国家代码数组
|
|
||||||
*/
|
|
||||||
export function convertMultipleToAlpha3(alpha2Codes: string[]): string[] {
|
|
||||||
return alpha2Codes.map((code) => convertToAlpha3(code));
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import React, { ReactNode, createContext, useContext, useState } from "react";
|
|
||||||
|
|
||||||
interface FilterContextType {
|
|
||||||
filter: boolean;
|
|
||||||
setFilter: (filter: boolean) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const FilterContext = createContext<FilterContextType | undefined>(undefined);
|
|
||||||
|
|
||||||
export function FilterProvider({ children }: { children: ReactNode }) {
|
|
||||||
const [filter, setFilter] = useState<boolean>(false);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<FilterContext.Provider value={{ filter, setFilter }}>
|
|
||||||
{children}
|
|
||||||
</FilterContext.Provider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useFilter() {
|
|
||||||
const context = useContext(FilterContext);
|
|
||||||
if (context === undefined) {
|
|
||||||
throw new Error("useFilter must be used within a FilterProvider");
|
|
||||||
}
|
|
||||||
return context;
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "nezha-dash",
|
"name": "nezha-dash",
|
||||||
"version": "1.4.2-fix",
|
"version": "1.4.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev -p 3040",
|
"dev": "next dev -p 3040",
|
||||||
@ -22,7 +22,6 @@
|
|||||||
"@radix-ui/react-slot": "^1.1.0",
|
"@radix-ui/react-slot": "^1.1.0",
|
||||||
"@radix-ui/react-tooltip": "^1.1.4",
|
"@radix-ui/react-tooltip": "^1.1.4",
|
||||||
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
||||||
"@turf/turf": "^7.1.0",
|
|
||||||
"@types/luxon": "^3.4.2",
|
"@types/luxon": "^3.4.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.15.0",
|
"@typescript-eslint/eslint-plugin": "^8.15.0",
|
||||||
"caniuse-lite": "^1.0.30001680",
|
"caniuse-lite": "^1.0.30001680",
|
||||||
@ -56,7 +55,7 @@
|
|||||||
"eslint-plugin-turbo": "^2.3.0",
|
"eslint-plugin-turbo": "^2.3.0",
|
||||||
"eslint-plugin-unused-imports": "^4.1.4",
|
"eslint-plugin-unused-imports": "^4.1.4",
|
||||||
"@next/bundle-analyzer": "^15.0.3",
|
"@next/bundle-analyzer": "^15.0.3",
|
||||||
"@types/node": "^22.9.1",
|
"@types/node": "^22.9.0",
|
||||||
"@types/react": "npm:types-react@19.0.0-rc.1",
|
"@types/react": "npm:types-react@19.0.0-rc.1",
|
||||||
"@types/react-dom": "npm:types-react-dom@19.0.0-rc.1",
|
"@types/react-dom": "npm:types-react-dom@19.0.0-rc.1",
|
||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
@ -64,7 +63,7 @@
|
|||||||
"eslint-config-next": "^15.0.3",
|
"eslint-config-next": "^15.0.3",
|
||||||
"postcss": "^8.4.49",
|
"postcss": "^8.4.49",
|
||||||
"prettier": "^3.3.3",
|
"prettier": "^3.3.3",
|
||||||
"prettier-plugin-tailwindcss": "^0.6.9",
|
"prettier-plugin-tailwindcss": "^0.6.8",
|
||||||
"tailwindcss": "^3.4.15",
|
"tailwindcss": "^3.4.15",
|
||||||
"typescript": "^5.6.3"
|
"typescript": "^5.6.3"
|
||||||
},
|
},
|
||||||
|