81a93a489b
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>
25 lines
1.6 KiB
XML
25 lines
1.6 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
||
<!-- Social share image (1200×630). SOURCE asset — most platforms ignore SVG
|
||
og:images, so export this to og-image.png for full Facebook/Twitter/etc.
|
||
support and point the meta tags at the PNG. -->
|
||
<svg viewBox="0 0 1200 630" xmlns="http://www.w3.org/2000/svg"
|
||
font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif">
|
||
<defs>
|
||
<linearGradient id="oxi-og-tile" x1="0" y1="0" x2="1" y2="1">
|
||
<stop offset="0" stop-color="#ff5e3a"/>
|
||
<stop offset="1" stop-color="#ff8a5c"/>
|
||
</linearGradient>
|
||
</defs>
|
||
<rect width="1200" height="630" fill="#0f172a"/>
|
||
<circle cx="1000" cy="110" r="280" fill="#ff5e3a" opacity="0.08"/>
|
||
<circle cx="150" cy="560" r="220" fill="#ff5e3a" opacity="0.06"/>
|
||
<rect x="490" y="158" width="140" height="140" rx="34" fill="url(#oxi-og-tile)"/>
|
||
<g transform="translate(560 228) scale(0.34) translate(-250 -250)">
|
||
<path
|
||
d="m 364.14537,344.11776 c 40.65049,0 73.64219,-32.99169 73.64219,-73.64218 0,-40.65047 -32.9917,-73.64217 -73.64219,-73.64217 -7.80607,0 -15.17028,1.17827 -22.23993,3.38754 -11.04633,-40.94506 -47.57285,-69.6655 -91.16903,-69.6655 -43.59616,0 -80.12268,28.72044 -92.64185,68.19265 -7.06965,-0.73642 -14.43386,-1.91469 -22.23994,-1.91469 -40.65049,0 -73.64218,32.9917 -73.64218,73.64217 0,40.65049 32.99169,73.64218 73.64218,73.64218 z"
|
||
fill="#ffffff"/>
|
||
</g>
|
||
<text x="600" y="400" text-anchor="middle" fill="#f1f5f9" font-size="78" font-weight="700">OxiCloud</text>
|
||
<text x="600" y="452" text-anchor="middle" fill="#94a3b8" font-size="30">Fast, private cloud storage built with Rust</text>
|
||
</svg>
|