Add review candidate panel headers

This commit is contained in:
Nick Beckley 2026-09-02 19:53:50 +00:00
parent 64225dde1a
commit 6263cf6b00
8 changed files with 56 additions and 20 deletions

View File

@ -941,12 +941,23 @@ static void StoryIntelligenceReviewModulePagesOmitWizardChrome()
Assert(view.Contains("<p class=\"eyebrow\">Story Intelligence</p>", StringComparison.Ordinal), $"{viewName} should use a simple module header eyebrow."); Assert(view.Contains("<p class=\"eyebrow\">Story Intelligence</p>", StringComparison.Ordinal), $"{viewName} should use a simple module header eyebrow.");
Assert(view.Contains("StoryIntelligenceReviewCentre", StringComparison.Ordinal), $"{viewName} should return to Review Centre."); Assert(view.Contains("StoryIntelligenceReviewCentre", StringComparison.Ordinal), $"{viewName} should return to Review Centre.");
Assert(view.Contains($">{title}</h1>", StringComparison.Ordinal), $"{viewName} should keep its focused module title."); Assert(view.Contains($">{title}</h1>", StringComparison.Ordinal), $"{viewName} should keep its focused module title.");
Assert(view.Contains("summary class=\"story-review-card-header\"", StringComparison.Ordinal), $"{viewName} should give each candidate panel a clear shared header.");
Assert(!view.Contains("StoryIntelligenceComplete", StringComparison.Ordinal), $"{viewName} should not route to the old final wizard step."); Assert(!view.Contains("StoryIntelligenceComplete", StringComparison.Ordinal), $"{viewName} should not route to the old final wizard step.");
foreach (var marker in forbidden) foreach (var marker in forbidden)
{ {
Assert(!view.Contains(marker, StringComparison.OrdinalIgnoreCase), $"{viewName} should not render obsolete wizard chrome: {marker}."); Assert(!view.Contains(marker, StringComparison.OrdinalIgnoreCase), $"{viewName} should not render obsolete wizard chrome: {marker}.");
} }
} }
var stylesheet = File.ReadAllText(Path.Combine(root, "wwwroot/css/onboarding.css"));
Assert(stylesheet.Contains(".story-review-card-header", StringComparison.Ordinal), "Shared review candidate header CSS should be present.");
Assert(stylesheet.Contains("justify-content: space-between;", StringComparison.Ordinal), "Review candidate headers should align title and status consistently.");
Assert(stylesheet.Contains("border-bottom: 1px solid rgba(31, 42, 68, .1);", StringComparison.Ordinal), "Review candidate headers should be visually separated from card bodies.");
var knowledgeView = File.ReadAllText(Path.Combine(root, "Views/Onboarding/StoryIntelligenceKnowledge.cshtml"));
var relationshipsView = File.ReadAllText(Path.Combine(root, "Views/Onboarding/StoryIntelligenceRelationships.cshtml"));
Assert(knowledgeView.Contains("<strong>@candidate.KnowledgeStatement</strong>", StringComparison.Ordinal), "Knowledge review headers should foreground the knowledge item.");
Assert(relationshipsView.Contains("<strong>@candidate.CharacterAName / @candidate.CharacterBName</strong>", StringComparison.Ordinal), "Relationship review headers should foreground both participants.");
} }
static void StoryIntelligenceDownstreamReviewUsesCompletedSceneAnalysis() static void StoryIntelligenceDownstreamReviewUsesCompletedSceneAnalysis()

View File

