---
title: "Уценка"
description: "Легкий и свободный от зависимостей способ отрисовки уценки в Reflex с использованием Tailwind Typography."
order: 0
---
# Уценка

Легкий и свободный от зависимостей способ отрисовки уценки в Reflex с использованием Tailwind Typography.

Большинство библиотек компонентов, включая Radix, поставляют компонент `Markdown`, который анализирует и отображает уценку на клиенте, в браузере, при каждом рендеринге. Это разумный вариант по умолчанию, но это также означает доставку анализатора клиенту и сопоставление каждого токена уценки с компонентом.

На этой странице показан другой шаблон: один раз проанализировать уценку в HTML на сервере с помощью библиотеки Python `markdown`, а затем передать необработанный HTML в `rx.html` с прикрепленным классом Tailwind Typography. Здесь нет синтаксического анализатора на стороне клиента и сопоставления компонентов с токенами, только HTML и CSS.

Это не компонент с API, который нужно изучить. Это небольшая служебная функция плюс класс CSS, которые вы должны скопировать и адаптировать.

# Как это работает

Три части работают вместе:

1. **`markdown`** — это библиотека Python, которая преобразует строку уценки в строку HTML.
2. **Класс prose**, построенный на `@tailwindcss/typography`, стилизует необработанные HTML-элементы (`h1`, `p`, `table`, `blockquote` и т. д.) в соответствии с вашим пользовательским интерфейсом.
3. **`rx.html`** отображает необработанную HTML-строку как компонент с примененным классом prose.

```python
def render_markdown(text: str) -> rx.Component:
    if not text.strip():
        return rx.el.div()

    html = markdown.markdown(text, extensions=["fenced_code", "tables"])
    return rx.html(html, class_name="prose-content")
```

Вот и весь шаблон. Все, что происходит после этого момента, включая то, какие расширения включить, как стилизовать класс и вообще выполнять ли постобработку HTML, не является обязательным и зависит от вашего проекта.

# Настройка

## Установить уценку

```bash
pip install markdown
```

Расширения, о которых стоит знать:

| Расширение | Цель |
| ------------- | ----------------------------------------- |
| `fenced_code` | Включает блоки кода с тройной обратной кавычкой |
| `tables` | Включает таблицы каналов в стиле GitHub |
| `toc` | Добавляет атрибуты `id` к заголовкам, полезные для якорных ссылок |

