pref: add Checker

This commit is contained in:
thehrz 2024-08-19 17:57:38 +08:00
parent 794ec8e6ff
commit 6c9a08e20f
Signed by: thehrz
GPG Key ID: C84CBCE7D5F88855
10 changed files with 139 additions and 32 deletions

View File

@ -9,6 +9,7 @@
"lint": "next lint"
},
"dependencies": {
"@tanstack/react-query": "^5.51.23",
"next": "14.2.5",
"react": "^18",
"react-dom": "^18",

View File

@ -8,6 +8,9 @@ importers:
.:
dependencies:
'@tanstack/react-query':
specifier: ^5.51.23
version: 5.51.23(react@18.3.1)
next:
specifier: 14.2.5
version: 14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@ -207,6 +210,14 @@ packages:
'@swc/helpers@0.5.5':
resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==}
'@tanstack/query-core@5.51.21':
resolution: {integrity: sha512-POQxm42IUp6n89kKWF4IZi18v3fxQWFRolvBA6phNVmA8psdfB1MvDnGacCJdS+EOX12w/CyHM62z//rHmYmvw==}
'@tanstack/react-query@5.51.23':
resolution: {integrity: sha512-CfJCfX45nnVIZjQBRYYtvVMIsGgWLKLYC4xcUiYEey671n1alvTZoCBaU9B85O8mF/tx9LPyrI04A6Bs2THv4A==}
peerDependencies:
react: ^18.0.0
'@types/json5@0.0.29':
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
@ -1691,6 +1702,13 @@ snapshots:
'@swc/counter': 0.1.3
tslib: 2.6.3
'@tanstack/query-core@5.51.21': {}
'@tanstack/react-query@5.51.23(react@18.3.1)':
dependencies:
'@tanstack/query-core': 5.51.21
react: 18.3.1
'@types/json5@0.0.29': {}
'@types/node@20.14.15':

View File

@ -19,11 +19,13 @@ export default function RootLayout({
return (
<html lang='zh'>
<body className={inter.className}>
<main className='h-screen flex flex-col'>
<div className='min-h-screen flex flex-col'>
<Nav />
{children}
<main className='flex-grow px-4 container max-w-3xl mx-auto'>
{children}
</main>
<Footer />
</main>
</div>
</body>
</html>
)

View File

@ -1,34 +1,15 @@
"use client"
import useSWR from "swr"
const fetcher = (url: string | URL | Request) =>
fetch(url).then((r) => r.json())
interface Myip {
address: string
version: string
}
import Checker from "@/components/Checker"
export default function Home() {
const { data: http4 } = useSWR<Myip>("https://4.ipv6test.online/ip/myip", fetcher)
const { data: http6 } = useSWR<Myip>("https://6.ipv6test.online/ip/myip", fetcher)
return (
<div className='max-w-full flex justify-center h-full'>
<div className='hero-content text-center'>
<div className='max-w-sm md:max-w-md'>
<h1 className='text-5xl font-bold'>IPv6测试</h1>
<>
<h1 className='text-2xl font-bold my-5'>IPv6测试</h1>
<div className='card bg-base-100 w-96 shadow-xl'>
<div className='card-body'>
<p>IPv4 {http4?.address}</p>
<p>IPv6 {http6?.address}</p>
</div>
</div>
{/* <button className='btn btn-primary'>探索更多</button> */}
<div className='card-bordered bg-base-100 shadow-xl max-w-2xl'>
<div className='card-body'>
<Checker />
</div>
</div>
</div>
</>
)
}

View File

@ -0,0 +1,50 @@
import { CheckItemIconState, CheckItemType } from "@/types/CheckItem"
import { Icon } from "@iconify/react/dist/iconify.js"
import useSWRImmutable from "swr/immutable"
type CheckItemProps = CheckItemType
const fetcher = (url: string | URL | Request) =>
fetch(url).then((r) => r.json())
const icon = {
ok: (
<Icon
icon='material-symbols:check-circle-outline-rounded'
className='stroke-1 text-info h-6 w-6 shrink-0'
/>
),
loading: <span className='loading loading-spinner loading-xs'></span>,
info: (
<Icon
icon='material-symbols:info-outline'
className='stroke-1 text-info h-6 w-6 shrink-0'
/>
),
error: (
<Icon
icon='material-symbols:error-outline'
className='stroke-1 text-info h-6 w-6 shrink-0'
/>
),
}
export default function CheckItem({ url, content }: CheckItemProps) {
const { data, error, isLoading } = useSWRImmutable(url, fetcher)
return (
<>
<div role='alert' className='alert'>
{error
? icon["error"]
: isLoading
? icon["loading"]
: data != undefined
? icon[content(data).state]
: null}
{data != undefined ? <span>{content(data).text}</span> : null}
</div>
</>
)
}

View File

@ -0,0 +1,35 @@
import CheckItem from "./CheckItem"
import { CheckItemType } from "@/types/CheckItem"
const checkList: CheckItemType[] = [
{
url: "https://6.ipv6test.online/ip/myip",
content: (data) => {
const isIPv6 = data?.version == 6
return {
state: isIPv6 ? "ok" : "error",
text: "公网 IPv6 地址: " + (isIPv6 ? `${data?.address}` : "未检测到")
}
},
},
{
url: "https://4.ipv6test.online/ip/myip",
content: (data) => {
const isIPv4 = data?.version == 4
return {
state: isIPv4 ? "ok" : "error",
text: "公网 IPv4 地址: " + (isIPv4 ? `${data?.address}` : "未检测到")
}
},
},
]
export default function Checker() {
return (
<>
{checkList.map((item, i) => {
return <CheckItem key={i} url={item.url} content={item.content}/>
})}
</>
)
}

View File

@ -0,0 +1,10 @@
type Props = {
address: string
version: number
};
export default function IPAddress({address, version}: Props) {
return (
<p><b>IPv4 </b>{address}</p>
)
}

View File

@ -3,15 +3,15 @@ import Link from "next/link"
export default function Nav() {
return (
<div className='navbar bg-base-200 px-5 border'>
<div className='navbar bg-base-200 px-5 border h-16'>
<div className='flex-1'>
<a className='text-xl'>ipv6-test IPv6 </a>
</div>
<div className='flex-none'>
<ul className='menu menu-horizontal px-1'>
<li>
<Link className='btn btn-circle' href="https://git.thehrz.net/thehrz/ipv6-test-backend">
<Icon icon='simple-icons:gitea' className="w-6 h-6" />
<Link className='btn btn-circle' href="https://git.thehrz.net/thehrz/ipv6-test-backend" >
<Icon icon='simple-icons:gitea' className="h-6 w-6"/>
</Link>
</li>
</ul>

6
src/types/CheckItem.ts Normal file
View File

@ -0,0 +1,6 @@
export interface CheckItemType {
url: string
content: (data: any) => {state: CheckItemIconState, text: string}
}
export type CheckItemIconState = "ok" | "loading" | "info" | "error"

View File

@ -0,0 +1,4 @@
export default interface MyIPResponse {
address: string
version: number
}