feat: ability to favorite tags (#1852)
This commit is contained in:
@@ -68,6 +68,7 @@ export const ICONS = {
|
||||
eye: icons.EyeIcon,
|
||||
file: icons.FileIcon,
|
||||
folder: icons.FolderIcon,
|
||||
fullscreen: icons.FullscreenIcon,
|
||||
hashtag: icons.HashtagIcon,
|
||||
help: icons.HelpIcon,
|
||||
history: icons.HistoryIcon,
|
||||
|
||||
@@ -37,7 +37,7 @@ const smartViewIconType = (view: SmartView, isSelected: boolean): IconType => {
|
||||
[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 => {
|
||||
|
||||
@@ -46,6 +46,11 @@ const TagContextMenu = ({ navigationController, isEntitledToFolders, selectedTag
|
||||
navigationController.remove(selectedTag, true).catch(console.error)
|
||||
}, [navigationController, selectedTag])
|
||||
|
||||
const onClickStar = useCallback(() => {
|
||||
navigationController.setFavorite(selectedTag, !selectedTag.starred).catch(console.error)
|
||||
navigationController.setContextMenuOpen(false)
|
||||
}, [navigationController, selectedTag])
|
||||
|
||||
const tagLastModified = useMemo(
|
||||
() => formatDateForContextMenu(selectedTag.userModifiedDate),
|
||||
[selectedTag.userModifiedDate],
|
||||
@@ -62,6 +67,12 @@ const TagContextMenu = ({ navigationController, isEntitledToFolders, selectedTag
|
||||
>
|
||||
<div ref={contextMenuRef}>
|
||||
<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}>
|
||||
<div className="flex items-center">
|
||||
<Icon type="add" className="mr-2 text-neutral" />
|
||||
|
||||
@@ -9,11 +9,12 @@ import { TagsListItem } from './TagsListItem'
|
||||
|
||||
type Props = {
|
||||
viewControllerManager: ViewControllerManager
|
||||
type: 'all' | 'favorites'
|
||||
}
|
||||
|
||||
const TagsList: FunctionComponent<Props> = ({ viewControllerManager }: Props) => {
|
||||
const tagsState = viewControllerManager.navigationController
|
||||
const allTags = tagsState.allLocalRootTags
|
||||
const TagsList: FunctionComponent<Props> = ({ viewControllerManager, type }: Props) => {
|
||||
const navigationController = viewControllerManager.navigationController
|
||||
const allTags = type === 'all' ? navigationController.allLocalRootTags : navigationController.starredTags
|
||||
|
||||
const backend = HTML5Backend
|
||||
|
||||
@@ -49,17 +50,20 @@ const TagsList: FunctionComponent<Props> = ({ viewControllerManager }: Props) =>
|
||||
level={0}
|
||||
key={tag.uuid}
|
||||
tag={tag}
|
||||
tagsState={tagsState}
|
||||
type={type}
|
||||
tagsState={navigationController}
|
||||
features={viewControllerManager.featuresController}
|
||||
linkingController={viewControllerManager.linkingController}
|
||||
onContextMenu={onContextMenu}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
<RootTagDropZone
|
||||
tagsState={viewControllerManager.navigationController}
|
||||
featuresState={viewControllerManager.featuresController}
|
||||
/>
|
||||
{type === 'all' && (
|
||||
<RootTagDropZone
|
||||
tagsState={viewControllerManager.navigationController}
|
||||
featuresState={viewControllerManager.featuresController}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</DndProvider>
|
||||
|
||||
@@ -29,6 +29,7 @@ import { LinkingController } from '@/Controllers/LinkingController'
|
||||
|
||||
type Props = {
|
||||
tag: SNTag
|
||||
type: 'all' | 'favorites'
|
||||
tagsState: NavigationController
|
||||
features: FeaturesController
|
||||
linkingController: LinkingController
|
||||
@@ -40,7 +41,7 @@ const PADDING_BASE_PX = 14
|
||||
const PADDING_PER_LEVEL_PX = 21
|
||||
|
||||
export const TagsListItem: FunctionComponent<Props> = observer(
|
||||
({ tag, features, tagsState, level, onContextMenu, linkingController }) => {
|
||||
({ tag, type, features, tagsState, level, onContextMenu, linkingController }) => {
|
||||
const { toggleAppPane } = useResponsiveAppPane()
|
||||
|
||||
const [title, setTitle] = useState(tag.title || '')
|
||||
@@ -263,7 +264,18 @@ export const TagsListItem: FunctionComponent<Props> = observer(
|
||||
</div>
|
||||
)}
|
||||
<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>
|
||||
{isEditing ? (
|
||||
<input
|
||||
@@ -335,6 +347,7 @@ export const TagsListItem: FunctionComponent<Props> = observer(
|
||||
level={level + 1}
|
||||
key={tag.uuid}
|
||||
tag={tag}
|
||||
type={type}
|
||||
tagsState={tagsState}
|
||||
features={features}
|
||||
linkingController={linkingController}
|
||||
|
||||
@@ -52,22 +52,37 @@ const TagsSection: FunctionComponent<Props> = ({ viewControllerManager }) => {
|
||||
}, [viewControllerManager, checkIfMigrationNeeded])
|
||||
|
||||
return (
|
||||
<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}
|
||||
/>
|
||||
<>
|
||||
{viewControllerManager.navigationController.starredTags.length > 0 && (
|
||||
<section>
|
||||
<div className={'section-title-bar'}>
|
||||
<div className="section-title-bar-header">
|
||||
<div className="title text-sm">
|
||||
<span className="font-bold">Favorites</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
<TagsList viewControllerManager={viewControllerManager} />
|
||||
</section>
|
||||
<TagsList type="all" viewControllerManager={viewControllerManager} />
|
||||
</section>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ export class NavigationController
|
||||
{
|
||||
tags: SNTag[] = []
|
||||
smartViews: SmartView[] = []
|
||||
starredTags: SNTag[] = []
|
||||
allNotesCount_ = 0
|
||||
selectedUuid: AnyTag['uuid'] | undefined = undefined
|
||||
selected_: AnyTag | undefined
|
||||
@@ -66,6 +67,7 @@ export class NavigationController
|
||||
|
||||
makeObservable(this, {
|
||||
tags: observable,
|
||||
starredTags: observable,
|
||||
smartViews: observable.ref,
|
||||
hasAtLeastOneFolder: computed,
|
||||
allNotesCount_: observable,
|
||||
@@ -111,7 +113,7 @@ export class NavigationController
|
||||
this.application.streamItems([ContentType.Tag, ContentType.SmartView], ({ changed, removed }) => {
|
||||
runInAction(() => {
|
||||
this.tags = this.application.items.getDisplayableTags()
|
||||
|
||||
this.starredTags = this.tags.filter((tag) => tag.starred)
|
||||
this.smartViews = this.application.items.getSmartViews()
|
||||
|
||||
const currentSelectedTag = this.selected_
|
||||
@@ -476,6 +478,14 @@ export class NavigationController
|
||||
.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 {
|
||||
return this.editing_
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user