From 124d380b0dd710ced8cb2fea301b65a028659e78 Mon Sep 17 00:00:00 2001 From: Nick Beckley Date: Mon, 6 Jul 2026 21:35:15 +0100 Subject: [PATCH] =?UTF-8?q?Phase=2020AD=20=E2=80=93=20Split=20Story=20Inte?= =?UTF-8?q?lligence=20Progress=20and=20Review=20Screens?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PlotLine/Controllers/OnboardingController.cs | 18 +- .../PersistedStoryIntelligenceRunner.cs | 6 +- .../Views/Onboarding/StoryIntelligence.cshtml | 2 +- .../StoryIntelligenceProgress.cshtml | 336 +++++------------- .../Onboarding/StoryIntelligenceReview.cshtml | 216 +++++++++++ PlotLine/wwwroot/css/onboarding.css | 219 ++++++++++++ .../wwwroot/js/story-intelligence-progress.js | 13 +- 7 files changed, 555 insertions(+), 255 deletions(-) create mode 100644 PlotLine/Views/Onboarding/StoryIntelligenceReview.cshtml diff --git a/PlotLine/Controllers/OnboardingController.cs b/PlotLine/Controllers/OnboardingController.cs index 680e223..ba02832 100644 --- a/PlotLine/Controllers/OnboardingController.cs +++ b/PlotLine/Controllers/OnboardingController.cs @@ -84,6 +84,20 @@ public sealed class OnboardingController(IOnboardingService onboarding, IOnboard return model is null ? NotFound() : View(model); } + [HttpGet("story-intelligence/review")] + public async Task StoryIntelligenceReview(Guid batchId) + { + var model = await storyIntelligence.GetProgressAsync(batchId); + if (model is null) + { + return NotFound(); + } + + return model.HasActiveRuns + ? RedirectToAction(nameof(StoryIntelligenceProgress), new { batchId }) + : View(model); + } + [HttpPost("story-intelligence/cancel")] [ValidateAntiForgeryToken] public async Task CancelStoryIntelligence(Guid batchId) @@ -95,7 +109,7 @@ public sealed class OnboardingController(IOnboardingService onboarding, IOnboard } TempData["OnboardingStoryIntelligenceMessage"] = "Analysis cancellation requested."; - return RedirectToAction(nameof(StoryIntelligenceProgress), new { batchId }); + return RedirectToAction(nameof(StoryIntelligenceReview), new { batchId }); } [HttpPost("story-intelligence/commit")] @@ -115,7 +129,7 @@ public sealed class OnboardingController(IOnboardingService onboarding, IOnboard return RedirectToAction("Index", "Writer", new { projectId = progress.ProjectID }); } - return RedirectToAction(nameof(StoryIntelligenceProgress), new { batchId }); + return RedirectToAction(nameof(StoryIntelligenceReview), new { batchId }); } [HttpGet("story-intelligence/complete")] diff --git a/PlotLine/Services/PersistedStoryIntelligenceRunner.cs b/PlotLine/Services/PersistedStoryIntelligenceRunner.cs index 2737bd4..1e59e46 100644 --- a/PlotLine/Services/PersistedStoryIntelligenceRunner.cs +++ b/PlotLine/Services/PersistedStoryIntelligenceRunner.cs @@ -563,19 +563,19 @@ public sealed class PersistedStoryIntelligenceRunner( .Where(name => !string.IsNullOrWhiteSpace(name)) .Distinct(StringComparer.OrdinalIgnoreCase) .Take(3) - .Select(name => $"Possible character detected: {name}")); + .Select(name => $"Possible character found: {name}")); discoveries.AddRange((scene.Locations ?? []) .Select(location => TrimOptional(location.Name, 120)) .Where(name => !string.IsNullOrWhiteSpace(name)) .Distinct(StringComparer.OrdinalIgnoreCase) .Take(3) - .Select(name => $"Possible location detected: {name}")); + .Select(name => $"Possible location found: {name}")); discoveries.AddRange((scene.Assets ?? []) .Select(asset => TrimOptional(asset.Name, 120)) .Where(name => !string.IsNullOrWhiteSpace(name)) .Distinct(StringComparer.OrdinalIgnoreCase) .Take(2) - .Select(name => $"Possible asset detected: {name}")); + .Select(name => $"Possible asset found: {name}")); discoveries.AddRange((scene.Relationships ?? []) .Select(relationship => BuildRelationshipDiscovery(relationship)) .Where(text => !string.IsNullOrWhiteSpace(text)) diff --git a/PlotLine/Views/Onboarding/StoryIntelligence.cshtml b/PlotLine/Views/Onboarding/StoryIntelligence.cshtml index 7495292..611aba8 100644 --- a/PlotLine/Views/Onboarding/StoryIntelligence.cshtml +++ b/PlotLine/Views/Onboarding/StoryIntelligence.cshtml @@ -26,7 +26,7 @@

Analysis has already started

You can continue reviewing progress for the approved chapters.

- Review scenes + Review analysis
diff --git a/PlotLine/Views/Onboarding/StoryIntelligenceProgress.cshtml b/PlotLine/Views/Onboarding/StoryIntelligenceProgress.cshtml index c50c529..1f4397e 100644 --- a/PlotLine/Views/Onboarding/StoryIntelligenceProgress.cshtml +++ b/PlotLine/Views/Onboarding/StoryIntelligenceProgress.cshtml @@ -1,27 +1,22 @@ @model StoryIntelligenceProgressViewModel -@using System.Security.Claims -@inject IConfiguration Configuration @{ - ViewData["Title"] = "Review scenes"; + ViewData["Title"] = "Reading your manuscript"; var runIds = string.Join(",", Model.Chapters.Select(chapter => chapter.RunID)); var progressPercent = ProgressPercent(Model); - var userEmail = User.FindFirstValue(ClaimTypes.Email); - var adminEmails = Configuration.GetSection("Admin:AllowedEmails").Get() ?? []; - var isAdmin = !string.IsNullOrWhiteSpace(userEmail) - && adminEmails.Any(email => string.Equals(email, userEmail, StringComparison.OrdinalIgnoreCase)); + var currentChapter = CurrentChapter(Model); }
-
-
+

@Model.BookTitle

-

Review scenes

-

PlotDirector is reading the approved chapters and preparing scene suggestions for you to review.

+

Reading your manuscript...

+

PlotDirector is analysing your chapters and preparing scenes for review. You can safely leave this page and return later.

@if (TempData["OnboardingStoryIntelligenceError"] is string error) @@ -33,191 +28,95 @@
@message
} -
- @if (Model.Chapters.Any(chapter => chapter.CanCommit || chapter.HasCompletedCommit)) - { - Scenes can be created now. Characters, locations, assets and relationships remain suggestions for later review. - } - else - { - Nothing has been added to your project yet. PlotDirector is preparing suggestions. You will review them before anything is created. - } +
+ Nothing has been added to your project yet. PlotDirector is preparing suggestions. You will review them before anything is created.
-
-
- Import progress - @progressPercent% -
-
- Chapters read - @Model.CompletedChapterCount of @Model.ChapterCount -
-
- Scenes read - @Model.TotalCompletedScenes so far -
-
- Needs review - @(Model.FailedChapterCount + Model.TotalFailedScenes) -
-
-

