📝 Docs: 为商店插件卡片添加更多展示内容 (#2626)

This commit is contained in:
Azide 2024-04-06 20:07:09 +08:00 committed by GitHub
parent 16fb5ac121
commit 983351f0b7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 148 additions and 18 deletions

View File

@ -7,6 +7,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import "./styles.css"; import "./styles.css";
import Tag from "@/components/Resource/Tag"; import Tag from "@/components/Resource/Tag";
import ValidStatus from "@/components/Resource/ValidStatus";
import type { Resource } from "@/libs/store"; import type { Resource } from "@/libs/store";
export type Props = { export type Props = {
@ -39,7 +40,7 @@ export default function ResourceCard({
return ( return (
<div className={clsx("resource-card-container", className)}> <div className={clsx("resource-card-container", className)}>
<div className="resource-card-header"> <div className="resource-card-header">
<div className="resource-card-header-title"> <div className="resource-card-header-title flex items-center">
{resource.name} {resource.name}
{resource.is_official && ( {resource.is_official && (
<FontAwesomeIcon <FontAwesomeIcon
@ -47,6 +48,11 @@ export default function ResourceCard({
icon={["fas", "circle-check"]} icon={["fas", "circle-check"]}
/> />
)} )}
<ValidStatus
resource={resource}
validLink={registryLink as string}
simple
/>
</div> </div>
<div className="resource-card-header-expand" onClick={onClick}> <div className="resource-card-header-expand" onClick={onClick}>
<FontAwesomeIcon icon={["fas", "expand"]} /> <FontAwesomeIcon icon={["fas", "expand"]} />

View File

@ -14,7 +14,7 @@
} }
&-check { &-check {
@apply ml-2 text-success w-5 h-5 fill-current; @apply ml-2 text-success/90 fill-current;
} }
&-expand { &-expand {

View File

@ -7,6 +7,7 @@ import copy from "copy-text-to-clipboard";
import { PyPIData } from "./types"; import { PyPIData } from "./types";
import Tag from "@/components/Resource/Tag"; import Tag from "@/components/Resource/Tag";
import ValidStatus from "@/components/Resource/ValidStatus";
import type { Resource } from "@/libs/store"; import type { Resource } from "@/libs/store";
import "./styles.css"; import "./styles.css";
@ -22,6 +23,11 @@ export default function ResourceDetailCard({ resource }: Props) {
const authorLink = `https://github.com/${resource.author}`; const authorLink = `https://github.com/${resource.author}`;
const authorAvatar = `${authorLink}.png?size=100`; const authorAvatar = `${authorLink}.png?size=100`;
const isPlugin = resource.resourceType === "plugin";
const registryLink =
isPlugin &&
`https://registry.nonebot.dev/plugin/${resource.project_link}:${resource.module_name}`;
const getProjectLink = (resource: Resource) => { const getProjectLink = (resource: Resource) => {
switch (resource.resourceType) { switch (resource.resourceType) {
case "plugin": case "plugin":
@ -60,7 +66,6 @@ export default function ResourceDetailCard({ resource }: Props) {
switch (resource.resourceType) { switch (resource.resourceType) {
case "plugin": case "plugin":
case "adapter": case "adapter":
case "driver":
return `https://pypi.org/project/${resource.project_link}`; return `https://pypi.org/project/${resource.project_link}`;
default: default:
return null; return null;
@ -106,7 +111,14 @@ export default function ResourceDetailCard({ resource }: Props) {
decoding="async" decoding="async"
/> />
<div className="detail-card-title"> <div className="detail-card-title">
<span className="detail-card-title-main">{resource.name}</span> <span className="detail-card-title-main flex items-center gap-x-1">
{resource.name}
{resource.is_official && (
<div className="rounded-md text-sm bg-success/10 text-success px-1 py-0.5">
</div>
)}
</span>
<a <a
className="detail-card-title-sub hover:underline hover:text-primary" className="detail-card-title-sub hover:underline hover:text-primary"
target="_blank" target="_blank"
@ -116,13 +128,21 @@ export default function ResourceDetailCard({ resource }: Props) {
{resource.author} {resource.author}
</a> </a>
</div> </div>
<button <div className="detail-card-actions">
className="detail-card-copy-button detail-card-copy-button-desktop" <ValidStatus
onClick={() => copyCommand(resource)} resource={resource}
> validLink={registryLink as string}
{copied ? "复制成功" : "复制安装命令"} className="detail-card-actions-desktop"
</button> />
<button
className="detail-card-actions-button detail-card-actions-desktop w-28"
onClick={() => copyCommand(resource)}
>
{copied ? "复制成功" : "复制安装命令"}
</button>
</div>
</div> </div>
<div className="divider detail-card-header-divider"></div>
<div className="detail-card-body"> <div className="detail-card-body">
<div className="detail-card-body-left"> <div className="detail-card-body-left">
<span className="h-full">{resource.desc}</span> <span className="h-full">{resource.desc}</span>
@ -192,12 +212,19 @@ export default function ResourceDetailCard({ resource }: Props) {
{projectLink} {projectLink}
</a> </a>
</div> </div>
<button <div className="detail-card-actions">
className="detail-card-copy-button detail-card-copy-button-mobile w-full" <ValidStatus
onClick={() => copyCommand(resource)} resource={resource}
> validLink={registryLink as string}
{copied ? "复制成功" : "复制安装命令"} className="detail-card-actions-mobile"
</button> />
<button
className="detail-card-actions detail-card-actions-button detail-card-actions-mobile w-28"
onClick={() => copyCommand(resource)}
>
{copied ? "复制成功" : "复制安装命令"}
</button>
</div>
</div> </div>
</div> </div>
</> </>

View File

@ -1,6 +1,10 @@
.detail-card { .detail-card {
&-header { &-header {
@apply flex items-center align-middle; @apply flex items-center align-middle;
&-divider {
@apply m-0;
}
} }
&-avatar { &-avatar {
@ -19,8 +23,12 @@
} }
} }
&-copy-button { &-actions {
@apply ml-auto btn btn-sm; @apply flex items-center gap-x-2 ml-auto;
&-button {
@apply btn btn-sm;
}
&-mobile { &-mobile {
@apply lg:hidden; @apply lg:hidden;

View File

@ -0,0 +1,83 @@
import React from "react";
import clsx from "clsx";
import type { IconName } from "@fortawesome/fontawesome-common-types";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Resource } from "@/libs/store";
import { ValidStatus } from "@/libs/valid";
export const getValidStatus = (resource: Resource) => {
switch (resource.resourceType) {
case "plugin":
if (resource.skip_test) return ValidStatus.SKIP;
if (resource.valid) return ValidStatus.VALID;
return ValidStatus.INVALID;
default:
return ValidStatus.MISSING;
}
};
export const validIcons: {
[key in ValidStatus]: IconName;
} = {
[ValidStatus.VALID]: "plug-circle-check",
[ValidStatus.INVALID]: "plug-circle-xmark",
[ValidStatus.SKIP]: "plug-circle-exclamation",
[ValidStatus.MISSING]: "plug-circle-exclamation",
};
export type Props = {
resource: Resource;
validLink: string;
className?: string;
simple?: boolean;
};
export default function ValidDisplay({
resource,
validLink,
className,
simple,
}: Props) {
const validStatus = getValidStatus(resource);
const isValid = validStatus === ValidStatus.VALID;
const isInvalid = validStatus === ValidStatus.INVALID;
const isSkip = validStatus === ValidStatus.SKIP;
return (
validStatus !== ValidStatus.MISSING && (
<a
target="_blank"
rel="noreferrer"
href={validLink}
className={className}
>
<div
className={clsx({
"rounded-md text-sm flex items-center gap-x-1 px-2 py-1 whitespace-nowrap":
!simple,
"ml-2": simple,
"bg-success/10": !simple && isValid,
"text-success/90": isValid,
"bg-error/10": !simple && isInvalid,
"text-error/90": isInvalid,
"bg-info/10": !simple && isSkip,
"text-info/90": isSkip,
})}
>
<FontAwesomeIcon icon={validIcons[validStatus]} />
{!simple && (
<>
{isValid && <p></p>}
{isInvalid && <p></p>}
{isSkip && <p></p>}
</>
)}
</div>
</a>
)
);
}

View File

@ -0,0 +1,6 @@
export enum ValidStatus {
VALID = "valid",
INVALID = "invalid",
SKIP = "skip",
MISSING = "missing",
}