import { ReactElement, useState } from 'react'; import { faBullseye } from '@fortawesome/free-solid-svg-icons'; import { faSquare, faSquareCheck } from '@fortawesome/free-regular-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { useAppDispatch, useAppSelector } from '../../../store/hooks'; import { PageFilter, PageSortOrder, fetchAllPagesForHumanTag } from '../../../db/pages'; import { clearSelectionAndSelectMulti, focusTag, renameTagInExpanded, selectIsExpanded, setTagExpanded, selectSelectedUrls, addMultiToSelection, removeMultiFromSelection, } from '../../../store/uiSlice'; import { useLiveQuery } from 'dexie-react-hooks'; import { formatDistance } from 'date-fns'; import TagPageList from './TagPageList'; import { logger } from '../../../utils/logger'; import CollapsibleSection from './CollapsibleSection'; import Stack from '@mui/joy/Stack'; import { Input, LinearProgress, Tooltip, Typography } from '@mui/joy'; import React from 'react'; import { renameTag, fetchTagLastActive } from '../../../db/tags'; interface CollapsibleTagProps { tag: string; overrideExpanded?: boolean; sortOrder: PageSortOrder; filter: PageFilter; groupByWindow: boolean; } enum TagEditState { NONE, EDITING, RENAMING, } const CollapsibleTag = React.memo( ({ tag, overrideExpanded = false, sortOrder, filter, groupByWindow, }: CollapsibleTagProps): ReactElement => { const expanded = useAppSelector((rootState) => selectIsExpanded(rootState, tag)) || overrideExpanded; const tagAccessTime = useLiveQuery(() => fetchTagLastActive(tag), [tag]); const pages = useLiveQuery(() => fetchAllPagesForHumanTag(tag), [tag]); const tagCount = pages ? pages.length : 0; const urls = pages ? pages.map((page) => page.nurl) : []; const dispatch = useAppDispatch(); const [tagEditState, setTagEditState] = useState(TagEditState.NONE); const selectedUrls = useAppSelector(selectSelectedUrls); const allSelected = tagCount > 0 && urls.every((url) => selectedUrls.includes(url.normalized)); const toggleSelectAll = () => { const normalizedUrls = urls.map((u) => u.normalized); if (allSelected) { dispatch(removeMultiFromSelection(normalizedUrls)); } else { dispatch(addMultiToSelection(normalizedUrls)); } }; return ( dispatch(setTagExpanded({ tag, expanded: val }))} prefix={ { e.stopPropagation(); toggleSelectAll(); }} style={{ cursor: 'pointer' }} /> dispatch(focusTag({ tag }))} title="Focus Tag" style={{ cursor: 'pointer' }} /> } title={ tagEditState == TagEditState.EDITING ? ( ) => {}} defaultValue={tag} onKeyUp={(event) => { if (event.key === 'Escape') { setTagEditState(TagEditState.NONE); } if (event.key === 'Enter') { logger.info('[Tag] Renaming ' + tag + ' to ' + event.currentTarget.value); renameTag(tag, event.currentTarget.value); setTagEditState(TagEditState.RENAMING); dispatch(renameTagInExpanded({ oldTag: tag, newTag: event.currentTarget.value })); } }} /> ) : tagEditState == TagEditState.RENAMING ? ( ) : ( { if (allSelected) { dispatch(removeMultiFromSelection(urls.map(u => u.normalized))); } else { dispatch( clearSelectionAndSelectMulti({ urls: urls, }) ); } }} onDoubleClick={() => setTagEditState(TagEditState.EDITING)} sx={{ cursor: 'pointer' }} > {tag} ({tagCount}) ) } suffix={ {tagAccessTime && formatDistance(tagAccessTime, new Date(), { addSuffix: true })} } > ); } ); export default CollapsibleTag;