These are chapters or scenes PlotDirector could not fully analyse. You can review them after the run completes.

- -
-
-
- -
-
-

Latest from your manuscript

-
-
- Current chapter - @(CurrentChapter(Model)?.ChapterTitle ?? "Waiting") -
-
- Current scene - @CurrentScene(Model) -
-
- Current stage - @FriendlyStage(CurrentChapter(Model)?.CurrentStage, CurrentChapter(Model)?.Status) -
-
- Elapsed - @Elapsed(Model) -
-
- Estimated remaining - @EstimateRemaining(Model) -
+
+
+
+

Import progress

+ @progressPercent%
-

@FriendlyMessage(CurrentChapter(Model))

- + @FriendlyStage(currentChapter?.CurrentStage, currentChapter?.Status) +
+
+
+
+
+
+ Chapters read + @Model.CompletedChapterCount of @Model.ChapterCount +
+
+ Scenes read + @Model.TotalCompletedScenes so far +
+
+ Needs review + @(Model.FailedChapterCount + Model.TotalFailedScenes) +
+
+ Elapsed + @Elapsed(Model) +
+
+ Estimated remaining + @EstimateRemaining(Model) +
+
+
+ +
+
+

Current chapter

+

@(currentChapter?.ChapterTitle ?? "Waiting")

