Files
Oxicloud/static/css/components/spinner.css
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

97 lines
2.4 KiB
CSS

/* Loading spinner overlay */
.files-loading-spinner {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: var(--space-20) var(--space-5);
gap: var(--space-4);
grid-column: 1 / -1;
}
.files-loading-spinner .spinner {
width: 36px;
height: 36px;
border: 3px solid var(--color-border);
border-top-color: var(--color-accent);
border-radius: 50%;
animation: spin 0.7s linear infinite;
}
/* @keyframes spin → base/animations.css (canonical, loaded via main.css). */
.files-loading-spinner span {
font-size: var(--text-base);
color: var(--color-text-placeholder);
font-weight: var(--weight-medium);
}
/* Full-area drop overlay. Hidden by default; shown over the content region
(right of the sidebar) while files are dragged into the Files section
(toggled in ui.js). Frosted backdrop + dashed border = a clear "drop here"
affordance instead of a small inline box. */
.dropzone {
position: fixed;
top: var(--space-4);
right: var(--space-4);
bottom: var(--space-4);
left: calc(var(--sidebar-width) + var(--space-4));
z-index: var(--z-overlay);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: var(--space-4);
border: 3px dashed var(--color-border-medium);
border-radius: var(--radius-3xl);
background: var(--color-scrim-control);
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
color: var(--color-text-secondary);
font-size: var(--text-lg);
font-weight: var(--weight-semibold);
text-align: center;
}
/* Children don't catch pointer events, so moving over the icon/text doesn't
fire dragleave on the overlay (avoids show/hide flicker). */
.dropzone > * {
pointer-events: none;
}
.dropzone-icon {
font-size: var(--text-6xl);
color: var(--color-accent);
}
.dropzone.active {
border-color: var(--color-accent);
color: var(--color-accent-text);
}
@media (max-width: 768px) {
.dropzone {
left: var(--space-4);
}
}
.upload-progress {
margin-top: 15px;
width: 100%;
display: block;
}
.progress-bar {
background-color: var(--color-bg-empty);
height: 6px;
border-radius: 3px;
overflow: hidden;
}
.progress-fill {
height: 100%;
background-color: var(--color-accent);
width: 0%;
transition: width 0.3s;
}