变更图标和title提示完善账户总览页面
This commit is contained in:
@@ -61,7 +61,7 @@
|
||||
"onlyBuiltDependencies": [
|
||||
"canvas",
|
||||
"sharp"
|
||||
],
|
||||
],
|
||||
"overrides": {
|
||||
"react-is": "19.0.0-rc.1"
|
||||
}
|
||||
|
||||
17
src/app/(auth)/login/layout.tsx
Normal file
17
src/app/(auth)/login/layout.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
import { ReactNode } from 'react'
|
||||
import { Metadata } from 'next'
|
||||
|
||||
export async function generateMetadata(): Promise<Metadata> {
|
||||
return {
|
||||
title: '登录 - 蓝狐代理',
|
||||
}
|
||||
}
|
||||
|
||||
export type LoginLayoutProps = {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export default async function LoginLayout(props: LoginLayoutProps) {
|
||||
return props.children
|
||||
}
|
||||
@@ -72,24 +72,24 @@ export default function Home() {
|
||||
].join(' ')}>
|
||||
<Sec3Item
|
||||
icon={`s1-1`} title={`短期动态IP池`} terms={[
|
||||
{icon: `s1-check`, text: `IP时效3-30分钟(可定制)`},
|
||||
{icon: `s1-check`, text: `支持高并发提取`},
|
||||
]}/>
|
||||
{icon: `s1-check`, text: `IP时效3-30分钟(可定制)`},
|
||||
{icon: `s1-check`, text: `支持高并发提取`},
|
||||
]}/>
|
||||
<Sec3Item
|
||||
icon={`s1-2`} title={`长期静态IP池`} terms={[
|
||||
{icon: `s1-check`, text: `IP覆盖全国各地`},
|
||||
{icon: `s1-check`, text: `平均响应时长:0.03s`},
|
||||
]}/>
|
||||
{icon: `s1-check`, text: `IP覆盖全国各地`},
|
||||
{icon: `s1-check`, text: `平均响应时长:0.03s`},
|
||||
]}/>
|
||||
<Sec3Item
|
||||
icon={`s1-3`} title={`固定IP池`} terms={[
|
||||
{icon: `s1-check`, text: `稳定长输不掉线`},
|
||||
{icon: `s1-check`, text: `全国热门静态IP线路`},
|
||||
]}/>
|
||||
{icon: `s1-check`, text: `稳定长输不掉线`},
|
||||
{icon: `s1-check`, text: `全国热门静态IP线路`},
|
||||
]}/>
|
||||
<Sec3Item
|
||||
icon={`s1-4`} title={`企业级定制池`} terms={[
|
||||
{icon: `s1-check`, text: `可视化监控设计`},
|
||||
{icon: `s1-check`, text: `技术团队现场支持`},
|
||||
]}/>
|
||||
{icon: `s1-check`, text: `可视化监控设计`},
|
||||
{icon: `s1-check`, text: `技术团队现场支持`},
|
||||
]}/>
|
||||
</ul>
|
||||
</Section>
|
||||
|
||||
|
||||
BIN
src/app/admin/(dashboard)/_assets/Mask group.webp
Normal file
BIN
src/app/admin/(dashboard)/_assets/Mask group.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
121
src/app/admin/(dashboard)/_client/charts.tsx
Normal file
121
src/app/admin/(dashboard)/_client/charts.tsx
Normal file
@@ -0,0 +1,121 @@
|
||||
'use client'
|
||||
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"
|
||||
import DashboardChart from "./chart"
|
||||
import Image from 'next/image'
|
||||
import soon from '../_assets/coming-soon.svg'
|
||||
import DatePicker from "@/components/date-picker"
|
||||
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"
|
||||
import { Form, FormField } from "@/components/ui/form"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { useForm } from "react-hook-form"
|
||||
import zod from 'zod'
|
||||
import {merge} from '@/lib/utils'
|
||||
import mask from '../_assets/Mask group.webp'
|
||||
import {Button} from '@/components/ui/button'
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export default function Charts() {
|
||||
|
||||
const data = [
|
||||
{ time: `2023-10-01`, count: 100 },
|
||||
{ time: `2023-10-02`, count: 50 },
|
||||
{ time: `2023-10-03`, count: 80 },
|
||||
{ time: `2023-10-04`, count: 200 },
|
||||
{ time: `2023-10-05`, count: 150 },
|
||||
]
|
||||
const formSchema = zod.object({
|
||||
name: zod.string(),
|
||||
age: zod.string(),
|
||||
})
|
||||
|
||||
type FormValues = zod.infer<typeof formSchema>
|
||||
|
||||
const form = useForm<FormValues>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
name: '',
|
||||
age: '',
|
||||
},
|
||||
})
|
||||
|
||||
return (
|
||||
<Card className={`col-start-1 row-start-3 col-span-3 row-span-2`}>
|
||||
<CardContent className={`overflow-hidden`}>
|
||||
<Tabs defaultValue={`dynamic`} className="h-full gap-4">
|
||||
<TabsList>
|
||||
<TabsTrigger value={`dynamic`} className={`data-[state=active]:text-primary`}>
|
||||
{/* <Image src={mask} alt={`Mask group`} width={35} height={35} priority /> */}
|
||||
动态 IP 套餐</TabsTrigger>
|
||||
<TabsTrigger value={`static`} className={`data-[state=active]:text-primary`}>静态 IP 套餐</TabsTrigger>
|
||||
</TabsList>
|
||||
<Form
|
||||
// className="space-y-6"
|
||||
form={form}
|
||||
className={merge(
|
||||
`grid grid-cols-3 gap-4 items-start`,
|
||||
)}
|
||||
>
|
||||
<FormField
|
||||
name="username"
|
||||
label={<span className={`w-full flex justify-end`}>套餐编号</span>}
|
||||
className={`grid grid-cols-[70px_1fr] grid-rows-[auto_auto] `}
|
||||
classNames={{
|
||||
message: `col-start-2`,
|
||||
}}
|
||||
>
|
||||
{({ field }) => (
|
||||
<Input {...field} className={`w-52`}/>
|
||||
)}
|
||||
</FormField>
|
||||
<div className={`flex items-center `} >
|
||||
<FormField
|
||||
name={`create_after`}
|
||||
label={<span className={`w-full flex justify-end`}>时间范围筛选</span>}
|
||||
className={`grid grid-cols-[100px_1fr] `}
|
||||
classNames={{
|
||||
message: `col-start-2`,
|
||||
}}
|
||||
>
|
||||
{({ field }) => (
|
||||
<DatePicker
|
||||
{...field}
|
||||
className={`w-36`}
|
||||
placeholder={`开始时间`}
|
||||
format={`yyyy-MM-dd`}
|
||||
/>
|
||||
)}
|
||||
</FormField>
|
||||
<span className={`px-1`}>-</span>
|
||||
<FormField name={`create_before`}>
|
||||
{({ field }) => (
|
||||
<DatePicker
|
||||
{...field}
|
||||
className={`w-36`}
|
||||
placeholder={`结束时间`}
|
||||
format={`yyyy-MM-dd`}
|
||||
/>
|
||||
)}
|
||||
</FormField>
|
||||
<Button className={'h-9 w-20'} type="submit">
|
||||
<span>查询</span>
|
||||
</Button>
|
||||
</div>
|
||||
</Form>
|
||||
<TabsContent value={`dynamic`} className={`overflow-hidden`}>
|
||||
<DashboardChart />
|
||||
</TabsContent>
|
||||
<TabsContent value={`static`} className={`flex flex-col items-center justify-center gap-2`}>
|
||||
<Image alt={`coming soon`} src={soon} />
|
||||
<p>敬请期待</p>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
76
src/app/admin/(dashboard)/_client/pins.tsx
Normal file
76
src/app/admin/(dashboard)/_client/pins.tsx
Normal file
@@ -0,0 +1,76 @@
|
||||
'use client'
|
||||
import Image from 'next/image'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import soon from '../_assets/coming-soon.svg'
|
||||
import mask from '../_assets/Mask group.webp'
|
||||
|
||||
|
||||
|
||||
export default function Pins() {
|
||||
|
||||
|
||||
return <>
|
||||
|
||||
{/* 短效 */}
|
||||
<Card className={`col-start-1 row-start-2 py-4`}>
|
||||
<CardHeader>
|
||||
<CardTitle><Image src={mask} alt={`Mask group`} width={35} height={35} priority /> 短效动态套餐</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className={`flex-auto flex flex-col gap-2`}>
|
||||
<div className={`flex-1 flex items-center justify-between`}>
|
||||
<h4>包时</h4>
|
||||
<p className={`flex flex-col items-end`}>
|
||||
<span className={`text-sm text-weak`}>当日可提取数量</span>
|
||||
<span className={`text-lg`}>todo</span>
|
||||
</p>
|
||||
</div>
|
||||
<div className={`border-b`}></div>
|
||||
<div className={`flex-1 flex items-center justify-between`}>
|
||||
<h4>包量</h4>
|
||||
<p className={`flex flex-col items-end`}>
|
||||
<span className={`text-sm text-weak`}>剩余可提取数量</span>
|
||||
<span className={`text-lg`}>todo</span>
|
||||
</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* 长效 */}
|
||||
<Card className={`col-start-2 row-start-2`}>
|
||||
<CardHeader>
|
||||
<CardTitle><Image src={mask} alt={`Mask group`} width={35} height={35} priority /> 长效动态套餐</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className={`flex-auto flex flex-col gap-2`}>
|
||||
{/* <Image alt={`coming soon`} src={soon} />
|
||||
<p>敬请期待</p> */}
|
||||
<div className={`flex-1 flex items-center justify-between`}>
|
||||
<h4>包时</h4>
|
||||
<p className={`flex flex-col items-end`}>
|
||||
<span className={`text-sm text-weak`}>当日可提取数量</span>
|
||||
<span className={`text-lg`}>todo</span>
|
||||
</p>
|
||||
</div>
|
||||
<div className={`border-b`}></div>
|
||||
<div className={`flex-1 flex items-center justify-between`}>
|
||||
<h4>包量</h4>
|
||||
<p className={`flex flex-col items-end`}>
|
||||
<span className={`text-sm text-weak`}>剩余可提取数量</span>
|
||||
<span className={`text-lg`}>todo</span>
|
||||
</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* 固定 */}
|
||||
<Card className={`col-start-3 row-start-2 py-4`}>
|
||||
<CardHeader className={`px-4`}>
|
||||
<CardTitle>固定IP套餐</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className={`flex-auto flex flex-col gap-2 items-center justify-center`}>
|
||||
<Image alt={`coming soon`} src={soon} />
|
||||
<p>敬请期待</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</>
|
||||
}
|
||||
|
||||
17
src/app/admin/(dashboard)/layout.tsx
Normal file
17
src/app/admin/(dashboard)/layout.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
import { ReactNode } from 'react'
|
||||
import { Metadata } from 'next'
|
||||
|
||||
export async function generateMetadata(): Promise<Metadata> {
|
||||
return {
|
||||
title: '账户总览 - 蓝狐代理',
|
||||
}
|
||||
}
|
||||
|
||||
export type BillsLayoutProps = {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export default async function BillsLayout(props: BillsLayoutProps) {
|
||||
return props.children
|
||||
}
|
||||
@@ -1,26 +1,24 @@
|
||||
import Page from '@/components/page'
|
||||
import Image from 'next/image'
|
||||
import {Card, CardContent, CardHeader, CardTitle} from '@/components/ui/card'
|
||||
import {Tabs, TabsContent, TabsList, TabsTrigger} from '@/components/ui/tabs'
|
||||
import {getProfile} from '@/actions/auth'
|
||||
import {format} from 'date-fns'
|
||||
import {CheckCircleIcon, CircleAlertIcon} from 'lucide-react'
|
||||
import {Button, buttonVariants} from '@/components/ui/button'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { getProfile } from '@/actions/auth'
|
||||
import { format } from 'date-fns'
|
||||
import { CheckCircleIcon, CircleAlertIcon } from 'lucide-react'
|
||||
import { Button, buttonVariants } from '@/components/ui/button'
|
||||
import RechargeModal from '@/components/composites/recharge'
|
||||
import {merge} from '@/lib/utils'
|
||||
|
||||
import { merge } from '@/lib/utils'
|
||||
import banner from './_assets/banner.webp'
|
||||
import soon from './_assets/coming-soon.svg'
|
||||
import actionBill from './_assets/action-bill.webp'
|
||||
import actionBuy from './_assets/action-buy.webp'
|
||||
import actionLogout from './_assets/action-logout.webp'
|
||||
import Link from 'next/link'
|
||||
import {listAnnouncements} from '@/actions/announcement'
|
||||
import DashboardChart from './_client/chart'
|
||||
import { listAnnouncements } from '@/actions/announcement'
|
||||
import Charts from './_client/charts'
|
||||
import Pins from './_client/pins'
|
||||
|
||||
export type DashboardPageProps = {}
|
||||
|
||||
export default async function DashboardPage(props: DashboardPageProps) {
|
||||
export default function DashboardPage(props: DashboardPageProps) {
|
||||
return (
|
||||
<Page className={merge(
|
||||
`flex-auto grid`,
|
||||
@@ -29,7 +27,7 @@ export default async function DashboardPage(props: DashboardPageProps) {
|
||||
)}>
|
||||
{/* banner */}
|
||||
<section className={`col-start-1 row-start-1 col-span-3 relative rounded-lg overflow-hidden`}>
|
||||
<Image src={banner} alt={`banner image`} className={`w-full h-full inset-0 absolute object-cover`}/>
|
||||
<Image src={banner} alt={`banner image`} className={`w-full h-full inset-0 absolute object-cover`} />
|
||||
<div className={`flex flex-col absolute inset-0 justify-center px-8 gap-1`}>
|
||||
<h3 className={`text-2xl text-primary font-medium`}>代理IP资源,先测后买</h3>
|
||||
<p className={`text-primary font-medium`}>短效/长效/固定IP代理,一站式服务</p>
|
||||
@@ -37,103 +35,21 @@ export default async function DashboardPage(props: DashboardPageProps) {
|
||||
</section>
|
||||
|
||||
{/* 磁贴集 */}
|
||||
<Pins/>
|
||||
<Pins />
|
||||
|
||||
{/* 图表 */}
|
||||
<Charts/>
|
||||
<Charts />
|
||||
|
||||
{/* 信息 */}
|
||||
<UserCenter/>
|
||||
<UserCenter />
|
||||
|
||||
{/* 通知 */}
|
||||
<Announcements/>
|
||||
<Announcements />
|
||||
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
|
||||
async function Pins() {
|
||||
return <>
|
||||
{/* 短效 */}
|
||||
<Card className={`col-start-1 row-start-2 py-4`}>
|
||||
<CardHeader>
|
||||
<CardTitle>短效动态套餐</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className={`flex-auto flex flex-col gap-2`}>
|
||||
<div className={`flex-1 flex items-center justify-between`}>
|
||||
<h4>包时</h4>
|
||||
<p className={`flex flex-col items-end`}>
|
||||
<span className={`text-sm text-weak`}>当日可提取数量</span>
|
||||
<span className={`text-lg`}>todo</span>
|
||||
</p>
|
||||
</div>
|
||||
<div className={`border-b`}></div>
|
||||
<div className={`flex-1 flex items-center justify-between`}>
|
||||
<h4>包量</h4>
|
||||
<p className={`flex flex-col items-end`}>
|
||||
<span className={`text-sm text-weak`}>剩余可提取数量</span>
|
||||
<span className={`text-lg`}>todo</span>
|
||||
</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* 长效 */}
|
||||
<Card className={`col-start-2 row-start-2`}>
|
||||
<CardHeader>
|
||||
<CardTitle>长效动态套餐</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className={`flex-auto flex flex-col gap-2 items-center justify-center`}>
|
||||
<Image alt={`coming soon`} src={soon}/>
|
||||
<p>敬请期待</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* 固定 */}
|
||||
<Card className={`col-start-3 row-start-2 py-4`}>
|
||||
<CardHeader className={`px-4`}>
|
||||
<CardTitle>固定IP套餐</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className={`flex-auto flex flex-col gap-2 items-center justify-center`}>
|
||||
<Image alt={`coming soon`} src={soon}/>
|
||||
<p>敬请期待</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</>
|
||||
}
|
||||
|
||||
async function Charts() {
|
||||
|
||||
const data = [
|
||||
{time: `2023-10-01`, count: 100},
|
||||
{time: `2023-10-02`, count: 50},
|
||||
{time: `2023-10-03`, count: 80},
|
||||
{time: `2023-10-04`, count: 200},
|
||||
{time: `2023-10-05`, count: 150},
|
||||
]
|
||||
|
||||
return (
|
||||
<Card className={`col-start-1 row-start-3 col-span-3 row-span-2`}>
|
||||
<CardContent className={`overflow-hidden`}>
|
||||
<Tabs defaultValue={`dynamic`} className="h-full gap-4">
|
||||
<TabsList>
|
||||
<TabsTrigger value={`dynamic`} className={`data-[state=active]:text-primary`}>动态 IP 套餐</TabsTrigger>
|
||||
<TabsTrigger value={`static`} className={`data-[state=active]:text-primary`}>静态 IP 套餐</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value={`dynamic`} className={`overflow-hidden`}>
|
||||
<DashboardChart/>
|
||||
</TabsContent>
|
||||
<TabsContent value={`static`} className={`flex flex-col items-center justify-center gap-2`}>
|
||||
<Image alt={`coming soon`} src={soon}/>
|
||||
<p>敬请期待</p>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
async function UserCenter() {
|
||||
|
||||
const resp = await getProfile()
|
||||
@@ -160,7 +76,7 @@ async function UserCenter() {
|
||||
{profile.id_token
|
||||
? <>
|
||||
<div className={`flex gap-2 items-center`}>
|
||||
<CheckCircleIcon size={20} className={`text-done`}/>
|
||||
<CheckCircleIcon size={20} className={`text-done`} />
|
||||
<span>已实名</span>
|
||||
</div>
|
||||
<div className={`flex flex-col items-end`}>
|
||||
@@ -170,7 +86,7 @@ async function UserCenter() {
|
||||
</>
|
||||
: <>
|
||||
<span className={`flex gap-2 items-center`}>
|
||||
<CircleAlertIcon className={`text-warn`}/>
|
||||
<CircleAlertIcon className={`text-warn`} />
|
||||
<span>未实名</span>
|
||||
</span>
|
||||
<Button className={`h-9`}>去实名</Button>
|
||||
@@ -181,22 +97,22 @@ async function UserCenter() {
|
||||
<h4 className={`text-sm text-weak`}>账户余额</h4>
|
||||
<div className={`flex justify-between items-baseline`}>
|
||||
<p className={`text-xl text-accent`}>¥{profile.balance}</p>
|
||||
<RechargeModal/>
|
||||
<RechargeModal />
|
||||
</div>
|
||||
</div>
|
||||
<div className={`flex flex-col gap-3`}>
|
||||
<h4 className={`text-sm text-weak`}>快捷入口</h4>
|
||||
<div className={`flex justify-around gap-2`}>
|
||||
<Link href="/admin/bills" className={merge(buttonVariants({variant: `ghost`}), `flex flex-col gap-2 py-2 px-3 h-auto`)}>
|
||||
<Image alt={`bill icon`} src={actionBill} height={48}/>
|
||||
<Link href="/admin/bills" className={merge(buttonVariants({ variant: `ghost` }), `flex flex-col gap-2 py-2 px-3 h-auto`)}>
|
||||
<Image alt={`bill icon`} src={actionBill} height={48} />
|
||||
<span className={`text-sm text-weak`}>我的帐单</span>
|
||||
</Link>
|
||||
<Link href="/admin/purchase" className={merge(buttonVariants({variant: `ghost`}), `flex flex-col gap-2 py-2 px-3 h-auto`)}>
|
||||
<Image alt={`buy icon`} src={actionBuy} height={48}/>
|
||||
<Link href="/admin/purchase" className={merge(buttonVariants({ variant: `ghost` }), `flex flex-col gap-2 py-2 px-3 h-auto`)}>
|
||||
<Image alt={`buy icon`} src={actionBuy} height={48} />
|
||||
<span className={`text-sm text-weak`}>购买产品</span>
|
||||
</Link>
|
||||
<Link href="/admin/profile" className={merge(buttonVariants({variant: `ghost`}), `flex flex-col gap-2 py-2 px-3 h-auto`)}>
|
||||
<Image alt={`logout icon`} src={actionLogout} height={48}/>
|
||||
<Link href="/admin/profile" className={merge(buttonVariants({ variant: `ghost` }), `flex flex-col gap-2 py-2 px-3 h-auto`)}>
|
||||
<Image alt={`logout icon`} src={actionLogout} height={48} />
|
||||
<span className={`text-sm text-weak`}>个人中心</span>
|
||||
</Link>
|
||||
</div>
|
||||
@@ -225,14 +141,17 @@ async function Announcements() {
|
||||
return (
|
||||
<Card className={`col-start-4 row-start-3 row-span-2`}>
|
||||
<CardHeader>
|
||||
<CardTitle>公告</CardTitle>
|
||||
<div className={`flex justify-between gap-2`}>
|
||||
<CardTitle>公告</CardTitle>
|
||||
<span className={`text-sm text-weak`}>查看更多</span>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className={`flex-auto p-0`}>
|
||||
{announcements.length === 0
|
||||
? (
|
||||
<div className={`flex flex-col items-center justify-center gap-2 h-full`}>
|
||||
<Image alt={`coming soon`} src={soon}/>
|
||||
<p>暂无公告</p>
|
||||
{/* <Image alt={`coming soon`} src={soon} />
|
||||
<p>暂无公告</p> */}
|
||||
</div>
|
||||
)
|
||||
: announcements.map(item => (
|
||||
|
||||
@@ -7,9 +7,22 @@ import Image from 'next/image'
|
||||
import logoAvatar from '../_assets/logo-avatar.svg'
|
||||
import logoText from '../_assets/logo-text.svg'
|
||||
import {Tooltip, TooltipContent, TooltipProvider, TooltipTrigger} from '@/components/ui/tooltip'
|
||||
import { UserRound } from 'lucide-react'
|
||||
import { UserRoundPen } from 'lucide-react'
|
||||
import { IdCard } from 'lucide-react'
|
||||
import { LockKeyhole } from 'lucide-react'
|
||||
import { Wallet } from 'lucide-react'
|
||||
import { ShoppingCart } from 'lucide-react'
|
||||
import { Package } from 'lucide-react'
|
||||
import { HardDriveUpload } from 'lucide-react'
|
||||
import { Eye } from 'lucide-react'
|
||||
import { Archive } from 'lucide-react'
|
||||
import { ArchiveRestore } from 'lucide-react'
|
||||
|
||||
|
||||
export type NavbarProps = {}
|
||||
|
||||
|
||||
export default function Navbar(props: NavbarProps) {
|
||||
|
||||
const navbar = useLayoutStore(store => store.navbar)
|
||||
@@ -43,20 +56,20 @@ export default function Navbar(props: NavbarProps) {
|
||||
`group-data-[expand=true]:px-4 group-data-[expand=false]:px-3`,
|
||||
)}>
|
||||
<TooltipProvider>
|
||||
<NavItem href={'/admin'} icon={`🏠`} label={`账户总览`} expand={navbar}/>
|
||||
<NavItem href={'/admin'} icon={<UserRound size={20}/>} label={`账户总览`} expand={navbar}/>
|
||||
<NavTitle label={`个人信息`}/>
|
||||
<NavItem href={`/admin/profile`} icon={`📝`} label={`个人中心`} expand={navbar}/>
|
||||
<NavItem href={`/admin/identify`} icon={`🆔`} label={`实名认证`} expand={navbar}/>
|
||||
<NavItem href={`/admin/whitelist`} icon={`🔒`} label={`白名单`} expand={navbar}/>
|
||||
<NavItem href={`/admin/bills`} icon={`💰`} label={`我的账单`} expand={navbar}/>
|
||||
<NavItem href={`/admin/profile`} icon={<UserRoundPen size={20}/>} label={`个人中心`} expand={navbar}/>
|
||||
<NavItem href={`/admin/identify`} icon={<IdCard size={20}/>} label={`实名认证`} expand={navbar}/>
|
||||
<NavItem href={`/admin/whitelist`} icon={<LockKeyhole size={20}/>} label={`白名单`} expand={navbar}/>
|
||||
<NavItem href={`/admin/bills`} icon={<Wallet size={20}/>} label={`我的账单`} expand={navbar}/>
|
||||
<NavTitle label={`套餐管理`}/>
|
||||
<NavItem href={`/admin/purchase`} icon={`🛒`} label={`购买套餐`} expand={navbar}/>
|
||||
<NavItem href={`/admin/resources`} icon={`📦`} label={`套餐管理`} expand={navbar}/>
|
||||
<NavItem href={`/admin/purchase`} icon={<ShoppingCart size={20}/>} label={`购买套餐`} expand={navbar}/>
|
||||
<NavItem href={`/admin/resources`} icon={<Package size={20}/>} label={`套餐管理`} expand={navbar}/>
|
||||
<NavTitle label={`IP 管理`}/>
|
||||
<NavItem href={`/admin/extract`} icon={`📤`} label={`提取 IP`} expand={navbar}/>
|
||||
<NavItem href={`/admin/channels`} icon={`👁️`} label={`IP 管理`} expand={navbar}/>
|
||||
<NavItem href={`/admin`} icon={`📜`} label={`提取记录`} expand={navbar}/>
|
||||
<NavItem href={`/admin`} icon={`🗂️`} label={`使用记录`} expand={navbar}/>
|
||||
<NavItem href={`/admin/extract`} icon={<HardDriveUpload size={20}/>} label={`提取 IP`} expand={navbar}/>
|
||||
<NavItem href={`/admin/channels`} icon={<Eye size={20}/>} label={`IP 管理`} expand={navbar}/>
|
||||
<NavItem href={`/admin`} icon={<Archive size={20}/>} label={`提取记录`} expand={navbar}/>
|
||||
<NavItem href={`/admin`} icon={<ArchiveRestore size={20}/>} label={`使用记录`} expand={navbar}/>
|
||||
</TooltipProvider>
|
||||
</section>
|
||||
</nav>
|
||||
|
||||
17
src/app/admin/bills/layout.tsx
Normal file
17
src/app/admin/bills/layout.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
import { ReactNode } from 'react'
|
||||
import { Metadata } from 'next'
|
||||
|
||||
export async function generateMetadata(): Promise<Metadata> {
|
||||
return {
|
||||
title: '我的账单 - 蓝狐代理',
|
||||
}
|
||||
}
|
||||
|
||||
export type BillsLayoutProps = {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export default async function BillsLayout(props: BillsLayoutProps) {
|
||||
return props.children
|
||||
}
|
||||
17
src/app/admin/channels/layout.tsx
Normal file
17
src/app/admin/channels/layout.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
import { ReactNode } from 'react'
|
||||
import { Metadata } from 'next'
|
||||
|
||||
export async function generateMetadata(): Promise<Metadata> {
|
||||
return {
|
||||
title: 'IP管理 - 蓝狐代理',
|
||||
}
|
||||
}
|
||||
|
||||
export type ChannelsLayoutProps = {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export default async function ChannelsLayout(props: ChannelsLayoutProps) {
|
||||
return props.children
|
||||
}
|
||||
17
src/app/admin/extract/layout.tsx
Normal file
17
src/app/admin/extract/layout.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
import { ReactNode } from 'react'
|
||||
import { Metadata } from 'next'
|
||||
|
||||
export async function generateMetadata(): Promise<Metadata> {
|
||||
return {
|
||||
title: '提取IP - 蓝狐代理',
|
||||
}
|
||||
}
|
||||
|
||||
export type ExtractLayoutProps = {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export default async function ExtractLayout(props: ExtractLayoutProps) {
|
||||
return props.children
|
||||
}
|
||||
16
src/app/admin/identify/layout.tsx
Normal file
16
src/app/admin/identify/layout.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import { ReactNode } from 'react'
|
||||
import { Metadata } from 'next'
|
||||
|
||||
export async function generateMetadata(): Promise<Metadata> {
|
||||
return {
|
||||
title: '实名认证 - 蓝狐代理',
|
||||
}
|
||||
}
|
||||
|
||||
export type IdentifyLayoutProps = {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export default async function IdentifyLayout(props: IdentifyLayoutProps) {
|
||||
return props.children
|
||||
}
|
||||
17
src/app/admin/profile/layout.tsx
Normal file
17
src/app/admin/profile/layout.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
import { ReactNode } from 'react'
|
||||
import { Metadata } from 'next'
|
||||
|
||||
export async function generateMetadata(): Promise<Metadata> {
|
||||
return {
|
||||
title: '个人中心 - 蓝狐代理',
|
||||
}
|
||||
}
|
||||
|
||||
export type ProfileLayoutProps = {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export default async function ProfileLayout(props: ProfileLayoutProps) {
|
||||
return props.children
|
||||
}
|
||||
17
src/app/admin/purchase/layout.tsx
Normal file
17
src/app/admin/purchase/layout.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
import { ReactNode } from 'react'
|
||||
import { Metadata } from 'next'
|
||||
|
||||
export async function generateMetadata(): Promise<Metadata> {
|
||||
return {
|
||||
title: '购买套餐 - 蓝狐代理',
|
||||
}
|
||||
}
|
||||
|
||||
export type PurchaseLayoutProps = {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export default async function PurchaseLayout(props: PurchaseLayoutProps) {
|
||||
return props.children
|
||||
}
|
||||
17
src/app/admin/resources/layout.tsx
Normal file
17
src/app/admin/resources/layout.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
import { ReactNode } from 'react'
|
||||
import { Metadata } from 'next'
|
||||
|
||||
export async function generateMetadata(): Promise<Metadata> {
|
||||
return {
|
||||
title: '套餐管理 - 蓝狐代理',
|
||||
}
|
||||
}
|
||||
|
||||
export type ResourcesLayoutProps = {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export default async function ResourcesLayout(props: ResourcesLayoutProps) {
|
||||
return props.children
|
||||
}
|
||||
17
src/app/admin/whitelist/layout.tsx
Normal file
17
src/app/admin/whitelist/layout.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
import { ReactNode } from 'react'
|
||||
import { Metadata } from 'next'
|
||||
|
||||
export async function generateMetadata(): Promise<Metadata> {
|
||||
return {
|
||||
title: '白名单 - 蓝狐代理',
|
||||
}
|
||||
}
|
||||
|
||||
export type WhitelistLayoutProps = {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export default async function WhitelistLayout(props: WhitelistLayoutProps) {
|
||||
return props.children
|
||||
}
|
||||
@@ -13,8 +13,7 @@ const font = localFont({
|
||||
|
||||
export async function generateMetadata(): Promise<Metadata> {
|
||||
return {
|
||||
title: 'Create Next App',
|
||||
description: 'Generated by create next app',
|
||||
title: '蓝狐代理',
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user