diff --git a/src/components/molecules/TagListFragment.tsx b/src/components/molecules/TagListFragment.tsx index 2cbf015ed2..a4bfbf2284 100644 --- a/src/components/molecules/TagListFragment.tsx +++ b/src/components/molecules/TagListFragment.tsx @@ -1,8 +1,8 @@ -import React, { useMemo } from 'react' +import React, { useMemo, useCallback } from 'react' import SideNavigatorItem from '../atoms/NavigatorItem' import NavigatorButton from '../atoms/NavigatorButton' import { NoteStorage } from '../../lib/db/types' -import { isTagNameValid } from '../../lib/db/utils' +import { isTagNameValid, keys } from '../../lib/db/utils' import { useGeneralStatus } from '../../lib/generalStatus' import { getTagListItemId } from '../../lib/nav' import { useRouter } from '../../lib/router' @@ -21,101 +21,22 @@ interface TagListFragmentProps { const TagListFragment = ({ storage }: TagListFragmentProps) => { const { toggleSideNavOpenedItem, sideNavOpenedItemSet } = useGeneralStatus() const { id: storageId, tagMap } = storage - const { push } = useRouter() - const { prompt, messageBox } = useDialog() - const { removeTag, renameTag } = useDb() const { t } = useTranslation() - const currentPathname = usePathnameWithoutNoteId() - const { report } = useAnalytics() const tagListNavItemId = getTagListItemId(storage.id) const tagListIsFolded = !sideNavOpenedItemSet.has(tagListNavItemId) - const openTagContextMenu = (tagName: string) => { - return (event: React.MouseEvent) => { - event.preventDefault() - openContextMenu({ - menuItems: [ - { - type: 'normal', - label: t('tag.remove'), - click: () => { - messageBox({ - title: `Remove "${tagName}" tag`, - message: t('tag.removeMessage'), - iconType: DialogIconTypes.Warning, - buttons: [t('tag.remove'), t('general.cancel')], - defaultButtonIndex: 0, - cancelButtonIndex: 1, - onClose: (value: number | null) => { - if (value === 0) { - removeTag(storageId, tagName) - report(analyticsEvents.removeTag) - } - }, - }) - }, - }, - { - type: 'normal', - label: t('tag.rename'), - click: () => { - prompt({ - title: `tag.rename`, - message: t('tag.renameMessage', { tagName }), - iconType: DialogIconTypes.Question, - defaultValue: tagName, - submitButtonLabel: t('tag.rename'), - onClose: (value: string | null) => { - if (value == null || !isTagNameValid(value) || value == tagName) return - renameTag(storageId, tagName, value); - report(analyticsEvents.renameTag) - }, - }) - }, - }, - ], - }) - } - } - const tagList = useMemo(() => { - return Object.keys(tagMap).map((tagName) => { - const tagPathname = `/app/storages/${storageId}/tags/${tagName}` - const tagIsActive = currentPathname === tagPathname + return keys(tagMap).map((tagName) => { return ( - { - push(tagPathname) - }} - active={tagIsActive} - onContextMenu={openTagContextMenu(tagName)} - control={ - - } + ) }) - }, [ - storageId, - tagMap, - push, - currentPathname, - messageBox, - removeTag, - t, - report, - prompt, - isTagNameValid, - renameTag, - ]) + }, [storageId, tagMap]) if (tagList.length === 0) { return null @@ -144,3 +65,92 @@ const TagListFragment = ({ storage }: TagListFragmentProps) => { } export default TagListFragment + +interface TagListItemProps { + storageId: string + tagName: string +} + +const TagListItem = ({ tagName, storageId }: TagListItemProps) => { + const { push } = useRouter() + const { prompt, messageBox } = useDialog() + const { removeTag, renameTag } = useDb() + const { t } = useTranslation() + const currentPathname = usePathnameWithoutNoteId() + const { report } = useAnalytics() + const openTagContextMenu = useCallback( + (event: React.MouseEvent) => { + event.preventDefault() + openContextMenu({ + menuItems: [ + { + type: 'normal', + label: t('tag.rename'), + click: () => { + prompt({ + title: `tag.rename`, + message: t('tag.renameMessage', { tagName }), + iconType: DialogIconTypes.Question, + defaultValue: tagName, + submitButtonLabel: t('tag.rename'), + onClose: (value: string | null) => { + if ( + value == null || + !isTagNameValid(value) || + value == tagName + ) + return + renameTag(storageId, tagName, value) + report(analyticsEvents.renameTag) + }, + }) + }, + }, + { type: 'separator' }, + { + type: 'normal', + label: t('tag.remove'), + click: () => { + messageBox({ + title: `Remove "${tagName}" tag`, + message: t('tag.removeMessage'), + iconType: DialogIconTypes.Warning, + buttons: [t('tag.remove'), t('general.cancel')], + defaultButtonIndex: 0, + cancelButtonIndex: 1, + onClose: (value: number | null) => { + if (value === 0) { + removeTag(storageId, tagName) + report(analyticsEvents.removeTag) + } + }, + }) + }, + }, + ], + }) + }, + [messageBox, prompt, removeTag, renameTag, report, storageId, t, tagName] + ) + const tagPathname = `/app/storages/${storageId}/tags/${tagName}` + const tagIsActive = currentPathname === tagPathname + return ( + { + push(tagPathname) + }} + active={tagIsActive} + onContextMenu={openTagContextMenu} + control={ + + } + /> + ) +}