bookish-press 0.4.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 (309) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +5 -0
  3. package/components/Auth.svelte +52 -0
  4. package/components/Auth.svelte.d.ts +16 -0
  5. package/components/Authentication.d.ts +8 -0
  6. package/components/Authentication.js +1 -0
  7. package/components/BookPreview.svelte +87 -0
  8. package/components/BookPreview.svelte.d.ts +18 -0
  9. package/components/External.svelte +4 -0
  10. package/components/External.svelte.d.ts +18 -0
  11. package/components/Link.svelte +5 -0
  12. package/components/Link.svelte.d.ts +19 -0
  13. package/components/chapter/Atom.svelte +36 -0
  14. package/components/chapter/Atom.svelte.d.ts +19 -0
  15. package/components/chapter/Block.svelte +32 -0
  16. package/components/chapter/Block.svelte.d.ts +17 -0
  17. package/components/chapter/Callout.svelte +10 -0
  18. package/components/chapter/Callout.svelte.d.ts +17 -0
  19. package/components/chapter/CaptionedCode.svelte +34 -0
  20. package/components/chapter/CaptionedCode.svelte.d.ts +17 -0
  21. package/components/chapter/ChapterBody.svelte +23 -0
  22. package/components/chapter/ChapterBody.svelte.d.ts +18 -0
  23. package/components/chapter/Citations.svelte +66 -0
  24. package/components/chapter/Citations.svelte.d.ts +17 -0
  25. package/components/chapter/Code.svelte +35 -0
  26. package/components/chapter/Code.svelte.d.ts +22 -0
  27. package/components/chapter/Comment.svelte +46 -0
  28. package/components/chapter/Comment.svelte.d.ts +17 -0
  29. package/components/chapter/Definition.svelte +38 -0
  30. package/components/chapter/Definition.svelte.d.ts +20 -0
  31. package/components/chapter/Embed.svelte +122 -0
  32. package/components/chapter/Embed.svelte.d.ts +18 -0
  33. package/components/chapter/ErrorMessage.svelte +4 -0
  34. package/components/chapter/ErrorMessage.svelte.d.ts +17 -0
  35. package/components/chapter/Footnote.svelte +37 -0
  36. package/components/chapter/Footnote.svelte.d.ts +19 -0
  37. package/components/chapter/Format.svelte +57 -0
  38. package/components/chapter/Format.svelte.d.ts +18 -0
  39. package/components/chapter/InlineCode.svelte +12 -0
  40. package/components/chapter/InlineCode.svelte.d.ts +17 -0
  41. package/components/chapter/Label.svelte +20 -0
  42. package/components/chapter/Label.svelte.d.ts +17 -0
  43. package/components/chapter/Link.svelte +51 -0
  44. package/components/chapter/Link.svelte.d.ts +17 -0
  45. package/components/chapter/List.svelte +14 -0
  46. package/components/chapter/List.svelte.d.ts +17 -0
  47. package/components/chapter/Marginal.svelte +48 -0
  48. package/components/chapter/Marginal.svelte.d.ts +19 -0
  49. package/components/chapter/Paragraph.svelte +15 -0
  50. package/components/chapter/Paragraph.svelte.d.ts +18 -0
  51. package/components/chapter/Python.svelte +81 -0
  52. package/components/chapter/Python.svelte.d.ts +18 -0
  53. package/components/chapter/Quote.svelte +16 -0
  54. package/components/chapter/Quote.svelte.d.ts +17 -0
  55. package/components/chapter/Rule.svelte +4 -0
  56. package/components/chapter/Rule.svelte.d.ts +17 -0
  57. package/components/chapter/Table.svelte +29 -0
  58. package/components/chapter/Table.svelte.d.ts +17 -0
  59. package/components/chapter/Text.svelte +62 -0
  60. package/components/chapter/Text.svelte.d.ts +17 -0
  61. package/components/chapter/renderPosition.d.ts +3 -0
  62. package/components/chapter/renderPosition.js +4 -0
  63. package/components/editor/BookishEditor.svelte +755 -0
  64. package/components/editor/BookishEditor.svelte.d.ts +22 -0
  65. package/components/editor/CalloutEditor.svelte +10 -0
  66. package/components/editor/CalloutEditor.svelte.d.ts +17 -0
  67. package/components/editor/CaptionedCodeEditor.svelte +22 -0
  68. package/components/editor/CaptionedCodeEditor.svelte.d.ts +17 -0
  69. package/components/editor/CaretContext.d.ts +18 -0
  70. package/components/editor/CaretContext.js +1 -0
  71. package/components/editor/CaretState.d.ts +47 -0
  72. package/components/editor/CaretState.js +1 -0
  73. package/components/editor/CaretUtilities.d.ts +5 -0
  74. package/components/editor/CaretUtilities.js +1 -0
  75. package/components/editor/CitationsEditor.svelte +42 -0
  76. package/components/editor/CitationsEditor.svelte.d.ts +17 -0
  77. package/components/editor/Clipboard.d.ts +3 -0
  78. package/components/editor/Clipboard.js +1 -0
  79. package/components/editor/Command.d.ts +18 -0
  80. package/components/editor/Command.js +1 -0
  81. package/components/editor/Commands.d.ts +3 -0
  82. package/components/editor/Commands.js +951 -0
  83. package/components/editor/ConfirmButton.svelte +43 -0
  84. package/components/editor/ConfirmButton.svelte.d.ts +18 -0
  85. package/components/editor/DefinitionEditor.svelte +28 -0
  86. package/components/editor/DefinitionEditor.svelte.d.ts +17 -0
  87. package/components/editor/EmbedEditor.svelte +87 -0
  88. package/components/editor/EmbedEditor.svelte.d.ts +17 -0
  89. package/components/editor/ImageChooser.svelte +70 -0
  90. package/components/editor/ImageChooser.svelte.d.ts +18 -0
  91. package/components/editor/InlineCodeEditor.svelte +9 -0
  92. package/components/editor/InlineCodeEditor.svelte.d.ts +17 -0
  93. package/components/editor/LabelEditor.svelte +23 -0
  94. package/components/editor/LabelEditor.svelte.d.ts +17 -0
  95. package/components/editor/LanguageEditor.svelte +11 -0
  96. package/components/editor/LanguageEditor.svelte.d.ts +17 -0
  97. package/components/editor/LinkEditor.svelte +75 -0
  98. package/components/editor/LinkEditor.svelte.d.ts +17 -0
  99. package/components/editor/Note.svelte +9 -0
  100. package/components/editor/Note.svelte.d.ts +23 -0
  101. package/components/editor/PositionEditor.svelte +14 -0
  102. package/components/editor/PositionEditor.svelte.d.ts +18 -0
  103. package/components/editor/QuoteEditor.svelte +5 -0
  104. package/components/editor/QuoteEditor.svelte.d.ts +17 -0
  105. package/components/editor/Switch.svelte +56 -0
  106. package/components/editor/Switch.svelte.d.ts +20 -0
  107. package/components/editor/TextEditor.svelte +193 -0
  108. package/components/editor/TextEditor.svelte.d.ts +23 -0
  109. package/components/editor/Toggle.svelte +38 -0
  110. package/components/editor/Toggle.svelte.d.ts +19 -0
  111. package/components/editor/Toolbar.svelte +202 -0
  112. package/components/editor/Toolbar.svelte.d.ts +20 -0
  113. package/components/editor/ToolbarGroup.svelte +41 -0
  114. package/components/editor/ToolbarGroup.svelte.d.ts +19 -0
  115. package/components/editor/ToolbarIcon.svelte +22 -0
  116. package/components/editor/ToolbarIcon.svelte.d.ts +16 -0
  117. package/components/editor/ToolbarSpacer.svelte +1 -0
  118. package/components/editor/ToolbarSpacer.svelte.d.ts +19 -0
  119. package/components/editor/URLEditor.svelte +15 -0
  120. package/components/editor/URLEditor.svelte.d.ts +18 -0
  121. package/components/editor/UndoState.d.ts +8 -0
  122. package/components/editor/UndoState.js +1 -0
  123. package/components/page/Acknowledgements.svelte +29 -0
  124. package/components/page/Acknowledgements.svelte.d.ts +14 -0
  125. package/components/page/Alert.svelte +11 -0
  126. package/components/page/Alert.svelte.d.ts +23 -0
  127. package/components/page/Authors.svelte +62 -0
  128. package/components/page/Authors.svelte.d.ts +20 -0
  129. package/components/page/BulkReferenceEditor.svelte +32 -0
  130. package/components/page/BulkReferenceEditor.svelte.d.ts +14 -0
  131. package/components/page/Chapter.svelte +301 -0
  132. package/components/page/Chapter.svelte.d.ts +18 -0
  133. package/components/page/ChapterContext.d.ts +10 -0
  134. package/components/page/ChapterContext.js +1 -0
  135. package/components/page/Contexts.d.ts +27 -0
  136. package/components/page/Contexts.js +21 -0
  137. package/components/page/DefinitionView.svelte +129 -0
  138. package/components/page/DefinitionView.svelte.d.ts +18 -0
  139. package/components/page/Description.svelte +22 -0
  140. package/components/page/Description.svelte.d.ts +14 -0
  141. package/components/page/Edition.svelte +106 -0
  142. package/components/page/Edition.svelte.d.ts +21 -0
  143. package/components/page/Glossary.svelte +61 -0
  144. package/components/page/Glossary.svelte.d.ts +14 -0
  145. package/components/page/Header.svelte +105 -0
  146. package/components/page/Header.svelte.d.ts +27 -0
  147. package/components/page/Index.svelte +117 -0
  148. package/components/page/Index.svelte.d.ts +14 -0
  149. package/components/page/Instructions.svelte +30 -0
  150. package/components/page/Instructions.svelte.d.ts +16 -0
  151. package/components/page/License.svelte +29 -0
  152. package/components/page/License.svelte.d.ts +14 -0
  153. package/components/page/Loading.svelte +13 -0
  154. package/components/page/Loading.svelte.d.ts +19 -0
  155. package/components/page/Media.svelte +76 -0
  156. package/components/page/Media.svelte.d.ts +14 -0
  157. package/components/page/MediaPreview.svelte +11 -0
  158. package/components/page/MediaPreview.svelte.d.ts +19 -0
  159. package/components/page/Outline.svelte +173 -0
  160. package/components/page/Outline.svelte.d.ts +19 -0
  161. package/components/page/Page.svelte +53 -0
  162. package/components/page/Page.svelte.d.ts +19 -0
  163. package/components/page/PossibleChapter.svelte +14 -0
  164. package/components/page/PossibleChapter.svelte.d.ts +14 -0
  165. package/components/page/PossibleReference.svelte +16 -0
  166. package/components/page/PossibleReference.svelte.d.ts +19 -0
  167. package/components/page/Print.svelte +8 -0
  168. package/components/page/Print.svelte.d.ts +14 -0
  169. package/components/page/Reference.svelte +145 -0
  170. package/components/page/Reference.svelte.d.ts +17 -0
  171. package/components/page/References.svelte +58 -0
  172. package/components/page/References.svelte.d.ts +14 -0
  173. package/components/page/Revisions.svelte +124 -0
  174. package/components/page/Revisions.svelte.d.ts +14 -0
  175. package/components/page/Search.svelte +108 -0
  176. package/components/page/Search.svelte.d.ts +14 -0
  177. package/components/page/Status.svelte +49 -0
  178. package/components/page/Status.svelte.d.ts +19 -0
  179. package/components/page/SubdomainEditor.svelte +30 -0
  180. package/components/page/SubdomainEditor.svelte.d.ts +14 -0
  181. package/components/page/TableOfContents.svelte +234 -0
  182. package/components/page/TableOfContents.svelte.d.ts +14 -0
  183. package/components/page/TableOfContentsImage.svelte +15 -0
  184. package/components/page/TableOfContentsImage.svelte.d.ts +16 -0
  185. package/components/page/TableOfContentsRow.svelte +57 -0
  186. package/components/page/TableOfContentsRow.svelte.d.ts +24 -0
  187. package/components/page/ThemeEditor.svelte +52 -0
  188. package/components/page/ThemeEditor.svelte.d.ts +14 -0
  189. package/components/page/ThemeEditorPreview.svelte +37 -0
  190. package/components/page/ThemeEditorPreview.svelte.d.ts +17 -0
  191. package/components/page/ThemeSetEditor.svelte +17 -0
  192. package/components/page/ThemeSetEditor.svelte.d.ts +18 -0
  193. package/components/page/ThemeVariableEditor.svelte +28 -0
  194. package/components/page/ThemeVariableEditor.svelte.d.ts +18 -0
  195. package/components/page/Unknown.svelte +29 -0
  196. package/components/page/Unknown.svelte.d.ts +16 -0
  197. package/components/page/margins.d.ts +2 -0
  198. package/components/page/margins.js +132 -0
  199. package/models/BookLoader.d.ts +2 -0
  200. package/models/BookLoader.js +67 -0
  201. package/models/Firebase.d.ts +4 -0
  202. package/models/Firebase.js +26 -0
  203. package/models/Firestore.d.ts +22 -0
  204. package/models/Firestore.js +194 -0
  205. package/models/book/Book.d.ts +60 -0
  206. package/models/book/Book.js +135 -0
  207. package/models/book/BookMedia.d.ts +23 -0
  208. package/models/book/BookMedia.js +102 -0
  209. package/models/book/Chapter.d.ts +70 -0
  210. package/models/book/Chapter.js +221 -0
  211. package/models/book/ChapterID.d.ts +10 -0
  212. package/models/book/ChapterID.js +10 -0
  213. package/models/book/Definition.d.ts +6 -0
  214. package/models/book/Definition.js +1 -0
  215. package/models/book/Edition.d.ts +111 -0
  216. package/models/book/Edition.js +466 -0
  217. package/models/book/Theme.d.ts +106 -0
  218. package/models/book/Theme.js +76 -0
  219. package/models/book/ThemeColors.d.ts +15 -0
  220. package/models/book/ThemeColors.js +1 -0
  221. package/models/chapter/AtomNode.d.ts +18 -0
  222. package/models/chapter/AtomNode.js +31 -0
  223. package/models/chapter/BlockNode.d.ts +21 -0
  224. package/models/chapter/BlockNode.js +117 -0
  225. package/models/chapter/BlocksNode.d.ts +50 -0
  226. package/models/chapter/BlocksNode.js +709 -0
  227. package/models/chapter/BlocksNode.test.d.ts +1 -0
  228. package/models/chapter/BlocksNode.test.js +302 -0
  229. package/models/chapter/Bookkeeping.d.ts +4 -0
  230. package/models/chapter/Bookkeeping.js +1 -0
  231. package/models/chapter/CalloutNode.d.ts +17 -0
  232. package/models/chapter/CalloutNode.js +36 -0
  233. package/models/chapter/Caret.d.ts +21 -0
  234. package/models/chapter/Caret.js +69 -0
  235. package/models/chapter/ChapterNode.d.ts +34 -0
  236. package/models/chapter/ChapterNode.js +80 -0
  237. package/models/chapter/CitationsNode.d.ts +16 -0
  238. package/models/chapter/CitationsNode.js +17 -0
  239. package/models/chapter/CodeNode.d.ts +30 -0
  240. package/models/chapter/CodeNode.js +64 -0
  241. package/models/chapter/CommentNode.d.ts +18 -0
  242. package/models/chapter/CommentNode.js +32 -0
  243. package/models/chapter/DefinitionNode.d.ts +12 -0
  244. package/models/chapter/DefinitionNode.js +20 -0
  245. package/models/chapter/Edit.d.ts +7 -0
  246. package/models/chapter/Edit.js +1 -0
  247. package/models/chapter/EmbedNode.d.ts +40 -0
  248. package/models/chapter/EmbedNode.js +89 -0
  249. package/models/chapter/ErrorNode.d.ts +17 -0
  250. package/models/chapter/ErrorNode.js +21 -0
  251. package/models/chapter/FootnoteNode.d.ts +18 -0
  252. package/models/chapter/FootnoteNode.js +29 -0
  253. package/models/chapter/FormatNode.d.ts +60 -0
  254. package/models/chapter/FormatNode.js +614 -0
  255. package/models/chapter/FormatNode.test.d.ts +1 -0
  256. package/models/chapter/FormatNode.test.js +54 -0
  257. package/models/chapter/InlineCodeNode.d.ts +12 -0
  258. package/models/chapter/InlineCodeNode.js +18 -0
  259. package/models/chapter/LabelNode.d.ts +17 -0
  260. package/models/chapter/LabelNode.js +22 -0
  261. package/models/chapter/LinkNode.d.ts +12 -0
  262. package/models/chapter/LinkNode.js +16 -0
  263. package/models/chapter/ListNode.d.ts +51 -0
  264. package/models/chapter/ListNode.js +370 -0
  265. package/models/chapter/ListNode.test.d.ts +1 -0
  266. package/models/chapter/ListNode.test.js +49 -0
  267. package/models/chapter/MetadataNode.d.ts +17 -0
  268. package/models/chapter/MetadataNode.js +24 -0
  269. package/models/chapter/Node.d.ts +36 -0
  270. package/models/chapter/Node.js +173 -0
  271. package/models/chapter/Node.test.d.ts +1 -0
  272. package/models/chapter/Node.test.js +27 -0
  273. package/models/chapter/ParagraphNode.d.ts +33 -0
  274. package/models/chapter/ParagraphNode.js +93 -0
  275. package/models/chapter/ParagraphNode.test.d.ts +1 -0
  276. package/models/chapter/ParagraphNode.test.js +21 -0
  277. package/models/chapter/Parser.d.ts +75 -0
  278. package/models/chapter/Parser.js +824 -0
  279. package/models/chapter/Parser.test.d.ts +1 -0
  280. package/models/chapter/Parser.test.js +25 -0
  281. package/models/chapter/Position.d.ts +2 -0
  282. package/models/chapter/Position.js +1 -0
  283. package/models/chapter/QuoteNode.d.ts +25 -0
  284. package/models/chapter/QuoteNode.js +61 -0
  285. package/models/chapter/ReferenceNode.d.ts +29 -0
  286. package/models/chapter/ReferenceNode.js +48 -0
  287. package/models/chapter/RootNode.d.ts +5 -0
  288. package/models/chapter/RootNode.js +1 -0
  289. package/models/chapter/RuleNode.d.ts +15 -0
  290. package/models/chapter/RuleNode.js +16 -0
  291. package/models/chapter/TableNode.d.ts +35 -0
  292. package/models/chapter/TableNode.js +176 -0
  293. package/models/chapter/TableNode.test.d.ts +1 -0
  294. package/models/chapter/TableNode.test.js +31 -0
  295. package/models/chapter/TextNode.d.ts +36 -0
  296. package/models/chapter/TextNode.js +136 -0
  297. package/models/chapter/TextNode.test.d.ts +1 -0
  298. package/models/chapter/TextNode.test.js +6 -0
  299. package/models/loadEdition.d.ts +5 -0
  300. package/models/loadEdition.js +16 -0
  301. package/package.json +189 -0
  302. package/util/getSubdomain.d.ts +3 -0
  303. package/util/getSubdomain.js +22 -0
  304. package/util/isMobile.d.ts +2 -0
  305. package/util/isMobile.js +6 -0
  306. package/util/mineReference.d.ts +3 -0
  307. package/util/mineReference.js +62 -0
  308. package/util/scrollToEyeLevel.d.ts +2 -0
  309. package/util/scrollToEyeLevel.js +5 -0
