From 7f9f051341cb26985a41cc88835e35d973ead14b Mon Sep 17 00:00:00 2001 From: Nick Beckley Date: Thu, 9 Jul 2026 21:45:15 +0100 Subject: [PATCH] =?UTF-8?q?Phase=2020AR=20=E2=80=93=20Story=20Intelligence?= =?UTF-8?q?=20Wizard=20Polish?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Onboarding/StoryIntelligenceAssets.cshtml | 6 +- .../StoryIntelligenceCharacters.cshtml | 6 +- .../StoryIntelligenceComplete.cshtml | 30 ++- .../StoryIntelligenceLocations.cshtml | 6 +- .../Onboarding/StoryIntelligenceReview.cshtml | 6 +- .../_StoryIntelligencePipelineHeader.cshtml | 160 +++++++++++---- PlotLine/wwwroot/css/onboarding.css | 194 ++++++++++++++++++ 7 files changed, 348 insertions(+), 60 deletions(-) diff --git a/PlotLine/Views/Onboarding/StoryIntelligenceAssets.cshtml b/PlotLine/Views/Onboarding/StoryIntelligenceAssets.cshtml index 9071603..70fb4a3 100644 --- a/PlotLine/Views/Onboarding/StoryIntelligenceAssets.cshtml +++ b/PlotLine/Views/Onboarding/StoryIntelligenceAssets.cshtml @@ -6,8 +6,10 @@
-
-

Review Story Intelligence

+
+

Phase 3

+

Review Story Intelligence

+

Stage 4 of 4

Review Assets

Approve the important objects PlotDirector should create or link from your imported scenes. Nothing is created unless you approve it.

diff --git a/PlotLine/Views/Onboarding/StoryIntelligenceCharacters.cshtml b/PlotLine/Views/Onboarding/StoryIntelligenceCharacters.cshtml index 1d46d78..b453404 100644 --- a/PlotLine/Views/Onboarding/StoryIntelligenceCharacters.cshtml +++ b/PlotLine/Views/Onboarding/StoryIntelligenceCharacters.cshtml @@ -6,8 +6,10 @@
-
-

Review Story Intelligence

+
+

Phase 3

+

Review Story Intelligence

+

Stage 2 of 4

Review Characters

Approve the characters PlotDirector should create or link from your imported scenes. You stay in control of every character record.

diff --git a/PlotLine/Views/Onboarding/StoryIntelligenceComplete.cshtml b/PlotLine/Views/Onboarding/StoryIntelligenceComplete.cshtml index 06f7491..e60f84e 100644 --- a/PlotLine/Views/Onboarding/StoryIntelligenceComplete.cshtml +++ b/PlotLine/Views/Onboarding/StoryIntelligenceComplete.cshtml @@ -6,15 +6,32 @@
-
-

Story Intelligence pipeline

+
+

Phase 4

+

Build Story Database

Story Intelligence complete

-

PlotDirector completed every implemented Story Intelligence stage for this manuscript. Future stages will continue from this same pipeline as they become available.

+

PlotDirector has built the implemented story database records from your reviewed manuscript analysis.

+
+

Building your Story Database...

+
    +
  • Chapters
  • +
  • Scenes
  • +
  • Characters
  • +
  • Locations
  • +
  • Assets
  • +
  • RelationshipsComing Soon
  • +
  • KnowledgeComing Soon
  • +
  • Preparing continuity...
  • +
  • Generating story indexes...
  • +
  • Finalising project...
  • +
+
+
Chapters analysed @@ -42,13 +59,6 @@
-
-
Review RelationshipsComing Soon
-
Review KnowledgeComing Soon
-
Review ContinuityComing Soon
-
Timeline EventsComing Soon
-
-
View scenes View book diff --git a/PlotLine/Views/Onboarding/StoryIntelligenceLocations.cshtml b/PlotLine/Views/Onboarding/StoryIntelligenceLocations.cshtml index 7707ea0..bb5d19e 100644 --- a/PlotLine/Views/Onboarding/StoryIntelligenceLocations.cshtml +++ b/PlotLine/Views/Onboarding/StoryIntelligenceLocations.cshtml @@ -6,8 +6,10 @@
-
-

