86 lines
8.7 KiB
Plaintext

@model StoryPointSnapshot
@using System.Globalization
@if (Model is null)
{
<p class="text-muted">No scenes are available in this project.</p>
}
else
{
var scene = Model.Scene;
var exactTime = scene.TimeModeName is "Exact DateTime" or "Exact Date and Time";
<article class="story-point" data-scene-id="@scene.SceneID">
<header class="story-point-header">
<p class="eyebrow">@Model.Book.BookDisplayTitle · Chapter @Model.Chapter.ChapterNumber.ToString("0.##") · Scene @scene.SceneNumber.ToString("0.##")</p>
<h2>@scene.SceneTitle</h2>
<p class="story-point-date">
@if (scene.StartDateTime.HasValue)
{ <span>@scene.StartDateTime.Value.ToString("dddd, d MMMM yyyy", CultureInfo.GetCultureInfo("en-GB"))</span>
@if (exactTime) { <span> · @scene.StartDateTime.Value.ToString("h:mm tt", CultureInfo.GetCultureInfo("en-GB"))</span> }
}
else { <span>Story date unknown</span> }
@if (!string.IsNullOrWhiteSpace(scene.RelativeTimeText)) { <span> · @scene.RelativeTimeText</span> }
<small class="text-muted"> · @scene.TimeModeName</small>
</p>
<p>POV: <strong>@(Model.PovName ?? "Not recorded")</strong> · Location: <strong>@(Model.Location?.LocationPath ?? scene.PrimaryLocationName ?? "Not recorded")</strong></p>
<div class="d-flex flex-wrap gap-2">
<a class="btn btn-sm btn-outline-primary" asp-controller="Scenes" asp-action="Edit" asp-route-id="@scene.SceneID">Open Scene</a>
<a class="btn btn-sm btn-outline-secondary" asp-controller="Timeline" asp-action="Index" asp-route-projectId="@Model.ProjectID" asp-route-bookId="@Model.Book.BookID" asp-route-selectedSceneId="@scene.SceneID">Timeline</a>
@if (scene.StartDateTime.HasValue) { <a class="btn btn-sm btn-outline-secondary" asp-controller="StoryCalendar" asp-action="Index" asp-route-projectId="@Model.ProjectID" asp-route-bookId="@Model.Book.BookID" asp-route-date="@scene.StartDateTime.Value.ToString("yyyy-MM-dd")" asp-route-month="@scene.StartDateTime.Value.ToString("yyyy-MM")">Calendar</a> }
</div>
</header>
<div class="story-point-grid">
<section class="story-point-section story-point-wide"><h3>Characters present <small>@Model.Characters.Count</small></h3>
@if (Model.Characters.Count == 0) { <p class="text-muted">No characters attached to this scene.</p> }
else { <div class="table-responsive"><table class="table table-sm align-middle"><thead><tr><th>Character</th><th>Age at this point</th><th>Known location</th><th>Previous appearance</th></tr></thead><tbody>
@foreach (var person in Model.Characters) { <tr><td><a asp-controller="Characters" asp-action="Edit" asp-route-id="@person.Appearance.CharacterID">@person.Appearance.CharacterName</a>
<small class="d-block text-muted">@string.Join(" · ", new[] { person.Appearance.RoleInSceneTypeName, person.Appearance.PresenceTypeName }.Where(x => !string.IsNullOrWhiteSpace(x)).Distinct(StringComparer.OrdinalIgnoreCase))</small></td>
<td>@(person.Age.DisplayText ?? "Unknown") @if (!person.Age.HasExactAge && person.Age.DisplayText is not null) { <small class="d-block text-muted">Approximate</small> }</td>
<td>@(person.State?.CurrentLocation ?? "Unknown")<small class="d-block text-muted">@(person.State?.State == "Inferred" ? "Last known" : "")</small></td>
<td>@if (person.PreviousAppearance is { } previous) { <a asp-controller="Scenes" asp-action="Edit" asp-route-id="@previous.SceneID">@previous.Label</a> } else { <span class="text-muted">First recorded appearance</span> }</td></tr> }
</tbody></table></div> }
</section>
<section class="story-point-section"><h3>Character knowledge</h3>
@if (Model.Characters.All(x => x.Knowledge.Count == 0)) { <p class="text-muted">No structured knowledge recorded by this point.</p> }
@foreach (var person in Model.Characters.Where(x => x.Knowledge.Count > 0)) {
<h4>@person.Appearance.CharacterName</h4><ul class="story-point-facts">
@foreach (var fact in person.Knowledge) { <li><strong>@fact.KnowledgeStateName:</strong> @(string.IsNullOrWhiteSpace(fact.Description) ? fact.AssetName ?? fact.ThreadTitle ?? "Recorded fact" : fact.Description)
<a class="story-point-source" asp-controller="Scenes" asp-action="Edit" asp-route-id="@fact.SceneID">@(Model.Sources.GetValueOrDefault(fact.SceneID)?.Label ?? "Source scene")</a></li> }
</ul>
}
</section>
<section class="story-point-section"><h3>Relationships at this point</h3>
@if (Model.Relationships.Count == 0) { <p class="text-muted">No historically established relationships recorded for these characters.</p> }
<ul class="story-point-facts">@foreach (var relationship in Model.Relationships) {
var source = relationship.History.LastOrDefault(x => x.SceneID.HasValue);
<li><strong>@relationship.CharacterAName ↔ @relationship.CharacterBName</strong><div>@relationship.CurrentStateName</div>
@if (source?.SceneID is int sourceId) { <a class="story-point-source" asp-controller="Scenes" asp-action="Edit" asp-route-id="@sourceId">@(Model.Sources.GetValueOrDefault(sourceId)?.Label ?? "Source scene")</a> }
else { <small class="text-muted">Established at story start</small> }</li>
}</ul></section>
<section class="story-point-section story-point-wide"><h3>Assets / important objects</h3>
@if (Model.Assets.Count == 0) { <p class="text-muted">No relevant assets recorded by this point.</p> }
else { <div class="table-responsive"><table class="table table-sm"><thead><tr><th>Asset</th><th>Holder</th><th>Location</th><th>Status</th><th>Last recorded event</th></tr></thead><tbody>
@foreach (var asset in Model.Assets) { <tr><td><a asp-controller="StoryAssets" asp-action="Edit" asp-route-id="@asset.StoryAssetID">@asset.AssetName</a></td><td>@asset.Holder</td><td>@asset.Location</td><td>@asset.Status</td><td>@asset.LatestEvent
@if (asset.LastConfirmedSceneID is int sourceId) { <a class="story-point-source" asp-controller="Scenes" asp-action="Edit" asp-route-id="@sourceId">@(Model.Sources.GetValueOrDefault(sourceId)?.Label ?? "Source scene")</a> }</td></tr> }
</tbody></table></div> }
</section>
<section class="story-point-section"><h3>Location state</h3>
@if (Model.Location is { } location) { <h4><a asp-controller="Locations" asp-action="Edit" asp-route-id="@location.LocationID">@location.LocationPath</a></h4>
<p><strong>People last known here:</strong> @(location.CharactersPresent.Count == 0 ? "None recorded" : string.Join(", ", location.CharactersPresent))</p>
<p><strong>Assets last known here:</strong> @(location.AssetsPresent.Count == 0 ? "None recorded" : string.Join(", ", location.AssetsPresent))</p>
@if (Model.PreviousLocationUse is { } previous) { <p>Previous scene here: <a asp-controller="Scenes" asp-action="Edit" asp-route-id="@previous.SceneID">@previous.Label</a></p> }
} else { <p class="text-muted">No primary location recorded.</p> }
</section>
<section class="story-point-section"><h3>Active threads / questions / clues</h3>
@if (Model.Threads.Count == 0) { <p class="text-muted">No active threads established by this point.</p> }
<ul class="story-point-facts">@foreach (var thread in Model.Threads) { <li><a asp-controller="PlotThreads" asp-action="Edit" asp-route-id="@thread.PlotThreadID">@thread.Title</a> <small class="text-muted">@thread.Type · @thread.State</small>
@if (thread.Source is { } source) { <a class="story-point-source" asp-controller="Scenes" asp-action="Edit" asp-route-id="@source.SceneID">@source.Label</a> }</li> }</ul>
</section>
<section class="story-point-section story-point-wide"><h3>Things worth checking at this point</h3>
@if (Model.Warnings.Count == 0) { <p class="text-muted">No relevant continuity warnings.</p> }
<ul class="story-point-facts">@foreach (var warning in Model.Warnings) { <li><strong>@warning.Severity:</strong> @warning.Message
@if (warning.SceneID is int sourceId) { <a class="story-point-source" asp-controller="Scenes" asp-action="Edit" asp-route-id="@sourceId">@(Model.Sources.GetValueOrDefault(sourceId)?.Label ?? "Source scene")</a> }</li> }</ul>
</section>
</div>
</article>
}