| <script setup lang="ts"> | |
| import { RiArrowRightLine } from '@remixicon/vue'; | |
| import { useI18n } from 'vue-i18n'; | |
| type Emits = { | |
| (e: 'search', val: string): void, | |
| } | |
| type Props = { | |
| loading: boolean | |
| autofocus: boolean | |
| limit?: number | |
| } | |
| const { t } = useI18n(); | |
| const props = withDefaults(defineProps<Props>(), { | |
| limit: 520 | |
| }); | |
| const emits = defineEmits<Emits>(); | |
| const query = defineModel<string>(); | |
| const onSearch = () => { | |
| if (!query.value?.trim()) return; | |
| emits('search', query.value.trim()); | |
| }; | |
| </script> | |
| <template> | |
| <div id="searchbar" class="flex flex-row rounded-3xl bg-zinc-100 p-2 transition-all dark:bg-zinc-800"> | |
| <div class="grow overflow-hidden rounded-3xl border border-zinc-100 dark:border-zinc-300 dark:bg-zinc-600"> | |
| <t-input | |
| v-model="query" | |
| :disabled="props.loading" | |
| :autofocus="autofocus" | |
| :maxlength="limit" | |
| :placeholder="t('tips.search')" | |
| size="large" | |
| clearable | |
| @enter="onSearch" | |
| > | |
| <template #suffix> | |
| <t-button :disabled="loading" shape="round" variant="base" @click="onSearch"> | |
| <template #icon><RiArrowRightLine /></template> | |
| </t-button> | |
| </template> | |
| </t-input> | |
| </div> | |
| <div class="grow-0"> | |
| <slot /> | |
| </div> | |
| </div> | |
| </template> | |
| <style scoped> | |
| #searchbar { | |
| --td-radius-default: 24px; | |
| } | |
| </style> | |