feat: ability to favorite tags (#1852)

This commit is contained in:
Mo
2022-10-20 09:28:35 -05:00
committed by GitHub
parent 9cc3304741
commit 4f3b258363
7 changed files with 81 additions and 27 deletions

View File

@@ -68,6 +68,7 @@ export const ICONS = {
eye: icons.EyeIcon, eye: icons.EyeIcon,
file: icons.FileIcon, file: icons.FileIcon,
folder: icons.FolderIcon, folder: icons.FolderIcon,
fullscreen: icons.FullscreenIcon,
hashtag: icons.HashtagIcon, hashtag: icons.HashtagIcon,
help: icons.HelpIcon, help: icons.HelpIcon,
history: icons.HistoryIcon, history: icons.HistoryIcon,

View File

@@ -37,7 +37,7 @@ const smartViewIconType = (view: SmartView, isSelected: boolean): IconType => {
[SystemViewId.StarredNotes]: 'star-filled', [SystemViewId.StarredNotes]: 'star-filled',
} }
return mapping[view.uuid as SystemViewId] || 'hashtag' return mapping[view.uuid as SystemViewId] || 'window'
} }
const getIconClass = (view: SmartView, isSelected: boolean): string => { const getIconClass = (view: SmartView, isSelected: boolean): string => {

View File

@@ -46,6 +46,11 @@ const TagContextMenu = ({ navigationController, isEntitledToFolders, selectedTag
navigationController.remove(selectedTag, true).catch(console.error) navigationController.remove(selectedTag, true).catch(console.error)
}, [navigationController, selectedTag]) }, [navigationController, selectedTag])
const onClickStar = useCallback(() => {
navigationController.setFavorite(selectedTag, !selectedTag.starred).catch(console.error)
navigationController.setContextMenuOpen(false)
}, [navigationController, selectedTag])
const tagLastModified = useMemo( const tagLastModified = useMemo(
() => formatDateForContextMenu(selectedTag.userModifiedDate), () => formatDateForContextMenu(selectedTag.userModifiedDate),
[selectedTag.userModifiedDate], [selectedTag.userModifiedDate],
@@ -62,6 +67,12 @@ const TagContextMenu = ({ navigationController, isEntitledToFolders, selectedTag
> >
<div ref={contextMenuRef}> <div ref={contextMenuRef}>
<Menu a11yLabel="Tag context menu" isOpen={contextMenuOpen}> <Menu a11yLabel="Tag context menu" isOpen={contextMenuOpen}>
<MenuItem type={MenuItemType.IconButton} className={'justify-between py-1.5'} onClick={onClickStar}>
<div className="flex items-center">
<Icon type="star" className="mr-2 text-neutral" />
{selectedTag.starred ? 'Unfavorite' : 'Favorite'}
</div>
</MenuItem>
<MenuItem type={MenuItemType.IconButton} className={'justify-between py-1.5'} onClick={onClickAddSubtag}> <MenuItem type={MenuItemType.IconButton} className={'justify-between py-1.5'} onClick={onClickAddSubtag}>
<div className="flex items-center"> <div className="flex items-center">
<Icon type="add" className="mr-2 text-neutral" /> <Icon type="add" className="mr-2 text-neutral" />

View File

@@ -9,11 +9,12 @@ import { TagsListItem } from './TagsListItem'
type Props = { type Props = {
viewControllerManager: ViewControllerManager viewControllerManager: ViewControllerManager
type: 'all' | 'favorites'
} }
const TagsList: FunctionComponent<Props> = ({ viewControllerManager }: Props) => { const TagsList: FunctionComponent<Props> = ({ viewControllerManager, type }: Props) => {
const tagsState = viewControllerManager.navigationController const navigationController = viewControllerManager.navigationController
const allTags = tagsState.allLocalRootTags const allTags = type === 'all' ? navigationController.allLocalRootTags : navigationController.starredTags
const backend = HTML5Backend const backend = HTML5Backend
@@ -49,17 +50,20 @@ const TagsList: FunctionComponent<Props> = ({ viewControllerManager }: Props) =>
level={0} level={0}
key={tag.uuid} key={tag.uuid}
tag={tag} tag={tag}
tagsState={tagsState} type={type}
tagsState={navigationController}
features={viewControllerManager.featuresController} features={viewControllerManager.featuresController}
linkingController={viewControllerManager.linkingController} linkingController={viewControllerManager.linkingController}
onContextMenu={onContextMenu} onContextMenu={onContextMenu}
/> />
) )
})} })}
<RootTagDropZone {type === 'all' && (
tagsState={viewControllerManager.navigationController} <RootTagDropZone
featuresState={viewControllerManager.featuresController} tagsState={viewControllerManager.navigationController}
/> featuresState={viewControllerManager.featuresController}
/>
)}
</> </>
)} )}
</DndProvider> </DndProvider>

View File

