# `PhoenixKitWeb.Components.AdminDock`
[🔗](https://github.com/BeamLabEU/phoenix_kit/blob/v2.64.1/lib/phoenix_kit_web/components/admin_dock.ex#L1)

The optional right-hand dock column of the admin layout, and the commands that open it.

A module's header widget (`c:PhoenixKit.Module.header_widgets/0`) that needs room beside
the page, a chat panel for instance, declares `dock: true`. While at least one rendered
widget does, `#admin-drawer` gets one more grid column, `#pk-dock`. Without such a widget
the layout has no dock markup at all.

## Contract

  * **Container**: `#pk-dock` (`container_id/0`), the last child of `#admin-drawer`. It is
    an empty `<aside>` that is `display: none` until opened. What goes into it is the
    widget's business: the widget can position its own panel over the column (the column
    holds the width free, the panel sits at `right-0` with `w-[var(--pk-dock-width,25rem)]`),
    or move its panel element into the container with a hook.
  * **State**: the class `pk-dock-open` (`open_class/0`) on `<body>` (`target/0`) or on
    **any element inside it**, the widget's own markup included; either opens the dock.
    The page is laid out as `<body> > header` (where the widgets live) next to
    `<body> > ... > #admin-drawer > #pk-dock`, so `<body>` is the one element above both
    and the CSS looks there. Which form to use depends on how long the state has to live:
      * The JS commands below put the class on `<body>`. LiveView never patches `<body>`, so
        the class survives `push_patch`, a live redirect to another LiveView (the usual
        admin navigation, e.g. a sidebar link), and the sticky widget is not mounted again.
        A full page load resets it.
      * A class on an element of the widget itself (in the header) travels with the sticky
        widget as well. A widget that keeps "open" in its own assigns renders
        `class={[@open? && "pk-dock-open"]}` on an element of its own, and the dock is shown
        for as long as that element has the class. It needs no JavaScript and no replay on
        mount.
  * **Width**: the CSS variable `--pk-dock-width` (`width_var/0`), `25rem` when unset. The
    dock reads it inside `#admin-drawer`, a widget panel in the header reads it from the
    header: set it on `:root` or `<body>` (above both), from CSS or a style attribute, and
    write `var(--pk-dock-width,25rem)` wherever you read it.
  * **Layout**: from `lg` up the dock is a third column of the drawer grid, so the work
    area gets narrower by the dock's width; the dock is as tall as the viewport below the
    header and scrolls itself. Below `lg` it covers the whole screen under the header.

## Commands

    <button phx-click={AdminDock.toggle()}>Chat</button>
    <button phx-click={AdminDock.close() |> JS.push("forget_panel")}>Close</button>

The commands target `<body>` by selector, so they work from the widget's nested LiveView,
which sits in the header. A widget that also keeps its own class on an element of its own
must not mix the two: when it closes, it removes the class from its element and runs
`close/1`.

## Not covered by tests

`Phoenix.LiveViewTest` has no notion of sticky LiveViews moving to the new page on a live
redirect, so the ExUnit tests pin the markup (the container, the class variants), the
JS ops, and that the element the commands address, and the one the CSS looks at, is an
ancestor of both the widget and the dock; not the survival across a navigation. That is
LiveView's own behaviour.

# `close`

```elixir
@spec close(Phoenix.LiveView.JS.t()) :: Phoenix.LiveView.JS.t()
```

Close the dock.

# `container_id`

```elixir
@spec container_id() :: String.t()
```

The id of the dock container.

# `open`

```elixir
@spec open(Phoenix.LiveView.JS.t()) :: Phoenix.LiveView.JS.t()
```

Open the dock.

# `open_class`

```elixir
@spec open_class() :: String.t()
```

The class that opens the dock.

# `target`

```elixir
@spec target() :: String.t()
```

The selector of the element the commands put the open class on.

# `toggle`

```elixir
@spec toggle(Phoenix.LiveView.JS.t()) :: Phoenix.LiveView.JS.t()
```

Open the dock if it is closed, close it if it is open.

# `width_var`

```elixir
@spec width_var() :: String.t()
```

The CSS variable that sets the dock's width.

---

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