Review Story Intelligence

+
+

Phase 3

+

Review Story Intelligence

+

Stage 3 of 4

Review Locations

Approve the places PlotDirector should create or link from your imported scenes. Nothing is created unless you approve it.

diff --git a/PlotLine/Views/Onboarding/StoryIntelligenceReview.cshtml b/PlotLine/Views/Onboarding/StoryIntelligenceReview.cshtml index 11ddb96..3df8ccd 100644 --- a/PlotLine/Views/Onboarding/StoryIntelligenceReview.cshtml +++ b/PlotLine/Views/Onboarding/StoryIntelligenceReview.cshtml @@ -14,8 +14,10 @@
-
-

Review Story Intelligence

+
+

Phase 3

+

Review Story Intelligence

+

Stage 1 of 4

Review Scenes

PlotDirector has finished reading your manuscript. Review the detected scenes before creating them in your story database.

diff --git a/PlotLine/Views/Onboarding/_StoryIntelligencePipelineHeader.cshtml b/PlotLine/Views/Onboarding/_StoryIntelligencePipelineHeader.cshtml index aa852f9..54d1e23 100644 --- a/PlotLine/Views/Onboarding/_StoryIntelligencePipelineHeader.cshtml +++ b/PlotLine/Views/Onboarding/_StoryIntelligencePipelineHeader.cshtml @@ -1,54 +1,130 @@ @model StoryIntelligencePipelineHeaderViewModel @{ - var phases = new[] + var reviewStages = new[] { - new { Name = "Phase 1", Label = "Prepare manuscript", Stages = new[] { "Welcome", "Writing Preferences", "Project", "Book", "Connect Word", "Scan Manuscript", "Review Chapters" } }, - new { Name = "Phase 2", Label = "Analyse manuscript", Stages = new[] { "Analyse Manuscript" } }, - new { Name = "Phase 3", Label = "Review Story Intelligence", Stages = new[] { "Review Scenes", "Review Characters", "Review Locations", "Review Assets" } }, - new { Name = "Phase 4", Label = "Build Story Database", Stages = new[] { "Complete" } } + new PipelineStage("Review Scenes", "Scenes", true), + new PipelineStage("Review Characters", "Characters", true), + new PipelineStage("Review Locations", "Locations", true), + new PipelineStage("Review Assets", "Assets", true), + new PipelineStage("Review Relationships", "Relationships", false), + new PipelineStage("Review Knowledge", "Knowledge", false) }; - var flatStages = phases.SelectMany(phase => phase.Stages).ToList(); - var currentIndex = Math.Max(0, flatStages.FindIndex(stage => string.Equals(stage, Model.CurrentStage, StringComparison.OrdinalIgnoreCase))); - var implementedReviewStages = new[] { "Review Scenes", "Review Characters", "Review Locations", "Review Assets", "Complete" }; - var reviewIndex = Array.FindIndex(implementedReviewStages, stage => string.Equals(stage, Model.CurrentStage, StringComparison.OrdinalIgnoreCase)); - var percent = reviewIndex >= 0 - ? Math.Clamp((reviewIndex * 100) / (implementedReviewStages.Length - 1), 0, 100) - : flatStages.Count <= 1 ? 100 : Math.Clamp((currentIndex * 100) / (flatStages.Count - 1), 0, 100); + var implementedReviewStages = reviewStages.Where(stage => stage.IsImplemented).ToList(); + var currentReviewIndex = implementedReviewStages.FindIndex(stage => string.Equals(stage.StageName, Model.CurrentStage, StringComparison.OrdinalIgnoreCase)); + var isReviewPhase = currentReviewIndex >= 0; + var isComplete = string.Equals(Model.CurrentStage, "Complete", StringComparison.OrdinalIgnoreCase); + var isAnalyse = string.Equals(Model.CurrentStage, "Analyse Manuscript", StringComparison.OrdinalIgnoreCase); + var activePhase = isComplete ? 4 : isReviewPhase ? 3 : isAnalyse ? 2 : 1; + var progressPercent = isReviewPhase + ? Math.Clamp(((currentReviewIndex + 1) * 100) / implementedReviewStages.Count, 0, 100) + : isComplete ? 100 : 100; + var currentStageNumber = isReviewPhase ? currentReviewIndex + 1 : isComplete ? implementedReviewStages.Count : 0; } -
- @Model.CurrentStage -
- +
+
+