@@ -29,6 +29,7 @@ import { LinkingController } from '@/Controllers/LinkingController'
type Props = { type Props = {
tag: SNTag tag: SNTag
type: 'all' | 'favorites'
tagsState: NavigationController tagsState: NavigationController
features: FeaturesController features: FeaturesController
linkingController: LinkingController linkingController: LinkingController
@@ -40,7 +41,7 @@ const PADDING_BASE_PX = 14
const PADDING_PER_LEVEL_PX = 21 const PADDING_PER_LEVEL_PX = 21
export const TagsListItem: FunctionComponent<Props> = observer( export const TagsListItem: FunctionComponent<Props> = observer(
({ tag, features, tagsState, level, onContextMenu, linkingController }) => { ({ tag, type, features, tagsState, level, onContextMenu, linkingController }) => {
const { toggleAppPane } = useResponsiveAppPane() const { toggleAppPane } = useResponsiveAppPane()
const [title, setTitle] = useState(tag.title || '') const [title, setTitle] = useState(tag.title || '')
@@ -263,7 +264,18 @@ export const TagsListItem: FunctionComponent<Props> = observer(
</div> </div>
)} )}
<div className={'tag-icon draggable mr-2'} ref={dragRef}> <div className={'tag-icon draggable mr-2'} ref={dragRef}>
<Icon type="hashtag" className={`${isSelected ? 'text-info' : 'text-neutral'}`} /> <Icon
type="hashtag"
className={`${
type === 'favorites'
? isSelected
? 'text-warning'
: 'text-info'
: isSelected
? 'text-info'
: 'text-neutral'
}`}
/>
</div> </div>
{isEditing ? ( {isEditing ? (
<input <input
@@ -335,6 +347,7 @@ export const TagsListItem: FunctionComponent<Props> = observer(
level={level + 1} level={level + 1}
key={tag.uuid} key={tag.uuid}
tag={tag} tag={tag}
type={type}
tagsState={tagsState} tagsState={tagsState}
features={features} features={features}
linkingController={linkingController} linkingController={linkingController}

View File

@@ -52,22 +52,37 @@ const TagsSection: FunctionComponent<Props> = ({ viewControllerManager }) => {
}, [viewControllerManager, checkIfMigrationNeeded]) }, [viewControllerManager, checkIfMigrationNeeded])
return ( return (
<section> <>
<div className={'section-title-bar'}> {viewControllerManager.navigationController.starredTags.length > 0 && (
<div className="section-title-bar-header"> <section>
<TagsSectionTitle <div className={'section-title-bar'}>
features={viewControllerManager.featuresController} <div className="section-title-bar-header">
hasMigration={hasMigration} <div className="title text-sm">
onClickMigration={runMigration} <span className="font-bold">Favorites</span>
/> </div>
<TagsSectionAddButton </div>
tags={viewControllerManager.navigationController} </div>
features={viewControllerManager.featuresController} <TagsList type="favorites" viewControllerManager={viewControllerManager} />
/> </section>
)}
<section>
<div className={'section-title-bar'}>
<div className="section-title-bar-header">
<TagsSectionTitle
features={viewControllerManager.featuresController}
hasMigration={hasMigration}
onClickMigration={runMigration}
/>
<TagsSectionAddButton
tags={viewControllerManager.navigationController}
features={viewControllerManager.featuresController}
/>
</div>
</div> </div>
</div> <TagsList type="all" viewControllerManager={viewControllerManager} />
<TagsList viewControllerManager={viewControllerManager} /> </section>
</section> </>
) )
} }

View File

@@ -35,6 +35,7 @@ export class NavigationController
{ {
tags: SNTag[] = [] tags: SNTag[] = []
smartViews: SmartView[] = [] smartViews: SmartView[] = []
starredTags: SNTag[] = []
allNotesCount_ = 0 allNotesCount_ = 0
selectedUuid: AnyTag['uuid'] | undefined = undefined selectedUuid: AnyTag['uuid'] | undefined = undefined
selected_: AnyTag | undefined selected_: AnyTag | undefined
@@ -66,6 +67,7 @@ export class NavigationController
makeObservable(this, { makeObservable(this, {
tags: observable, tags: observable,
starredTags: observable,
smartViews: observable.ref, smartViews: observable.ref,
hasAtLeastOneFolder: computed, hasAtLeastOneFolder: computed,
allNotesCount_: observable, allNotesCount_: observable,
@@ -111,7 +113,7 @@ export class NavigationController
this.application.streamItems([ContentType.Tag, ContentType.SmartView], ({ changed, removed }) => { this.application.streamItems([ContentType.Tag, ContentType.SmartView], ({ changed, removed }) => {
runInAction(() => { runInAction(() => {
this.tags = this.application.items.getDisplayableTags() this.tags = this.application.items.getDisplayableTags()
this.starredTags = this.tags.filter((tag) => tag.starred)
this.smartViews = this.application.items.getSmartViews() this.smartViews = this.application.items.getSmartViews()
const currentSelectedTag = this.selected_ const currentSelectedTag = this.selected_
@@ -476,6 +478,14 @@ export class NavigationController
.catch(console.error) .catch(console.error)
} }
public async setFavorite(tag: SNTag, favorite: boolean) {
return this.application.mutator
.changeAndSaveItem<TagMutator>(tag, (mutator) => {
mutator.starred = favorite
})
.catch(console.error)
}
public get editingTag(): SNTag | SmartView | undefined { public get editingTag(): SNTag | SmartView | undefined {
return this.editing_ return this.editing_
} }