Added docs RazorConsole

This commit is contained in:
2026-04-13 16:53:31 +03:00
parent e37ab09fc5
commit c117d928b0
5 changed files with 913 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
# RazorConsole — Документация
Документация по библиотеке [RazorConsole](https://github.com/RazorConsole/RazorConsole) для проекта LazyBearWorks.
## Файлы
| Файл | Содержание |
|---|---|
| [overview.md](overview.md) | Обзор, установка, минимальный пример, примеры приложений |
| [components.md](components.md) | Полный справочник по 25+ встроенным компонентам |
| [custom-translators.md](custom-translators.md) | Архитектура VDOM, создание и регистрация кастомных трансляторов |
| [contributing.md](contributing.md) | Настройка окружения, стандарты кода, процесс PR |
## Быстрый старт
```bash
dotnet add package RazorConsole.Core
```
```xml
<!-- .csproj -->
<Project Sdk="Microsoft.NET.Sdk.Razor">
```
```csharp
// Program.cs
IHostBuilder hostBuilder = Host.CreateDefaultBuilder(args)
.UseRazorConsole<MyRootComponent>();
await hostBuilder.Build().RunAsync();
```
## Версия
Документация актуальна для **v0.5.0** (март 2026).

View File

@@ -0,0 +1,418 @@
# RazorConsole — Встроенные компоненты
Полный справочник по 25+ компонентам, поставляемым с `RazorConsole.Core`.
Каждый компонент транслируется в `IRenderable` Spectre.Console во время рендеринга.
> Параметры, отмеченные ⚠️, являются обязательными.
---
## Макет (Layout)
### Align
Выравнивает дочерний контент горизонтально и вертикально.
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| `ChildContent` | `RenderFragment?` | — | Вложенный контент |
| `Horizontal` | `HorizontalAlignment` | `Left` | `Left`, `Center`, `Right` |
| `Vertical` | `VerticalAlignment` | `Top` | `Top`, `Middle`, `Bottom` |
| `Width` | `int?` | `null` | Фиксированная ширина в символах |
| `Height` | `int?` | `null` | Фиксированная высота в строках |
---
### Columns
Располагает дочерние элементы горизонтально (колонками).
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| `ChildContent` | `RenderFragment?` | — | Элементы колонок |
| `Expand` | `bool` | `false` | Растянуть на всю ширину консоли |
---
### Rows
Стекует дочерние элементы вертикально.
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| `ChildContent` | `RenderFragment?` | — | Элементы строк |
| `Expand` | `bool` | `false` | Растянуть на всю высоту |
---
### FlexBox
CSS-подобный flexbox-макет с настройкой направления, выравнивания и переноса.
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| `ChildContent` | `RenderFragment?` | — | Элементы контейнера |
| `Direction` | `FlexDirection` | `Row` | `Row` (горизонталь) или `Column` (вертикаль) |
| `Justify` | `FlexJustify` | `Start` | `Start`, `End`, `Center`, `SpaceBetween`, `SpaceAround`, `SpaceEvenly` |
| `Align` | `FlexAlign` | `Start` | `Start`, `End`, `Center`, `Stretch` |
| `Wrap` | `FlexWrap` | `NoWrap` | `NoWrap`, `Wrap` |
| `Gap` | `int` | `0` | Отступ между элементами (символы / строки) |
| `Width` | `int?` | `null` | Явное ограничение ширины |
| `Height` | `int?` | `null` | Явное ограничение высоты |
---
### Grid
Многострочный многоколоночный макет с точным управлением ячейками.
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| `ChildContent` | `RenderFragment?` | — | Строки и ячейки сетки |
| `Columns` | `int` | `2` | Количество колонок |
| `Expand` | `bool` | `false` | Растянуть на доступную ширину |
| `Width` | `int?` | `null` | Фиксированная ширина |
---
### Padder
Добавляет внешние отступы вокруг дочернего контента.
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| `ChildContent` | `RenderFragment?` | — | Внутренний контент |
| `Padding` | `Padding` | `new(0,0,0,0)` | Отступы (left, top, right, bottom) |
---
### Scrollable
Постраничный скроллинг для типизированных коллекций с поддержкой клавиатуры.
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| `Items` | `IReadOnlyList<TItem>` | `Array.Empty<TItem>()` | Источник данных |
| `PageSize` | `int` | `1` | Элементов на странице |
| `ChildContent` | `RenderFragment<ScrollContext<TItem>>` | — | Разметка видимой страницы |
| `ScrollOffset` | `int` | `0` | Двусторонний: индекс начала страницы |
| `ScrollOffsetChanged` | `EventCallback<int>` | — | Срабатывает при смене offset |
| `IsScrollbarEmbedded` | `bool` | `true` | Встроить скроллбар внутрь `Table`/`Panel`/`Border` |
#### ScrollContext\<TItem\>
| Член | Тип | Описание |
|---|---|---|
| `this[int i]` | `TItem` | Видимый элемент по индексу |
| `Count` | `int` | Количество видимых элементов |
| `KeyDownEventHandler` | `Func<KeyboardEventArgs,Task>` | Привязать через `@onkeydown` |
| `CurrentOffset` | `int` | Текущий scroll offset |
| `PagesCount` | `int` | Всего страниц |
---
### ViewHeightScrollable
Постраничный скроллинг произвольного `RenderFragment` по строкам (без типизированных данных).
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| `ChildContent` | `RenderFragment<ScrollContext>` | — | ⚠️ Контент вьюпорта |
| `LinesToRender` | `int` | `10` | Высота вьюпорта в строках |
| `ScrollOffset` | `int` | `0` | Двусторонний: индекс первой видимой строки |
| `ScrollOffsetChanged` | `EventCallback<int>` | — | Срабатывает при скролле |
| `Scrollbar` | `ScrollbarSettings?` | `null` | Настройки скроллбара |
| `IsScrollbarEmbedded` | `bool` | `true` | Встроить скроллбар внутрь border-компонента |
**Горячие клавиши:** `↑`/`↓` — одна строка, `PageUp`/`PageDown`/`Space` — страница, `Home`/`End` — границы.
#### ScrollbarSettings
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| `TrackChar` | `char` | `'│'` | Символ дорожки |
| `ThumbChar` | `char` | `'█'` | Символ ползунка |
| `TrackColor` | `Color` | `Color.Grey` | Цвет дорожки |
| `ThumbColor` | `Color` | `Color.White` | Цвет ползунка |
| `TrackFocusedColor` | `Color` | `Color.Grey74` | Цвет дорожки при фокусе |
| `ThumbFocusedColor` | `Color` | `Color.DeepSkyBlue1` | Цвет ползунка при фокусе |
| `MinThumbHeight` | `int` | `1` | Минимальная высота ползунка |
---
## Ввод (Input)
### TextInput
Поле ввода текста с placeholder, маскированием и управлением фокусом.
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| `Value` | `string?` | `null` | Двустороннее связывание текста |
| `ValueChanged` | `EventCallback<string?>` | — | Срабатывает при изменении |
| `OnInput` | `EventCallback<string?>` | — | Срабатывает при каждом нажатии |
| `Placeholder` | `string?` | `null` | Текст-подсказка |
| `MaskInput` | `bool` | `false` | Маскирование символов (пароли) |
| `FocusOrder` | `int?` | `null` | Порядок фокуса |
---
### TextButton
Кликабельная кнопка с изменением цвета при фокусе.
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| `Content` | `string` | `string.Empty` | Текст кнопки |
| `BackgroundColor` | `Color` | `Color.Default` | Фон в нормальном состоянии |
| `FocusedColor` | `Color` | `Color.DeepSkyBlue1` | Фон при фокусе |
| `OnClick` | `EventCallback` | — | Срабатывает при нажатии |
| `FocusOrder` | `int?` | `null` | Порядок фокуса |
---
### Select
Интерактивный выпадающий список с клавиатурной навигацией.
**Основные параметры:**
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| `Options` | `string[]` | `Array.Empty<string>()` | Доступные варианты |
| `Value` | `string?` | `null` | Текущий выбор |
| `ValueChanged` | `EventCallback<string>` | — | Срабатывает при смене |
| `OnSelected` | `EventCallback<string?>` | — | Срабатывает при подтверждении |
| `OnClear` | `EventCallback` | — | Срабатывает при очистке |
| `Placeholder` | `string` | `"Select an option"` | Текст при отсутствии выбора |
| `Expand` | `bool` | `false` | Растянуть горизонтально |
| `FocusOrder` | `int?` | `null` | Порядок фокуса |
| `BorderStyle` | `BoxBorder` | `Rounded` | Стиль рамки |
**Клавиатура:** стрелки, `Space` для переключения, `Enter` для подтверждения, `Escape` для отмены, буквы для быстрого перехода.
---
## Отображение (Display)
### Markup
Стилизованный текст с тегами разметки Spectre.
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| `Content` ⚠️ | `string` | — | Текст (автоматически экранируется) |
| `Foreground` | `Color` | `Style.Plain.Foreground` | Цвет текста |
| `Background` | `Color` | `Style.Plain.Background` | Цвет фона |
| `Decoration` | `Decoration` | `None` | `Bold`, `Italic`, `Underline` и др. |
| `link` | `string?` | `null` | Гиперссылка |
---
### Markdown
Рендеринг markdown-строки в консоль.
| Параметр | Тип | Описание |
|---|---|---|
| `Content` ⚠️ | `string` | Markdown-текст для отображения |
---
### Panel
Обёртка Spectre.Console Panel с заголовком и рамкой.
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| `ChildContent` | `RenderFragment?` | — | Содержимое панели |
| `Title` | `string?` | `null` | Заголовок панели |
| `TitleColor` | `Color?` | `null` | Цвет заголовка |
| `BorderColor` | `Color?` | `null` | Цвет рамки |
| `Border` | `BoxBorder?` | `null` | Стиль рамки |
| `Height` | `int?` | `null` | Фиксированная высота |
| `Width` | `int?` | `null` | Фиксированная ширина |
| `Padding` | `Padding?` | `null` | Внутренние отступы |
| `Expand` | `bool` | `false` | Растянуть на ширину |
---
### Border
Рамка вокруг дочернего контента (без заголовка).
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| `ChildContent` | `RenderFragment?` | — | Контент внутри рамки |
| `BorderColor` | `Color?` | `null` | Цвет рамки |
| `BoxBorder` | `BoxBorder` | `Rounded` | Стиль рамки |
| `Padding` | `Padding` | `new(0,0,0,0)` | Внутренние отступы |
---
### Table
HTML-подобная таблица, транслируемая в Spectre.Console `Table`.
> Ключевая идея: используйте стандартные `<table>`, `<thead>`, `<tbody>`, `<tfoot>`, `<tr>`, `<th>`, `<td>`.
| Атрибут | Тип | По умолчанию | Описание |
|---|---|---|---|
| `class="table"` ⚠️ | — | — | Обязательный хук для транслятора |
| `data-expand` | `bool` | `false` | Растянуть на ширину консоли |
| `data-width` | `int?` | `null` | Фиксированная ширина |
| `data-title` | `string?` | `null` | Подпись таблицы |
| `data-border` | `TableBorderStyle` | `None` | Стиль рамки |
| `data-show-headers` | `bool` | `true` | Показывать заголовки |
Выравнивание колонок: атрибут `data-align="left|center|right"` на `<th>`.
```razor
<table class="table" data-border="Square" data-expand="true" data-title="Build status">
<thead>
<tr>
<th data-align="left">Stage</th>
<th data-align="right">Result</th>
</tr>
</thead>
<tbody>
<tr>
<td>Compile</td>
<td><Markup Content="[green]✔[/]" /></td>
</tr>
</tbody>
</table>
```
---
### Figlet
Большой ASCII-арт текст с использованием FIGlet-шрифтов.
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| `Content` | `string` | `string.Empty` | Текст для рендеринга |
| `Justify` | `Justify` | `Center` | Выравнивание |
| `Color` | `Color` | `Color.Default` | Цвет глифов |
---
### BarChart
Горизонтальная барная диаграмма.
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| `BarChartItems` ⚠️ | `List<IBarChartItem>` | — | Данные (`Label`, `Value`, `Color`) |
| `Width` | `int?` | `null` | Ширина (по умолчанию — вся консоль) |
| `Label` | `string?` | `null` | Заголовок диаграммы |
| `MaxValue` | `double?` | `null` | Максимальное значение шкалы |
| `ShowValues` | `bool` | `false` | Показывать числа рядом с барами |
| `Culture` | `CultureInfo` | текущая | Культура для форматирования чисел |
---
### BreakdownChart
Диаграмма разбивки (pie-style).
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| `BreakdownChartItems` ⚠️ | `List<IBreakdownChartItem>` | — | Данные (`Label`, `Value`, `Color`) |
| `Compact` | `bool` | `false` | Компактный режим |
| `Expand` | `bool` | `false` | Растянуть на всю ширину |
| `Width` | `int?` | `null` | Ширина |
| `ShowTags` | `bool` | `false` | Показывать легенду |
| `ShowTagValues` | `bool` | `false` | Показывать абсолютные значения |
| `ShowTagValuesPercentage` | `bool` | `false` | Показывать проценты |
---
### StepChart
Ступенчатая диаграмма с использованием Unicode box-drawing символов.
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| `Series` ⚠️ | `List<ChartSeries>` | — | Набор серий данных |
| `Width` | `int` | `60` | Ширина диаграммы |
| `Height` | `int` | `20` | Высота диаграммы |
| `ShowAxes` | `bool` | `true` | Показывать оси |
| `AxesColor` | `Color` | `Color.Grey` | Цвет осей |
| `LabelsColor` | `Color` | `Color.Grey` | Цвет подписей |
| `Title` | `string?` | `null` | Заголовок |
| `TitleColor` | `Color` | `Color.Grey` | Цвет заголовка |
**ChartSeries:**
| Член | Тип | Описание |
|---|---|---|
| `Color` | `Color` | Цвет линии |
| `Points` | `List<(double X, double Y)>` | Точки данных |
---
### SpectreCanvas
Рендеринг массива пикселей с разными цветами.
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| `Pixels` ⚠️ | `(int x, int y, Color color)[]` | — | Массив пикселей |
| `CanvasWidth` ⚠️ | `int` | — | Ширина холста |
| `CanvasHeight` ⚠️ | `int` | — | Высота холста |
| `MaxWidth` | `int?` | `null` | Максимальная ширина |
| `PixelWidth` | `int` | `2` | Ширина прямоугольника пикселя |
| `Scale` | `bool` | `false` | Масштабировать при рендеринге |
---
### SyntaxHighlighter
Подсветка синтаксиса кода с темами ColorCode.
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| `Code` | `string` | `string.Empty` | Исходный код |
| `Language` | `string?` | `null` | Язык: `"csharp"`, `"json"`, `"sql"` и др. |
| `Theme` | `string?` | `null` | Тема оформления |
| `ShowLineNumbers` | `bool` | `false` | Показывать номера строк |
**Встроенные языки:** `text/plaintext/plain`, `csharp/cs`, `razor`, `html`, `json`, `xml`, `sql`, `js/javascript`, `ts/typescript`, `css`, `powershell/ps`, `python`, `md/markdown`.
---
### ModalWindow
Модальное окно с автоматическим центрированием через z-index.
---
### ModalWindow
Модальное окно поверх текущего экрана с автоматическим центрированием.
> Визуализация построена на z-index, чтобы окно корректно перекрывало другие элементы.
---
## Утилиты
### Spinner
Анимированный индикатор прогресса.
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| `SpinnerType` | `Spinner` | `Spinner.Known.Dots` | Тип спиннера |
| `SpinnerName` | `string?` | `null` | Имя спиннера (переопределение) |
| `Message` | `string?` | `null` | Сопроводительный текст |
| `Style` | `string?` | `null` | Markup-стиль Spectre |
| `AutoDismiss` | `bool` | `false` | Скрыть по завершении |
---
### Newline
Вставляет один перенос строки. Параметров нет.

View File

@@ -0,0 +1,69 @@
# RazorConsole — Контрибьюция
## Начало работы
- **Для крупных PR, рефакторингов, новых фич** — сначала создай Issue для обсуждения
- **Discord:** https://discord.gg/DphHAnJxCM — мейнтейнеры активны там
## Настройка окружения разработки
### Требования
- .NET 8.0 или 9.0 SDK
- Git LFS (для крупных медиафайлов)
### Клонирование
```bash
git lfs install
git clone https://github.com/RazorConsole/RazorConsole.git
cd RazorConsole
dotnet build RazorConsole.slnx
dotnet test RazorConsole.slnx
```
## Стандарты кода
- Следовать правилам `.editorconfig` (4 пробела, file-scoped namespaces, System usings первые)
- Предпочитать `async/await` с `ConfigureAwait(false)` в библиотечном коде
- Public API: nullable-enabled, документировать исключения и edge cases
- Spectre.Console renderables — immutable вне rendering loops
## Перед отправкой PR
```bash
dotnet format RazorConsole.slnx # форматирование
dotnet test RazorConsole.slnx # тесты (должны пройти на Linux и Windows)
```
При изменениях в focus/keyboard handling — добавить/обновить тесты в `FocusManagerTests` или `KeyboardEventManagerTests`.
## Процесс PR
1. Создать Issue для крупных изменений
2. Форкнуть репозиторий, создать ветку от `main`
3. Сделать изменения, соблюдая стандарты кода
4. Написать/обновить тесты
5. Запустить `dotnet format` и `dotnet test`
6. Отправить PR с описанием изменений
## Структура тестов
- Тесты находятся в `src/RazorConsole.Tests`
- CI требует чистого прохождения на Linux и Windows
- Покрытие: Codecov (Cobertura format)
## Документация
- `README.md` — обновлять при user-facing изменениях
- XML doc-комментарии для public API
- `examples/` — добавлять примеры для новых фич
- `design-doc/` — архитектурные заметки
## Git LFS
Отслеживаемые типы файлов: `*.gif`, `*.png`, `*.jpg`, `*.jpeg`, `*.mp4`, `*.mov`, `*.avi`, `*.zip`, `*.tar.gz`, `*.pdf`.
## Релизный процесс
Создание GitHub Release запускает `.github/workflows/release.yml` — сборка, тесты, паковка и публикация. Версии следуют семантическому версионированию.

View File

@@ -0,0 +1,276 @@
# RazorConsole — Кастомные VDOM-трансляторы
## Архитектура
RazorConsole использует Virtual DOM (VDOM) для преобразования Razor-компонентов в Spectre.Console `IRenderable`. Система трансляторов (translators) является расширяемой: можно добавить поддержку новых Spectre.Console-конструкций или построить полностью кастомные компоненты.
### Ключевые компоненты
#### `IVdomElementTranslator`
```csharp
public interface IVdomElementTranslator
{
// Чем меньше значение — тем выше приоритет (обрабатывается раньше).
int Priority { get; }
bool TryTranslate(VNode node, TranslationContext context, out IRenderable? renderable);
}
```
#### `TranslationContext`
```csharp
public sealed class TranslationContext
{
// Рекурсивный перевод дочерних узлов
public bool TryTranslate(VNode node, out IRenderable? renderable);
}
```
#### `VdomSpectreTranslator`
Оркестратор, который:
1. Получает список трансляторов через DI (отсортированных по приоритету)
2. Пробует каждый по очереди
3. Возвращает первый успешный результат
4. Предоставляет статические вспомогательные методы
### Pipeline трансляции
```
Razor-компонент → ConsoleRenderer → VNode tree → VdomSpectreTranslator
→ [Priority 10] → [Priority 20] → ... → [Priority 1000 (fallback)]
→ IRenderable
```
---
## Встроенные трансляторы
| Приоритет | Транслятор | Обрабатывает |
|---|---|---|
| 10 | TextElementTranslator | `<span data-text="true">` |
| 20 | HtmlInlineTextElementTranslator | `<strong>`, `<em>`, `<code>` |
| 30 | ParagraphElementTranslator | `<p>` |
| 40 | SpacerElementTranslator | `<div data-spacer="true">` |
| 50 | NewlineElementTranslator | `<br>` |
| 60 | SpinnerElementTranslator | `<div class="spinner">` |
| 7080 | Button translators | `<button>` |
| 90 | SyntaxHighlighterElementTranslator | `<div class="syntax-highlighter">` |
| 100190 | Layout translators | Panels, Rows, Columns, Grid, Padding, Align |
| 1000 | FailToRenderElementTranslator | Fallback для необработанных узлов |
---
## Создание кастомного транслятора
### Шаг 1: Реализовать интерфейс
```csharp
using RazorConsole.Core.Rendering.Vdom;
using RazorConsole.Core.Vdom;
using Spectre.Console;
using Spectre.Console.Rendering;
public sealed class OverflowElementTranslator : IVdomElementTranslator
{
public int Priority => 85; // между встроенными 80 и 90
public bool TryTranslate(VNode node, TranslationContext context, out IRenderable? renderable)
{
renderable = null;
// 1. Быстрые проверки — fail fast
if (node.Kind != VNodeKind.Element) return false;
if (!string.Equals(node.TagName, "div", StringComparison.OrdinalIgnoreCase)) return false;
if (!node.Attributes.TryGetValue("data-overflow", out var overflowType)) return false;
// 2. Трансляция дочерних узлов
if (!VdomSpectreTranslator.TryConvertChildrenToRenderables(
node.Children, context, out var children)) return false;
var content = VdomSpectreTranslator.ComposeChildContent(children);
// 3. Создать IRenderable
renderable = overflowType?.ToLowerInvariant() switch
{
"ellipsis" => new Padder(content).Overflow(Overflow.Ellipsis),
"crop" => new Padder(content).Overflow(Overflow.Crop),
"fold" => new Padder(content).Overflow(Overflow.Fold),
_ => content
};
return true;
}
}
```
### Шаг 2: Зарегистрировать транслятор
```csharp
using Microsoft.Extensions.Hosting;
using RazorConsole.Core;
using RazorConsole.Core.Vdom;
IHostBuilder hostBuilder = Host.CreateDefaultBuilder(args)
.UseRazorConsole<MyComponent>(configure: config =>
{
config.ConfigureServices(services =>
{
// По типу (создаётся через DI)
services.AddVdomTranslator<OverflowElementTranslator>();
// По экземпляру
services.AddVdomTranslator(new OverflowElementTranslator());
// Через фабрику (для инъекции зависимостей)
services.AddVdomTranslator(sp =>
new OverflowElementTranslator(sp.GetRequiredService<IMyService>()));
});
});
```
### Шаг 3: Использовать в Razor-компонентах
```razor
<div data-overflow="ellipsis">
Очень длинный текст, который будет обрезан с многоточием...
</div>
```
---
## Вспомогательные методы `VdomSpectreTranslator`
### Инспекция узла
```csharp
string? value = VdomSpectreTranslator.GetAttribute(node, "data-style");
bool hasClass = VdomSpectreTranslator.HasClass(node, "my-class");
string? text = VdomSpectreTranslator.CollectInnerText(node);
```
### Парсинг атрибутов
```csharp
// bool
if (VdomSpectreTranslator.TryGetBoolAttribute(node, "data-enabled", out bool enabled)) { }
// int с fallback
int count = VdomSpectreTranslator.TryGetIntAttribute(node, "data-count", fallback: 10);
// положительный int
if (VdomSpectreTranslator.TryParsePositiveInt(rawValue, out int result)) { }
// int? (null если невалидно)
int? width = VdomSpectreTranslator.ParseOptionalPositiveInt(rawValue);
// CSS-подобный padding: "1", "1,2", "1,2,3,4"
if (VdomSpectreTranslator.TryParsePadding(rawValue, out Padding padding)) { }
```
### Парсинг выравнивания
```csharp
var hAlign = VdomSpectreTranslator.ParseHorizontalAlignment(value); // Left/Center/Right
var vAlign = VdomSpectreTranslator.ParseVerticalAlignment(value); // Top/Middle/Bottom
```
### Работа с дочерними узлами
```csharp
// Перевести дочерние узлы
if (VdomSpectreTranslator.TryConvertChildrenToRenderables(
node.Children, context, out List<IRenderable> renderables)) { }
// Объединить в один IRenderable
// - 1 элемент → возвращает его напрямую
// - N элементов → Rows
// - 0 элементов → пустой Markup
IRenderable composed = VdomSpectreTranslator.ComposeChildContent(renderables);
```
---
## Правила выбора приоритета
| Диапазон | Когда использовать |
|---|---|
| 19 | Переопределить встроенное поведение |
| 10190 | Вклиниться между конкретными встроенными трансляторами |
| 200999 | Общие кастомные трансляторы |
| 1000+ | Fallback-обработчики |
---
## Лучшие практики
1. **Fail fast** — сразу возвращай `false` если узел не совпадает
2. **Case-insensitive сравнение**`StringComparison.OrdinalIgnoreCase` для `TagName` и атрибутов
3. **Всегда используй `TryConvertChildrenToRenderables`** для рекурсивной трансляции детей
4. **Валидируй атрибуты** — предусматривай defaults, не бросай исключения
5. **Immutability** — создавай новые экземпляры `IRenderable`, не мутируй существующие
6. **Thread safety** — трансляторы должны быть stateless или использовать immutable state
---
## Продвинутые сценарии
### DI в трансляторе
```csharp
public sealed class DatabaseStyleTranslator : IVdomElementTranslator
{
private readonly IStyleProvider _styleProvider;
public DatabaseStyleTranslator(IStyleProvider styleProvider)
{
_styleProvider = styleProvider;
}
public int Priority => 95;
public bool TryTranslate(VNode node, TranslationContext context, out IRenderable? renderable)
{
renderable = null;
if (!node.Attributes.TryGetValue("data-style-id", out var styleId)) return false;
var style = _styleProvider.GetStyle(styleId);
// ... создать renderable ...
return true;
}
}
// Регистрация
services.AddSingleton<IStyleProvider, MyStyleProvider>();
services.AddVdomTranslator<DatabaseStyleTranslator>();
```
### Условная трансляция (Alert-компонент)
```csharp
public sealed class AlertTranslator : IVdomElementTranslator
{
public int Priority => 105;
public bool TryTranslate(VNode node, TranslationContext context, out IRenderable? renderable)
{
renderable = null;
if (!VdomSpectreTranslator.HasClass(node, "alert")) return false;
if (!VdomSpectreTranslator.TryConvertChildrenToRenderables(
node.Children, context, out var children)) return false;
var content = VdomSpectreTranslator.ComposeChildContent(children);
renderable = VdomSpectreTranslator.HasClass(node, "alert-danger")
? new Panel(content).BorderColor(Color.Red).Header("[red]⚠ Error[/]")
: VdomSpectreTranslator.HasClass(node, "alert-success")
? new Panel(content).BorderColor(Color.Green).Header("[green]✓ Success[/]")
: new Panel(content).BorderColor(Color.Blue).Header("[blue] Info[/]");
return true;
}
}
```

View File

@@ -0,0 +1,116 @@
# RazorConsole — Обзор
**Репозиторий:** https://github.com/RazorConsole/RazorConsole
**Лицензия:** MIT
**Последняя версия:** v0.5.0 (март 2026)
**NuGet:** `RazorConsole.Core`
## Что такое RazorConsole?
RazorConsole — это .NET-библиотека для построения интерактивных TUI-приложений (Terminal User Interface) с использованием синтаксиса Razor-компонентов и движка рендеринга Spectre.Console.
Библиотека заполняет разрыв между веб-разработкой на Blazor/Razor и консольными приложениями: разработчик пишет компоненты `.razor`, а на выходе получает полноценный интерактивный терминальный интерфейс.
## Ключевые возможности
| Возможность | Описание |
|---|---|
| Компонентная архитектура | Razor-компоненты с data binding, event handling и lifecycle |
| 25+ встроенных компонентов | Макет, ввод, отображение, утилиты |
| Интерактивность | Кнопки, текстовые поля, селекторы, навигация клавиатурой |
| Hot Reload | Обновление UI без перезапуска через metadata update handler |
| VDOM + Translators | Виртуальный DOM с расширяемой системой трансляторов |
| DI интеграция | Построен на `Microsoft.Extensions.Hosting` |
| Галерея компонентов | Глобальный инструмент `razorconsole-gallery` |
## Технологический стек
- **Runtime:** .NET 8 / .NET 9
- **SDK:** `Microsoft.NET.Sdk.Razor` (обязателен в `.csproj`)
- **Рендеринг:** Spectre.Console
- **DI/Host:** `Microsoft.Extensions.Hosting`
- **Синтаксис подсветки:** ColorCode
## Установка
```bash
dotnet add package RazorConsole.Core
```
## Минимальный проект
### Файл проекта (`.csproj`)
```xml
<Project Sdk="Microsoft.NET.Sdk.Razor">
<!-- другие настройки -->
</Project>
```
### Компонент `Counter.razor`
```razor
@using Microsoft.AspNetCore.Components
@using Microsoft.AspNetCore.Components.Web
@using RazorConsole.Components
<Columns>
<p>Current count</p>
<Markup Content="@currentCount.ToString()" Foreground="@Spectre.Console.Color.Green" />
</Columns>
<TextButton Content="Click me"
OnClick="IncrementCount"
BackgroundColor="@Spectre.Console.Color.Grey"
FocusedColor="@Spectre.Console.Color.Blue" />
@code {
private int currentCount = 0;
private void IncrementCount() { currentCount++; }
}
```
### `Program.cs`
```csharp
using Microsoft.Extensions.Hosting;
using RazorConsole.Core;
IHostBuilder hostBuilder = Host.CreateDefaultBuilder(args)
.UseRazorConsole<Counter>();
IHost host = hostBuilder.Build();
await host.RunAsync();
```
## Примеры приложений
| Пример | Демонстрирует |
|---|---|
| `examples/Counter/` | Основы: кнопки, состояние, layout, styled text |
| `examples/LLMAgentTUI/` | Интеграция с AI SDK (OpenAI/Ollama), чат-интерфейс |
| `examples/LoginForm/` | Форма с валидацией, маскирование пароля, состояния ошибок |
## Компонентная галерея
```bash
dotnet tool install --global RazorConsole.Gallery --version 0.0.3-alpha
razorconsole-gallery
```
## Структура репозитория
```
src/ — исходный код библиотеки
examples/ — примеры приложений
design-doc/ — архитектурные документы
nuget/ — конфигурация NuGet
release-notes/ — история релизов
docfx/ — генерация документации
website/ — сайт проекта
```
## Сообщество
- Discord: https://discord.gg/DphHAnJxCM
- Issues: https://github.com/RazorConsole/RazorConsole/issues
- Codecov: https://codecov.io/gh/RazorConsole/RazorConsole