Skip to content

Updated the media browser component - #499

Merged
ddon merged 11 commits into
BeamLabEU:devfrom
alexdont:dev
Apr 20, 2026
Merged

Updated the media browser component#499
ddon merged 11 commits into
BeamLabEU:devfrom
alexdont:dev

Conversation

@alexdont

Copy link
Copy Markdown
Contributor

No description provided.

Alexander Don and others added 11 commits April 19, 2026 22:36
Move project logo from authorization to main settings page. Add site
icon (favicon) setting with browser tab preview mockup. Add default
tab title setting for browser tab fallback text. Layout wrapper reads
both settings to render dynamic favicon and tab title.

Also: fix recursive CTE in scoped trash query, use scope folder name
instead of hardcoded "Root" in MediaBrowser, remove file counts from
content area headers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix scope guard gap in restore_selected and append PR BeamLabEU#497 follow-up review

Address PR review: make MediaBrowser uploads work in embedded components

Parent LiveViews embedding MediaBrowser must register uploads on their
own socket since LiveView routes upload channel events to the parent.
Add setup_uploads/1 helper and handle_parent_info/2 catch-all. The
component tracks its id with the parent via :register_component
message, and uploads are routed back to the component via send_update
with a :pending_upload key so folder placement uses the component's
current state.

- Hide All Files button when scoped (only on admin page)
- Show scope folder name instead of "Root" in sidebar/header
- Remove file count from header titles
- Bypass scope check on initial upload placement (files start at root)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove phx-target from the hidden upload form so validate events route
to the parent LiveView where uploads are registered. Enable the
FolderDropUpload hook whenever buckets are available (not only when in
a subfolder). Drop a file anywhere in the media browser to auto-upload
with inline progress bars.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Hide the search bar by default behind a magnifying glass icon button
in the header. Click to expand the search input, click again to
collapse. The bar stays visible when a search query is active, and
the toggle button highlights to indicate the active state.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Attach MediaDragDrop hook to the component root so existing
data-draggable-file and data-drop-folder attributes on files/folders
become functional. Use pushEventTo(self.el) to route the move event
to the component instead of the parent LiveView.

Fix FolderDropUpload hook to ignore internal drags by checking for
"Files" in dataTransfer.types, so device uploads and folder moves
don't interfere.

Change scoped root query to show only direct children (not the full
subtree) so files moved into subfolders visually disappear from the
root view. Searches still walk the full subtree via recursive CTE.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Wrap sidebar and content area in a shared card with rounded corners
and shadow so they look like one component instead of separate pieces.
Remove the inner content card's shadow, add left padding to the
content area for breathing room, and hide the "Folders" sidebar
header in scoped embeds.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Removed the `[data-media-view]` display rules and the pre-render script
that synced `html.dataset.mediaView` from localStorage. The server now
conditionally renders only one of the grid or list view based on
@view_mode, so those CSS rules could incorrectly hide the list view when
localStorage held a stale value.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The inline "Folder name" input at the scope root was indented less than
the folder rows above it because it lacked the chevron spacer and used a
different outer gap. Added the w-5 spacer, matched gap-0.5 on the form,
and set ml-1.5 before the input so icons line up vertically.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Click on a file now only pushes to /admin/media/:uuid when the component
is rendered with admin={true}. In any other embedding the click toggles
the file into the selection and switches select_mode on, so the component
acts as a picker by default. The admin media page opts in explicitly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Selection header gains a `…` dropdown with Download and Delete. Download
pushes a `download_files` client event consumed by the MediaDragDrop hook,
which fires one staggered `<a download>` click per file. Delete covers
both files (trashed) and folders (removed) in a single action, with a
context-aware confirmation built by `delete_selected_confirm/3`.

Introduces `PhoenixKitWeb.Components.MediaBrowser.Embed` so embedding the
browser is a single `use` line on the parent LiveView. The macro attaches
an `on_mount` that calls `setup_uploads/1` and injects the `"validate"`
upload-channel stub and `handle_info` delegator via `@before_compile`, so
user clauses for other events/messages still match first. `users/media.ex`
is migrated to the macro as the reference caller.

AGENTS.md gets a MediaBrowser Component section covering the one-line
embed, the `parent_uploads` template requirement, the `admin` attr, the
built-in selection actions, and the manual-wiring fallback.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The fully-qualified PhoenixKitWeb.Components.MediaBrowser references
inside __before_compile__ are intentional: the quote is injected into
the caller's module, where any alias declared in Embed wouldn't be in
scope. Suppress the Credo suggestion locally and leave a note about why.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ddon
ddon merged commit 2d8a85e into BeamLabEU:dev Apr 20, 2026
ddon pushed a commit that referenced this pull request Apr 20, 2026
Covers three merged PRs since 1.7.98:
- #498: V100 staff + V101 projects migrations
- #499: MediaBrowser Embed macro, selection menu/bulk download, admin
  attr, drag-drop file→folder move, toggleable search, drag-drop upload
  at any folder level, unified sidebar/content card, site icon + tab
  title + logo settings
- #500: V102 smart-catalogue + discount migration, multilang debounce
  flow (attach_hook + client-side skeleton toggles), core form
  class/wrapper_class realignment, CSS sources abs-path fix, Elixir
  1.19 test filters, AGENTS.md core form + multilang docs + CHANGELOG
  ownership rule

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ddon ddon mentioned this pull request Apr 20, 2026
3 tasks
alexdont pushed a commit to alexdont/phoenix_kit that referenced this pull request Apr 23, 2026
Addresses follow-ups from PR BeamLabEU#499 review.

maybe_set_folder/2 now verifies the target folder is in-scope before
passing nil to Storage.move_file_to_folder/3. Previously the scope-bypass
was load-bearing but implicit — a refactor of folder_uuid derivation
could have silently turned it into "ignore scope entirely." Out-of-scope
placements are now refused with a log line instead.

Upload processing buffers results into :pending_batch and schedules a
single commit via send_update_after after a 250ms debounce window.
Dragging ten files onto a folder now triggers one reload_current_page
and one combined flash ("10 new files uploaded") instead of ten serial
reloads and overlapping flashes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

2 participants