elk/composables/masto/search.ts

110 lines
3.2 KiB
TypeScript
Raw Permalink Normal View History

2023-05-02 00:58:55 +01:00
import type { MaybeRefOrGetter } from '@vueuse/core'
2024-01-09 08:56:15 +00:00
import type { mastodon } from 'masto'
2023-01-07 14:52:58 +00:00
import type { RouteLocation } from 'vue-router'
2022-12-17 21:35:07 +00:00
2023-05-02 00:58:55 +01:00
export type UseSearchOptions = MaybeRefOrGetter<
2024-01-09 08:56:15 +00:00
Partial<Omit<mastodon.rest.v2.SearchParams, keyof mastodon.DefaultPaginationParams | 'q'>>
2023-01-08 13:42:53 +00:00
>
2022-12-17 21:35:07 +00:00
2023-01-07 14:52:58 +00:00
export interface BuildSearchResult<K extends keyof any, T> {
id: string
type: K
data: T
to: RouteLocation & {
href: string
}
}
2023-01-08 06:21:09 +00:00
export type AccountSearchResult = BuildSearchResult<'account', mastodon.v1.Account>
export type HashTagSearchResult = BuildSearchResult<'hashtag', mastodon.v1.Tag>
export type StatusSearchResult = BuildSearchResult<'status', mastodon.v1.Status>
2023-01-07 14:52:58 +00:00
export type SearchResult = HashTagSearchResult | AccountSearchResult | StatusSearchResult
2023-05-02 00:58:55 +01:00
export function useSearch(query: MaybeRefOrGetter<string>, options: UseSearchOptions = {}) {
2022-12-17 21:35:07 +00:00
const done = ref(false)
const { client } = useMasto()
2022-12-17 21:35:07 +00:00
const loading = ref(false)
2023-01-07 14:52:58 +00:00
const accounts = ref<AccountSearchResult[]>([])
const hashtags = ref<HashTagSearchResult[]>([])
const statuses = ref<StatusSearchResult[]>([])
2022-12-17 21:35:07 +00:00
const q = computed(() => resolveUnref(query).trim())
2023-01-09 08:36:24 +00:00
2024-01-09 08:56:15 +00:00
let paginator: mastodon.Paginator<mastodon.v2.Search, mastodon.rest.v2.SearchParams> | undefined
2022-12-22 10:34:35 +00:00
2023-01-08 06:21:09 +00:00
const appendResults = (results: mastodon.v2.Search, empty = false) => {
2023-01-07 14:52:58 +00:00
if (empty) {
accounts.value = []
hashtags.value = []
statuses.value = []
}
accounts.value = [...accounts.value, ...results.accounts.map<AccountSearchResult>(account => ({
type: 'account',
id: account.id,
data: account,
to: getAccountRoute(account),
}))]
hashtags.value = [...hashtags.value, ...results.hashtags.map<HashTagSearchResult>(hashtag => ({
type: 'hashtag',
id: `hashtag-${hashtag.name}`,
data: hashtag,
to: getTagRoute(hashtag.name),
}))]
statuses.value = [...statuses.value, ...results.statuses.map<StatusSearchResult>(status => ({
type: 'status',
id: status.id,
data: status,
to: getStatusRoute(status),
}))]
}
2023-01-09 08:36:24 +00:00
watch(() => resolveUnref(query), () => {
loading.value = !!(q.value && isHydrated.value)
2023-01-07 14:59:57 +00:00
})
2023-01-09 08:36:24 +00:00
debouncedWatch(() => resolveUnref(query), async () => {
if (!q.value || !isHydrated.value)
2022-12-17 21:35:07 +00:00
return
loading.value = true
/**
* Based on the source it seems like modifying the params when calling next would result in a new search,
* but that doesn't seem to be the case. So instead we just create a new paginator with the new params.
*/
paginator = client.value.v2.search.list({
q: q.value,
2023-01-08 13:42:53 +00:00
...resolveUnref(options),
2023-01-07 14:52:58 +00:00
resolve: !!currentUser.value,
})
2022-12-17 21:35:07 +00:00
const nextResults = await paginator.next()
2023-01-07 14:52:58 +00:00
done.value = !!nextResults.done
if (!nextResults.done)
appendResults(nextResults.value, true)
2022-12-17 21:35:07 +00:00
loading.value = false
2023-01-07 14:59:57 +00:00
}, { debounce: 300 })
2022-12-17 21:35:07 +00:00
const next = async () => {
if (!q.value || !isHydrated.value || !paginator)
2022-12-17 21:35:07 +00:00
return
loading.value = true
const nextResults = await paginator.next()
loading.value = false
2023-01-07 14:52:58 +00:00
done.value = !!nextResults.done
if (!nextResults.done)
appendResults(nextResults.value)
2022-12-17 21:35:07 +00:00
}
return {
accounts,
hashtags,
statuses,
loading: readonly(loading),
next,
}
}