Полный список в [Python-Markdown extension docs](https://python-markdown.github.io/extensions/).

## Добавить типографику попутного ветра

Поскольку `@tailwindcss/typography` обрабатывается как файл JavaScript, его следует добавлять непосредственно в плагины `rxconfig.py`.

```python
import reflex as rx
from reflex.plugins.shared_tailwind import TailwindConfig

config = rx.Config(
    ...,
    plugins=[
        rx.plugins.TailwindV4Plugin(
            config=TailwindConfig(plugins=["@tailwindcss/typography"])
        ),
    ],
)
```

## Написать урок прозы

Класс `prose` из Typography не имеет стиля, но имеет собственную структуру; большинство проектов добавляют класс поверх него, чтобы добавить свою собственную тему. Ниже приведен один из примеров. Считайте имя класса, цвета и интервалы заполнителями, а не требованиями.

Два правила стоит соблюдать независимо от темы, поскольку они исправляют особенности рендеринга, а не выражают мнение о стиле:

- Сброс содержимого `::before`/`::after` на `code` и `blockquote`. Типографика по умолчанию добавляет декоративные кавычки, чего не хотят большинство нередакционных пользовательских интерфейсов.
- Сброс отступов и фона `pre > code`. Без него вы получите двойной фон, поскольку как `pre`, так и `code` внутри него стилизованы.

```css
@layer components {
  /* name and theme this however fits your project */
  .prose-content {
    @apply prose dark:prose-invert max-w-none w-full;

    /* fixes double-styling on code blocks */
    @apply prose-pre:p-0
            prose-pre:overflow-x-auto
            prose-pre:before:content-none
            prose-pre:after:content-none
            prose-code:before:content-none
            prose-code:after:content-none;

    /* everything below is a styling choice, not a requirement */
    @apply prose-code:rounded-md
            prose-code:bg-muted
            prose-code:px-1.5
            prose-code:py-0.5
            prose-code:text-sm
            prose-pre:rounded-lg
            prose-pre:bg-muted
            prose-pre:border;
  }
}
```

## Собери это вместе

```python
from components.markdown import render_markdown

def page() -> rx.Component:
    return render_markdown("""
# Welcome

Some **markdown** content, rendered straight to HTML.
""")
```

# Как выглядят элементы уценки

Все, что приведено ниже, представляет собой реальную уценку, прошедшую через `render_markdown` и оформленную с использованием собственного класса прозы этого сайта. Это один из возможных вариантов, а не единственный.

## Заголовки

Типографские стили `h1`–`h6` прямо из коробки. При необходимости переопределите модификаторы `prose-h1:*` / `prose-h2:*`.

```md
# Page title

## Section heading
```

## Форматирование текста

Маркеры кода, выделенные жирным шрифтом, курсивом и строчные, сопоставляются со своими HTML-эквивалентами.

Вы можете использовать **жирный текст**, _курсив_ или `inline code` внутри обычного абзаца.

```md
You can use **bold text**, _italic text_, or `inline code`.
```

## Списки

- Маркеры списка можно изменить с помощью `prose-li:marker:*`.
- Упорядоченные и неупорядоченные списки наследуют стандартный типографский интервал.
- Вложенные списки работают «из коробки»

```md
- First item
- Second item
  - Nested item
```

## Ссылки

[Links](#) наследует стандартную обработку подчеркивания при наведении в Typography. Сделайте рестайлинг с помощью `prose-a:*`.

## Блоки кода

Блоки изолированного кода происходят из расширения `fenced_code`. Типографика объединяет их в пару `pre > code`, а исправление двойного стиля из приведенного выше CSS сохраняет эту пару чистой.

```python
def hello(name: str) -> str:
    return f"Hello, {name}!"
```

## Блоковые кавычки

Цитата по умолчанию в Typography представляет собой курсив по левой границе. Некоторые проекты предпочитают вместо этого выноску с рамкой. Оба разумны; измените стиль с помощью `prose-blockquote:*`.

> Блоковая цитата, оформленная в соответствии с вашим содержанием.

```md
> A blockquote, styled however fits your content.
```

# Необязательно: обработка переполнения таблицы

Таблицы Markdown отображаются как простые элементы `<table>`, которые могут переполнять свой контейнер на узких экранах или при длинном контенте. Это не характерно для данного подхода к рендерингу; это общая проблема с таблицами HTML. Но это достаточно распространено в таблицах с уценкой, поэтому на это стоит обратить внимание.

Один из способов справиться с этим — выполнить постобработку сгенерированного HTML и обернуть каждый `<table>` в прокручиваемый контейнер до того, как он достигнет `rx.html`. Это один из нескольких вариантов. С таким же успехом вы можете воспользоваться утилитой `overflow-x-auto` для родительского элемента, запросом контейнера CSS или оставить таблицы развернутыми, если в вашем контенте никогда не бывает широких таблиц.

```python
from bs4 import BeautifulSoup

def wrap_tables(html: str) -> str:
    soup = BeautifulSoup(html, "html.parser")

    for table in soup.find_all("table"):
        wrapper = soup.new_tag("div")
        wrapper["class"] = "w-full overflow-x-auto"
        table.wrap(wrapper)

    return str(soup)
```

```md
| Column A | Column B |
| -------- | -------- |
| Value 1  | Value 2  |
```

Если вы пойдете по этому пути, вам потребуется `beautifulsoup4`:

```bash
pip install beautifulsoup4
```

```python
def render_markdown(text: str) -> rx.Component:
    if not text.strip():
        return rx.el.div()

    html = markdown.markdown(text, extensions=["fenced_code", "tables"])
    html = wrap_tables(html)  # optional
    return rx.html(html, class_name="prose-content")
```