catapi-web/components/api-docs.tsx
2024-11-07 12:37:00 +08:00

389 lines
13 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { useState, useEffect } from "react";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Badge } from "@/components/ui/badge";
import { Skeleton } from "@/components/ui/skeleton";
import { motion } from "framer-motion";
import { ExternalLink, GitCommit } from "lucide-react";
export default function ApiDocsComponent() {
const [activePage, setActivePage] = useState("home");
const [imageCount, setImageCount] = useState<number | null>(null);
const [announcements, setAnnouncements] = useState<
Array<{ date: string; content: string }>
>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchData = async () => {
setLoading(true);
try {
const [imageCountResponse, announcementsResponse] = await Promise.all([
fetch("/?api=total-pic"),
fetch("/?api=announcements"),
]);
const imageCountData = await imageCountResponse.json();
const announcementsData = await announcementsResponse.json();
setImageCount(imageCountData.count);
setAnnouncements(announcementsData.announcements);
} catch (error) {
console.error("Failed to fetch data:", error);
setImageCount(null);
setAnnouncements([]);
} finally {
setLoading(false);
}
};
fetchData();
}, []);
const apiEndpoints = [
{
id: 1,
device: "手机",
method: "GET",
url: "/phone",
description: "竖屏随机图片API",
},
{
id: 2,
device: "电脑",
method: "GET",
url: "/pc",
description: "横屏随机图片API",
},
{
id: 3,
device: "All",
method: "GET",
url: "/favicon",
description: "获取本站favicon",
},
{
id: 4,
device: "All",
method: "GET",
url: "/bj",
description: "获取静态页面装饰图",
},
{
id: 5,
device: "All",
method: "GET",
url: "/fox",
description: "获取狐狸图",
},
];
const parameters = [
{
id: 1,
param: "time",
value: "Boolean",
description: "是否区分时段默认为false",
},
{
id: 2,
param: "mode",
value: "String",
description:
"填json则返回一串数组填redirect则会重定向至图片URL不填则返回一张图片",
},
{
id: 3,
param: "source",
value: "Boolean",
description: "是否使用原图(加载较慢)默认为true",
},
];
const returnData = [
{ id: 1, data: "code", description: "状态码" },
{ id: 2, data: "image_url", description: "图片地址" },
{ id: 3, data: "time", description: "是否分时段" },
{ id: 4, data: "endpoint_type", description: "适用设备" },
{ id: 5, data: "is_source", description: "是否为原图" },
{ id: 6, data: "mode", description: "输出模式" },
];
const friendlyLinks = [
{ name: "mei的网络日志", url: "https://mmeiblog.cn" }
];
const HomePage = () => (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
className="space-y-6"
>
<Card className="bg-white shadow-lg rounded-lg overflow-hidden">
<CardHeader className="bg-gradient-to-r from-purple-500 to-pink-500 text-white">
<CardTitle className="text-2xl font-bold"></CardTitle>
</CardHeader>
<CardContent className="p-6">
<p className="text-gray-700">
使{" "}
<code className="bg-gray-100 p-1 rounded text-pink-600 font-mono">
Cat API
</code>
, mei
</p>
<p className="mt-4 text-gray-600">
</p>
<p className="mt-4 text-gray-600">
API有什么不完善的地方或者说你有什么更好的想{" "}
<a
href="mailto:i@mmeiblog.cn"
className="text-blue-600 hover:underline"
>
i@mmeiblog.cn
</a>
</p>
</CardContent>
</Card>
<Card className="bg-white shadow-lg rounded-lg overflow-hidden">
<CardHeader className="bg-gradient-to-r from-green-500 to-teal-500 text-white">
<CardTitle className="text-2xl font-bold"></CardTitle>
</CardHeader>
<CardContent className="p-6">
{loading ? (
<Skeleton className="h-20 w-full" />
) : announcements.length > 0 ? (
announcements.map((announcement, index) => (
<div
key={index}
className="mb-4 last:mb-0 bg-gray-50 p-4 rounded-lg"
>
<Badge
variant="outline"
className="bg-teal-100 text-teal-800 mb-2"
>
{announcement.date}
</Badge>
<p className="text-gray-700">{announcement.content}</p>
</div>
))
) : (
<p className="text-gray-500 italic"></p>
)}
</CardContent>
</Card>
<Card className="bg-white shadow-lg rounded-lg overflow-hidden">
<CardHeader className="bg-gradient-to-r from-blue-500 to-indigo-500 text-white">
<CardTitle className="text-2xl font-bold"></CardTitle>
</CardHeader>
<CardContent className="p-6">
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4">
{friendlyLinks.map((link, index) => (
<a
key={index}
href={link.url}
target="_blank"
rel="noopener noreferrer"
className="flex items-center p-4 bg-gray-50 rounded-lg shadow-sm hover:shadow-md transition-shadow duration-200 hover:bg-gray-100"
>
<ExternalLink className="w-5 h-5 mr-2 text-indigo-500" />
<span className="text-indigo-600 hover:underline">
{link.name}
</span>
</a>
))}
</div>
</CardContent>
</Card>
</motion.div>
);
const RandomImagePage = () => (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
className="space-y-8"
>
<Card className="bg-white shadow-lg rounded-lg overflow-hidden">
<CardHeader className="bg-gradient-to-r from-yellow-400 to-orange-500 text-white">
<CardTitle className="text-2xl font-bold"> API</CardTitle>
</CardHeader>
<CardContent className="p-6">
<p className="text-gray-700">
API
</p>
<p className="mt-4 text-gray-600">
:{" "}
{loading ? (
<Skeleton className="h-4 w-[100px] inline-block ml-2" />
) : (
<Badge
variant="secondary"
className="ml-2 bg-orange-100 text-orange-800"
>
{imageCount !== null ? imageCount : "获取失败"}
</Badge>
)}
</p>
</CardContent>
</Card>
<Tabs
defaultValue="endpoints"
className="bg-white shadow-lg rounded-lg overflow-hidden"
>
<TabsList className="grid w-full grid-cols-3 bg-gradient-to-r from-purple-500 to-pink-500 p-1 gap-1">
<TabsTrigger
value="endpoints"
className="text-white data-[state=active]:bg-white data-[state=active]:text-purple-500"
>
API
</TabsTrigger>
<TabsTrigger
value="parameters"
className="text-white data-[state=active]:bg-white data-[state=active]:text-purple-500"
>
</TabsTrigger>
<TabsTrigger
value="returnData"
className="text-white data-[state=active]:bg-white data-[state=active]:text-purple-500"
>
</TabsTrigger>
</TabsList>
<TabsContent value="endpoints" className="p-6">
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-[50px]">#</TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{apiEndpoints.map((endpoint) => (
<TableRow key={endpoint.id}>
<TableCell>{endpoint.id}</TableCell>
<TableCell>{endpoint.device}</TableCell>
<TableCell>{endpoint.method}</TableCell>
<TableCell>{endpoint.url}</TableCell>
<TableCell>{endpoint.description}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TabsContent>
<TabsContent value="parameters" className="p-6">
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-[50px]">#</TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{parameters.map((param) => (
<TableRow key={param.id}>
<TableCell>{param.id}</TableCell>
<TableCell>{param.param}</TableCell>
<TableCell>{param.value}</TableCell>
<TableCell>{param.description}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TabsContent>
<TabsContent value="returnData" className="p-6">
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-[50px]">#</TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{returnData.map((data) => (
<TableRow key={data.id}>
<TableCell>{data.id}</TableCell>
<TableCell>{data.data}</TableCell>
<TableCell>{data.description}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TabsContent>
</Tabs>
</motion.div>
);
return (
<div className="flex flex-col min-h-screen bg-gray-100">
<div className="flex flex-1">
<nav className="w-64 bg-white shadow-md">
<div className="p-6">
<h1 className="text-2xl font-bold mb-6 text-gray-800">
Cat API
</h1>
<ul className="space-y-2">
<li>
<Button
variant={activePage === "home" ? "default" : "ghost"}
className="w-full justify-start text-left"
onClick={() => setActivePage("home")}
>
</Button>
</li>
<li>
<Button
variant={activePage === "random-image" ? "default" : "ghost"}
className="w-full justify-start text-left"
onClick={() => setActivePage("random-image")}
>
</Button>
</li>
</ul>
</div>
</nav>
<main className="flex-1 p-8 overflow-auto">
{activePage === "home" ? <HomePage /> : <RandomImagePage />}
</main>
</div>
<footer className="bg-white shadow-md mt-8">
<div className="container mx-auto px-6 py-4">
<div className="flex justify-between items-center">
<p className="text-gray-600">
&copy; 2024 mei. All rights reserved.
</p>
<div className="flex items-center text-gray-500">
<GitCommit className="w-5 h-5 mr-2" />
<span className="text-sm">{process.env.NEXT_PUBLIC_BUILD_ID || 'dev'}</span>
</div>
</div>
</div>
</footer>
</div>
);
}