@ -55,7 +55,7 @@
{ {
var candidate = assetCandidates[i]; var candidate = assetCandidates[i];
<details class="story-character-card" open data-asset-card data-asset-existing-match="@candidate.IsExistingMatch.ToString().ToLowerInvariant()"> <details class="story-character-card" open data-asset-card data-asset-existing-match="@candidate.IsExistingMatch.ToString().ToLowerInvariant()">
<summary> <summary class="story-review-card-header">
<span> <span>
<strong>@candidate.AssetName</strong> <strong>@candidate.AssetName</strong>
<small>@candidate.Category · @candidate.AppearsInScenes.ToString("N0") scene@(candidate.AppearsInScenes == 1 ? string.Empty : "s")</small> <small>@candidate.Category · @candidate.AppearsInScenes.ToString("N0") scene@(candidate.AppearsInScenes == 1 ? string.Empty : "s")</small>

View File

@ -77,7 +77,7 @@
{ {
var candidate = characterCandidates[i]; var candidate = characterCandidates[i];
<details class="story-character-card" open data-character-card> <details class="story-character-card" open data-character-card>
<summary> <summary class="story-review-card-header">
<span> <span>
<strong>@candidate.CharacterName</strong> <strong>@candidate.CharacterName</strong>
<small>@candidate.Classification &middot; @candidate.AppearsInScenes.ToString("N0") scene@(candidate.AppearsInScenes == 1 ? string.Empty : "s")</small> <small>@candidate.Classification &middot; @candidate.AppearsInScenes.ToString("N0") scene@(candidate.AppearsInScenes == 1 ? string.Empty : "s")</small>

View File

@ -59,10 +59,10 @@
{ {
var candidate = knowledgeCandidates[i]; var candidate = knowledgeCandidates[i];
<details class="story-character-card" open data-knowledge-card> <details class="story-character-card" open data-knowledge-card>
<summary> <summary class="story-review-card-header">
<span> <span>
<strong>@candidate.CharacterName</strong> <strong>@candidate.KnowledgeStatement</strong>
<small>@candidate.KnowledgeStateName - @candidate.KnowledgeStatement</small> <small>@candidate.CharacterName - @candidate.KnowledgeStateName</small>
</span> </span>
<em>@candidate.Confidence</em> <em>@candidate.Confidence</em>
</summary> </summary>

View File

@ -60,7 +60,7 @@
: string.Empty; : string.Empty;
var searchText = string.Join(" ", new[] { candidate.LocationName, candidate.ExistingLocationName, candidate.Category, candidate.ParentLocationHint, candidate.ProposedParentLocationName }); var searchText = string.Join(" ", new[] { candidate.LocationName, candidate.ExistingLocationName, candidate.Category, candidate.ParentLocationHint, candidate.ProposedParentLocationName });
<details class="story-character-card" open data-location-card data-location-status="@status" data-location-existing-match="@candidate.IsExistingMatch.ToString().ToLowerInvariant()" data-location-search-text="@searchText"> <details class="story-character-card" open data-location-card data-location-status="@status" data-location-existing-match="@candidate.IsExistingMatch.ToString().ToLowerInvariant()" data-location-search-text="@searchText">
<summary> <summary class="story-review-card-header">
<span> <span>
<strong>@candidate.LocationName</strong> <strong>@candidate.LocationName</strong>
<small>@candidate.Category · @candidate.AppearsInScenes.ToString("N0") scene@(candidate.AppearsInScenes == 1 ? string.Empty : "s")</small> <small>@candidate.Category · @candidate.AppearsInScenes.ToString("N0") scene@(candidate.AppearsInScenes == 1 ? string.Empty : "s")</small>

View File

@ -55,7 +55,7 @@
{ {
var candidate = narrativeCandidates[i]; var candidate = narrativeCandidates[i];
<details class="story-character-card" open> <details class="story-character-card" open>
<summary> <summary class="story-review-card-header">
<span> <span>
<strong>@candidate.ProposedTitle</strong> <strong>@candidate.ProposedTitle</strong>
<small>@candidate.CandidateType @(!string.IsNullOrWhiteSpace(candidate.Category) ? $"- {candidate.Category}" : string.Empty)</small> <small>@candidate.CandidateType @(!string.IsNullOrWhiteSpace(candidate.Category) ? $"- {candidate.Category}" : string.Empty)</small>

View File

@ -59,10 +59,10 @@
{ {
var candidate = relationshipCandidates[i]; var candidate = relationshipCandidates[i];
<details class="story-character-card" open data-relationship-card> <details class="story-character-card" open data-relationship-card>
<summary> <summary class="story-review-card-header">
<span> <span>
<strong>@candidate.CharacterAName</strong> <strong>@candidate.CharacterAName / @candidate.CharacterBName</strong>
<small>@candidate.RelationshipType / @candidate.CharacterBName - @candidate.AppearsInScenes.ToString("N0") scene@(candidate.AppearsInScenes == 1 ? string.Empty : "s")</small> <small>@candidate.RelationshipType - @candidate.AppearsInScenes.ToString("N0") scene@(candidate.AppearsInScenes == 1 ? string.Empty : "s")</small>
</span> </span>
<em>@candidate.Confidence</em> <em>@candidate.Confidence</em>
</summary> </summary>

View File

@ -1469,35 +1469,52 @@ summary.story-review-chapter-heading {
border: 1px solid rgba(31, 42, 68, .1); border: 1px solid rgba(31, 42, 68, .1);
border-radius: 8px; border-radius: 8px;
background: rgba(255, 255, 255, .64); background: rgba(255, 255, 255, .64);
padding: .8rem; overflow: hidden;
} }
.story-character-card summary { .story-review-card-header {
display: grid;
grid-template-columns: auto minmax(0, 1fr) auto;
gap: .65rem;
align-items: center; align-items: center;
background: rgba(47, 111, 99, .07);
border-bottom: 1px solid rgba(31, 42, 68, .1);
cursor: pointer; cursor: pointer;
display: flex;
flex-wrap: wrap;
gap: .55rem 1rem;
justify-content: space-between;
padding: .75rem .85rem;
} }
.story-character-card summary span { .story-review-card-header span {
display: grid; display: grid;
gap: .1rem; gap: .12rem;
min-width: 0; min-width: 0;
} }
.story-character-card summary small, .story-review-card-header strong {
.story-character-card summary em { color: var(--bs-body-color);
font-size: 1rem;
line-height: 1.25;
overflow-wrap: anywhere;
}
.story-review-card-header small,
.story-review-card-header em {
color: var(--bs-secondary-color); color: var(--bs-secondary-color);
font-size: .82rem; font-size: .82rem;
font-style: normal; font-style: normal;
font-weight: 700; font-weight: 700;
} }
.story-review-card-header em {
color: var(--plotdirector-green, #2f6f63);
flex: 0 0 auto;
text-align: right;
}
.story-character-card__body { .story-character-card__body {
display: grid; display: grid;
gap: .75rem; gap: .75rem;
padding-top: .85rem; padding: .85rem;
} }
.story-character-card__body dl { .story-character-card__body dl {
@ -2324,6 +2341,14 @@ summary.story-review-chapter-heading {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
.story-review-card-header {
align-items: flex-start;
}
.story-review-card-header em {
text-align: left;
}
.story-review-centre-grid { .story-review-centre-grid {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }