pref: add Checker
This commit is contained in:
parent
794ec8e6ff
commit
6c9a08e20f
@ -9,6 +9,7 @@
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tanstack/react-query": "^5.51.23",
|
||||
"next": "14.2.5",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
|
@ -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':
|
||||
|
@ -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 />
|
||||
<main className='flex-grow px-4 container max-w-3xl mx-auto'>
|
||||
{children}
|
||||
<Footer />
|
||||
</main>
|
||||
<Footer />
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
|
@ -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-bordered bg-base-100 shadow-xl max-w-2xl'>
|
||||
<div className='card-body'>
|
||||
<p>IPv4 {http4?.address}</p>
|
||||
<p>IPv6 {http6?.address}</p>
|
||||
</div>
|
||||
</div>
|
||||
{/* <button className='btn btn-primary'>探索更多</button> */}
|
||||
</div>
|
||||
<Checker />
|
||||
</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,7 +3,7 @@ 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>
|
||||
@ -11,7 +11,7 @@ export default function Nav() {
|
||||
<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" />
|
||||
<Icon icon='simple-icons:gitea' className="h-6 w-6"/>
|
||||
</Link>
|
||||
</li>
|
||||
</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