Surface arcs, character beats and open questions in the web client
The character page gains three sections under the dossier: the arc as an editable ordered table with each stage pinnable to a chapter, every beat the character appears in across the book (each row linking into that chapter's outline), and the character's open questions. The sidebar groups main characters above supporting ones, and both the sheet and the add dialog let you set importance. The arc section shows for main characters, and also for supporting ones that already have stages — demoting someone should not hide work they thought they had lost. The outline page gains a notes section and an open-questions section at the bottom. Beat rows are now anchored so the character page can link straight to a row. Raising a question from either page attaches it to what that page is about, and the section hides the association it is already scoped to rather than repeating "Landfall" on every row. Also fixes an ordering wart the browser run exposed: both CharacterRole and CharacterImportance are stored as text, so ordering them in SQL ordered the spelling — "Deuteragonist" beat "Protagonist" and the sidebar put the second lead above the character the book is about. Listing now sorts after materialising, which uses the enums' declaration order. The test for it was checked both ways: it fails on the SQL ordering and passes on the fix. 73 tests pass, the web client builds and lints clean. Driven in a browser end to end: resolving a question with "also add to notes" drops it off the open list and appends the decision under the chapter's existing note, "show resolved" brings it back with a Reopen button, and a beat link on the character page lands on the right chapter outline at that beat's anchor. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S56bfZMGe1hnhpWP4CjjNw
This commit is contained in:
co-authored by
Claude Opus 5
parent
0358667679
commit
4f396bb5f9
@@ -8,16 +8,30 @@ namespace Novelly.Api.Characters;
|
||||
|
||||
public class CharacterService(INovelDbContext db, TagService tags)
|
||||
{
|
||||
/// <summary>
|
||||
/// Main characters first, then by the part they play, then by name.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The ordering is done in memory on purpose. Both enums are stored as text, so sorting
|
||||
/// them in SQL sorts the spelling — which puts Deuteragonist above Protagonist and buries
|
||||
/// the character the book is about. Sorting after materialising uses the declaration
|
||||
/// order, which is the significance order these enums are written in. A project's cast is
|
||||
/// small enough that this costs nothing.
|
||||
/// </remarks>
|
||||
public async Task<IReadOnlyList<CharacterDto>> ListAsync(Guid projectId, CancellationToken ct = default)
|
||||
{
|
||||
var characters = await Query()
|
||||
.Where(c => c.ProjectId == projectId)
|
||||
.OrderBy(c => c.Importance)
|
||||
.ThenBy(c => c.Role)
|
||||
.ThenBy(c => c.Name)
|
||||
.ToListAsync(ct);
|
||||
|
||||
return [.. characters.Select(c => c.ToDto())];
|
||||
return
|
||||
[
|
||||
.. characters
|
||||
.OrderBy(c => c.Importance)
|
||||
.ThenBy(c => c.Role)
|
||||
.ThenBy(c => c.Name)
|
||||
.Select(c => c.ToDto())
|
||||
];
|
||||
}
|
||||
|
||||
public async Task<CharacterDto> GetAsync(Guid id, CancellationToken ct = default) =>
|
||||
|
||||
Reference in New Issue
Block a user