@sutrata/editor 0.1.1 → 0.2.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.
Files changed (268) hide show
  1. package/README.md +87 -0
  2. package/dist/ai/VoiceConfirmDialog.d.ts +1 -0
  3. package/dist/ai/VoiceConfirmDialog.js +6 -6
  4. package/dist/ai/VoiceToolbar.d.ts +1 -0
  5. package/dist/ai/VoiceToolbar.js +22 -16
  6. package/dist/ai/clean-response.d.ts +7 -0
  7. package/dist/ai/clean-response.js +58 -0
  8. package/dist/ai/format-transcript.d.ts +3 -0
  9. package/dist/ai/format-transcript.js +7 -0
  10. package/dist/ai/prompts.d.ts +8 -1
  11. package/dist/ai/prompts.js +34 -7
  12. package/dist/autocomplete/suggestions.js +1 -1
  13. package/dist/context/DocumentContext.d.ts +28 -4
  14. package/dist/context/DocumentContext.js +67 -37
  15. package/dist/editor/EditorView.js +32 -4
  16. package/dist/editor/SelectionMenu.js +5 -3
  17. package/dist/editor/external-decorations-plugin.d.ts +23 -0
  18. package/dist/editor/external-decorations-plugin.js +151 -0
  19. package/dist/editor/omitted-scene-plugin.d.ts +9 -0
  20. package/dist/editor/omitted-scene-plugin.js +44 -0
  21. package/dist/editor/plugins.js +4 -0
  22. package/dist/editor/private-metadata-plugin.d.ts +10 -0
  23. package/dist/editor/private-metadata-plugin.js +60 -0
  24. package/dist/editor/prosemirror-to-sutra.js +179 -74
  25. package/dist/editor/scene-heading-view.js +2 -0
  26. package/dist/editor/schema.js +69 -12
  27. package/dist/editor/sutra-to-prosemirror.d.ts +2 -0
  28. package/dist/editor/sutra-to-prosemirror.js +32 -34
  29. package/dist/extensions/ai-provider.d.ts +44 -0
  30. package/dist/extensions/ai-provider.js +27 -0
  31. package/dist/extensions/collab.d.ts +21 -0
  32. package/dist/extensions/collab.js +6 -0
  33. package/dist/extensions/command-registry.d.ts +49 -0
  34. package/dist/extensions/command-registry.js +28 -0
  35. package/dist/extensions/decorations.d.ts +48 -0
  36. package/dist/extensions/decorations.js +6 -0
  37. package/dist/extensions/export-registry.d.ts +59 -0
  38. package/dist/extensions/export-registry.js +10 -0
  39. package/dist/extensions/panel-registry.d.ts +30 -0
  40. package/dist/extensions/panel-registry.js +16 -0
  41. package/dist/extensions/registries.d.ts +15 -0
  42. package/dist/extensions/registries.js +12 -0
  43. package/dist/extensions/registry-store.d.ts +26 -0
  44. package/dist/extensions/registry-store.js +35 -0
  45. package/dist/extensions/session.d.ts +29 -0
  46. package/dist/extensions/session.js +20 -0
  47. package/dist/extensions/speech-provider.d.ts +35 -0
  48. package/dist/extensions/speech-provider.js +17 -0
  49. package/dist/file/builtin-exporters.d.ts +9 -0
  50. package/dist/file/builtin-exporters.js +72 -0
  51. package/dist/file/docx-exporter.js +7 -4
  52. package/dist/file/docx-importer.d.ts +9 -0
  53. package/dist/file/docx-importer.js +47 -19
  54. package/dist/file/scene-number.d.ts +5 -0
  55. package/dist/file/scene-number.js +8 -0
  56. package/dist/file/workflow-reports.js +13 -7
  57. package/dist/findreplace/FindReplace.js +5 -2
  58. package/dist/import/AIImportDialog.d.ts +11 -0
  59. package/dist/import/AIImportDialog.js +112 -0
  60. package/dist/import/ai-import.d.ts +51 -0
  61. package/dist/import/ai-import.js +200 -0
  62. package/dist/import/apply-import.d.ts +7 -0
  63. package/dist/import/apply-import.js +35 -0
  64. package/dist/import/extract.d.ts +17 -0
  65. package/dist/import/extract.js +18 -0
  66. package/dist/index.d.ts +17 -2
  67. package/dist/index.js +7 -0
  68. package/dist/locales/bn.json +8 -0
  69. package/dist/locales/en.json +8 -0
  70. package/dist/locales/gu.json +8 -0
  71. package/dist/locales/hi.json +8 -0
  72. package/dist/locales/kn.json +8 -0
  73. package/dist/locales/ml.json +8 -0
  74. package/dist/locales/mr.json +8 -0
  75. package/dist/locales/or.json +8 -0
  76. package/dist/locales/pa.json +8 -0
  77. package/dist/locales/si.json +8 -0
  78. package/dist/locales/ta.json +8 -0
  79. package/dist/locales/te.json +8 -0
  80. package/dist/navigator/SceneNavigator.js +125 -131
  81. package/dist/navigator/StatisticsDialog.js +5 -1
  82. package/dist/navigator/scene-edits.d.ts +18 -0
  83. package/dist/navigator/scene-edits.js +143 -0
  84. package/dist/navigator/scene-list.js +4 -4
  85. package/dist/navigator/scene-numbering.d.ts +37 -0
  86. package/dist/navigator/scene-numbering.js +88 -0
  87. package/dist/settings/SettingsDialog.js +8 -120
  88. package/dist/shell/AppBar.js +21 -2
  89. package/dist/shell/AppShell.js +18 -4
  90. package/dist/shell/ElementToolbar.d.ts +5 -0
  91. package/dist/shell/ElementToolbar.js +35 -25
  92. package/dist/shell/LanguageStatus.js +6 -0
  93. package/dist/shell/StatusBar.js +11 -6
  94. package/dist/shell/builtin-commands.d.ts +10 -0
  95. package/dist/shell/builtin-commands.js +43 -0
  96. package/dist/shell/icons.d.ts +6 -0
  97. package/dist/shell/icons.js +6 -0
  98. package/dist/shell/use-commands.d.ts +7 -0
  99. package/dist/shell/use-commands.js +24 -0
  100. package/dist/shell/use-panel-context.d.ts +3 -0
  101. package/dist/shell/use-panel-context.js +39 -0
  102. package/dist/source/SourceView.js +18 -1
  103. package/dist/styles/screenplay.css +113 -1
  104. package/dist/titlepage/ExportDialog.d.ts +5 -0
  105. package/dist/titlepage/ExportDialog.js +59 -96
  106. package/package.json +32 -5
  107. package/dist/ai/OnboardingDialog.d.ts +0 -6
  108. package/dist/ai/OnboardingDialog.js +0 -115
  109. package/dist/ai/ai-client.d.ts +0 -71
  110. package/dist/ai/ai-client.js +0 -494
  111. package/dist/ai/generated-providers.json +0 -3696
  112. package/dist/ai/voice-service.d.ts +0 -15
  113. package/dist/ai/voice-service.js +0 -81
  114. package/dist/editor/character-view.d.ts +0 -35
  115. package/dist/editor/character-view.js +0 -112
  116. package/dist/editor/transliterate-input.d.ts +0 -10
  117. package/dist/editor/transliterate-input.js +0 -88
  118. package/dist/extensions/types.d.ts +0 -73
  119. package/dist/extensions/types.js +0 -12
  120. package/scripts/copy-assets.mjs +0 -16
  121. package/scripts/generate-providers.mjs +0 -127
  122. package/src/ai/OnboardingDialog.tsx +0 -390
  123. package/src/ai/VoiceConfirmDialog.tsx +0 -137
  124. package/src/ai/VoiceToolbar.tsx +0 -321
  125. package/src/ai/ai-client.ts +0 -596
  126. package/src/ai/commands.ts +0 -164
  127. package/src/ai/generated-providers.json +0 -3696
  128. package/src/ai/prompts.ts +0 -62
  129. package/src/ai/voice-service.ts +0 -96
  130. package/src/autocomplete/AutocompletePlugin.ts +0 -21
  131. package/src/autocomplete/suggestions.ts +0 -147
  132. package/src/context/DocumentContext.tsx +0 -648
  133. package/src/desktop-api.d.ts +0 -40
  134. package/src/editor/EditorView.tsx +0 -82
  135. package/src/editor/SelectionMenu.tsx +0 -152
  136. package/src/editor/attr-pencil-plugin.ts +0 -172
  137. package/src/editor/character-decoration-plugin.ts +0 -104
  138. package/src/editor/editor-bus.ts +0 -51
  139. package/src/editor/find-highlight-plugin.ts +0 -68
  140. package/src/editor/frontmatter-field-view.ts +0 -52
  141. package/src/editor/frontmatter-field.ts +0 -115
  142. package/src/editor/grapheme-cursor.ts +0 -99
  143. package/src/editor/ime-plugin.ts +0 -85
  144. package/src/editor/insert-helper.ts +0 -43
  145. package/src/editor/keymap.ts +0 -124
  146. package/src/editor/language-class-plugin.ts +0 -91
  147. package/src/editor/plugins.ts +0 -26
  148. package/src/editor/prosemirror-to-sutra.ts +0 -192
  149. package/src/editor/scene-heading-view.ts +0 -147
  150. package/src/editor/schema.ts +0 -156
  151. package/src/editor/sutra-to-prosemirror.ts +0 -156
  152. package/src/extensions/storage-adapter.ts +0 -65
  153. package/src/extensions/types.ts +0 -60
  154. package/src/file/docx-exporter.ts +0 -585
  155. package/src/file/docx-importer.ts +0 -313
  156. package/src/file/print-paginator.ts +0 -301
  157. package/src/file/templates.ts +0 -73
  158. package/src/file/workflow-reports.ts +0 -820
  159. package/src/findreplace/FindReplace.tsx +0 -242
  160. package/src/findreplace/find-engine.ts +0 -97
  161. package/src/findreplace/scroll-to-match.ts +0 -89
  162. package/src/fonts/tofu-detect.ts +0 -53
  163. package/src/i18n/LanguageContext.tsx +0 -207
  164. package/src/i18n/language-detect.ts +0 -73
  165. package/src/i18n/useTranslation.tsx +0 -74
  166. package/src/index.ts +0 -27
  167. package/src/locales/bn.json +0 -143
  168. package/src/locales/en.json +0 -143
  169. package/src/locales/gu.json +0 -143
  170. package/src/locales/hi.json +0 -143
  171. package/src/locales/kn.json +0 -143
  172. package/src/locales/ml.json +0 -143
  173. package/src/locales/mr.json +0 -143
  174. package/src/locales/or.json +0 -143
  175. package/src/locales/pa.json +0 -143
  176. package/src/locales/si.json +0 -143
  177. package/src/locales/ta.json +0 -143
  178. package/src/locales/te.json +0 -143
  179. package/src/navigator/SceneNavigator.tsx +0 -844
  180. package/src/navigator/StatisticsDialog.tsx +0 -249
  181. package/src/navigator/scene-list.ts +0 -84
  182. package/src/settings/SettingsDialog.tsx +0 -303
  183. package/src/shell/AppBar.tsx +0 -354
  184. package/src/shell/AppShell.tsx +0 -71
  185. package/src/shell/ConfirmDialog.tsx +0 -71
  186. package/src/shell/ElementToolbar.tsx +0 -175
  187. package/src/shell/LanguageStatus.tsx +0 -101
  188. package/src/shell/StatusBar.tsx +0 -135
  189. package/src/shell/SutrataLogo.tsx +0 -89
  190. package/src/shell/Toast.tsx +0 -46
  191. package/src/shell/ToolbarButton.tsx +0 -30
  192. package/src/shell/VersionHistory.tsx +0 -212
  193. package/src/shell/Watermark.tsx +0 -9
  194. package/src/shell/fonts/fonts.css +0 -1133
  195. package/src/shell/icons.tsx +0 -335
  196. package/src/shell/toolbar-actions.ts +0 -59
  197. package/src/source/SourceView.tsx +0 -111
  198. package/src/source/find-highlight-source.ts +0 -57
  199. package/src/source/sutra-lang.ts +0 -121
  200. package/src/spellcheck/dictionaries.ts +0 -21
  201. package/src/spellcheck/hunspell.ts +0 -110
  202. package/src/spellcheck/spellcheck-plugin.ts +0 -83
  203. package/src/styles/StyleDialog.tsx +0 -148
  204. package/src/styles/builtin-styles.ts +0 -139
  205. package/src/styles/css-adapter.ts +0 -76
  206. package/src/styles/docx-adapter.ts +0 -109
  207. package/src/styles/embed-fonts.ts +0 -81
  208. package/src/styles/pagination.ts +0 -27
  209. package/src/styles/print-adapter.ts +0 -288
  210. package/src/styles/registry.ts +0 -20
  211. package/src/styles/screenplay.css +0 -3006
  212. package/src/styles/script-ranges.ts +0 -17
  213. package/src/styles/types.ts +0 -104
  214. package/src/styles/validate.ts +0 -114
  215. package/src/templates/templates.ts +0 -194
  216. package/src/titlepage/ExportDialog.tsx +0 -494
  217. package/src/titlepage/TitlePageDialog.tsx +0 -312
  218. package/src/titlepage/frontmatter-form.ts +0 -280
  219. package/src/titlepage/languages.ts +0 -37
  220. package/src/types.ts +0 -7
  221. package/tests/AppBar.test.tsx +0 -35
  222. package/tests/AppShell.test.tsx +0 -22
  223. package/tests/ElementToolbar.test.tsx +0 -36
  224. package/tests/LanguageStatus.test.tsx +0 -129
  225. package/tests/SelectionMenu.test.tsx +0 -71
  226. package/tests/ToolbarButton.test.tsx +0 -24
  227. package/tests/ai-onboarding.test.ts +0 -102
  228. package/tests/ai-status.test.tsx +0 -72
  229. package/tests/ai-structured.test.ts +0 -94
  230. package/tests/autocomplete/AutocompletePlugin.test.ts +0 -20
  231. package/tests/autocomplete/suggestions.test.ts +0 -106
  232. package/tests/document-context.test.tsx +0 -565
  233. package/tests/docx-importer.test.ts +0 -160
  234. package/tests/editor/character-decoration-plugin.test.ts +0 -101
  235. package/tests/editor/character-extension.test.ts +0 -44
  236. package/tests/editor/grapheme-cursor.test.ts +0 -118
  237. package/tests/editor/ime-plugin.test.ts +0 -72
  238. package/tests/editor/inline-note-bridge.test.ts +0 -32
  239. package/tests/editor/language-class-plugin.test.ts +0 -265
  240. package/tests/editor/title-page.test.ts +0 -124
  241. package/tests/embed-fonts.test.ts +0 -17
  242. package/tests/exporters.test.ts +0 -365
  243. package/tests/findreplace/FindReplace.test.tsx +0 -391
  244. package/tests/findreplace/find-engine.test.ts +0 -86
  245. package/tests/findreplace/scroll-to-match.test.ts +0 -50
  246. package/tests/fonts/tofu-detect.test.ts +0 -122
  247. package/tests/i18n/LanguageContext.test.tsx +0 -146
  248. package/tests/i18n/language-detect.test.ts +0 -54
  249. package/tests/i18n/locale-parity.test.ts +0 -25
  250. package/tests/i18n/useTranslation.test.tsx +0 -45
  251. package/tests/keymap.test.ts +0 -18
  252. package/tests/navigator/SceneNavigator.test.tsx +0 -177
  253. package/tests/navigator/StatisticsDialog.test.tsx +0 -63
  254. package/tests/navigator/scene-list.test.ts +0 -71
  255. package/tests/print-paginator.test.ts +0 -82
  256. package/tests/shell/VersionHistory.test.tsx +0 -129
  257. package/tests/spellcheck/hunspell.test.ts +0 -82
  258. package/tests/spellcheck/spellcheck-plugin.test.ts +0 -56
  259. package/tests/styles.test.ts +0 -315
  260. package/tests/templates/templates.test.ts +0 -83
  261. package/tests/titlepage/TitlePageDialog.test.tsx +0 -90
  262. package/tests/titlepage/apply-title-page.test.ts +0 -61
  263. package/tests/titlepage/frontmatter-form.test.ts +0 -115
  264. package/tests/toolbar-actions.test.ts +0 -93
  265. package/tests/voice-commands.test.ts +0 -58
  266. package/tsconfig.json +0 -17
  267. package/vitest.config.ts +0 -11
  268. package/vitest.setup.ts +0 -65
@@ -1,17 +0,0 @@
1
- /** Unicode block ranges for the complex scripts Sutrata recognizes, keyed by the same
2
- * lang codes used throughout (docx-exporter.ts's SCRIPT_FONT_BY_LANG, types.ts's
3
- * COMPLEX_SCRIPT_CODES, complexScriptFontOverrides / italicScripts). Shared so
4
- * docx-exporter.ts (font override) and workflow-reports.ts (forced-italic wrapping in the
5
- * print/PDF HTML) test the same ranges rather than maintaining two copies that could drift. */
6
- export const SCRIPT_UNICODE_RANGES: Record<string, RegExp> = {
7
- hi: /[ऀ-ॿ]/,
8
- ta: /[஀-௿]/,
9
- te: /[ఀ-౿]/,
10
- kn: /[ಀ-೿]/,
11
- ml: /[ഀ-ൿ]/,
12
- bn: /[ঀ-৿]/,
13
- gu: /[઀-૿]/,
14
- pa: /[਀-੿]/,
15
- or: /[଀-୿]/,
16
- si: /[඀-෿]/,
17
- }
@@ -1,104 +0,0 @@
1
- /** Screenplay body elements that carry a visual style — one entry per docx-exporter.ts
2
- * paragraph style / screenplay.css class. Excludes structural/chrome things
3
- * (scene metadata, page breaks, parenthetical parens) that aren't stylistic choices. */
4
- export const BODY_ELEMENT_KEYS = [
5
- 'sceneHeading', 'action', 'character', 'parenthetical', 'dialogue',
6
- 'transition', 'centered', 'lyrics', 'section', 'note', 'comment',
7
- ] as const
8
- export type BodyElementKey = typeof BODY_ELEMENT_KEYS[number]
9
-
10
- /** Cover-page elements. Export-only (DOCX/PDF) — there is no live editor
11
- * preview of the cover page today, so these never produce editor CSS vars. */
12
- export const COVER_ELEMENT_KEYS = ['title', 'author', 'logline'] as const
13
- export type CoverElementKey = typeof COVER_ELEMENT_KEYS[number]
14
-
15
- export interface ElementStyle {
16
- fontSizePt: number
17
- bold?: boolean
18
- italic?: boolean
19
- underline?: boolean
20
- /** 6 hex digits, no leading '#' (docx-native shape; CSS adapter adds the '#'). */
21
- color?: string
22
- /** Percentage of the printable content width. */
23
- marginLeftPct?: number
24
- marginRightPct?: number
25
- align?: 'left' | 'center' | 'right'
26
- /** Space before/after the paragraph, in points. DOCX-only: the live editor
27
- * only ever applies `spaceBeforePt` (as margin-top); adjacent elements in
28
- * the editor create their gap from the *following* element's margin-top,
29
- * not from a margin-bottom on the preceding one, so `spaceAfterPt` has no
30
- * editor-CSS effect — see css-adapter.ts. */
31
- spaceBeforePt?: number
32
- spaceAfterPt?: number
33
- }
34
-
35
- export type ScreenplayElements =
36
- Record<BodyElementKey, ElementStyle> & Record<CoverElementKey, ElementStyle>
37
-
38
- /** How the exported cover page arranges its blocks (DOCX + PDF; there is no editor
39
- * preview of the cover). 'centered' stacks everything down the middle of the page;
40
- * 'corners' puts title / "by <author>" / logline flush top-left and date + contact
41
- * down in the bottom-right, the arrangement Tamil shooting scripts print. Per-element
42
- * font/size/color still come from `elements.title|author|logline` either way — this
43
- * chooses the *placement* those elements are laid out in, nothing else. */
44
- export type CoverLayout = 'centered' | 'corners'
45
- export const COVER_LAYOUTS: readonly CoverLayout[] = ['centered', 'corners']
46
- export const DEFAULT_COVER_LAYOUT: CoverLayout = 'centered'
47
-
48
- export interface ScreenplayStyleDefinition {
49
- /** Stable slug: persisted in frontmatter's `style:` field and as the IndexedDB key. */
50
- id: string
51
- name: string
52
- description?: string
53
- /** Latin body font. For the live editor and PDF/print export this is just the
54
- * first entry in a CSS font stack (screenplay.css / print-adapter.ts put
55
- * 'Noto Sans'/script-specific Noto Sans fonts after it), so the browser's own
56
- * per-glyph fallback transparently covers any script this font doesn't have —
57
- * no per-style CSS plumbing needed. DOCX has no such per-glyph fallback
58
- * (a `w:rFonts` run property names exactly one font), so a style whose body
59
- * font *does* cover a non-Latin script it cares about (e.g. Traditional's
60
- * Vijaya for Tamil) must say so explicitly via `complexScriptFontOverrides`. */
61
- fontFamily: string
62
- /** Per-script font override, keyed by the same lang codes docx-exporter.ts's
63
- * getComplexFont switches on ('ta', 'hi', 'te', ...). Omit a script and it keeps
64
- * using the shared default (e.g. 'Noto Sans Tamil') — this is an opt-in exception,
65
- * not a requirement to theme every script. Consumed by all three renderers:
66
- * DOCX (docx-exporter.ts, where it's required — a `w:rFonts` run property names
67
- * exactly one font, so there's no per-glyph fallback to lean on), the live editor
68
- * (css-adapter.ts turns each entry into a `--cs-lang-<code>-font-family` CSS var
69
- * that screenplay.css's `.cs-lang-<code>` rules prefer over the generic Noto Sans
70
- * fallback), and PDF/print (print-adapter.ts folds the values into the body font
71
- * stack ahead of the generic Indic fallbacks). */
72
- complexScriptFontOverrides?: Record<string, string>
73
- /** Lang codes (same set as above) whose *default* presentation is italic under this
74
- * style — not "emphasized text happens to be italic", but "upright is not this
75
- * script's normal look here" (e.g. Traditional's Tamil, styled after Noto Serif
76
- * Tamil Italic to approximate Vijaya's slant). Forces italic even where the
77
- * element itself isn't (bold scene headings included) — confirmed as the intended
78
- * behavior, not layered underneath per-element italic. DOCX applies this
79
- * unconditionally per run; the editor applies it via a `.cs-force-italic-<code>`
80
- * class (see EditorView.tsx/css-adapter.ts) rather than a plain CSS var, because a
81
- * var would unconditionally set `font-style` and stomp elements that are
82
- * legitimately italic for their own reasons (lyrics, comments) on styles that
83
- * don't list the script here. PDF/print has no per-span language tagging, so this
84
- * has no effect there — a known, documented gap, not an oversight. */
85
- italicScripts?: string[]
86
- /** Defaults to DEFAULT_COVER_LAYOUT when a style (or an imported one) omits it. */
87
- coverLayout?: CoverLayout
88
- page: {
89
- marginTopIn: number
90
- marginBottomIn: number
91
- marginLeftIn: number
92
- marginRightIn: number
93
- }
94
- elements: ScreenplayElements
95
- }
96
-
97
- export const DEFAULT_STYLE_ID = 'classic'
98
-
99
- /** Lang codes docx-exporter.ts's getComplexFont / SCRIPT_RANGES recognize — the full
100
- * key space for `complexScriptFontOverrides` / `italicScripts`. Iterated by
101
- * css-adapter.ts to clear a previous style's per-script vars/classes when switching
102
- * to a style that doesn't set them (so nothing lingers). */
103
- export const COMPLEX_SCRIPT_CODES = ['hi', 'ta', 'te', 'kn', 'ml', 'bn', 'gu', 'pa', 'or', 'si'] as const
104
- export type ComplexScriptCode = typeof COMPLEX_SCRIPT_CODES[number]
@@ -1,114 +0,0 @@
1
- import { BODY_ELEMENT_KEYS, COVER_ELEMENT_KEYS, COVER_LAYOUTS } from './types.js'
2
- import type { ScreenplayStyleDefinition } from './types.js'
3
-
4
- export type ValidationResult =
5
- | { ok: true; style: ScreenplayStyleDefinition }
6
- | { ok: false; errors: string[] }
7
-
8
- const ALIGNS = new Set(['left', 'center', 'right'])
9
- const COLOR_RE = /^[0-9a-fA-F]{6}$/
10
-
11
- function isFiniteNumber(v: unknown): v is number {
12
- return typeof v === 'number' && Number.isFinite(v)
13
- }
14
-
15
- function validateElement(path: string, data: unknown, errors: string[]): void {
16
- if (typeof data !== 'object' || data === null) {
17
- errors.push(`${path}: expected an object`)
18
- return
19
- }
20
- const el = data as Record<string, unknown>
21
- if (!isFiniteNumber(el['fontSizePt']) || el['fontSizePt'] <= 0) {
22
- errors.push(`${path}.fontSizePt: expected a positive number`)
23
- }
24
- for (const flag of ['bold', 'italic', 'underline'] as const) {
25
- if (el[flag] !== undefined && typeof el[flag] !== 'boolean') {
26
- errors.push(`${path}.${flag}: expected a boolean`)
27
- }
28
- }
29
- if (el['color'] !== undefined && (typeof el['color'] !== 'string' || !COLOR_RE.test(el['color']))) {
30
- errors.push(`${path}.color: expected 6 hex digits with no '#' (e.g. "0A5C6A")`)
31
- }
32
- for (const marginKey of ['marginLeftPct', 'marginRightPct'] as const) {
33
- const v = el[marginKey]
34
- if (v !== undefined && (!isFiniteNumber(v) || v < 0 || v > 100)) {
35
- errors.push(`${path}.${marginKey}: expected a number between 0 and 100`)
36
- }
37
- }
38
- if (el['align'] !== undefined && (typeof el['align'] !== 'string' || !ALIGNS.has(el['align']))) {
39
- errors.push(`${path}.align: expected "left", "center", or "right"`)
40
- }
41
- for (const spaceKey of ['spaceBeforePt', 'spaceAfterPt'] as const) {
42
- const v = el[spaceKey]
43
- if (v !== undefined && !isFiniteNumber(v)) {
44
- errors.push(`${path}.${spaceKey}: expected a number`)
45
- }
46
- }
47
- }
48
-
49
- /** Hand-rolled structural validation for a style imported from a .json file — no schema
50
- * library dependency, matching the codebase's other hand-rolled parsers (frontmatter.ts).
51
- * Collects every error found rather than failing on the first, for a useful import message. */
52
- export function validateStyleJson(data: unknown): ValidationResult {
53
- const errors: string[] = []
54
- if (typeof data !== 'object' || data === null) {
55
- return { ok: false, errors: ['Expected a JSON object'] }
56
- }
57
- const obj = data as Record<string, unknown>
58
-
59
- for (const key of ['id', 'name', 'fontFamily'] as const) {
60
- if (typeof obj[key] !== 'string' || obj[key] === '') {
61
- errors.push(`${key}: expected a non-empty string`)
62
- }
63
- }
64
- if (obj['description'] !== undefined && typeof obj['description'] !== 'string') {
65
- errors.push('description: expected a string')
66
- }
67
- if (obj['complexScriptFontOverrides'] !== undefined) {
68
- const overrides = obj['complexScriptFontOverrides']
69
- if (typeof overrides !== 'object' || overrides === null) {
70
- errors.push('complexScriptFontOverrides: expected an object')
71
- } else if (Object.values(overrides).some(v => typeof v !== 'string' || v === '')) {
72
- errors.push('complexScriptFontOverrides: expected every value to be a non-empty string')
73
- }
74
- }
75
- if (obj['italicScripts'] !== undefined) {
76
- const scripts = obj['italicScripts']
77
- if (!Array.isArray(scripts) || scripts.some(v => typeof v !== 'string' || v === '')) {
78
- errors.push('italicScripts: expected an array of non-empty strings')
79
- }
80
- }
81
-
82
- if (obj['coverLayout'] !== undefined && !COVER_LAYOUTS.includes(obj['coverLayout'] as never)) {
83
- errors.push(`coverLayout: expected ${COVER_LAYOUTS.map(l => `"${l}"`).join(' or ')}`)
84
- }
85
-
86
- const page = obj['page']
87
- if (typeof page !== 'object' || page === null) {
88
- errors.push('page: expected an object')
89
- } else {
90
- const p = page as Record<string, unknown>
91
- for (const key of ['marginTopIn', 'marginBottomIn', 'marginLeftIn', 'marginRightIn'] as const) {
92
- if (!isFiniteNumber(p[key]) || p[key] < 0) {
93
- errors.push(`page.${key}: expected a non-negative number`)
94
- }
95
- }
96
- }
97
-
98
- const elements = obj['elements']
99
- if (typeof elements !== 'object' || elements === null) {
100
- errors.push('elements: expected an object')
101
- } else {
102
- const el = elements as Record<string, unknown>
103
- for (const key of [...BODY_ELEMENT_KEYS, ...COVER_ELEMENT_KEYS]) {
104
- if (!(key in el)) {
105
- errors.push(`elements.${key}: missing`)
106
- } else {
107
- validateElement(`elements.${key}`, el[key], errors)
108
- }
109
- }
110
- }
111
-
112
- if (errors.length > 0) return { ok: false, errors }
113
- return { ok: true, style: obj as unknown as ScreenplayStyleDefinition }
114
- }
@@ -1,194 +0,0 @@
1
- /**
2
- * Localized screenplay templates for each supported script.
3
- * Returns a starter Sutra document in the target language.
4
- */
5
-
6
- export const TEMPLATES: Record<string, string> = {
7
- en: `---
8
- title: Untitled Screenplay
9
- lang: en
10
- ---
11
-
12
- ## INT. ROOM - DAY
13
-
14
- A writer sits at a desk, staring at a blank screen.
15
-
16
- @WRITER
17
- (to themselves)
18
- Where do I begin?
19
-
20
- `,
21
-
22
- hi: `---
23
- title: अनाम पटकथा
24
- lang: hi
25
- ---
26
-
27
- ## आंत. कमरा - दिन
28
-
29
- एक लेखक मेज पर बैठा है, खाली स्क्रीन को देख रहा है।
30
-
31
- @लेखक
32
- (खुद से)
33
- मैं कहाँ से शुरू करूँ?
34
-
35
- `,
36
-
37
- ta: `---
38
- title: தலைப்பற்ற திரைக்கதை
39
- lang: ta
40
- ---
41
-
42
- ## உள்ளே. அறை - பகல்
43
-
44
- ஒரு எழுத்தாளர் மேசையில் அமர்ந்து, வெற்று திரையை பார்க்கிறார்.
45
-
46
- @எழுத்தாளர்
47
- (தனக்கே)
48
- நான் எங்கிருந்து தொடங்குவது?
49
-
50
- `,
51
-
52
- te: `---
53
- title: పేరులేని స్క్రీన్‌ప్లే
54
- lang: te
55
- ---
56
-
57
- ## లోపల. గది - పగలు
58
-
59
- ఒక రచయిత బల్లదగ్గర కూర్చుని, ఖాళీ స్క్రీన్‌ని చూస్తున్నారు.
60
-
61
- @రచయిత
62
- (తమలో తాము)
63
- నేను ఎక్కడ నుండి ప్రారంభించాలి?
64
-
65
- `,
66
-
67
- kn: `---
68
- title: ಹೆಸರಿಲ್ಲದ ಚಲನಚಿತ್ರ ಕಥೆ
69
- lang: kn
70
- ---
71
-
72
- ## ಒಳಗೆ. ಕೋಣೆ - ಹಗಲು
73
-
74
- ಒಬ್ಬ ಬರಹಗಾರ ಮೇಜಿನ ಬಳಿ ಕುಳಿತು, ಖಾಲಿ ಪರದೆಯನ್ನು ನೋಡುತ್ತಿದ್ದಾರೆ.
75
-
76
- @ಬರಹಗಾರ
77
- (ತಮ್ಮಷ್ಟಕ್ಕೆ)
78
- ನಾನು ಎಲ್ಲಿಂದ ಪ್ರಾರಂಭಿಸಲಿ?
79
-
80
- `,
81
-
82
- ml: `---
83
- title: പേരില്ലാത്ത തിരക്കഥ
84
- lang: ml
85
- ---
86
-
87
- ## അകത്ത്. മുറി - പകൽ
88
-
89
- ഒരു എഴുത്തുകാരൻ മേശയ്ക്കരുകിൽ ഇരുന്ന്, ശൂന്യമായ സ്ക്രീൻ നോക്കുന്നു.
90
-
91
- @എഴുത്തുകാരൻ
92
- (സ്വയം)
93
- ഞാൻ എവിടെ നിന്ന് തുടങ്ങണം?
94
-
95
- `,
96
-
97
- bn: `---
98
- title: নামহীন চিত্রনাট্য
99
- lang: bn
100
- ---
101
-
102
- ## ভেতরে. ঘর - দিন
103
-
104
- একজন লেখক টেবিলের পাশে বসে, ফাঁকা পর্দার দিকে তাকিয়ে আছেন।
105
-
106
- @লেখক
107
- (নিজের মনে)
108
- আমি কোথা থেকে শুরু করব?
109
-
110
- `,
111
-
112
- gu: `---
113
- title: અનામ પટકથા
114
- lang: gu
115
- ---
116
-
117
- ## અંદર. ઓરડો - દિવસ
118
-
119
- એક લેખક ટેબલ પર બેઠો છે, ખાલી સ્ક્રીન જોઈ રહ્યો છે.
120
-
121
- @લેખક
122
- (પોતાની જાતને)
123
- હું ક્યાંથી શરૂ કરું?
124
-
125
- `,
126
-
127
- mr: `---
128
- title: अनाम पटकथा
129
- lang: mr
130
- ---
131
-
132
- ## आत. खोली - दिवस
133
-
134
- एक लेखक टेबलावर बसला आहे, रिकाम्या स्क्रीनकडे पाहत आहे.
135
-
136
- @लेखक
137
- (स्वतःशी)
138
- मी कुठून सुरुवात करू?
139
-
140
- `,
141
-
142
- pa: `---
143
- title: ਬੇਨਾਮ ਸਕ੍ਰੀਨਪਲੇ
144
- lang: pa
145
- ---
146
-
147
- ## ਅੰਦਰ. ਕਮਰਾ - ਦਿਨ
148
-
149
- ਇੱਕ ਲੇਖਕ ਮੇਜ਼ ਕੋਲ ਬੈਠਾ ਹੈ, ਖਾਲੀ ਸਕ੍ਰੀਨ ਵੱਲ ਦੇਖ ਰਿਹਾ ਹੈ।
150
-
151
- @ਲੇਖਕ
152
- (ਆਪਣੇ ਆਪ ਨੂੰ)
153
- ਮੈਂ ਕਿੱਥੋਂ ਸ਼ੁਰੂ ਕਰਾਂ?
154
-
155
- `,
156
-
157
- or: `---
158
- title: ଅନାମ ଚଳଚ୍ଚିତ୍ର ଲିପି
159
- lang: or
160
- ---
161
-
162
- ## ଭିତର. କୋଠରୀ - ଦିନ
163
-
164
- ଜଣେ ଲେଖକ ଟେବୁଲ ପାଖରେ ବସି, ଖାଲି ସ୍କ୍ରୀନ ଆଡ଼କୁ ଚାହିଁ ରହିଛନ୍ତି।
165
-
166
- @ଲେଖକ
167
- (ନିଜ ମନରେ)
168
- ମୁଁ କୁଆଡ଼ୁ ଆରମ୍ଭ କରିବି?
169
-
170
- `,
171
-
172
- si: `---
173
- title: නම් නොකළ තිර රචනය
174
- lang: si
175
- ---
176
-
177
- ## ඇතුළත. කාමරය - දවල්
178
-
179
- ලේඛකයෙක් මේසයක් ළඟ වාඩි වී, හිස් තිරයක් දෙස බලා සිටියි.
180
-
181
- @ලේඛකයා
182
- (තමන්ටම)
183
- මම කොහෙන්ද පටන් ගන්නේ?
184
-
185
- `,
186
- }
187
-
188
- /**
189
- * Get the starter template for a given language code.
190
- * Falls back to English if no template for the requested language.
191
- */
192
- export function getTemplate(lang: string): string {
193
- return TEMPLATES[lang] ?? TEMPLATES['en'] ?? ''
194
- }