+

@FriendlyMessage(currentChapter)

+
+
+

Current scene

+ @CurrentScene(Model) +
+
+ +
+
+

Latest from your manuscript

+ +

Scene summaries will appear here as PlotDirector reads.

+
+
+

Recent discoveries

    - -
    -

    Chapters

    -
    - @foreach (var chapter in Model.Chapters.OrderBy(chapter => chapter.ChapterNumber)) - { -
    - - @chapter.ChapterNumber. @chapter.ChapterTitle - @ChapterStatusLabel(chapter) - -
    -
    - Status - @FriendlyStatus(chapter.Status) -
    -
    - Scenes detected - @((chapter.CompletedScenes ?? 0).ToString("N0")) / @((chapter.TotalDetectedScenes ?? 0).ToString("N0")) -
    -
    - Needs review - @((chapter.FailedScenes ?? 0).ToString("N0")) -
    -
    - -

    @FriendlyMessage(chapter)

    - @if ((chapter.FailedScenes ?? 0) > 0) - { -

    Needs review after analysis completes.

    - } - else - { - - } - @if (!string.IsNullOrWhiteSpace(chapter.ErrorMessage)) - { -

    @chapter.ErrorMessage

    - } - else - { - - } - @if (chapter.Warnings.Any()) - { -
      - @foreach (var warning in chapter.Warnings) - { -
    • @warning
    • - } -
    - } - @if (chapter.Blockers.Any()) - { -
      - @foreach (var blocker in chapter.Blockers) - { -
    • @blocker
    • - } -
    - } - -
    - @if (chapter.HasCompletedCommit) - { - @chapter.ScenesCreated scene(s) created - } - else if (chapter.CanCommit && Model.BatchID.HasValue) - { -
    - - - -
    - } - else if (chapter.IsRunComplete) - { - Review needed - } -
    - @if (isAdmin) - { -
    - Diagnostics -
    -
    Run ID
    -
    @chapter.RunID
    -
    Raw status
    -
    @chapter.Status
    -
    Raw stage
    -
    @(chapter.CurrentStage ?? "-")
    -
    Tokens
    -
    @(chapter.TotalTokens?.ToString("N0") ?? "-")
    - @if (!string.IsNullOrWhiteSpace(chapter.FailureStage)) - { -
    Failure stage
    -
    @chapter.FailureStage
    - } -
    -
    - } -
    - } -
    -
    + +
    @if (Model.BatchID.HasValue) { -
    - -
    - Continue + aria-disabled="@Model.HasActiveRuns">Review analysis }
    @@ -228,39 +127,14 @@ } @functions { - private static string ChapterStatusLabel(StoryIntelligenceOnboardingChapterViewModel chapter) - { - if (chapter.HasCompletedCommit) - { - return "Scenes created"; - } - - if (chapter.CanCommit) - { - return "Ready to create"; - } - - if (chapter.IsActive) - { - return "Analysing"; - } - - if (chapter.IsFailed) - { - return "Needs attention"; - } - - return "Reviewing"; - } - private static string FriendlyStatus(string? status) => status switch { StoryIntelligenceRunStatuses.Pending => "Waiting", StoryIntelligenceRunStatuses.Running => "Reading", - StoryIntelligenceRunStatuses.Completed => "Ready to review", - StoryIntelligenceRunStatuses.CompletedWithWarnings => "Ready to review, with notes", - StoryIntelligenceRunStatuses.Failed => "Needs attention", + StoryIntelligenceRunStatuses.Completed => "Ready to create", + StoryIntelligenceRunStatuses.CompletedWithWarnings => "Ready with notes", + StoryIntelligenceRunStatuses.Failed => "Needs review", StoryIntelligenceRunStatuses.Cancelled => "Cancelled", _ => "Waiting" }; @@ -274,7 +148,7 @@ if (status is StoryIntelligenceRunStatuses.Failed) { - return "Needs attention"; + return "Needs review"; } if (status is StoryIntelligenceRunStatuses.Cancelled) @@ -285,13 +159,11 @@ return stage switch { "Queued" => "Waiting", - StoryIntelligenceFailureStages.DocumentRead => "Preparing chapter", StoryIntelligenceFailureStages.ChapterStructure => "Finding scenes", - StoryIntelligenceFailureStages.SceneSplit => "Preparing scenes", StoryIntelligenceFailureStages.SceneIntelligence => "Reading scenes", - StoryIntelligenceFailureStages.Validation => "Checking results", - StoryIntelligenceFailureStages.Persistence => "Saving analysis", - StoryIntelligenceRunStatuses.Completed => "Ready to review", + StoryIntelligenceFailureStages.SceneSplit => "Preparing review", + StoryIntelligenceFailureStages.Validation => "Preparing review", + StoryIntelligenceFailureStages.Persistence => "Preparing review", _ => "Reading" }; } @@ -310,13 +182,12 @@ if (chapter.Status == StoryIntelligenceRunStatuses.Failed) { - return "This chapter needs attention before scenes can be created."; + return "This chapter needs review before scenes can be created."; } return chapter.CurrentStage switch { "Queued" => "Waiting to read this chapter.", - StoryIntelligenceFailureStages.DocumentRead => "Preparing this chapter.", StoryIntelligenceFailureStages.ChapterStructure => "Finding scenes in this chapter.", StoryIntelligenceFailureStages.SceneSplit => "Preparing the detected scenes.", StoryIntelligenceFailureStages.SceneIntelligence => "Reading the detected scenes.", @@ -345,12 +216,7 @@ private static decimal ChapterProgress(StoryIntelligenceOnboardingChapterViewModel chapter) { - if (chapter.HasCompletedCommit || chapter.IsRunComplete) - { - return 1m; - } - - if (chapter.IsFailed) + if (chapter.HasCompletedCommit || chapter.IsRunComplete || chapter.IsFailed) { return 1m; } @@ -379,29 +245,7 @@ } private static string EstimateRemaining(StoryIntelligenceProgressViewModel model) - { - if (!model.HasActiveRuns) - { - return "Almost done"; - } - - if (model.TotalCompletedScenes <= 0) - { - return "Estimating..."; - } - - var remainingScenes = Math.Max(0, model.TotalDetectedScenes - model.TotalCompletedScenes); - if (remainingScenes == 0) - { - return "Almost done"; - } - - var elapsedMs = model.Chapters.Max(chapter => chapter.TotalDurationMs ?? 0); - var averageSceneMinutes = Math.Max(1, (int)Math.Ceiling(TimeSpan.FromMilliseconds(elapsedMs).TotalMinutes / Math.Max(1, model.TotalCompletedScenes))); - var low = Math.Max(1, averageSceneMinutes * remainingScenes); - var high = Math.Max(low + 1, low * 2); - return $"About {low:N0}-{high:N0} minutes"; - } + => model.HasActiveRuns && model.TotalCompletedScenes > 0 ? "Estimating..." : model.HasActiveRuns ? "Estimating..." : "Ready to review"; private static string CurrentScene(StoryIntelligenceProgressViewModel model) { diff --git a/PlotLine/Views/Onboarding/StoryIntelligenceReview.cshtml b/PlotLine/Views/Onboarding/StoryIntelligenceReview.cshtml new file mode 100644 index 0000000..4a85c4d --- /dev/null +++ b/PlotLine/Views/Onboarding/StoryIntelligenceReview.cshtml @@ -0,0 +1,216 @@ +@model StoryIntelligenceProgressViewModel +@using System.Security.Claims +@inject IConfiguration Configuration +@{ + ViewData["Title"] = "Review analysis"; + var adminEmails = Configuration.GetSection("Admin:AllowedEmails").Get() ?? []; + var userEmail = User.FindFirstValue(ClaimTypes.Email); + var isAdmin = !string.IsNullOrWhiteSpace(userEmail) + && adminEmails.Any(email => string.Equals(email, userEmail, StringComparison.OrdinalIgnoreCase)); + var chaptersNeedingReview = Model.Chapters.Count(NeedsReview); + var readyToCreate = Model.Chapters.Count(chapter => chapter.CanCommit); +} + +
    +
    +
    +

    @Model.BookTitle

    +

    Review analysis

    +

    PlotDirector has finished reading your manuscript. Review the chapter results, then create scenes when you are ready.

    +
    + + @if (TempData["OnboardingStoryIntelligenceError"] is string error) + { +
    @error
    + } + @if (TempData["OnboardingStoryIntelligenceMessage"] is string message) + { +
    @message
    + } + +
    + Nothing is added to your project until you choose Create scenes. This step only creates scenes, summaries and supported scene notes. +
    + +
    +
    + Chapters analysed + @Model.CompletedChapterCount of @Model.ChapterCount +
    +
    + Scenes found + @Model.TotalDetectedScenes.ToString("N0") +
    +
    + Ready to create + @readyToCreate.ToString("N0") +
    +
    + Needs review + @chaptersNeedingReview.ToString("N0") +
    +
    + +
    + @foreach (var chapter in Model.Chapters.OrderBy(chapter => chapter.ChapterNumber)) + { +
    +
    +
    +

    Chapter @chapter.ChapterNumber

    +

    @chapter.ChapterTitle

    +
    + @FriendlyStatus(chapter) +
    + +
    +
    + Scenes found + @((chapter.TotalDetectedScenes ?? 0).ToString("N0")) +
    +
    + Scenes ready + @((chapter.CompletedScenes ?? 0).ToString("N0")) +
    +
    + Needs review + @(((chapter.FailedScenes ?? 0) + chapter.Blockers.Count).ToString("N0")) +
    +
    + + @if (!string.IsNullOrWhiteSpace(chapter.CommitMessage)) + { +

    @chapter.CommitMessage

    + } + + @if (chapter.Warnings.Count > 0) + { +
    + Notes +
      + @foreach (var warning in chapter.Warnings) + { +
    • @warning
    • + } +
    +
    + } + + @if (chapter.Blockers.Count > 0) + { +
    + Before scenes can be created +
      + @foreach (var blocker in chapter.Blockers) + { +
    • @blocker
    • + } +
    +
    + } + + @if (!string.IsNullOrWhiteSpace(chapter.ErrorMessage)) + { +

    @chapter.ErrorMessage

    + } + +
    + @if (chapter.HasCompletedCommit) + { + + } + else if (chapter.CanCommit && Model.BatchID.HasValue) + { +
    + + + +
    + } + else if (chapter.IsActive && Model.BatchID.HasValue) + { + View progress + } + else + { + + } +
    + + @if (isAdmin) + { +
    + Admin diagnostics +
    +
    Run ID
    @chapter.RunID
    +
    Status
    @chapter.Status
    +
    Stage
    @(chapter.CurrentStage ?? "-")
    +
    Failure stage
    @(chapter.FailureStage ?? "-")
    +
    Tokens
    @(chapter.TotalTokens?.ToString("N0") ?? "-")
    +
    +
    + } +
    + } +
    + +
    + @if (Model.BatchID.HasValue) + { + View progress + } +
    + +
    +
    +
    +
    + +@functions { + private static bool NeedsReview(StoryIntelligenceOnboardingChapterViewModel chapter) + => chapter.IsFailed + || (chapter.FailedScenes ?? 0) > 0 + || chapter.Blockers.Count > 0 + || (!chapter.CanCommit && !chapter.HasCompletedCommit && chapter.IsRunComplete); + + private static string FriendlyStatus(StoryIntelligenceOnboardingChapterViewModel chapter) + { + if (chapter.HasCompletedCommit) + { + return "Scenes created"; + } + + if (chapter.CanCommit) + { + return chapter.Warnings.Count > 0 ? "Ready with notes" : "Ready to create"; + } + + return chapter.Status switch + { + StoryIntelligenceRunStatuses.Pending => "Waiting", + StoryIntelligenceRunStatuses.Running => "Reading", + StoryIntelligenceRunStatuses.Completed => "Needs attention", + StoryIntelligenceRunStatuses.CompletedWithWarnings => "Needs attention", + StoryIntelligenceRunStatuses.Failed => "Needs review", + StoryIntelligenceRunStatuses.Cancelled => "Cancelled", + _ => "Needs attention" + }; + } + + private static string StatusClass(StoryIntelligenceOnboardingChapterViewModel chapter) + { + if (chapter.HasCompletedCommit) + { + return "story-review-status story-review-status--created"; + } + + if (chapter.CanCommit) + { + return "story-review-status story-review-status--ready"; + } + + return chapter.IsActive + ? "story-review-status story-review-status--active" + : "story-review-status story-review-status--warning"; + } +} diff --git a/PlotLine/wwwroot/css/onboarding.css b/PlotLine/wwwroot/css/onboarding.css index 68c751b..a88e86d 100644 --- a/PlotLine/wwwroot/css/onboarding.css +++ b/PlotLine/wwwroot/css/onboarding.css @@ -596,6 +596,211 @@ color: #1f2a44; } +.story-live-progress { + max-width: 980px; +} + +.story-live-hero h1 { + font-size: clamp(2.4rem, 5vw, 4rem); +} + +.story-live-progress-card, +.story-live-current, +.story-live-feed-grid, +.story-review-summary, +.story-review-chapter-card { + border: 1px solid rgba(31, 42, 68, .12); + border-radius: 8px; + background: rgba(255, 255, 255, .62); +} + +.story-live-progress-card { + display: grid; + gap: 1rem; + padding: 1.2rem; +} + +.story-live-progress-heading, +.story-review-chapter-heading { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 1rem; +} + +.story-live-progress-heading strong { + display: block; + font-size: clamp(2rem, 5vw, 3.5rem); + line-height: 1; +} + +.story-live-progress-heading > span, +.story-review-status { + display: inline-flex; + align-items: center; + min-height: 2rem; + border-radius: 999px; + padding: .25rem .7rem; + background: rgba(47, 111, 99, .12); + color: #2f6f63; + font-weight: 800; + white-space: nowrap; +} + +.story-live-stats, +.story-review-summary, +.story-review-scene-panel { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: .75rem; +} + +.story-live-stats div, +.story-review-summary div, +.story-review-scene-panel div { + min-width: 0; + border: 1px solid rgba(31, 42, 68, .1); + border-radius: 8px; + padding: .8rem; + background: rgba(255, 255, 255, .58); +} + +.story-live-stats span, +.story-review-summary span, +.story-review-scene-panel span { + display: block; + color: var(--bs-secondary-color); + font-size: .78rem; + font-weight: 800; + text-transform: uppercase; +} + +.story-live-stats strong, +.story-review-summary strong, +.story-review-scene-panel strong { + display: block; + margin-top: .15rem; + font-size: 1.12rem; +} + +.story-live-current, +.story-live-feed-grid { + display: grid; + grid-template-columns: minmax(0, 1.2fr) minmax(280px, .8fr); + gap: 1rem; + margin-top: 1rem; + padding: 1rem; +} + +.story-live-current h2, +.story-live-feed-grid h2, +.story-review-chapter-card h2 { + margin: 0; + font-size: 1.25rem; +} + +.story-live-feed-grid { + align-items: start; +} + +.story-review-page { + display: grid; + gap: 1rem; +} + +.story-review-summary { + padding: 1rem; +} + +.story-review-chapter-list { + display: grid; + gap: .9rem; +} + +.story-review-chapter-card { + display: grid; + gap: .9rem; + padding: 1rem; +} + +.story-review-status--created { + background: rgba(47, 111, 99, .16); +} + +.story-review-status--ready { + background: rgba(47, 111, 99, .12); +} + +.story-review-status--active { + background: rgba(182, 138, 70, .14); + color: #755624; +} + +.story-review-status--warning { + background: rgba(176, 58, 46, .12); + color: #8a2f25; +} + +.story-review-note { + margin: 0; + border-left: 4px solid rgba(47, 111, 99, .45); + border-radius: 8px; + padding: .8rem 1rem; + background: rgba(47, 111, 99, .07); + color: var(--bs-secondary-color); +} + +.story-review-note ul { + margin: .35rem 0 0; + padding-left: 1.1rem; +} + +.story-review-note--warning { + border-left-color: rgba(176, 58, 46, .5); + background: rgba(176, 58, 46, .07); +} + +.story-review-card-actions { + display: flex; + justify-content: flex-end; + gap: .65rem; +} + +.story-review-admin { + border-top: 1px solid rgba(31, 42, 68, .1); + padding-top: .75rem; +} + +.story-review-admin summary { + cursor: pointer; + color: var(--bs-secondary-color); + font-weight: 700; +} + +.story-review-admin dl { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: .6rem; + margin: .75rem 0 0; +} + +.story-review-admin div { + min-width: 0; + border: 1px solid rgba(31, 42, 68, .1); + border-radius: 8px; + padding: .65rem; +} + +.story-review-admin dt { + color: var(--bs-secondary-color); + font-weight: 700; +} + +.story-review-admin dd { + margin: .15rem 0 0; + overflow-wrap: anywhere; +} + [data-story-discovery-feed] { display: grid; gap: .45rem; @@ -921,6 +1126,20 @@ position: static; } + .story-live-stats, + .story-review-summary, + .story-review-scene-panel, + .story-live-current, + .story-live-feed-grid, + .story-review-admin dl { + grid-template-columns: 1fr; + } + + .story-live-progress-heading, + .story-review-chapter-heading { + flex-direction: column; + } + .onboarding-build-panel, .onboarding-success-heading { grid-template-columns: 1fr; diff --git a/PlotLine/wwwroot/js/story-intelligence-progress.js b/PlotLine/wwwroot/js/story-intelligence-progress.js index c25a368..383d918 100644 --- a/PlotLine/wwwroot/js/story-intelligence-progress.js +++ b/PlotLine/wwwroot/js/story-intelligence-progress.js @@ -88,9 +88,12 @@ }; const possibleDiscoveryText = (text) => String(text || "") - .replace(/^Character detected:/i, "Possible character detected:") - .replace(/^Location detected:/i, "Possible location detected:") - .replace(/^Asset detected:/i, "Possible asset detected:") + .replace(/^Character detected:/i, "Possible character found:") + .replace(/^Possible character detected:/i, "Possible character found:") + .replace(/^Location detected:/i, "Possible location found:") + .replace(/^Possible location detected:/i, "Possible location found:") + .replace(/^Asset detected:/i, "Possible asset found:") + .replace(/^Possible asset detected:/i, "Possible asset found:") .replace(/^Timeline clue detected:/i, "Timeline clue found:") .replace(/^Relationship detected:/i, "Relationship signal found:"); @@ -363,6 +366,10 @@ if (summaryNode && latestSummary) { summaryNode.textContent = latestSummary; summaryNode.hidden = false; + const emptyNode = root.querySelector("[data-story-latest-empty]"); + if (emptyNode) { + emptyNode.hidden = true; + } } const feed = root.querySelector("[data-story-discovery-feed]");