@@ -0,0 +1,8 @@
1
+ import type { IndexRange } from "../../models/chapter/Caret";
2
+ import type Command from "./Command";
3
+ declare type UndoState = {
4
+ command: Command | undefined;
5
+ bookdown: string;
6
+ range: IndexRange;
7
+ };
8
+ export default UndoState;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,29 @@
1
+ <script>import Parser from "../../models/chapter/Parser";
2
+ import ChapterBody from "../chapter/ChapterBody.svelte";
3
+ import BookishEditor from "../editor/BookishEditor.svelte";
4
+ import Instructions from "./Instructions.svelte";
5
+ import { getEdition, isEditable } from "./Contexts";
6
+ let edition = getEdition();
7
+ let editable = isEditable();
8
+ $: acknowledgements = $edition.getAcknowledgements();
9
+ $: acksNode = Parser.parseChapter($edition, acknowledgements);
10
+ </script>
11
+
12
+ <Instructions>
13
+ This section is not shown if empty.
14
+ But surely you have someone to thank!
15
+ </Instructions>
16
+
17
+ <!-- If editable, show acknowledgements even if they're empty, otherwise hide -->
18
+ {#if editable }
19
+ <BookishEditor
20
+ ast={acksNode}
21
+ chapter={false}
22
+ component={ChapterBody}
23
+ placeholder="Who would you like to thank?"
24
+ save={node => $edition.setAcknowledgements(node.toBookdown())}
25
+ />
26
+ {:else if acknowledgements.length > 0 }
27
+ <h2 class="bookish-header" id="acknowledgements">Acknowledgements</h2>
28
+ <ChapterBody node={acksNode}/>
29
+ {/if}
@@ -0,0 +1,14 @@
1
+ import { SvelteComponentTyped } from "svelte";
2
+ declare const __propDef: {
3
+ props: {};
4
+ events: {
5
+ [evt: string]: CustomEvent<any>;
6
+ };
7
+ slots: {};
8
+ };
9
+ export declare type AcknowledgementsProps = typeof __propDef.props;
10
+ export declare type AcknowledgementsEvents = typeof __propDef.events;
11
+ export declare type AcknowledgementsSlots = typeof __propDef.slots;
12
+ export default class Acknowledgements extends SvelteComponentTyped<AcknowledgementsProps, AcknowledgementsEvents, AcknowledgementsSlots> {
13
+ }
14
+ export {};
@@ -0,0 +1,11 @@
1
+ <section><slot></slot></section>
2
+
3
+ <style>
4
+ section {
5
+ margin-top: 1em;
6
+ margin-bottom: 1em;
7
+ background-color: var(--bookish-app-error-background);
8
+ color: var(--bookish-app-error-color);
9
+ padding: var(--bookish-app-chrome-padding);
10
+ }
11
+ </style>
@@ -0,0 +1,23 @@
1
+ /** @typedef {typeof __propDef.props} AlertProps */
2
+ /** @typedef {typeof __propDef.events} AlertEvents */
3
+ /** @typedef {typeof __propDef.slots} AlertSlots */
4
+ export default class Alert extends SvelteComponentTyped<{}, {
5
+ [evt: string]: CustomEvent<any>;
6
+ }, {
7
+ default: {};
8
+ }> {
9
+ }
10
+ export type AlertProps = typeof __propDef.props;
11
+ export type AlertEvents = typeof __propDef.events;
12
+ export type AlertSlots = typeof __propDef.slots;
13
+ import { SvelteComponentTyped } from "svelte";
14
+ declare const __propDef: {
15
+ props: {};
16
+ events: {
17
+ [evt: string]: CustomEvent<any>;
18
+ };
19
+ slots: {
20
+ default: {};
21
+ };
22
+ };
23
+ export {};
@@ -0,0 +1,62 @@
1
+ <script>import Parser from '../../models/chapter/Parser';
2
+ import TextEditor from '../editor/TextEditor.svelte';
3
+ import Format from '../chapter/Format.svelte';
4
+ import { afterUpdate } from 'svelte';
5
+ import { getEdition, isEditable } from './Contexts';
6
+ import Note from '../editor/Note.svelte';
7
+ export let authors;
8
+ export let inheritedAuthors = undefined;
9
+ export let add;
10
+ export let edit;
11
+ export let remove;
12
+ let editable = isEditable();
13
+ let edition = getEdition();
14
+ let authorList = null;
15
+ let newAuthor = false;
16
+ function addAuthor() {
17
+ add();
18
+ newAuthor = true;
19
+ }
20
+ // When there's a new author, focus on it.
21
+ afterUpdate(() => {
22
+ if (authors.length > 0 && authorList && newAuthor) {
23
+ const editors = authorList.querySelectorAll("input");
24
+ if (editors.length > 0) {
25
+ const lastAuthor = editors[editors.length - 1];
26
+ if (lastAuthor instanceof HTMLElement) {
27
+ lastAuthor.focus();
28
+ }
29
+ }
30
+ newAuthor = false;
31
+ }
32
+ });
33
+ </script>
34
+
35
+ <div class="bookish-authors" bind:this={authorList}>
36
+ {#if authors.length === 0 }
37
+ {#if editable && inheritedAuthors !== undefined && inheritedAuthors.length > 0 }
38
+ <Note>&nbsp;(book authors)&nbsp;</Note>
39
+ {:else}
40
+ No authors
41
+ {/if}
42
+ {:else}
43
+ <em>by </em>
44
+ {#each authors as author, index }
45
+ {#if editable }
46
+ <TextEditor
47
+ startText={author}
48
+ label={'Author name editor'}
49
+ placeholder="Author"
50
+ valid={ () => undefined }
51
+ save={ text => /* If text is already empty, remove */ author.length > 0 && text === "" ? remove(index) : edit(index, text) }
52
+ />
53
+ {:else}
54
+ <span><Format node={Parser.parseFormat($edition, author)} /></span>
55
+ {/if}
56
+ {#if index < authors.length - 1},&nbsp{/if}
57
+ {/each}
58
+ {/if}
59
+ {#if editable }
60
+ &nbsp;<button on:click={addAuthor}>+</button>
61
+ {/if}
62
+ </div>
@@ -0,0 +1,20 @@
1
+ import { SvelteComponentTyped } from "svelte";
2
+ declare const __propDef: {
3
+ props: {
4
+ authors: string[];
5
+ inheritedAuthors?: string[] | undefined;
6
+ add: () => Promise<void>;
7
+ edit: (index: number, text: string) => Promise<void> | undefined;
8
+ remove: (index: number) => Promise<void> | undefined;
9
+ };
10
+ events: {
11
+ [evt: string]: CustomEvent<any>;
12
+ };
13
+ slots: {};
14
+ };
15
+ export declare type AuthorsProps = typeof __propDef.props;
16
+ export declare type AuthorsEvents = typeof __propDef.events;
17
+ export declare type AuthorsSlots = typeof __propDef.slots;
18
+ export default class Authors extends SvelteComponentTyped<AuthorsProps, AuthorsEvents, AuthorsSlots> {
19
+ }
20
+ export {};
@@ -0,0 +1,32 @@
1
+ <script>import Instructions from "./Instructions.svelte";
2
+ import { getUniqueReferenceID, mineReference } from "../../util/mineReference";
3
+ import ReferenceNode from "../../models/chapter/ReferenceNode";
4
+ import { getEdition } from "./Contexts";
5
+ let edition = getEdition();
6
+ let text = "";
7
+ function handleBulkAdd() {
8
+ // Split by lines, skipping empty lines.
9
+ const references = text.split(/\n+/).map(line => mineReference(Object.keys($edition.getReferences()), line));
10
+ $edition.addReferences(references)
11
+ .catch(() => {
12
+ alert("Failed to save references.");
13
+ });
14
+ }
15
+ function handleEmptyAdd() {
16
+ $edition.addReferences([new ReferenceNode(getUniqueReferenceID(Object.keys($edition.getReferences())))])
17
+ .catch(() => {
18
+ alert("Failed to save empty reference.");
19
+ });
20
+ }
21
+ </script>
22
+
23
+ <Instructions>
24
+ To cite references in a chapter, add them here.
25
+ You can add one at a time, or try pasting them in bulk, and we'll do our best to pull out the relevant parts, looking for things that look like author lists, years, sources, and URLs.
26
+ Be sure to verify it though &mdash; it's likely to get some things wrong!
27
+ </Instructions>
28
+ <div>
29
+ <textarea rows={5} bind:value={text} style="width: 100%"></textarea>
30
+ <button disabled={text.length === 0} on:click={handleBulkAdd}>Add bulk references</button>
31
+ <button on:click={handleEmptyAdd}>Add empty reference</button>
32
+ </div>
@@ -0,0 +1,14 @@
1
+ import { SvelteComponentTyped } from "svelte";
2
+ declare const __propDef: {
3
+ props: {};
4
+ events: {
5
+ [evt: string]: CustomEvent<any>;
6
+ };
7
+ slots: {};
8
+ };
9
+ export declare type BulkReferenceEditorProps = typeof __propDef.props;
10
+ export declare type BulkReferenceEditorEvents = typeof __propDef.events;
11
+ export declare type BulkReferenceEditorSlots = typeof __propDef.slots;
12
+ export default class BulkReferenceEditor extends SvelteComponentTyped<BulkReferenceEditorProps, BulkReferenceEditorEvents, BulkReferenceEditorSlots> {
13
+ }
14
+ export {};
@@ -0,0 +1,301 @@
1
+ <script>import Parser from "../../models/chapter/Parser";
2
+ import Header from './Header.svelte';
3
+ import Authors from "./Authors.svelte";
4
+ import Outline from './Outline.svelte';
5
+ import Page from './Page.svelte';
6
+ import TextEditor from '../editor/TextEditor.svelte';
7
+ import BookishEditor from '../editor/BookishEditor.svelte';
8
+ import Toggle from '../editor/Toggle.svelte';
9
+ import Instructions from './Instructions.svelte';
10
+ import ChapterBody from '../chapter/ChapterBody.svelte';
11
+ import PossibleReference from "./PossibleReference.svelte";
12
+ import { CHAPTER, getEdition, isEditable } from "./Contexts";
13
+ import { writable } from "svelte/store";
14
+ import { onMount, setContext } from "svelte";
15
+ import { hideOutlineIfObscured, layoutMarginals } from "./margins";
16
+ import scrollToEyeLevel from "../../util/scrollToEyeLevel";
17
+ import { goto } from "$app/navigation";
18
+ import ChapterNode from "../../models/chapter/ChapterNode";
19
+ export let chapter;
20
+ export let print = false;
21
+ let edition = getEdition();
22
+ let editable = isEditable();
23
+ // Keep track of the scroll position to facilitate reading during reloads.
24
+ function rememberPosition() { localStorage.setItem('scrollposition', "" + window.scrollY); }
25
+ // When the window resizes, the responsive layout might cause the marginals to move to the footer.
26
+ // when this happens, we want to immediately remove all of the explicit positioning.
27
+ function handleResize() { layoutMarginals(); }
28
+ // The currently selected marginal; we only do one at a time.
29
+ let marginal = undefined;
30
+ // Keep track of which hash mark is scrolled to
31
+ let highlightedID = undefined;
32
+ // When this component is mounted...
33
+ // 1) Subscribe and unsubscribe to window listeners
34
+ // 2) Do initial layout of marginals
35
+ // 3) Start observing any elements corresponding to the ID in the URL's hash string
36
+ // 4) Clean up our mess after unmounting.
37
+ onMount(() => {
38
+ // On render or when scrolling, see if the URL hash has changed and update state accordingly.
39
+ // We also track whether we've scrolled to it.
40
+ const observeHash = () => {
41
+ // Get the ID without the hash and the corresponding element
42
+ const elementID = window.location.hash.substring(1);
43
+ const element = elementID ? document.getElementById(elementID) : null;
44
+ // If it's not empty, observe it, and remember what we're observing for highlighting
45
+ if (element) {
46
+ highlightedID = elementID;
47
+ // Start watching this a few seconds after we see it, giving the for in-page scrolling.
48
+ setTimeout(() => observer.observe(element), 2500);
49
+ }
50
+ };
51
+ // Do things to do when scrolling
52
+ const handleScroll = () => {
53
+ // See if the outline is obscured by an image
54
+ hideOutlineIfObscured();
55
+ // See if there are any new hashes to observe. This is because
56
+ // we're using react-router-hash-link, which doesn't trigger hashchange events for some reason.
57
+ observeHash();
58
+ };
59
+ // Lay things out when the window or scroll changes.
60
+ window.addEventListener('scroll', handleScroll);
61
+ window.addEventListener('resize', handleResize);
62
+ // Remember the scroll position before a refresh.
63
+ // We have to do all of these because browser support varies.
64
+ window.addEventListener("beforeunload", rememberPosition);
65
+ window.addEventListener("visibilitychange", rememberPosition);
66
+ window.addEventListener("pagehide", rememberPosition);
67
+ // Start listening for hash changes, since we want to remove them upon scrolling away from them.
68
+ window.addEventListener("pushstate", observeHash);
69
+ window.addEventListener("popstate", observeHash);
70
+ window.addEventListener("hashchange", observeHash);
71
+ // Make an intersection observer to monitor the location of elements selected by the URL hash ID.
72
+ const observer = new IntersectionObserver((entries => {
73
+ // Go through all of the monitored elements
74
+ entries.forEach(entry => {
75
+ // If the observed element is out of view and in the hash, remove the hash
76
+ if (entry.intersectionRatio === 0 && entry.target.id === window.location.hash.substring(1)) {
77
+ history.pushState("", document.title, window.location.pathname + window.location.search);
78
+ observer.unobserve(entry.target);
79
+ highlightedID = undefined;
80
+ }
81
+ });
82
+ }));
83
+ // Do an initial check the hash to see if there's an ID to scroll to
84
+ observeHash();
85
+ // Position the marginals, since there's new content.
86
+ layoutMarginals();
87
+ // Periodically save the chapter's edits.
88
+ const chapterSaverID = setInterval(() => {
89
+ $currentChapter.saveEdits();
90
+ }, 500);
91
+ // On cleanup, unsubscribe from everything above.
92
+ return () => {
93
+ window.removeEventListener('scroll', handleScroll);
94
+ window.removeEventListener('resize', handleResize);
95
+ // Stop listening to page visibility changes.
96
+ window.removeEventListener("beforeunload", rememberPosition);
97
+ window.removeEventListener("visibilitychange", rememberPosition);
98
+ window.removeEventListener("pagehide", rememberPosition);
99
+ // Delete the remembered position so that the next page scrolls to top.
100
+ localStorage.removeItem("scrollposition");
101
+ // Stop listening for hash changes
102
+ window.removeEventListener("pushstate", observeHash);
103
+ window.removeEventListener("popstate", observeHash);
104
+ window.removeEventListener("hashchange", observeHash);
105
+ // Stop observing everything on unmount
106
+ observer.disconnect();
107
+ // Stop saving.
108
+ clearInterval(chapterSaverID);
109
+ };
110
+ });
111
+ // Position the marginals on mount.
112
+ onMount(() => layoutMarginals());
113
+ // Keep track of the current chapter in a store to manage listeners on the chapter.
114
+ let currentChapter = writable(chapter);
115
+ let chapterChanged = () => currentChapter.set(chapter);
116
+ $: {
117
+ // Listen to the new edition
118
+ $currentChapter.removeListener(chapterChanged);
119
+ // Update the current edition.
120
+ currentChapter.set(chapter);
121
+ // Listen to changes on the book and chapter.
122
+ $currentChapter.addListener(chapterChanged);
123
+ }
124
+ // This gets called after the page is done loading. There are various things we scroll to.
125
+ function scrollToLastLocation() {
126
+ // In case loading changed marginal positions
127
+ layoutMarginals();
128
+ // If there's a word we're trying to highlight in the URL path, scroll to the corresponding match.
129
+ if (location.search) {
130
+ const highlights = document.getElementsByClassName("bookish-text bookish-content-highlight");
131
+ const num = getHighlightedNumber();
132
+ if (num && highlights.length > 0 && num < highlights.length && num >= 0) {
133
+ scrollToEyeLevel(highlights[num]);
134
+ }
135
+ }
136
+ // Otherwise, if there's an ID in the URL, jump to it.
137
+ else if (highlightedID) {
138
+ const el = document.getElementById(highlightedID);
139
+ // If we found the element, remove the hash any time after a few seconds. See handleScroll for the removal logic.
140
+ if (el) {
141
+ scrollToEyeLevel(el);
142
+ }
143
+ }
144
+ else {
145
+ // If we got to this page through a refresh, scroll to
146
+ const entries = performance.getEntriesByType("navigation");
147
+ const position = localStorage.getItem('scrollposition');
148
+ if (position !== null && entries.length > 0 && entries[entries.length - 1].type === "reload") {
149
+ // Scroll to the previous position, if there was one, so that refresh preserves position.
150
+ window.scrollTo(0, parseInt(position));
151
+ }
152
+ // Otherwise, just scroll to the top.
153
+ else {
154
+ window.scrollTo(0, 0);
155
+ }
156
+ }
157
+ }
158
+ function getHighlightedWord() { return location.search.split("&")[0]?.split("=")[1] ?? undefined; }
159
+ function getHighlightedNumber() {
160
+ const number = location.search.split("&")[1]?.split("=")[1];
161
+ return number === undefined ? undefined : parseInt(number);
162
+ }
163
+ // Prepare to render the chapter by getting some data from the chapter and book.
164
+ $: chapterID = $currentChapter.getChapterID();
165
+ $: chapterNumber = $edition.getChapterNumber(chapterID);
166
+ $: chapterSection = $edition.getChapterSection(chapterID);
167
+ $: chapterAST = $currentChapter.getAST();
168
+ $: citations = chapterAST ? chapterAST.getCitations() : undefined;
169
+ let chapterStore = writable();
170
+ setContext(CHAPTER, chapterStore);
171
+ $: chapterStore.set({
172
+ chapter: chapter,
173
+ highlightedWord: getHighlightedWord(),
174
+ highlightedID: highlightedID,
175
+ marginalID: marginal,
176
+ setMarginal: (id) => marginal = id,
177
+ layoutMarginals: layoutMarginals
178
+ });
179
+ </script>
180
+
181
+ <Page afterLoaded={scrollToLastLocation} title={`${$edition.getTitle()} - ${chapter.getTitle()}`}>
182
+ <div class="bookish-chapter">
183
+ <Header
184
+ header={chapter.getTitle()}
185
+ label="Chapter title"
186
+ tags={$edition.getTags()}
187
+ save={ text => chapter.setTitle(text) }
188
+ getImage={() => chapter.getImage()}
189
+ setImage={embed => chapter.setImage(embed)}
190
+ print={print}
191
+ >
192
+ <!-- Collapse the outline if a marginal is selected. -->
193
+ <Outline
194
+ slot="outline"
195
+ collapse={marginal !== undefined}
196
+ previous={$edition.getPreviousChapterID(chapterID)}
197
+ next={$edition.getNextChapterID(chapterID)}
198
+ listener={ expanded => {
199
+ // If the outline is being expanded, hide the marginal, otherwise leave it alone.
200
+ if(expanded)
201
+ marginal = undefined;
202
+
203
+ // Check if we need to hide the outline after positioning.
204
+ hideOutlineIfObscured();
205
+ }}
206
+ />
207
+ <!-- Add an editable chapter ID if in editor mode -->
208
+ <svelte:fragment slot="before">
209
+ {#if editable }
210
+ <span class="bookish-muted">
211
+ <TextEditor
212
+ startText={chapter.getChapterID()}
213
+ label="Chapter URL ID editor"
214
+ save={
215
+ // After the ID is edited, reload the page with the new URL.
216
+ id => chapter.setChapterID(id)?.then(() => {
217
+ const ref = $edition.getRef();
218
+ if(ref?.id)
219
+ goto(`/write/${ref?.id}/chapter/${id}`)
220
+ })
221
+ }
222
+ placeholder="chapter ID"
223
+ valid={(newChapterID) =>
224
+ !/^[a-zA-Z0-9]+$/.test(newChapterID) ? "Chapter IDs must be one or more letters or numbers" :
225
+ chapter.getChapterID() !== newChapterID && $edition.hasChapter(newChapterID) ? "There's already a chapter that has this ID." :
226
+ undefined
227
+ }
228
+ saveOnExit={true}
229
+ />
230
+ <br/>
231
+ </span>
232
+ {/if}
233
+ {#if editable }
234
+ <Toggle on={chapter.isNumbered()} save={ on => chapter.setNumbered(on) }>
235
+ {#if chapterNumber !== undefined }
236
+ <span class="bookish-chapter-number">Chapter {chapterNumber}</span>
237
+ {:else}
238
+ <span class="bookish-muted">Unnumbered</span>
239
+ {/if}
240
+ </Toggle>
241
+ {:else if chapterNumber !== undefined }
242
+ <span class="bookish-chapter-number">Chapter {chapterNumber}</span>
243
+ {/if}
244
+ {#if chapterSection !== undefined }
245
+ <span class="bookish-section-name">&nbsp;&nbsp;{chapterSection}</span>
246
+ {/if}
247
+ </svelte:fragment>
248
+ <!-- If there are chapter authors, render those, otherwise use the book authors -->
249
+ <Authors
250
+ slot="after"
251
+ authors={ chapter.getAuthors() }
252
+ inheritedAuthors={ $edition.getAuthors() }
253
+ add={ () => chapter.addAuthor("") }
254
+ edit={(index, text) => chapter.setAuthor(index, text) }
255
+ remove={index => chapter.removeAuthor(index)}
256
+ />
257
+ </Header>
258
+ <!-- We load this on the page but hide it; it's used as a filter for highlighing in CSS -->
259
+ <img src={"/svg/marker.svg"} alt="highlight mark" style="display: none"/>
260
+ <Instructions>
261
+ Edit your chapter's title, authors, and cover image above.
262
+ You can also change the ID of the chapter, which appears in it's URL.
263
+ Write your chapter text below, using the many formatting options in the toolbar above to format text, add headers, lists, tables, comments, citations, footnotes, and more.
264
+ It's okay to try things, you can always undo!
265
+ Saves are automatic, each time you stop typing.
266
+ </Instructions>
267
+
268
+ <!-- Render the chapter body, passing some context -->
269
+ {#if chapterAST }
270
+ {#if editable }
271
+ <BookishEditor
272
+ ast={chapterAST}
273
+ save={ node => node instanceof ChapterNode ? chapter.setAST(node) : undefined }
274
+ chapter={true}
275
+ autofocus
276
+ component={ChapterBody}
277
+ placeholder="Type here"
278
+ />
279
+ {:else}
280
+ <ChapterBody node={chapterAST} />
281
+ {/if}
282
+ {:else}
283
+ <span>Loading...</span>
284
+ {/if}
285
+ {#if citations && citations.size > 0 }
286
+ {@const refs = $edition.getReferences() }
287
+ <h1 id="references" class="bookish-header">References</h1>
288
+ <ol>
289
+ {#each [...citations].sort() as citationID }
290
+ {#if citationID in refs }
291
+ <li class={"bookish-reference"} id={"ref-" + citationID}>
292
+ <PossibleReference node={Parser.parseReference(citationID, refs[citationID], $edition)}/>
293
+ </li>
294
+ {:else}
295
+ <li class="bookish-error">Unknown reference: <code>{citationID}</code></li>
296
+ {/if}
297
+ {/each}
298
+ </ol>
299
+ {/if}
300
+ </div>
301
+ </Page>
@@ -0,0 +1,18 @@
1
+ import { SvelteComponentTyped } from "svelte";
2
+ import type ChapterModel from '../../models/book/Chapter';
3
+ declare const __propDef: {
4
+ props: {
5
+ chapter: ChapterModel;
6
+ print?: boolean | undefined;
7
+ };
8
+ events: {
9
+ [evt: string]: CustomEvent<any>;
10
+ };
11
+ slots: {};
12
+ };
13
+ export declare type ChapterProps = typeof __propDef.props;
14
+ export declare type ChapterEvents = typeof __propDef.events;
15
+ export declare type ChapterSlots = typeof __propDef.slots;
16
+ export default class Chapter extends SvelteComponentTyped<ChapterProps, ChapterEvents, ChapterSlots> {
17
+ }
18
+ export {};
@@ -0,0 +1,10 @@
1
+ import type Chapter from "../../models/book/Chapter";
2
+ declare type ChapterContext = {
3
+ chapter: Chapter;
4
+ highlightedWord?: string;
5
+ highlightedID?: string;
6
+ marginalID?: string;
7
+ setMarginal: (id: string | undefined) => void;
8
+ layoutMarginals: () => void;
9
+ } | undefined;
10
+ export default ChapterContext;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,27 @@
1
+ import type { Writable } from "svelte/store";
2
+ import type Book from "../../models/book/Book";
3
+ import type Edition from "../../models/book/Edition";
4
+ import type Authentication from "../Authentication";
5
+ import type CaretContext from "../editor/CaretContext";
6
+ import type ChapterContext from "./ChapterContext";
7
+ export declare type AuthContext = Writable<Authentication>;
8
+ export declare const AUTH: unique symbol;
9
+ export declare function getAuth(): AuthContext;
10
+ export declare type EditionStore = Writable<Edition>;
11
+ export declare const EDITION: unique symbol;
12
+ export declare function getEdition(): EditionStore;
13
+ export declare type CaretStore = Writable<CaretContext>;
14
+ export declare const CARET: unique symbol;
15
+ export declare function getCaret(): CaretStore;
16
+ export declare type DarkModeStore = Writable<boolean>;
17
+ export declare const DARK_MODE: unique symbol;
18
+ export declare function getDarkMode(): DarkModeStore;
19
+ export declare type ChapterStore = Writable<ChapterContext>;
20
+ export declare const CHAPTER: unique symbol;
21
+ export declare function getChapter(): ChapterStore;
22
+ export declare const EDITABLE: unique symbol;
23
+ export declare function isEditable(): unknown;
24
+ export declare const BASE: unique symbol;
25
+ export declare function getBase(): string;
26
+ export declare const BOOK: unique symbol;
27
+ export declare function getBook(): Book;
@@ -0,0 +1,21 @@
1
+ // We use these unique objects as keys in Svelte context in order
2
+ // to avoid key collisions and prevent typos. This is partly
3
+ // future-proofing, but also because getContext<Type>() isn't type safe,
4
+ // as the resulting value is coerced to Type even if it's not that value.
5
+ import { getContext } from "svelte";
6
+ export const AUTH = Symbol("auth");
7
+ export function getAuth() { return getContext(AUTH); }
8
+ export const EDITION = Symbol("edition");
9
+ export function getEdition() { return getContext(EDITION); }
10
+ export const CARET = Symbol("caret");
11
+ export function getCaret() { return getContext(CARET); }
12
+ export const DARK_MODE = Symbol("dark");
13
+ export function getDarkMode() { return getContext(DARK_MODE); }
14
+ export const CHAPTER = Symbol("chapter");
15
+ export function getChapter() { return getContext(CHAPTER); }
16
+ export const EDITABLE = Symbol("editable");
17
+ export function isEditable() { return getContext(EDITABLE); }
18
+ export const BASE = Symbol("base");
19
+ export function getBase() { return getContext(BASE); }
20
+ export const BOOK = Symbol("book");
21
+ export function getBook() { return getContext(BOOK); }