docs/components/feedback.md

# Feedback

20 feedback components — alerts, banners, loading states, progress, skeletons, notifications, toasts, error displays, and confirmation patterns.

**Module**: `PhiaUi.Components.Feedback`

```elixir
import PhiaUi.Components.Feedback
```

---

## Table of Contents

**Alerts & Banners**
- [alert](#alert)
- [banner](#banner)
- [announcement_bar](#announcement_bar)
- [cookie_consent](#cookie_consent)
- [global_message](#global_message)

**Loading**
- [spinner](#spinner)
- [loading_overlay](#loading_overlay)
- [loading_dots](#loading_dots)
- [loading_bar](#loading_bar)
- [skeleton](#skeleton)

**Progress**
- [progress](#progress)
- [circular_progress](#circular_progress)
- [labeled_progress](#labeled_progress)
- [segmented_progress](#segmented_progress)
- [quota_bar](#quota_bar)
- [step_progress_bar](#step_progress_bar)

**Status**
- [status_indicator](#status_indicator)
- [connection_status](#connection_status)
- [live_indicator](#live_indicator)

**Notifications & Toasts**
- [toast](#toast)
- [snackbar](#snackbar)
- [sonner](#sonner)
- [notification](#notification)

**Error & Empty States**
- [empty_state](#empty_state)
- [result_state](#result_state)
- [error_display](#error_display)

**Confirmation**
- [popconfirm](#popconfirm)
- [step_tracker](#step_tracker)

---

## alert

Non-interactive feedback banner with variants and optional icon slot.

**Variants**: `default` · `destructive` · `warning` · `success`

```heex
<.alert variant="success">
  <:icon><.icon name="check-circle" /></:icon>
  Your changes have been saved.
</.alert>

<.alert variant="destructive">
  <:icon><.icon name="x-circle" /></:icon>
  Failed to process payment. Please try again.
</.alert>

<.alert variant="warning">
  <:icon><.icon name="alert-triangle" /></:icon>
  Your trial expires in 3 days.
  <:action><.button size="sm" variant="outline">Upgrade</.button></:action>
</.alert>

<%!-- Dismissable --%>
<.alert variant="default" phx-click="dismiss_alert" id="info-alert">
  New features are available in this version.
</.alert>
```

---

## banner

Top-of-page notification bar with optional action and dismiss button.

```heex
<.banner variant="info" phx-click="dismiss_banner">
  System maintenance scheduled for Sunday 2am–4am UTC.
  <:action><.button size="sm" variant="ghost">Learn more</.button></:action>
</.banner>
```

---

## announcement_bar

Marquee-scrolling announcement banner.

```heex
<.announcement_bar items={["Free shipping on orders over $50", "New products added weekly", "Use code SAVE20 for 20% off"]} />
```

---

## cookie_consent

GDPR-style cookie consent banner with accept/decline.

```heex
<.cookie_consent
  on_accept="accept_cookies"
  on_decline="decline_cookies"
  policy_url="/privacy"
/>
```

---

## global_message

App-level flash-style message bar. Hook: `PhiaGlobalMessage`.

```heex
<%!-- In your root layout --%>
<.global_message id="app-flash" />
```

```elixir
# Trigger from LiveView
def handle_info({:show_message, msg}, socket) do
  {:noreply, push_event(socket, "phia-global-message", %{message: msg, type: "success"})}
end
```

---

## spinner

Inline loading spinner.

```heex
<.spinner />
<.spinner size="lg" class="text-primary" />

<%!-- Inside a button --%>
<.button disabled={@loading}>
  <%= if @loading do %>
    <.spinner size="sm" class="mr-2" /> Loading…
  <% else %>
    Save
  <% end %>
</.button>
```

**Sizes**: `:sm` · `:md` (default) · `:lg`

---

## loading_overlay

Full-container overlay with spinner and optional message.

```heex
<div class="relative">
  <.loading_overlay visible={@loading} message="Loading data…" />
  <.table rows={@rows}>…</.table>
</div>
```

---

## loading_dots

Three animated dots — use for chat "typing" indicators.

```heex
<.loading_dots />
<.loading_dots size="lg" class="text-primary" />
```

---

## loading_bar

Indeterminate top-of-page loading bar (like YouTube/GitHub).

```heex
<.loading_bar visible={@page_loading} />
```

---

## skeleton

Content placeholder while data loads.

```heex
<%!-- Inline --%>
<.skeleton class="h-4 w-32 rounded" />
<.skeleton class="h-10 w-full rounded-lg" />

<%!-- Pre-built variants --%>
<.skeleton_list items={5} />    <%!-- 5 row skeletons --%>
<.skeleton_form fields={4} />   <%!-- 4 input field skeletons --%>
<.skeleton_table_row cols={4} />
<.skeleton_profile />           <%!-- Avatar + text lines --%>
```

---

## progress

Horizontal progress bar.

```heex
<.progress value={65} />
<.progress value={@percent} class="h-2 [&>div]:bg-green-500" />
```

**Attrs**: `value` (0–100), `class`

---

## circular_progress

SVG circular progress ring.

```heex
<.circular_progress value={75} size={80} stroke_width={6} />
<.circular_progress value={@cpu_usage} label="CPU" />
```

---

## labeled_progress

Progress bar with label and percentage text.

```heex
<.labeled_progress label="Storage" value={68} unit="GB used of 100GB" />
```

---

## segmented_progress

Multi-section progress bar for multi-step flows.

```heex
<.segmented_progress steps={4} current_step={2} />
```

---

## quota_bar

Stacked bar showing quota usage with colour zones.

```heex
<.quota_bar used={8.2} total={10} unit="GB" warn_at={80} danger_at={90} />
```

---

## step_progress_bar

Horizontal bar with step dots and labels.

```heex
<.step_progress_bar current={2} steps={["Details", "Address", "Payment", "Review"]} />
```

---

## status_indicator

Dot indicator with colour-coded status.

```heex
<div class="flex items-center gap-2">
  <.status_indicator status={:online} />
  <span>Alice Smith</span>
</div>
```

**Statuses**: `:online` · `:offline` · `:away` · `:busy` · `:error`

---

## connection_status

Shows LiveView socket connection state.

```heex
<.connection_status />
```

---

## live_indicator

Pulsing "LIVE" badge.

```heex
<.live_indicator />
<.live_indicator label="Broadcasting" />
```

---

## toast

Programmatic toast notification. Fire with `put_flash/3` or `push_event/3`.

```heex
<%!-- In root layout --%>
<.toast flash={@flash} />
```

```elixir
# In a LiveView event handler
def handle_event("save", _params, socket) do
  case save(socket.assigns.form) do
    {:ok, _} ->
      {:noreply, put_flash(socket, :info, "Saved successfully!")}
    {:error, _} ->
      {:noreply, put_flash(socket, :error, "Failed to save.")}
  end
end
```

---

## snackbar

Bottom-anchored notification with action button.

```heex
<.snackbar id="undo-snack" message="Item deleted" action_label="Undo" on_action="undo_delete" />
```

---

## sonner

Toast stack manager inspired by Sonner. Supports queueing multiple toasts. Hook: `PhiaSonner`.

```heex
<%!-- In root layout --%>
<.sonner id="app-toasts" position={:bottom_right} />
```

```elixir
# Trigger from LiveView
push_event(socket, "phia-sonner", %{
  type: "success",
  title: "Saved",
  description: "Your changes have been saved.",
  duration: 4000
})
```

---

## notification

Notification item in a notification list or notification_center.

```heex
<.notification_center id="notif-center">
  <%= for n <- @notifications do %>
    <.notification_item
      title={n.title}
      body={n.body}
      timestamp={n.inserted_at}
      read={n.read_at != nil}
      icon={n.icon}
      phx-click="mark_read"
      phx-value-id={n.id}
    />
  <% end %>
</.notification_center>
```

---

## empty_state

Centred placeholder for empty lists.

```heex
<.empty_state
  icon="inbox"
  title="No messages"
  description="When you receive messages, they'll appear here."
>
  <:action>
    <.button phx-click="compose">Compose message</.button>
  </:action>
</.empty_state>
```

---

## result_state

Success / error / warning full-page or section result screen.

```heex
<.result_state
  status={:success}
  title="Payment confirmed"
  description="Your order #1234 has been placed."
>
  <:action>
    <.button href="/orders">View orders</.button>
  </:action>
</.result_state>
```

**Statuses**: `:success` · `:error` · `:warning` · `:info`

---

## error_display

Formatted error message with stack trace (development mode).

```heex
<.error_display error={@error} show_trace={Mix.env() == :dev} />
```

---

## popconfirm

Inline confirm/cancel popover for destructive actions.

```heex
<.popconfirm
  id="delete-confirm"
  message="Are you sure you want to delete this record? This cannot be undone."
  on_confirm="delete_record"
  confirm_label="Yes, delete"
>
  <.button variant="destructive">Delete</.button>
</.popconfirm>
```

---

## step_tracker

Multi-step wizard tracker with icons and statuses.

```heex
<.step_tracker current={@step}>
  <:step status={:complete} icon="check">Account</:step>
  <:step status={:active} icon="user">Profile</:step>
  <:step status={:pending}>Plan</:step>
  <:step status={:pending}>Confirm</:step>
</.step_tracker>
```