pref: add Checker
This commit is contained in:
parent
794ec8e6ff
commit
6c9a08e20f
@ -9,6 +9,7 @@
|
|||||||
"lint": "next lint"
|
"lint": "next lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@tanstack/react-query": "^5.51.23",
|
||||||
"next": "14.2.5",
|
"next": "14.2.5",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
"react-dom": "^18",
|
"react-dom": "^18",
|
||||||
|
@ -8,6 +8,9 @@ importers:
|
|||||||
|
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@tanstack/react-query':
|
||||||
|
specifier: ^5.51.23
|
||||||
|
version: 5.51.23(react@18.3.1)
|
||||||
next:
|
next:
|
||||||
specifier: 14.2.5
|
specifier: 14.2.5
|
||||||
version: 14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
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':
|
'@swc/helpers@0.5.5':
|
||||||
resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==}
|
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':
|
'@types/json5@0.0.29':
|
||||||
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
|
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
|
||||||
|
|
||||||
@ -1691,6 +1702,13 @@ snapshots:
|
|||||||
'@swc/counter': 0.1.3
|
'@swc/counter': 0.1.3
|
||||||
tslib: 2.6.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/json5@0.0.29': {}
|
||||||
|
|
||||||
'@types/node@20.14.15':
|
'@types/node@20.14.15':
|
||||||
|
@ -19,11 +19,13 @@ export default function RootLayout({
|
|||||||
return (
|
return (
|
||||||
<html lang='zh'>
|
<html lang='zh'>
|
||||||
<body className={inter.className}>
|
<body className={inter.className}>
|
||||||
<main className='h-screen flex flex-col'>
|
<div className='min-h-screen flex flex-col'>
|
||||||
<Nav />
|
<Nav />
|
||||||
|
<main className='flex-grow px-4 container max-w-3xl mx-auto'>
|
||||||
{children}
|
{children}
|
||||||
<Footer />
|
|
||||||
</main>
|
</main>
|
||||||
|
<Footer />
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
)
|
)
|
||||||
|
@ -1,34 +1,15 @@
|
|||||||
"use client"
|
import Checker from "@/components/Checker"
|
||||||
import useSWR from "swr"
|
|
||||||
|
|
||||||
const fetcher = (url: string | URL | Request) =>
|
|
||||||
fetch(url).then((r) => r.json())
|
|
||||||
|
|
||||||
interface Myip {
|
|
||||||
address: string
|
|
||||||
version: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Home() {
|
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 (
|
return (
|
||||||
<div className='max-w-full flex justify-center h-full'>
|
<>
|
||||||
<div className='hero-content text-center'>
|
<h1 className='text-2xl font-bold my-5'>IPv6测试</h1>
|
||||||
<div className='max-w-sm md:max-w-md'>
|
|
||||||
<h1 className='text-5xl font-bold'>免费IPv6测试</h1>
|
|
||||||
|
|
||||||
<div className='card bg-base-100 w-96 shadow-xl'>
|
<div className='card-bordered bg-base-100 shadow-xl max-w-2xl'>
|
||||||
<div className='card-body'>
|
<div className='card-body'>
|
||||||
<p>IPv4 {http4?.address}</p>
|
<Checker />
|
||||||
<p>IPv6 {http6?.address}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/* <button className='btn btn-primary'>探索更多</button> */}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
50
src/components/CheckItem.tsx
Normal file
50
src/components/CheckItem.tsx
Normal 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>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
35
src/components/Checker.tsx
Normal file
35
src/components/Checker.tsx
Normal 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}/>
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
10
src/components/IPAddress.tsx
Normal file
10
src/components/IPAddress.tsx
Normal 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>
|
||||||
|
)
|
||||||
|
}
|
@ -3,15 +3,15 @@ import Link from "next/link"
|
|||||||
|
|
||||||
export default function Nav() {
|
export default function Nav() {
|
||||||
return (
|
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'>
|
<div className='flex-1'>
|
||||||
<a className='text-xl'>ipv6-test IPv6 测试</a>
|
<a className='text-xl'>ipv6-test IPv6 测试</a>
|
||||||
</div>
|
</div>
|
||||||
<div className='flex-none'>
|
<div className='flex-none'>
|
||||||
<ul className='menu menu-horizontal px-1'>
|
<ul className='menu menu-horizontal px-1'>
|
||||||
<li>
|
<li>
|
||||||
<Link className='btn btn-circle' href="https://git.thehrz.net/thehrz/ipv6-test-backend">
|
<Link className='btn btn-circle' href="https://git.thehrz.net/thehrz/ipv6-test-backend" >
|
||||||
<Icon icon='simple-icons:gitea' className="w-6 h-6" />
|
<Icon icon='simple-icons:gitea' className="h-6 w-6"/>
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
6
src/types/CheckItem.ts
Normal file
6
src/types/CheckItem.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export interface CheckItemType {
|
||||||
|
url: string
|
||||||
|
content: (data: any) => {state: CheckItemIconState, text: string}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CheckItemIconState = "ok" | "loading" | "info" | "error"
|
4
src/types/MyIPResponse.ts
Normal file
4
src/types/MyIPResponse.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export default interface MyIPResponse {
|
||||||
|
address: string
|
||||||
|
version: number
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user