PhoenixKitWeb.Components.Core.PreviewCard (phoenix_kit v2.30.0)

Copy Markdown View Source

A read-only preview card for any resource that has photos/files and a handful of display fields — the catalogue product card, generalised. Opened from a picker thumbnail or a list's featured-image thumb, and potentially shown to a CLIENT, not just admins, so it has to stand on its own.

preview_card/1 renders a <.modal> whose media area is ONE continuous swipeable carousel: images first, then attached files (a PDF renders inline, any other file as a tile with an Open action) — swipe through the images and just keep going into the files. Below it: the resource's filled scalar fields and a compact file list for saving. Slide switching is entirely client-side (scroll-snap); the only server event left is the close.

The component is pure render: every DB-backed value (images, files, fields, title) is resolved by the caller, so it stays testable without a database. preview_card_body/1 is the same content without the modal shell (the "notpopup" form).

Usage

The catalogue item card:

<PreviewCard.preview_card
  id={@id}
  show={@card_open}
  title={@card_name}
  images={ProductCard.resolve_images(@item)}
  files={ProductCard.resolve_files(@item)}
  fields={ProductCard.build_fields(@item, @locale)}
  target={@myself}
  on_close="card_close"
/>

An Andi sub-order's featured-image card:

<PreviewCard.preview_card
  id="sub-order-card"
  show={true}
  title={SubOrderCard.build(@sub_order, @order).name}
  images={@sub_order_card.images}
  files={@sub_order_card.files}
  fields={@sub_order_card.fields}
  target={nil}
  on_close="close_sub_order_card"
/>

Summary

Functions

Renders the preview card modal. Pure: every DB-backed value (images, files, fields, title) is resolved by the caller and passed in.

The card's content without the modal shell — the "notpopup" form, for embedding the same preview inline (a detail pane, a future product page). Same attrs as preview_card/1 minus the modal ones — and minus :target: the body renders no event of its own (slide switching is client-side, the close button lives in the modal's action row), so an inline embedder has nothing to point at.

Functions

preview_card(assigns)

Renders the preview card modal. Pure: every DB-backed value (images, files, fields, title) is resolved by the caller and passed in.

Attrs:

  • :id (required) — used to derive the modal's DOM id.
  • :show (required) — whether the modal is open.
  • :target (required, nil allowed) — the @myself of the LiveComponent that handles the close event, or nil when the host is a LiveView itself.
  • :title — card title; falls back to gettext "Preview".
  • :images — ordered list of %{uuid, name} (main image first).
  • :fields — list of {label, value} for the already-filtered, non-empty fields.
  • :files — ordered list of %{uuid, name, size, pdf?}.
  • :on_close — event pushed to @target on close (default "preview_card_close").
  • :max_width — modal width class, forwarded to <.modal> (default "3xl").

Attributes

  • id (:string) (required)
  • show (:boolean) (required)
  • target (:any) (required)
  • title (:string) - Defaults to nil.
  • images (:list) - Defaults to [].
  • fields (:list) - Defaults to [].
  • files (:list) - Defaults to [].
  • on_close (:string) - Defaults to "preview_card_close".
  • max_width (:string) - Defaults to "3xl".

Slots

  • extra_actions - rendered in the modal's action row before Close — a host puts a mode-aware Add/quantity control or similar here.

preview_card_body(assigns)

The card's content without the modal shell — the "notpopup" form, for embedding the same preview inline (a detail pane, a future product page). Same attrs as preview_card/1 minus the modal ones — and minus :target: the body renders no event of its own (slide switching is client-side, the close button lives in the modal's action row), so an inline embedder has nothing to point at.

The media area is ONE continuous swipeable carousel: images first, then the attached files (a PDF renders inline, any other file as a tile) — the client swipes through the images and just keeps going into the files. Scroll-snap (daisyUI carousel) drives it entirely client-side: native swipe on touch, arrow buttons on desktop, no server round-trip per slide.

Attributes

  • title (:string) - Defaults to nil.
  • images (:list) - Defaults to [].
  • fields (:list) - Defaults to [].
  • files (:list) - Defaults to [].