This commit is contained in:
Qiao 2026-01-31 22:15:54 +08:00 committed by GitHub
commit 2fae571298
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 78 additions and 64 deletions

View File

@ -4,7 +4,7 @@ import clsx from 'clsx';
import key from '@/const/key';
export interface ContainerProps {
title: string;
title: React.ReactNode;
tag?: React.ReactNode;
action: React.ReactNode;
enableSwitch: React.ReactNode;
@ -22,6 +22,7 @@ export interface DisplayCardProps {
const DisplayCardContainer: React.FC<ContainerProps> = ({
title: _title,
tag,
action,
enableSwitch,
children,
@ -39,13 +40,15 @@ const DisplayCardContainer: React.FC<ContainerProps> = ({
>
<CardHeader className='p-4 pb-2 flex items-center justify-between gap-3'>
<div className='flex-1 min-w-0 mr-2'>
<div className='inline-flex items-center px-3 py-1 rounded-lg bg-default-100/50 dark:bg-white/10 border border-transparent dark:border-white/5'>
<span className='font-bold text-default-600 dark:text-white/90 text-sm truncate select-text'>
{/* 限制标题区域最大宽度并隐藏溢出,确保 long title 能正确截断显示省略号 */}
<div className='inline-flex items-center px-3 py-1 rounded-lg bg-default-100/50 dark:bg-white/10 border border-transparent dark:border-white/5 max-w-full overflow-hidden'>
<span className='block font-bold text-default-600 dark:text-white/90 text-sm truncate select-text whitespace-nowrap'>
{_title}
</span>
</div>
</div>
<div className='flex-shrink-0'>{enableSwitch}</div>
{tag && <div className='flex-shrink-0'>{tag}</div>}
{enableSwitch && <div className='flex-shrink-0'>{enableSwitch}</div>}
</CardHeader>
<CardBody className='px-4 py-2 text-sm text-default-600'>{children}</CardBody>
<CardFooter className='px-4 pb-4 pt-2'>{action}</CardFooter>

View File

@ -1,6 +1,7 @@
import { Button } from '@heroui/button';
import { Switch } from '@heroui/switch';
import { Chip } from '@heroui/chip';
import { Tooltip } from '@heroui/tooltip';
import { useState } from 'react';
import { MdDeleteForever, MdSettings } from 'react-icons/md';
@ -41,28 +42,27 @@ const PluginDisplayCard: React.FC<PluginDisplayCardProps> = ({
<DisplayCardContainer
className='w-full max-w-[420px]'
action={
<div className='flex flex-col gap-2 w-full'>
<div className='flex gap-2 w-full'>
<div className='flex gap-2 w-full'>
<Tooltip content="卸载">
<Button
fullWidth
isIconOnly
radius='full'
size='sm'
variant='flat'
className='flex-1 bg-default-100 dark:bg-default-50 text-default-600 font-medium hover:bg-danger/20 hover:text-danger transition-colors'
startContent={<MdDeleteForever size={16} />}
className='bg-default-100 dark:bg-default-50 text-default-600 hover:bg-danger/20 hover:text-danger transition-colors'
onPress={handleUninstall}
isDisabled={processing}
>
<MdDeleteForever size={16} />
</Button>
</div>
</Tooltip>
{hasConfig && (
<Button
fullWidth
radius='full'
size='sm'
variant='flat'
className='bg-default-100 dark:bg-default-50 text-default-600 font-medium hover:bg-secondary/20 hover:text-secondary transition-colors'
className='flex-1 bg-default-100 dark:bg-default-50 text-default-600 font-medium hover:bg-secondary/20 hover:text-secondary transition-colors'
startContent={<MdSettings size={16} />}
onPress={onConfig}
>

View File

@ -1,6 +1,8 @@
import { Button } from '@heroui/button';
import { Chip } from '@heroui/chip';
import { Tooltip } from '@heroui/tooltip';
import { useState } from 'react';
import clsx from 'clsx';
import { IoMdDownload, IoMdRefresh, IoMdCheckmarkCircle } from 'react-icons/io';
import DisplayCardContainer from './container';
@ -20,8 +22,9 @@ const PluginStoreCard: React.FC<PluginStoreCardProps> = ({
onInstall,
installStatus = 'not-installed',
}) => {
const { name, version, author, description, tags, id } = data;
const { name, version, author, description, tags, id, homepage } = data;
const [processing, setProcessing] = useState(false);
const displayId = id?.replace(/^napcat-plugin-/, '') || id;
const handleInstall = () => {
setProcessing(true);
@ -56,8 +59,24 @@ const PluginStoreCard: React.FC<PluginStoreCardProps> = ({
return (
<DisplayCardContainer
className='w-full max-w-[420px]'
title={name}
className='w-full max-w-[420px] md:max-w-[460px] lg:max-w-[520px] 2xl:max-w-[560px]'
title={
<div className="flex items-baseline gap-2">
{homepage ? (
<Tooltip content="打开插件主页">
<span
className="cursor-pointer hover:text-default-900 dark:hover:text-white transition-colors underline decoration-dashed decoration-default-400/70 underline-offset-4 hover:decoration-default-600"
onClick={() => window.open(homepage, '_blank')}
>
{name}
</span>
</Tooltip>
) : (
<span>{name}</span>
)}
<span className="text-[10px] font-normal text-default-400">v{version}</span>
</div>
}
tag={
<div className="ml-auto flex items-center gap-1">
{installStatus === 'installed' && (
@ -65,7 +84,8 @@ const PluginStoreCard: React.FC<PluginStoreCardProps> = ({
color="success"
size="sm"
variant="flat"
startContent={<IoMdCheckmarkCircle size={14} />}
className="h-6 text-[10px] bg-success-50 dark:bg-success-500/10 text-success-600"
startContent={<IoMdCheckmarkCircle size={12} />}
>
</Chip>
@ -75,17 +95,11 @@ const PluginStoreCard: React.FC<PluginStoreCardProps> = ({
color="warning"
size="sm"
variant="flat"
className="h-6 text-[10px] bg-warning-50 dark:bg-warning-500/10 text-warning-600"
>
</Chip>
)}
<Chip
color="primary"
size="sm"
variant="flat"
>
v{version}
</Chip>
</div>
}
enableSwitch={undefined}
@ -104,51 +118,48 @@ const PluginStoreCard: React.FC<PluginStoreCardProps> = ({
</Button>
}
>
<div className='grid grid-cols-2 gap-3'>
<div className='flex flex-col gap-1 p-3 bg-default-100/50 dark:bg-white/10 rounded-xl border border-transparent hover:border-default-200 transition-colors'>
<span className='text-xs text-default-500 dark:text-white/50 font-medium tracking-wide'>
<div className='flex flex-col gap-2 h-[132px]'>
{/* 作者和包名 */}
<div className='flex items-center gap-2 text-[12px] text-default-400'>
<span className="flex items-center gap-1">
: <span className='text-default-600 dark:text-white/70 font-medium'>{author || '未知'}</span>
</span>
<div className='text-sm font-medium text-default-700 dark:text-white/90 truncate'>
{author || '未知'}
</div>
<span className='text-default-300'>/</span>
<Tooltip content={id}>
<span className='truncate max-w-[160px] opacity-70 italic'>{displayId}</span>
</Tooltip>
</div>
<div className='flex flex-col gap-1 p-3 bg-default-100/50 dark:bg-white/10 rounded-xl border border-transparent hover:border-default-200 transition-colors'>
<span className='text-xs text-default-500 dark:text-white/50 font-medium tracking-wide'>
</span>
<div className='text-sm font-medium text-default-700 dark:text-white/90 truncate'>
v{version}
</div>
</div>
<div className='col-span-2 flex flex-col gap-1 p-3 bg-default-100/50 dark:bg-white/10 rounded-xl border border-transparent hover:border-default-200 transition-colors'>
<span className='text-xs text-default-500 dark:text-white/50 font-medium tracking-wide'>
</span>
<div className='text-sm font-medium text-default-700 dark:text-white/90 break-words line-clamp-2 h-10 overflow-hidden'>
{description || '暂无描述'}
</div>
</div>
{id && (
<div className='flex flex-col gap-1 p-3 bg-default-100/50 dark:bg-white/10 rounded-xl border border-transparent hover:border-default-200 transition-colors'>
<span className='text-xs text-default-500 dark:text-white/50 font-medium tracking-wide'>
</span>
<div className='text-sm font-medium text-default-700 dark:text-white/90 break-words line-clamp-2 h-10 overflow-hidden'>
{id || '包名'}
{/* 描述 */}
<Tooltip content={description || '暂无描述'}>
<div className='h-[62px] p-3 bg-default-100/30 dark:bg-white/5 rounded-xl border border-default-100 dark:border-white/5 flex items-center'>
<div className='text-[14px] leading-relaxed text-default-600 dark:text-white/80 break-words line-clamp-2 text-center w-full'>
{description || '暂无描述'}
</div>
</div>
)}
{tags && tags.length > 0 && (
<div className='flex flex-col gap-1 p-3 bg-default-100/50 dark:bg-white/10 rounded-xl border border-transparent hover:border-default-200 transition-colors'>
<span className='text-xs text-default-500 dark:text-white/50 font-medium tracking-wide'>
</span>
<div className='text-sm font-medium text-default-700 dark:text-white/90 truncate'>
{tags.slice(0, 2).join(' · ')}
</div>
</div>
)}
</Tooltip>
{/* 标签栏 - 优化后的极简风格 */}
<div className='flex flex-wrap gap-1.5 min-h-[20px] items-center pt-1'>
{tags && tags.length > 0 ? (
tags.map((tag, index) => (
<div
key={index}
className="flex items-center gap-1.5 px-2 py-0.5 rounded-full bg-default-100/50 dark:bg-white/10 text-[11px] text-default-500 dark:text-white/60 border border-transparent hover:border-default-200 transition-all"
>
<span className={clsx(
"w-1 h-1 rounded-full",
tag === '官方' ? "bg-secondary-400" :
tag === '工具' ? "bg-primary-400" :
tag === '娱乐' ? "bg-warning-400" : "bg-default-400"
)} />
{tag}
</div>
))
) : (
<span className='text-[10px] text-default-300 italic'>no tags</span>
)}
</div>
</div>
</DisplayCardContainer>
);