diff --git a/app/assets/icons/ic-chevron-right.svg b/app/assets/icons/ic-chevron-right.svg new file mode 100644 index 000000000..862c72f97 --- /dev/null +++ b/app/assets/icons/ic-chevron-right.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/icons/ic-hashtag.svg b/app/assets/icons/ic-hashtag.svg new file mode 100644 index 000000000..5d9333ec1 --- /dev/null +++ b/app/assets/icons/ic-hashtag.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/javascripts/components/Icon.tsx b/app/assets/javascripts/components/Icon.tsx index fee3b436a..f11c5d262 100644 --- a/app/assets/javascripts/components/Icon.tsx +++ b/app/assets/javascripts/components/Icon.tsx @@ -5,6 +5,8 @@ import PinIcon from '../../icons/ic-pin.svg'; import UnpinIcon from '../../icons/ic-pin-off.svg'; import ArchiveIcon from '../../icons/ic-archive.svg'; import UnarchiveIcon from '../../icons/ic-unarchive.svg'; +import HashtagIcon from '../../icons/ic-hashtag.svg'; +import ChevronRightIcon from '../../icons/ic-chevron-right.svg'; import { toDirective } from './utils'; export enum IconType { @@ -14,7 +16,9 @@ export enum IconType { Pin = 'pin', Unpin = 'unpin', Archive = 'archive', - Unarchive = 'unarchive' + Unarchive = 'unarchive', + Hashtag = 'hashtag', + ChevronRight = 'chevron-right', } const ICONS = { @@ -24,7 +28,9 @@ const ICONS = { [IconType.Pin]: PinIcon, [IconType.Unpin]: UnpinIcon, [IconType.Archive]: ArchiveIcon, - [IconType.Unarchive]: UnarchiveIcon + [IconType.Unarchive]: UnarchiveIcon, + [IconType.Hashtag]: HashtagIcon, + [IconType.ChevronRight]: ChevronRightIcon, }; type Props = { diff --git a/app/assets/javascripts/components/NotesOptions.tsx b/app/assets/javascripts/components/NotesOptions.tsx index ebed8810e..5b1c5c698 100644 --- a/app/assets/javascripts/components/NotesOptions.tsx +++ b/app/assets/javascripts/components/NotesOptions.tsx @@ -2,7 +2,12 @@ import { AppState } from '@/ui_models/app_state'; import { Icon, IconType } from './Icon'; import { Switch } from './Switch'; import { observer } from 'mobx-react-lite'; -import { useRef } from 'preact/hooks'; +import { useRef, useState } from 'preact/hooks'; +import { + Disclosure, + DisclosureButton, + DisclosurePanel, +} from '@reach/disclosure'; type Props = { appState: AppState; @@ -12,6 +17,12 @@ type Props = { export const NotesOptions = observer( ({ appState, closeOnBlur, setLockCloseOnBlur }: Props) => { + const [tagsMenuOpen, setTagsMenuOpen] = useState(false); + const [tagsMenuPosition, setTagsMenuPosition] = useState({ + top: 0, + right: 0, + }); + const notes = Object.values(appState.notes.selectedNotes); const hidePreviews = !notes.some((note) => !note.hidePreview); const locked = !notes.some((note) => !note.locked); @@ -20,6 +31,7 @@ export const NotesOptions = observer( const pinned = !notes.some((note) => !note.pinned); const trashButtonRef = useRef(); + const tagsButtonRef = useRef(); const iconClass = 'fill-current color-neutral mr-2'; const buttonClass = @@ -56,6 +68,60 @@ export const NotesOptions = observer(
+ { + const buttonRect = tagsButtonRef.current.getBoundingClientRect(); + const { offsetTop, offsetWidth } = tagsButtonRef.current; + setTagsMenuPosition({ + top: offsetTop, + right: ((buttonRect.right + 265) > document.body.clientWidth) ? offsetWidth : -offsetWidth, + }); + setTagsMenuOpen(!tagsMenuOpen); + }} + > + { + if (event.key === 'Escape') { + setTagsMenuOpen(false); + } + }} + onBlur={closeOnBlur} + ref={tagsButtonRef} + className={`${buttonClass} justify-between`} + > +
+ + {"Add tag"} +
+ +
+ { + if (event.key === 'Escape') { + setTagsMenuOpen(false); + tagsButtonRef.current.focus(); + } + }} + style={{ + ...tagsMenuPosition + }} + className="sn-dropdown sn-dropdown-anchor-right flex flex-col py-2 max-w-265" + > + {appState.tags.tags.map(tag => ( + + ))} + +