# `Brix.Page`
[🔗](https://github.com/LoamStudios/brix/blob/main/lib/brix/page.ex#L1)

A content page. Has a slug, metadata, sections, and references
to a layout, authors, and tags.

# `t`

```elixir
@type t() :: %Brix.Page{
  authors: [String.t()] | nil,
  extra: map() | nil,
  layout: String.t() | nil,
  meta_description: String.t() | nil,
  meta_title: String.t() | nil,
  og_description: String.t() | nil,
  og_image: String.t() | nil,
  og_title: String.t() | nil,
  published_at: DateTime.t() | nil,
  published_version: DateTime.t() | nil,
  sections: [Brix.Section.t()] | nil,
  slug: String.t() | nil,
  slug_history: [String.t()] | nil,
  tags: [String.t()] | nil,
  title: String.t() | nil,
  updated_at: DateTime.t() | nil,
  versions: [Brix.Version.t()] | nil
}
```

# `excerpt`

```elixir
@spec excerpt(t(), keyword() | non_neg_integer()) :: String.t()
```

Returns a plain-text excerpt from the page's prose, truncated to
`:length` characters (default 200). HTML tags are stripped and
whitespace is normalized. Appends "…" when truncated.

Only prose fields contribute. By default (`fields: :richtext`) those
are the fields the section's template declares as `type: richtext`,
looked up through the configured store; sections whose template is
unknown contribute nothing. Pass `fields: ["body", "summary"]` to
name the prose fields explicitly instead, with no template lookup.

Sections are walked in order, children depth first.

An integer second argument is shorthand for `length:`.

# `matches?`

```elixir
@spec matches?(t(), String.t() | nil) :: boolean()
```

Returns true if the page matches the given search query.
Searches title, meta_description, and all section string fields.
HTML tags are stripped from richtext fields before matching.
Case-insensitive. Blank queries match everything.

# `published?`

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

Returns true if the page is published (published_at is set and not in the future).

---

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