Files
Oxicloud/static/js/app/searchView.js
T
DioCrafts 81a93a489b feat: photo/video capture-date pipeline + premium UI/UX overhaul
Backend — Photos timeline now groups by real capture date instead of upload time. New MediaMetadataService (FileLifecycleHook) extracts EXIF DateTimeOriginal from images and container creation_time from videos (mov/mp4/mkv) via nom-exif, timezone-correct (OffsetTimeOriginal), persisting captured_at so the existing media_sort_date trigger takes over. Adds POST /admin/photos/metadata/reextract to backfill existing media. Falls back to upload date when no embedded date exists.

Frontend — premium grid cards: combined metadata line (relative date · size, owner avatar when shared), custom selection checkbox with a clear checked state, uniform full-width 4:3 thumbnail tiles independent of filename length, centered file-type icons, and a hit-test fix so checkbox/star/kebab clicks reach the controls (the decorative thumbnail no longer captures pointer events). Notification messages internationalised across all 16 locales. Broader polish: design tokens, a11y/focus-visible states, brand + PWA assets.

Chore — bump semver-compatible dependencies (cargo upgrade); add nom-exif 3.6.1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 00:24:27 +02:00

68 lines
2.1 KiB
JavaScript

/**
* Search view orchestration logic
*/
import { i18n } from '../core/i18n.js';
import { search } from '../features/files/search.js';
import { resolveHomeFolder } from './authSession.js';
import { app } from './state.js';
import { ui } from './ui.js';
/**
* @import {SearchCriteria, SortByEnnum} from '../core/types.js'
*/
/**
* @param {string} query
* @param {SortByEnnum} [sortBy]
*/
// FIXME: refactor with search.js ?
async function performSearch(query, sortBy) {
console.log(`Performing search for: "${query}" (sort: ${sortBy || 'relevance'})`);
try {
app.isSearchMode = true;
ui.updateBreadcrumb();
ui.showError(`<h3><i class="fas fa-spinner fa-spin search-spinner"></i> Searching for "${query}"...</h3>`);
/** @type {SearchCriteria} */
const options = {
recursive: true,
limit: 100,
offset: 0,
sort_by: sortBy || 'relevance'
};
if (app.currentSection !== 'trash') {
// Ensure we have a valid folder_id before searching
if (!app.currentPath || app.currentPath === '') {
await resolveHomeFolder();
}
// Only set folder_id if we have a valid value
if (app.currentPath && app.currentPath !== '') {
options.folder_id = app.currentPath;
}
// If still no valid folder_id, search will be global (without folder_id)
}
const searchResults = await search.searchFiles(query, options);
search.displaySearchResults(searchResults);
} catch (error) {
console.error('Search error:', error);
ui.showNotification(i18n.t('notif.errorTitle'), i18n.t('notif.searchError'));
}
}
document.addEventListener('search-resort', (e) => {
const event = /** @type {CustomEvent<{sort_by: string}>} */ (e);
const searchInput = /** @type {HTMLInputElement} */ (document.querySelector('.search-container input'));
if (searchInput?.value.trim()) {
const sortBy = /** @type {SortByEnnum} */ (event.detail.sort_by);
performSearch(searchInput.value.trim(), sortBy);
}
});
export { performSearch };