Files
Oxicloud/static/share.html
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

88 lines
4.5 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Declares the page supports both modes. Switching between them is
driven by the CSS `color-scheme` property (via the `data-color-scheme`
attribute on <html> set by theme-init.js), not by mutating this tag. -->
<meta name="color-scheme" content="light dark">
<title>OxiCloud — Shared</title>
<link rel="icon" type="image/svg+xml" href="/logo/logo-plain.svg">
<link rel="icon" href="/favicon.ico" sizes="32x32">
<link rel="apple-touch-icon" href="/logo/apple-touch-icon.png">
<link rel="mask-icon" href="/logo/logo-plain.svg" color="#ff5e3a">
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" media="(prefers-color-scheme: light)" content="#f5f7fa">
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#0f172a">
<meta property="og:type" content="website">
<meta property="og:title" content="OxiCloud — Shared">
<meta property="og:description" content="A file shared with you via OxiCloud.">
<meta property="og:image" content="/logo/og-image.png">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="OxiCloud — Shared">
<meta name="twitter:description" content="A file shared with you via OxiCloud.">
<meta name="twitter:image" content="/logo/og-image.png">
<script src="/js/core/theme-init.js"></script>
<script type="module" src="/js/core/icons.js"></script>
<link rel="stylesheet" href="/css/main.css">
<link rel="stylesheet" href="/css/views/share-public.css">
</head>
<body>
<div class="share-card" id="share-card" role="main">
<div class="share-logo">
<span class="brand-mark"><svg viewBox="120 120 280 280"><path d="M345 310c32 0 58-26 58-58s-26-58-58-58c-6.2 0-12 0.9-17.5 2.7C318 166 289 143 255 143c-34.3 0-63.1 22.6-73 53.7C176.9 195.7 171 195 165 195c-32 0-58 26-58 58s26 58 58 58h180z"/></svg></span>
<h1><span>Oxi</span>Cloud</h1>
</div>
<noscript>
<p class="subtitle">JavaScript is required to open this shared link.</p>
</noscript>
<!-- Loading state -->
<div id="share-loading" class="share-state">
<div class="spinner"></div>
<p>Loading shared content&hellip;</p>
</div>
<!-- Password prompt -->
<div id="share-password" class="share-state hidden">
<h2>Password Required</h2>
<p class="subtitle">This shared content is protected. Enter the password to continue.</p>
<form id="password-form" autocomplete="off">
<input type="password" id="password-input" placeholder="Password" required />
<div id="password-error" class="error-text hidden"></div>
<button type="submit" class="btn-primary">Unlock</button>
</form>
</div>
<!-- Expired / error -->
<div id="share-expired" class="share-state hidden">
<div class="share-icon expired-icon"><svg width="56" height="56" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg></div>
<h2>Link Unavailable</h2>
<p class="subtitle" id="expired-message">This share link has expired or is no longer available.</p>
</div>
<!-- File share view -->
<div id="share-file" class="share-state hidden">
<div class="share-icon file-icon" id="file-type-icon"><svg width="56" height="56" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg></div>
<h2 id="file-name"></h2>
<p class="subtitle" id="file-meta"></p>
<a id="file-download" class="btn-primary" download>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
Download
</a>
</div>
<!-- Folder share view: populated by publicShare.js -->
<div id="share-folder" class="share-state hidden"></div>
<footer class="share-trust">
<i class="fas fa-lock" aria-hidden="true"></i> Secured by OxiCloud
</footer>
</div>
<script type="module" src="/js/views/public/publicShare.js"></script>
</body>
</html>