feat: delta/instant upload + frontend UI/UX polish
Bundles the backend+frontend delta-upload (content-dedup) feature with a batch of frontend fixes from this session. Upload / dedup: - Client-hashed delta & instant upload (deltaUpload, hashWasm vendor shim) - Backend dedup batch endpoint (dedup_service, dedup_handler, routes) - session store owned-hash helpers; unit tests + upload-strategy bench Frontend UI/UX: - Colour file-type icons in grid/list (per-type tinted tiles + glyph hue) - Robust thumbnail fallback; PDFs now show their type icon (backend generates no PDF thumbnails) instead of a blank tile - Fix PDF preview: load via a same-origin blob: iframe — the API URL is blocked by the global X-Frame-Options: DENY in the browser's framed PDF viewer, matching the existing CSP `frame-src blob:` design - Groups: localized virtual-group description (no DB schema-note leak), add nav.groups to the 15 missing locales, fix primary-button contrast - Repoint --color-text-light → --color-on-accent (was faint grey on accent) - Nudge the admin role badge off the user-menu header divider Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -236,7 +236,11 @@
|
||||
--color-text-gray: var(--color-text-muted);
|
||||
--color-text-medium: var(--color-text-muted);
|
||||
--color-text-faint2: var(--color-text-faint);
|
||||
--color-text-light: var(--color-text-faint);
|
||||
/* "Light" = light-coloured (near-white) text for accent/dark fills, NOT a
|
||||
* faint tier. Every consumer is a primary button (background: --color-primary),
|
||||
* so this must resolve to the on-accent foreground, not muted grey — which
|
||||
* rendered muddy and failed contrast on the orange accent. */
|
||||
--color-text-light: var(--color-on-accent);
|
||||
--color-text-placeholder: var(--color-text-faint);
|
||||
|
||||
/* Accent (orange) — mostly mode-agnostic. */
|
||||
@@ -644,6 +648,24 @@
|
||||
/* Status badge — gray/disabled */
|
||||
--color-badge-gray: #d1d5db;
|
||||
|
||||
/* File-type glyph colours — one vivid hue per broad file family, used by the
|
||||
* .file-icon--* buckets (resourceList.css) so the grid/list type icons read
|
||||
* as colourful tiles instead of flat monochrome. Tile tints are derived from
|
||||
* these with color-mix(), so only the foreground hue lives here. Dark-mode
|
||||
* shades are lightened for contrast against the dark tile fill. */
|
||||
--file-kind-folder: light-dark(#3b82f6, #60a5fa);
|
||||
--file-kind-pdf: light-dark(#ef4444, #f87171);
|
||||
--file-kind-doc: light-dark(#2563eb, #60a5fa);
|
||||
--file-kind-sheet: light-dark(#16a34a, #4ade80);
|
||||
--file-kind-slides: light-dark(#ea580c, #fb923c);
|
||||
--file-kind-archive: light-dark(#d97706, #fbbf24);
|
||||
--file-kind-code: light-dark(#7c3aed, #a78bfa);
|
||||
--file-kind-image: light-dark(#0891b2, #22d3ee);
|
||||
--file-kind-video: light-dark(#c026d3, #e879f9);
|
||||
--file-kind-audio: light-dark(#db2777, #f472b6);
|
||||
--file-kind-text: light-dark(#475569, #94a3b8);
|
||||
--file-kind-generic: light-dark(#64748b, #94a3b8);
|
||||
|
||||
/* (Removed: the legacy dark-mode badge tokens that lived here had zero
|
||||
* consumers — the light-dark() badge tokens above are the single source.) */
|
||||
|
||||
|
||||
@@ -43,6 +43,69 @@
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* ── File-type colours ───────────────────────────────────────
|
||||
Each bucket sets a local --fk (the foreground hue, from the
|
||||
--file-kind-* tokens). The glyph takes --fk directly and the tile
|
||||
fill/ring derive soft tints from it with color-mix(), so the icons read
|
||||
as colourful tiles instead of flat monochrome. Adding a bucket is a
|
||||
single custom-property line; the consuming rules never change. */
|
||||
.file-icon {
|
||||
--fk: var(--file-kind-generic);
|
||||
}
|
||||
|
||||
.file-icon--folder {
|
||||
--fk: var(--file-kind-folder);
|
||||
}
|
||||
|
||||
.file-icon--pdf {
|
||||
--fk: var(--file-kind-pdf);
|
||||
}
|
||||
|
||||
.file-icon--doc {
|
||||
--fk: var(--file-kind-doc);
|
||||
}
|
||||
|
||||
.file-icon--sheet {
|
||||
--fk: var(--file-kind-sheet);
|
||||
}
|
||||
|
||||
.file-icon--slides {
|
||||
--fk: var(--file-kind-slides);
|
||||
}
|
||||
|
||||
.file-icon--archive {
|
||||
--fk: var(--file-kind-archive);
|
||||
}
|
||||
|
||||
.file-icon--code {
|
||||
--fk: var(--file-kind-code);
|
||||
}
|
||||
|
||||
.file-icon--image {
|
||||
--fk: var(--file-kind-image);
|
||||
}
|
||||
|
||||
.file-icon--video {
|
||||
--fk: var(--file-kind-video);
|
||||
}
|
||||
|
||||
.file-icon--audio {
|
||||
--fk: var(--file-kind-audio);
|
||||
}
|
||||
|
||||
.file-icon--text {
|
||||
--fk: var(--file-kind-text);
|
||||
}
|
||||
|
||||
.file-icon--generic {
|
||||
--fk: var(--file-kind-generic);
|
||||
}
|
||||
|
||||
.file-icon > i,
|
||||
.file-icon > svg {
|
||||
color: var(--fk);
|
||||
}
|
||||
|
||||
/* ── Item states ─────────────────────────────────────────── */
|
||||
|
||||
.file-item {
|
||||
@@ -355,9 +418,10 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: var(--radius-lg);
|
||||
/* Hairline inner ring — consistent with the grid thumbnails so light
|
||||
previews don't bleed into the row. */
|
||||
box-shadow: inset 0 0 0 1px var(--color-border);
|
||||
/* Soft type-tinted tile + matching hairline ring so the row glyph reads as
|
||||
a colourful chip (and light previews don't bleed into the row). */
|
||||
background: color-mix(in srgb, var(--fk) 12%, transparent);
|
||||
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--fk) 22%, var(--color-border));
|
||||
font-size: var(--text-md);
|
||||
margin-bottom: 0;
|
||||
flex-shrink: 0;
|
||||
@@ -859,9 +923,11 @@
|
||||
height: auto;
|
||||
aspect-ratio: 4 / 3;
|
||||
border-radius: var(--radius-lg);
|
||||
background: var(--color-bg-input);
|
||||
/* Hairline inner ring so light thumbnails don't bleed into the card. */
|
||||
box-shadow: inset 0 0 0 1px var(--color-border);
|
||||
/* Soft type-tinted fill + matching hairline ring (a thumbnail, when
|
||||
present, covers both edge-to-edge). Gives non-preview files a modern
|
||||
colourful tile keyed to their type instead of a flat grey panel. */
|
||||
background: color-mix(in srgb, var(--fk) 9%, var(--color-bg-input));
|
||||
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--fk) 22%, var(--color-border));
|
||||
margin: 0 0 var(--space-3);
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
@@ -262,7 +262,7 @@
|
||||
}
|
||||
|
||||
.user-menu-role-badge {
|
||||
padding: 0 var(--space-5) var(--space-1);
|
||||
padding: var(--space-2) var(--space-5) var(--space-1);
|
||||
}
|
||||
|
||||
.role-badge {
|
||||
|
||||
Reference in New Issue
Block a user