mirror of
https://github.com/NovaOSS/nova-betterchat.git
synced 2024-11-25 20:34:00 +01:00
feat: folder colors (#191)
This commit is contained in:
parent
892e7792ba
commit
4823b1dc38
17
src/assets/icons/ColorPaletteIcon.tsx
Normal file
17
src/assets/icons/ColorPaletteIcon.tsx
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const ColorPaletteIcon = (props: React.SVGProps<SVGSVGElement>) => {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
viewBox='0 0 24 24'
|
||||||
|
fill='currentColor'
|
||||||
|
height='1em'
|
||||||
|
width='1em'
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<path d='M12 22A10 10 0 012 12 10 10 0 0112 2c5.5 0 10 4 10 9a6 6 0 01-6 6h-1.8c-.3 0-.5.2-.5.5 0 .1.1.2.1.3.4.5.6 1.1.6 1.7.1 1.4-1 2.5-2.4 2.5m0-18a8 8 0 00-8 8 8 8 0 008 8c.3 0 .5-.2.5-.5 0-.2-.1-.3-.1-.4-.4-.5-.6-1-.6-1.6 0-1.4 1.1-2.5 2.5-2.5H16a4 4 0 004-4c0-3.9-3.6-7-8-7m-5.5 6c.8 0 1.5.7 1.5 1.5S7.3 13 6.5 13 5 12.3 5 11.5 5.7 10 6.5 10m3-4c.8 0 1.5.7 1.5 1.5S10.3 9 9.5 9 8 8.3 8 7.5 8.7 6 9.5 6m5 0c.8 0 1.5.7 1.5 1.5S15.3 9 14.5 9 13 8.3 13 7.5 13.7 6 14.5 6m3 4c.8 0 1.5.7 1.5 1.5s-.7 1.5-1.5 1.5-1.5-.7-1.5-1.5.7-1.5 1.5-1.5z' />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ColorPaletteIcon;
|
|
@ -14,6 +14,10 @@ import EditIcon from '@icon/EditIcon';
|
||||||
import DeleteIcon from '@icon/DeleteIcon';
|
import DeleteIcon from '@icon/DeleteIcon';
|
||||||
import CrossIcon from '@icon/CrossIcon';
|
import CrossIcon from '@icon/CrossIcon';
|
||||||
import TickIcon from '@icon/TickIcon';
|
import TickIcon from '@icon/TickIcon';
|
||||||
|
import ColorPaletteIcon from '@icon/ColorPaletteIcon';
|
||||||
|
import RefreshIcon from '@icon/RefreshIcon';
|
||||||
|
|
||||||
|
import { folderColorOptions } from '@constants/color';
|
||||||
|
|
||||||
const ChatFolder = ({
|
const ChatFolder = ({
|
||||||
folderChats,
|
folderChats,
|
||||||
|
@ -24,16 +28,19 @@ const ChatFolder = ({
|
||||||
}) => {
|
}) => {
|
||||||
const folderName = useStore((state) => state.folders[folderId].name);
|
const folderName = useStore((state) => state.folders[folderId].name);
|
||||||
const isExpanded = useStore((state) => state.folders[folderId].expanded);
|
const isExpanded = useStore((state) => state.folders[folderId].expanded);
|
||||||
|
const color = useStore((state) => state.folders[folderId].color);
|
||||||
|
|
||||||
const setChats = useStore((state) => state.setChats);
|
const setChats = useStore((state) => state.setChats);
|
||||||
const setFolders = useStore((state) => state.setFolders);
|
const setFolders = useStore((state) => state.setFolders);
|
||||||
|
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
|
const folderRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const [_folderName, _setFolderName] = useState<string>(folderName);
|
const [_folderName, _setFolderName] = useState<string>(folderName);
|
||||||
const [isEdit, setIsEdit] = useState<boolean>(false);
|
const [isEdit, setIsEdit] = useState<boolean>(false);
|
||||||
const [isDelete, setIsDelete] = useState<boolean>(false);
|
const [isDelete, setIsDelete] = useState<boolean>(false);
|
||||||
const [isHover, setIsHover] = useState<boolean>(false);
|
const [isHover, setIsHover] = useState<boolean>(false);
|
||||||
|
const [showPalette, setShowPalette] = useState<boolean>(false);
|
||||||
|
|
||||||
const editTitle = () => {
|
const editTitle = () => {
|
||||||
const updatedFolders: FolderCollection = JSON.parse(
|
const updatedFolders: FolderCollection = JSON.parse(
|
||||||
|
@ -62,6 +69,16 @@ const ChatFolder = ({
|
||||||
setIsDelete(false);
|
setIsDelete(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const updateColor = (_color?: string) => {
|
||||||
|
const updatedFolders: FolderCollection = JSON.parse(
|
||||||
|
JSON.stringify(useStore.getState().folders)
|
||||||
|
);
|
||||||
|
if (_color) updatedFolders[folderId].color = _color;
|
||||||
|
else delete updatedFolders[folderId].color;
|
||||||
|
setFolders(updatedFolders);
|
||||||
|
setShowPalette(false);
|
||||||
|
};
|
||||||
|
|
||||||
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||||
if (e.key === 'Enter') {
|
if (e.key === 'Enter') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
@ -133,8 +150,20 @@ const ChatFolder = ({
|
||||||
onDragLeave={handleDragLeave}
|
onDragLeave={handleDragLeave}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className='flex py-3 px-3 items-center gap-3 relative rounded-md hover:bg-gray-850 break-all cursor-pointer'
|
style={{ background: color || '' }}
|
||||||
|
className={`${
|
||||||
|
color ? '' : 'hover:bg-gray-850'
|
||||||
|
} transition-colors flex py-3 px-3 items-center gap-3 relative rounded-md break-all cursor-pointer`}
|
||||||
onClick={toggleExpanded}
|
onClick={toggleExpanded}
|
||||||
|
ref={folderRef}
|
||||||
|
onMouseEnter={() => {
|
||||||
|
if (color && folderRef.current)
|
||||||
|
folderRef.current.style.background = `${color}dd`;
|
||||||
|
}}
|
||||||
|
onMouseLeave={() => {
|
||||||
|
if (color && folderRef.current)
|
||||||
|
folderRef.current.style.background = color;
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<FolderIcon className='h-4 w-4' />
|
<FolderIcon className='h-4 w-4' />
|
||||||
<div className='flex-1 text-ellipsis max-h-5 overflow-hidden break-all relative'>
|
<div className='flex-1 text-ellipsis max-h-5 overflow-hidden break-all relative'>
|
||||||
|
@ -169,6 +198,40 @@ const ChatFolder = ({
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
<div className='relative'>
|
||||||
|
<button
|
||||||
|
className='p-1 hover:text-white'
|
||||||
|
onClick={() => {
|
||||||
|
setShowPalette((prev) => !prev);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ColorPaletteIcon />
|
||||||
|
</button>
|
||||||
|
{showPalette && (
|
||||||
|
<div className='absolute left-0 bottom-0 translate-y-full p-2 z-20 bg-gray-900 rounded border border-gray-600 flex flex-col gap-2 items-center'>
|
||||||
|
<>
|
||||||
|
{folderColorOptions.map((c) => (
|
||||||
|
<button
|
||||||
|
key={c}
|
||||||
|
style={{ background: c }}
|
||||||
|
className={`hover:scale-90 transition-transform h-4 w-4 rounded-full`}
|
||||||
|
onClick={() => {
|
||||||
|
updateColor(c);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
updateColor();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<RefreshIcon />
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
className='p-1 hover:text-white'
|
className='p-1 hover:text-white'
|
||||||
onClick={() => setIsEdit(true)}
|
onClick={() => setIsEdit(true)}
|
||||||
|
|
7
src/constants/color.ts
Normal file
7
src/constants/color.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
export const folderColorOptions = [
|
||||||
|
'#be123c', // rose-700
|
||||||
|
'#6d28d9', // violet-700
|
||||||
|
'#0369a1', // sky-700
|
||||||
|
'#047857', // emerald-700
|
||||||
|
'#b45309', // amber-700
|
||||||
|
];
|
Loading…
Reference in a new issue