@model BookDetailViewModel @{ ViewData["Title"] = Model.Book.BookTitle; ViewData["ProjectSection"] = "Overview"; } @if (TempData["ArchiveMessage"] is string archiveMessage) {
@archiveMessage
} @if (TempData["ManuscriptMessage"] is string manuscriptMessage) {
@manuscriptMessage
}

@Model.Project.ProjectName

Book @Model.Book.BookNumber: @Model.Book.BookTitle

@if (!string.IsNullOrWhiteSpace(Model.Book.Subtitle)) {

@Model.Book.Subtitle

} @if (!string.IsNullOrWhiteSpace(Model.Book.Tagline)) {

@Model.Book.Tagline

} @if (!string.IsNullOrWhiteSpace(Model.Book.Description)) {

@Model.Book.Description

}
Edit book Add chapter
@if (Model.StoryIntelligencePipeline is not null) { var pipeline = Model.StoryIntelligencePipeline;

Story Intelligence

@(pipeline.IsComplete ? "Story Intelligence Complete" : "Continue Story Intelligence")

@StoryIntelligenceDescription(pipeline)

@(pipeline.IsComplete ? "View Story Intelligence Summary" : "Continue Story Intelligence")
}

Book metadata

@Model.Book.Status
@Model.Book.CurrentWordCount.ToString("N0") current words
@(Model.Book.TargetWordCount?.ToString("N0") ?? "Not set") target words
@(Model.Book.ProgressPercentage.HasValue ? $"{Model.Book.ProgressPercentage:0.#}%" : "Not set") progress
@Model.Book.ChapterCount.ToString("N0") chapters
@Model.Book.SceneCount.ToString("N0") scenes
@(Model.Book.WritingStartDate?.ToString("dd MMM yyyy") ?? "Not set") writing start
@(Model.Book.TargetCompletionDate?.ToString("dd MMM yyyy") ?? "Not set") target completion
@(Model.Book.PublicationDate?.ToString("dd MMM yyyy") ?? "Not set") publication
@if (Model.ManuscriptDocument is null) { No manuscript linked } else { Manuscript linked Last synced: @(Model.ManuscriptDocument.LastSyncUtc?.ToString("dd MMM yyyy HH:mm") ?? "Never")
} Manuscript Status
@if (!string.IsNullOrWhiteSpace(Model.Book.ShortDescription)) {

@Model.Book.ShortDescription

}

Chapters

@if (!Model.Chapters.Any()) {

No chapters yet.

} else {
@foreach (var chapter in Model.Chapters) { }
Chapter Title Status Manuscript Summary
@chapter.ChapterNumber @chapter.ChapterTitle @chapter.RevisionStatusName @if (!string.IsNullOrWhiteSpace(chapter.ChapterPurposeName)) { @chapter.ChapterPurposeName } @(chapter.IsLinkedToManuscript ? "🔗 Linked" : "📝 Planned") @chapter.Summary Edit
}
@functions { private static string StoryIntelligenceDescription(StoryIntelligenceBookPipelineState pipeline) { if (pipeline.IsComplete) { return "All currently available Story Intelligence stages are complete."; } return pipeline.CurrentReviewStage switch { StoryIntelligencePipelineStages.RelationshipReview => "Review detected relationships and decide what to create or link.", StoryIntelligencePipelineStages.AssetReview => "Review detected assets and decide what to create or link.", StoryIntelligencePipelineStages.LocationReview => "Review detected locations and decide what to create or link.", StoryIntelligencePipelineStages.CharacterReview => "Scene creation is complete. Review detected characters to continue building the story database.", StoryIntelligencePipelineStages.SceneReview => "Review prepared scenes before creating them in PlotDirector.", _ when StoryIntelligenceReadyForRelationships(pipeline) => "Review detected relationships and decide what to create or link.", _ when StoryIntelligenceReadyForAssets(pipeline) => "Review detected assets and decide what to create or link.", _ when StoryIntelligenceReadyForLocations(pipeline) => "Review detected locations and decide what to create or link.", _ => "PlotDirector will resume from the next Story Intelligence stage." }; } private static bool StoryIntelligenceReadyForRelationships(StoryIntelligenceBookPipelineState pipeline) => string.Equals(pipeline.LastCompletedStage, StoryIntelligencePipelineStages.AssetImport, StringComparison.OrdinalIgnoreCase) || pipeline.CurrentStage is StoryIntelligencePipelineStages.RelationshipReview or StoryIntelligencePipelineStages.RelationshipImport; private static bool StoryIntelligenceReadyForAssets(StoryIntelligenceBookPipelineState pipeline) => string.Equals(pipeline.LastCompletedStage, StoryIntelligencePipelineStages.LocationImport, StringComparison.OrdinalIgnoreCase) || pipeline.CurrentStage is StoryIntelligencePipelineStages.AssetReview or StoryIntelligencePipelineStages.AssetImport or StoryIntelligencePipelineStages.RelationshipReview or StoryIntelligencePipelineStages.RelationshipImport || (string.Equals(pipeline.CurrentStage, StoryIntelligencePipelineStages.Complete, StringComparison.OrdinalIgnoreCase) && !string.Equals(pipeline.LastCompletedStage, StoryIntelligencePipelineStages.RelationshipImport, StringComparison.OrdinalIgnoreCase)); private static bool StoryIntelligenceReadyForLocations(StoryIntelligenceBookPipelineState pipeline) => string.Equals(pipeline.LastCompletedStage, StoryIntelligencePipelineStages.CharacterImport, StringComparison.OrdinalIgnoreCase) || pipeline.CurrentStage is StoryIntelligencePipelineStages.LocationReview or StoryIntelligencePipelineStages.LocationImport or StoryIntelligencePipelineStages.AssetReview or StoryIntelligencePipelineStages.AssetImport or StoryIntelligencePipelineStages.RelationshipReview or StoryIntelligencePipelineStages.RelationshipImport; }