Enhance tables canvas reading states

This commit is contained in:
2026-03-21 15:08:39 +01:00
parent 7a5568f77c
commit ae582367d6
7 changed files with 327 additions and 18 deletions

View File

@@ -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};";
}