from ConsistencyChecker/CriticView elements */}
{formattedOutput ? (
-
- {formattedOutput}
-
+ mode === 'rendered' ? (
+
+ ) : (
+
+ {formattedOutput}
+
+ )
) : (
diff --git a/graphify-out/GRAPH_REPORT.md b/graphify-out/GRAPH_REPORT.md
index 153c9a896..16b4344c6 100644
--- a/graphify-out/GRAPH_REPORT.md
+++ b/graphify-out/GRAPH_REPORT.md
@@ -1,12 +1,12 @@
# Graph Report - StoryCraft-Studio (2026-06-23)
## Corpus Check
-- 1153 files · ~1,301,323 words
+- 1155 files · ~1,302,334 words
- Verdict: corpus is large enough that graph structure adds value.
## Summary
-- 4999 nodes · 8780 edges · 87 communities detected
-- Extraction: 76% EXTRACTED · 24% INFERRED · 0% AMBIGUOUS · INFERRED: 2146 edges (avg confidence: 0.8)
+- 5009 nodes · 8800 edges · 84 communities detected
+- Extraction: 76% EXTRACTED · 24% INFERRED · 0% AMBIGUOUS · INFERRED: 2154 edges (avg confidence: 0.8)
- Token cost: 0 input · 0 output
## Community Hubs (Navigation)
@@ -39,39 +39,39 @@
- [[_COMMUNITY_Community 26|Community 26]]
- [[_COMMUNITY_Community 27|Community 27]]
- [[_COMMUNITY_Community 28|Community 28]]
-- [[_COMMUNITY_Community 29|Community 29]]
-- [[_COMMUNITY_Community 30|Community 30]]
-- [[_COMMUNITY_Community 33|Community 33]]
+- [[_COMMUNITY_Community 31|Community 31]]
+- [[_COMMUNITY_Community 32|Community 32]]
- [[_COMMUNITY_Community 34|Community 34]]
-- [[_COMMUNITY_Community 35|Community 35]]
- [[_COMMUNITY_Community 36|Community 36]]
+- [[_COMMUNITY_Community 37|Community 37]]
- [[_COMMUNITY_Community 38|Community 38]]
-- [[_COMMUNITY_Community 40|Community 40]]
- [[_COMMUNITY_Community 41|Community 41]]
-- [[_COMMUNITY_Community 42|Community 42]]
-- [[_COMMUNITY_Community 45|Community 45]]
+- [[_COMMUNITY_Community 43|Community 43]]
+- [[_COMMUNITY_Community 44|Community 44]]
- [[_COMMUNITY_Community 47|Community 47]]
-- [[_COMMUNITY_Community 48|Community 48]]
-- [[_COMMUNITY_Community 51|Community 51]]
-- [[_COMMUNITY_Community 54|Community 54]]
+- [[_COMMUNITY_Community 50|Community 50]]
+- [[_COMMUNITY_Community 55|Community 55]]
+- [[_COMMUNITY_Community 58|Community 58]]
- [[_COMMUNITY_Community 61|Community 61]]
+- [[_COMMUNITY_Community 62|Community 62]]
- [[_COMMUNITY_Community 63|Community 63]]
-- [[_COMMUNITY_Community 65|Community 65]]
-- [[_COMMUNITY_Community 66|Community 66]]
- [[_COMMUNITY_Community 67|Community 67]]
-- [[_COMMUNITY_Community 68|Community 68]]
-- [[_COMMUNITY_Community 73|Community 73]]
-- [[_COMMUNITY_Community 78|Community 78]]
+- [[_COMMUNITY_Community 69|Community 69]]
+- [[_COMMUNITY_Community 70|Community 70]]
+- [[_COMMUNITY_Community 75|Community 75]]
+- [[_COMMUNITY_Community 81|Community 81]]
- [[_COMMUNITY_Community 84|Community 84]]
-- [[_COMMUNITY_Community 87|Community 87]]
-- [[_COMMUNITY_Community 98|Community 98]]
-- [[_COMMUNITY_Community 131|Community 131]]
-- [[_COMMUNITY_Community 143|Community 143]]
-- [[_COMMUNITY_Community 149|Community 149]]
-- [[_COMMUNITY_Community 182|Community 182]]
-- [[_COMMUNITY_Community 230|Community 230]]
-- [[_COMMUNITY_Community 270|Community 270]]
-- [[_COMMUNITY_Community 275|Community 275]]
+- [[_COMMUNITY_Community 95|Community 95]]
+- [[_COMMUNITY_Community 128|Community 128]]
+- [[_COMMUNITY_Community 139|Community 139]]
+- [[_COMMUNITY_Community 145|Community 145]]
+- [[_COMMUNITY_Community 178|Community 178]]
+- [[_COMMUNITY_Community 226|Community 226]]
+- [[_COMMUNITY_Community 266|Community 266]]
+- [[_COMMUNITY_Community 271|Community 271]]
+- [[_COMMUNITY_Community 740|Community 740]]
+- [[_COMMUNITY_Community 741|Community 741]]
+- [[_COMMUNITY_Community 742|Community 742]]
- [[_COMMUNITY_Community 743|Community 743]]
- [[_COMMUNITY_Community 744|Community 744]]
- [[_COMMUNITY_Community 745|Community 745]]
@@ -94,14 +94,11 @@
- [[_COMMUNITY_Community 762|Community 762]]
- [[_COMMUNITY_Community 763|Community 763]]
- [[_COMMUNITY_Community 764|Community 764]]
-- [[_COMMUNITY_Community 765|Community 765]]
-- [[_COMMUNITY_Community 766|Community 766]]
-- [[_COMMUNITY_Community 767|Community 767]]
## God Nodes (most connected - your core abstractions)
1. `mt()` - 104 edges
2. `Bv` - 74 edges
-3. `fn()` - 62 edges
+3. `fn()` - 63 edges
4. `t()` - 51 edges
5. `Ze()` - 43 edges
6. `wx()` - 41 edges
@@ -111,6 +108,8 @@
10. `tA()` - 34 edges
## Surprising Connections (you probably didn't know these)
+- `App()` --calls--> `useApp()` [INFERRED]
+ App.tsx → hooks/useApp.ts
- `useTranslation()` --calls--> `IdbUnlockModal()` [INFERRED]
hooks/useTranslation.ts → components/settings/IdbUnlockModal.tsx
- `getItem()` --calls--> `readMode()` [INFERRED]
@@ -119,466 +118,448 @@
features/featureFlags/featureFlagsStorage.ts → components/copilot/CopilotPanel.tsx
- `setItem()` --calls--> `enableDebugLogging()` [INFERRED]
features/featureFlags/featureFlagsStorage.ts → services/logger.ts
-- `removeItem()` --calls--> `disableDebugLogging()` [INFERRED]
- features/featureFlags/featureFlagsStorage.ts → services/logger.ts
## Communities
### Community 0 - "Community 0"
Cohesion: 0.01
-Nodes (322): md(), _0, _2(), A0, a2(), aA(), ab(), ac() (+314 more)
+Nodes (308): flushMicrotasks(), _0, _2(), A0, a2(), aA(), ac(), ad() (+300 more)
### Community 1 - "Community 1"
Cohesion: 0.01
-Nodes (117): recordLatency(), _clearPendingRequestsForTest(), createCancellationToken(), buildConsistencyHints(), buildEntityId(), buildRelationshipEdges(), createStoryCodexEntity(), escapeRegExpLiteral() (+109 more)
+Nodes (145): recordLatency(), AiInferenceCacheService, hashKey(), _clearPendingRequestsForTest(), binderDepth(), createCancellationToken(), CloudSyncClient, buildConsistencyHints() (+137 more)
### Community 2 - "Community 2"
Cohesion: 0.01
-Nodes (177): af(), ef(), ff(), Ja(), lf(), mt(), nf(), of() (+169 more)
+Nodes (171): af(), ef(), ff(), Ja(), lf(), mt(), nf(), of() (+163 more)
### Community 3 - "Community 3"
Cohesion: 0.01
-Nodes (108): item(), glossaryTranslate(), loadCheckpoint(), loadGlossary(), main(), maskPlaceholders(), parseArgs(), restorePlaceholders() (+100 more)
+Nodes (150): getActiveAiMode(), getLocalFallbackModel(), getOpenRouterFallbackProvider(), getOpenRouterModel(), isCloudOnlyMode(), isOffline(), notifyLocalModelsReady(), shouldRouteLocally() (+142 more)
### Community 4 - "Community 4"
Cohesion: 0.01
-Nodes (82): handleCopyForNotion(), handleDocxImport(), handleExport(), handlePasteImport(), loadAgent(), analyticsPersistenceAllowedNow(), isAnalyticsPersistenceAllowed(), setRetryFeedback() (+74 more)
+Nodes (103): handleCopyForNotion(), handleDocxImport(), handleExport(), handlePasteImport(), loadAgent(), handleBuildLocalRag(), handleWebllmDownload(), isCustomOllamaModel() (+95 more)
### Community 5 - "Community 5"
Cohesion: 0.02
-Nodes (59): isEcoMode(), flushMicrotasks(), decrypt(), decryptJson(), encrypt(), encryptJson(), generateMessageId(), getWorker() (+51 more)
+Nodes (59): pipeline(), pipeline(), isEcoMode(), EcoModeService, FeedbackService, handleEcoToggle(), routeTask(), KokoroTtsEngine (+51 more)
### Community 6 - "Community 6"
Cohesion: 0.02
-Nodes (73): AiInferenceCacheService, hashKey(), _cleanupPendingRequest(), handleRemoveKey(), handleSaveKey(), handleTestConnection(), binderDepth(), CloudSyncBackend (+65 more)
+Nodes (69): accessibilityPresetDefaults(), normalizeAccessibilitySettings(), applyPreset(), handleRemoveKey(), handleSaveKey(), handleTestConnection(), CloudSyncBackend, decryptCloudPayload() (+61 more)
### Community 7 - "Community 7"
Cohesion: 0.02
-Nodes (24): a_(), bh, Dh(), eA(), el(), GE(), Gh(), lv() (+16 more)
+Nodes (47): AudioNavigator, md(), ab(), av(), br(), bs(), Bv, CA() (+39 more)
### Community 8 - "Community 8"
-Cohesion: 0.01
-Nodes (78): categoryFromMessage(), categoryFromStatus(), classificationFor(), classifyAiError(), extractStatus(), getAiErrorMessage(), isOffline(), clampRetryAfter() (+70 more)
+Cohesion: 0.03
+Nodes (18): a_(), bh, Dh(), eA(), el(), GE(), Gh(), lv() (+10 more)
### Community 9 - "Community 9"
-Cohesion: 0.02
-Nodes (85): handleBuildLocalRag(), handleWebllmDownload(), isCustomOllamaModel(), countWords(), enrichProjectIndex(), extractCharacterNames(), getDb(), indexProject() (+77 more)
+Cohesion: 0.01
+Nodes (81): categoryFromMessage(), categoryFromStatus(), classificationFor(), classifyAiError(), extractStatus(), getAiErrorMessage(), isOffline(), clampRetryAfter() (+73 more)
### Community 10 - "Community 10"
Cohesion: 0.02
-Nodes (64): AnalyticsBootstrap(), App(), ViewLoader(), BookPreviewView(), useCommandExecutor(), CopilotLauncher(), Header(), useAppDispatch() (+56 more)
+Nodes (78): AiModeIndicator(), item(), getLocalUser(), getRandomColor(), handleKeyDown(), sanitizeRoomInput(), stripControlChars(), loadFeatureFlagsState() (+70 more)
### Community 11 - "Community 11"
-Cohesion: 0.03
-Nodes (80): AiModeIndicator(), assertCloudAiAllowed(), assertCloudAiAllowedSync(), assertLoraLocalOnly(), _deduplicateRequest(), generateTextSingleProvider(), isAbortError(), _pendingKey() (+72 more)
+Cohesion: 0.02
+Nodes (64): AnalyticsBootstrap(), App(), ViewLoader(), BookPreviewView(), useCommandExecutor(), CopilotLauncher(), Header(), useAppDispatch() (+56 more)
### Community 12 - "Community 12"
-Cohesion: 0.03
-Nodes (69): collectSubtreeIds(), installDesktopMenu(), installCloseToTray(), installDesktopTray(), buildTimeoutSignal(), createWorldScriptFetch(), resolveTauriFetch(), routeTask() (+61 more)
+Cohesion: 0.02
+Nodes (58): AdaptiveAiEngine, _clearLatencyHistory(), estimateLatency(), getTaskConfig(), selectModelForBackend(), start(), clearBenchmarkResults(), getLastBenchmarkResults() (+50 more)
### Community 13 - "Community 13"
-Cohesion: 0.04
-Nodes (53): getActiveAiMode(), getLocalFallbackModel(), getOpenRouterFallbackProvider(), getOpenRouterModel(), isCloudOnlyMode(), isOffline(), notifyLocalModelsReady(), shouldRouteLocally() (+45 more)
+Cohesion: 0.03
+Nodes (76): countWords(), enrichProjectIndex(), extractCharacterNames(), getDb(), indexProject(), listIndexedProjects(), removeProjectIndex(), semanticSearchProjects() (+68 more)
### Community 14 - "Community 14"
Cohesion: 0.03
-Nodes (51): AdaptiveAiEngine, _clearLatencyHistory(), estimateLatency(), getTaskConfig(), selectModelForBackend(), pipeline(), pipeline(), start() (+43 more)
+Nodes (43): CollabEncryptionRequiredError, CollaborationService, resolveWebRtcSignalingUrls(), MockDoc, MockWebrtcProvider, createAttentionPipeline(), createComputePipeline(), createKvCachePipeline() (+35 more)
### Community 15 - "Community 15"
Cohesion: 0.04
-Nodes (24): assertNoSeriousViolations(), navigateToCollaborationSettings(), connectSrcTokens(), group1(), tauriCsp(), webCsp(), Bv, jb() (+16 more)
+Nodes (53): applyTextEdit(), applyReviewEditsToSection(), containsDisallowedControlChar(), isValidRange(), nearestFreeOccurrence(), planAcceptedManuscriptEdits(), validateProposedText(), collectSubtreeIds() (+45 more)
### Community 16 - "Community 16"
-Cohesion: 0.09
-Nodes (16): FsAssetStore, FsCodexStore, countProjectWords(), decompressData(), decryptText(), deriveFileSystemCryptoKey(), encryptText(), FsCore (+8 more)
+Cohesion: 0.07
+Nodes (22): FsAssetStore, FsCodexStore, deleteIdb(), formatStorageError(), initializeStorage(), resetAllDatabases(), countProjectWords(), decompressData() (+14 more)
### Community 17 - "Community 17"
Cohesion: 0.04
-Nodes (35): AudioNavigator, buildEncodedPayload(), makeCommands(), makeProjectData(), Hb(), makeContext(), makeLargeContext(), makeSection() (+27 more)
+Nodes (32): assertNoSeriousViolations(), navigateToCollaborationSettings(), connectSrcTokens(), group1(), tauriCsp(), webCsp(), clickNavItem(), ensureBlankProject() (+24 more)
### Community 18 - "Community 18"
Cohesion: 0.05
-Nodes (22): CollabEncryptionRequiredError, CollaborationService, resolveWebRtcSignalingUrls(), MockDoc, MockWebrtcProvider, createAttentionPipeline(), createComputePipeline(), createKvCachePipeline() (+14 more)
+Nodes (15): installDesktopMenu(), installCloseToTray(), installDesktopTray(), buildTimeoutSignal(), createWorldScriptFetch(), resolveTauriFetch(), StorageManager, registerTauriMenuHandler() (+7 more)
### Community 19 - "Community 19"
-Cohesion: 0.06
-Nodes (35): collect(), buildPaletteCommandModels(), collectAllDefinitions(), resolveTitle(), runCommandById(), id, install_app_menu(), run() (+27 more)
+Cohesion: 0.07
+Nodes (9): getFocusable(), onKeyDown(), onPointerUp(), k2, n2(), getFocusable(), handleEsc(), handleTabKey() (+1 more)
### Community 20 - "Community 20"
-Cohesion: 0.06
-Nodes (23): applyTextEdit(), applyReviewEditsToSection(), containsDisallowedControlChar(), isValidRange(), nearestFreeOccurrence(), planAcceptedManuscriptEdits(), validateProposedText(), mockT() (+15 more)
+Cohesion: 0.07
+Nodes (26): applyPreset(), async(), close(), isSidebar(), onKey(), onPointerDown(), readMode(), writeMode() (+18 more)
### Community 21 - "Community 21"
Cohesion: 0.07
-Nodes (9): getFocusable(), onKeyDown(), onPointerUp(), k2, n2(), getFocusable(), handleEsc(), handleTabKey() (+1 more)
+Nodes (13): createBrowserProForgeCapability(), buildPorts(), runCopilotDiagnostic(), buildNormManuscriptExport(), paginateNormLines(), stripLightMarkdown(), wrapParagraphToLines(), wrapPlainTextToNormLines() (+5 more)
### Community 22 - "Community 22"
-Cohesion: 0.06
-Nodes (29): applyPreset(), async(), close(), isSidebar(), onKey(), onPointerDown(), readMode(), writeMode() (+21 more)
+Cohesion: 0.07
+Nodes (16): smallProject(), buildCharacter(), buildLargeManuscript(), buildParagraph(), buildSectionContent(), buildWorld(), countWords(), makeRng() (+8 more)
### Community 23 - "Community 23"
-Cohesion: 0.07
-Nodes (13): createBrowserProForgeCapability(), buildPorts(), runCopilotDiagnostic(), buildNormManuscriptExport(), paginateNormLines(), stripLightMarkdown(), wrapParagraphToLines(), wrapPlainTextToNormLines() (+5 more)
+Cohesion: 0.09
+Nodes (21): collect(), DeadLetterQueue, openDlqDb(), storeClear(), storeGetAll(), analyze_text(), count_sentences(), count_syllables() (+13 more)
### Community 24 - "Community 24"
-Cohesion: 0.11
-Nodes (1): StorageManager
-
-### Community 25 - "Community 25"
-Cohesion: 0.07
-Nodes (16): smallProject(), buildCharacter(), buildLargeManuscript(), buildParagraph(), buildSectionContent(), buildWorld(), countWords(), makeRng() (+8 more)
-
-### Community 26 - "Community 26"
Cohesion: 0.23
Nodes (3): LS, xn(), aa
-### Community 27 - "Community 27"
-Cohesion: 0.1
-Nodes (11): handleEvaluate(), ScoreGauge(), comparePromptOutputs(), computeStyleConsistencyScore(), cosineSimilarity(), getEmbeddingService(), meanSimilarity(), scoreLabel() (+3 more)
-
-### Community 28 - "Community 28"
+### Community 25 - "Community 25"
Cohesion: 0.14
Nodes (21): handleToggle(), handleDelete(), handleFileChange(), activateAdapter(), clearDatasetEntries(), deactivateAdapter(), deleteAdapter(), exportAdapter() (+13 more)
-### Community 29 - "Community 29"
-Cohesion: 0.16
+### Community 26 - "Community 26"
+Cohesion: 0.15
Nodes (14): buildExcerpt(), extractCharacters(), extractManuscriptSections(), searchAcrossProjectIndex(), searchAcrossProjects(), normalizeSearch(), scoreAgainstQuery(), subsequenceScore() (+6 more)
-### Community 30 - "Community 30"
+### Community 27 - "Community 27"
Cohesion: 0.35
Nodes (2): cc, Gb()
-### Community 33 - "Community 33"
-Cohesion: 0.29
-Nodes (1): PriorityTaskQueue
-
-### Community 34 - "Community 34"
-Cohesion: 0.22
-Nodes (4): accessibilityPresetDefaults(), normalizeAccessibilitySettings(), applyPreset(), baseSettings()
+### Community 28 - "Community 28"
+Cohesion: 0.17
+Nodes (8): check(), extractCatalogFlags(), extractHiddenFlags(), extractSectionFlags(), green(), grep(), hasRuntimeConsumption(), red()
-### Community 35 - "Community 35"
+### Community 31 - "Community 31"
Cohesion: 0.42
Nodes (6): emit(), main(), merge(), ProgressCallback, Emits JSON progress events on each training log step., train()
-### Community 36 - "Community 36"
+### Community 32 - "Community 32"
Cohesion: 0.25
Nodes (3): useManuscriptLayout(), useMediaQuery(), useResizablePanels()
-### Community 38 - "Community 38"
+### Community 34 - "Community 34"
Cohesion: 0.29
Nodes (5): MockAudioContext, MockBufferSource, MockGain, NonEndingSource, TrackingContext
-### Community 40 - "Community 40"
+### Community 36 - "Community 36"
Cohesion: 0.33
Nodes (3): useSwipeGesture(), useWriterLayout(), useWriterViewContext()
-### Community 41 - "Community 41"
+### Community 37 - "Community 37"
Cohesion: 0.53
Nodes (4): buildWebNNExecutionProviders(), detectWebNN(), isDirectMLAvailable(), isDirectMLHeuristic()
-### Community 42 - "Community 42"
+### Community 38 - "Community 38"
Cohesion: 0.7
Nodes (4): check_cuda_and_vram(), check_package(), check_python_version(), main()
-### Community 45 - "Community 45"
+### Community 41 - "Community 41"
Cohesion: 0.5
Nodes (3): createStorageMock(), setupStorage(), SpeechSynthesisUtteranceMock
-### Community 47 - "Community 47"
+### Community 43 - "Community 43"
Cohesion: 0.4
Nodes (4): Room, SignalingConn, WebrtcConn, WebrtcProvider
-### Community 48 - "Community 48"
+### Community 44 - "Community 44"
Cohesion: 0.4
Nodes (2): useDashboardContext(), DashboardHeader()
-### Community 51 - "Community 51"
+### Community 47 - "Community 47"
Cohesion: 0.6
Nodes (4): applyFormula(), computeReadabilitySnapshot(), estimateSyllables(), getSyllablePattern()
-### Community 54 - "Community 54"
+### Community 50 - "Community 50"
Cohesion: 0.67
Nodes (2): makeConfig(), startPipelinePayload()
-### Community 61 - "Community 61"
+### Community 55 - "Community 55"
Cohesion: 0.67
-Nodes (2): defaultProject(), setProjectData()
+Nodes (2): make(), noop()
-### Community 63 - "Community 63"
+### Community 58 - "Community 58"
Cohesion: 0.67
-Nodes (2): make(), noop()
+Nodes (2): defaultProject(), setProjectData()
-### Community 65 - "Community 65"
+### Community 61 - "Community 61"
Cohesion: 0.83
Nodes (3): makeChars(), makeProject(), makeWorlds()
-### Community 66 - "Community 66"
+### Community 62 - "Community 62"
Cohesion: 0.83
Nodes (3): emptyChars(), emptyWorlds(), makeProject()
-### Community 67 - "Community 67"
+### Community 63 - "Community 63"
Cohesion: 0.5
-Nodes (2): ManuscriptDesktopLayout(), useManuscriptViewContext()
+Nodes (3): AsyncDuckDB, AsyncDuckDBConnection, ConsoleLogger
-### Community 68 - "Community 68"
+### Community 67 - "Community 67"
Cohesion: 0.5
-Nodes (3): AsyncDuckDB, AsyncDuckDBConnection, ConsoleLogger
+Nodes (2): ManuscriptDesktopLayout(), useManuscriptViewContext()
-### Community 73 - "Community 73"
+### Community 69 - "Community 69"
Cohesion: 0.67
Nodes (2): getQuestionsForArchetype(), getTemplateForArchetype()
-### Community 78 - "Community 78"
+### Community 70 - "Community 70"
+Cohesion: 0.83
+Nodes (3): esc(), inline(), renderExportMarkdownToHtml()
+
+### Community 75 - "Community 75"
Cohesion: 0.67
Nodes (1): makeSection()
-### Community 84 - "Community 84"
+### Community 81 - "Community 81"
Cohesion: 0.67
Nodes (1): MockGoogleGenAI
-### Community 87 - "Community 87"
+### Community 84 - "Community 84"
Cohesion: 0.67
Nodes (1): makeDeps()
-### Community 98 - "Community 98"
+### Community 95 - "Community 95"
Cohesion: 0.67
Nodes (1): TaskError
-### Community 131 - "Community 131"
+### Community 128 - "Community 128"
Cohesion: 1.0
Nodes (1): MockIntersectionObserver
-### Community 143 - "Community 143"
+### Community 139 - "Community 139"
Cohesion: 1.0
Nodes (1): MockWorker
-### Community 149 - "Community 149"
+### Community 145 - "Community 145"
Cohesion: 1.0
Nodes (1): MockBroadcastChannel
-### Community 182 - "Community 182"
+### Community 178 - "Community 178"
Cohesion: 1.0
Nodes (1): MockIntersectionObserver
-### Community 230 - "Community 230"
+### Community 226 - "Community 226"
Cohesion: 1.0
Nodes (1): MockWorker
-### Community 270 - "Community 270"
+### Community 266 - "Community 266"
Cohesion: 1.0
Nodes (1): FileSystemService
-### Community 275 - "Community 275"
+### Community 271 - "Community 271"
Cohesion: 1.0
Nodes (1): IndexedDBService
-### Community 743 - "Community 743"
+### Community 740 - "Community 740"
Cohesion: 1.0
Nodes (1): Remove ANSI escape codes from text.
-### Community 744 - "Community 744"
+### Community 741 - "Community 741"
Cohesion: 1.0
Nodes (1): Remove timestamp strings from text.
-### Community 745 - "Community 745"
+### Community 742 - "Community 742"
Cohesion: 1.0
Nodes (1): Replace long base64 strings with placeholder.
-### Community 746 - "Community 746"
+### Community 743 - "Community 743"
Cohesion: 1.0
Nodes (1): Remove NPM/pnpm warning lines.
-### Community 747 - "Community 747"
+### Community 744 - "Community 744"
Cohesion: 1.0
Nodes (1): Remove redundant success messages.
-### Community 748 - "Community 748"
+### Community 745 - "Community 745"
Cohesion: 1.0
Nodes (1): Apply all preprocessing steps to reduce token payload.
-### Community 749 - "Community 749"
+### Community 746 - "Community 746"
Cohesion: 1.0
Nodes (1): Extract only error-related sections from log.
-### Community 750 - "Community 750"
+### Community 747 - "Community 747"
Cohesion: 1.0
Nodes (1): Pydantic models for CI Analyzer structured output. QNBS-v3: These models enforce
-### Community 751 - "Community 751"
+### Community 748 - "Community 748"
Cohesion: 1.0
Nodes (1): Structured CI error for VS Code problem matcher integration.
-### Community 752 - "Community 752"
+### Community 749 - "Community 749"
Cohesion: 1.0
Nodes (1): Vitest JSON test result structure.
-### Community 753 - "Community 753"
+### Community 750 - "Community 750"
Cohesion: 1.0
Nodes (1): Full Vitest JSON report structure.
-### Community 754 - "Community 754"
+### Community 751 - "Community 751"
Cohesion: 1.0
Nodes (1): Stryker per-file mutation report.
-### Community 755 - "Community 755"
+### Community 752 - "Community 752"
Cohesion: 1.0
Nodes (1): Full Stryker JSON report structure.
-### Community 756 - "Community 756"
+### Community 753 - "Community 753"
Cohesion: 1.0
Nodes (1): Initialize OpenRouter client for Poolside Laguna model.
-### Community 757 - "Community 757"
+### Community 754 - "Community 754"
Cohesion: 1.0
Nodes (1): Analyze Vitest JSON report and raw logs for errors.
-### Community 758 - "Community 758"
+### Community 755 - "Community 755"
Cohesion: 1.0
Nodes (1): Analyze Stryker JSON report for surviving mutants.
-### Community 759 - "Community 759"
+### Community 756 - "Community 756"
Cohesion: 1.0
Nodes (1): Send preprocessed errors to LLM for analysis.
-### Community 760 - "Community 760"
+### Community 757 - "Community 757"
Cohesion: 1.0
Nodes (1): Format errors for VS Code problem matcher.
-### Community 761 - "Community 761"
+### Community 758 - "Community 758"
Cohesion: 1.0
Nodes (1): Main entry point for CI analyzer.
-### Community 762 - "Community 762"
+### Community 759 - "Community 759"
Cohesion: 1.0
Nodes (1): Execute gh CLI command and return parsed JSON output.
-### Community 763 - "Community 763"
+### Community 760 - "Community 760"
Cohesion: 1.0
Nodes (1): Get the ID of the most recent failed CI run.
-### Community 764 - "Community 764"
+### Community 761 - "Community 761"
Cohesion: 1.0
Nodes (1): Download a specific artifact from a workflow run.
-### Community 765 - "Community 765"
+### Community 762 - "Community 762"
Cohesion: 1.0
Nodes (1): Get raw logs from a failed workflow run.
-### Community 766 - "Community 766"
+### Community 763 - "Community 763"
Cohesion: 1.0
Nodes (1): Parse Vitest JSON report for failing tests.
-### Community 767 - "Community 767"
+### Community 764 - "Community 764"
Cohesion: 1.0
Nodes (1): Parse Stryker JSON report for surviving mutants.
## Knowledge Gaps
- **53 isolated node(s):** `Emits JSON progress events on each training log step.`, `qb`, `v2`, `MockIntersectionObserver`, `MockWorker` (+48 more)
These have ≤1 connection - possible missing edges or undocumented components.
-- **Thin community `Community 24`** (36 nodes): `storageService.ts`, `StorageManager`, `.clearApiKey()`, `.clearGeminiApiKey()`, `.constructor()`, `.deleteAllBinderAssetsForProject()`, `.deleteBinderAsset()`, `.deleteImage()`, `.deleteProject()`, `.deleteRagVectors()`, `.deleteSnapshot()`, `.deleteStoryCodex()`, `.getApiKey()`, `.getBackend()`, `.getBinderAsset()`, `.getGeminiApiKey()`, `.getImage()`, `.getRagVectors()`, `.getSnapshotData()`, `.getStoryCodex()`, `.hasSavedData()`, `.initializeBackend()`, `.listBinderAssetIds()`, `.listProjects()`, `.listSnapshots()`, `.loadProject()`, `.loadSettings()`, `.saveApiKey()`, `.saveBinderAsset()`, `.saveGeminiApiKey()`, `.saveImage()`, `.saveProject()`, `.saveRagVectors()`, `.saveSettings()`, `.saveSnapshot()`, `.saveStoryCodex()`
- Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 30`** (17 nodes): `cc`, `._applyAttribute()`, `._assert()`, `.constructor()`, `._eof()`, `._isWhitespace()`, `._next()`, `.parse()`, `._peek()`, `._readAttributes()`, `._readIdentifier()`, `._readRegex()`, `._readString()`, `._readStringOrRegex()`, `._skipWhitespace()`, `._throwError()`, `Gb()`
- Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 33`** (10 nodes): `taskQueue.ts`, `PriorityTaskQueue`, `.constructor()`, `.dequeue()`, `.effectivePriority()`, `.enqueue()`, `.peek()`, `.promoteStarvedTasks()`, `.stats()`, `.totalDepth()`
+- **Thin community `Community 27`** (17 nodes): `cc`, `._applyAttribute()`, `._assert()`, `.constructor()`, `._eof()`, `._isWhitespace()`, `._next()`, `.parse()`, `._peek()`, `._readAttributes()`, `._readIdentifier()`, `._readRegex()`, `._readString()`, `._readStringOrRegex()`, `._skipWhitespace()`, `._throwError()`, `Gb()`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 48`** (5 nodes): `DashboardHeader.tsx`, `DashboardContext.ts`, `useDashboardContext()`, `Chip()`, `DashboardHeader()`
+- **Thin community `Community 44`** (5 nodes): `DashboardHeader.tsx`, `DashboardContext.ts`, `useDashboardContext()`, `Chip()`, `DashboardHeader()`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 54`** (4 nodes): `makeConfig()`, `makeReviewItem()`, `startPipelinePayload()`, `proForgeSlice.test.ts`
+- **Thin community `Community 50`** (4 nodes): `makeConfig()`, `makeReviewItem()`, `startPipelinePayload()`, `proForgeSlice.test.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 61`** (4 nodes): `useDashboard.test.ts`, `defaultProject()`, `defaultSection()`, `setProjectData()`
+- **Thin community `Community 55`** (4 nodes): `make()`, `noop()`, `aiRetry.test.ts`, `aiRetry.test.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 63`** (4 nodes): `make()`, `noop()`, `aiRetry.test.ts`, `aiRetry.test.ts`
+- **Thin community `Community 58`** (4 nodes): `useDashboard.test.ts`, `defaultProject()`, `defaultSection()`, `setProjectData()`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 67`** (4 nodes): `ManuscriptDesktopLayout.tsx`, `ManuscriptViewContext.ts`, `ManuscriptDesktopLayout()`, `useManuscriptViewContext()`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 73`** (4 nodes): `getAllTemplates()`, `getQuestionsForArchetype()`, `getTemplateForArchetype()`, `characterInterviewTemplates.ts`
+- **Thin community `Community 69`** (4 nodes): `getAllTemplates()`, `getQuestionsForArchetype()`, `getTemplateForArchetype()`, `characterInterviewTemplates.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 78`** (3 nodes): `makeSection()`, `plotBoardService.test.ts`, `plotBoardService.test.ts`
+- **Thin community `Community 75`** (3 nodes): `makeSection()`, `plotBoardService.test.ts`, `plotBoardService.test.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 84`** (3 nodes): `makeStream()`, `MockGoogleGenAI`, `geminiService.test.ts`
+- **Thin community `Community 81`** (3 nodes): `makeStream()`, `MockGoogleGenAI`, `geminiService.test.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 87`** (3 nodes): `makeDeps()`, `aiSuggestions.test.ts`, `aiSuggestions.test.ts`
+- **Thin community `Community 84`** (3 nodes): `makeDeps()`, `aiSuggestions.test.ts`, `aiSuggestions.test.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 98`** (3 nodes): `types.ts`, `TaskError`, `.constructor()`
+- **Thin community `Community 95`** (3 nodes): `types.ts`, `TaskError`, `.constructor()`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 131`** (2 nodes): `MockIntersectionObserver`, `BookPreviewView.test.tsx`
+- **Thin community `Community 128`** (2 nodes): `MockIntersectionObserver`, `BookPreviewView.test.tsx`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 143`** (2 nodes): `MockWorker`, `duckdbClient.test.ts`
+- **Thin community `Community 139`** (2 nodes): `MockWorker`, `duckdbClient.test.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 149`** (2 nodes): `MockBroadcastChannel`, `tabLeaderElection.test.ts`
+- **Thin community `Community 145`** (2 nodes): `MockBroadcastChannel`, `tabLeaderElection.test.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 182`** (2 nodes): `useBookPreviewView.test.ts`, `MockIntersectionObserver`
+- **Thin community `Community 178`** (2 nodes): `useBookPreviewView.test.ts`, `MockIntersectionObserver`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 230`** (2 nodes): `workerPool.test.ts`, `MockWorker`
+- **Thin community `Community 226`** (2 nodes): `workerPool.test.ts`, `MockWorker`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 270`** (2 nodes): `FileSystemService`, `index.ts`
+- **Thin community `Community 266`** (2 nodes): `FileSystemService`, `index.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 275`** (2 nodes): `IndexedDBService`, `index.ts`
+- **Thin community `Community 271`** (2 nodes): `IndexedDBService`, `index.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 743`** (1 nodes): `Remove ANSI escape codes from text.`
+- **Thin community `Community 740`** (1 nodes): `Remove ANSI escape codes from text.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 744`** (1 nodes): `Remove timestamp strings from text.`
+- **Thin community `Community 741`** (1 nodes): `Remove timestamp strings from text.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 745`** (1 nodes): `Replace long base64 strings with placeholder.`
+- **Thin community `Community 742`** (1 nodes): `Replace long base64 strings with placeholder.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 746`** (1 nodes): `Remove NPM/pnpm warning lines.`
+- **Thin community `Community 743`** (1 nodes): `Remove NPM/pnpm warning lines.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 747`** (1 nodes): `Remove redundant success messages.`
+- **Thin community `Community 744`** (1 nodes): `Remove redundant success messages.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 748`** (1 nodes): `Apply all preprocessing steps to reduce token payload.`
+- **Thin community `Community 745`** (1 nodes): `Apply all preprocessing steps to reduce token payload.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 749`** (1 nodes): `Extract only error-related sections from log.`
+- **Thin community `Community 746`** (1 nodes): `Extract only error-related sections from log.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 750`** (1 nodes): `Pydantic models for CI Analyzer structured output. QNBS-v3: These models enforce`
+- **Thin community `Community 747`** (1 nodes): `Pydantic models for CI Analyzer structured output. QNBS-v3: These models enforce`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 751`** (1 nodes): `Structured CI error for VS Code problem matcher integration.`
+- **Thin community `Community 748`** (1 nodes): `Structured CI error for VS Code problem matcher integration.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 752`** (1 nodes): `Vitest JSON test result structure.`
+- **Thin community `Community 749`** (1 nodes): `Vitest JSON test result structure.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 753`** (1 nodes): `Full Vitest JSON report structure.`
+- **Thin community `Community 750`** (1 nodes): `Full Vitest JSON report structure.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 754`** (1 nodes): `Stryker per-file mutation report.`
+- **Thin community `Community 751`** (1 nodes): `Stryker per-file mutation report.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 755`** (1 nodes): `Full Stryker JSON report structure.`
+- **Thin community `Community 752`** (1 nodes): `Full Stryker JSON report structure.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 756`** (1 nodes): `Initialize OpenRouter client for Poolside Laguna model.`
+- **Thin community `Community 753`** (1 nodes): `Initialize OpenRouter client for Poolside Laguna model.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 757`** (1 nodes): `Analyze Vitest JSON report and raw logs for errors.`
+- **Thin community `Community 754`** (1 nodes): `Analyze Vitest JSON report and raw logs for errors.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 758`** (1 nodes): `Analyze Stryker JSON report for surviving mutants.`
+- **Thin community `Community 755`** (1 nodes): `Analyze Stryker JSON report for surviving mutants.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 759`** (1 nodes): `Send preprocessed errors to LLM for analysis.`
+- **Thin community `Community 756`** (1 nodes): `Send preprocessed errors to LLM for analysis.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 760`** (1 nodes): `Format errors for VS Code problem matcher.`
+- **Thin community `Community 757`** (1 nodes): `Format errors for VS Code problem matcher.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 761`** (1 nodes): `Main entry point for CI analyzer.`
+- **Thin community `Community 758`** (1 nodes): `Main entry point for CI analyzer.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 762`** (1 nodes): `Execute gh CLI command and return parsed JSON output.`
+- **Thin community `Community 759`** (1 nodes): `Execute gh CLI command and return parsed JSON output.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 763`** (1 nodes): `Get the ID of the most recent failed CI run.`
+- **Thin community `Community 760`** (1 nodes): `Get the ID of the most recent failed CI run.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 764`** (1 nodes): `Download a specific artifact from a workflow run.`
+- **Thin community `Community 761`** (1 nodes): `Download a specific artifact from a workflow run.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 765`** (1 nodes): `Get raw logs from a failed workflow run.`
+- **Thin community `Community 762`** (1 nodes): `Get raw logs from a failed workflow run.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 766`** (1 nodes): `Parse Vitest JSON report for failing tests.`
+- **Thin community `Community 763`** (1 nodes): `Parse Vitest JSON report for failing tests.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 767`** (1 nodes): `Parse Stryker JSON report for surviving mutants.`
+- **Thin community `Community 764`** (1 nodes): `Parse Stryker JSON report for surviving mutants.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
## Suggested Questions
_Questions this graph is uniquely positioned to answer:_
-- **Why does `mt()` connect `Community 2` to `Community 0`, `Community 1`, `Community 4`, `Community 5`, `Community 7`, `Community 13`, `Community 17`, `Community 20`, `Community 22`, `Community 23`, `Community 26`?**
- _High betweenness centrality (0.084) - this node is a cross-community bridge._
-- **Why does `t()` connect `Community 4` to `Community 1`, `Community 2`, `Community 5`, `Community 6`, `Community 7`, `Community 8`, `Community 9`, `Community 10`, `Community 11`, `Community 12`, `Community 19`, `Community 22`, `Community 28`?**
- _High betweenness centrality (0.075) - this node is a cross-community bridge._
-- **Why does `fn()` connect `Community 8` to `Community 1`, `Community 5`, `Community 6`, `Community 13`, `Community 16`, `Community 17`, `Community 22`, `Community 23`?**
- _High betweenness centrality (0.052) - this node is a cross-community bridge._
+- **Why does `mt()` connect `Community 2` to `Community 0`, `Community 1`, `Community 3`, `Community 4`, `Community 5`, `Community 7`, `Community 8`, `Community 12`, `Community 15`, `Community 20`, `Community 21`, `Community 24`?**
+ _High betweenness centrality (0.085) - this node is a cross-community bridge._
+- **Why does `t()` connect `Community 4` to `Community 0`, `Community 1`, `Community 2`, `Community 6`, `Community 9`, `Community 10`, `Community 11`, `Community 12`, `Community 18`, `Community 20`, `Community 25`?**
+ _High betweenness centrality (0.073) - this node is a cross-community bridge._
+- **Why does `wx()` connect `Community 0` to `Community 2`, `Community 4`, `Community 5`, `Community 7`, `Community 14`, `Community 16`, `Community 20`?**
+ _High betweenness centrality (0.046) - this node is a cross-community bridge._
- **Are the 87 inferred relationships involving `mt()` (e.g. with `pE()` and `xE()`) actually correct?**
_`mt()` has 87 INFERRED edges - model-reasoned connections that need verification._
-- **Are the 61 inferred relationships involving `fn()` (e.g. with `makeMediaQuery()` and `MockSpeechRecognition()`) actually correct?**
- _`fn()` has 61 INFERRED edges - model-reasoned connections that need verification._
+- **Are the 62 inferred relationships involving `fn()` (e.g. with `makeMediaQuery()` and `MockSpeechRecognition()`) actually correct?**
+ _`fn()` has 62 INFERRED edges - model-reasoned connections that need verification._
- **Are the 50 inferred relationships involving `t()` (e.g. with `.flattenForSingleProject()` and `fr()`) actually correct?**
_`t()` has 50 INFERRED edges - model-reasoned connections that need verification._
- **What connects `Emits JSON progress events on each training log step.`, `qb`, `v2` to the rest of the system?**
diff --git a/index.css b/index.css
index 7aa907467..9efcc76bf 100644
--- a/index.css
+++ b/index.css
@@ -1017,3 +1017,43 @@ body.is-desktop
--glass-border: var(--sc-border-subtle);
}
}
+
+/* QNBS-v3 (PR2): scoped typography for the Export view's "Rendered" preview. DOMPurify strips
+ class/style from the sanitized markdown HTML, so these element selectors carry the styling. */
+.export-rendered-preview h1 {
+ font-size: 1.8em;
+ font-weight: 700;
+ text-align: center;
+ margin: 0.6em 0;
+}
+.export-rendered-preview h2 {
+ font-size: 1.4em;
+ font-weight: 700;
+ border-bottom: 1px solid var(--sc-border-subtle);
+ padding-bottom: 0.2em;
+ margin: 1em 0 0.4em;
+}
+.export-rendered-preview h3 {
+ font-size: 1.15em;
+ font-weight: 600;
+ margin: 0.8em 0 0.3em;
+}
+.export-rendered-preview p {
+ margin: 0.5em 0;
+ line-height: 1.7;
+}
+.export-rendered-preview ul {
+ margin: 0.5em 0;
+ padding-inline-start: 1.4em;
+ list-style: disc;
+}
+.export-rendered-preview img {
+ max-width: 100%;
+ height: auto;
+}
+.export-rendered-preview code {
+ font-family: monospace;
+ background: var(--sc-surface-overlay);
+ padding: 0 0.25em;
+ border-radius: 3px;
+}
diff --git a/locales/ar/export.json b/locales/ar/export.json
index ff8098921..68087a86f 100644
--- a/locales/ar/export.json
+++ b/locales/ar/export.json
@@ -87,6 +87,9 @@
"export.pasteSection.textPlaceholder": "الصق نصًا من Google Docs أو Notion هنا (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "عنوان الفصل (اختياري)",
"export.preview.noContent": "اختر محتوى لرؤية معاينة.",
+ "export.preview.modeLabel": "وضع المعاينة",
+ "export.preview.modeText": "نص",
+ "export.preview.modeRendered": "معروض",
"export.preview.title": "معاينة حيّة",
"export.title": "جناح النشر والتصدير",
"export.toggleSection": "تبديل ظهور {{title}}",
diff --git a/locales/de/export.json b/locales/de/export.json
index ebb892893..1ac696dd2 100644
--- a/locales/de/export.json
+++ b/locales/de/export.json
@@ -87,6 +87,9 @@
"export.pasteSection.textPlaceholder": "Text aus Google Docs oder Notion hier einfügen (Strg+V)…",
"export.pasteSection.titlePlaceholder": "Kapiteltitel (optional)",
"export.preview.noContent": "Wählen Sie Inhalte aus, um eine Vorschau zu sehen.",
+ "export.preview.modeLabel": "Vorschaumodus",
+ "export.preview.modeText": "Text",
+ "export.preview.modeRendered": "Gerendert",
"export.preview.title": "Live-Vorschau",
"export.title": "Publishing-Suite",
"export.toggleSection": "Sichtbarkeit für {{title}} umschalten",
diff --git a/locales/el/export.json b/locales/el/export.json
index a75396a6c..b7ae67f0c 100644
--- a/locales/el/export.json
+++ b/locales/el/export.json
@@ -87,6 +87,9 @@
"export.pasteSection.textPlaceholder": "Επικολλήστε εδώ κείμενο από τα Έγγραφα Google ή το Notion (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Τίτλος κεφαλαίου (προαιρετικό)",
"export.preview.noContent": "Επιλέξτε περιεχόμενο για να δείτε μια προεπισκόπηση.",
+ "export.preview.modeLabel": "Λειτουργία προεπισκόπησης",
+ "export.preview.modeText": "Κείμενο",
+ "export.preview.modeRendered": "Αποδοθέν",
"export.preview.title": "Ζωντανή προεπισκόπηση",
"export.title": "Εξαγωγή Publishing Suite",
"export.toggleSection": "Εναλλαγή ορατότητας για {{title}}",
diff --git a/locales/en/export.json b/locales/en/export.json
index 7ef959105..63f244255 100644
--- a/locales/en/export.json
+++ b/locales/en/export.json
@@ -6,6 +6,9 @@
"export.options.copied": "Copied!",
"export.preview.title": "Live Preview",
"export.preview.noContent": "Select content to see a preview.",
+ "export.preview.modeLabel": "Preview mode",
+ "export.preview.modeText": "Text",
+ "export.preview.modeRendered": "Rendered",
"export.loglineLabel": "Logline",
"export.charactersLabel": "Characters",
"export.appearanceLabel": "Appearance",
diff --git a/locales/es/export.json b/locales/es/export.json
index 9435050a1..73093b87f 100644
--- a/locales/es/export.json
+++ b/locales/es/export.json
@@ -87,6 +87,9 @@
"export.pasteSection.textPlaceholder": "Pega texto de Google Docs o Notion aquí (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Título del capítulo (opcional)",
"export.preview.noContent": "Selecciona contenido para ver una vista previa.",
+ "export.preview.modeLabel": "Modo de vista previa",
+ "export.preview.modeText": "Texto",
+ "export.preview.modeRendered": "Renderizado",
"export.preview.title": "Vista previa en vivo",
"export.title": "Suite de publicación Export",
"export.toggleSection": "Alternar visibilidad para {{title}}",
diff --git a/locales/eu/export.json b/locales/eu/export.json
index 50c7b80ad..92666ca28 100644
--- a/locales/eu/export.json
+++ b/locales/eu/export.json
@@ -87,6 +87,9 @@
"export.pasteSection.textPlaceholder": "Itsatsi Google Docs edo Notion-eko testua hemen (Ktrl+V)...",
"export.pasteSection.titlePlaceholder": "Kapituluaren izenburua (aukerakoa)",
"export.preview.noContent": "Hautatu edukia aurrebista ikusteko.",
+ "export.preview.modeLabel": "Aurrebista modua",
+ "export.preview.modeText": "Testua",
+ "export.preview.modeRendered": "Errendatua",
"export.preview.title": "Zuzeneko aurrebista",
"export.title": "Esportatu Argitalpen Suite",
"export.toggleSection": "Aldatu ikusgaitasuna {{title}}",
diff --git a/locales/fa/export.json b/locales/fa/export.json
index 2a804c1c7..9dbd35b38 100644
--- a/locales/fa/export.json
+++ b/locales/fa/export.json
@@ -87,6 +87,9 @@
"export.pasteSection.textPlaceholder": "متن را از Google Docs یا Notion در اینجا جایگذاری کنید (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "عنوان فصل (اختیاری)",
"export.preview.noContent": "برای مشاهده پیش نمایش، محتوا را انتخاب کنید.",
+ "export.preview.modeLabel": "حالت پیشنمایش",
+ "export.preview.modeText": "متن",
+ "export.preview.modeRendered": "رندرشده",
"export.preview.title": "پیش نمایش زنده",
"export.title": "Export Publishing Suite",
"export.toggleSection": "تغییر وضعیت دید برای {{title}}",
diff --git a/locales/fi/export.json b/locales/fi/export.json
index 2fb9abf6e..7ef0b4e80 100644
--- a/locales/fi/export.json
+++ b/locales/fi/export.json
@@ -87,6 +87,9 @@
"export.pasteSection.textPlaceholder": "Liitä teksti Google Docsista tai Notionista tähän (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Luvun otsikko (valinnainen)",
"export.preview.noContent": "Valitse sisältö nähdäksesi esikatselun.",
+ "export.preview.modeLabel": "Esikatselutila",
+ "export.preview.modeText": "Teksti",
+ "export.preview.modeRendered": "Renderöity",
"export.preview.title": "Live-esikatselu",
"export.title": "Vie Publishing Suite",
"export.toggleSection": "Vaihda näkyvyys {{title}}",
diff --git a/locales/fr/export.json b/locales/fr/export.json
index bad2ee2ee..717f1cc08 100644
--- a/locales/fr/export.json
+++ b/locales/fr/export.json
@@ -87,6 +87,9 @@
"export.pasteSection.textPlaceholder": "Collez du texte depuis Google Docs ou Notion ici (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Titre du chapitre (facultatif)",
"export.preview.noContent": "Sélectionnez du contenu pour voir un aperçu.",
+ "export.preview.modeLabel": "Mode d'aperçu",
+ "export.preview.modeText": "Texte",
+ "export.preview.modeRendered": "Rendu",
"export.preview.title": "Aperçu en direct",
"export.title": "Suite de publication Export",
"export.toggleSection": "Basculer la visibilité pour {{title}}",
diff --git a/locales/he/export.json b/locales/he/export.json
index 8c7af45df..652d7a969 100644
--- a/locales/he/export.json
+++ b/locales/he/export.json
@@ -87,6 +87,9 @@
"export.pasteSection.textPlaceholder": "הדביקו כאן טקסט מ‑Google Docs או מ‑Notion (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "כותרת הפרק (אופציונלי)",
"export.preview.noContent": "בחרו תוכן כדי לראות תצוגה מקדימה.",
+ "export.preview.modeLabel": "מצב תצוגה מקדימה",
+ "export.preview.modeText": "טקסט",
+ "export.preview.modeRendered": "מעובד",
"export.preview.title": "תצוגה מקדימה חיה",
"export.title": "חבילת הוצאה לאור וייצוא",
"export.toggleSection": "החלפת נראות עבור {{title}}",
diff --git a/locales/hu/export.json b/locales/hu/export.json
index 339a0b332..b2f5092e5 100644
--- a/locales/hu/export.json
+++ b/locales/hu/export.json
@@ -87,6 +87,9 @@
"export.pasteSection.textPlaceholder": "Illesszen be szöveget a Google Docsból vagy a Notionból (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Fejezet címe (nem kötelező)",
"export.preview.noContent": "Az előnézet megtekintéséhez válassza ki a tartalmat.",
+ "export.preview.modeLabel": "Előnézeti mód",
+ "export.preview.modeText": "Szöveg",
+ "export.preview.modeRendered": "Megjelenített",
"export.preview.title": "Élő előnézet",
"export.title": "Export Publishing Suite",
"export.toggleSection": "{{title}} láthatóságának váltása",
diff --git a/locales/is/export.json b/locales/is/export.json
index 1ff7766fe..1fbe41a8a 100644
--- a/locales/is/export.json
+++ b/locales/is/export.json
@@ -87,6 +87,9 @@
"export.pasteSection.textPlaceholder": "Límdu texta úr Google skjölum eða hugmynd hér (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Kaflaheiti (valfrjálst)",
"export.preview.noContent": "Veldu efni til að sjá forskoðun.",
+ "export.preview.modeLabel": "Forskoðunarhamur",
+ "export.preview.modeText": "Texti",
+ "export.preview.modeRendered": "Myndað",
"export.preview.title": "Forskoðun í beinni",
"export.title": "Flytja út útgáfusvítu",
"export.toggleSection": "Skipta á sýnileika fyrir {{title}}",
diff --git a/locales/it/export.json b/locales/it/export.json
index 132dc3dcf..c2b0106b8 100644
--- a/locales/it/export.json
+++ b/locales/it/export.json
@@ -87,6 +87,9 @@
"export.pasteSection.textPlaceholder": "Incolla testo da Google Docs o Notion qui (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Titolo capitolo (opzionale)",
"export.preview.noContent": "Seleziona contenuto per vedere un'anteprima.",
+ "export.preview.modeLabel": "Modalità anteprima",
+ "export.preview.modeText": "Testo",
+ "export.preview.modeRendered": "Renderizzato",
"export.preview.title": "Anteprima in diretta",
"export.title": "Suite di pubblicazione Export",
"export.toggleSection": "Attiva/disattiva visibilità per {{title}}",
diff --git a/locales/ja/export.json b/locales/ja/export.json
index 0dec028b5..e6113cef2 100644
--- a/locales/ja/export.json
+++ b/locales/ja/export.json
@@ -87,6 +87,9 @@
"export.pasteSection.textPlaceholder": "Google ドキュメントまたは Notion からここにテキストを貼り付けます (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "章のタイトル (オプション)",
"export.preview.noContent": "コンテンツを選択してプレビューを表示します。",
+ "export.preview.modeLabel": "プレビューモード",
+ "export.preview.modeText": "テキスト",
+ "export.preview.modeRendered": "レンダリング",
"export.preview.title": "ライブプレビュー",
"export.title": "エクスポート Publishing Suite",
"export.toggleSection": "{{title}} の公開設定を切り替えます",
diff --git a/locales/ko/export.json b/locales/ko/export.json
index 0e04ea627..34c05c7c8 100644
--- a/locales/ko/export.json
+++ b/locales/ko/export.json
@@ -87,6 +87,9 @@
"export.pasteSection.textPlaceholder": "Google Docs 또는 Notion의 텍스트를 여기에 붙여넣습니다(Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "장 제목(선택사항)",
"export.preview.noContent": "미리보기를 보려면 콘텐츠를 선택하세요.",
+ "export.preview.modeLabel": "미리 보기 모드",
+ "export.preview.modeText": "텍스트",
+ "export.preview.modeRendered": "렌더링됨",
"export.preview.title": "실시간 미리보기",
"export.title": "출판 제품군 내보내기",
"export.toggleSection": "{{title}}에 대한 공개 여부를 전환합니다.",
diff --git a/locales/pt/export.json b/locales/pt/export.json
index 0d1f47a62..66a64b171 100644
--- a/locales/pt/export.json
+++ b/locales/pt/export.json
@@ -87,6 +87,9 @@
"export.pasteSection.textPlaceholder": "Cole o texto do Google Docs ou Notion aqui (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Título do capítulo (opcional)",
"export.preview.noContent": "Selecione o conteúdo para ver uma prévia.",
+ "export.preview.modeLabel": "Modo de pré-visualização",
+ "export.preview.modeText": "Texto",
+ "export.preview.modeRendered": "Renderizado",
"export.preview.title": "Visualização ao vivo",
"export.title": "Exportar Publishing Suite",
"export.toggleSection": "Alternar visibilidade para {{title}}",
diff --git a/locales/ru/export.json b/locales/ru/export.json
index 4b33124e8..c8c4e0f5f 100644
--- a/locales/ru/export.json
+++ b/locales/ru/export.json
@@ -87,6 +87,9 @@
"export.pasteSection.textPlaceholder": "Вставьте сюда текст из Google Docs или Notion (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Название главы (необязательно)",
"export.preview.noContent": "Выберите контент, чтобы просмотреть его.",
+ "export.preview.modeLabel": "Режим предпросмотра",
+ "export.preview.modeText": "Текст",
+ "export.preview.modeRendered": "С разметкой",
"export.preview.title": "Живой просмотр",
"export.title": "Экспортный издательский пакет",
"export.toggleSection": "Переключить видимость для {{title}}",
diff --git a/locales/sv/export.json b/locales/sv/export.json
index 23a02e33d..2fcd73737 100644
--- a/locales/sv/export.json
+++ b/locales/sv/export.json
@@ -87,6 +87,9 @@
"export.pasteSection.textPlaceholder": "Klistra in text från Google Dokument eller Notion här (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Kapiteltitel (valfritt)",
"export.preview.noContent": "Välj innehåll för att se en förhandsvisning.",
+ "export.preview.modeLabel": "Förhandsgranskningsläge",
+ "export.preview.modeText": "Text",
+ "export.preview.modeRendered": "Renderad",
"export.preview.title": "Live Preview",
"export.title": "Exportera Publishing Suite",
"export.toggleSection": "Växla synlighet för {{title}}",
diff --git a/locales/zh/export.json b/locales/zh/export.json
index f3426e547..584d66576 100644
--- a/locales/zh/export.json
+++ b/locales/zh/export.json
@@ -87,6 +87,9 @@
"export.pasteSection.textPlaceholder": "将 Google Docs 或 Notion 中的文本粘贴到此处 (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "章节标题(可选)",
"export.preview.noContent": "选择内容以查看预览。",
+ "export.preview.modeLabel": "预览模式",
+ "export.preview.modeText": "文本",
+ "export.preview.modeRendered": "渲染",
"export.preview.title": "实时预览",
"export.title": "导出 Publishing Suite",
"export.toggleSection": "切换 {{title}} 的可见性",
diff --git a/public/locales/ar/bundle.json b/public/locales/ar/bundle.json
index 734928be5..e541bb77f 100644
--- a/public/locales/ar/bundle.json
+++ b/public/locales/ar/bundle.json
@@ -1060,6 +1060,9 @@
"export.pasteSection.textPlaceholder": "الصق نصًا من Google Docs أو Notion هنا (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "عنوان الفصل (اختياري)",
"export.preview.noContent": "اختر محتوى لرؤية معاينة.",
+ "export.preview.modeLabel": "وضع المعاينة",
+ "export.preview.modeText": "نص",
+ "export.preview.modeRendered": "معروض",
"export.preview.title": "معاينة حيّة",
"export.title": "جناح النشر والتصدير",
"export.toggleSection": "تبديل ظهور {{title}}",
diff --git a/public/locales/de/bundle.json b/public/locales/de/bundle.json
index 20cd7f8bc..fc5588c5f 100644
--- a/public/locales/de/bundle.json
+++ b/public/locales/de/bundle.json
@@ -1060,6 +1060,9 @@
"export.pasteSection.textPlaceholder": "Text aus Google Docs oder Notion hier einfügen (Strg+V)…",
"export.pasteSection.titlePlaceholder": "Kapiteltitel (optional)",
"export.preview.noContent": "Wählen Sie Inhalte aus, um eine Vorschau zu sehen.",
+ "export.preview.modeLabel": "Vorschaumodus",
+ "export.preview.modeText": "Text",
+ "export.preview.modeRendered": "Gerendert",
"export.preview.title": "Live-Vorschau",
"export.title": "Publishing-Suite",
"export.toggleSection": "Sichtbarkeit für {{title}} umschalten",
diff --git a/public/locales/el/bundle.json b/public/locales/el/bundle.json
index 93aeebc54..55295a3d0 100644
--- a/public/locales/el/bundle.json
+++ b/public/locales/el/bundle.json
@@ -1060,6 +1060,9 @@
"export.pasteSection.textPlaceholder": "Επικολλήστε εδώ κείμενο από τα Έγγραφα Google ή το Notion (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Τίτλος κεφαλαίου (προαιρετικό)",
"export.preview.noContent": "Επιλέξτε περιεχόμενο για να δείτε μια προεπισκόπηση.",
+ "export.preview.modeLabel": "Λειτουργία προεπισκόπησης",
+ "export.preview.modeText": "Κείμενο",
+ "export.preview.modeRendered": "Αποδοθέν",
"export.preview.title": "Ζωντανή προεπισκόπηση",
"export.title": "Εξαγωγή Publishing Suite",
"export.toggleSection": "Εναλλαγή ορατότητας για {{title}}",
diff --git a/public/locales/en/bundle.json b/public/locales/en/bundle.json
index bcc57bd63..89340298f 100644
--- a/public/locales/en/bundle.json
+++ b/public/locales/en/bundle.json
@@ -979,6 +979,9 @@
"export.options.copied": "Copied!",
"export.preview.title": "Live Preview",
"export.preview.noContent": "Select content to see a preview.",
+ "export.preview.modeLabel": "Preview mode",
+ "export.preview.modeText": "Text",
+ "export.preview.modeRendered": "Rendered",
"export.loglineLabel": "Logline",
"export.charactersLabel": "Characters",
"export.appearanceLabel": "Appearance",
diff --git a/public/locales/es/bundle.json b/public/locales/es/bundle.json
index 6ffb951bc..45acb0849 100644
--- a/public/locales/es/bundle.json
+++ b/public/locales/es/bundle.json
@@ -1060,6 +1060,9 @@
"export.pasteSection.textPlaceholder": "Pega texto de Google Docs o Notion aquí (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Título del capítulo (opcional)",
"export.preview.noContent": "Selecciona contenido para ver una vista previa.",
+ "export.preview.modeLabel": "Modo de vista previa",
+ "export.preview.modeText": "Texto",
+ "export.preview.modeRendered": "Renderizado",
"export.preview.title": "Vista previa en vivo",
"export.title": "Suite de publicación Export",
"export.toggleSection": "Alternar visibilidad para {{title}}",
diff --git a/public/locales/eu/bundle.json b/public/locales/eu/bundle.json
index f27cd167a..c6de49e32 100644
--- a/public/locales/eu/bundle.json
+++ b/public/locales/eu/bundle.json
@@ -1060,6 +1060,9 @@
"export.pasteSection.textPlaceholder": "Itsatsi Google Docs edo Notion-eko testua hemen (Ktrl+V)...",
"export.pasteSection.titlePlaceholder": "Kapituluaren izenburua (aukerakoa)",
"export.preview.noContent": "Hautatu edukia aurrebista ikusteko.",
+ "export.preview.modeLabel": "Aurrebista modua",
+ "export.preview.modeText": "Testua",
+ "export.preview.modeRendered": "Errendatua",
"export.preview.title": "Zuzeneko aurrebista",
"export.title": "Esportatu Argitalpen Suite",
"export.toggleSection": "Aldatu ikusgaitasuna {{title}}",
diff --git a/public/locales/fa/bundle.json b/public/locales/fa/bundle.json
index 9b2e9580a..6790d0e5f 100644
--- a/public/locales/fa/bundle.json
+++ b/public/locales/fa/bundle.json
@@ -1060,6 +1060,9 @@
"export.pasteSection.textPlaceholder": "متن را از Google Docs یا Notion در اینجا جایگذاری کنید (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "عنوان فصل (اختیاری)",
"export.preview.noContent": "برای مشاهده پیش نمایش، محتوا را انتخاب کنید.",
+ "export.preview.modeLabel": "حالت پیشنمایش",
+ "export.preview.modeText": "متن",
+ "export.preview.modeRendered": "رندرشده",
"export.preview.title": "پیش نمایش زنده",
"export.title": "Export Publishing Suite",
"export.toggleSection": "تغییر وضعیت دید برای {{title}}",
diff --git a/public/locales/fi/bundle.json b/public/locales/fi/bundle.json
index 1e4375fd3..80ea1fe08 100644
--- a/public/locales/fi/bundle.json
+++ b/public/locales/fi/bundle.json
@@ -1060,6 +1060,9 @@
"export.pasteSection.textPlaceholder": "Liitä teksti Google Docsista tai Notionista tähän (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Luvun otsikko (valinnainen)",
"export.preview.noContent": "Valitse sisältö nähdäksesi esikatselun.",
+ "export.preview.modeLabel": "Esikatselutila",
+ "export.preview.modeText": "Teksti",
+ "export.preview.modeRendered": "Renderöity",
"export.preview.title": "Live-esikatselu",
"export.title": "Vie Publishing Suite",
"export.toggleSection": "Vaihda näkyvyys {{title}}",
diff --git a/public/locales/fr/bundle.json b/public/locales/fr/bundle.json
index 3abb0ef24..8c95e45c5 100644
--- a/public/locales/fr/bundle.json
+++ b/public/locales/fr/bundle.json
@@ -1060,6 +1060,9 @@
"export.pasteSection.textPlaceholder": "Collez du texte depuis Google Docs ou Notion ici (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Titre du chapitre (facultatif)",
"export.preview.noContent": "Sélectionnez du contenu pour voir un aperçu.",
+ "export.preview.modeLabel": "Mode d'aperçu",
+ "export.preview.modeText": "Texte",
+ "export.preview.modeRendered": "Rendu",
"export.preview.title": "Aperçu en direct",
"export.title": "Suite de publication Export",
"export.toggleSection": "Basculer la visibilité pour {{title}}",
diff --git a/public/locales/he/bundle.json b/public/locales/he/bundle.json
index a091b6414..c73f28d9e 100644
--- a/public/locales/he/bundle.json
+++ b/public/locales/he/bundle.json
@@ -1060,6 +1060,9 @@
"export.pasteSection.textPlaceholder": "הדביקו כאן טקסט מ‑Google Docs או מ‑Notion (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "כותרת הפרק (אופציונלי)",
"export.preview.noContent": "בחרו תוכן כדי לראות תצוגה מקדימה.",
+ "export.preview.modeLabel": "מצב תצוגה מקדימה",
+ "export.preview.modeText": "טקסט",
+ "export.preview.modeRendered": "מעובד",
"export.preview.title": "תצוגה מקדימה חיה",
"export.title": "חבילת הוצאה לאור וייצוא",
"export.toggleSection": "החלפת נראות עבור {{title}}",
diff --git a/public/locales/hu/bundle.json b/public/locales/hu/bundle.json
index 7d2556b81..b6137e12b 100644
--- a/public/locales/hu/bundle.json
+++ b/public/locales/hu/bundle.json
@@ -1060,6 +1060,9 @@
"export.pasteSection.textPlaceholder": "Illesszen be szöveget a Google Docsból vagy a Notionból (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Fejezet címe (nem kötelező)",
"export.preview.noContent": "Az előnézet megtekintéséhez válassza ki a tartalmat.",
+ "export.preview.modeLabel": "Előnézeti mód",
+ "export.preview.modeText": "Szöveg",
+ "export.preview.modeRendered": "Megjelenített",
"export.preview.title": "Élő előnézet",
"export.title": "Export Publishing Suite",
"export.toggleSection": "{{title}} láthatóságának váltása",
diff --git a/public/locales/is/bundle.json b/public/locales/is/bundle.json
index 362b75a63..852dfcd06 100644
--- a/public/locales/is/bundle.json
+++ b/public/locales/is/bundle.json
@@ -1060,6 +1060,9 @@
"export.pasteSection.textPlaceholder": "Límdu texta úr Google skjölum eða hugmynd hér (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Kaflaheiti (valfrjálst)",
"export.preview.noContent": "Veldu efni til að sjá forskoðun.",
+ "export.preview.modeLabel": "Forskoðunarhamur",
+ "export.preview.modeText": "Texti",
+ "export.preview.modeRendered": "Myndað",
"export.preview.title": "Forskoðun í beinni",
"export.title": "Flytja út útgáfusvítu",
"export.toggleSection": "Skipta á sýnileika fyrir {{title}}",
diff --git a/public/locales/it/bundle.json b/public/locales/it/bundle.json
index 97bcffa63..42929743c 100644
--- a/public/locales/it/bundle.json
+++ b/public/locales/it/bundle.json
@@ -1060,6 +1060,9 @@
"export.pasteSection.textPlaceholder": "Incolla testo da Google Docs o Notion qui (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Titolo capitolo (opzionale)",
"export.preview.noContent": "Seleziona contenuto per vedere un'anteprima.",
+ "export.preview.modeLabel": "Modalità anteprima",
+ "export.preview.modeText": "Testo",
+ "export.preview.modeRendered": "Renderizzato",
"export.preview.title": "Anteprima in diretta",
"export.title": "Suite di pubblicazione Export",
"export.toggleSection": "Attiva/disattiva visibilità per {{title}}",
diff --git a/public/locales/ja/bundle.json b/public/locales/ja/bundle.json
index 12d96a803..452ca0034 100644
--- a/public/locales/ja/bundle.json
+++ b/public/locales/ja/bundle.json
@@ -1060,6 +1060,9 @@
"export.pasteSection.textPlaceholder": "Google ドキュメントまたは Notion からここにテキストを貼り付けます (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "章のタイトル (オプション)",
"export.preview.noContent": "コンテンツを選択してプレビューを表示します。",
+ "export.preview.modeLabel": "プレビューモード",
+ "export.preview.modeText": "テキスト",
+ "export.preview.modeRendered": "レンダリング",
"export.preview.title": "ライブプレビュー",
"export.title": "エクスポート Publishing Suite",
"export.toggleSection": "{{title}} の公開設定を切り替えます",
diff --git a/public/locales/ko/bundle.json b/public/locales/ko/bundle.json
index 07c464312..da2ff3891 100644
--- a/public/locales/ko/bundle.json
+++ b/public/locales/ko/bundle.json
@@ -1060,6 +1060,9 @@
"export.pasteSection.textPlaceholder": "Google Docs 또는 Notion의 텍스트를 여기에 붙여넣습니다(Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "장 제목(선택사항)",
"export.preview.noContent": "미리보기를 보려면 콘텐츠를 선택하세요.",
+ "export.preview.modeLabel": "미리 보기 모드",
+ "export.preview.modeText": "텍스트",
+ "export.preview.modeRendered": "렌더링됨",
"export.preview.title": "실시간 미리보기",
"export.title": "출판 제품군 내보내기",
"export.toggleSection": "{{title}}에 대한 공개 여부를 전환합니다.",
diff --git a/public/locales/pt/bundle.json b/public/locales/pt/bundle.json
index 5c47266ee..a054af26b 100644
--- a/public/locales/pt/bundle.json
+++ b/public/locales/pt/bundle.json
@@ -1060,6 +1060,9 @@
"export.pasteSection.textPlaceholder": "Cole o texto do Google Docs ou Notion aqui (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Título do capítulo (opcional)",
"export.preview.noContent": "Selecione o conteúdo para ver uma prévia.",
+ "export.preview.modeLabel": "Modo de pré-visualização",
+ "export.preview.modeText": "Texto",
+ "export.preview.modeRendered": "Renderizado",
"export.preview.title": "Visualização ao vivo",
"export.title": "Exportar Publishing Suite",
"export.toggleSection": "Alternar visibilidade para {{title}}",
diff --git a/public/locales/ru/bundle.json b/public/locales/ru/bundle.json
index 8bd828af0..366b4c333 100644
--- a/public/locales/ru/bundle.json
+++ b/public/locales/ru/bundle.json
@@ -1060,6 +1060,9 @@
"export.pasteSection.textPlaceholder": "Вставьте сюда текст из Google Docs или Notion (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Название главы (необязательно)",
"export.preview.noContent": "Выберите контент, чтобы просмотреть его.",
+ "export.preview.modeLabel": "Режим предпросмотра",
+ "export.preview.modeText": "Текст",
+ "export.preview.modeRendered": "С разметкой",
"export.preview.title": "Живой просмотр",
"export.title": "Экспортный издательский пакет",
"export.toggleSection": "Переключить видимость для {{title}}",
diff --git a/public/locales/sv/bundle.json b/public/locales/sv/bundle.json
index cc5b8ad3d..f70af9f64 100644
--- a/public/locales/sv/bundle.json
+++ b/public/locales/sv/bundle.json
@@ -1060,6 +1060,9 @@
"export.pasteSection.textPlaceholder": "Klistra in text från Google Dokument eller Notion här (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Kapiteltitel (valfritt)",
"export.preview.noContent": "Välj innehåll för att se en förhandsvisning.",
+ "export.preview.modeLabel": "Förhandsgranskningsläge",
+ "export.preview.modeText": "Text",
+ "export.preview.modeRendered": "Renderad",
"export.preview.title": "Live Preview",
"export.title": "Exportera Publishing Suite",
"export.toggleSection": "Växla synlighet för {{title}}",
diff --git a/public/locales/zh/bundle.json b/public/locales/zh/bundle.json
index 3beb6faaf..0f8b836ce 100644
--- a/public/locales/zh/bundle.json
+++ b/public/locales/zh/bundle.json
@@ -1060,6 +1060,9 @@
"export.pasteSection.textPlaceholder": "将 Google Docs 或 Notion 中的文本粘贴到此处 (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "章节标题(可选)",
"export.preview.noContent": "选择内容以查看预览。",
+ "export.preview.modeLabel": "预览模式",
+ "export.preview.modeText": "文本",
+ "export.preview.modeRendered": "渲染",
"export.preview.title": "实时预览",
"export.title": "导出 Publishing Suite",
"export.toggleSection": "切换 {{title}} 的可见性",
diff --git a/services/epubApiService.ts b/services/epubApiService.ts
index bdefecdcd..0eafecf50 100644
--- a/services/epubApiService.ts
+++ b/services/epubApiService.ts
@@ -21,11 +21,65 @@ const esc = (s: string) =>
(c) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[c] ?? c,
);
-const toParagraphs = (text: string) =>
- text
+// QNBS-v3: markdown image token — ``. Only data: URLs are bundled into the EPUB; remote
+// URLs are non-conformant inside an EPUB container, so they degrade to their alt text.
+const IMG_RE = /!\[([^\]]*)\]\(([^)\s]+)\)/g;
+
+/** Registers a data-URL image into the EPUB, returning its in-package href (or null to skip). */
+type ImageRegistrar = (src: string) => string | null;
+
+interface OebpsFolder {
+ file: (name: string, data: string, opts?: { base64?: boolean }) => unknown;
+}
+
+/** Book-scoped image registrar: emits data-URL images under images/, dedupes, appends to manifest. */
+function createImageRegistrar(oebps: OebpsFolder, manifest: string[]): ImageRegistrar {
+ let n = 0;
+ const cache = new Map();
+ return (src: string): string | null => {
+ if (!src.startsWith('data:image/')) return null;
+ const cached = cache.get(src);
+ if (cached) return cached;
+ const meta = src.split(';')[0] ?? '';
+ const mime = meta.split(':')[1] ?? 'application/octet-stream';
+ const ext = (mime.split('/')[1] ?? 'bin').replace('jpeg', 'jpg').replace('svg+xml', 'svg');
+ const base64 = src.split(',')[1] ?? '';
+ if (!base64) return null;
+ n += 1;
+ const href = `images/img${n}.${ext}`;
+ oebps.file(href, base64, { base64: true });
+ manifest.push(` `);
+ cache.set(src, href);
+ return href;
+ };
+}
+
+/** Escape a line of text while rewriting markdown image tokens to bundled
(or alt fallback). */
+function renderLine(line: string, registerImage: ImageRegistrar): string {
+ let out = '';
+ let last = 0;
+ for (const m of line.matchAll(IMG_RE)) {
+ const idx = m.index ?? 0;
+ out += esc(line.slice(last, idx));
+ const alt = m[1] ?? '';
+ const href = registerImage(m[2] ?? '');
+ out += href ? `
` : esc(alt);
+ last = idx + m[0].length;
+ }
+ out += esc(line.slice(last));
+ return out;
+}
+
+/** Split text into blocks, rewriting any inline/standalone markdown images to bundled
. */
+function renderBody(text: string, registerImage: ImageRegistrar): string {
+ return text
.split('\n')
- .map((l) => (l.trim() ? `
${esc(l.trim())}
` : ''))
+ .map((l) => {
+ const trimmed = l.trim();
+ return trimmed ? `${renderLine(trimmed, registerImage)}
` : '';
+ })
.join('');
+}
export async function exportEpub(options: EpubExportOptions): Promise {
const { title, author, synopsis, chapters, lang = 'de', coverImage, compileProfile } = options;
@@ -67,9 +121,14 @@ p{margin:.6em 0;text-indent:1.6em}p:first-child,.no-indent{text-indent:0}
const manifest: string[] = [
` `,
``,
+ // QNBS-v3: NCX for EPUB-2 backward compatibility (older e-readers ignore the EPUB-3 nav doc).
+ ` `,
];
const spine: string[] = [];
- const tocEntries: string[] = [];
+ // QNBS-v3: structured TOC entries — drive BOTH the EPUB-3 nav.xhtml and the EPUB-2 toc.ncx.
+ const navList: Array<{ href: string; label: string }> = [];
+ // QNBS-v3: bundle data-URL images referenced from manuscript/front-matter markdown into the EPUB.
+ const registerImage = createImageRegistrar(oebps, manifest);
// Optional cover image
if (coverImage?.startsWith('data:image/')) {
@@ -96,7 +155,7 @@ p{margin:.6em 0;text-indent:1.6em}p:first-child,.no-indent{text-indent:0}
// Title page — optional Markdown body from compile profile (Scrivener-style front matter).
const titleInner = compileProfile?.titlePageMarkdown?.trim()
- ? `${toParagraphs(compileProfile.titlePageMarkdown)}`
+ ? `${renderBody(compileProfile.titlePageMarkdown, registerImage)}`
: `${esc(title)}
${author ? `${esc(author)}
` : ''}`;
oebps.file(
@@ -108,7 +167,7 @@ ${author ? `${esc(author)}
` : ''} `;
);
manifest.push(` `);
spine.push(` `);
- tocEntries.push(`${esc(title)} `);
+ navList.push({ href: 'titlepage.xhtml', label: title });
let extraIdx = 0;
const pushCompilePage = (navLabel: string, markdown: string) => {
@@ -119,11 +178,11 @@ ${author ? `${esc(author)}
` : ''}`;
`
${esc(navLabel)}
-${esc(navLabel)}
${toParagraphs(markdown)}`,
+${esc(navLabel)}
${renderBody(markdown, registerImage)}