- Добавить GlobalKeyboardService — выделенный поток с блокирующим Console.ReadKey, единственный источник клавишных событий для TUI - Убрать FocusManager из App.razor: перехватывал Tab до компонентов - Удалить @onkeydown с <Select>: RazorConsole не пробрасывает Tab/стрелки через этот механизм - Использовать FocusedValue вместо Value в Select для корректной подсветки - Обновить CLAUDE.md и AGENTS.md: архитектура TUI, RazorConsole gotchas - Добавить docs/tui_log.md: разбор проблемы и справочник по RazorConsole Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
81 lines
2.7 KiB
Plaintext
81 lines
2.7 KiB
Plaintext
<Rows>
|
|
<Markup Content="Module Overview" Foreground="@UiPalette.Text" Decoration="@Spectre.Console.Decoration.Bold" />
|
|
<Markup Content="Up/Down select a module. Enter opens its settings." Foreground="@UiPalette.TextMuted" />
|
|
<Markup Content=" " />
|
|
|
|
@if (Rows.Count == 0)
|
|
{
|
|
<Border BorderColor="@UiPalette.Frame" BoxBorder="@Spectre.Console.BoxBorder.Rounded" Padding="@(new Spectre.Console.Padding(0, 0, 0, 0))">
|
|
<Markup Content="No modules registered." Foreground="@UiPalette.TextDim" />
|
|
</Border>
|
|
}
|
|
else
|
|
{
|
|
<Select TItem="int"
|
|
Options="@GetOptions()"
|
|
Value="@GetNormalizedIndex()"
|
|
FocusedValue="@GetNormalizedIndex()"
|
|
Formatter="@FormatRow"
|
|
Expand="true"
|
|
BorderStyle="@Spectre.Console.BoxBorder.Rounded"
|
|
SelectedIndicator="@('>')" />
|
|
}
|
|
|
|
<Markup Content=" " />
|
|
<Markup Content="@GetFooterText()" Foreground="@UiPalette.TextMuted" />
|
|
</Rows>
|
|
|
|
@code {
|
|
[Parameter, EditorRequired] public IReadOnlyList<OverviewRow> Rows { get; set; } = Array.Empty<OverviewRow>();
|
|
[Parameter] public int SelectedIndex { get; set; }
|
|
[Parameter] public EventCallback<int> SelectedIndexChanged { get; set; }
|
|
[Parameter] public int ViewportRows { get; set; } = 3;
|
|
|
|
private int[] GetOptions() => Enumerable.Range(0, Rows.Count).ToArray();
|
|
|
|
private int GetNormalizedIndex() => Rows.Count == 0 ? 0 : Math.Clamp(SelectedIndex, 0, Rows.Count - 1);
|
|
|
|
private string GetFooterText()
|
|
{
|
|
if (Rows.Count == 0)
|
|
{
|
|
return "No integration modules available.";
|
|
}
|
|
|
|
var selected = Rows[Math.Clamp(SelectedIndex, 0, Rows.Count - 1)];
|
|
var state = selected.IsModuleEnabled ? "ON" : "OFF";
|
|
return $"{selected.ModuleName}: {selected.Description} | Module {state} | Tools {selected.ConfiguredTools}/{selected.TotalTools}";
|
|
}
|
|
|
|
private static Spectre.Console.Color GetRowForeground(OverviewRow row) =>
|
|
row.IsModuleEnabled ? UiPalette.Text : UiPalette.TextMuted;
|
|
|
|
private string FormatRow(int index)
|
|
{
|
|
var row = Rows[index];
|
|
var status = row.IsModuleEnabled ? "[ON] " : "[OFF]";
|
|
var text = $"{row.ModuleName,-12} {status} {row.ConfiguredTools,2}/{row.TotalTools,-2} {row.Description}";
|
|
return Fit(text, Math.Max(Console.WindowWidth - 12, 32));
|
|
}
|
|
|
|
private static string Fit(string text, int width)
|
|
{
|
|
if (width <= 0)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
if (text.Length <= width)
|
|
{
|
|
return text.PadRight(width);
|
|
}
|
|
|
|
if (width <= 3)
|
|
{
|
|
return text[..width];
|
|
}
|
|
|
|
return text[..(width - 3)] + "...";
|
|
}
|
|
}
|