Skip to content

ENHANCED: Add the Sage file grid and floating selection actions - #40

Open
bmdavis419 wants to merge 9 commits into
review/hosted-10-opsfrom
review/hosted-11-sage
Open

bmdavis419 wants to merge 9 commits into
review/hosted-10-opsfrom
review/hosted-11-sage

Conversation

@bmdavis419

@bmdavis419 bmdavis419 commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Preserve the approved Sage /E design: file facts above flat previews, floating selection actions, and shift-click selection. Keep quarantine/pending states visible, expose touch selection controls, fit narrow screens, and return from file details to the selected variant and filters. Development image previews stream originals when local transforms are unavailable.

Uploads and selection actions share a bounded dock. Notifications occupy a separate upper region while the dock stays reachable below, including on short screens. Iris selected custom tags choose readable foreground colors; generic-MIME archives use their filename extension. Sage styling remains the approved design, and default promotion is separate work.

Validation:

  • Final combined root suite passed, including 216 route/Postgres cases and 25 rune/component cases.
  • Final integrated checks passed: 25 rune/component cases, 18 focused sign-in/billing/cookie cases, TypeScript, Effect, Svelte, formatting, and Worker build.
  • Additional focused coverage passed: 4 streaming-thumbnail cases, 19 return-navigation cases, and 27 tag-contrast/file-family cases. Svelte autofixer reported no errors.
  • Second broad Codex review and targeted follow-up commit reviews were clean; independent UI and backend/navigation reviews completed.
  • Native Chromium verified real HTTP uploads, stable shift-click selection, nonoverlapping upload/bulk panels, failure toasts with accessible Clear/dismiss controls, detail return with filters, visible touch selection, and no horizontal overflow at 1280×900, 390×844, and 320×400. A selected white Iris tag rendered black label/count text. No browser runtime errors.

Stack layer 11/11: depends on #39. Browser proof uses disposable local data and development providers; production transforms, live providers, and deployment verification remain launch checks. No merge or deployment.

Note

Add Sage FileCardStack grid, design variant A-E routing, and shared selection utilities

  • Introduces a five-variant design system (A–E) with a SvelteKit variant route matcher, reactive context provider, and a layout-level variant switcher. Each variant gets theme-scoped CSS in app.css covering accents, typography, and component hooks.
  • Adds the Sage variant (E) file grid: a new FileCardStack component renders file facts above a stacked preview, with a matching FileGridSkeleton, animated count line, hex badges, and reduced-motion handling.
  • Adds reusable dashboard utilities: fileFamily MIME/extension classifier, tagForeground hex-contrast picker, shiftSelectHandlers for shift-click selection, and formatShortDate.
  • Consolidates BulkActionBar and UploadQueue into a single shared dock region in Dashboard.svelte; the upload queue is now in-flow rather than a fixed viewport overlay.
  • Switches global typography to Geist variable fonts and replaces the zinc palette with neutral grayscale values across light and dark modes.
  • Adds a development-only thumbnail fallback in +server.ts that streams the original response without rendering or storing a WebP when image transformation fails.
  • Behavioral Change: dashboardReturnHref now accepts only root or single-letter A–E dashboard paths and rejects control characters; file-detail back links fall back to the dashboard root for other values. UploadQueue no longer independently overlays the bottom-right viewport.

Macroscope summarized 9a23825.

RetriggerConfidence Score: 4/5

Not safe to merge until notifications no longer cover the authenticated account controls on narrow screens.

Fix All in CodexFindings

  1. P1 Toast blocks account controls
  2. P2 Bulk-action error toast covers the floating action controls
  3. P2 Bulk-action error toast covers the floating action controls
Fix with agent prompt
### Issue 1
apps/web/src/lib/components/ui/Toast.svelte:34
On a narrow authenticated dashboard, a visible notification occupies the same top-right area as Settings and Sign out. The changed fixed, high-layer toast intercepts clicks on both controls, so users cannot open Settings or sign out until they dismiss or wait for the notification. Move the notification below the header or reserve space for the account controls at narrow breakpoints.

### Issue 2
apps/web/src/lib/components/Dashboard.svelte:undefined-350
- When selected-file controls are present and a bulk mutation fails, the toast and bulk bar occupy the same bottom-right pixels.
- `apps/web/src/lib/components/Dashboard.svelte:350` uses `fixed right/bottom ... z-40`, while `apps/web/src/lib/components/ui/Toast.svelte:34` uses the same fixed bottom-right placement with `z-[100]`.
- Separate the bottom-right regions or place the dock in a non-conflicting corner; pointer events do not resolve visual occlusion.

