📝 Docs: 添加商店表单支持 (#2460)

Co-authored-by: Ju4tCode <42488585+yanyongyu@users.noreply.github.com>
This commit is contained in:
StarHeart
2023-11-22 14:04:22 +08:00
committed by GitHub
parent af9327de14
commit ef882927f3
20 changed files with 972 additions and 18 deletions

View File

@ -0,0 +1,157 @@
import React, { useEffect, useState } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
// @ts-expect-error: we need to make package have type: module
import copy from "copy-text-to-clipboard";
import { PyPIData } from "./types";
import Tag from "@/components/Resource/Tag";
import type { Resource } from "@/libs/store";
import "./styles.css";
export type Props = {
resource: Resource;
};
export default function ResourceDetailCard({ resource }: Props) {
const [pypiData, setPypiData] = useState<PyPIData | null>(null);
const [copied, setCopied] = useState<boolean>(false);
const authorLink = `https://github.com/${resource.author}`;
const authorAvatar = `${authorLink}.png?size=100`;
const getProjectLink = (resource: Resource) => {
switch (resource.resourceType) {
case "plugin":
case "adapter":
case "driver":
return resource.project_link;
default:
return null;
}
};
const getModuleName = (resource: Resource) => {
switch (resource.resourceType) {
case "plugin":
case "adapter":
return resource.module_name;
case "driver":
return resource.module_name.replace(/~/, "nonebot.drivers.");
default:
return null;
}
};
const fetchPypiProject = (projectName: string) =>
fetch(`https://pypi.org/pypi/${projectName}/json`)
.then((response) => response.json())
.then((data) => setPypiData(data));
const copyCommand = (resource: Resource) => {
const projectLink = getProjectLink(resource);
if (projectLink) {
copy(`nb ${resource.resourceType} install ${projectLink}`);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
}
};
useEffect(() => {
const fetchingTasks: Promise<void>[] = [];
if (resource.resourceType === "bot" || resource.resourceType === "driver")
return;
if (resource.project_link)
fetchingTasks.push(fetchPypiProject(resource.project_link));
Promise.all(fetchingTasks);
}, [resource]);
const projectLink = getProjectLink(resource) || "无";
const moduleName = getModuleName(resource) || "无";
return (
<>
<div className="detail-card-header">
<img
src={authorAvatar}
className="detail-card-avatar"
decoding="async"
></img>
<div className="detail-card-title">
<span className="detail-card-title-main">{resource.name}</span>
<span className="detail-card-title-sub">{resource.author}</span>
</div>
<button
className="detail-card-copy-button detail-card-copy-button-desktop"
onClick={() => copyCommand(resource)}
>
{copied ? "复制成功" : "复制安装命令"}
</button>
</div>
<div className="detail-card-body">
<div className="detail-card-body-left">
<span className="h-full">{resource.desc}</span>
<div className="resource-card-footer-tags mb-4">
{resource.tags.map((tag, index) => (
<Tag className="align-bottom" key={index} {...tag} />
))}
</div>
</div>
<div className="detail-card-body-divider" />
<div className="detail-card-body-right">
<div className="detail-card-meta-item">
<span>
<FontAwesomeIcon fixedWidth icon={["fab", "python"]} />{" "}
{(pypiData && pypiData.info.requires_python) || "无"}
</span>
</div>
<div className="detail-card-meta-item">
<FontAwesomeIcon fixedWidth icon={["fas", "file-zipper"]} />{" "}
{(pypiData &&
pypiData.releases[pypiData.info.version] &&
`${
pypiData.releases[pypiData.info.version].reduce(
(acc, curr) => acc + curr.size,
0
) / 1000
}K`) ||
"无"}
</div>
<div className="detail-card-meta-item">
<span>
<FontAwesomeIcon
className="fa-fw"
icon={["fas", "scale-balanced"]}
/>{" "}
{(pypiData && pypiData.info.license) || "无"}
</span>
</div>
<div className="detail-card-meta-item">
<FontAwesomeIcon fixedWidth icon={["fas", "tag"]} />{" "}
{(pypiData && pypiData.info.version) || "无"}
</div>
<div className="detail-card-meta-item">
<FontAwesomeIcon fixedWidth icon={["fas", "fingerprint"]} />{" "}
<span>{moduleName}</span>
</div>
<div className="detail-card-meta-item">
<FontAwesomeIcon fixedWidth icon={["fas", "cubes"]} />{" "}
<span>{projectLink}</span>
</div>
<button
className="detail-card-copy-button detail-card-copy-button-mobile w-full"
onClick={() => copyCommand(resource)}
>
{copied ? "复制成功" : "复制安装命令"}
</button>
</div>
</div>
</>
);
}

View File

@ -0,0 +1,53 @@
.detail-card {
&-header {
@apply flex items-center align-middle;
}
&-avatar {
@apply mr-3 w-12 h-12 rounded-full;
}
&-title {
@apply inline-flex flex-col h-12 justify-start;
&-main {
@apply font-bold;
}
&-sub {
@apply text-sm;
}
}
&-copy-button {
@apply ml-auto btn btn-sm;
&-mobile {
@apply lg:hidden;
}
&-desktop {
@apply max-lg:hidden;
}
}
&-body {
@apply flex flex-col w-full lg:flex-row;
&-left {
@apply flex flex-col min-h-[150px] lg:basis-3/4;
}
&-divider {
@apply divider lg:divider-horizontal;
}
&-right {
@apply flex flex-col justify-start gap-y-2 lg:basis-1/4;
}
}
&-meta-item {
@apply text-sm whitespace-nowrap;
}
}

View File

@ -0,0 +1,64 @@
export type Downloads = {
last_day: number;
last_month: number;
last_week: number;
};
export type Info = {
author: string;
author_email: string;
bugtrack_url: null;
classifiers: string[];
description: string;
description_content_type: string;
docs_url: null;
download_url: string;
downloads: Downloads;
home_page: string;
keywords: string;
license: string;
maintainer: string;
maintainer_email: string;
name: string;
package_url: string;
platform: null;
project_url: string;
release_url: string;
requires_dist: string[];
requires_python: string;
summary: string;
version: string;
yanked: boolean;
yanked_reason: null;
};
export interface Digests {
blake2b_256: string;
md5: string;
sha256: string;
}
export type Releases = {
comment_text: string;
digests: Digests;
downloads: number;
filename: string;
has_sig: boolean;
md5_digest: string;
packagetype: string;
python_version: string;
requires_python: string;
size: number;
upload_time: Date;
upload_time_iso_8601: Date;
url: string;
yanked: boolean;
yanked_reason: null;
};
export type PyPIData = {
info: Info;
last_serial: number;
releases: { [key: string]: Releases[] };
urls: URL[];
vulnerabilities: unknown[];
};