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

The bloggers grid: one card per blogger, in as many columns as fit the screen.

Declared only by `MishkaBlog.Blogger`, and it reads that record directly rather than by column
position — a profile card is a specific shape (an avatar beside its actions, a name over its role
and expertise, and a footer weighing posts against followers) that a generic position mapping
cannot describe. The resource's columns stay the field-selection contract and the vocabulary the
table view sorts by.

## No fabricated engagement

The prototype's card ends in an "Engagement 86%" bar, but that figure is invented — the mock
hardcodes it for every blogger and `MishkaBlog.Blogger` has no engagement metric. Rather than draw
a bar off a number that does not exist, the footer shows the two figures that are real
(`post_count` and `follower_count`) and the card carries a Publisher/Contributor badge from
`can_publish_directly`, which is the page's actual axis — the "Can publish directly" filter and the
publishing-permission model both turn on it.

## The grid is intrinsic, not stepped

The track list is `repeat(auto-fill, minmax(min(100%, 300px), 1fr))`: a card never goes below
300px 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, with "Can publish directly" as a switch
- `:select` - per-card selection for bulk operations
- `:bulk_actions` - bulk actions on the selected cards
- `:paginate` - the page-size picker and Load more under the grid

The furniture is `MishkaCmsCoreWeb.Templates.CardChrome` and the controls are
`MishkaCmsCoreWeb.UIAdapters.Admin`, both shared with the collections and posts card pages.

See `MishkaBlogWeb.Templates.CollectionCard` for the same shape holding a different record.

# `avatar`

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

The avatar tint pair, picked from the record's id so it never flickers between renders.

# `count`

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

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

# `expertise`

```elixir
@spec expertise(map()) :: [String.t()]
```

The blogger's expertise topics, always a list.

# `icon`

The switcher draws the grid-of-squares glyph for this view, as it does for collections.

# `initials`

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

The two letters the avatar tile shows, from the blogger's display name.

# `render_bulk_actions`

# `render_empty`

# `render_error`

# `render_filters`

# `render_header`

# `render_item`

One blogger card.

The head row wraps rather than shrinking: on a card narrow enough that the avatar 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`

# `render_template_switcher`

---

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