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.
- package/LICENSE +21 -0
- package/README.md +5 -0
- package/components/Auth.svelte +52 -0
- package/components/Auth.svelte.d.ts +16 -0
- package/components/Authentication.d.ts +8 -0
- package/components/Authentication.js +1 -0
- package/components/BookPreview.svelte +87 -0
- package/components/BookPreview.svelte.d.ts +18 -0
- package/components/External.svelte +4 -0
- package/components/External.svelte.d.ts +18 -0
- package/components/Link.svelte +5 -0
- package/components/Link.svelte.d.ts +19 -0
- package/components/chapter/Atom.svelte +36 -0
- package/components/chapter/Atom.svelte.d.ts +19 -0
- package/components/chapter/Block.svelte +32 -0
- package/components/chapter/Block.svelte.d.ts +17 -0
- package/components/chapter/Callout.svelte +10 -0
- package/components/chapter/Callout.svelte.d.ts +17 -0
- package/components/chapter/CaptionedCode.svelte +34 -0
- package/components/chapter/CaptionedCode.svelte.d.ts +17 -0
- package/components/chapter/ChapterBody.svelte +23 -0
- package/components/chapter/ChapterBody.svelte.d.ts +18 -0
- package/components/chapter/Citations.svelte +66 -0
- package/components/chapter/Citations.svelte.d.ts +17 -0
- package/components/chapter/Code.svelte +35 -0
- package/components/chapter/Code.svelte.d.ts +22 -0
- package/components/chapter/Comment.svelte +46 -0
- package/components/chapter/Comment.svelte.d.ts +17 -0
- package/components/chapter/Definition.svelte +38 -0
- package/components/chapter/Definition.svelte.d.ts +20 -0
- package/components/chapter/Embed.svelte +122 -0
- package/components/chapter/Embed.svelte.d.ts +18 -0
- package/components/chapter/ErrorMessage.svelte +4 -0
- package/components/chapter/ErrorMessage.svelte.d.ts +17 -0
- package/components/chapter/Footnote.svelte +37 -0
- package/components/chapter/Footnote.svelte.d.ts +19 -0
- package/components/chapter/Format.svelte +57 -0
- package/components/chapter/Format.svelte.d.ts +18 -0
- package/components/chapter/InlineCode.svelte +12 -0
- package/components/chapter/InlineCode.svelte.d.ts +17 -0
- package/components/chapter/Label.svelte +20 -0
- package/components/chapter/Label.svelte.d.ts +17 -0
- package/components/chapter/Link.svelte +51 -0
- package/components/chapter/Link.svelte.d.ts +17 -0
- package/components/chapter/List.svelte +14 -0
- package/components/chapter/List.svelte.d.ts +17 -0
- package/components/chapter/Marginal.svelte +48 -0
- package/components/chapter/Marginal.svelte.d.ts +19 -0
- package/components/chapter/Paragraph.svelte +15 -0
- package/components/chapter/Paragraph.svelte.d.ts +18 -0
- package/components/chapter/Python.svelte +81 -0
- package/components/chapter/Python.svelte.d.ts +18 -0
- package/components/chapter/Quote.svelte +16 -0
- package/components/chapter/Quote.svelte.d.ts +17 -0
- package/components/chapter/Rule.svelte +4 -0
- package/components/chapter/Rule.svelte.d.ts +17 -0
- package/components/chapter/Table.svelte +29 -0
- package/components/chapter/Table.svelte.d.ts +17 -0
- package/components/chapter/Text.svelte +62 -0
- package/components/chapter/Text.svelte.d.ts +17 -0
- package/components/chapter/renderPosition.d.ts +3 -0
- package/components/chapter/renderPosition.js +4 -0
- package/components/editor/BookishEditor.svelte +755 -0
- package/components/editor/BookishEditor.svelte.d.ts +22 -0
- package/components/editor/CalloutEditor.svelte +10 -0
- package/components/editor/CalloutEditor.svelte.d.ts +17 -0
- package/components/editor/CaptionedCodeEditor.svelte +22 -0
- package/components/editor/CaptionedCodeEditor.svelte.d.ts +17 -0
- package/components/editor/CaretContext.d.ts +18 -0
- package/components/editor/CaretContext.js +1 -0
- package/components/editor/CaretState.d.ts +47 -0
- package/components/editor/CaretState.js +1 -0
- package/components/editor/CaretUtilities.d.ts +5 -0
- package/components/editor/CaretUtilities.js +1 -0
- package/components/editor/CitationsEditor.svelte +42 -0
- package/components/editor/CitationsEditor.svelte.d.ts +17 -0
- package/components/editor/Clipboard.d.ts +3 -0
- package/components/editor/Clipboard.js +1 -0
- package/components/editor/Command.d.ts +18 -0
- package/components/editor/Command.js +1 -0
- package/components/editor/Commands.d.ts +3 -0
- package/components/editor/Commands.js +951 -0
- package/components/editor/ConfirmButton.svelte +43 -0
- package/components/editor/ConfirmButton.svelte.d.ts +18 -0
- package/components/editor/DefinitionEditor.svelte +28 -0
- package/components/editor/DefinitionEditor.svelte.d.ts +17 -0
- package/components/editor/EmbedEditor.svelte +87 -0
- package/components/editor/EmbedEditor.svelte.d.ts +17 -0
- package/components/editor/ImageChooser.svelte +70 -0
- package/components/editor/ImageChooser.svelte.d.ts +18 -0
- package/components/editor/InlineCodeEditor.svelte +9 -0
- package/components/editor/InlineCodeEditor.svelte.d.ts +17 -0
- package/components/editor/LabelEditor.svelte +23 -0
- package/components/editor/LabelEditor.svelte.d.ts +17 -0
- package/components/editor/LanguageEditor.svelte +11 -0
- package/components/editor/LanguageEditor.svelte.d.ts +17 -0
- package/components/editor/LinkEditor.svelte +75 -0
- package/components/editor/LinkEditor.svelte.d.ts +17 -0
- package/components/editor/Note.svelte +9 -0
- package/components/editor/Note.svelte.d.ts +23 -0
- package/components/editor/PositionEditor.svelte +14 -0
- package/components/editor/PositionEditor.svelte.d.ts +18 -0
- package/components/editor/QuoteEditor.svelte +5 -0
- package/components/editor/QuoteEditor.svelte.d.ts +17 -0
- package/components/editor/Switch.svelte +56 -0
- package/components/editor/Switch.svelte.d.ts +20 -0
- package/components/editor/TextEditor.svelte +193 -0
- package/components/editor/TextEditor.svelte.d.ts +23 -0
- package/components/editor/Toggle.svelte +38 -0
- package/components/editor/Toggle.svelte.d.ts +19 -0
- package/components/editor/Toolbar.svelte +202 -0
- package/components/editor/Toolbar.svelte.d.ts +20 -0
- package/components/editor/ToolbarGroup.svelte +41 -0
- package/components/editor/ToolbarGroup.svelte.d.ts +19 -0
- package/components/editor/ToolbarIcon.svelte +22 -0
- package/components/editor/ToolbarIcon.svelte.d.ts +16 -0
- package/components/editor/ToolbarSpacer.svelte +1 -0
- package/components/editor/ToolbarSpacer.svelte.d.ts +19 -0
- package/components/editor/URLEditor.svelte +15 -0
- package/components/editor/URLEditor.svelte.d.ts +18 -0
- package/components/editor/UndoState.d.ts +8 -0
- package/components/editor/UndoState.js +1 -0
- package/components/page/Acknowledgements.svelte +29 -0
- package/components/page/Acknowledgements.svelte.d.ts +14 -0
- package/components/page/Alert.svelte +11 -0
- package/components/page/Alert.svelte.d.ts +23 -0
- package/components/page/Authors.svelte +62 -0
- package/components/page/Authors.svelte.d.ts +20 -0
- package/components/page/BulkReferenceEditor.svelte +32 -0
- package/components/page/BulkReferenceEditor.svelte.d.ts +14 -0
- package/components/page/Chapter.svelte +301 -0
- package/components/page/Chapter.svelte.d.ts +18 -0
- package/components/page/ChapterContext.d.ts +10 -0
- package/components/page/ChapterContext.js +1 -0
- package/components/page/Contexts.d.ts +27 -0
- package/components/page/Contexts.js +21 -0
- package/components/page/DefinitionView.svelte +129 -0
- package/components/page/DefinitionView.svelte.d.ts +18 -0
- package/components/page/Description.svelte +22 -0
- package/components/page/Description.svelte.d.ts +14 -0
- package/components/page/Edition.svelte +106 -0
- package/components/page/Edition.svelte.d.ts +21 -0
- package/components/page/Glossary.svelte +61 -0
- package/components/page/Glossary.svelte.d.ts +14 -0
- package/components/page/Header.svelte +105 -0
- package/components/page/Header.svelte.d.ts +27 -0
- package/components/page/Index.svelte +117 -0
- package/components/page/Index.svelte.d.ts +14 -0
- package/components/page/Instructions.svelte +30 -0
- package/components/page/Instructions.svelte.d.ts +16 -0
- package/components/page/License.svelte +29 -0
- package/components/page/License.svelte.d.ts +14 -0
- package/components/page/Loading.svelte +13 -0
- package/components/page/Loading.svelte.d.ts +19 -0
- package/components/page/Media.svelte +76 -0
- package/components/page/Media.svelte.d.ts +14 -0
- package/components/page/MediaPreview.svelte +11 -0
- package/components/page/MediaPreview.svelte.d.ts +19 -0
- package/components/page/Outline.svelte +173 -0
- package/components/page/Outline.svelte.d.ts +19 -0
- package/components/page/Page.svelte +53 -0
- package/components/page/Page.svelte.d.ts +19 -0
- package/components/page/PossibleChapter.svelte +14 -0
- package/components/page/PossibleChapter.svelte.d.ts +14 -0
- package/components/page/PossibleReference.svelte +16 -0
- package/components/page/PossibleReference.svelte.d.ts +19 -0
- package/components/page/Print.svelte +8 -0
- package/components/page/Print.svelte.d.ts +14 -0
- package/components/page/Reference.svelte +145 -0
- package/components/page/Reference.svelte.d.ts +17 -0
- package/components/page/References.svelte +58 -0
- package/components/page/References.svelte.d.ts +14 -0
- package/components/page/Revisions.svelte +124 -0
- package/components/page/Revisions.svelte.d.ts +14 -0
- package/components/page/Search.svelte +108 -0
- package/components/page/Search.svelte.d.ts +14 -0
- package/components/page/Status.svelte +49 -0
- package/components/page/Status.svelte.d.ts +19 -0
- package/components/page/SubdomainEditor.svelte +30 -0
- package/components/page/SubdomainEditor.svelte.d.ts +14 -0
- package/components/page/TableOfContents.svelte +234 -0
- package/components/page/TableOfContents.svelte.d.ts +14 -0
- package/components/page/TableOfContentsImage.svelte +15 -0
- package/components/page/TableOfContentsImage.svelte.d.ts +16 -0
- package/components/page/TableOfContentsRow.svelte +57 -0
- package/components/page/TableOfContentsRow.svelte.d.ts +24 -0
- package/components/page/ThemeEditor.svelte +52 -0
- package/components/page/ThemeEditor.svelte.d.ts +14 -0
- package/components/page/ThemeEditorPreview.svelte +37 -0
- package/components/page/ThemeEditorPreview.svelte.d.ts +17 -0
- package/components/page/ThemeSetEditor.svelte +17 -0
- package/components/page/ThemeSetEditor.svelte.d.ts +18 -0
- package/components/page/ThemeVariableEditor.svelte +28 -0
- package/components/page/ThemeVariableEditor.svelte.d.ts +18 -0
- package/components/page/Unknown.svelte +29 -0
- package/components/page/Unknown.svelte.d.ts +16 -0
- package/components/page/margins.d.ts +2 -0
- package/components/page/margins.js +132 -0
- package/models/BookLoader.d.ts +2 -0
- package/models/BookLoader.js +67 -0
- package/models/Firebase.d.ts +4 -0
- package/models/Firebase.js +26 -0
- package/models/Firestore.d.ts +22 -0
- package/models/Firestore.js +194 -0
- package/models/book/Book.d.ts +60 -0
- package/models/book/Book.js +135 -0
- package/models/book/BookMedia.d.ts +23 -0
- package/models/book/BookMedia.js +102 -0
- package/models/book/Chapter.d.ts +70 -0
- package/models/book/Chapter.js +221 -0
- package/models/book/ChapterID.d.ts +10 -0
- package/models/book/ChapterID.js +10 -0
- package/models/book/Definition.d.ts +6 -0
- package/models/book/Definition.js +1 -0
- package/models/book/Edition.d.ts +111 -0
- package/models/book/Edition.js +466 -0
- package/models/book/Theme.d.ts +106 -0
- package/models/book/Theme.js +76 -0
- package/models/book/ThemeColors.d.ts +15 -0
- package/models/book/ThemeColors.js +1 -0
- package/models/chapter/AtomNode.d.ts +18 -0
- package/models/chapter/AtomNode.js +31 -0
- package/models/chapter/BlockNode.d.ts +21 -0
- package/models/chapter/BlockNode.js +117 -0
- package/models/chapter/BlocksNode.d.ts +50 -0
- package/models/chapter/BlocksNode.js +709 -0
- package/models/chapter/BlocksNode.test.d.ts +1 -0
- package/models/chapter/BlocksNode.test.js +302 -0
- package/models/chapter/Bookkeeping.d.ts +4 -0
- package/models/chapter/Bookkeeping.js +1 -0
- package/models/chapter/CalloutNode.d.ts +17 -0
- package/models/chapter/CalloutNode.js +36 -0
- package/models/chapter/Caret.d.ts +21 -0
- package/models/chapter/Caret.js +69 -0
- package/models/chapter/ChapterNode.d.ts +34 -0
- package/models/chapter/ChapterNode.js +80 -0
- package/models/chapter/CitationsNode.d.ts +16 -0
- package/models/chapter/CitationsNode.js +17 -0
- package/models/chapter/CodeNode.d.ts +30 -0
- package/models/chapter/CodeNode.js +64 -0
- package/models/chapter/CommentNode.d.ts +18 -0
- package/models/chapter/CommentNode.js +32 -0
- package/models/chapter/DefinitionNode.d.ts +12 -0
- package/models/chapter/DefinitionNode.js +20 -0
- package/models/chapter/Edit.d.ts +7 -0
- package/models/chapter/Edit.js +1 -0
- package/models/chapter/EmbedNode.d.ts +40 -0
- package/models/chapter/EmbedNode.js +89 -0
- package/models/chapter/ErrorNode.d.ts +17 -0
- package/models/chapter/ErrorNode.js +21 -0
- package/models/chapter/FootnoteNode.d.ts +18 -0
- package/models/chapter/FootnoteNode.js +29 -0
- package/models/chapter/FormatNode.d.ts +60 -0
- package/models/chapter/FormatNode.js +614 -0
- package/models/chapter/FormatNode.test.d.ts +1 -0
- package/models/chapter/FormatNode.test.js +54 -0
- package/models/chapter/InlineCodeNode.d.ts +12 -0
- package/models/chapter/InlineCodeNode.js +18 -0
- package/models/chapter/LabelNode.d.ts +17 -0
- package/models/chapter/LabelNode.js +22 -0
- package/models/chapter/LinkNode.d.ts +12 -0
- package/models/chapter/LinkNode.js +16 -0
- package/models/chapter/ListNode.d.ts +51 -0
- package/models/chapter/ListNode.js +370 -0
- package/models/chapter/ListNode.test.d.ts +1 -0
- package/models/chapter/ListNode.test.js +49 -0
- package/models/chapter/MetadataNode.d.ts +17 -0
- package/models/chapter/MetadataNode.js +24 -0
- package/models/chapter/Node.d.ts +36 -0
- package/models/chapter/Node.js +173 -0
- package/models/chapter/Node.test.d.ts +1 -0
- package/models/chapter/Node.test.js +27 -0
- package/models/chapter/ParagraphNode.d.ts +33 -0
- package/models/chapter/ParagraphNode.js +93 -0
- package/models/chapter/ParagraphNode.test.d.ts +1 -0
- package/models/chapter/ParagraphNode.test.js +21 -0
- package/models/chapter/Parser.d.ts +75 -0
- package/models/chapter/Parser.js +824 -0
- package/models/chapter/Parser.test.d.ts +1 -0
- package/models/chapter/Parser.test.js +25 -0
- package/models/chapter/Position.d.ts +2 -0
- package/models/chapter/Position.js +1 -0
- package/models/chapter/QuoteNode.d.ts +25 -0
- package/models/chapter/QuoteNode.js +61 -0
- package/models/chapter/ReferenceNode.d.ts +29 -0
- package/models/chapter/ReferenceNode.js +48 -0
- package/models/chapter/RootNode.d.ts +5 -0
- package/models/chapter/RootNode.js +1 -0
- package/models/chapter/RuleNode.d.ts +15 -0
- package/models/chapter/RuleNode.js +16 -0
- package/models/chapter/TableNode.d.ts +35 -0
- package/models/chapter/TableNode.js +176 -0
- package/models/chapter/TableNode.test.d.ts +1 -0
- package/models/chapter/TableNode.test.js +31 -0
- package/models/chapter/TextNode.d.ts +36 -0
- package/models/chapter/TextNode.js +136 -0
- package/models/chapter/TextNode.test.d.ts +1 -0
- package/models/chapter/TextNode.test.js +6 -0
- package/models/loadEdition.d.ts +5 -0
- package/models/loadEdition.js +16 -0
- package/package.json +189 -0
- package/util/getSubdomain.d.ts +3 -0
- package/util/getSubdomain.js +22 -0
- package/util/isMobile.d.ts +2 -0
- package/util/isMobile.js +6 -0
- package/util/mineReference.d.ts +3 -0
- package/util/mineReference.js +62 -0
- package/util/scrollToEyeLevel.d.ts +2 -0
- package/util/scrollToEyeLevel.js +5 -0
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
import Chapter from './Chapter';
|
|
2
|
+
import Parser from "../chapter/Parser";
|
|
3
|
+
import EmbedNode from "../chapter/EmbedNode";
|
|
4
|
+
import { addChapterInFirestore, removeChapterFromEditionInFirestore, updateEditionInFirestore } from "../Firestore";
|
|
5
|
+
import ChapterIDs from './ChapterID.js';
|
|
6
|
+
export var BookSaveStatus;
|
|
7
|
+
(function (BookSaveStatus) {
|
|
8
|
+
BookSaveStatus[BookSaveStatus["Changed"] = 0] = "Changed";
|
|
9
|
+
BookSaveStatus[BookSaveStatus["Saving"] = 1] = "Saving";
|
|
10
|
+
BookSaveStatus[BookSaveStatus["Saved"] = 2] = "Saved";
|
|
11
|
+
BookSaveStatus[BookSaveStatus["Error"] = 3] = "Error";
|
|
12
|
+
})(BookSaveStatus || (BookSaveStatus = {}));
|
|
13
|
+
export default class Edition {
|
|
14
|
+
specification;
|
|
15
|
+
book;
|
|
16
|
+
editionRef;
|
|
17
|
+
chapters;
|
|
18
|
+
chaptersByID;
|
|
19
|
+
listeners;
|
|
20
|
+
// A list of requested edits, stored as promises, resolved
|
|
21
|
+
// when the book is ready to save.
|
|
22
|
+
edits = [];
|
|
23
|
+
lastEdit = 0;
|
|
24
|
+
// Given an object with a valid specification and an object mapping chapter IDs to chapter text,
|
|
25
|
+
// construct an object representing a book.
|
|
26
|
+
constructor(book, editionRef, specification) {
|
|
27
|
+
if (typeof specification !== "object" && specification !== undefined)
|
|
28
|
+
throw Error("Expected a book specification object, but received " + specification);
|
|
29
|
+
this.book = book;
|
|
30
|
+
this.editionRef = editionRef;
|
|
31
|
+
// Copy all of the specification metadata to fields.
|
|
32
|
+
// Choose suitable defaults if the spec is lacking a field.
|
|
33
|
+
this.specification = {
|
|
34
|
+
title: specification ? specification.title : "Untitled",
|
|
35
|
+
symbols: specification && specification.symbols ? specification.symbols : {},
|
|
36
|
+
tags: specification && specification.tags ? specification.tags : [],
|
|
37
|
+
license: specification ? specification.license : "All rights reserved.",
|
|
38
|
+
references: specification && specification.references ? specification.references : {},
|
|
39
|
+
glossary: specification && specification.glossary ? specification.glossary : {},
|
|
40
|
+
authors: specification && specification.authors ? specification.authors : [],
|
|
41
|
+
description: specification ? specification.description : "",
|
|
42
|
+
acknowledgements: specification && specification.acknowledgements ? specification.acknowledgements : "",
|
|
43
|
+
revisions: specification && specification.revisions ? specification.revisions : [],
|
|
44
|
+
images: specification && specification.revisions ? specification.images : {},
|
|
45
|
+
sources: specification && specification.revisions ? specification.sources : {},
|
|
46
|
+
theme: specification && specification.theme ? specification.theme : null,
|
|
47
|
+
uids: specification && specification.uids ? specification.uids : [],
|
|
48
|
+
chapters: specification && specification.chapters ? specification.chapters : []
|
|
49
|
+
};
|
|
50
|
+
// No listeners yet
|
|
51
|
+
this.listeners = new Set();
|
|
52
|
+
// Create a list and dictionary of Chapter objects.
|
|
53
|
+
this.chapters = [];
|
|
54
|
+
this.chaptersByID = {};
|
|
55
|
+
// If there's a spec and it has chapters, process them.
|
|
56
|
+
if (this.specification.chapters.length > 0) {
|
|
57
|
+
// Initialize the chapters dictionary since parsing depends this index to detect whether a chapter exists.
|
|
58
|
+
this.specification.chapters.forEach(chapterSpec => this.chaptersByID[chapterSpec.id] = undefined);
|
|
59
|
+
this.specification.chapters.forEach(chapterSpec => {
|
|
60
|
+
const chap = new Chapter(this, chapterSpec);
|
|
61
|
+
this.chaptersByID[chapterSpec.id] = chap;
|
|
62
|
+
this.chapters.push(chap);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
setRef(ref) {
|
|
67
|
+
if (this.editionRef)
|
|
68
|
+
throw Error("Can only set a ref of an edition when not yet set.");
|
|
69
|
+
this.editionRef = ref;
|
|
70
|
+
}
|
|
71
|
+
async saveEdits() {
|
|
72
|
+
// If it's been more than a second since our last edit and there
|
|
73
|
+
// are edits that haven't been saved, try updating the book,
|
|
74
|
+
// and if we succeed, resolve all of the edits, and if we fail,
|
|
75
|
+
// then reject them.
|
|
76
|
+
if (Date.now() - this.lastEdit > 1000 && this.edits.length > 0) {
|
|
77
|
+
// Tell listeners that this book model changed.
|
|
78
|
+
this.notifyListeners(BookSaveStatus.Saving);
|
|
79
|
+
return updateEditionInFirestore(this)
|
|
80
|
+
.then(() => {
|
|
81
|
+
// Approve the edits.
|
|
82
|
+
this.edits.forEach(edit => edit.resolve());
|
|
83
|
+
this.notifyListeners(BookSaveStatus.Saved);
|
|
84
|
+
})
|
|
85
|
+
.catch(() => {
|
|
86
|
+
// Reject the edits.
|
|
87
|
+
this.edits.forEach(edit => edit.reject());
|
|
88
|
+
this.notifyListeners(BookSaveStatus.Error);
|
|
89
|
+
})
|
|
90
|
+
.finally(() => {
|
|
91
|
+
// Reset the edit queue.
|
|
92
|
+
this.edits = [];
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
getBook() { return this.book; }
|
|
97
|
+
addListener(listener) { this.listeners.add(listener); }
|
|
98
|
+
removeListener(listener) { this.listeners.delete(listener); }
|
|
99
|
+
notifyListeners(status) { this.listeners.forEach(listener => listener.call(undefined, status)); }
|
|
100
|
+
// Adds a save request to the queue, to be resolved later after a period of
|
|
101
|
+
// inactivity. Returns a promise that will eventually be resolved.
|
|
102
|
+
requestSave() {
|
|
103
|
+
// Tell listeners that this book model changed.
|
|
104
|
+
this.notifyListeners(BookSaveStatus.Changed);
|
|
105
|
+
// Return a promise that will resolve or reject later after this model saves the edits to the database.
|
|
106
|
+
this.lastEdit = Date.now();
|
|
107
|
+
const promise = new Promise((resolve, reject) => {
|
|
108
|
+
this.edits.push({ resolve: resolve, reject: reject });
|
|
109
|
+
});
|
|
110
|
+
return promise;
|
|
111
|
+
}
|
|
112
|
+
// Convert the book to an object for storage.
|
|
113
|
+
toObject() {
|
|
114
|
+
// Deep copy, then let the chapter models handle the chapters.
|
|
115
|
+
const spec = JSON.parse(JSON.stringify(this.specification));
|
|
116
|
+
spec.chapters = this.chapters.map(chapter => chapter.toObject());
|
|
117
|
+
return spec;
|
|
118
|
+
}
|
|
119
|
+
getRef() { return this.editionRef; }
|
|
120
|
+
addUserID(uid) {
|
|
121
|
+
this.specification.uids.push(uid);
|
|
122
|
+
}
|
|
123
|
+
getTitle() { return this.specification.title; }
|
|
124
|
+
setTitle(title) {
|
|
125
|
+
// Update locally, then update on the server.
|
|
126
|
+
this.specification.title = title;
|
|
127
|
+
return this.requestSave();
|
|
128
|
+
}
|
|
129
|
+
getDescription() { return this.specification.description; }
|
|
130
|
+
setDescription(text) {
|
|
131
|
+
// Update locally, then update on the server.
|
|
132
|
+
this.specification.description = text;
|
|
133
|
+
return this.requestSave();
|
|
134
|
+
}
|
|
135
|
+
getAcknowledgements() { return this.specification.acknowledgements; }
|
|
136
|
+
setAcknowledgements(text) {
|
|
137
|
+
// Update locally, then update on the server.
|
|
138
|
+
this.specification.acknowledgements = text;
|
|
139
|
+
return this.requestSave();
|
|
140
|
+
}
|
|
141
|
+
getLicense() { return this.specification.license; }
|
|
142
|
+
setLicense(text) {
|
|
143
|
+
// Update locally, then update on the server.
|
|
144
|
+
this.specification.license = text;
|
|
145
|
+
return this.requestSave();
|
|
146
|
+
}
|
|
147
|
+
getChapters() { return this.chapters; }
|
|
148
|
+
hasChapter(chapterID) { return chapterID in this.chaptersByID || ["references", "glossary", "index", "search", "media"].includes(chapterID); }
|
|
149
|
+
getChapter(chapterID) { return this.hasChapter(chapterID) ? this.chaptersByID[chapterID] : undefined; }
|
|
150
|
+
getChapterPosition(chapterID) {
|
|
151
|
+
var position = 0;
|
|
152
|
+
for (; position < this.chapters.length; position++)
|
|
153
|
+
if (this.chapters[position].getChapterID() === chapterID)
|
|
154
|
+
return position;
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
getChapterCount() { return this.chapters.length; }
|
|
158
|
+
async addChapter() {
|
|
159
|
+
if (!this.editionRef)
|
|
160
|
+
throw Error("No edition ID, can't add chapter");
|
|
161
|
+
const editionID = this.editionRef;
|
|
162
|
+
// Synthesize a chapter ID placeholder that doesn't overlap with existing chapter names
|
|
163
|
+
let number = 1;
|
|
164
|
+
while (this.hasChapter("chapter" + number))
|
|
165
|
+
number++;
|
|
166
|
+
const chapterRef = await addChapterInFirestore(editionID, { text: "" });
|
|
167
|
+
// Create a default chapter on this model. Remember the document reference so we can modify it later.
|
|
168
|
+
const emptyChapter = {
|
|
169
|
+
ref: chapterRef,
|
|
170
|
+
id: `chapter${number}`,
|
|
171
|
+
title: "Untitled Chapter",
|
|
172
|
+
authors: [],
|
|
173
|
+
numbered: true,
|
|
174
|
+
forthcoming: true,
|
|
175
|
+
image: null
|
|
176
|
+
};
|
|
177
|
+
const chap = new Chapter(this, emptyChapter);
|
|
178
|
+
this.chapters.push(chap);
|
|
179
|
+
this.chaptersByID[emptyChapter.id] = chap;
|
|
180
|
+
// Ask the database to create the chapter, returning the promise
|
|
181
|
+
this.requestSave();
|
|
182
|
+
}
|
|
183
|
+
moveChapter(chapterID, increment) {
|
|
184
|
+
// Get the index of the chapter.
|
|
185
|
+
let index = this.chapters.findIndex(chapter => chapter.getChapterID() === chapterID);
|
|
186
|
+
if (index < 0)
|
|
187
|
+
throw Error(`Chapter with ID ${chapterID} doesn't exist, can't move it.`);
|
|
188
|
+
else if (index + increment < 0)
|
|
189
|
+
throw Error(`Can't move this chapter ${increment} chapters earlier.`);
|
|
190
|
+
else if (index + increment >= this.chapters.length)
|
|
191
|
+
throw Error(`Can't move this chapter ${increment} chapters later.`);
|
|
192
|
+
const temp = this.chapters[index + increment];
|
|
193
|
+
this.chapters[index + increment] = this.chapters[index];
|
|
194
|
+
this.chapters[index] = temp;
|
|
195
|
+
// Ask the database to update with this new order.
|
|
196
|
+
return this.requestSave();
|
|
197
|
+
}
|
|
198
|
+
async deleteChapter(chapterID) {
|
|
199
|
+
let index = this.chapters.findIndex(chapter => chapter.getChapterID() === chapterID);
|
|
200
|
+
if (index < 0)
|
|
201
|
+
throw Error(`Chapter with ID ${chapterID} doesn't exist, can't delete it.`);
|
|
202
|
+
const chapter = this.chapters[index];
|
|
203
|
+
this.chapters.splice(index, 1);
|
|
204
|
+
// Ask the database to update the new book metadata then delete the chapter.
|
|
205
|
+
return this.requestSave().then(() => removeChapterFromEditionInFirestore(chapter));
|
|
206
|
+
}
|
|
207
|
+
getSymbols() { return this.specification.symbols; }
|
|
208
|
+
hasReferences() { return this.specification.references && Object.keys(this.specification.references).length > 0; }
|
|
209
|
+
getReferences() { return this.specification.references; }
|
|
210
|
+
getReference(citationID) { return citationID in this.specification.references ? this.specification.references[citationID] : undefined; }
|
|
211
|
+
addReferences(references) {
|
|
212
|
+
// Generate a unique ID for the reference.
|
|
213
|
+
references.forEach(ref => this.specification.references[ref.citationID] = ref.toList());
|
|
214
|
+
return this.requestSave();
|
|
215
|
+
}
|
|
216
|
+
editReference(ref) {
|
|
217
|
+
if (!(ref.citationID in this.specification.references))
|
|
218
|
+
return;
|
|
219
|
+
this.specification.references[ref.citationID] = ref.toList();
|
|
220
|
+
return this.requestSave();
|
|
221
|
+
}
|
|
222
|
+
editReferenceID(newCitationID, ref) {
|
|
223
|
+
if (!(ref.citationID in this.specification.references))
|
|
224
|
+
return;
|
|
225
|
+
delete this.specification.references[ref.citationID];
|
|
226
|
+
this.specification.references[newCitationID] = ref.withCitationID(newCitationID).toList();
|
|
227
|
+
return this.requestSave();
|
|
228
|
+
}
|
|
229
|
+
removeReference(citationID) {
|
|
230
|
+
if (!(citationID in this.specification.references))
|
|
231
|
+
return;
|
|
232
|
+
delete this.specification.references[citationID];
|
|
233
|
+
return this.requestSave();
|
|
234
|
+
}
|
|
235
|
+
hasGlossary() { return this.specification.glossary && Object.keys(this.specification.glossary).length > 0; }
|
|
236
|
+
getGlossary() { return this.specification.glossary; }
|
|
237
|
+
hasDefinition(id) { return id in this.specification.glossary; }
|
|
238
|
+
addDefinition(id, phrase, definition, synonyms) {
|
|
239
|
+
this.specification.glossary[id] = {
|
|
240
|
+
phrase: phrase,
|
|
241
|
+
definition: definition,
|
|
242
|
+
synonyms: synonyms
|
|
243
|
+
};
|
|
244
|
+
return this.requestSave();
|
|
245
|
+
}
|
|
246
|
+
removeDefinition(id) {
|
|
247
|
+
delete this.specification.glossary[id];
|
|
248
|
+
return this.requestSave();
|
|
249
|
+
}
|
|
250
|
+
editDefinition(id, definition) {
|
|
251
|
+
this.specification.glossary[id] = definition;
|
|
252
|
+
return this.requestSave();
|
|
253
|
+
}
|
|
254
|
+
editDefinitionID(id, newID) {
|
|
255
|
+
if (!(id in this.specification.glossary))
|
|
256
|
+
return;
|
|
257
|
+
const definition = this.specification.glossary[id];
|
|
258
|
+
delete this.specification.glossary[id];
|
|
259
|
+
this.specification.glossary[newID] = definition;
|
|
260
|
+
return this.requestSave();
|
|
261
|
+
}
|
|
262
|
+
getTags() { return this.specification.tags; }
|
|
263
|
+
getTheme() { return this.specification.theme; }
|
|
264
|
+
setTheme(theme) {
|
|
265
|
+
this.specification.theme = theme;
|
|
266
|
+
return this.requestSave();
|
|
267
|
+
}
|
|
268
|
+
setThemeValue(group, name, value) {
|
|
269
|
+
if (this.specification.theme[group][name] === value)
|
|
270
|
+
return;
|
|
271
|
+
this.specification.theme[group][name] = value;
|
|
272
|
+
return this.requestSave();
|
|
273
|
+
}
|
|
274
|
+
// Don't let callers get their sneaky hands on this mutable array...
|
|
275
|
+
getAuthors() { return [...this.specification.authors]; }
|
|
276
|
+
addAuthor(name) {
|
|
277
|
+
this.specification.authors.push(name);
|
|
278
|
+
return this.requestSave();
|
|
279
|
+
}
|
|
280
|
+
setAuthor(index, name) {
|
|
281
|
+
if (index >= 0 && index < this.specification.authors.length)
|
|
282
|
+
this.specification.authors[index] = name;
|
|
283
|
+
return this.requestSave();
|
|
284
|
+
}
|
|
285
|
+
removeAuthor(index) {
|
|
286
|
+
if (index >= 0 && index < this.specification.authors.length)
|
|
287
|
+
this.specification.authors.splice(index, 1);
|
|
288
|
+
return this.requestSave();
|
|
289
|
+
}
|
|
290
|
+
getRevisions() { return [...this.specification.revisions]; }
|
|
291
|
+
hasImage(id) { return id in this.specification.images && this.specification.images[id] !== null; }
|
|
292
|
+
getImage(id) { return this.specification.images[id] ?? null; }
|
|
293
|
+
setImage(id, embed) {
|
|
294
|
+
if (this.specification.images[id] === embed)
|
|
295
|
+
return;
|
|
296
|
+
this.specification.images[id] = embed ?? null;
|
|
297
|
+
return this.requestSave();
|
|
298
|
+
}
|
|
299
|
+
getBookReadingTime() {
|
|
300
|
+
return this.chapters
|
|
301
|
+
.map(chapter => chapter.getReadingTime())
|
|
302
|
+
.reduce((total, time) => total === undefined ? 0 :
|
|
303
|
+
time === undefined ?
|
|
304
|
+
total : total + time, 0);
|
|
305
|
+
}
|
|
306
|
+
getChapterNumber(chapterID) {
|
|
307
|
+
let chapterNumber = 1;
|
|
308
|
+
let match = null;
|
|
309
|
+
this.chapters.forEach(chapter => {
|
|
310
|
+
// If we found a match...
|
|
311
|
+
if (chapter.getChapterID() === chapterID) {
|
|
312
|
+
match = chapterNumber;
|
|
313
|
+
// And it's an unnumbered chapter, set to null.
|
|
314
|
+
if (!chapter.isNumbered())
|
|
315
|
+
match = null;
|
|
316
|
+
}
|
|
317
|
+
// Otherwise, increment if it's numbered.
|
|
318
|
+
else if (chapter.isNumbered())
|
|
319
|
+
chapterNumber++;
|
|
320
|
+
});
|
|
321
|
+
// Remember the number if we found it.
|
|
322
|
+
if (match !== null)
|
|
323
|
+
return match;
|
|
324
|
+
else
|
|
325
|
+
return undefined;
|
|
326
|
+
}
|
|
327
|
+
getSource(sourceID) {
|
|
328
|
+
return sourceID.charAt(0) === "#" && sourceID.substring(1) in this.specification.sources ?
|
|
329
|
+
this.specification.sources[sourceID.substring(1)] :
|
|
330
|
+
null;
|
|
331
|
+
}
|
|
332
|
+
getChapterName(chapterID) {
|
|
333
|
+
const chapter = this.getChapter(chapterID);
|
|
334
|
+
return chapter?.getTitle();
|
|
335
|
+
}
|
|
336
|
+
getChapterSection(chapterID) {
|
|
337
|
+
const chapter = this.chaptersByID[chapterID];
|
|
338
|
+
return chapter?.getSection();
|
|
339
|
+
}
|
|
340
|
+
getFootnoteSymbol(number) {
|
|
341
|
+
let symbols = "abcdefghijklmnopqrstuvwxyz";
|
|
342
|
+
// Let's hope there are never more than 26^2 footnotes in a single chapter...
|
|
343
|
+
return number < symbols.length ?
|
|
344
|
+
symbols.charAt(number) :
|
|
345
|
+
symbols.charAt(Math.floor(number / symbols.length) - 1) + symbols.charAt(number % symbols.length);
|
|
346
|
+
}
|
|
347
|
+
getBookIndex() {
|
|
348
|
+
// A map from word to a map of chapters containing the word
|
|
349
|
+
const bookIndex = {};
|
|
350
|
+
// Construct the index by building a dictionary of chapters in which each word appears.
|
|
351
|
+
this.chapters.forEach(chapter => {
|
|
352
|
+
let index = chapter.getIndex();
|
|
353
|
+
if (index)
|
|
354
|
+
Object.keys(index).forEach(word => {
|
|
355
|
+
if (word !== "" && word.length > 2) {
|
|
356
|
+
if (!(word in bookIndex))
|
|
357
|
+
bookIndex[word] = new Set();
|
|
358
|
+
bookIndex[word].add(chapter.getChapterID());
|
|
359
|
+
}
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
return bookIndex;
|
|
363
|
+
}
|
|
364
|
+
// Given the current chapter, find the available chapter after it.
|
|
365
|
+
getNextChapterID(chapterID) {
|
|
366
|
+
// Handle back matter chapters.
|
|
367
|
+
switch (chapterID) {
|
|
368
|
+
case ChapterIDs.ReferencesID: return this.hasGlossary() ? ChapterIDs.GlossaryID : ChapterIDs.IndexID;
|
|
369
|
+
case ChapterIDs.GlossaryID: return ChapterIDs.IndexID;
|
|
370
|
+
case ChapterIDs.IndexID: return ChapterIDs.SearchID;
|
|
371
|
+
case ChapterIDs.SearchID: return ChapterIDs.MediaID;
|
|
372
|
+
case ChapterIDs.MediaID: return ChapterIDs.TableOfContentsID;
|
|
373
|
+
case ChapterIDs.TableOfContentsID: return this.chapters.length > 0 ? this.chapters[0].getChapterID() : null;
|
|
374
|
+
default:
|
|
375
|
+
let after = false;
|
|
376
|
+
for (let i = 0; i < this.chapters.length; i++) {
|
|
377
|
+
let chapter = this.chapters[i];
|
|
378
|
+
if (chapter.getChapterID() === chapterID)
|
|
379
|
+
after = true;
|
|
380
|
+
// If we're after the given chapter and it's not forthcoming.
|
|
381
|
+
else if (after && !chapter.isForthcoming())
|
|
382
|
+
return chapter.getChapterID();
|
|
383
|
+
}
|
|
384
|
+
// If the given ID was the last chapter, go to the next back matter chapter.
|
|
385
|
+
if (after)
|
|
386
|
+
return this.hasReferences() ? ChapterIDs.ReferencesID : this.hasGlossary() ? ChapterIDs.GlossaryID : ChapterIDs.IndexID;
|
|
387
|
+
// Otherwise, it wasn't a valid ID
|
|
388
|
+
else
|
|
389
|
+
return null;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
// Given a chapter id, find the available chapter before it.
|
|
393
|
+
getPreviousChapterID(chapterID) {
|
|
394
|
+
switch (chapterID) {
|
|
395
|
+
// Handle back matter chapters.
|
|
396
|
+
case ChapterIDs.ReferencesID: return this.chapters.length > 0 ? this.chapters[this.chapters.length - 1].getChapterID() : null; // Last chapter of the book
|
|
397
|
+
case ChapterIDs.GlossaryID: return this.hasReferences() ? ChapterIDs.ReferencesID : this.chapters.length > 0 ? this.chapters[this.chapters.length - 1].getChapterID() : ChapterIDs.TableOfContentsID;
|
|
398
|
+
case ChapterIDs.IndexID: return this.hasGlossary() ? ChapterIDs.GlossaryID : this.hasReferences() ? ChapterIDs.ReferencesID : this.chapters.length > 0 ? this.chapters[this.chapters.length - 1].getChapterID() : ChapterIDs.TableOfContentsID;
|
|
399
|
+
case ChapterIDs.SearchID: return ChapterIDs.IndexID;
|
|
400
|
+
case ChapterIDs.MediaID: return ChapterIDs.SearchID;
|
|
401
|
+
default:
|
|
402
|
+
let before = false;
|
|
403
|
+
for (let i = this.chapters.length - 1; i >= 0; i--) {
|
|
404
|
+
let chapter = this.chapters[i];
|
|
405
|
+
if (chapter.getChapterID() === chapterID)
|
|
406
|
+
before = true;
|
|
407
|
+
// If we're before the given chapter and it's not forthcoming.
|
|
408
|
+
else if (before && !chapter.isForthcoming())
|
|
409
|
+
return chapter.getChapterID();
|
|
410
|
+
}
|
|
411
|
+
// If the given ID was the last chapter, go to the next back matter chapter.
|
|
412
|
+
if (before)
|
|
413
|
+
return ChapterIDs.TableOfContentsID;
|
|
414
|
+
// Otherwise, it wasn't a valid ID
|
|
415
|
+
else
|
|
416
|
+
return null;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
// Get all of the embeds in the book
|
|
420
|
+
getEmbeds() {
|
|
421
|
+
let embeds = [];
|
|
422
|
+
// Add the book cover
|
|
423
|
+
const cover = this.getImage("cover");
|
|
424
|
+
if (cover) {
|
|
425
|
+
let coverNode = Parser.parseEmbed(this, cover);
|
|
426
|
+
if (coverNode instanceof EmbedNode)
|
|
427
|
+
embeds.push(coverNode);
|
|
428
|
+
}
|
|
429
|
+
// Add the cover and images from each chapter.
|
|
430
|
+
this.getChapters().forEach(c => {
|
|
431
|
+
const image = c.getImage();
|
|
432
|
+
let cover = image === null ? undefined : Parser.parseEmbed(this, image);
|
|
433
|
+
if (cover && cover instanceof EmbedNode)
|
|
434
|
+
embeds.push(cover);
|
|
435
|
+
// Get the chapter body's embeds
|
|
436
|
+
let bodyEmbeds = c?.getAST()?.getEmbeds();
|
|
437
|
+
if (bodyEmbeds)
|
|
438
|
+
bodyEmbeds.forEach((embed) => embeds.push(embed));
|
|
439
|
+
});
|
|
440
|
+
// Add the back matter covers
|
|
441
|
+
let backmatter = ["references", "glossary", "index", "search", "media"];
|
|
442
|
+
backmatter.forEach(id => {
|
|
443
|
+
const img = this.getImage(id);
|
|
444
|
+
if (img) {
|
|
445
|
+
let image = Parser.parseEmbed(this, img);
|
|
446
|
+
if (image instanceof EmbedNode)
|
|
447
|
+
embeds.push(image);
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
return embeds;
|
|
451
|
+
}
|
|
452
|
+
isLatestPublishedEdition() {
|
|
453
|
+
const latestEditionID = this.book?.getLatestPublishedEditionID();
|
|
454
|
+
return latestEditionID !== undefined && latestEditionID === this.editionRef?.id;
|
|
455
|
+
}
|
|
456
|
+
/* Edition numbers are 1 to N */
|
|
457
|
+
getEditionNumber() {
|
|
458
|
+
const revisions = this.book?.getRevisions();
|
|
459
|
+
if (revisions === undefined)
|
|
460
|
+
return undefined;
|
|
461
|
+
for (let i = 0; i < revisions.length; i++)
|
|
462
|
+
if (revisions[i].ref.id === this.editionRef?.id)
|
|
463
|
+
return revisions.length - i;
|
|
464
|
+
return undefined;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type ThemeColors from "./ThemeColors";
|
|
2
|
+
declare type Theme = {
|
|
3
|
+
light: ThemeColors;
|
|
4
|
+
dark: ThemeColors;
|
|
5
|
+
fonts: {
|
|
6
|
+
paragraphFontFamily: string;
|
|
7
|
+
headerFontFamily: string;
|
|
8
|
+
codeFontFamily: string;
|
|
9
|
+
bulletFontFamily: string;
|
|
10
|
+
};
|
|
11
|
+
sizes: {
|
|
12
|
+
paragraphFontSize: string;
|
|
13
|
+
blockFontSize: string;
|
|
14
|
+
smallFontSize: string;
|
|
15
|
+
titleFontSize: string;
|
|
16
|
+
header1FontSize: string;
|
|
17
|
+
header2FontSize: string;
|
|
18
|
+
header3FontSize: string;
|
|
19
|
+
codeFontSize: string;
|
|
20
|
+
};
|
|
21
|
+
weights: {
|
|
22
|
+
headerFontWeight: string;
|
|
23
|
+
paragraphFontWeight: string;
|
|
24
|
+
boldFontWeight: string;
|
|
25
|
+
linkFontWeight: string;
|
|
26
|
+
codeFontWeight: string;
|
|
27
|
+
bulletFontWeight: string;
|
|
28
|
+
};
|
|
29
|
+
spacing: {
|
|
30
|
+
paragraphLineHeight: string;
|
|
31
|
+
paragraphLineHeightTight: string;
|
|
32
|
+
headerLineHeight: string;
|
|
33
|
+
paragraphSpacing: string;
|
|
34
|
+
headerSpacing: string;
|
|
35
|
+
indent: string;
|
|
36
|
+
inlinePadding: string;
|
|
37
|
+
blockPadding: string;
|
|
38
|
+
roundedness: string;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
export declare const defaultTheme: {
|
|
42
|
+
light: {
|
|
43
|
+
backgroundColor: string;
|
|
44
|
+
blockBackgroundColor: string;
|
|
45
|
+
errorBackgroundColor: string;
|
|
46
|
+
borderColorLight: string;
|
|
47
|
+
borderColorBold: string;
|
|
48
|
+
paragraphColor: string;
|
|
49
|
+
mutedColor: string;
|
|
50
|
+
highlightColor: string;
|
|
51
|
+
commentColor: string;
|
|
52
|
+
errorColor: string;
|
|
53
|
+
linkColor: string;
|
|
54
|
+
bulletColor: string;
|
|
55
|
+
};
|
|
56
|
+
dark: {
|
|
57
|
+
backgroundColor: string;
|
|
58
|
+
blockBackgroundColor: string;
|
|
59
|
+
errorBackgroundColor: string;
|
|
60
|
+
borderColorLight: string;
|
|
61
|
+
borderColorBold: string;
|
|
62
|
+
paragraphColor: string;
|
|
63
|
+
mutedColor: string;
|
|
64
|
+
highlightColor: string;
|
|
65
|
+
commentColor: string;
|
|
66
|
+
errorColor: string;
|
|
67
|
+
linkColor: string;
|
|
68
|
+
bulletColor: string;
|
|
69
|
+
};
|
|
70
|
+
fonts: {
|
|
71
|
+
paragraphFontFamily: string;
|
|
72
|
+
headerFontFamily: string;
|
|
73
|
+
codeFontFamily: string;
|
|
74
|
+
bulletFontFamily: string;
|
|
75
|
+
};
|
|
76
|
+
sizes: {
|
|
77
|
+
paragraphFontSize: string;
|
|
78
|
+
blockFontSize: string;
|
|
79
|
+
smallFontSize: string;
|
|
80
|
+
titleFontSize: string;
|
|
81
|
+
header1FontSize: string;
|
|
82
|
+
header2FontSize: string;
|
|
83
|
+
header3FontSize: string;
|
|
84
|
+
codeFontSize: string;
|
|
85
|
+
};
|
|
86
|
+
weights: {
|
|
87
|
+
headerFontWeight: string;
|
|
88
|
+
paragraphFontWeight: string;
|
|
89
|
+
boldFontWeight: string;
|
|
90
|
+
linkFontWeight: string;
|
|
91
|
+
codeFontWeight: string;
|
|
92
|
+
bulletFontWeight: string;
|
|
93
|
+
};
|
|
94
|
+
spacing: {
|
|
95
|
+
paragraphLineHeight: string;
|
|
96
|
+
paragraphLineHeightTight: string;
|
|
97
|
+
headerLineHeight: string;
|
|
98
|
+
paragraphSpacing: string;
|
|
99
|
+
headerSpacing: string;
|
|
100
|
+
indent: string;
|
|
101
|
+
inlinePadding: string;
|
|
102
|
+
blockPadding: string;
|
|
103
|
+
roundedness: string;
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
export default Theme;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export const defaultTheme = {
|
|
2
|
+
// Background colors
|
|
3
|
+
light: {
|
|
4
|
+
// Background colors;
|
|
5
|
+
backgroundColor: "#FFFFFF",
|
|
6
|
+
blockBackgroundColor: "#FCFAFA",
|
|
7
|
+
errorBackgroundColor: "#F8D7DA",
|
|
8
|
+
// Border colors
|
|
9
|
+
borderColorLight: "#E0E0E0",
|
|
10
|
+
borderColorBold: "#000000",
|
|
11
|
+
// Foreground colors
|
|
12
|
+
paragraphColor: "#000000",
|
|
13
|
+
mutedColor: "#9AA1A7",
|
|
14
|
+
highlightColor: "#E8AF22",
|
|
15
|
+
commentColor: "#257F31",
|
|
16
|
+
errorColor: "#721C24",
|
|
17
|
+
linkColor: "#1B499C",
|
|
18
|
+
bulletColor: "#EB2C27"
|
|
19
|
+
},
|
|
20
|
+
dark: {
|
|
21
|
+
// Background colors;
|
|
22
|
+
backgroundColor: "#1C1C1C",
|
|
23
|
+
blockBackgroundColor: "#333333",
|
|
24
|
+
errorBackgroundColor: "#721C24",
|
|
25
|
+
// Border colors
|
|
26
|
+
borderColorLight: "#444444",
|
|
27
|
+
borderColorBold: "#DADADA",
|
|
28
|
+
// Foreground colors
|
|
29
|
+
paragraphColor: "#DADADA",
|
|
30
|
+
mutedColor: "#666666",
|
|
31
|
+
highlightColor: "#c5a248",
|
|
32
|
+
commentColor: "#1c4722",
|
|
33
|
+
errorColor: "#F8D7DA",
|
|
34
|
+
linkColor: "#73a3fa",
|
|
35
|
+
bulletColor: "#721C24"
|
|
36
|
+
},
|
|
37
|
+
// Fonts
|
|
38
|
+
fonts: {
|
|
39
|
+
paragraphFontFamily: '"Georgia", serif',
|
|
40
|
+
headerFontFamily: '"Verdana", serif',
|
|
41
|
+
codeFontFamily: '"Courier New", monospace',
|
|
42
|
+
bulletFontFamily: '"Verdana"'
|
|
43
|
+
},
|
|
44
|
+
// Font sizes
|
|
45
|
+
sizes: {
|
|
46
|
+
paragraphFontSize: "14pt",
|
|
47
|
+
blockFontSize: "11pt",
|
|
48
|
+
smallFontSize: "9pt",
|
|
49
|
+
titleFontSize: "2.4rem",
|
|
50
|
+
header1FontSize: "2rem",
|
|
51
|
+
header2FontSize: "1.5rem",
|
|
52
|
+
header3FontSize: "1rem",
|
|
53
|
+
codeFontSize: "11pt"
|
|
54
|
+
},
|
|
55
|
+
// Font weights
|
|
56
|
+
weights: {
|
|
57
|
+
headerFontWeight: "700",
|
|
58
|
+
paragraphFontWeight: "400",
|
|
59
|
+
boldFontWeight: "700",
|
|
60
|
+
linkFontWeight: "400",
|
|
61
|
+
codeFontWeight: "400",
|
|
62
|
+
bulletFontWeight: "500"
|
|
63
|
+
},
|
|
64
|
+
// Spacing
|
|
65
|
+
spacing: {
|
|
66
|
+
paragraphLineHeight: "1.8em",
|
|
67
|
+
paragraphLineHeightTight: "1.4em",
|
|
68
|
+
headerLineHeight: "1.4em",
|
|
69
|
+
paragraphSpacing: "1.8rem",
|
|
70
|
+
headerSpacing: "2rem",
|
|
71
|
+
indent: "10%",
|
|
72
|
+
inlinePadding: "0.25rem",
|
|
73
|
+
blockPadding: "1rem",
|
|
74
|
+
roundedness: "5px"
|
|
75
|
+
}
|
|
76
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
declare type ThemeColors = {
|
|
2
|
+
backgroundColor: string;
|
|
3
|
+
blockBackgroundColor: string;
|
|
4
|
+
errorBackgroundColor: string;
|
|
5
|
+
borderColorLight: string;
|
|
6
|
+
borderColorBold: string;
|
|
7
|
+
paragraphColor: string;
|
|
8
|
+
mutedColor: string;
|
|
9
|
+
highlightColor: string;
|
|
10
|
+
commentColor: string;
|
|
11
|
+
errorColor: string;
|
|
12
|
+
linkColor: string;
|
|
13
|
+
bulletColor: string;
|
|
14
|
+
};
|
|
15
|
+
export default ThemeColors;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type Caret from "./Caret";
|
|
2
|
+
import FormatNode from "./FormatNode";
|
|
3
|
+
import Node from "./Node";
|
|
4
|
+
import type RootNode from "./RootNode";
|
|
5
|
+
export default abstract class AtomNode<MetadataType> extends Node {
|
|
6
|
+
#private;
|
|
7
|
+
constructor(meta: MetadataType);
|
|
8
|
+
getMeta(): MetadataType;
|
|
9
|
+
abstract getDefaultCaret(): Caret | undefined;
|
|
10
|
+
getChildren(): (MetadataType & Node)[];
|
|
11
|
+
nextWord(root: RootNode): Caret;
|
|
12
|
+
previousWord(root: RootNode): Caret;
|
|
13
|
+
getFormatRoot(root: Node): FormatNode | undefined;
|
|
14
|
+
getCaretPositionCount(): number;
|
|
15
|
+
abstract toBookdown(format?: FormatNode): string;
|
|
16
|
+
abstract toText(): string;
|
|
17
|
+
abstract withMeta(meta: MetadataType): AtomNode<MetadataType>;
|
|
18
|
+
}
|