-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: implement to be able to edit labels
- Loading branch information
Showing
9 changed files
with
330 additions
and
8 deletions.
There are no files selected for viewing
116 changes: 116 additions & 0 deletions
116
client/src/layout/NotesLayout/ui/NavigationDrawer/ui/LabelDetails.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
import { FC, MouseEvent, useRef, useState } from 'react'; | ||
|
||
import { MdMenu } from '@material/web/all'; | ||
|
||
import { menuItemStyles } from '@pages/Notes/lib/const'; | ||
import cn from '@shared/lib/helpers/cn'; | ||
import ConfirmDialog from '@shared/ui/ConfirmDialog'; | ||
import ContextMenu from '@shared/ui/ContextMenu'; | ||
import FilledTonalIconButton from '@shared/ui/FilledTonalIconButton'; | ||
import Icon from '@shared/ui/Icon'; | ||
import InputDialog from '@shared/ui/InputDialog'; | ||
import MenuItem from '@shared/ui/MenuItem'; | ||
import { useTranslation } from 'react-i18next'; | ||
|
||
type DetailsProps = { | ||
id: number; | ||
}; | ||
|
||
const Details: FC<DetailsProps> = ({ id }) => { | ||
const [isConfirmDialogOpen, setIsConfirmDialogOpen] = useState(false); | ||
const [isDialogRenameOpen, setIsDialogRenameOpen] = useState(false); | ||
const [isContextMenuOpen, setIsContextMenuOpen] = useState(false); | ||
const { t } = useTranslation(); | ||
const menuRef = useRef<MdMenu>(null); | ||
|
||
function handleMenuToggle(e: MouseEvent) { | ||
e.stopPropagation(); | ||
e.preventDefault(); | ||
if (menuRef.current) { | ||
menuRef.current.open = !menuRef.current.open; | ||
|
||
setIsContextMenuOpen(menuRef.current.open); | ||
} | ||
} | ||
|
||
const handleToggleConfirmDialog = (e: MouseEvent) => { | ||
e.stopPropagation(); | ||
e.preventDefault(); | ||
console.log('confirm'); | ||
|
||
setIsConfirmDialogOpen((prev) => !prev); | ||
}; | ||
|
||
const handleDeleteLabel = async (e: MouseEvent) => { | ||
e.stopPropagation(); | ||
}; | ||
|
||
const handleToggleDialogRename = (e: MouseEvent) => { | ||
e.stopPropagation(); | ||
e.preventDefault(); | ||
|
||
console.log('rename'); | ||
setIsDialogRenameOpen((prev) => !prev); | ||
}; | ||
|
||
const handleRenameLabel = async (e: MouseEvent) => { | ||
e.stopPropagation(); | ||
}; | ||
|
||
return ( | ||
<> | ||
<ConfirmDialog | ||
setIsOpen={setIsConfirmDialogOpen} | ||
open={isConfirmDialogOpen} | ||
title={t('deleteDialog.title')} | ||
subtitle={t('deleteDialog.content')} | ||
confirmText={t('deleteDialog.delete')} | ||
cancelText={t('deleteDialog.cancel')} | ||
onCancel={handleToggleConfirmDialog} | ||
onConfirm={handleDeleteLabel} | ||
/> | ||
<InputDialog | ||
open={isDialogRenameOpen} | ||
setIsOpen={setIsDialogRenameOpen} | ||
title={t('renameDialog.title')} | ||
initialValue="label title" | ||
onCancel={handleToggleDialogRename} | ||
onConfirm={handleRenameLabel} | ||
/> | ||
<ContextMenu | ||
id={`details-menu-${id}`} | ||
className="relative ml-auto flex items-center brightness-125" | ||
button={ | ||
<FilledTonalIconButton | ||
className={cn('invisible absolute -right-4 group-hover:visible', { | ||
visible: | ||
isDialogRenameOpen || isConfirmDialogOpen || isContextMenuOpen, | ||
})} | ||
onClick={(e) => handleMenuToggle(e)}> | ||
<Icon>more_vert</Icon> | ||
</FilledTonalIconButton> | ||
}> | ||
<MenuItem | ||
style={menuItemStyles} | ||
className="mx-2 rounded-md" | ||
onClick={handleToggleDialogRename}> | ||
Rename | ||
<Icon className="text-on-surface" slot="end"> | ||
edit | ||
</Icon> | ||
</MenuItem> | ||
<MenuItem | ||
style={menuItemStyles} | ||
className="mx-2 rounded-md" | ||
onClick={handleToggleConfirmDialog}> | ||
Delete | ||
<Icon className="text-on-surface" slot="end"> | ||
delete | ||
</Icon> | ||
</MenuItem> | ||
</ContextMenu> | ||
</> | ||
); | ||
}; | ||
|
||
export default Details; |
81 changes: 81 additions & 0 deletions
81
client/src/layout/NotesLayout/ui/NavigationDrawer/ui/LabelItem.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import { FC, PropsWithChildren } from 'react'; | ||
|
||
import { filledIconStyles } from '@shared/lib/const'; | ||
import cn from '@shared/lib/helpers/cn'; | ||
import Icon from '@shared/ui/Icon'; | ||
import { motion } from 'framer-motion'; | ||
import { NavLink } from 'react-router-dom'; | ||
|
||
type TabItemProps = PropsWithChildren<{ | ||
id: number; | ||
to: string; | ||
}>; | ||
|
||
const animations = { | ||
initial: { scale: 0, opacity: 0 }, | ||
animate: { scale: 1, opacity: 1 }, | ||
transition: { type: 'spring', stiffness: 550, damping: 40 }, | ||
}; | ||
|
||
const LabelItem: FC<TabItemProps> = ({ children, to }) => { | ||
return ( | ||
<motion.div {...animations} layout> | ||
<NavLink | ||
to={to} | ||
className="group relative inline-block w-full animate-fade-in-screen rounded-full"> | ||
{({ isActive }) => ( | ||
<> | ||
<span | ||
className={cn( | ||
'absolute left-0 top-0 h-full w-full scale-x-[.32] rounded-full bg-surface-container-highest py-4 pl-4 pr-6 opacity-0 transition-transform duration-200 ease-linear active:brightness-90', | ||
{ | ||
'scale-x-100 bg-primary-container opacity-100 group-hover:brightness-95 group-active:brightness-95': | ||
isActive, | ||
}, | ||
)} | ||
/> | ||
<span | ||
className={cn( | ||
'relative z-10 flex origin-left items-center gap-3 rounded-full py-4 pl-4 pr-6 text-on-surface-variant group-hover:bg-[color-mix(in_srgb,_var(--md-sys-color-inverse-surface)_8%,_transparent)] group-active:brightness-95', | ||
{ | ||
'text-on-secondary-container-text font-medium': isActive, | ||
}, | ||
)}> | ||
<span className="animation-delay-200 flex animate-fade-in-standard items-center"> | ||
<Icon style={isActive ? filledIconStyles : undefined}> | ||
label | ||
</Icon> | ||
</span> | ||
{children} | ||
</span> | ||
</> | ||
)} | ||
</NavLink> | ||
{/* <div className="group relative inline-block w-full animate-fade-in-screen rounded-full"> */} | ||
{/* <span */} | ||
{/* className={cn( */} | ||
{/* 'absolute left-0 top-0 h-full w-full scale-x-[.32] rounded-full bg-surface-container-highest py-4 pl-4 pr-6 opacity-0 transition-transform duration-200 ease-linear active:brightness-90', */} | ||
{/* { */} | ||
{/* 'scale-x-100 bg-primary-container opacity-100 group-hover:brightness-95 group-active:brightness-95': */} | ||
{/* isActive, */} | ||
{/* }, */} | ||
{/* )} */} | ||
{/* /> */} | ||
{/* <span */} | ||
{/* className={cn( */} | ||
{/* 'relative z-10 flex origin-left items-center gap-3 rounded-full py-4 pl-4 pr-6 group-hover:bg-[color-mix(in_srgb,_var(--md-sys-color-inverse-surface)_8%,_transparent)] group-active:brightness-95', */} | ||
{/* { */} | ||
{/* 'text-on-secondary-container-text font-medium': isActive, */} | ||
{/* }, */} | ||
{/* )}> */} | ||
{/* <span className="animation-delay-200 flex animate-fade-in-standard items-center"> */} | ||
{/* <Icon style={isActive ? filledIconStyles : undefined}>label</Icon> */} | ||
{/* </span> */} | ||
{/* {children} */} | ||
{/* </span> */} | ||
{/* </div> */} | ||
</motion.div> | ||
); | ||
}; | ||
|
||
export default LabelItem; |
12 changes: 8 additions & 4 deletions
12
client/src/layout/NotesLayout/ui/NavigationDrawer/ui/LabelsList.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import React from 'react'; | ||
|
||
import { createComponent } from '@lit/react'; | ||
import { MdFilledTonalIconButton } from '@material/web/all'; | ||
|
||
const FilledTonalIconButton = createComponent({ | ||
react: React, | ||
tagName: 'md-filled-tonal-icon-button', | ||
elementClass: MdFilledTonalIconButton, | ||
}); | ||
|
||
export default FilledTonalIconButton; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import { | ||
Dispatch, | ||
FC, | ||
MouseEvent, | ||
SetStateAction, | ||
useRef, | ||
useState, | ||
} from 'react'; | ||
|
||
import { MdDialog } from '@material/web/all'; | ||
import { MdOutlinedTextField } from '@material/web/textfield/outlined-text-field'; | ||
|
||
import FilledTonalButton from '@/shared/ui/FilledTonalButton'; | ||
import TextButton from '@/shared/ui/TextButton'; | ||
import Dialog from '@shared/ui/Dialog'; | ||
import OutlinedTextField from '@shared/ui/OutlinedTextField'; | ||
|
||
type ConfirmDialogProps = { | ||
setIsOpen: Dispatch<SetStateAction<boolean>>; | ||
open: boolean; | ||
title: string; | ||
cancelText?: string; | ||
confirmText?: string; | ||
initialValue?: string; | ||
onCancel: (e: MouseEvent) => void | Promise<void>; | ||
onConfirm: (e: MouseEvent) => void | Promise<void>; | ||
}; | ||
|
||
const InputDialog: FC<ConfirmDialogProps> = ({ | ||
open, | ||
setIsOpen, | ||
title, | ||
cancelText = 'Cancel', | ||
confirmText = 'Save', | ||
onCancel, | ||
onConfirm, | ||
initialValue, | ||
}) => { | ||
const [val, setVal] = useState(initialValue); | ||
const dialogRef = useRef<MdDialog>(null); | ||
|
||
const handleConfirm = async (e: MouseEvent) => { | ||
e.stopPropagation(); | ||
await dialogRef.current?.close(); | ||
onConfirm(e); | ||
}; | ||
|
||
const handleCancel = async (e: MouseEvent) => { | ||
e.stopPropagation(); | ||
await dialogRef.current?.close(); | ||
onCancel(e); | ||
}; | ||
|
||
return ( | ||
<Dialog | ||
open={open} | ||
ref={dialogRef} | ||
className="max-w-[312px]" | ||
closed={() => setIsOpen(false)}> | ||
<h3 slot="headline">{title}</h3> | ||
<form slot="content" id="form-id" method="dialog"> | ||
<OutlinedTextField | ||
onInput={(e) => { | ||
setVal((e.target as MdOutlinedTextField).value); | ||
}} | ||
className="w-full text-start" | ||
textDirection="ltr" | ||
value={val} | ||
/> | ||
</form> | ||
<div slot="actions"> | ||
<TextButton onClick={handleCancel}>{cancelText}</TextButton> | ||
<FilledTonalButton onClick={handleConfirm}> | ||
{confirmText} | ||
</FilledTonalButton> | ||
</div> | ||
</Dialog> | ||
); | ||
}; | ||
|
||
export default InputDialog; |
Oops, something went wrong.