MishkaBlogWeb.Templates.CollectionCard (Mishka Blog v0.0.1)

Copy Markdown View Source

The collections grid: one card per collection, in as many columns as fit the screen.

Declared only by MishkaBlog.Collection, and it reads that record directly rather than by column position — a card is a specific shape (a folder tile beside its actions, a title over its blurb, and a footer weighing posts against versions) that a generic position mapping cannot describe. The resource's columns stay the field-selection contract and the vocabulary the table view sorts by.

The grid is intrinsic, not stepped

The design draws three columns and the prototype steps down to two, which leaves a phone showing two cramped cards with their actions cut off. Here the track list is repeat(auto-fill, minmax(min(100%, 280px), 1fr)): a card never goes below 280px unless the viewport itself is narrower, so the count falls from three to two to one on its own, at whatever width the content actually needs. No breakpoint to miss, and none to get wrong.

Features

  • :filter - the labelled filter row: search, site, status, language
  • :select - per-card selection for bulk operations, beside the Featured-only switch
  • :bulk_actions - bulk actions on the selected cards
  • :paginate - the page-size picker and numbered pages under the grid

The furniture around the cards is MishkaCmsCoreWeb.Templates.CardChrome, shared with the document card pages. Pairs with MishkaCmsCoreWeb.UIAdapters.Admin, which draws the archive switch, the view switch and the row actions.

Summary

Functions

One aggregate off the record, or 0 when it arrived unloaded.

The switcher draws this glyph for the card view. It is the grid of four squares the design uses, and MishkaGervaz.UIAdapters.Tailwind.switcher_icon_class/1 renders it inline — the runtime CSS compiler cannot emit a mask for a name it only sees at runtime.

Where a collection's title goes: the posts page, narrowed to that collection.

One collection card.

How a collection's status badge reads and what colour it wears.

Functions

count(record, key)

@spec count(map(), atom()) :: non_neg_integer()

One aggregate off the record, or 0 when it arrived unloaded.

icon()

The switcher draws this glyph for the card view. It is the grid of four squares the design uses, and MishkaGervaz.UIAdapters.Tailwind.switcher_icon_class/1 renders it inline — the runtime CSS compiler cannot emit a mask for a name it only sees at runtime.

posts_path(arg)

Where a collection's title goes: the posts page, narrowed to that collection.

posts_filter_collection_id is the URL contract MishkaBlog.BlogPost's url_sync block declares (prefix "posts"), decoded back into filter state on arrival — so the destination opens with the Collection filter already applied and the admin can widen it from there. A plain string rather than path/2 because a template module has no socket, matching MishkaDocumentWeb.Templates.DocumentCard.edition_path/1.

render_bulk_actions(assigns)

Callback implementation for MishkaGervaz.Table.Behaviours.Template.render_bulk_actions/1.

render_empty(assigns)

Callback implementation for MishkaGervaz.Table.Behaviours.Template.render_empty/1.

render_error(assigns)

Callback implementation for MishkaGervaz.Table.Behaviours.Template.render_error/1.

render_filters(assigns)

Callback implementation for MishkaGervaz.Table.Behaviours.Template.render_filters/1.

render_header(assigns)

Callback implementation for MishkaGervaz.Table.Behaviours.Template.render_header/1.

render_item(assigns)

One collection card.

The head row wraps rather than shrinking: on a card narrow enough that the folder tile and the three labelled actions cannot share a line, the actions drop underneath instead of pushing "Delete" past the edge — which is what the prototype does at phone width.

render_pagination(assigns)

Callback implementation for MishkaGervaz.Table.Behaviours.Template.render_pagination/1.

render_template_switcher(assigns)

Callback implementation for MishkaGervaz.Table.Behaviours.Template.render_template_switcher/1.

status_badge(record)

@spec status_badge(map()) :: %{label: String.t(), chip: String.t()}

How a collection's status badge reads and what colour it wears.

One entry per value of the status attribute, falling back to :draft — the attribute's own default.