mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2026-02-04 06:31:13 +00:00
Merge 0301421bc8 into 9377dc3d52
This commit is contained in:
commit
2fae571298
@ -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>
|
||||
|
||||
@ -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}
|
||||
>
|
||||
|
||||
@ -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>
|
||||
);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user