diff --git a/PlotLine/Views/WordCompanionHost/Index.cshtml b/PlotLine/Views/WordCompanionHost/Index.cshtml index b0ae7a4..3415b5b 100644 --- a/PlotLine/Views/WordCompanionHost/Index.cshtml +++ b/PlotLine/Views/WordCompanionHost/Index.cshtml @@ -15,8 +15,10 @@
-

PlotDirector Companion

-

@statusText

+
+

PlotDirector

+

@statusText

+
@if (Model.IsAuthenticated) {

Signed in as @Model.DisplayName

@@ -27,296 +29,320 @@ }
-
- - -

+ + +
+
+
+ + +

+
+
+ + +

+
+
+ +
+
+ + +
+

+

No resolved PlotDirector scene.

+ +
+
+ Current Chapter + Not detected +
+
+ Current Scene + Not detected +
+
+ Not detected + Not attached +
+
+ +
+
+ Word Count + - +
+
+ Actual + - +
+
+ Estimated + - +
+
+ Revision + - +
+
+ Blocked + - +
+ +
+ + +

+
+ + + + + +
-
- - -

+ -
-
- Current Scene -
-
- - -
-

-

No resolved PlotDirector scene.

-
-
- Current Chapter - Not detected +
-
-
- Last Synced - - -
-
- Sync Count - - -
-
- -

+
-
- - - - - - -
-
- Structure Sync Preview -
- - -
-
-

Select a project and book to analyse manuscript structure.

-
-

No preview generated.

-
-
- -
- Document Outline -
-

No structure scanned.