Phase @activePhase

+

@CurrentPhaseTitle(activePhase)

+ @if (isReviewPhase) + { +

Stage @currentStageNumber of @implementedReviewStages.Count

+ } + else if (isComplete) + { +

Final import and completion

+ } + else if (isAnalyse) + { +

Story Intelligence Analysis

+ } + else + { +

Prepare the manuscript for analysis

+ }
-
-
    - @foreach (var phase in phases) - { - var firstStageIndex = flatStages.FindIndex(stage => phase.Stages.Contains(stage)); - var lastStageIndex = firstStageIndex + phase.Stages.Length - 1; - var phaseClass = currentIndex > lastStageIndex - ? "is-complete" - : currentIndex >= firstStageIndex && currentIndex <= lastStageIndex - ? "is-current" - : "is-upcoming"; -
  1. - @phase.Name.Replace("Phase ", string.Empty) - @phase.Label - @StageSummary(phase.Stages, currentIndex, firstStageIndex) + +
    + @ProgressLabel(activePhase, Model.CurrentStage) +
    + +
    +
    + +
      +
    1. + Prepare Manuscript + 7 completed steps +
        +
      • Welcome
      • +
      • Writing Preferences
      • +
      • Project
      • +
      • Book
      • +
      • Connect Word
      • +
      • Scan Manuscript
      • +
      • Review Chapters
      • +
    2. - } -
    +
  2. + Analyse Manuscript + Story Intelligence Analysis +
  3. +
  4. + Review Story Intelligence + @ReviewSummary(isReviewPhase, currentStageNumber, implementedReviewStages.Count) +
      + @foreach (var stage in reviewStages) + { + var index = implementedReviewStages.FindIndex(item => string.Equals(item.StageName, stage.StageName, StringComparison.OrdinalIgnoreCase)); + var stageClass = !stage.IsImplemented + ? "is-upcoming" + : isComplete || index < currentReviewIndex + ? "is-complete" + : index == currentReviewIndex + ? "is-current" + : "is-upcoming"; +
    • + + @stage.Label + @if (!stage.IsImplemented) + { + Coming Soon + } +
    • + } +
    +
  5. +
  6. + Build Story Database + Final import and completion +
  7. +
