# `Tayori`
[🔗](https://github.com/hattoriai/tayori/blob/v0.1.0/lib/tayori.ex#L1)

Tayori (便り) is product news for Phoenix: what the app has to say to
its people, written in an admin the app mounts, and read in the app, on
a public page, in feeds and in emails.

Add Tayori to the app's supervision tree, after the repo and the
PubSub (`Tayori.Config` has the options):

    {Tayori, repo: MyApp.Repo, pubsub: MyApp.PubSub, secret_key_base: secret}

The functions of this module read the news for a `Tayori.Reader`, built
by the app from its own user: `news/2`, `entry/3`, `unread_count/2`,
`mark_seen/2`. `Tayori.Entries` writes them; the admin
(`Tayori.Router.tayori_admin/2`) is a page over it.

Start with the [Quickstart](quickstart.md).

## Live

`subscribe/0` subscribes the caller to the news on the app's PubSub. It
receives:

  * `{Tayori, :published, id}` - an entry was published, at once or at
    its scheduled time;
  * `{Tayori, :changed, id}` - an entry was changed, unpublished or
    deleted.

`subscribe/1` subscribes to a reader's own topic, which receives
`{Tayori, :seen, reader_id}` when they see the news in another tab or
on another device.

# `adjacent`

```elixir
@spec adjacent(Tayori.Reader.t(), Tayori.Entry.t(), keyword()) ::
  {Tayori.Entry.t() | nil, Tayori.Entry.t() | nil}
```

The entries on either side of an entry, for the reader: `{newer, older}`,
each an entry with its translation or nil.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `entry`

```elixir
@spec entry(Tayori.Reader.t(), String.t(), keyword()) :: Tayori.Entry.t() | nil
```

An entry of the news by its slug, if the reader sees it.

# `mark_seen`

```elixir
@spec mark_seen(Tayori.Reader.t(), DateTime.t()) :: :ok
```

Marks the news as seen by the reader, at a time (now): what was
published until then is no longer unread. Tells the reader's other tabs
(`subscribe/1`). Does nothing for a visitor.

# `new_after`

```elixir
@spec new_after(Tayori.Reader.t()) :: DateTime.t() | nil
```

The time after which an entry is new to the reader: when they last saw
the news, else `reader.since`, else the beginning of time (everything is
new to a reader who never looked). Nil for a visitor: nothing is new.

# `news`

```elixir
@spec news(Tayori.Reader.t(), keyword()) :: [Tayori.Entry.t()]
```

The news a reader sees, the newest first, each entry with its
translation in the reader's language.

The first page starts with the pinned entries, the last pinned first;
the next pages (`:before`) leave them out, so that no entry comes twice.

Options:

  * `:limit` - how many entries (20), besides the pinned ones.
  * `:before` - an entry: the entries published before it, for the next
    page.
  * `:category` - the key of a category: its entries only.
  * `:search` - words of the title, summary or body, in any language.
  * `:now` - the time to read the news at (now).

# `seen_at`

```elixir
@spec seen_at(Tayori.Reader.t()) :: DateTime.t() | nil
```

When the reader last saw the news, or nil.

# `start_link`

```elixir
@spec start_link(keyword()) :: Supervisor.on_start()
```

Starts Tayori with the options of `Tayori.Config`.

# `subscribe`

```elixir
@spec subscribe() :: :ok | {:error, term()}
```

Subscribes the caller to the news (see the module doc).

# `subscribe`

```elixir
@spec subscribe(Tayori.Reader.t()) :: :ok | {:error, term()}
```

Subscribes the caller to a reader's own topic (see the module doc).

# `unread_count`

```elixir
@spec unread_count(Tayori.Reader.t(), keyword()) :: non_neg_integer()
```

How many entries the reader has not seen: those published since they
last saw the news (`mark_seen/2`), or since `reader.since`. Zero for a
visitor.

Options: `:now` (now), `:max` - stop counting there (99), so that the
count is one cheap query.

# `version`

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

Returns the current Tayori version.

## Examples

    iex> Tayori.version()
    "0.1.0"

---

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