-
-
- -
- Diagnostics -
- Diagnostics - -
-
-
- Selected Project ID - - -
-
- Selected Project - - -
-
- Selected Book ID - - -
-
- Selected Book - - -
-
- Detected Chapter - - -
-
- Detected Scene - - -
-
- Resolve Request Chapter - - -
-
- Resolve Request Scene - - -
-
- Resolve Result - Not run -
-
- Chapter ID - - -
-
- Scene ID - - -
-
- Anchor Type - Title Match -
-
- Stored Scene ID - - -
-
- Stored Chapter ID - - -
-
- Current Resolution Method - - -
-
- Office Host - Unknown -
-
- Office Platform - Unknown -
-
- Office Ready - No -
-
- Word API Available - No -
-
- Last Scan Result - Not run -
-
- Last Error - - -
-
- Paragraphs Found - - -
-
- Heading 1 Found - - -
-
- Heading 2 Found - - -
-
-
-
Word Companion loading
+ +
diff --git a/PlotLine/wwwroot/css/word-companion.css b/PlotLine/wwwroot/css/word-companion.css index e6c9f7e..01becd6 100644 --- a/PlotLine/wwwroot/css/word-companion.css +++ b/PlotLine/wwwroot/css/word-companion.css @@ -21,24 +21,26 @@ body { margin: 0; min-width: 280px; color: var(--companion-ink); - background: var(--companion-paper); + background: #f4f6f4; font-family: "Segoe UI", system-ui, -apple-system, BlinkMacSystemFont, sans-serif; } .word-companion-shell { display: grid; - gap: 12px; + gap: 10px; width: 100%; max-width: 420px; min-height: 100vh; - padding: 16px; + padding: 10px; } .word-companion-header { - display: grid; - gap: 6px; + display: flex; + align-items: center; + justify-content: space-between; + gap: 10px; border-bottom: 1px solid var(--companion-line); - padding-bottom: 14px; + padding-bottom: 8px; } .word-companion-eyebrow { @@ -52,7 +54,7 @@ body { .word-companion-header h1 { margin: 0; - font-size: 1.55rem; + font-size: 1.12rem; line-height: 1.1; } @@ -62,7 +64,7 @@ body { .word-companion-footer { margin: 0; color: var(--companion-muted); - font-size: 0.9rem; + font-size: 0.82rem; } .word-companion-status { @@ -84,12 +86,43 @@ body { text-decoration: none; } -.word-companion-section { +.word-companion-tabs { display: grid; - gap: 8px; + grid-template-columns: repeat(4, 1fr); + gap: 3px; border: 1px solid var(--companion-line); border-radius: 8px; - padding: 12px; + padding: 3px; + background: #ffffff; +} + +.word-companion-tabs button { + min-height: 30px; + border: 0; + border-radius: 6px; + background: transparent; + color: var(--companion-muted); + font: inherit; + font-size: 0.78rem; + font-weight: 800; +} + +.word-companion-tabs button.is-active { + background: var(--companion-accent); + color: #ffffff; +} + +.word-companion-tab-panel { + display: grid; + gap: 10px; +} + +.word-companion-section { + display: grid; + gap: 7px; + border: 1px solid var(--companion-line); + border-radius: 8px; + padding: 10px; background: var(--companion-panel); } @@ -108,7 +141,7 @@ body { .word-companion-section select { width: 100%; - min-height: 36px; + min-height: 32px; border: 1px solid var(--companion-line); border-radius: 6px; padding: 6px 8px; @@ -117,6 +150,15 @@ body { font: inherit; } +.word-companion-connection { + grid-template-columns: 1fr 1fr; + gap: 8px; +} + +.word-companion-connection .word-companion-message { + grid-column: auto; +} + .word-companion-section select:disabled { background: var(--companion-soft); color: var(--companion-muted); @@ -137,7 +179,7 @@ body { } .word-companion-section-header button { - min-height: 32px; + min-height: 30px; border: 1px solid var(--companion-accent); border-radius: 6px; padding: 5px 9px; @@ -162,7 +204,7 @@ body { } .word-companion-actions button { - min-height: 36px; + min-height: 34px; border: 1px solid var(--companion-accent); border-radius: 6px; padding: 6px 8px; @@ -212,7 +254,8 @@ body { } .word-companion-scene-card, -.word-companion-structure-grid { +.word-companion-structure-grid, +.word-companion-metrics { display: grid; gap: 8px; } @@ -224,14 +267,59 @@ body { background: var(--companion-soft); } +.word-companion-scene-summary { + gap: 9px; +} + +.word-companion-title-row strong { + font-size: 1rem; +} + +.word-companion-badges { + display: flex; + flex-wrap: wrap; + gap: 6px; +} + +.word-companion-badge { + display: inline-flex; + align-items: center; + width: fit-content; + min-height: 24px; + border: 1px solid rgba(47, 111, 99, 0.24); + border-radius: 999px; + padding: 3px 8px; + background: #ffffff; + color: var(--companion-accent-dark) !important; + font-size: 0.74rem !important; + font-weight: 800 !important; + text-transform: none !important; +} + .word-companion-scene-card div, .word-companion-sync-meta div, .word-companion-structure-grid div, -.word-companion-diagnostics-grid div { +.word-companion-diagnostics-grid div, +.word-companion-metrics div { display: grid; gap: 2px; } +.word-companion-metrics { + grid-template-columns: repeat(2, minmax(0, 1fr)); +} + +.word-companion-metrics div { + border: 1px solid rgba(47, 111, 99, 0.16); + border-radius: 6px; + padding: 7px; + background: #ffffff; +} + +.word-companion-metrics strong { + font-size: 0.92rem; +} + .word-companion-sync-meta { display: grid; gap: 8px; @@ -264,6 +352,7 @@ body { .word-companion-resolve-diagnostics { padding-top: 4px; + grid-template-columns: repeat(2, minmax(0, 1fr)); } .word-companion-resolve-diagnostics strong { diff --git a/PlotLine/wwwroot/js/word-companion-host.js b/PlotLine/wwwroot/js/word-companion-host.js index 46c95f6..e6325c8 100644 --- a/PlotLine/wwwroot/js/word-companion-host.js +++ b/PlotLine/wwwroot/js/word-companion-host.js @@ -5,6 +5,8 @@ }; const shell = document.querySelector(".word-companion-shell"); + const tabButtons = [...document.querySelectorAll("[data-tab-button]")]; + const tabPanels = [...document.querySelectorAll("[data-tab-panel]")]; const officeStatus = document.querySelector("[data-office-status]"); const connectionStatus = document.querySelector("[data-connection-status]"); const summaryConnection = document.querySelector("[data-summary-connection]"); @@ -157,6 +159,20 @@ } }; + const selectTab = (tabName) => { + for (const button of tabButtons) { + const active = button.dataset.tabButton === tabName; + button.classList.toggle("is-active", active); + button.setAttribute("aria-selected", active ? "true" : "false"); + } + + for (const panel of tabPanels) { + const active = panel.dataset.tabPanel === tabName; + panel.classList.toggle("is-active", active); + panel.hidden = !active; + } + }; + const setConnectionStatus = (message) => { if (connectionStatus) { connectionStatus.textContent = message; @@ -306,7 +322,7 @@ saveSceneLinksButton.disabled = !resolvedSceneId; } setSyncStatus(resolvedSceneId ? "Ready to sync." : "No resolved PlotDirector scene."); - setSceneLinksStatus(resolvedSceneId ? "Ready to save." : "No resolved PlotDirector scene."); + setSceneLinksStatus(resolvedSceneId ? "Ready to save." : "Link a PlotDirector scene first."); updateAnchorDisplay(); }; @@ -411,7 +427,7 @@ setPlotDirectorSceneStatus(message); setHidden(plotDirectorSceneDetails, true); setHidden(writingBriefBlock, true); - setHidden(plotDirectorLinkGroups, true); + setHidden(plotDirectorLinkGroups, false); hideChapterCreateLink(); hideSceneCreateLink(); currentResolutionMethod = ""; @@ -1838,7 +1854,7 @@ const saveSceneLinks = async () => { if (!resolvedSceneId) { - setSceneLinksStatus("No resolved PlotDirector scene."); + setSceneLinksStatus("Link a PlotDirector scene first."); return; } @@ -2861,6 +2877,10 @@ } }; + for (const button of tabButtons) { + button.addEventListener("click", () => selectTab(button.dataset.tabButton)); + } + projectSelect?.addEventListener("change", async () => { const projectId = Number.parseInt(projectSelect.value || "", 10); writeStoredId(storageKeys.projectId, Number.isInteger(projectId) && projectId > 0 ? projectId : null);