### Issue 3
apps/web/src/lib/components/Dashboard.svelte:undefined-350
- **Bug**
  - When selected-file controls are present and a bulk mutation fails, the toast and bulk bar occupy the same bottom-right pixels. The toast paints over the controls, so they are visually obscured.
- **Cause**
  - `apps/web/src/lib/components/Dashboard.svelte:350` uses `fixed right/bottom ... z-40`, while `apps/web/src/lib/components/ui/Toast.svelte:34` uses the same fixed bottom-right placement with `z-[100]`. The current change adds `pointer-events-none` to the dock but leaves both rectangles and z-indexes unchanged.
- **Fix**
  - Separate the bottom-right regions (for example, offset the toast above the dock while actions/uploads are present), or place the dock in a non-conflicting corner. Do not rely on pointer-events to resolve visual occlusion.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

  • This PR adds dashboard variants, floating bulk-action and upload controls, improved file opening behavior, and revised notification placement. The revised top-right notification placement prevents access to authenticated account controls on narrow screens while a notification is visible.

Reviews (2) · Last reviewed commit: "Keep notifications clear of floating fil..."

@coderabbitai

coderabbitai Bot commented Sep 11, 2026

Copy link
Copy Markdown

Warning

Review limit reached

  • Run on-demand review

On-demand reviews are free for the next 9 days. After that, they cost $0.25 per reviewed file.

Or wait 33 minutes for your next included review.

Check out review usage here.

View limit details

Limit details: You’ve used all 6 included reviews currently available. Your 49 included PR review attempts over the past 7 days set your current allowance at 6 reviews per hour.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: dcd802ee-abd5-4d96-86c8-1e84dd80a5af

📥 Commits

Reviewing files that changed from the base of the PR and between 5746003 and 9a23825.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (35)
  • apps/web/package.json
  • apps/web/src/app.css
  • apps/web/src/lib/components/Dashboard.svelte
  • apps/web/src/lib/components/FileDetailView.svelte
  • apps/web/src/lib/components/auth/SignIn.svelte
  • apps/web/src/lib/components/dashboard/BulkActionBar.svelte
  • apps/web/src/lib/components/dashboard/DashboardHeader.svelte
  • apps/web/src/lib/components/dashboard/FileListing.svelte
  • apps/web/src/lib/components/dashboard/SearchFilterBar.svelte
  • apps/web/src/lib/components/files/FileCard.svelte
  • apps/web/src/lib/components/files/FileCardStack.svelte
  • apps/web/src/lib/components/files/FileCardStack.svelte.test.ts
  • apps/web/src/lib/components/files/FileGrid.svelte
  • apps/web/src/lib/components/files/FileGridSkeleton.svelte
  • apps/web/src/lib/components/files/FileList.svelte
  • apps/web/src/lib/components/files/FileThumb.svelte
  • apps/web/src/lib/components/tags/TagChip.svelte
  • apps/web/src/lib/components/ui/Button.svelte
  • apps/web/src/lib/components/ui/Toast.svelte
  • apps/web/src/lib/components/upload/UploadQueue.svelte
  • apps/web/src/lib/dashboard/design-variant.ts
  • apps/web/src/lib/dashboard/file-family.test.ts
  • apps/web/src/lib/dashboard/file-family.ts
  • apps/web/src/lib/dashboard/format.ts
  • apps/web/src/lib/dashboard/return-href.test.ts
  • apps/web/src/lib/dashboard/return-href.ts
  • apps/web/src/lib/dashboard/shift-select.ts
  • apps/web/src/lib/dashboard/tag-foreground.test.ts
  • apps/web/src/lib/dashboard/tag-foreground.ts
  • apps/web/src/lib/server/routes/thumbnail-stream.test.ts
  • apps/web/src/params/variant.ts
  • apps/web/src/routes/+layout.svelte
  • apps/web/src/routes/[design=variant]/+page.server.ts
  • apps/web/src/routes/[design=variant]/+page.svelte
  • apps/web/src/routes/t/[id]/[version]/grid.webp/+server.ts

Comment @coderabbitai help to get the list of available commands.

