# Stories in a site

A Récit site (this one, for instance) publishes stories with `@recit/site-stories`: each story gets
its own page, embeds in any other page, and a per-slide search. One file is enough.

## 1. Declare the stories (recit.config.ts)

```ts title="recit.config.ts"
import "@recit/site-stories/styles.css";
import { defineConfig } from "recit/config";
import * as components from "./components/index.js";

export default defineConfig({
  // Site options
  site: { title: "Lorem Ipsum Docs" },
  navigation: [{ type: "doc", file: "index" }],
  // Récit: the stories published by the site
  publish: {
    dir: "./stories", // default
    routePrefix: "/present", // default: /stories
    layout: "none", // "default": inside the documentation layout
    components,
    entries: [{ slug: "showcase", file: "../examples/deck-showcase/slides.md" }],
  },
});
```

`defineConfig` adds `recitPlugin` (routes, embeds, search) and `recitVitePlugin` (compilation) to
the site: no separate site config and no `vite.config.ts`. Every `.md` or `.mdx` file of `dir` is
compiled, plus the explicit `entries`. Each one uses the `recit.config.*` found next to it and is
recompiled on change in development. A `.md` is sanitized unless the project sets
`security.allowHtml: true`; an `.mdx` is **never** sanitized, because MDX is code, not content. See
[recit.config](/documentation/configuration/recit-config#a-site).

A site that declares `recitPlugin` in `plugins` by hand keeps it, and then adds `recitVitePlugin`
from `@recit/site-stories/vite` to its own `vite.config.ts`.

Every story gets a route (`/present/showcase`), **prerendered** with the site. The styles are scoped
to the `.recit-wrapper` element, so they never leak into the documentation.

## 2. Embed in pages

```mdx title="my-page.mdx"
<StoryEmbed slug="showcase" slide={4} />

<StoryGallery decks={["starter", "pitch"]} />
```

Both components are provided by the plugin, no import needed. `StoryGallery` takes optional `links`
and `descriptions` objects, keyed by slug.

This is the story of the `examples/site-embed` project, embedded with
`<StoryEmbed slug="lorem-ipsum" />`:

<StoryEmbed slug="lorem-ipsum" />

## Languages

With an `i18n` section in `recit.config.ts`, every language of a story gets its own page. A story
`talk.md` with a `talk.fr.md` variant is served at `/present/talk` and `/fr/present/talk`. With
`routing: "prefix-always"`, the default language gets a prefix too (`/en/present/talk`).
`StoryEmbed`, `StoryGallery` and the plugin's links follow the same routes.

```ts title="recit.config.ts"
export default defineConfig({
  site: { title: "Lorem Ipsum" },
  publish: { dir: "./stories", routePrefix: "/present" },
  i18n: { locales: ["en", "fr"], defaultLocale: "en" },
});
```

- Story pages carry `<html lang dir>` and `hreflang` / `x-default` links to their other languages.
- Each prefixed language gets a home page (`/fr`) listing its stories.
- A language switcher is added to the header. It keeps the current story when it exists in the other
  language, otherwise it goes to that language's home.
- Pagefind builds one index per language.

## Per-slide search

The page of each story contains a hidden index: the site's Pagefind search returns the **slide**
(`/present/course#slide-7`) and the deck opens right on it. Try searching for "dichotomia" (⌘K).
