@sutrata/editor 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +674 -0
- package/dist/ai/OnboardingDialog.d.ts +6 -0
- package/dist/ai/OnboardingDialog.js +115 -0
- package/dist/ai/VoiceConfirmDialog.d.ts +9 -0
- package/dist/ai/VoiceConfirmDialog.js +37 -0
- package/dist/ai/VoiceToolbar.d.ts +2 -0
- package/dist/ai/VoiceToolbar.js +177 -0
- package/dist/ai/ai-client.d.ts +71 -0
- package/dist/ai/ai-client.js +494 -0
- package/dist/ai/commands.d.ts +12 -0
- package/dist/ai/commands.js +140 -0
- package/dist/ai/generated-providers.json +3696 -0
- package/dist/ai/prompts.d.ts +25 -0
- package/dist/ai/prompts.js +59 -0
- package/dist/ai/voice-service.d.ts +15 -0
- package/dist/ai/voice-service.js +81 -0
- package/dist/autocomplete/AutocompletePlugin.d.ts +2 -0
- package/dist/autocomplete/AutocompletePlugin.js +19 -0
- package/dist/autocomplete/suggestions.d.ts +25 -0
- package/dist/autocomplete/suggestions.js +126 -0
- package/dist/context/DocumentContext.d.ts +68 -0
- package/dist/context/DocumentContext.js +605 -0
- package/dist/desktop-api.d.ts +40 -0
- package/dist/editor/EditorView.d.ts +2 -0
- package/dist/editor/EditorView.js +78 -0
- package/dist/editor/SelectionMenu.d.ts +2 -0
- package/dist/editor/SelectionMenu.js +102 -0
- package/dist/editor/attr-pencil-plugin.d.ts +17 -0
- package/dist/editor/attr-pencil-plugin.js +158 -0
- package/dist/editor/character-decoration-plugin.d.ts +26 -0
- package/dist/editor/character-decoration-plugin.js +77 -0
- package/dist/editor/character-view.d.ts +35 -0
- package/dist/editor/character-view.js +112 -0
- package/dist/editor/editor-bus.d.ts +14 -0
- package/dist/editor/editor-bus.js +39 -0
- package/dist/editor/find-highlight-plugin.d.ts +7 -0
- package/dist/editor/find-highlight-plugin.js +57 -0
- package/dist/editor/frontmatter-field-view.d.ts +10 -0
- package/dist/editor/frontmatter-field-view.js +48 -0
- package/dist/editor/frontmatter-field.d.ts +21 -0
- package/dist/editor/frontmatter-field.js +116 -0
- package/dist/editor/grapheme-cursor.d.ts +10 -0
- package/dist/editor/grapheme-cursor.js +104 -0
- package/dist/editor/ime-plugin.d.ts +18 -0
- package/dist/editor/ime-plugin.js +71 -0
- package/dist/editor/insert-helper.d.ts +1 -0
- package/dist/editor/insert-helper.js +42 -0
- package/dist/editor/keymap.d.ts +3 -0
- package/dist/editor/keymap.js +131 -0
- package/dist/editor/language-class-plugin.d.ts +7 -0
- package/dist/editor/language-class-plugin.js +75 -0
- package/dist/editor/plugins.d.ts +1 -0
- package/dist/editor/plugins.js +25 -0
- package/dist/editor/prosemirror-to-sutra.d.ts +2 -0
- package/dist/editor/prosemirror-to-sutra.js +208 -0
- package/dist/editor/scene-heading-view.d.ts +27 -0
- package/dist/editor/scene-heading-view.js +136 -0
- package/dist/editor/schema.d.ts +3 -0
- package/dist/editor/schema.js +135 -0
- package/dist/editor/sutra-to-prosemirror.d.ts +3 -0
- package/dist/editor/sutra-to-prosemirror.js +154 -0
- package/dist/editor/transliterate-input.d.ts +10 -0
- package/dist/editor/transliterate-input.js +88 -0
- package/dist/extensions/storage-adapter.d.ts +59 -0
- package/dist/extensions/storage-adapter.js +9 -0
- package/dist/extensions/types.d.ts +73 -0
- package/dist/extensions/types.js +12 -0
- package/dist/file/docx-exporter.d.ts +8 -0
- package/dist/file/docx-exporter.js +494 -0
- package/dist/file/docx-importer.d.ts +10 -0
- package/dist/file/docx-importer.js +283 -0
- package/dist/file/print-paginator.d.ts +29 -0
- package/dist/file/print-paginator.js +289 -0
- package/dist/file/templates.d.ts +2 -0
- package/dist/file/templates.js +66 -0
- package/dist/file/workflow-reports.d.ts +34 -0
- package/dist/file/workflow-reports.js +719 -0
- package/dist/findreplace/FindReplace.d.ts +2 -0
- package/dist/findreplace/FindReplace.js +164 -0
- package/dist/findreplace/find-engine.d.ts +29 -0
- package/dist/findreplace/find-engine.js +69 -0
- package/dist/findreplace/scroll-to-match.d.ts +29 -0
- package/dist/findreplace/scroll-to-match.js +74 -0
- package/dist/fonts/tofu-detect.d.ts +1 -0
- package/dist/fonts/tofu-detect.js +48 -0
- package/dist/i18n/LanguageContext.d.ts +10 -0
- package/dist/i18n/LanguageContext.js +174 -0
- package/dist/i18n/language-detect.d.ts +1 -0
- package/dist/i18n/language-detect.js +58 -0
- package/dist/i18n/useTranslation.d.ts +11 -0
- package/dist/i18n/useTranslation.js +60 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +5 -0
- package/dist/locales/bn.json +143 -0
- package/dist/locales/en.json +143 -0
- package/dist/locales/gu.json +143 -0
- package/dist/locales/hi.json +143 -0
- package/dist/locales/kn.json +143 -0
- package/dist/locales/ml.json +143 -0
- package/dist/locales/mr.json +143 -0
- package/dist/locales/or.json +143 -0
- package/dist/locales/pa.json +143 -0
- package/dist/locales/si.json +143 -0
- package/dist/locales/ta.json +143 -0
- package/dist/locales/te.json +143 -0
- package/dist/navigator/SceneNavigator.d.ts +2 -0
- package/dist/navigator/SceneNavigator.js +612 -0
- package/dist/navigator/StatisticsDialog.d.ts +6 -0
- package/dist/navigator/StatisticsDialog.js +146 -0
- package/dist/navigator/scene-list.d.ts +16 -0
- package/dist/navigator/scene-list.js +70 -0
- package/dist/settings/SettingsDialog.d.ts +6 -0
- package/dist/settings/SettingsDialog.js +147 -0
- package/dist/shell/AppBar.d.ts +2 -0
- package/dist/shell/AppBar.js +34 -0
- package/dist/shell/AppShell.d.ts +2 -0
- package/dist/shell/AppShell.js +30 -0
- package/dist/shell/ConfirmDialog.d.ts +16 -0
- package/dist/shell/ConfirmDialog.js +23 -0
- package/dist/shell/ElementToolbar.d.ts +2 -0
- package/dist/shell/ElementToolbar.js +30 -0
- package/dist/shell/LanguageStatus.d.ts +2 -0
- package/dist/shell/LanguageStatus.js +65 -0
- package/dist/shell/StatusBar.d.ts +2 -0
- package/dist/shell/StatusBar.js +54 -0
- package/dist/shell/SutrataLogo.d.ts +8 -0
- package/dist/shell/SutrataLogo.js +7 -0
- package/dist/shell/Toast.d.ts +12 -0
- package/dist/shell/Toast.js +21 -0
- package/dist/shell/ToolbarButton.d.ts +11 -0
- package/dist/shell/ToolbarButton.js +4 -0
- package/dist/shell/VersionHistory.d.ts +12 -0
- package/dist/shell/VersionHistory.js +89 -0
- package/dist/shell/Watermark.d.ts +3 -0
- package/dist/shell/Watermark.js +10 -0
- package/dist/shell/fonts/fonts.css +1133 -0
- package/dist/shell/icons.d.ts +45 -0
- package/dist/shell/icons.js +51 -0
- package/dist/shell/toolbar-actions.d.ts +6 -0
- package/dist/shell/toolbar-actions.js +58 -0
- package/dist/source/SourceView.d.ts +1 -0
- package/dist/source/SourceView.js +106 -0
- package/dist/source/find-highlight-source.d.ts +14 -0
- package/dist/source/find-highlight-source.js +47 -0
- package/dist/source/sutra-lang.d.ts +2 -0
- package/dist/source/sutra-lang.js +97 -0
- package/dist/spellcheck/dictionaries.d.ts +9 -0
- package/dist/spellcheck/dictionaries.js +16 -0
- package/dist/spellcheck/hunspell.d.ts +23 -0
- package/dist/spellcheck/hunspell.js +94 -0
- package/dist/spellcheck/spellcheck-plugin.d.ts +18 -0
- package/dist/spellcheck/spellcheck-plugin.js +75 -0
- package/dist/styles/StyleDialog.d.ts +6 -0
- package/dist/styles/StyleDialog.js +63 -0
- package/dist/styles/builtin-styles.d.ts +43 -0
- package/dist/styles/builtin-styles.js +131 -0
- package/dist/styles/css-adapter.d.ts +32 -0
- package/dist/styles/css-adapter.js +71 -0
- package/dist/styles/docx-adapter.d.ts +7 -0
- package/dist/styles/docx-adapter.js +84 -0
- package/dist/styles/embed-fonts.d.ts +20 -0
- package/dist/styles/embed-fonts.js +81 -0
- package/dist/styles/pagination.d.ts +19 -0
- package/dist/styles/pagination.js +22 -0
- package/dist/styles/print-adapter.d.ts +6 -0
- package/dist/styles/print-adapter.js +288 -0
- package/dist/styles/registry.d.ts +6 -0
- package/dist/styles/registry.js +14 -0
- package/dist/styles/screenplay.css +3006 -0
- package/dist/styles/script-ranges.d.ts +6 -0
- package/dist/styles/script-ranges.js +17 -0
- package/dist/styles/types.d.ts +93 -0
- package/dist/styles/types.js +18 -0
- package/dist/styles/validate.d.ts +12 -0
- package/dist/styles/validate.js +105 -0
- package/dist/templates/templates.d.ts +10 -0
- package/dist/templates/templates.js +181 -0
- package/dist/titlepage/ExportDialog.d.ts +1 -0
- package/dist/titlepage/ExportDialog.js +152 -0
- package/dist/titlepage/TitlePageDialog.d.ts +6 -0
- package/dist/titlepage/TitlePageDialog.js +96 -0
- package/dist/titlepage/frontmatter-form.d.ts +56 -0
- package/dist/titlepage/frontmatter-form.js +245 -0
- package/dist/titlepage/languages.d.ts +10 -0
- package/dist/titlepage/languages.js +31 -0
- package/dist/types.d.ts +6 -0
- package/dist/types.js +1 -0
- package/package.json +47 -0
- package/scripts/copy-assets.mjs +16 -0
- package/scripts/generate-providers.mjs +127 -0
- package/src/ai/OnboardingDialog.tsx +390 -0
- package/src/ai/VoiceConfirmDialog.tsx +137 -0
- package/src/ai/VoiceToolbar.tsx +321 -0
- package/src/ai/ai-client.ts +596 -0
- package/src/ai/commands.ts +164 -0
- package/src/ai/generated-providers.json +3696 -0
- package/src/ai/prompts.ts +62 -0
- package/src/ai/voice-service.ts +96 -0
- package/src/autocomplete/AutocompletePlugin.ts +21 -0
- package/src/autocomplete/suggestions.ts +147 -0
- package/src/context/DocumentContext.tsx +648 -0
- package/src/desktop-api.d.ts +40 -0
- package/src/editor/EditorView.tsx +82 -0
- package/src/editor/SelectionMenu.tsx +152 -0
- package/src/editor/attr-pencil-plugin.ts +172 -0
- package/src/editor/character-decoration-plugin.ts +104 -0
- package/src/editor/editor-bus.ts +51 -0
- package/src/editor/find-highlight-plugin.ts +68 -0
- package/src/editor/frontmatter-field-view.ts +52 -0
- package/src/editor/frontmatter-field.ts +115 -0
- package/src/editor/grapheme-cursor.ts +99 -0
- package/src/editor/ime-plugin.ts +85 -0
- package/src/editor/insert-helper.ts +43 -0
- package/src/editor/keymap.ts +124 -0
- package/src/editor/language-class-plugin.ts +91 -0
- package/src/editor/plugins.ts +26 -0
- package/src/editor/prosemirror-to-sutra.ts +192 -0
- package/src/editor/scene-heading-view.ts +147 -0
- package/src/editor/schema.ts +156 -0
- package/src/editor/sutra-to-prosemirror.ts +156 -0
- package/src/extensions/storage-adapter.ts +65 -0
- package/src/extensions/types.ts +60 -0
- package/src/file/docx-exporter.ts +585 -0
- package/src/file/docx-importer.ts +313 -0
- package/src/file/print-paginator.ts +301 -0
- package/src/file/templates.ts +73 -0
- package/src/file/workflow-reports.ts +820 -0
- package/src/findreplace/FindReplace.tsx +242 -0
- package/src/findreplace/find-engine.ts +97 -0
- package/src/findreplace/scroll-to-match.ts +89 -0
- package/src/fonts/tofu-detect.ts +53 -0
- package/src/i18n/LanguageContext.tsx +207 -0
- package/src/i18n/language-detect.ts +73 -0
- package/src/i18n/useTranslation.tsx +74 -0
- package/src/index.ts +27 -0
- package/src/locales/bn.json +143 -0
- package/src/locales/en.json +143 -0
- package/src/locales/gu.json +143 -0
- package/src/locales/hi.json +143 -0
- package/src/locales/kn.json +143 -0
- package/src/locales/ml.json +143 -0
- package/src/locales/mr.json +143 -0
- package/src/locales/or.json +143 -0
- package/src/locales/pa.json +143 -0
- package/src/locales/si.json +143 -0
- package/src/locales/ta.json +143 -0
- package/src/locales/te.json +143 -0
- package/src/navigator/SceneNavigator.tsx +844 -0
- package/src/navigator/StatisticsDialog.tsx +249 -0
- package/src/navigator/scene-list.ts +84 -0
- package/src/settings/SettingsDialog.tsx +303 -0
- package/src/shell/AppBar.tsx +354 -0
- package/src/shell/AppShell.tsx +71 -0
- package/src/shell/ConfirmDialog.tsx +71 -0
- package/src/shell/ElementToolbar.tsx +175 -0
- package/src/shell/LanguageStatus.tsx +101 -0
- package/src/shell/StatusBar.tsx +135 -0
- package/src/shell/SutrataLogo.tsx +89 -0
- package/src/shell/Toast.tsx +46 -0
- package/src/shell/ToolbarButton.tsx +30 -0
- package/src/shell/VersionHistory.tsx +212 -0
- package/src/shell/Watermark.tsx +9 -0
- package/src/shell/fonts/fonts.css +1133 -0
- package/src/shell/icons.tsx +335 -0
- package/src/shell/toolbar-actions.ts +59 -0
- package/src/source/SourceView.tsx +111 -0
- package/src/source/find-highlight-source.ts +57 -0
- package/src/source/sutra-lang.ts +121 -0
- package/src/spellcheck/dictionaries.ts +21 -0
- package/src/spellcheck/hunspell.ts +110 -0
- package/src/spellcheck/spellcheck-plugin.ts +83 -0
- package/src/styles/StyleDialog.tsx +148 -0
- package/src/styles/builtin-styles.ts +139 -0
- package/src/styles/css-adapter.ts +76 -0
- package/src/styles/docx-adapter.ts +109 -0
- package/src/styles/embed-fonts.ts +81 -0
- package/src/styles/pagination.ts +27 -0
- package/src/styles/print-adapter.ts +288 -0
- package/src/styles/registry.ts +20 -0
- package/src/styles/screenplay.css +3006 -0
- package/src/styles/script-ranges.ts +17 -0
- package/src/styles/types.ts +104 -0
- package/src/styles/validate.ts +114 -0
- package/src/templates/templates.ts +194 -0
- package/src/titlepage/ExportDialog.tsx +494 -0
- package/src/titlepage/TitlePageDialog.tsx +312 -0
- package/src/titlepage/frontmatter-form.ts +280 -0
- package/src/titlepage/languages.ts +37 -0
- package/src/types.ts +7 -0
- package/tests/AppBar.test.tsx +35 -0
- package/tests/AppShell.test.tsx +22 -0
- package/tests/ElementToolbar.test.tsx +36 -0
- package/tests/LanguageStatus.test.tsx +129 -0
- package/tests/SelectionMenu.test.tsx +71 -0
- package/tests/ToolbarButton.test.tsx +24 -0
- package/tests/ai-onboarding.test.ts +102 -0
- package/tests/ai-status.test.tsx +72 -0
- package/tests/ai-structured.test.ts +94 -0
- package/tests/autocomplete/AutocompletePlugin.test.ts +20 -0
- package/tests/autocomplete/suggestions.test.ts +106 -0
- package/tests/document-context.test.tsx +565 -0
- package/tests/docx-importer.test.ts +160 -0
- package/tests/editor/character-decoration-plugin.test.ts +101 -0
- package/tests/editor/character-extension.test.ts +44 -0
- package/tests/editor/grapheme-cursor.test.ts +118 -0
- package/tests/editor/ime-plugin.test.ts +72 -0
- package/tests/editor/inline-note-bridge.test.ts +32 -0
- package/tests/editor/language-class-plugin.test.ts +265 -0
- package/tests/editor/title-page.test.ts +124 -0
- package/tests/embed-fonts.test.ts +17 -0
- package/tests/exporters.test.ts +365 -0
- package/tests/findreplace/FindReplace.test.tsx +391 -0
- package/tests/findreplace/find-engine.test.ts +86 -0
- package/tests/findreplace/scroll-to-match.test.ts +50 -0
- package/tests/fonts/tofu-detect.test.ts +122 -0
- package/tests/i18n/LanguageContext.test.tsx +146 -0
- package/tests/i18n/language-detect.test.ts +54 -0
- package/tests/i18n/locale-parity.test.ts +25 -0
- package/tests/i18n/useTranslation.test.tsx +45 -0
- package/tests/keymap.test.ts +18 -0
- package/tests/navigator/SceneNavigator.test.tsx +177 -0
- package/tests/navigator/StatisticsDialog.test.tsx +63 -0
- package/tests/navigator/scene-list.test.ts +71 -0
- package/tests/print-paginator.test.ts +82 -0
- package/tests/shell/VersionHistory.test.tsx +129 -0
- package/tests/spellcheck/hunspell.test.ts +82 -0
- package/tests/spellcheck/spellcheck-plugin.test.ts +56 -0
- package/tests/styles.test.ts +315 -0
- package/tests/templates/templates.test.ts +83 -0
- package/tests/titlepage/TitlePageDialog.test.tsx +90 -0
- package/tests/titlepage/apply-title-page.test.ts +61 -0
- package/tests/titlepage/frontmatter-form.test.ts +115 -0
- package/tests/toolbar-actions.test.ts +93 -0
- package/tests/voice-commands.test.ts +58 -0
- package/tsconfig.json +17 -0
- package/vitest.config.ts +11 -0
- package/vitest.setup.ts +65 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect, useRef } from 'react';
|
|
3
|
+
import { useLanguage } from '../i18n/LanguageContext';
|
|
4
|
+
import { useDocument } from '../context/DocumentContext';
|
|
5
|
+
import { getEditorView } from '../editor/editor-bus';
|
|
6
|
+
const LANG_NAMES = {
|
|
7
|
+
en: 'English',
|
|
8
|
+
hi: 'Hindi (Devanagari)',
|
|
9
|
+
ta: 'Tamil',
|
|
10
|
+
te: 'Telugu',
|
|
11
|
+
kn: 'Kannada',
|
|
12
|
+
ml: 'Malayalam',
|
|
13
|
+
bn: 'Bengali',
|
|
14
|
+
gu: 'Gujarati',
|
|
15
|
+
pa: 'Gurmukhi',
|
|
16
|
+
or: 'Odia',
|
|
17
|
+
si: 'Sinhala',
|
|
18
|
+
};
|
|
19
|
+
export function LanguageStatus() {
|
|
20
|
+
const { currentLanguage } = useLanguage();
|
|
21
|
+
const { text, setText } = useDocument();
|
|
22
|
+
const [menuOpen, setMenuOpen] = useState(false);
|
|
23
|
+
const menuRef = useRef(null);
|
|
24
|
+
const langName = LANG_NAMES[currentLanguage] ?? currentLanguage;
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (!menuOpen)
|
|
27
|
+
return;
|
|
28
|
+
const handleClickOutside = (e) => {
|
|
29
|
+
if (menuRef.current && !menuRef.current.contains(e.target)) {
|
|
30
|
+
setMenuOpen(false);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
const handleKeyDown = (e) => {
|
|
34
|
+
if (e.key === 'Escape')
|
|
35
|
+
setMenuOpen(false);
|
|
36
|
+
};
|
|
37
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
38
|
+
document.addEventListener('keydown', handleKeyDown);
|
|
39
|
+
return () => {
|
|
40
|
+
document.removeEventListener('mousedown', handleClickOutside);
|
|
41
|
+
document.removeEventListener('keydown', handleKeyDown);
|
|
42
|
+
};
|
|
43
|
+
}, [menuOpen]);
|
|
44
|
+
const handleSelectLanguage = (code) => {
|
|
45
|
+
const view = getEditorView();
|
|
46
|
+
if (view) {
|
|
47
|
+
const { state, dispatch } = view;
|
|
48
|
+
const { from, to } = state.selection;
|
|
49
|
+
const tagText = `{lang=${code}}`;
|
|
50
|
+
dispatch(state.tr.insertText(tagText, from, to));
|
|
51
|
+
view.focus();
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
setText(text + `\n{lang=${code}}`);
|
|
55
|
+
}
|
|
56
|
+
setMenuOpen(false);
|
|
57
|
+
};
|
|
58
|
+
return (_jsxs("div", { className: "cs-lang-status", ref: menuRef, children: [_jsxs("button", { type: "button", className: "cs-lang-status-btn cs-lang-pill", title: `Script language at caret: ${langName} (${currentLanguage.toUpperCase()})`, "aria-label": `Script language: ${langName}`, "aria-haspopup": "menu", "aria-expanded": menuOpen, onClick: () => setMenuOpen(!menuOpen), children: [_jsx("span", { className: "cs-lang-pill-script", children: "\u0905/A" }), _jsx("span", { className: "cs-lang-code", children: currentLanguage.toUpperCase() })] }), menuOpen && (_jsx("div", { className: "cs-lang-menu", role: "menu", "aria-label": "Script languages", children: Object.entries(LANG_NAMES).map(([code, name]) => {
|
|
59
|
+
const isActive = currentLanguage === code;
|
|
60
|
+
return (_jsxs("button", { type: "button", role: "menuitem", className: `cs-lang-option${isActive ? ' cs-lang-active' : ''}`, onClick: (e) => {
|
|
61
|
+
e.stopPropagation();
|
|
62
|
+
handleSelectLanguage(code);
|
|
63
|
+
}, children: [_jsx("span", { children: name }), _jsx("span", { className: "cs-lang-code", style: { fontSize: '10px', opacity: 0.7 }, children: code.toUpperCase() })] }, code));
|
|
64
|
+
}) }))] }));
|
|
65
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo, useState, useEffect } from 'react';
|
|
3
|
+
import { useDocument } from '../context/DocumentContext';
|
|
4
|
+
import { LanguageStatus } from './LanguageStatus';
|
|
5
|
+
import { buildSceneList } from '../navigator/scene-list';
|
|
6
|
+
import { StatisticsDialog } from '../navigator/StatisticsDialog';
|
|
7
|
+
import { VersionHistory } from './VersionHistory';
|
|
8
|
+
import { StatsIcon, HistoryIcon } from './icons';
|
|
9
|
+
import { subscribeToAICalls, formatActiveCalls } from '../ai/ai-client';
|
|
10
|
+
import { useTranslation } from '../i18n/useTranslation';
|
|
11
|
+
function AIStatusBarStatus() {
|
|
12
|
+
const [activeCalls, setActiveCalls] = useState([]);
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
return subscribeToAICalls(setActiveCalls);
|
|
15
|
+
}, []);
|
|
16
|
+
if (activeCalls.length === 0)
|
|
17
|
+
return null;
|
|
18
|
+
return (_jsxs("div", { className: "cs-ai-status-indicator", style: {
|
|
19
|
+
display: 'inline-flex',
|
|
20
|
+
alignItems: 'center',
|
|
21
|
+
gap: '6px',
|
|
22
|
+
color: 'var(--cs-ui-accent, #c4760a)',
|
|
23
|
+
fontWeight: 600,
|
|
24
|
+
fontSize: '11px',
|
|
25
|
+
marginRight: '8px',
|
|
26
|
+
}, children: [_jsx("span", { className: "cs-spinner", style: { width: '10px', height: '10px', borderWidth: '1.5px' } }), _jsx("span", { children: formatActiveCalls(activeCalls) })] }));
|
|
27
|
+
}
|
|
28
|
+
export function StatusBar() {
|
|
29
|
+
const { text, isDirty, lastSaveTarget, filePath, versions, versionHistoryVisible, setVersionHistoryVisible, restoreVersion, clearVersionHistory } = useDocument();
|
|
30
|
+
const { t } = useTranslation();
|
|
31
|
+
const [statsOpen, setStatsOpen] = useState(false);
|
|
32
|
+
// VS Code-style: a local autosave backs the content up but never counts as
|
|
33
|
+
// "saved" in the main label — only a real write to the file (saveFile/
|
|
34
|
+
// saveFileAs, which clears isDirty) does. While still dirty, the tooltip
|
|
35
|
+
// says whether that local backup has caught up with the latest edits yet.
|
|
36
|
+
const saveLabel = isDirty
|
|
37
|
+
? t('statusbar.unsavedChanges')
|
|
38
|
+
: lastSaveTarget === 'file' ? t('statusbar.savedToFile')
|
|
39
|
+
: t('statusbar.allChangesSaved');
|
|
40
|
+
const saveTooltip = isDirty
|
|
41
|
+
? lastSaveTarget === 'local' ? t('statusbar.savedLocallyTooltip') : undefined
|
|
42
|
+
: lastSaveTarget === 'file' ? t('statusbar.savedToFileTooltip')
|
|
43
|
+
: undefined;
|
|
44
|
+
const scenes = useMemo(() => buildSceneList(text), [text]);
|
|
45
|
+
const { wordCount, pageEstimate } = useMemo(() => {
|
|
46
|
+
const trimmed = text.trim();
|
|
47
|
+
const words = trimmed ? trimmed.split(/\s+/).length : 0;
|
|
48
|
+
// Standard screenplay rule: ~54 lines or ~200-250 words per page
|
|
49
|
+
const lines = text.split('\n').length;
|
|
50
|
+
const estPages = Math.max(1, Math.round(lines / 54));
|
|
51
|
+
return { wordCount: words, pageEstimate: estPages };
|
|
52
|
+
}, [text]);
|
|
53
|
+
return (_jsxs(_Fragment, { children: [_jsxs("footer", { className: "cs-status-bar", role: "contentinfo", "aria-label": "Status bar", children: [_jsxs("div", { className: "cs-sb-left", children: [_jsxs("span", { className: "cs-sb-metric cs-sb-metric-scenes", title: t('statusbar.scenesTooltip'), children: [_jsx("strong", { children: scenes.length }), " ", _jsx("span", { className: "cs-sb-metric-label", children: scenes.length === 1 ? t('statusbar.scene') : t('statusbar.scenes') })] }), _jsx("span", { className: "cs-sb-sep", children: "\u2022" }), _jsxs("span", { className: "cs-sb-metric cs-sb-metric-pages", title: t('statusbar.pagesTooltip'), children: [_jsxs("strong", { children: ["~", pageEstimate] }), " ", _jsx("span", { className: "cs-sb-metric-label", children: pageEstimate === 1 ? t('statusbar.page') : t('statusbar.pages') })] }), _jsx("span", { className: "cs-sb-sep cs-sb-words-sep", children: "\u2022" }), _jsxs("span", { className: "cs-sb-metric cs-sb-metric-words", title: t('statusbar.wordsTooltip'), children: [_jsx("strong", { children: wordCount.toLocaleString() }), " ", _jsx("span", { className: "cs-sb-metric-label", children: t('statusbar.words') })] })] }), _jsx("div", { className: "cs-sb-center", children: _jsxs("div", { className: "cs-sb-save", role: "status", "aria-live": "polite", title: saveTooltip, children: [_jsx("span", { className: `cs-sb-dot ${isDirty ? 'cs-sb-dot-dirty' : 'cs-sb-dot-clean'}` }), _jsx("span", { className: isDirty ? 'cs-sb-save-dirty' : 'cs-sb-save-clean', children: saveLabel })] }) }), _jsxs("div", { className: "cs-sb-right", children: [_jsx(AIStatusBarStatus, {}), filePath && versions.length > 0 && (_jsxs("button", { type: "button", className: "cs-nav-action-btn", onClick: () => setVersionHistoryVisible(true), title: `${versions.length} version${versions.length === 1 ? '' : 's'} saved`, style: { fontSize: '11px', gap: '4px', padding: '2px 6px' }, children: [_jsx(HistoryIcon, { size: 13 }), _jsx("span", { children: versions.length })] })), _jsxs("button", { type: "button", className: "cs-nav-action-btn", onClick: () => setStatsOpen(true), title: t('statusbar.statsTooltip'), style: { fontSize: '11px', gap: '4px', padding: '2px 6px' }, children: [_jsx(StatsIcon, { size: 13 }), _jsx("span", { children: t('statusbar.statsButton') })] }), _jsx(LanguageStatus, {})] })] }), statsOpen && _jsx(StatisticsDialog, { onClose: () => setStatsOpen(false) }), filePath && (_jsx(VersionHistory, { versions: versions, filePath: filePath, onRestore: restoreVersion, onClearAll: clearVersionHistory, visible: versionHistoryVisible, onClose: () => setVersionHistoryVisible(false) }))] }));
|
|
54
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
const MONOGRAM_ASPECT = 231.65818 / 324.60373;
|
|
3
|
+
export function SutrataLogo({ size = 20, className = '', showText = true }) {
|
|
4
|
+
const height = size;
|
|
5
|
+
const width = size * MONOGRAM_ASPECT;
|
|
6
|
+
return (_jsxs("div", { className: `cs-brand-mark ${className}`, style: { display: 'inline-flex', alignItems: 'center', gap: '7px', userSelect: 'none' }, children: [_jsx("svg", { width: width, height: height, viewBox: "0 0 231.65818 324.60373", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", style: { flexShrink: 0 }, children: _jsxs("g", { transform: "translate(-3.0466903,-3.069361)", children: [_jsxs("g", { children: [_jsx("path", { fill: "#502308", d: "M 76.35291,222.53041 C 75.478969,209.22098 71.352034,194.29907 56.664655,177.24787 35.352192,152.22995 46.850499,139.85601 62.978003,130.13046 L 3.6899176,150.4351 c 5.0786411,20.05339 13.9650544,36.08746 28.6678214,45.98205 16.601069,11.28577 30.572578,19.06546 43.995171,26.11326 z" }), _jsx("path", { fill: "#92400e", d: "m 213.6921,3.069361 c 0,0 0.96049,32.353598 -0.14192,43.494212 -1.10241,11.140614 -14.06146,22.120287 -23.28179,26.493068 -26.78003,12.700542 -124.035721,55.394599 -124.035721,55.394599 0,0 -7.314493,3.8005 -14.852175,9.23243 -7.537682,5.43193 -23.670324,18.71663 -28.098707,33.71845 -1.670439,5.65887 -2.408461,14.04935 -2.408461,14.04935 C 8.2528446,173.99227 -4.2995876,149.42142 8.2289074,120.92479 18.129451,103.32842 31.24605,87.051456 55.796006,75.465101 101.11959,52.013746 150.99666,33.115884 198.69801,12.042303 Z" }), _jsxs("g", { children: [_jsx("path", { fill: "#fbbf24", d: "m 157.01648,44.42498 c 14.17698,-5.71484 11.14517,-6.35429 11.1893,10.23596 -0.40601,13.28313 2.27097,11.17087 -9.33278,16.05641 -13.29184,4.92069 -12.50077,7.73152 -12.14266,-9.03173 -0.29088,-15.61229 -1.75968,-11.39786 10.28614,-17.26064 z" }), _jsx("path", { fill: "#fbbf24", d: "m 118.47741,61.789741 c 14.17699,-5.71484 11.14518,-6.35429 11.18931,10.23596 -0.40601,13.28313 2.27097,11.17087 -9.33279,16.05641 -13.29183,4.92069 -12.50076,7.73152 -12.14265,-9.03173 -0.29089,-15.61229 -1.75968,-11.39786 10.28613,-17.26064 z" }), _jsx("path", { fill: "#fbbf24", d: "m 80.42697,79.119631 c 14.176988,-5.71484 11.145175,-6.35429 11.189307,10.23596 -0.406014,13.283129 2.27097,11.170869 -9.332786,16.056409 -13.291838,4.92069 -12.500765,7.73152 -12.142656,-9.031729 -0.290884,-15.61229 -1.759682,-11.39786 10.286135,-17.26064 z" })] })] }), _jsxs("g", { transform: "rotate(180,118.87578,165.37123)", children: [_jsx("path", { fill: "#502308", d: "M 76.35291,222.53041 C 75.478969,209.22098 71.352034,194.29907 56.664655,177.24787 35.352192,152.22995 46.850499,139.85601 62.978003,130.13046 L 3.6899176,150.4351 c 5.0786411,20.05339 13.9650544,36.08746 28.6678214,45.98205 16.601069,11.28577 30.572578,19.06546 43.995171,26.11326 z" }), _jsx("path", { fill: "#92400e", d: "m 213.6921,3.069361 c 0,0 0.96049,32.353598 -0.14192,43.494212 -1.10241,11.140614 -14.06146,22.120287 -23.28179,26.493068 -26.78003,12.700542 -124.035721,55.394599 -124.035721,55.394599 0,0 -7.314493,3.8005 -14.852175,9.23243 -7.537682,5.43193 -23.670324,18.71663 -28.098707,33.71845 -1.670439,5.65887 -2.408461,14.04935 -2.408461,14.04935 C 8.2528446,173.99227 -4.2995876,149.42142 8.2289074,120.92479 18.129451,103.32842 31.24605,87.051456 55.796006,75.465101 101.11959,52.013746 150.99666,33.115884 198.69801,12.042303 Z" }), _jsxs("g", { children: [_jsx("path", { fill: "#fbbf24", d: "m 157.01648,44.42498 c 14.17698,-5.71484 11.14517,-6.35429 11.1893,10.23596 -0.40601,13.28313 2.27097,11.17087 -9.33278,16.05641 -13.29184,4.92069 -12.50077,7.73152 -12.14266,-9.03173 -0.29088,-15.61229 -1.75968,-11.39786 10.28614,-17.26064 z" }), _jsx("path", { fill: "#fbbf24", d: "m 118.47741,61.789741 c 14.17699,-5.71484 11.14518,-6.35429 11.18931,10.23596 -0.40601,13.28313 2.27097,11.17087 -9.33279,16.05641 -13.29183,4.92069 -12.50076,7.73152 -12.14265,-9.03173 -0.29089,-15.61229 -1.75968,-11.39786 10.28613,-17.26064 z" }), _jsx("path", { fill: "#fbbf24", d: "m 80.42697,79.119631 c 14.176988,-5.71484 11.145175,-6.35429 11.189307,10.23596 -0.406014,13.283129 2.27097,11.170869 -9.332786,16.056409 -13.291838,4.92069 -12.500765,7.73152 -12.142656,-9.031729 -0.290884,-15.61229 -1.759682,-11.39786 10.286135,-17.26064 z" })] })] }), _jsxs("g", { transform: "matrix(1.1983554,-0.06280315,0.06280315,1.1983554,-34.773977,-29.239318)", children: [_jsx("path", { fill: "#fbbf24", d: "m 90.317275,164.77885 48.369915,-17.86274 c -6.75724,-6.27184 -19.73649,-10.33577 -32.1128,-4.41552 -11.797753,5.74748 -14.462218,13.89845 -16.257115,22.27826 z" }), _jsx("path", { fill: "#fbbf24", d: "M 148.18495,171.26956 99.815045,189.1323 c 6.757235,6.27184 19.736485,10.33577 32.112795,4.41552 11.79775,-5.74748 14.46221,-13.89845 16.25711,-22.27826 z" }), _jsx("path", { fill: "#fbbf24", d: "m 90.417628,169.79648 51.882262,-19.36804 c 3.81102,4.8999 5.68801,10.3205 6.02115,16.15676 l -52.032789,19.06698 c -3.269689,-4.15996 -5.408353,-9.28938 -5.870623,-15.8557 z" })] })] }) }), showText && (_jsx("span", { className: "cs-brand-text", style: { fontWeight: 700, fontSize: '11px', letterSpacing: '1.2px', textTransform: 'uppercase', color: 'var(--cs-ui-accent-badge, #d97706)' }, children: "Sutrata" }))] }));
|
|
7
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface ToastItem {
|
|
3
|
+
id: string;
|
|
4
|
+
message: string;
|
|
5
|
+
type?: 'info' | 'success' | 'warn' | 'error';
|
|
6
|
+
}
|
|
7
|
+
interface ToastContainerProps {
|
|
8
|
+
toasts: ToastItem[];
|
|
9
|
+
onDismiss: (id: string) => void;
|
|
10
|
+
}
|
|
11
|
+
export declare function ToastContainer({ toasts, onDismiss }: ToastContainerProps): React.JSX.Element;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect } from 'react';
|
|
3
|
+
export function ToastContainer({ toasts, onDismiss }) {
|
|
4
|
+
return (_jsx("div", { className: "cs-toast-container", "aria-live": "polite", "aria-atomic": "true", children: toasts.map((toast) => (_jsx(ToastMessage, { toast: toast, onDismiss: onDismiss }, toast.id))) }));
|
|
5
|
+
}
|
|
6
|
+
function ToastMessage({ toast, onDismiss }) {
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
const timer = setTimeout(() => {
|
|
9
|
+
onDismiss(toast.id);
|
|
10
|
+
}, 3500);
|
|
11
|
+
return () => clearTimeout(timer);
|
|
12
|
+
}, [toast.id, onDismiss]);
|
|
13
|
+
const typeClass = toast.type === 'success'
|
|
14
|
+
? 'cs-toast-success'
|
|
15
|
+
: toast.type === 'error'
|
|
16
|
+
? 'cs-toast-error'
|
|
17
|
+
: toast.type === 'warn'
|
|
18
|
+
? 'cs-toast-warn'
|
|
19
|
+
: 'cs-toast-info';
|
|
20
|
+
return (_jsx("div", { className: `cs-toast ${typeClass}`, role: "status", children: _jsx("span", { children: toast.message }) }));
|
|
21
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface ToolbarButtonProps {
|
|
3
|
+
label: string;
|
|
4
|
+
sigil?: string;
|
|
5
|
+
shortcut?: string;
|
|
6
|
+
active?: boolean;
|
|
7
|
+
onClick: () => void;
|
|
8
|
+
children: React.ReactNode;
|
|
9
|
+
}
|
|
10
|
+
export declare function ToolbarButton({ label, sigil, shortcut, active, onClick, children }: ToolbarButtonProps): React.JSX.Element;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
export function ToolbarButton({ label, sigil, shortcut, active, onClick, children }) {
|
|
3
|
+
return (_jsxs("button", { type: "button", "aria-label": label, className: `cs-tb-btn${active ? ' cs-tb-active' : ''}`, onClick: onClick, children: [_jsx("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', width: '100%', height: '100%' }, children: children }), _jsxs("span", { className: "cs-tb-tip", role: "tooltip", children: [_jsx("span", { children: label }), sigil ? _jsx("span", { className: "cs-tb-sigil", children: sigil }) : null, shortcut ? _jsx("span", { className: "cs-tb-key", children: shortcut }) : null] })] }));
|
|
4
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { VersionEntry } from '../types';
|
|
3
|
+
interface VersionHistoryProps {
|
|
4
|
+
versions: VersionEntry[];
|
|
5
|
+
filePath: string | null;
|
|
6
|
+
onRestore: (entry: VersionEntry) => void;
|
|
7
|
+
onClearAll: () => Promise<void>;
|
|
8
|
+
visible: boolean;
|
|
9
|
+
onClose: () => void;
|
|
10
|
+
}
|
|
11
|
+
export declare function VersionHistory({ versions, filePath, onRestore, onClearAll, visible, onClose }: VersionHistoryProps): React.JSX.Element | null;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
3
|
+
import { diffWordsWithSpace } from 'diff';
|
|
4
|
+
// Word-level diff over the full text (not line-bucketed): if only one word in
|
|
5
|
+
// a sentence changed, only that word is marked added/removed — the rest of
|
|
6
|
+
// the sentence comes back as an unchanged, unstyled Change chunk. Whitespace
|
|
7
|
+
// (including newlines) is treated as part of the diff so line breaks survive.
|
|
8
|
+
function computeDiff(oldText, newText) {
|
|
9
|
+
return diffWordsWithSpace(oldText, newText);
|
|
10
|
+
}
|
|
11
|
+
// Two markers within this many pixels of each other collapse into one, so a
|
|
12
|
+
// tight run of word edits doesn't paint a solid wall of ticks.
|
|
13
|
+
const CLUSTER_PX = 10;
|
|
14
|
+
function formatTimestamp(ts) {
|
|
15
|
+
return new Date(ts).toLocaleString(undefined, {
|
|
16
|
+
month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit',
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
export function VersionHistory({ versions, filePath, onRestore, onClearAll, visible, onClose }) {
|
|
20
|
+
const [selectedId, setSelectedId] = useState(null);
|
|
21
|
+
const diffScrollRef = useRef(null);
|
|
22
|
+
// Maps a diff-part index (only added/removed parts) to its rendered <span>,
|
|
23
|
+
// so marker positions come from real layout instead of a text-based estimate —
|
|
24
|
+
// screenplay format has wildly uneven character density per line (short
|
|
25
|
+
// character cues and blank lines vs. long action paragraphs), which threw
|
|
26
|
+
// off an earlier character-offset heuristic by a page or more.
|
|
27
|
+
const spanRefMap = useRef(new Map());
|
|
28
|
+
const [markers, setMarkers] = useState([]);
|
|
29
|
+
const currentVersion = versions[0] ?? null;
|
|
30
|
+
const selectedVersion = useMemo(() => versions.find(v => v.id === selectedId) ?? null, [versions, selectedId]);
|
|
31
|
+
const diff = useMemo(() => {
|
|
32
|
+
if (!selectedVersion || !currentVersion || selectedVersion.id === currentVersion.id)
|
|
33
|
+
return null;
|
|
34
|
+
return computeDiff(selectedVersion.content, currentVersion.content);
|
|
35
|
+
}, [selectedVersion, currentVersion]);
|
|
36
|
+
useLayoutEffect(() => {
|
|
37
|
+
const container = diffScrollRef.current;
|
|
38
|
+
if (!container || !diff) {
|
|
39
|
+
setMarkers([]);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const raw = [];
|
|
43
|
+
diff.forEach((part, i) => {
|
|
44
|
+
if (!part.added && !part.removed)
|
|
45
|
+
return;
|
|
46
|
+
const span = spanRefMap.current.get(i);
|
|
47
|
+
if (!span)
|
|
48
|
+
return;
|
|
49
|
+
raw.push({ type: part.added ? 'added' : 'removed', top: span.offsetTop });
|
|
50
|
+
});
|
|
51
|
+
raw.sort((a, b) => a.top - b.top);
|
|
52
|
+
const scrollHeight = container.scrollHeight || 1;
|
|
53
|
+
const clustered = [];
|
|
54
|
+
let lastTop = -Infinity;
|
|
55
|
+
let lastType = null;
|
|
56
|
+
for (const m of raw) {
|
|
57
|
+
if (lastType === m.type && m.top - lastTop < CLUSTER_PX)
|
|
58
|
+
continue;
|
|
59
|
+
clustered.push({ type: m.type, position: m.top / scrollHeight });
|
|
60
|
+
lastTop = m.top;
|
|
61
|
+
lastType = m.type;
|
|
62
|
+
}
|
|
63
|
+
setMarkers(clustered);
|
|
64
|
+
}, [diff]);
|
|
65
|
+
const scrollToMarker = (position) => {
|
|
66
|
+
const el = diffScrollRef.current;
|
|
67
|
+
if (!el)
|
|
68
|
+
return;
|
|
69
|
+
const target = Math.max(0, position * el.scrollHeight - el.clientHeight / 2);
|
|
70
|
+
if (typeof el.scrollTo === 'function')
|
|
71
|
+
el.scrollTo({ top: target, behavior: 'smooth' });
|
|
72
|
+
else
|
|
73
|
+
el.scrollTop = target;
|
|
74
|
+
};
|
|
75
|
+
if (!visible || !filePath)
|
|
76
|
+
return null;
|
|
77
|
+
return (_jsx("div", { className: "cs-dialog-overlay", role: "presentation", onClick: e => { if (e.target === e.currentTarget)
|
|
78
|
+
onClose(); }, children: _jsxs("div", { className: "cs-dialog", role: "dialog", "aria-modal": "true", "aria-labelledby": "cs-version-dialog-title", style: { maxWidth: '620px', width: '92%', maxHeight: '80vh', display: 'flex', flexDirection: 'column' }, children: [_jsxs("div", { className: "cs-panel-header", children: [_jsx("span", { id: "cs-version-dialog-title", className: "cs-panel-title", children: "Version History" }), _jsx("button", { className: "cs-panel-close", onClick: onClose, "aria-label": "Close", children: "\u00D7" })] }), _jsxs("div", { className: "cs-version-body", children: [_jsx("div", { className: "cs-version-list", children: versions.length === 0 ? (_jsx("div", { className: "cs-version-empty", children: "No versions saved yet" })) : (versions.map((v, idx) => (_jsxs("button", { type: "button", className: `cs-version-list-item${selectedId === v.id ? ' cs-version-list-item-active' : ''}`, onClick: () => setSelectedId(v.id), children: [_jsx("div", { className: "cs-version-list-item-label", children: idx === 0 ? 'Current' : formatTimestamp(v.timestamp) }), idx !== 0 && _jsx("div", { className: "cs-version-list-item-date", children: formatTimestamp(v.timestamp) })] }, v.id)))) }), _jsxs("div", { className: "cs-version-diff-wrap", children: [_jsx("div", { className: "cs-version-diff", ref: diffScrollRef, children: !selectedVersion ? (_jsx("div", { className: "cs-version-empty", children: "Select a version to compare against the current document" })) : selectedVersion.id === currentVersion?.id ? (_jsx("div", { className: "cs-version-empty", children: "This is the current version" })) : diff ? (diff.every(part => !part.added && !part.removed) ? (_jsx("div", { className: "cs-version-empty", children: "No differences from the current version" })) : (_jsx("div", { className: "cs-version-diff-content", children: diff.map((part, i) => {
|
|
79
|
+
const isChange = part.added || part.removed;
|
|
80
|
+
return (_jsx("span", { ref: isChange ? (el) => {
|
|
81
|
+
if (el)
|
|
82
|
+
spanRefMap.current.set(i, el);
|
|
83
|
+
else
|
|
84
|
+
spanRefMap.current.delete(i);
|
|
85
|
+
} : undefined, className: part.added ? 'cs-version-diff-added'
|
|
86
|
+
: part.removed ? 'cs-version-diff-removed'
|
|
87
|
+
: undefined, children: part.value }, i));
|
|
88
|
+
}) }))) : null }), _jsx("div", { className: "cs-version-diff-minimap", "aria-hidden": "true", children: markers.map((m, i) => (_jsx("button", { type: "button", className: `cs-version-diff-marker cs-version-diff-marker-${m.type}`, style: { top: `${m.position * 100}%` }, title: m.type === 'added' ? 'Jump to added text' : 'Jump to removed text', onClick: () => scrollToMarker(m.position) }, i))) })] })] }), _jsxs("div", { className: "cs-version-footer", children: [_jsx("button", { type: "button", className: "cs-confirm-btn-cancel cs-version-clear-btn", onClick: () => void onClearAll(), disabled: versions.length === 0, children: "Delete Version History" }), _jsxs("div", { style: { display: 'flex', gap: '10px' }, children: [_jsx("button", { type: "button", className: "cs-confirm-btn-cancel", onClick: onClose, children: "Close" }), selectedVersion && selectedVersion.id !== currentVersion?.id && (_jsx("button", { type: "button", className: "cs-confirm-btn-primary", onClick: () => onRestore(selectedVersion), children: "Restore This Version" }))] })] })] }) }));
|
|
89
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useDocument } from '../context/DocumentContext';
|
|
3
|
+
/** Renders the document's frontmatter `watermark:` text.
|
|
4
|
+
* Hidden in the screen editor UI, visible only in print output. */
|
|
5
|
+
export function Watermark() {
|
|
6
|
+
const { watermarkText } = useDocument();
|
|
7
|
+
if (!watermarkText)
|
|
8
|
+
return null;
|
|
9
|
+
return _jsx("div", { className: "cs-watermark", "aria-hidden": "true", children: watermarkText });
|
|
10
|
+
}
|