mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2026-03-01 16:20:25 +00:00
Added a new CommandPalette component for quick API selection and execution (Ctrl/Cmd+K). Refactored the HTTP debug page to use the command palette, improved tab and panel UI, and enhanced the code editor's appearance and theme integration. Updated OneBotApiDebug to support imperative methods for request body and sending, improved response panel resizing, and made various UI/UX refinements across related components.
112 lines
4.0 KiB
TypeScript
112 lines
4.0 KiB
TypeScript
import { Button } from '@heroui/button';
|
|
import { useLocalStorage } from '@uidotdev/usehooks';
|
|
import clsx from 'clsx';
|
|
import { AnimatePresence, motion } from 'motion/react';
|
|
import React from 'react';
|
|
import { IoMdLogOut } from 'react-icons/io';
|
|
import { MdDarkMode, MdLightMode } from 'react-icons/md';
|
|
|
|
import key from '@/const/key';
|
|
import useAuth from '@/hooks/auth';
|
|
import useDialog from '@/hooks/use-dialog';
|
|
import { useTheme } from '@/hooks/use-theme';
|
|
import type { MenuItem } from '@/config/site';
|
|
|
|
import Menus from './menus';
|
|
|
|
interface SideBarProps {
|
|
open: boolean;
|
|
items: MenuItem[];
|
|
onClose?: () => void;
|
|
}
|
|
|
|
const SideBar: React.FC<SideBarProps> = (props) => {
|
|
const { open, items, onClose } = props;
|
|
const { toggleTheme, isDark } = useTheme();
|
|
const { revokeAuth } = useAuth();
|
|
const dialog = useDialog();
|
|
const [backgroundImage] = useLocalStorage<string>(key.backgroundImage, '');
|
|
const hasBackground = !!backgroundImage;
|
|
|
|
const onRevokeAuth = () => {
|
|
dialog.confirm({
|
|
title: '退出登录',
|
|
content: '确定要退出登录吗?',
|
|
onConfirm: revokeAuth,
|
|
});
|
|
};
|
|
return (
|
|
<>
|
|
<AnimatePresence initial={false}>
|
|
{open && (
|
|
<motion.div
|
|
className='fixed inset-y-0 left-64 right-0 bg-black/20 backdrop-blur-[1px] z-40 md:hidden'
|
|
aria-hidden='true'
|
|
onClick={onClose}
|
|
initial={{ opacity: 0 }}
|
|
animate={{ opacity: 1 }}
|
|
exit={{ opacity: 0, transition: { duration: 0.15 } }}
|
|
transition={{ duration: 0.2, delay: 0.15 }}
|
|
/>
|
|
)}
|
|
</AnimatePresence>
|
|
<motion.div
|
|
className={clsx(
|
|
'overflow-hidden fixed top-0 left-0 h-full z-50 md:static md:shadow-none rounded-r-2xl md:rounded-none',
|
|
hasBackground
|
|
? 'bg-transparent backdrop-blur-md'
|
|
: 'bg-content1/70 backdrop-blur-xl backdrop-saturate-150 shadow-xl',
|
|
'md:bg-transparent md:backdrop-blur-none md:backdrop-saturate-100 md:shadow-none'
|
|
)}
|
|
initial={{ width: 0 }}
|
|
animate={{ width: open ? '16rem' : 0 }}
|
|
transition={{
|
|
type: open ? 'spring' : 'tween',
|
|
stiffness: 150,
|
|
damping: open ? 15 : 10,
|
|
}}
|
|
style={{ overflow: 'hidden' }}
|
|
>
|
|
<motion.div className='w-64 flex flex-col items-stretch h-full transition-transform duration-300 ease-in-out z-30 relative float-right p-4'>
|
|
<div className='flex items-center justify-start gap-3 px-2 my-8 ml-2'>
|
|
<div className="h-5 w-1 bg-primary rounded-full shadow-sm" />
|
|
<div className={clsx(
|
|
"text-xl font-bold tracking-wide select-none",
|
|
hasBackground ? 'text-white' : 'text-default-900 dark:text-white'
|
|
)}>
|
|
NapCat
|
|
</div>
|
|
</div>
|
|
<div className='overflow-y-auto flex flex-col flex-1 px-2'>
|
|
<Menus items={items} />
|
|
<div className='mt-auto mb-10 md:mb-0 space-y-3 px-2'>
|
|
<Button
|
|
className='w-full bg-primary-50/50 hover:bg-primary-100/80 text-primary-600 font-medium shadow-sm hover:shadow-md transition-all duration-300 backdrop-blur-sm'
|
|
radius='full'
|
|
variant='flat'
|
|
onPress={toggleTheme}
|
|
startContent={
|
|
!isDark ? <MdLightMode size={18} /> : <MdDarkMode size={18} />
|
|
}
|
|
>
|
|
切换主题
|
|
</Button>
|
|
<Button
|
|
className='w-full mb-2 bg-danger-50/50 hover:bg-danger-100/80 text-danger-500 font-medium shadow-sm hover:shadow-md transition-all duration-300 backdrop-blur-sm'
|
|
radius='full'
|
|
variant='flat'
|
|
onPress={onRevokeAuth}
|
|
startContent={<IoMdLogOut size={18} />}
|
|
>
|
|
退出登录
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</motion.div>
|
|
</motion.div>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default SideBar;
|