Enhance tables canvas reading states
This commit is contained in:
@@ -61,17 +61,23 @@
|
||||
SelectedGroupKey="selectedGroupKey"
|
||||
SelectedColumnKey="selectedColumnKey"
|
||||
RollJumpValue="rollJumpValue"
|
||||
DensityMode="densityMode"
|
||||
OnTogglePin="TogglePinnedTableAsync"
|
||||
OnModeChanged="UpdateReferenceModeAsync"
|
||||
OnGroupChanged="UpdateSelectedGroupAsync"
|
||||
OnColumnChanged="UpdateSelectedColumnAsync"
|
||||
OnRollJumpChanged="UpdateRollJumpAsync" />
|
||||
OnRollJumpChanged="UpdateRollJumpAsync"
|
||||
OnDensityChanged="UpdateDensityModeAsync" />
|
||||
|
||||
<TablesCanvas
|
||||
Detail="detail"
|
||||
CurrentMode="referenceMode"
|
||||
SelectedGroupKey="selectedGroupKey"
|
||||
SelectedColumnKey="selectedColumnKey"
|
||||
RollJumpValue="rollJumpValue"
|
||||
DensityMode="densityMode"
|
||||
SelectedCell="selectedCell"
|
||||
OnSelectCell="SelectCell"
|
||||
OnOpenCuration="OpenCellCurationAsync"
|
||||
OnOpenEditor="OpenCellEditorAsync" />
|
||||
</div>
|
||||
@@ -150,6 +156,8 @@
|
||||
private string selectedGroupKey = string.Empty;
|
||||
private string selectedColumnKey = string.Empty;
|
||||
private string rollJumpValue = string.Empty;
|
||||
private string densityMode = TablesDensityMode.Comfortable;
|
||||
private TablesCellSelection? selectedCell;
|
||||
private bool hasResolvedStoredTableSelection;
|
||||
private CriticalTableReference? SelectedTableReference =>
|
||||
referenceData?.CriticalTables.FirstOrDefault(item => string.Equals(item.Key, selectedTableSlug, StringComparison.OrdinalIgnoreCase));
|
||||
@@ -664,6 +672,23 @@
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private Task UpdateDensityModeAsync(string mode)
|
||||
{
|
||||
densityMode = NormalizeDensityMode(mode);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void SelectCell(TablesCellSelection selection)
|
||||
{
|
||||
if (tableDetail?.Cells.Any(cell => cell.ResultId == selection.ResultId) != true)
|
||||
{
|
||||
selectedCell = null;
|
||||
return;
|
||||
}
|
||||
|
||||
selectedCell = selection;
|
||||
}
|
||||
|
||||
private void NormalizeViewStateForCurrentDetail()
|
||||
{
|
||||
referenceMode = NormalizeMode(referenceMode);
|
||||
@@ -673,6 +698,8 @@
|
||||
selectedGroupKey = string.Empty;
|
||||
selectedColumnKey = string.Empty;
|
||||
rollJumpValue = string.Empty;
|
||||
densityMode = NormalizeDensityMode(densityMode);
|
||||
selectedCell = null;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -687,6 +714,12 @@
|
||||
}
|
||||
|
||||
rollJumpValue = NormalizeRollInput(rollJumpValue);
|
||||
densityMode = NormalizeDensityMode(densityMode);
|
||||
|
||||
if (selectedCell is not null && tableDetail.Cells.All(cell => cell.ResultId != selectedCell.ResultId))
|
||||
{
|
||||
selectedCell = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static string NormalizeMode(string? mode) =>
|
||||
@@ -700,6 +733,11 @@
|
||||
private static string NormalizeOptionalFilter(string? value) =>
|
||||
string.IsNullOrWhiteSpace(value) ? string.Empty : value.Trim();
|
||||
|
||||
private static string NormalizeDensityMode(string? mode) =>
|
||||
string.Equals(mode, TablesDensityMode.Dense, StringComparison.Ordinal)
|
||||
? TablesDensityMode.Dense
|
||||
: TablesDensityMode.Comfortable;
|
||||
|
||||
private static string NormalizeRollInput(string? value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<div class="table-scroll">
|
||||
<div class="critical-table-grid" role="group" aria-label="@Detail.DisplayName" style="@gridTemplateStyle">
|
||||
<div class="critical-table-grid @BuildGridCssClass()" role="group" aria-label="@Detail.DisplayName" style="@gridTemplateStyle">
|
||||
@if (Detail.Groups.Count > 0)
|
||||
{
|
||||
<div class="critical-table-grid-header-cell critical-table-grid-corner" aria-hidden="true"></div>
|
||||
@foreach (var group in visibleGroups)
|
||||
{
|
||||
<div
|
||||
class="critical-table-grid-header-cell critical-table-grid-group-header"
|
||||
class="@BuildGroupHeaderCssClass(group.Key)"
|
||||
style="@BuildColumnSpanStyle(visibleColumns.Count)">
|
||||
<span>@group.Label</span>
|
||||
</div>
|
||||
@@ -16,14 +16,14 @@
|
||||
<div class="critical-table-grid-header-cell critical-table-grid-roll-band-header" aria-hidden="true"></div>
|
||||
@foreach (var displayColumn in displayColumns)
|
||||
{
|
||||
<div class="critical-table-grid-header-cell critical-table-grid-column-header">
|
||||
<div class="@BuildColumnHeaderCssClass(displayColumn.GroupKey, displayColumn.ColumnKey)">
|
||||
<span>@displayColumn.ColumnLabel</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
@foreach (var rollBand in Detail.RollBands)
|
||||
{
|
||||
<div class="critical-table-grid-header-cell critical-table-grid-roll-band">@rollBand.Label</div>
|
||||
<div class="@BuildRollBandCssClass(rollBand.Label)">@rollBand.Label</div>
|
||||
@foreach (var displayColumn in displayColumns)
|
||||
{
|
||||
if (TryGetCell(rollBand.Label, displayColumn.GroupKey, displayColumn.ColumnKey, out var resolvedCell) && resolvedCell is not null)
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
@if (MatchesModeFilter(cell))
|
||||
{
|
||||
<div class="@GetCellCssClass(cell)">
|
||||
<div class="@GetCellCssClass(cell, displayColumn.GroupKey)" @onclick="() => SelectCell(cell)">
|
||||
<div class="critical-table-cell-shell">
|
||||
<div class="critical-table-cell-actions">
|
||||
@if (cell.IsCurated)
|
||||
@@ -45,6 +45,7 @@
|
||||
type="button"
|
||||
class="critical-cell-action-button is-curation"
|
||||
title="Open the curation preview for this cell."
|
||||
@onclick:stopPropagation="true"
|
||||
@onclick="() => OnOpenCuration.InvokeAsync(cell.ResultId)">
|
||||
Needs Curation
|
||||
</button>
|
||||
@@ -54,6 +55,7 @@
|
||||
type="button"
|
||||
class="critical-cell-action-button is-edit"
|
||||
title="Open the full editor for this cell."
|
||||
@onclick:stopPropagation="true"
|
||||
@onclick="() => OnOpenEditor.InvokeAsync(cell.ResultId)">
|
||||
Edit
|
||||
</button>
|
||||
@@ -105,6 +107,18 @@
|
||||
[Parameter]
|
||||
public string SelectedColumnKey { get; set; } = string.Empty;
|
||||
|
||||
[Parameter]
|
||||
public string RollJumpValue { get; set; } = string.Empty;
|
||||
|
||||
[Parameter]
|
||||
public string DensityMode { get; set; } = TablesDensityMode.Comfortable;
|
||||
|
||||
[Parameter]
|
||||
public TablesCellSelection? SelectedCell { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<TablesCellSelection> OnSelectCell { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<int> OnOpenCuration { get; set; }
|
||||
|
||||
@@ -175,10 +189,133 @@
|
||||
_ => true
|
||||
};
|
||||
|
||||
private static string BuildColumnSpanStyle(int span) => $"grid-column: span {span};";
|
||||
private string? ActiveRollBand =>
|
||||
!string.IsNullOrWhiteSpace(SelectedCell?.RollBand)
|
||||
? SelectedCell.RollBand
|
||||
: ResolveRollJumpBandLabel();
|
||||
|
||||
private static string GetCellCssClass(CriticalTableCellDetail cell) =>
|
||||
cell.IsCurated
|
||||
? "critical-table-cell is-curated"
|
||||
: "critical-table-cell needs-curation";
|
||||
private string? ActiveColumnKey =>
|
||||
!string.IsNullOrWhiteSpace(SelectedCell?.ColumnKey)
|
||||
? SelectedCell.ColumnKey
|
||||
: (!string.IsNullOrWhiteSpace(SelectedColumnKey) ? SelectedColumnKey : null);
|
||||
|
||||
private string? ActiveGroupKey =>
|
||||
!string.IsNullOrWhiteSpace(SelectedCell?.GroupKey)
|
||||
? SelectedCell.GroupKey
|
||||
: (!string.IsNullOrWhiteSpace(SelectedGroupKey) ? SelectedGroupKey : null);
|
||||
|
||||
private string BuildGridCssClass() =>
|
||||
string.Equals(DensityMode, TablesDensityMode.Dense, StringComparison.Ordinal)
|
||||
? "is-dense"
|
||||
: "is-comfortable";
|
||||
|
||||
private string BuildGroupHeaderCssClass(string groupKey)
|
||||
{
|
||||
var classes = new List<string> { "critical-table-grid-header-cell", "critical-table-grid-group-header" };
|
||||
if (string.Equals(groupKey, ActiveGroupKey, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
classes.Add("is-active-group");
|
||||
}
|
||||
|
||||
return string.Join(' ', classes);
|
||||
}
|
||||
|
||||
private string BuildColumnHeaderCssClass(string? groupKey, string columnKey)
|
||||
{
|
||||
var classes = new List<string> { "critical-table-grid-header-cell", "critical-table-grid-column-header" };
|
||||
|
||||
if (string.Equals(columnKey, ActiveColumnKey, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
classes.Add("is-active-column");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(groupKey) &&
|
||||
string.Equals(groupKey, ActiveGroupKey, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
classes.Add("is-active-group");
|
||||
}
|
||||
|
||||
return string.Join(' ', classes);
|
||||
}
|
||||
|
||||
private string BuildRollBandCssClass(string rollBandLabel)
|
||||
{
|
||||
var classes = new List<string> { "critical-table-grid-header-cell", "critical-table-grid-roll-band" };
|
||||
if (string.Equals(rollBandLabel, ActiveRollBand, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
classes.Add("is-active-row");
|
||||
}
|
||||
|
||||
if (string.Equals(rollBandLabel, ResolveRollJumpBandLabel(), StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
classes.Add("is-roll-target");
|
||||
}
|
||||
|
||||
return string.Join(' ', classes);
|
||||
}
|
||||
|
||||
private string GetCellCssClass(CriticalTableCellDetail cell, string? groupKey)
|
||||
{
|
||||
var classes = new List<string>
|
||||
{
|
||||
"critical-table-cell",
|
||||
cell.IsCurated ? "is-curated" : "needs-curation"
|
||||
};
|
||||
|
||||
if (string.Equals(cell.RollBand, ActiveRollBand, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
classes.Add("is-active-row");
|
||||
}
|
||||
|
||||
if (string.Equals(cell.ColumnKey, ActiveColumnKey, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
classes.Add("is-active-column");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(groupKey) &&
|
||||
string.Equals(groupKey, ActiveGroupKey, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
classes.Add("is-active-group");
|
||||
}
|
||||
|
||||
if (SelectedCell is not null && cell.ResultId == SelectedCell.ResultId)
|
||||
{
|
||||
classes.Add("is-selected-cell");
|
||||
}
|
||||
|
||||
if (string.Equals(cell.RollBand, ResolveRollJumpBandLabel(), StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
classes.Add("is-roll-target");
|
||||
}
|
||||
|
||||
return string.Join(' ', classes);
|
||||
}
|
||||
|
||||
private string? ResolveRollJumpBandLabel()
|
||||
{
|
||||
if (!int.TryParse(RollJumpValue, out var targetRoll))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach (var rollBand in Detail.RollBands)
|
||||
{
|
||||
if (targetRoll < rollBand.MinRoll)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rollBand.MaxRoll is null || targetRoll <= rollBand.MaxRoll.Value)
|
||||
{
|
||||
return rollBand.Label;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Task SelectCell(CriticalTableCellDetail cell) =>
|
||||
OnSelectCell.InvokeAsync(new TablesCellSelection(cell.ResultId, cell.RollBand, cell.ColumnKey, cell.GroupKey));
|
||||
|
||||
private static string BuildColumnSpanStyle(int span) => $"grid-column: span {span};";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace RolemasterDb.App.Components.Tables;
|
||||
|
||||
public sealed record TablesCellSelection(
|
||||
int ResultId,
|
||||
string RollBand,
|
||||
string ColumnKey,
|
||||
string? GroupKey);
|
||||
@@ -13,12 +13,21 @@
|
||||
</div>
|
||||
|
||||
<div class="tables-context-controls">
|
||||
<SegmentedTabs
|
||||
Items="modeTabs"
|
||||
SelectedValue="CurrentMode"
|
||||
SelectedValueChanged="OnModeChanged"
|
||||
AriaLabel="Reference mode"
|
||||
CssClass="tables-context-mode-tabs" />
|
||||
<div class="tables-context-tab-row">
|
||||
<SegmentedTabs
|
||||
Items="modeTabs"
|
||||
SelectedValue="CurrentMode"
|
||||
SelectedValueChanged="OnModeChanged"
|
||||
AriaLabel="Reference mode"
|
||||
CssClass="tables-context-mode-tabs" />
|
||||
|
||||
<SegmentedTabs
|
||||
Items="densityTabs"
|
||||
SelectedValue="DensityMode"
|
||||
SelectedValueChanged="OnDensityChanged"
|
||||
AriaLabel="Table density"
|
||||
CssClass="tables-context-density-tabs" />
|
||||
</div>
|
||||
|
||||
<div class="tables-context-fields">
|
||||
@if (Detail.Groups.Count > 1)
|
||||
@@ -104,6 +113,12 @@
|
||||
new(TablesReferenceMode.Curated, "Curated")
|
||||
];
|
||||
|
||||
private readonly IReadOnlyList<SegmentedTabItem> densityTabs =
|
||||
[
|
||||
new(TablesDensityMode.Comfortable, "Comfortable"),
|
||||
new(TablesDensityMode.Dense, "Dense")
|
||||
];
|
||||
|
||||
[Parameter, EditorRequired]
|
||||
public CriticalTableDetail Detail { get; set; } = default!;
|
||||
|
||||
@@ -122,6 +137,9 @@
|
||||
[Parameter]
|
||||
public string RollJumpValue { get; set; } = string.Empty;
|
||||
|
||||
[Parameter]
|
||||
public string DensityMode { get; set; } = TablesDensityMode.Comfortable;
|
||||
|
||||
[Parameter]
|
||||
public EventCallback OnTogglePin { get; set; }
|
||||
|
||||
@@ -137,6 +155,9 @@
|
||||
[Parameter]
|
||||
public EventCallback<string> OnRollJumpChanged { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<string> OnDensityChanged { get; set; }
|
||||
|
||||
private string GetReadingHint() =>
|
||||
Detail.Groups.Count > 0
|
||||
? "Find the roll band on the left, then read across to the group and severity you need."
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace RolemasterDb.App.Components.Tables;
|
||||
|
||||
public static class TablesDensityMode
|
||||
{
|
||||
public const string Comfortable = "comfortable";
|
||||
public const string Dense = "dense";
|
||||
}
|
||||
Reference in New Issue
Block a user