+
@functions { - private static string StageSummary(IReadOnlyList stages, int currentIndex, int firstStageIndex) - { - var localIndex = currentIndex - firstStageIndex; - if (localIndex >= 0 && localIndex < stages.Count) - { - return stages[localIndex]; - } + private sealed record PipelineStage(string StageName, string Label, bool IsImplemented); - return stages.Count == 1 ? stages[0] : $"{stages.Count} stages"; - } + private static string CurrentPhaseTitle(int phase) + => phase switch + { + 1 => "Prepare Manuscript", + 2 => "Analyse Manuscript", + 3 => "Review Story Intelligence", + _ => "Build Story Database" + }; + + private static string ProgressLabel(int phase, string currentStage) + => phase switch + { + 3 => currentStage, + 4 => "Finalising import", + _ => "Completed" + }; + + private static string ReviewSummary(bool isReviewPhase, int currentStageNumber, int implementedStageCount) + => isReviewPhase + ? $"{Math.Max(0, currentStageNumber - 1)} of {implementedStageCount} review stages completed" + : $"{implementedStageCount} review stages completed"; + + private static string StageMarker(string stageClass, bool isImplemented) + => !isImplemented ? "○" : stageClass == "is-current" ? "►" : stageClass == "is-complete" ? "✓" : "○"; } diff --git a/PlotLine/wwwroot/css/onboarding.css b/PlotLine/wwwroot/css/onboarding.css index bc064e9..78299cb 100644 --- a/PlotLine/wwwroot/css/onboarding.css +++ b/PlotLine/wwwroot/css/onboarding.css @@ -807,6 +807,195 @@ summary.story-review-chapter-heading { gap: 1rem; } +.story-pipeline-header { + display: grid; + gap: 1rem; + margin-bottom: 1.5rem; +} + +.story-pipeline-current { + display: grid; + gap: .15rem; +} + +.story-pipeline-current h2 { + margin: 0; + font-size: clamp(1.45rem, 3vw, 2.15rem); +} + +.story-pipeline-current p:not(.eyebrow) { + margin: 0; + color: var(--bs-secondary-color); + font-weight: 800; +} + +.story-pipeline-progress { + margin-bottom: 0; +} + +.story-pipeline-phase-list { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: .75rem; + margin: 0; + padding: 0; + list-style: none; +} + +.story-pipeline-phase-list > li { + display: grid; + align-content: start; + gap: .45rem; + min-width: 0; + border: 1px solid rgba(31, 42, 68, .12); + border-radius: 8px; + padding: .85rem; + background: rgba(255, 255, 255, .58); +} + +.story-pipeline-phase-list > li.is-current { + border-color: rgba(47, 111, 99, .42); + background: rgba(47, 111, 99, .08); + box-shadow: inset 0 0 0 1px rgba(47, 111, 99, .12); +} + +.story-pipeline-phase-list > li.is-complete { + background: rgba(47, 111, 99, .06); +} + +.story-pipeline-phase-list > li.is-complete > strong::before { + content: "✓ "; + color: #2f6f63; +} + +.story-pipeline-phase-list > li > strong { + font-size: .98rem; +} + +.story-pipeline-phase-list > li > span { + color: var(--bs-secondary-color); + font-size: .82rem; + font-weight: 800; +} + +.story-pipeline-phase-list ul { + display: grid; + gap: .2rem; + margin: .25rem 0 0; + padding: 0; + list-style: none; + color: var(--bs-secondary-color); + font-size: .8rem; +} + +.story-pipeline-review-list li { + display: flex; + align-items: center; + gap: .35rem; +} + +.story-pipeline-review-list li strong { + font-size: .82rem; +} + +.story-pipeline-review-list li span { + width: 1rem; + color: var(--bs-secondary-color); + font-weight: 900; +} + +.story-pipeline-review-list li.is-complete span { + color: #2f6f63; +} + +.story-pipeline-review-list li.is-current { + color: var(--bs-body-color); +} + +.story-pipeline-review-list li.is-current span, +.story-pipeline-review-list li.is-current strong { + color: var(--bs-primary); +} + +.story-pipeline-review-list li em { + color: var(--bs-secondary-color); + font-size: .74rem; + font-style: normal; + font-weight: 800; +} + +.story-review-heading { + display: grid; + gap: .15rem; +} + +.story-review-heading p { + margin: 0; +} + +.story-review-heading__phase { + color: var(--bs-secondary-color); + font-size: .92rem; + font-weight: 800; +} + +.story-review-heading__stage { + color: var(--bs-secondary-color); + font-size: .84rem; + font-weight: 800; +} + +.story-database-build { + display: grid; + gap: .8rem; + border: 1px solid rgba(47, 111, 99, .18); + border-radius: 8px; + padding: 1rem; + background: rgba(47, 111, 99, .07); +} + +.story-database-build h2 { + margin: 0; + font-size: 1.2rem; +} + +.story-database-build ul { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: .5rem .9rem; + margin: 0; + padding: 0; + list-style: none; +} + +.story-database-build li { + display: flex; + align-items: center; + gap: .45rem; + font-weight: 800; +} + +.story-database-build li span { + color: #2f6f63; + font-weight: 900; +} + +.story-database-build li em { + color: var(--bs-secondary-color); + font-size: .76rem; + font-style: normal; + font-weight: 800; + margin-left: auto; +} + +.story-database-build li.is-upcoming { + color: var(--bs-secondary-color); +} + +.story-database-build li.is-upcoming span { + color: var(--bs-secondary-color); +} + .story-review-summary { padding: 1rem; } @@ -1361,6 +1550,11 @@ summary.story-review-chapter-heading { } @media (max-width: 720px) { + .story-pipeline-phase-list, + .story-database-build ul { + grid-template-columns: 1fr; + } + .onboarding-choice-grid, .onboarding-option-grid--software { grid-template-columns: 1fr;