mirror of
				https://github.com/nonebot/nonebot2.git
				synced 2025-10-31 15:06:42 +00:00 
			
		
		
		
	📝 Docs: 为商店插件卡片添加更多展示内容 (#2626)
This commit is contained in:
		| @@ -7,6 +7,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; | ||||
|  | ||||
| import "./styles.css"; | ||||
| import Tag from "@/components/Resource/Tag"; | ||||
| import ValidStatus from "@/components/Resource/ValidStatus"; | ||||
| import type { Resource } from "@/libs/store"; | ||||
|  | ||||
| export type Props = { | ||||
| @@ -39,7 +40,7 @@ export default function ResourceCard({ | ||||
|   return ( | ||||
|     <div className={clsx("resource-card-container", className)}> | ||||
|       <div className="resource-card-header"> | ||||
|         <div className="resource-card-header-title"> | ||||
|         <div className="resource-card-header-title flex items-center"> | ||||
|           {resource.name} | ||||
|           {resource.is_official && ( | ||||
|             <FontAwesomeIcon | ||||
| @@ -47,6 +48,11 @@ export default function ResourceCard({ | ||||
|               icon={["fas", "circle-check"]} | ||||
|             /> | ||||
|           )} | ||||
|           <ValidStatus | ||||
|             resource={resource} | ||||
|             validLink={registryLink as string} | ||||
|             simple | ||||
|           /> | ||||
|         </div> | ||||
|         <div className="resource-card-header-expand" onClick={onClick}> | ||||
|           <FontAwesomeIcon icon={["fas", "expand"]} /> | ||||
|   | ||||
| @@ -14,7 +14,7 @@ | ||||
|     } | ||||
|  | ||||
|     &-check { | ||||
|       @apply ml-2 text-success w-5 h-5 fill-current; | ||||
|       @apply ml-2 text-success/90 fill-current; | ||||
|     } | ||||
|  | ||||
|     &-expand { | ||||
|   | ||||
| @@ -7,6 +7,7 @@ import copy from "copy-text-to-clipboard"; | ||||
| import { PyPIData } from "./types"; | ||||
|  | ||||
| import Tag from "@/components/Resource/Tag"; | ||||
| import ValidStatus from "@/components/Resource/ValidStatus"; | ||||
| import type { Resource } from "@/libs/store"; | ||||
|  | ||||
| import "./styles.css"; | ||||
| @@ -22,6 +23,11 @@ export default function ResourceDetailCard({ resource }: Props) { | ||||
|   const authorLink = `https://github.com/${resource.author}`; | ||||
|   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) => { | ||||
|     switch (resource.resourceType) { | ||||
|       case "plugin": | ||||
| @@ -60,7 +66,6 @@ export default function ResourceDetailCard({ resource }: Props) { | ||||
|     switch (resource.resourceType) { | ||||
|       case "plugin": | ||||
|       case "adapter": | ||||
|       case "driver": | ||||
|         return `https://pypi.org/project/${resource.project_link}`; | ||||
|       default: | ||||
|         return null; | ||||
| @@ -106,7 +111,14 @@ export default function ResourceDetailCard({ resource }: Props) { | ||||
|           decoding="async" | ||||
|         /> | ||||
|         <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 | ||||
|             className="detail-card-title-sub hover:underline hover:text-primary" | ||||
|             target="_blank" | ||||
| @@ -116,13 +128,21 @@ export default function ResourceDetailCard({ resource }: Props) { | ||||
|             {resource.author} | ||||
|           </a> | ||||
|         </div> | ||||
|         <button | ||||
|           className="detail-card-copy-button detail-card-copy-button-desktop" | ||||
|           onClick={() => copyCommand(resource)} | ||||
|         > | ||||
|           {copied ? "复制成功" : "复制安装命令"} | ||||
|         </button> | ||||
|         <div className="detail-card-actions"> | ||||
|           <ValidStatus | ||||
|             resource={resource} | ||||
|             validLink={registryLink as string} | ||||
|             className="detail-card-actions-desktop" | ||||
|           /> | ||||
|           <button | ||||
|             className="detail-card-actions-button detail-card-actions-desktop w-28" | ||||
|             onClick={() => copyCommand(resource)} | ||||
|           > | ||||
|             {copied ? "复制成功" : "复制安装命令"} | ||||
|           </button> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div className="divider detail-card-header-divider"></div> | ||||
|       <div className="detail-card-body"> | ||||
|         <div className="detail-card-body-left"> | ||||
|           <span className="h-full">{resource.desc}</span> | ||||
| @@ -192,12 +212,19 @@ export default function ResourceDetailCard({ resource }: Props) { | ||||
|               {projectLink} | ||||
|             </a> | ||||
|           </div> | ||||
|           <button | ||||
|             className="detail-card-copy-button detail-card-copy-button-mobile w-full" | ||||
|             onClick={() => copyCommand(resource)} | ||||
|           > | ||||
|             {copied ? "复制成功" : "复制安装命令"} | ||||
|           </button> | ||||
|           <div className="detail-card-actions"> | ||||
|             <ValidStatus | ||||
|               resource={resource} | ||||
|               validLink={registryLink as string} | ||||
|               className="detail-card-actions-mobile" | ||||
|             /> | ||||
|             <button | ||||
|               className="detail-card-actions detail-card-actions-button detail-card-actions-mobile w-28" | ||||
|               onClick={() => copyCommand(resource)} | ||||
|             > | ||||
|               {copied ? "复制成功" : "复制安装命令"} | ||||
|             </button> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </> | ||||
|   | ||||
| @@ -1,6 +1,10 @@ | ||||
| .detail-card { | ||||
|   &-header { | ||||
|     @apply flex items-center align-middle; | ||||
|  | ||||
|     &-divider { | ||||
|       @apply m-0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   &-avatar { | ||||
| @@ -19,8 +23,12 @@ | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   &-copy-button { | ||||
|     @apply ml-auto btn btn-sm; | ||||
|   &-actions { | ||||
|     @apply flex items-center gap-x-2 ml-auto; | ||||
|  | ||||
|     &-button { | ||||
|       @apply btn btn-sm; | ||||
|     } | ||||
|  | ||||
|     &-mobile { | ||||
|       @apply lg:hidden; | ||||
|   | ||||
							
								
								
									
										83
									
								
								website/src/components/Resource/ValidStatus/index.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								website/src/components/Resource/ValidStatus/index.tsx
									
									
									
									
									
										Normal 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> | ||||
|     ) | ||||
|   ); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user