refactor: improve search bar component

This commit is contained in:
starknt
2024-01-12 23:57:34 +08:00
parent 3985ade643
commit c77b8223c8
5 changed files with 50 additions and 46 deletions

View File

@@ -293,3 +293,4 @@ watch_later:
search_bar:
history_title: 搜索历史
clear_history: 清空搜索历史
placeholder: 输入关键字搜索

View File

@@ -296,3 +296,4 @@ watch_later:
search_bar:
history_title: 搜尋記錄
clear_history: 清除所有搜尋記錄
placeholder: 輸入關鍵字搜尋

View File

@@ -292,3 +292,4 @@ watch_later:
search_bar:
history_title: Search History
clear_history: Clear search history
placeholder: Enter keywords to search

View File

@@ -296,3 +296,4 @@ watch_later:
search_bar:
history_title: 搜尋記錄
clear_history: 剷晒你啲搜尋記錄
placeholder: 键入关键字搜尋

View File

@@ -1,5 +1,6 @@
<!-- TODO: refactor all that shit -->
<script setup lang="ts">
import { onClickOutside, useFocus, useWindowFocus, watchThrottled } from '@vueuse/core'
import type { HistoryItem, SuggestionItem, SuggestionResponse } from './searchHistoryProvider'
import {
addSearchHistory,
@@ -14,7 +15,9 @@ defineProps<{
focusedCharacter?: string
}>()
const isFocus = ref<boolean>(false)
const inputRef = ref<HTMLInputElement | null>(null)
const { focused: isFocus } = useFocus(inputRef)
const isWindowFocus = useWindowFocus()
const keyword = ref<string>('')
const suggestions = reactive<SuggestionItem[]>([])
const selectedIndex = ref<number>(-1)
@@ -22,30 +25,35 @@ const searchHistory = shallowRef<HistoryItem[]>([])
const historyItemRef = ref<HTMLElement[]>([])
const suggestionItemRef = ref<HTMLElement[]>([])
watch(isFocus, async (focus) => {
watch([isFocus, isWindowFocus], async ([focus, windowFocus]) => {
// 延后加载搜索历史
if (focus)
if (focus && windowFocus)
searchHistory.value = await getSearchHistory()
})
if (!windowFocus) {
selectedIndex.value = -1
inputRef.value?.blur()
}
}, { flush: 'sync' })
function handleInput() {
watchThrottled(keyword, (keyword) => {
selectedIndex.value = -1
if (keyword.value.length > 0) {
browser.runtime
.sendMessage({
contentScriptQuery: 'getSearchSuggestion',
term: keyword.value,
})
.then((res: SuggestionResponse) => {
if (!res || (res && res.code !== 0))
return
Object.assign(suggestions, res.result.tag)
})
}
else {
if (keyword.length <= 0) {
suggestions.length = 0
return
}
}
browser.runtime
.sendMessage({
contentScriptQuery: 'getSearchSuggestion',
term: keyword,
})
.then((res: SuggestionResponse) => {
if (!res || (res && res.code !== 0))
return
Object.assign(suggestions, res.result.tag)
})
}, { throttle: 100 })
async function navigateToSearchResultPage(keyword: string) {
if (keyword) {
@@ -78,13 +86,15 @@ function handleKeyUp() {
suggestionItemRef.value.forEach((item, index) => {
if (index === selectedIndex.value)
item.classList.add('active')
else item.classList.remove('active')
else
item.classList.remove('active')
})
historyItemRef.value.forEach((item, index) => {
if (index === selectedIndex.value)
item.classList.add('active')
else item.classList.remove('active')
else
item.classList.remove('active')
})
}
@@ -142,12 +152,10 @@ async function handleClearSearchHistory() {
w="full"
h="full"
content="~"
@click="isFocus = false"
/>
<Transition name="mask">
<div
v-if="darkenOnFocus && isFocus" pos="fixed top-0 left-0" w-full h-full bg="black opacity-60"
@click="isFocus = false"
/>
</Transition>
@@ -162,8 +170,8 @@ async function handleClearSearchHistory() {
<Transition name="focus-character">
<img v-show="focusedCharacter && isFocus" :src="focusedCharacter" width="100" object-contain pos="absolute right-0 bottom-40px">
</Transition>
<input
ref="inputRef"
v-model.trim="keyword"
rounded="60px focus:$bew-radius"
p="l-6 r-16 y-3"
@@ -173,12 +181,11 @@ async function handleClearSearchHistory() {
ring="1 $bew-border-color"
transition="all duration-300"
type="text"
@focus="isFocus = true"
@input="handleInput"
@keyup.enter.stop.passive="navigateToSearchResultPage(keyword)"
@keyup.up.stop.passive="handleKeyUp"
@keyup.down.stop.passive="handleKeyDown"
@keydown.stop="() => {}"
autocomplete="off"
:placeholder="$t('search_bar.placeholder')"
@keyup.up="handleKeyUp"
@keyup.down="handleKeyDown"
@keyup.enter="navigateToSearchResultPage(keyword)"
>
<button
p-2
@@ -199,14 +206,13 @@ async function handleClearSearchHistory() {
<Transition name="result-list">
<div
v-if="
isFocus
&& searchHistory.length !== 0
&& keyword.length === 0
"
id="search-history"
v-if="isFocus"
class="search-suggestion search-history min-h-60px"
>
<div class="history-list flex flex-col gap-y-2">
<div
v-show="keyword.length === 0 && searchHistory.length !== 0"
class="history-list flex flex-col gap-y-2"
>
<div class="title p-2 pb-0 flex justify-between">
<span>{{ $t('search_bar.history_title') }}</span>
<button class="rounded-2 duration-300 pointer-events-auto cursor-pointer" hover="text-$bew-theme-color" text="base $bew-text-2" @click="handleClearSearchHistory">
@@ -233,16 +239,10 @@ async function handleClearSearchHistory() {
</div>
</div>
</div>
</div>
</Transition>
<Transition name="result-list">
<div
v-if="isFocus && suggestions.length !== 0 && keyword.length > 0"
id="search-suggestion"
>
<div
v-for="(item, index) in suggestions"
v-show="keyword.length > 0"
:key="index"
ref="suggestionItemRef"
class="suggestion-item"
@@ -339,7 +339,7 @@ async function handleClearSearchHistory() {
hover:bg-$bew-fill-2;
}
#search-history {
.search-history {
@include search-content;
--at-apply: bg-$bew-elevated-1;
@@ -357,7 +357,7 @@ async function handleClearSearchHistory() {
}
}
#search-suggestion {
.search-suggestion {
@include search-content;
--at-apply: bg-$bew-elevated-1;