# `MingaEditor.Shell.Board.State`
[🔗](https://github.com/jsmestad/minga/blob/main/lib/minga_editor/shell/board/state.ex#L1)

Presentation state for The Board shell.

Holds the card grid, focus tracking, zoom state, and an ID counter.
All operations are pure functions on this struct; the Editor GenServer
calls them from Shell.Board callbacks.

## Zoom lifecycle

The Board has two modes: grid view (showing all cards) and zoomed view
(showing one card's workspace). The `zoomed_into` field tracks which
card is currently expanded. When `nil`, the grid is showing.

Zooming in: the caller snapshots the current workspace onto the card,
then restores the target card's workspace as the live workspace.

Zooming out: the caller snapshots the live workspace back onto the card,
then either clears the live workspace or restores a minimal Board workspace.

# `t`

```elixir
@type t() :: %MingaEditor.Shell.Board.State{
  agent: MingaEditor.State.Agent.t(),
  bottom_panel: MingaEditor.BottomPanel.t(),
  card_order: [MingaEditor.Shell.Board.Card.id()],
  cards: %{
    required(MingaEditor.Shell.Board.Card.id()) =&gt;
      MingaEditor.Shell.Board.Card.t()
  },
  dashboard: nil,
  filter_mode: boolean(),
  filter_text: String.t(),
  focused_card: MingaEditor.Shell.Board.Card.id() | nil,
  git_status_panel: nil,
  hover_popup: nil,
  modeline_click_regions: [],
  nav_flash: nil,
  next_id: pos_integer(),
  picker_ui: MingaEditor.State.Picker.t(),
  prompt_ui: MingaEditor.State.Prompt.t(),
  signature_help: nil,
  status_msg: String.t() | nil,
  suppress_tool_prompts: boolean(),
  tab_bar: nil,
  tab_bar_click_regions: [],
  tool_declined: MapSet.t(),
  tool_prompt_queue: [atom()],
  warning_popup_timer: nil,
  whichkey: MingaEditor.State.WhichKey.t(),
  zoomed_into: MingaEditor.Shell.Board.Card.id() | nil
}
```

# `card_count`

```elixir
@spec card_count(t()) :: non_neg_integer()
```

Returns the number of cards on the board.

# `create_card`

```elixir
@spec create_card(
  t(),
  keyword()
) :: {t(), MingaEditor.Shell.Board.Card.t()}
```

Creates a new card and adds it to the board.

Returns `{updated_state, card}`. The card gets a unique monotonic ID.
If no card was focused, the new card becomes focused.

# `filtered_cards`

```elixir
@spec filtered_cards(t()) :: [MingaEditor.Shell.Board.Card.t()]
```

Returns cards filtered by the current filter text, in display order.

# `focus_card`

```elixir
@spec focus_card(t(), MingaEditor.Shell.Board.Card.id()) :: t()
```

Sets focus to the given card ID.

# `focused`

```elixir
@spec focused(t()) :: MingaEditor.Shell.Board.Card.t() | nil
```

Returns the currently focused card, or nil.

# `grid_view?`

```elixir
@spec grid_view?(t()) :: boolean()
```

Returns true when the grid is showing (not zoomed into a card).

# `move_focus`

```elixir
@spec move_focus(t(), :up | :down | :left | :right, pos_integer()) :: t()
```

Moves focus in the given direction within the grid.

Direction is `:up`, `:down`, `:left`, or `:right`. The grid is
computed from sorted card IDs laid out in rows of `cols` columns.

# `new`

```elixir
@spec new() :: t()
```

Creates a fresh Board state with an empty card grid.

# `remove_card`

```elixir
@spec remove_card(t(), MingaEditor.Shell.Board.Card.id()) :: t()
```

Removes a card from the board.

If the removed card was focused, focus moves to the next card in ID
order, or `nil` if the board is now empty. If the removed card was
zoomed into, zoom is cleared.

# `reorder_card`

```elixir
@spec reorder_card(t(), MingaEditor.Shell.Board.Card.id(), non_neg_integer()) :: t()
```

Reorders a card to a new position in the display order.

Moves the card with the given ID to the specified index in the card_order list.
If the card or index is invalid, returns the state unchanged.

# `sorted_cards`

```elixir
@spec sorted_cards(t()) :: [MingaEditor.Shell.Board.Card.t()]
```

Returns all cards in display order (respecting user reordering).

# `update_card`

```elixir
@spec update_card(
  t(),
  MingaEditor.Shell.Board.Card.id(),
  (MingaEditor.Shell.Board.Card.t() -&gt;
     MingaEditor.Shell.Board.Card.t())
) :: t()
```

Updates a card by applying a function to it.

# `zoom_into`

```elixir
@spec zoom_into(t(), MingaEditor.Shell.Board.Card.id(), map()) :: t()
```

Zooms into a card, storing the given workspace snapshot on it.

The caller is responsible for restoring the card's workspace as the
live `state.workspace` on EditorState.

# `zoom_out`

```elixir
@spec zoom_out(t()) :: {t(), map() | nil}
```

Zooms out of the current card, returning {state, workspace_snapshot}.

The returned snapshot is the workspace that was stored on the card
when it was zoomed into. Returns `{state, nil}` if not zoomed.

# `zoomed`

```elixir
@spec zoomed(t()) :: MingaEditor.Shell.Board.Card.t() | nil
```

Returns the currently zoomed-into card, or nil.

---

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