diff --git a/src/RolemasterDb.App/Components/Pages/Tables.razor b/src/RolemasterDb.App/Components/Pages/Tables.razor index 3797610..c9dae62 100644 --- a/src/RolemasterDb.App/Components/Pages/Tables.razor +++ b/src/RolemasterDb.App/Components/Pages/Tables.razor @@ -121,12 +121,14 @@ @if (TryGetCell(rollBand.Label, group.Key, column.Key, out var groupedCell)) { @@ -148,12 +150,14 @@ @if (TryGetCell(rollBand.Label, null, column.Key, out var cell)) { @@ -457,4 +461,14 @@ await OpenCellEditorAsync(resultId); } } + + private static string GetCellCssClass(CriticalTableCellDetail cell) => + cell.IsCurated + ? "critical-table-cell is-editable is-curated" + : "critical-table-cell is-editable needs-curation"; + + private static string GetCellTitle(CriticalTableCellDetail cell) => + cell.IsCurated + ? "Curated cell. Click to edit this cell." + : "Needs curation. Click to edit this cell."; } diff --git a/src/RolemasterDb.App/Components/Shared/CompactCriticalCell.razor b/src/RolemasterDb.App/Components/Shared/CompactCriticalCell.razor index 65a53c6..1cdc973 100644 --- a/src/RolemasterDb.App/Components/Shared/CompactCriticalCell.razor +++ b/src/RolemasterDb.App/Components/Shared/CompactCriticalCell.razor @@ -2,6 +2,12 @@ @using RolemasterDb.App.Features
+
+ + @(IsCurated ? "Curated" : "Needs Curation") + +
+ @if (!string.IsNullOrWhiteSpace(Description)) {

@Description

@@ -40,6 +46,9 @@ [Parameter, EditorRequired] public string Description { get; set; } = string.Empty; + [Parameter] + public bool IsCurated { get; set; } + [Parameter] public IReadOnlyList? Effects { get; set; } diff --git a/src/RolemasterDb.App/Components/Shared/CriticalCellEditorDialog.razor b/src/RolemasterDb.App/Components/Shared/CriticalCellEditorDialog.razor index c743170..a97f7e1 100644 --- a/src/RolemasterDb.App/Components/Shared/CriticalCellEditorDialog.razor +++ b/src/RolemasterDb.App/Components/Shared/CriticalCellEditorDialog.razor @@ -32,6 +32,15 @@ ยท Variant @Model.GroupLabel }

+
+ + @(Model.IsCurated ? "Curated" : "Needs Curation") + + @if (Model.SourcePageNumber is not null) + { + Source page @Model.SourcePageNumber + } +
} else { @@ -67,6 +76,47 @@

@SaveErrorMessage

} +
+
+
+
+

Curation State

+

Curated cells are protected from importer content overwrites until you unmark them.

+
+
+ +

+ @(Model.IsCurated + ? "This result will keep its current text, branches, and effects on later imports." + : "This result will be refreshed from the importer on later imports.") +

+
+ +
+
+
+

Source Cell

+

Use the importer crop as a visual reference while curating the result.

+
+
+ + @if (!string.IsNullOrWhiteSpace(Model.SourceImageUrl)) + { + @BuildSourceImageAltText(Model) + } + else + { +

No source image is available for this cell yet.

+ } +
+
+
@@ -692,6 +742,23 @@ ? "This is the result that will be saved." : "This is the edited card before the last re-parse."; + private static string BuildSourceImageAltText(CriticalCellEditorModel model) + { + var segments = new List + { + model.TableName, + $"roll band {model.RollBand}", + $"column {model.ColumnLabel}" + }; + + if (!string.IsNullOrWhiteSpace(model.GroupLabel)) + { + segments.Add($"variant {model.GroupLabel}"); + } + + return string.Join(", ", segments); + } + private static IReadOnlyList BuildPreviewEffects(CriticalCellEditorModel model) => model.Effects .Select(CreatePreviewEffect) diff --git a/src/RolemasterDb.App/wwwroot/app.css b/src/RolemasterDb.App/wwwroot/app.css index 2b2e235..d3e85d7 100644 --- a/src/RolemasterDb.App/wwwroot/app.css +++ b/src/RolemasterDb.App/wwwroot/app.css @@ -314,6 +314,37 @@ textarea { min-height: 100%; } +.critical-cell-status-row { + display: flex; + justify-content: flex-end; +} + +.critical-cell-status-chip, +.critical-editor-curation-badge { + display: inline-flex; + align-items: center; + border-radius: 999px; + padding: 0.18rem 0.55rem; + font-size: 0.72rem; + letter-spacing: 0.06em; + text-transform: uppercase; + border: 1px solid transparent; +} + +.critical-cell-status-chip.is-curated, +.critical-editor-curation-badge.is-curated { + background: rgba(102, 138, 83, 0.16); + border-color: rgba(102, 138, 83, 0.34); + color: #45613a; +} + +.critical-cell-status-chip.needs-curation, +.critical-editor-curation-badge.needs-curation { + background: rgba(184, 121, 59, 0.16); + border-color: rgba(184, 121, 59, 0.34); + color: #8a5b21; +} + .critical-cell-footer { margin-top: auto; display: flex; @@ -629,6 +660,18 @@ textarea { outline: none; } +.critical-table-cell.is-curated { + background: + linear-gradient(135deg, rgba(102, 138, 83, 0.16), transparent 34%), + rgba(255, 255, 255, 0.85); +} + +.critical-table-cell.needs-curation { + background: + linear-gradient(135deg, rgba(184, 121, 59, 0.18), transparent 34%), + rgba(255, 255, 255, 0.85); +} + .critical-table td .critical-cell { display: flex; flex-direction: column; @@ -763,6 +806,13 @@ textarea { margin-bottom: 0; } +.critical-editor-status-row { + display: flex; + gap: 0.5rem; + flex-wrap: wrap; + margin-top: 0.55rem; +} + .critical-editor-body { flex: 1 1 auto; min-height: 0; @@ -778,6 +828,34 @@ textarea { gap: 0.85rem; } +.critical-editor-source-grid { + display: grid; + gap: 0.85rem; + grid-template-columns: minmax(240px, 0.8fr) minmax(320px, 1.2fr); +} + +.critical-editor-status-card, +.critical-editor-source-card { + align-content: start; +} + +.critical-editor-curation-toggle { + display: flex; + align-items: center; + gap: 0.6rem; + font-family: var(--font-heading); + color: #5b4327; +} + +.critical-editor-source-image { + width: 100%; + max-height: 340px; + object-fit: contain; + border-radius: 14px; + border: 1px solid rgba(127, 96, 55, 0.14); + background: rgba(255, 255, 255, 0.96); +} + .critical-editor-section h4, .critical-editor-subsection h5 { margin: 0; @@ -1164,7 +1242,8 @@ textarea { } .critical-editor-effect-row-main, - .critical-editor-branch-line { + .critical-editor-branch-line, + .critical-editor-source-grid { grid-template-columns: 1fr; }