Media gallery template for image/file-heavy data.
Optimized for displaying images, videos, and files with:
- Thumbnail grid with hover preview
- Lightbox for full-size viewing
- File type icons for non-image files
- Quick actions overlay
Features
:filter- Filter by file type, date, etc.:select- Multi-select for bulk operations:bulk_actions- Bulk download, delete, move:paginate- Infinite scroll preferred:expand- Lightbox expansion
Column-Based Layout
MediaGallery uses the columns DSL to determine what to display:
- First visible column becomes the thumbnail image
- Remaining visible columns are rendered below the thumbnail in order
Use visible fn state -> state.template.name() == :media_gallery end to show columns
only in MediaGallery, or visible fn state -> state.template.name() == :table end
for Table-only columns.
The card's actions
A card draws its row actions in three parts: a star toggle over the thumbnail, one wide labelled
button, and bordered squares beside it, red if they destroy something. split_actions/3 sorts
them, and the :overlay_action / :primary_action options below name which action goes where.
The thumbnail that fails to load
A card paints its type glyph behind the thumbnail, so a broken <img> only has to be hidden for
the glyph to show through; a thumbnail that does load sits on white, so a transparent PNG does not
pick up the tile's tint.
The consuming app must register a MediaThumb JS hook in its admin bundle. It reads
data-loaded-background from the hook element for the colour a loaded image sits on, and binds
load/error on the <img> inside it.
Options
:columns- Number of grid columns (3, 4, 6, or 8):overlay_action- the action drawn as the star over the thumbnail (default:toggle_featured):primary_action- the action drawn wide and labelled (default:edit)
Performance
Uses @static.* for columns, ui_adapter, etc. (no re-render on user interaction)
Uses @state.* for page, filter_values, etc. (re-renders when changed)
See MishkaGervaz.Table.Behaviours.Template,
MishkaGervaz.Table.Templates.Shared,
MishkaGervaz.Table.Templates.Table (sibling), and
MishkaGervaz.UIAdapters.MediaGallery (paired UI adapter).
Summary
Functions
Whether this file is featured — the star, and the card's gold ring.
The adapter a media card is drawn with, unless the resource named one of its own.
The switcher draws this glyph for the gallery view.
The name of the category a file belongs to, or nil.
The date a file was added, formatted for a card, or nil when it is not loaded.
A file's extension as declared by its format attribute, or nil.
A file's display name, with its extension when the record carries one.
A file's size, humanised, or an em dash when the record has none.
A record's media type — :images, :videos, :documents, or nil.
Callback implementation for MishkaGervaz.Table.Behaviours.Template.render_bulk_actions/1.
Callback implementation for MishkaGervaz.Table.Behaviours.Template.render_error/1.
Callback implementation for MishkaGervaz.Table.Behaviours.Template.render_pagination/1.
Callback implementation for MishkaGervaz.Table.Behaviours.Template.render_template_switcher/1.
Whether this record is selected, under either selection mode.
The card's three action groups: the star over the thumbnail, the one wide button, and the squares.
The URL of a record's thumbnail, or nil when it has none to show.
The background wash a file's type gets. See media_type/1.
The glyph a file wears when there is no thumbnail to show instead.
Functions
Whether this file is featured — the star, and the card's gold ring.
The adapter a media card is drawn with, unless the resource named one of its own.
The switcher draws this glyph for the gallery view.
A grid of squares, matching the other card views in the admin.
The name of the category a file belongs to, or nil.
Only one of the two category relationships is ever loaded — a tenant's own, or the master alias that bypasses tenancy — so both are tried and whichever holds a record wins.
The date a file was added, formatted for a card, or nil when it is not loaded.
iex> media_date(%{inserted_at: ~U[2026-08-13 10:00:00Z]})
"Aug 13, 2026"
A file's extension as declared by its format attribute, or nil.
A file's display name, with its extension when the record carries one.
iex> media_name(%{name: "cover", format: "png"})
"cover.png"
A file's size, humanised, or an em dash when the record has none.
iex> media_size(%{size: 2048})
"2.0 KB"
A record's media type — :images, :videos, :documents, or nil.
Callback implementation for MishkaGervaz.Table.Behaviours.Template.render_bulk_actions/1.
Callback implementation for MishkaGervaz.Table.Behaviours.Template.render_error/1.
Callback implementation for MishkaGervaz.Table.Behaviours.Template.render_pagination/1.
Callback implementation for MishkaGervaz.Table.Behaviours.Template.render_template_switcher/1.
Whether this record is selected, under either selection mode.
select_all? inverts the meaning of the set: everything is chosen except what is in
excluded_ids.
@spec split_actions([map()], map(), boolean()) :: %{ overlay: [map()], primary: [map()], secondary: [map()] }
The card's three action groups: the star over the thumbnail, the one wide button, and the squares.
Which action gets which part is a template_options decision, defaulting to the names the media
resource uses:
presentation do
template_options [overlay_action: :pin, primary_action: :open]
endA resource whose row_actions_layout places an action — inline, or behind a dropdown — gets all
of them back under :secondary.
When featured? is true the overlay's star is filled; otherwise it stays an outline.
The URL of a record's thumbnail, or nil when it has none to show.
The thumbnail is the first column visible to this template. Visibility is always asked as
:media_gallery, whichever template is drawing, so a template that borrows the card — by
delegating render_item/1 or by calling this — still sees the columns a resource gated with
visible fn state -> state.template.name() == :media_gallery end.
The background wash a file's type gets. See media_type/1.
The glyph a file wears when there is no thumbnail to show instead.
See MishkaCmsCoreWeb.Templates.AssetsList in the CMS, which draws the same file smaller.
Attributes
type(:atom) - Defaults tonil.class(:string) - Defaults to"size-[26px]".