clean up tags autocomplete desktop

This commit is contained in:
Eric Bailey
2023-09-27 19:57:20 -05:00
parent bd9c1626e6
commit 6f6a34cc99
6 changed files with 89 additions and 218 deletions
+6
View File
@@ -22,6 +22,7 @@ import {resetToTab} from '../../Navigation'
import {ImageSizesCache} from './cache/image-sizes'
import {MutedThreads} from './muted-threads'
import {reset as resetNavigation} from '../../Navigation'
import {RecentTagsModel} from './ui/tags-autocomplete'
// TEMPORARY (APP-700)
// remove after backend testing finishes
@@ -53,6 +54,7 @@ export class RootStoreModel {
linkMetas = new LinkMetasCache(this)
imageSizes = new ImageSizesCache()
mutedThreads = new MutedThreads()
recentTags = new RecentTagsModel()
constructor(agent: BskyAgent) {
this.agent = agent
@@ -77,6 +79,7 @@ export class RootStoreModel {
preferences: this.preferences.serialize(),
invitedUsers: this.invitedUsers.serialize(),
mutedThreads: this.mutedThreads.serialize(),
recentTags: this.recentTags.serialize(),
}
}
@@ -109,6 +112,9 @@ export class RootStoreModel {
if (hasProp(v, 'mutedThreads')) {
this.mutedThreads.hydrate(v.mutedThreads)
}
if (hasProp(v, 'recentTags')) {
this.recentTags.hydrate(v.recentTags)
}
}
}
+68 -41
View File
@@ -2,25 +2,44 @@ import {makeAutoObservable, runInAction} from 'mobx'
import AwaitLock from 'await-lock'
import {RootStoreModel} from '../root-store'
import Fuse from 'fuse.js'
import {isObj, hasProp, isStrArray} from 'lib/type-guards'
export class TagsAutocompleteView {
// state
isLoading = false
isActive = false
prefix = ''
export class RecentTagsModel {
_tags: string[] = []
constructor() {
makeAutoObservable(this, {}, {autoBind: true})
}
get tags() {
return this._tags
}
add(tag: string) {
this._tags = Array.from(new Set([tag, ...this._tags]))
}
remove(tag: string) {
this._tags = this._tags.filter(t => t !== tag)
}
serialize() {
return {_tags: this._tags}
}
hydrate(v: unknown) {
if (isObj(v) && hasProp(v, '_tags') && isStrArray(v._tags)) {
this._tags = Array.from(new Set(v._tags))
}
}
}
export class TagsAutocompleteModel {
lock = new AwaitLock()
isActive = false
query = ''
searchedTags: string[] = []
recentTags: string[] = [
'js',
'javascript',
'art',
'music',
]
profileTags: string[] = [
'bikes',
'beer',
]
profileTags: string[] = []
constructor(public rootStore: RootStoreModel) {
makeAutoObservable(
@@ -32,56 +51,64 @@ export class TagsAutocompleteView {
)
}
setActive(isActive: boolean) {
this.isActive = isActive
}
commitRecentTag(tag: string) {
this.rootStore.recentTags.add(tag)
}
get suggestions() {
if (!this.isActive) {
return []
}
const items = [
...this.recentTags,
...this.profileTags,
...this.searchedTags,
]
const items = Array.from(
new Set([
...this.rootStore.recentTags.tags.slice(0, 3),
...this.profileTags.slice(0, 3),
...this.searchedTags,
]),
)
if (!this.prefix) {
return items.slice(0, 8)
if (!this.query) {
return items.slice(0, 9)
}
const fuse = new Fuse(items)
const results = fuse.search(this.prefix)
const results = fuse.search(this.query)
return results.slice(0, 8).map(r => r.item)
return results.slice(0, 9).map(r => r.item)
}
setActive(v: boolean) {
this.isActive = v
}
async search(query: string) {
this.query = query.trim()
async setPrefix(prefix: string) {
this.prefix = prefix.trim()
await this.lock.acquireAsync()
try {
if (this.prefix) {
if (this.prefix !== this.prefix) {
return // another prefix was set before we got our chance
}
await this._search()
} else {
// this.searchRes = []
}
// another query was set before we got our chance
if (this.query !== this.query) return
await this._search()
} finally {
this.lock.release()
}
}
// internal
// =
async _search() {
runInAction(() => {
this.searchedTags = [
'code',
'dev',
'javascript',
'react',
'typescript',
'mobx',
'mobx-state-tree',
'mobx-react',
'mobx-react-lite',
'mobx-react-form',
]
})
}