refactor: SearchView + PeopleView layout alignment with WordPress CSS

This commit is contained in:
2026-06-14 14:07:29 +08:00
parent 6c262acff0
commit a6a5add2f2
2 changed files with 143 additions and 102 deletions

View File

@@ -3,27 +3,36 @@
<div class="search-header">
<h1>Search</h1>
<div class="mode-selector">
<button v-for="m in modes" :key="m.value"
<button v-for="m in modes" :key="m.value"
:class="['mode-btn', { active: mode === m.value }]"
@click="mode = m.value">
{{ m.label }}
</button>
</div>
</div>
<div class="search-bar">
<input v-model="query" @keyup.enter="search"
placeholder="Enter search query..."
<input v-model="query" @keyup.enter="search"
placeholder="Enter search query..."
:disabled="loading" />
<button @click="search" :disabled="loading || !query">
<button class="ms-fm-btn ms-fm-btn-primary" @click="search" :disabled="loading || !query">
<span v-if="loading" class="spinner"></span>
{{ loading ? 'Searching...' : 'Search' }}
</button>
</div>
<div v-if="loading && !results.length" class="loading-state">
<div class="spinner-lg"></div>
<p>Searching...</p>
</div>
<div class="results" v-if="results.length">
<div v-for="(r, i) in results" :key="i" class="result-card" @click="playVideo(r)">
<div class="result-thumb">
<div class="play-icon"></div>
<img v-if="thumbs[r.file_uuid]" :src="thumbs[r.file_uuid]" alt="" loading="lazy" @vue:mounted="loadThumb(r.file_uuid)">
<div v-else class="thumb-placeholder" @vue:mounted="loadThumb(r.file_uuid)">
<div class="play-icon"></div>
</div>
</div>
<div class="result-info">
<div class="result-meta">
@@ -55,8 +64,7 @@ import VideoPlayer from '../components/VideoPlayer.vue'
const modes = [
{ label: 'Keyword', value: 'keyword' },
{ label: 'Semantic', value: 'semantic' },
{ label: 'Agent', value: 'agent' }
{ label: 'Semantic', value: 'semantic' }
]
const mode = ref('semantic')
@@ -64,6 +72,7 @@ const query = ref('')
const results = ref<any[]>([])
const loading = ref(false)
const searched = ref(false)
const thumbs = ref<Record<string, string>>({})
const playing = ref(false)
const currentVideo = ref({ fileUuid: '', startTime: 0, endTime: 0, title: '' })
@@ -83,6 +92,15 @@ async function search() {
}
}
async function loadThumb(uuid: string) {
if (!uuid || thumbs.value[uuid]) return
try {
thumbs.value[uuid] = await invoke('get_thumbnail', { uuid, frame: 30 })
} catch {
// keep placeholder
}
}
function formatTime(sec: number): string {
const m = Math.floor(sec / 60)
const s = Math.floor(sec % 60)
@@ -105,22 +123,28 @@ function playVideo(r: any) {
.search-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 24px; }
h1 { font-size: 1.5rem; }
.mode-selector { display: flex; gap: 8px; }
.mode-btn { padding: 8px 16px; border: 1px solid #d1d5db; background: #fff; border-radius: 8px; cursor: pointer; font-size: 0.85rem; }
.mode-btn.active { background: #4f46e5; color: #fff; border-color: #4f46e5; }
.mode-btn { padding: 8px 16px; border: 1.5px solid #d1d5db; background: #fff; border-radius: 10px; cursor: pointer; font-size: 0.85rem; font-weight: 500; transition: all 0.15s; }
.mode-btn:hover { background: #f3f4f6; }
.mode-btn.active { background: #202124; color: #fff; border-color: #202124; }
.search-bar { display: flex; gap: 10px; margin-bottom: 24px; }
.search-bar input { flex: 1; padding: 12px 16px; border: 1px solid #d1d5db; border-radius: 8px; font-size: 1rem; }
.search-bar input { flex: 1; padding: 12px 16px; border: 1.5px solid #d1d5db; border-radius: 10px; font-size: 1rem; outline: none; transition: border-color 0.15s; }
.search-bar input:focus { border-color: #202124; }
.search-bar input:disabled { background: #f3f4f6; }
.search-bar button { padding: 12px 24px; background: #4f46e5; color: #fff; border: none; border-radius: 8px; cursor: pointer; font-weight: 500; }
.search-bar button:disabled { opacity: 0.6; cursor: not-allowed; }
.result-card { display: flex; gap: 16px; background: #fff; border: 1px solid #e5e7eb; border-radius: 12px; padding: 16px; margin-bottom: 12px; cursor: pointer; transition: border-color 0.15s, box-shadow 0.15s; }
.result-card:hover { border-color: #4f46e5; box-shadow: 0 4px 12px rgba(79,70,229,0.1); }
.result-thumb { width: 120px; height: 68px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 8px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.result-card { display: flex; gap: 16px; background: #fff; border: 1px solid #e8eaed; border-radius: 12px; padding: 16px; margin-bottom: 12px; cursor: pointer; transition: transform 0.15s, box-shadow 0.15s; }
.result-card:hover { transform: translateY(-2px); box-shadow: 0 6px 18px rgba(0,0,0,0.1); }
.result-thumb { width: 120px; height: 68px; border-radius: 8px; overflow: hidden; flex-shrink: 0; background: #e8eaed; }
.result-thumb img { width: 100%; height: 100%; object-fit: cover; }
.thumb-placeholder { width: 100%; height: 100%; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); display: flex; align-items: center; justify-content: center; }
.play-icon { color: #fff; font-size: 1.5rem; opacity: 0.8; }
.result-info { flex: 1; }
.result-info { flex: 1; min-width: 0; }
.result-meta { display: flex; gap: 12px; margin-bottom: 6px; }
.score { color: #4f46e5; font-weight: 600; font-size: 0.85rem; }
.time { color: #6b7280; font-size: 0.85rem; }
.summary { color: #374151; margin-bottom: 4px; }
.file-name { color: #9ca3af; font-size: 0.8rem; }
.no-results { text-align: center; padding: 40px; color: #6b7280; }
.score { color: #1a56db; font-weight: 600; font-size: 0.85rem; }
.time { color: #9aa0a6; font-size: 0.85rem; }
.summary { color: #3c4043; margin-bottom: 4px; line-height: 1.4; }
.file-name { color: #9aa0a6; font-size: 0.8rem; }
.no-results { text-align: center; padding: 40px; color: #5f6368; }
.loading-state { text-align: center; padding: 60px 0; color: #5f6368; }
.spinner { display: inline-block; width: 14px; height: 14px; border: 2px solid rgba(255,255,255,0.3); border-top-color: #fff; border-radius: 50%; animation: spin 0.6s linear infinite; margin-right: 6px; }
.spinner-lg { width: 24px; height: 24px; border: 3px solid #e8eaed; border-top-color: #202124; border-radius: 50%; animation: spin 0.7s linear infinite; margin: 0 auto 12px; }
@keyframes spin { to { transform: rotate(360deg); } }
</style>