From a6a5add2f23e0f58bc6584d60fda7cd8aee887e0 Mon Sep 17 00:00:00 2001 From: Momentry Studio Date: Sun, 14 Jun 2026 14:07:29 +0800 Subject: [PATCH] refactor: SearchView + PeopleView layout alignment with WordPress CSS --- src/views/PeopleView.vue | 177 +++++++++++++++++++++------------------ src/views/SearchView.vue | 68 ++++++++++----- 2 files changed, 143 insertions(+), 102 deletions(-) diff --git a/src/views/PeopleView.vue b/src/views/PeopleView.vue index 8fec49f..ff677e2 100644 --- a/src/views/PeopleView.vue +++ b/src/views/PeopleView.vue @@ -1,36 +1,54 @@ @@ -104,6 +132,7 @@ const showCandidates = ref(false) const showMerge = ref(false) const mergeTarget = ref('') const candidates = ref([]) +const candidateThumbs = ref>({}) const filteredPeople = computed(() => { if (isSearching.value && searchResults.value.length) return searchResults.value @@ -141,6 +170,11 @@ async function loadProfile(uuid: string) { try { profiles.value[uuid] = await invoke('get_identity_profile', { uuid }) } catch {} } +async function loadCandidateThumb(uuid: string) { + if (!uuid || candidateThumbs.value[uuid]) return + try { candidateThumbs.value[uuid] = await invoke('get_thumbnail', { uuid, frame: 30 }) } catch {} +} + async function selectPerson(p: any) { selected.value = p selectedProfile.value = profiles.value[p.identity_uuid] || '' @@ -215,50 +249,33 @@ watch(showCandidates, (v) => { if (v) loadCandidates() }) diff --git a/src/views/SearchView.vue b/src/views/SearchView.vue index 15a4e28..81226e3 100644 --- a/src/views/SearchView.vue +++ b/src/views/SearchView.vue @@ -3,27 +3,36 @@

Search

-
- + +
+
+

Searching...

+
+
-
+ +
+
+
@@ -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([]) const loading = ref(false) const searched = ref(false) +const thumbs = ref>({}) 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); } }