Phase 20AR – Story Intelligence Wizard Polish
This commit is contained in:
parent
ab3b591e4d
commit
7f9f051341
@ -6,8 +6,10 @@
|
||||
<section class="onboarding-shell" aria-labelledby="story-asset-title">
|
||||
<div class="onboarding-panel onboarding-review-panel story-review-page">
|
||||
<partial name="_StoryIntelligencePipelineHeader" model="@(new StoryIntelligencePipelineHeaderViewModel { CurrentStage = "Review Assets" })" />
|
||||
<div class="onboarding-copy">
|
||||
<p class="eyebrow">Review Story Intelligence</p>
|
||||
<div class="onboarding-copy story-review-heading">
|
||||
<p class="eyebrow">Phase 3</p>
|
||||
<p class="story-review-heading__phase">Review Story Intelligence</p>
|
||||
<p class="story-review-heading__stage">Stage 4 of 4</p>
|
||||
<h1 id="story-asset-title">Review Assets</h1>
|
||||
<p>Approve the important objects PlotDirector should create or link from your imported scenes. Nothing is created unless you approve it.</p>
|
||||
</div>
|
||||
|
||||
@ -6,8 +6,10 @@
|
||||
<section class="onboarding-shell" aria-labelledby="story-character-title">
|
||||
<div class="onboarding-panel onboarding-review-panel story-review-page">
|
||||
<partial name="_StoryIntelligencePipelineHeader" model="@(new StoryIntelligencePipelineHeaderViewModel { CurrentStage = "Review Characters" })" />
|
||||
<div class="onboarding-copy">
|
||||
<p class="eyebrow">Review Story Intelligence</p>
|
||||
<div class="onboarding-copy story-review-heading">
|
||||
<p class="eyebrow">Phase 3</p>
|
||||
<p class="story-review-heading__phase">Review Story Intelligence</p>
|
||||
<p class="story-review-heading__stage">Stage 2 of 4</p>
|
||||
<h1 id="story-character-title">Review Characters</h1>
|
||||
<p>Approve the characters PlotDirector should create or link from your imported scenes. You stay in control of every character record.</p>
|
||||
</div>
|
||||
|
||||
@ -6,15 +6,32 @@
|
||||
<section class="onboarding-shell" aria-labelledby="story-complete-title">
|
||||
<div class="onboarding-panel onboarding-review-panel">
|
||||
<partial name="_StoryIntelligencePipelineHeader" model="@(new StoryIntelligencePipelineHeaderViewModel { CurrentStage = "Complete" })" />
|
||||
<div class="onboarding-copy">
|
||||
<p class="eyebrow">Story Intelligence pipeline</p>
|
||||
<div class="onboarding-copy story-review-heading">
|
||||
<p class="eyebrow">Phase 4</p>
|
||||
<p class="story-review-heading__phase">Build Story Database</p>
|
||||
<div class="onboarding-success-heading">
|
||||
<span aria-hidden="true">✓</span>
|
||||
<h1 id="story-complete-title">Story Intelligence complete</h1>
|
||||
</div>
|
||||
<p>PlotDirector completed every implemented Story Intelligence stage for this manuscript. Future stages will continue from this same pipeline as they become available.</p>
|
||||
<p>PlotDirector has built the implemented story database records from your reviewed manuscript analysis.</p>
|
||||
</div>
|
||||
|
||||
<section class="story-database-build" aria-label="Story database build checklist">
|
||||
<h2>Building your Story Database...</h2>
|
||||
<ul>
|
||||
<li><span aria-hidden="true">✓</span><strong>Chapters</strong></li>
|
||||
<li><span aria-hidden="true">✓</span><strong>Scenes</strong></li>
|
||||
<li><span aria-hidden="true">✓</span><strong>Characters</strong></li>
|
||||
<li><span aria-hidden="true">✓</span><strong>Locations</strong></li>
|
||||
<li><span aria-hidden="true">✓</span><strong>Assets</strong></li>
|
||||
<li class="is-upcoming"><span aria-hidden="true">○</span><strong>Relationships</strong><em>Coming Soon</em></li>
|
||||
<li class="is-upcoming"><span aria-hidden="true">○</span><strong>Knowledge</strong><em>Coming Soon</em></li>
|
||||
<li><span aria-hidden="true">✓</span><strong>Preparing continuity...</strong></li>
|
||||
<li><span aria-hidden="true">✓</span><strong>Generating story indexes...</strong></li>
|
||||
<li><span aria-hidden="true">✓</span><strong>Finalising project...</strong></li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<div class="onboarding-scan-counts onboarding-review-counts">
|
||||
<div>
|
||||
<span>Chapters analysed</span>
|
||||
@ -42,13 +59,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="story-future-stage-grid">
|
||||
<article class="story-future-stage"><strong>Review Relationships</strong><span>Coming Soon</span></article>
|
||||
<article class="story-future-stage"><strong>Review Knowledge</strong><span>Coming Soon</span></article>
|
||||
<article class="story-future-stage"><strong>Review Continuity</strong><span>Coming Soon</span></article>
|
||||
<article class="story-future-stage"><strong>Timeline Events</strong><span>Coming Soon</span></article>
|
||||
</div>
|
||||
|
||||
<div class="onboarding-actions">
|
||||
<a class="btn btn-primary" asp-controller="Writer" asp-action="Index" asp-route-projectId="@Model.ProjectID">View scenes</a>
|
||||
<a class="btn btn-outline-primary" asp-controller="Books" asp-action="Details" asp-route-id="@Model.BookID">View book</a>
|
||||
|
||||
@ -6,8 +6,10 @@
|
||||
<section class="onboarding-shell" aria-labelledby="story-location-title">
|
||||
<div class="onboarding-panel onboarding-review-panel story-review-page">
|
||||
<partial name="_StoryIntelligencePipelineHeader" model="@(new StoryIntelligencePipelineHeaderViewModel { CurrentStage = "Review Locations" })" />
|
||||
<div class="onboarding-copy">
|
||||
<p class="eyebrow">Review Story Intelligence</p>
|
||||
<div class="onboarding-copy story-review-heading">
|
||||
<p class="eyebrow">Phase 3</p>
|
||||
<p class="story-review-heading__phase">Review Story Intelligence</p>
|
||||
<p class="story-review-heading__stage">Stage 3 of 4</p>
|
||||
<h1 id="story-location-title">Review Locations</h1>
|
||||
<p>Approve the places PlotDirector should create or link from your imported scenes. Nothing is created unless you approve it.</p>
|
||||
</div>
|
||||
|
||||
@ -14,8 +14,10 @@
|
||||
<section class="onboarding-shell" aria-labelledby="story-review-title">
|
||||
<div class="onboarding-panel onboarding-review-panel story-review-page">
|
||||
<partial name="_StoryIntelligencePipelineHeader" model="@(new StoryIntelligencePipelineHeaderViewModel { CurrentStage = "Review Scenes" })" />
|
||||
<div class="onboarding-copy">
|
||||
<p class="eyebrow">Review Story Intelligence</p>
|
||||
<div class="onboarding-copy story-review-heading">
|
||||
<p class="eyebrow">Phase 3</p>
|
||||
<p class="story-review-heading__phase">Review Story Intelligence</p>
|
||||
<p class="story-review-heading__stage">Stage 1 of 4</p>
|
||||
<h1 id="story-review-title">Review Scenes</h1>
|
||||
<p>PlotDirector has finished reading your manuscript. Review the detected scenes before creating them in your story database.</p>
|
||||
</div>
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
<div class="onboarding-progress story-pipeline-progress" aria-label="Story Intelligence pipeline progress">
|
||||
<span>@Model.CurrentStage</span>
|
||||
<div class="onboarding-progress-track">
|
||||
<span style="width:@percent%"></span>
|
||||
</div>
|
||||
</div>
|
||||
<ol class="onboarding-stepper story-pipeline-stepper" aria-label="Story Intelligence pipeline">
|
||||
@foreach (var phase in phases)
|
||||
<section class="story-pipeline-header" aria-label="Story Intelligence pipeline">
|
||||
<div class="story-pipeline-current">
|
||||
<p class="eyebrow">Phase @activePhase</p>
|
||||
<h2>@CurrentPhaseTitle(activePhase)</h2>
|
||||
@if (isReviewPhase)
|
||||
{
|
||||
var firstStageIndex = flatStages.FindIndex(stage => phase.Stages.Contains(stage));
|
||||
var lastStageIndex = firstStageIndex + phase.Stages.Length - 1;
|
||||
var phaseClass = currentIndex > lastStageIndex
|
||||
<p>Stage @currentStageNumber of @implementedReviewStages.Count</p>
|
||||
}
|
||||
else if (isComplete)
|
||||
{
|
||||
<p>Final import and completion</p>
|
||||
}
|
||||
else if (isAnalyse)
|
||||
{
|
||||
<p>Story Intelligence Analysis</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<p>Prepare the manuscript for analysis</p>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="onboarding-progress story-pipeline-progress" aria-label="@CurrentPhaseTitle(activePhase) progress">
|
||||
<span>@ProgressLabel(activePhase, Model.CurrentStage)</span>
|
||||
<div class="onboarding-progress-track">
|
||||
<span style="width:@progressPercent%"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ol class="story-pipeline-phase-list">
|
||||
<li class="@(activePhase > 1 ? "is-complete" : activePhase == 1 ? "is-current" : "is-upcoming")">
|
||||
<strong>Prepare Manuscript</strong>
|
||||
<span>7 completed steps</span>
|
||||
<ul>
|
||||
<li>Welcome</li>
|
||||
<li>Writing Preferences</li>
|
||||
<li>Project</li>
|
||||
<li>Book</li>
|
||||
<li>Connect Word</li>
|
||||
<li>Scan Manuscript</li>
|
||||
<li>Review Chapters</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="@(activePhase > 2 ? "is-complete" : activePhase == 2 ? "is-current" : "is-upcoming")">
|
||||
<strong>Analyse Manuscript</strong>
|
||||
<span>Story Intelligence Analysis</span>
|
||||
</li>
|
||||
<li class="@(activePhase > 3 ? "is-complete" : activePhase == 3 ? "is-current" : "is-upcoming")">
|
||||
<strong>Review Story Intelligence</strong>
|
||||
<span>@ReviewSummary(isReviewPhase, currentStageNumber, implementedReviewStages.Count)</span>
|
||||
<ul class="story-pipeline-review-list">
|
||||
@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"
|
||||
: currentIndex >= firstStageIndex && currentIndex <= lastStageIndex
|
||||
: index == currentReviewIndex
|
||||
? "is-current"
|
||||
: "is-upcoming";
|
||||
<li class="@phaseClass">
|
||||
<span>@phase.Name.Replace("Phase ", string.Empty)</span>
|
||||
<strong>@phase.Label</strong>
|
||||
<small>@StageSummary(phase.Stages, currentIndex, firstStageIndex)</small>
|
||||
<li class="@stageClass">
|
||||
<span aria-hidden="true">@StageMarker(stageClass, stage.IsImplemented)</span>
|
||||
<strong>@stage.Label</strong>
|
||||
@if (!stage.IsImplemented)
|
||||
{
|
||||
<em>Coming Soon</em>
|
||||
}
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</li>
|
||||
<li class="@(activePhase == 4 ? "is-current" : "is-upcoming")">
|
||||
<strong>Build Story Database</strong>
|
||||
<span>Final import and completion</span>
|
||||
</li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
@functions {
|
||||
private static string StageSummary(IReadOnlyList<string> 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" ? "✓" : "○";
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user