Download src/components/SearchForm.vue from xcolorday/ps: direct link, hf CLI and curl.
- Browser
- Download file 3.91 kB
-
https://huggingface.co/spaces/xcolorday/ps/resolve/main/src/components/SearchForm.vue
- Command line
-
hf download hf://spaces/xcolorday/ps/src/components/SearchForm.vue
-
curl -L -o SearchForm.vue https://huggingface.co/spaces/xcolorday/ps/resolve/main/src/components/SearchForm.vue
3.91 kB
| <script setup lang="ts"> | |
| import { ref } from 'vue'; | |
| import type { SearchParams } from '@/api'; | |
| import { Button, Input, Icons } from '@/components/ui'; | |
| const keyword = ref(''); | |
| const loading = ref(false); | |
| const emit = defineEmits<{ | |
| (e: 'search', params: SearchParams): void; | |
| (e: 'searchComplete'): void; | |
| }>(); | |
| const handleSearch = () => { | |
| if (!keyword.value.trim()) { | |
| return; | |
| } | |
| loading.value = true; | |
| const params: SearchParams = { | |
| kw: keyword.value, | |
| res: 'merge', | |
| src: 'all' | |
| }; | |
| emit('search', params); | |
| // 2秒后重置loading状态 | |
| setTimeout(() => { | |
| loading.value = false; | |
| // 不再触发searchComplete事件 | |
| }, 2000); | |
| }; | |
| </script> | |
| <template> | |
| <div class="w-full max-w-content mx-auto"> | |
| <div class="relative w-full"> | |
| <div class="relative flex flex-row items-center w-full"> | |
| <div class="relative w-full"> | |
| <input | |
| v-model="keyword" | |
| type="text" | |
| placeholder="搜索资源、电影、音乐、软件..." | |
| :disabled="loading" | |
| @keydown.enter="handleSearch" | |
| class="flex h-10 outline-none focus:outline-none rounded-md border bg-background px-3 py-2 text-sm file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 w-full text-center pr-12 transition-all duration-300 border-primary/20 hover:border-primary/40 shadow-sm hover:shadow-md focus-visible:shadow-lg focus-visible:ring-primary/30 focus-visible:ring-offset-0 focus-visible:border-primary/60" | |
| /> | |
| <button | |
| type="button" | |
| @click="handleSearch" | |
| :disabled="loading || !keyword.trim()" | |
| class="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50 w-10 absolute right-0 top-0 h-full rounded-l-none transition-all duration-300 border-0 hover:border hover:border-l-0 hover:border-primary/40 hover:bg-primary hover:text-primary-foreground hover:scale-[1.03]" | |
| > | |
| <component | |
| :is="loading ? Icons.Loading() : Icons.Send()" | |
| :class="[ | |
| 'w-4 h-4', | |
| loading && 'animate-spin' | |
| ]" | |
| /> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </template> | |
| <style scoped> | |
| .search-form { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 1rem; | |
| width: 100%; | |
| margin-bottom: 2rem; | |
| } | |
| .search-input-wrapper { | |
| position: relative; | |
| width: 100%; | |
| flex: 1; | |
| } | |
| .search-input { | |
| width: 100%; | |
| padding: 0.75rem 1rem; | |
| border-radius: 0.75rem; | |
| border: 1px solid #e5e7eb; | |
| background-color: #fff; | |
| color: #111827; | |
| font-size: 1rem; | |
| outline: none; | |
| transition: all 0.2s ease; | |
| } | |
| .search-input::placeholder { | |
| color: #9ca3af; | |
| } | |
| .search-input:focus { | |
| border-color: #3b82f6; | |
| box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2); | |
| } | |
| .search-button { | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| padding: 0.75rem 1.5rem; | |
| border-radius: 0.75rem; | |
| background-color: #3b82f6; | |
| color: #fff; | |
| font-weight: 500; | |
| font-size: 1rem; | |
| border: none; | |
| cursor: pointer; | |
| transition: all 0.2s ease; | |
| } | |
| .search-button:hover:not(:disabled) { | |
| background-color: #2563eb; | |
| } | |
| .search-button:disabled { | |
| opacity: 0.5; | |
| cursor: not-allowed; | |
| } | |
| .loading-spinner { | |
| display: inline-block; | |
| width: 1rem; | |
| height: 1rem; | |
| border: 2px solid rgba(255, 255, 255, 0.3); | |
| border-radius: 50%; | |
| border-top-color: #fff; | |
| animation: spin 0.8s linear infinite; | |
| } | |
| @keyframes spin { | |
| to { | |
| transform: rotate(360deg); | |
| } | |
| } | |
| @media (min-width: 768px) { | |
| .search-form { | |
| flex-direction: row; | |
| align-items: center; | |
| } | |
| .search-button { | |
| width: auto; | |
| white-space: nowrap; | |
| } | |
| } | |
| </style> |