@bmdavis419
bmdavis419 added this pull request to stack #41 September 11, 2026 04:32
Comment thread apps/web/src/app.css Outdated
[data-theme='b'] .tag-chip[aria-pressed='true'] {
background: var(--tag-color, var(--color-accent-500));
border-color: var(--tag-color, var(--color-accent-500));
color: #fff;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium src/app.css:419

Selected Iris TagChips use white text against the user-controlled --tag-color, so light or white tag colors make the tag name and count nearly invisible and the active filter unreadable. Constrain tag colors to a contrast-safe palette or compute a contrasting foreground color before applying this style.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/app.css around line 419:

Selected Iris `TagChip`s use white text against the user-controlled `--tag-color`, so light or white tag colors make the tag name and count nearly invisible and the active filter unreadable. Constrain tag colors to a contrast-safe palette or compute a contrasting foreground color before applying this style.

Comment on lines +19 to +21
if (file.kind === 'site' || type === 'text/html') return 'site';
if (type.startsWith('image/')) return 'image';
if (ARCHIVE.test(type)) return 'archive';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium dashboard/file-family.ts:19

fileFamily returns other for page.html and backup.zip when API/MCP uploads use application/octet-stream, so their site/archive labels, icons, and colors are incorrect. Add filename-extension fallbacks for sites and archives alongside the content-type checks.

-\tif (file.kind === 'site' || type === 'text/html') return 'site';
+\tif (file.kind === 'site' || type === 'text/html' || /\.html?$/i.test(file.displayName)) return 'site';
 \tif (type.startsWith('image/')) return 'image';
-\tif (ARCHIVE.test(type)) return 'archive';
+\tif (ARCHIVE.test(type) || /\.(zip|gz|tar|tgz|7z|rar|bz2)$/i.test(file.displayName)) return 'archive';
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/lib/dashboard/file-family.ts around lines 19-21:

`fileFamily` returns `other` for `page.html` and `backup.zip` when API/MCP uploads use `application/octet-stream`, so their site/archive labels, icons, and colors are incorrect. Add filename-extension fallbacks for sites and archives alongside the content-type checks.

<UploadQueue {uploads} />
{#if selection.selectedFiles.length > 0 || uploads.items.length > 0}
<div
class="dashboard-dock pointer-events-none fixed right-3 bottom-3 z-40 flex max-h-[calc(100dvh-1.5rem)] max-w-[calc(100vw-1.5rem)] flex-col items-end gap-3 overflow-y-auto overscroll-contain p-1 sm:right-5 sm:bottom-5 sm:max-h-[calc(100dvh-2.5rem)] sm:max-w-[calc(100vw-2.5rem)]"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Bulk-action error toast covers the floating action controls

  • When selected-file controls are present and a bulk mutation fails, the toast and bulk bar occupy the same bottom-right pixels.
  • apps/web/src/lib/components/Dashboard.svelte:350 uses fixed right/bottom ... z-40, while apps/web/src/lib/components/ui/Toast.svelte:34 uses the same fixed bottom-right placement with z-[100].
  • Separate the bottom-right regions or place the dock in a non-conflicting corner; pointer events do not resolve visual occlusion.
Artifacts

Evidence from the check

  • The authored Playwright script renders matching pre-change and current dock/toast layouts, records both, and measures their stacking geometry; it directly checks whether the toast covers the controls.

Command output from the check

  • Captured command output records the before/current rectangles, z-indexes, and topmost element at the intersection; it confirms unchanged overlap and toast precedence.

▶ Recording of the check

  • Chromium capture of the parent Dashboard dock layout with selected-file controls and a bulk-action error toast; the toast covers the controls.

▶ Recording of the check

  • Chromium capture of the current Dashboard dock layout after `pointer-events-none` was added; the toast still covers the controls.

View artifacts

T-Rex Ran code and verified through T-Rex

<UploadQueue {uploads} />
{#if selection.selectedFiles.length > 0 || uploads.items.length > 0}
<div
class="dashboard-dock pointer-events-none fixed right-3 bottom-3 z-40 flex max-h-[calc(100dvh-1.5rem)] max-w-[calc(100vw-1.5rem)] flex-col items-end gap-3 overflow-y-auto overscroll-contain p-1 sm:right-5 sm:bottom-5 sm:max-h-[calc(100dvh-2.5rem)] sm:max-w-[calc(100vw-2.5rem)]"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Bulk-action error toast covers the floating action controls

  • Bug
    • When selected-file controls are present and a bulk mutation fails, the toast and bulk bar occupy the same bottom-right pixels. The toast paints over the controls, so they are visually obscured.
  • Cause
    • apps/web/src/lib/components/Dashboard.svelte:350 uses fixed right/bottom ... z-40, while apps/web/src/lib/components/ui/Toast.svelte:34 uses the same fixed bottom-right placement with z-[100]. The current change adds pointer-events-none to the dock but leaves both rectangles and z-indexes unchanged.
  • Fix
    • Separate the bottom-right regions (for example, offset the toast above the dock while actions/uploads are present), or place the dock in a non-conflicting corner. Do not rely on pointer-events to resolve visual occlusion.
Artifacts

Evidence from the check

  • The authored Playwright script renders matching pre-change and current dock/toast layouts, records both, and measures their stacking geometry; it directly checks whether the toast covers the controls.

Command output from the check

  • Captured command output records the before/current rectangles, z-indexes, and topmost element at the intersection; it confirms unchanged overlap and toast precedence.

▶ Recording of the check

  • Chromium capture of the parent Dashboard dock layout with selected-file controls and a bulk-action error toast; the toast covers the controls.

▶ Recording of the check

  • Chromium capture of the current Dashboard dock layout after `pointer-events-none` was added; the toast still covers the controls.

View artifacts

T-Rex Ran code and verified through T-Rex

Comment thread apps/web/src/app.css
line-height: 1.1rem;
-webkit-line-clamp: 9;
}
[data-theme='e'] .thumb-icon {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium src/app.css:704

Variant E renders quarantined files with a completely blank thumbnail: FileCardStack provides only the quarantine placeholder .thumb-icon, but this rule hides every .thumb-icon. Scope the hide rule to non-fallback thumbnails so the quarantine placeholder remains visible.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/app.css around line 704:

Variant E renders quarantined files with a completely blank thumbnail: `FileCardStack` provides only the quarantine placeholder `.thumb-icon`, but this rule hides every `.thumb-icon`. Scope the hide rule to non-fallback thumbnails so the quarantine placeholder remains visible.

Comment thread apps/web/src/app.css
}

/* A · Ember — orange on true neutrals; orange means "public". */
[data-theme='a'] {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium src/app.css:351

Variant D primary buttons render white text on #2b93e4 at only about 3.3:1 contrast, and variant A renders white text on #f97316 at about 2.8:1; both fail the 4.5:1 minimum for normal-size labels. Set a dark --accent-fg in the light-mode rules for [data-theme='d'] and [data-theme='a'] (as already done for their dark-mode variants).

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/app.css around line 351:

Variant D primary buttons render white text on `#2b93e4` at only about 3.3:1 contrast, and variant A renders white text on `#f97316` at about 2.8:1; both fail the 4.5:1 minimum for normal-size labels. Set a dark `--accent-fg` in the light-mode rules for `[data-theme='d']` and `[data-theme='a']` (as already done for their dark-mode variants).

Comment thread apps/web/src/app.css
--radius-2xl: 0.25rem;
--family-image: #c026d3;
--family-code: #16a34a;
--family-data: #ca8a04;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium src/app.css:443

In the light Terminal variant, data file links use #ca8a04 and render at only about 3.0:1 contrast on the white table background, so they fail the 4.5:1 requirement and are hard to read. Use a darker light-mode --family-data value while retaining the existing dark-mode override.

-	--family-data: #ca8a04;
+	--family-data: #a16207;
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/app.css around line 443:

In the light Terminal variant, `data` file links use `#ca8a04` and render at only about 3.0:1 contrast on the white table background, so they fail the 4.5:1 requirement and are hard to read. Use a darker light-mode `--family-data` value while retaining the existing dark-mode override.

bmdavis419 and others added 9 commits September 11, 2026 01:47
Geist and Geist Mono replace Inter, the gray scale moves to true
neutrals, and each variant remaps the accent scale plus one signature:
Ember (orange, public rule on thumbs), Iris (violet, tag color as
structure), Terminal (amber, mono names, type-family tints), Tide
(blue, search hero with ambient glow), Sage (mint, drawn rule and
typographic placeholders). Components gain stable hook classes and
data attributes the variant CSS targets; nothing changes without a
data-theme on the shell.

In development the thumbnail route serves images unresized when the
local runtime cannot transform them, so the grid shows real previews.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@bmdavis419
bmdavis419 force-pushed the review/hosted-11-sage branch from 2b6018d to 9a23825 Compare September 11, 2026 08:50
Comment on lines +29 to +30
if (ARCHIVE_EXT.test(file.displayName)) return 'archive';
return 'other';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium dashboard/file-family.ts:29

fileFamily returns other for image uploads such as photo.jpg with MIME type application/octet-stream, so they receive the generic badge/color. Unlike the other families, the extension fallback has no image check; add one for common image extensions before the final return.

 	if (ARCHIVE_EXT.test(file.displayName)) return 'archive';
+	if (/\.(avif|bmp|gif|ico|jpe?g|png|svg|webp)$/i.test(file.displayName)) return 'image';
 	return 'other';
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/lib/dashboard/file-family.ts around lines 29-30:

`fileFamily` returns `other` for image uploads such as `photo.jpg` with MIME type `application/octet-stream`, so they receive the generic badge/color. Unlike the other families, the extension fallback has no image check; add one for common image extensions before the final return.


<div
class="pointer-events-none fixed right-4 bottom-4 z-[100] flex w-[min(24rem,calc(100%-2rem))] flex-col gap-2"
class="toast-region pointer-events-none fixed top-4 right-4 z-[100] flex max-h-[calc(50dvh-1.5rem)] w-[min(24rem,calc(100vw-2rem))] flex-col gap-2 overflow-y-auto overscroll-contain"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium ui/Toast.svelte:34

The fixed z-[100] toast region now covers the header's Settings and Sign out controls on desktop, so those controls cannot be clicked while a toast is visible. Because each toast has pointer-events-auto, restore the region to the bottom placement instead of top-4.

Suggested change
class="toast-region pointer-events-none fixed top-4 right-4 z-[100] flex max-h-[calc(50dvh-1.5rem)] w-[min(24rem,calc(100vw-2rem))] flex-col gap-2 overflow-y-auto overscroll-contain"
class="pointer-events-none fixed bottom-4 right-4 z-[100] flex max-h-[calc(50dvh-1.5rem)] w-[min(24rem,calc(100vw-2rem))] flex-col gap-2 overflow-y-auto overscroll-contain"
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/lib/components/ui/Toast.svelte around line 34:

The fixed `z-[100]` toast region now covers the header's `Settings` and `Sign out` controls on desktop, so those controls cannot be clicked while a toast is visible. Because each toast has `pointer-events-auto`, restore the region to the bottom placement instead of `top-4`.


<div
class="pointer-events-none fixed right-4 bottom-4 z-[100] flex w-[min(24rem,calc(100%-2rem))] flex-col gap-2"
class="toast-region pointer-events-none fixed top-4 right-4 z-[100] flex max-h-[calc(50dvh-1.5rem)] w-[min(24rem,calc(100vw-2rem))] flex-col gap-2 overflow-y-auto overscroll-contain"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Toast blocks account controls

On a narrow authenticated dashboard, a visible notification occupies the same top-right area as Settings and Sign out. The changed fixed, high-layer toast intercepts clicks on both controls, so users cannot open Settings or sign out until they dismiss or wait for the notification. Move the notification below the header or reserve space for the account controls at narrow breakpoints.

Knowledge Base Used: File platform and web application

Artifacts

Evidence from the check

  • The executable Chromium probe renders the authenticated header and representative toast in both placements, measures hit targets, and clicks the controls; it is the validation method.

Evidence from the check

  • The shell command records the exact Bun invocation and working directory before running the Playwright validation; it documents the executed command.

Command output from the check

  • The executed probe output records 390×844 geometry, browser hit-test targets, click outcomes, and successful exit code; the top toast intercepts both controls.

▶ Recording of the check

  • Chromium recording of the prior bottom-right toast placement with visible Settings and Sign out controls; both controls remain reachable.

Before change: bottom-right toast below authenticated header

  • Poster frame from the prior placement at 390×844, showing the toast below the header controls; no overlap occurs.

▶ Recording of the check

  • Chromium recording of the current top-right toast placement with visible Settings and Sign out controls; the toast overlays them.

After change: top-right toast over Settings and Sign out

  • Poster frame from the current placement at 390×844, showing the toast covering the authenticated account controls; the overlap is visible.

View artifacts

T-Rex Ran code and verified through T-Rex

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/web/src/lib/components/ui/Toast.svelte
Line: 34

Comment:
**Toast blocks account controls**

On a narrow authenticated dashboard, a visible notification occupies the same top-right area as Settings and Sign out. The changed fixed, high-layer toast intercepts clicks on both controls, so users cannot open Settings or sign out until they dismiss or wait for the notification. Move the notification below the header or reserve space for the account controls at narrow breakpoints.

**Knowledge Base Used:** [File platform and web application](https://app.greptile.com/davis7dotsh/-/custom-context/knowledge-base/davis7dotsh/adrive/-/docs/file-platform.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Codex

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant