# `MishkaBlogWeb.Templates.PostCard`
[🔗](https://github.com/mishka-group/mishka_blog/blob/v0.0.1/lib/mishka_blog_web/templates/post_card.ex#L5)

The blog posts list: one full-width row per post, stacked.

Declared only by `MishkaBlog.BlogPost`, and it reads that record directly rather than by column
position — a post row is a specific shape (a thumbnail beside a title over its site and date, an
excerpt under its language, a stats line ending in a status badge, and a row of language chips)
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 list shows one row per post rather than one per translation
(`MishkaCmsCore.LanguageEditions`); the chips under the stats line
(`MishkaBlogWeb.Templates.EditionChips`) are the way to a translation without searching for it.

## The row folds rather than overflowing

The prototype keeps the five actions on the title's line at every width, so on a phone they wrap
into a right-aligned block that pushes the excerpt into a column two words wide. Here the actions
drop to their own full-width line under a rule below 560px, and the thumbnail shrinks with them —
the row keeps its reading order and nothing leaves the viewport.

## Features
- `:filter` - the labelled filter row: search, site, status, language, with Featured as a switch
- `:select` - per-row selection for bulk operations
- `:bulk_actions` - bulk actions on the selected rows
- `:paginate` - the page-size picker and Load more under the list

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

See `MishkaBlogWeb.Templates.CollectionCard` for the same shape as a grid.

# `count`

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

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

# `date_label`

```elixir
@spec date_label(map()) :: String.t()
```

When the post went out, or when it was written if it never did.

A scheduled post reads as its due date, which is the only date about it worth showing.

# `icon`

The switcher draws this glyph for the card view.

The same grid-of-squares every blog card page uses, so the Table/Cards switch reads identically on
posts, comments, collections and bloggers — the resource picking a different glyph would make the
same control look like a different one from page to page. `switcher_icon_class/1` on the admin
adapter has a clause per name, because the runtime CSS compiler cannot emit a mask for a name it
only ever sees at runtime.

# `render_bulk_actions`

# `render_empty`

# `render_error`

# `render_filters`

# `render_header`

# `render_item`

One post row.

The tick sits level with the title rather than centred on the card, because a card's height is set
by however long its excerpt runs and a centred tick drifts away from the thing it selects.

# `render_pagination`

# `render_template_switcher`

# `status_badge`

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

How a post'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.

# `tint`

```elixir
@spec tint(map()) :: String.t()
```

The thumbnail tint for a post with no image, picked from its id so it never flickers.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
