feat(career): theme polish, rich-text bullets, entry ordering, outline API
Phase 4.5 backend enablers. - Themes (priority 3): AtsFriendly flag on single-column themes (surfaced in GET /api/cv/themes), print-quality page-break rules (entries never split across a page; headings stay with content; widow/orphan control), darkened the creative sidebar for AA contrast. - Rich text (priority 1): bullets/summary support **bold**, *italic*, __underline__, [text](url) via a safe inline pass — everything is HTML-escaped first, so no user tag can survive; only the whitelist emits markup. - Entry ordering (priority 1): CvSectionSetting.ItemOrder reorders entries within a section by ItemKey, never touching the master profile. - Outline API: GET /api/cv/outline returns the master profile as sections+entries with ItemKeys, so the Content tab can render editable per-item rows. - 3 new tests (22 total in the builder suite). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -27,6 +27,8 @@ public interface ICvVariantService
|
||||
Task<ThemedCvRenderResult?> RenderAsync(string ownerUserId, int id, CvRenderPerson person, CancellationToken ct);
|
||||
// Render arbitrary (unsaved) settings against the current master profile — live preview.
|
||||
Task<ThemedCvRenderResult> RenderSettingsAsync(string ownerUserId, CvVariantSettings settings, CvRenderPerson person, CancellationToken ct);
|
||||
// The master profile resolved to sections+entries (with ItemKeys) for the Content tab to edit.
|
||||
Task<CvRenderModel> OutlineAsync(string ownerUserId, CvRenderPerson person, CancellationToken ct);
|
||||
// Render a public variant by slug (anonymous). Returns null if the slug is unknown or not public.
|
||||
Task<(ThemedCvRenderResult render, string ownerUserId)?> RenderPublicAsync(string publicSlug, CvRenderPerson person, CancellationToken ct);
|
||||
Task<string?> GetPublicOwnerAsync(string publicSlug, CancellationToken ct);
|
||||
@@ -153,6 +155,12 @@ public sealed class CvVariantService : ICvVariantService
|
||||
return RenderInternal(profile, settings, person);
|
||||
}
|
||||
|
||||
public async Task<CvRenderModel> OutlineAsync(string ownerUserId, CvRenderPerson person, CancellationToken ct)
|
||||
{
|
||||
var profile = await _career.LoadStructuredAsync(ownerUserId, ct);
|
||||
return CvVariantResolver.Build(profile, new CvVariantSettings(), person.FallbackName, person.PhotoDataUrl);
|
||||
}
|
||||
|
||||
public async Task<(ThemedCvRenderResult render, string ownerUserId)?> RenderPublicAsync(string publicSlug, CvRenderPerson person, CancellationToken ct)
|
||||
{
|
||||
var variant = await _db.CvVariants.IgnoreQueryFilters()
|
||||
|
||||
Reference in New Issue
Block a user