bookish-press 0.9.4 → 0.10.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/dist/components/Auth.svelte +37 -21
- package/dist/components/BookPreview.svelte +4 -4
- package/dist/components/BookPreview.svelte.d.ts +1 -1
- package/dist/components/Link.svelte +19 -12
- package/dist/components/app/Button.svelte +1 -8
- package/dist/components/app/Link.svelte +1 -7
- package/dist/components/app/Options.svelte +1 -6
- package/dist/components/app/TextInput.svelte +2 -8
- package/dist/components/chapter/Atom.svelte +2 -1
- package/dist/components/chapter/Atom.svelte.d.ts +1 -1
- package/dist/components/chapter/Block.svelte +9 -9
- package/dist/components/chapter/Block.svelte.d.ts +1 -1
- package/dist/components/chapter/Callout.svelte.d.ts +1 -1
- package/dist/components/chapter/CaptionedCode.svelte +1 -0
- package/dist/components/chapter/CaptionedCode.svelte.d.ts +1 -1
- package/dist/components/chapter/ChapterBody.svelte +5 -2
- package/dist/components/chapter/ChapterBody.svelte.d.ts +1 -1
- package/dist/components/chapter/ChapterBody.test.js +3 -3
- package/dist/components/chapter/Citations.svelte +17 -16
- package/dist/components/chapter/Citations.svelte.d.ts +1 -1
- package/dist/components/chapter/Code.svelte +8 -14
- package/dist/components/chapter/Comment.svelte +7 -12
- package/dist/components/chapter/Comment.svelte.d.ts +1 -1
- package/dist/components/chapter/Definition.svelte +8 -9
- package/dist/components/chapter/Definition.svelte.d.ts +1 -1
- package/dist/components/chapter/Embed.svelte +41 -61
- package/dist/components/chapter/Embed.svelte.d.ts +1 -1
- package/dist/components/chapter/ErrorMessage.svelte.d.ts +1 -1
- package/dist/components/chapter/Figure.svelte +14 -14
- package/dist/components/chapter/Figure.svelte.d.ts +4 -4
- package/dist/components/chapter/Footnote.svelte +11 -17
- package/dist/components/chapter/Footnote.svelte.d.ts +1 -1
- package/dist/components/chapter/Format.svelte +11 -11
- package/dist/components/chapter/Format.svelte.d.ts +1 -1
- package/dist/components/chapter/InlineCode.svelte.d.ts +1 -1
- package/dist/components/chapter/Label.svelte +1 -1
- package/dist/components/chapter/Label.svelte.d.ts +1 -1
- package/dist/components/chapter/LineBreak.svelte +1 -0
- package/dist/components/chapter/LineBreak.svelte.d.ts +1 -1
- package/dist/components/chapter/Link.svelte +14 -12
- package/dist/components/chapter/Link.svelte.d.ts +1 -1
- package/dist/components/chapter/List.svelte +1 -1
- package/dist/components/chapter/List.svelte.d.ts +1 -1
- package/dist/components/chapter/Marginal.svelte +36 -42
- package/dist/components/chapter/Paragraph.svelte +4 -4
- package/dist/components/chapter/Paragraph.svelte.d.ts +1 -1
- package/dist/components/chapter/Positioned.svelte +1 -0
- package/dist/components/chapter/Positioned.svelte.d.ts +1 -1
- package/dist/components/chapter/Python.svelte +42 -31
- package/dist/components/chapter/Python.svelte.d.ts +1 -1
- package/dist/components/chapter/Quote.svelte.d.ts +1 -1
- package/dist/components/chapter/Rule.svelte +1 -0
- package/dist/components/chapter/Rule.svelte.d.ts +1 -1
- package/dist/components/chapter/Table.svelte.d.ts +1 -1
- package/dist/components/chapter/Text.svelte +41 -50
- package/dist/components/chapter/Text.svelte.d.ts +1 -1
- package/dist/components/controls/DarkToggle.svelte +4 -4
- package/dist/components/editor/BookishEditor.svelte +605 -569
- package/dist/components/editor/BookishEditor.svelte.d.ts +1 -1
- package/dist/components/editor/CalloutEditor.svelte +1 -1
- package/dist/components/editor/CalloutEditor.svelte.d.ts +1 -1
- package/dist/components/editor/CaptionedCodeEditor.svelte +1 -1
- package/dist/components/editor/CaptionedCodeEditor.svelte.d.ts +1 -1
- package/dist/components/editor/CaretContext.d.ts +14 -14
- package/dist/components/editor/CaretState.d.ts +3 -3
- package/dist/components/editor/CaretView.svelte +8 -19
- package/dist/components/editor/CitationsEditor.svelte +10 -18
- package/dist/components/editor/CitationsEditor.svelte.d.ts +1 -1
- package/dist/components/editor/Clipboard.d.ts +1 -1
- package/dist/components/editor/Command.d.ts +1 -1
- package/dist/components/editor/Commands.js +19 -19
- package/dist/components/editor/ConfirmButton.svelte +1 -6
- package/dist/components/editor/DefinitionEditor.svelte +9 -7
- package/dist/components/editor/DefinitionEditor.svelte.d.ts +1 -1
- package/dist/components/editor/EmbedEditor.svelte +25 -34
- package/dist/components/editor/EmbedEditor.svelte.d.ts +1 -1
- package/dist/components/editor/ImageChooser.svelte +8 -7
- package/dist/components/editor/ImageChooser.svelte.d.ts +1 -1
- package/dist/components/editor/ImageThumbnail.svelte +21 -18
- package/dist/components/editor/InlineCodeEditor.svelte +1 -1
- package/dist/components/editor/InlineCodeEditor.svelte.d.ts +1 -1
- package/dist/components/editor/LabelEditor.svelte +2 -2
- package/dist/components/editor/LabelEditor.svelte.d.ts +1 -1
- package/dist/components/editor/LanguageEditor.svelte +8 -1
- package/dist/components/editor/LinkEditor.svelte +42 -44
- package/dist/components/editor/LinkEditor.svelte.d.ts +1 -1
- package/dist/components/editor/Permissions.svelte +23 -29
- package/dist/components/editor/PositionEditor.svelte +1 -1
- package/dist/components/editor/PositionEditor.svelte.d.ts +1 -1
- package/dist/components/editor/QuoteEditor.svelte +1 -1
- package/dist/components/editor/QuoteEditor.svelte.d.ts +1 -1
- package/dist/components/editor/Switch.svelte +5 -11
- package/dist/components/editor/TableEditor.svelte +1 -1
- package/dist/components/editor/TableEditor.svelte.d.ts +1 -1
- package/dist/components/editor/TextEditor.svelte +61 -58
- package/dist/components/editor/Toggle.svelte +16 -14
- package/dist/components/editor/Toolbar.svelte +81 -94
- package/dist/components/editor/UndoState.d.ts +2 -2
- package/dist/components/page/Acknowledgements.svelte +2 -8
- package/dist/components/page/Authors.svelte +12 -21
- package/dist/components/page/BookLoader.svelte +32 -34
- package/dist/components/page/BulkReferenceEditor.svelte +21 -41
- package/dist/components/page/Chapter.svelte +139 -114
- package/dist/components/page/Chapter.svelte.d.ts +1 -1
- package/dist/components/page/ChapterTitle.svelte +1 -1
- package/dist/components/page/Contexts.js +3 -1
- package/dist/components/page/DefinitionView.svelte +30 -42
- package/dist/components/page/DefinitionView.svelte.d.ts +1 -1
- package/dist/components/page/Description.svelte +2 -8
- package/dist/components/page/DownloadEPUB.svelte +83 -41
- package/dist/components/page/EditableHeader.svelte.d.ts +1 -1
- package/dist/components/page/Edition.svelte +44 -30
- package/dist/components/page/Edition.svelte.d.ts +1 -1
- package/dist/components/page/EditionLoader.svelte +101 -100
- package/dist/components/page/Editions.svelte +13 -13
- package/dist/components/page/Glossary.svelte +9 -10
- package/dist/components/page/Header.svelte +15 -28
- package/dist/components/page/Index.svelte +17 -18
- package/dist/components/page/License.svelte +2 -8
- package/dist/components/page/Media.svelte +7 -14
- package/dist/components/page/MediaPreview.svelte +14 -17
- package/dist/components/page/Outline.svelte +74 -66
- package/dist/components/page/Page.svelte +23 -17
- package/dist/components/page/PossibleChapter.svelte +2 -2
- package/dist/components/page/PossibleReference.svelte +1 -1
- package/dist/components/page/PossibleReference.svelte.d.ts +2 -2
- package/dist/components/page/Print.svelte +5 -8
- package/dist/components/page/Publish.svelte +33 -39
- package/dist/components/page/Reference.svelte +9 -11
- package/dist/components/page/Reference.svelte.d.ts +1 -1
- package/dist/components/page/References.svelte +1 -1
- package/dist/components/page/Search.svelte +39 -40
- package/dist/components/page/SubdomainEditor.svelte +11 -10
- package/dist/components/page/TableOfContents.svelte +52 -48
- package/dist/components/page/TableOfContentsImage.svelte +2 -2
- package/dist/components/page/TableOfContentsRow.svelte +9 -22
- package/dist/components/page/TableOfContentsRow.svelte.d.ts +2 -2
- package/dist/components/page/ThemeEditor.svelte +10 -17
- package/dist/components/page/ThemeEditorPreview.svelte +3 -6
- package/dist/components/page/ThemeEditorPreview.svelte.d.ts +1 -1
- package/dist/components/page/ThemeVariableEditor.svelte +6 -6
- package/dist/components/page/Unknown.svelte +1 -1
- package/dist/epub/build.d.ts +6 -0
- package/dist/epub/build.js +16 -3
- package/dist/epub/build.test.js +65 -0
- package/dist/epub/images.d.ts +7 -5
- package/dist/epub/images.js +15 -10
- package/dist/epub/images.test.js +8 -6
- package/dist/epub/package.js +25 -3
- package/dist/models/FirebaseAvailable.d.ts +9 -0
- package/dist/models/FirebaseAvailable.js +10 -0
- package/dist/models/book/BookMedia.d.ts +2 -1
- package/dist/models/book/BookMedia.js +33 -9
- package/package.json +18 -14
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import Outline from "./Outline.svelte";
|
|
3
3
|
import Page from "./Page.svelte";
|
|
4
4
|
import Instructions from "./Instructions.svelte";
|
|
5
|
-
import ChapterIDs from "../../models/book/ChapterID";
|
|
5
|
+
import ChapterIDs from "../../models/book/ChapterID.js";
|
|
6
6
|
import Link from "../Link.svelte";
|
|
7
7
|
import { getBase, getEdition, isEditionEditable } from "./Contexts";
|
|
8
8
|
import { page } from "$app/state";
|
|
@@ -14,28 +14,27 @@ import Rows from "./Rows.svelte";
|
|
|
14
14
|
let editable = isEditionEditable();
|
|
15
15
|
let edition = getEdition();
|
|
16
16
|
let base = getBase();
|
|
17
|
+
// What letter are we matching?
|
|
17
18
|
let letter = $derived(page.params.letter);
|
|
18
19
|
let bookIndex = $derived($edition?.getBookIndex() ?? {});
|
|
20
|
+
// Figure out what letters have words
|
|
19
21
|
let letters = $derived.by(() => {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
))
|
|
24
|
-
map[word.charAt(0).toLocaleLowerCase()] = true;
|
|
25
|
-
return map;
|
|
22
|
+
const map = {};
|
|
23
|
+
for (const word of Object.keys(bookIndex).sort((a, b) => a.localeCompare(b))) map[word.charAt(0).toLocaleLowerCase()] = true;
|
|
24
|
+
return map;
|
|
26
25
|
});
|
|
27
26
|
let words = $derived.by(() => {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
27
|
+
const list = [];
|
|
28
|
+
let count = 0;
|
|
29
|
+
Object.keys(bookIndex).sort((a, b) => a.localeCompare(b)).forEach((word) => {
|
|
30
|
+
const firstLetter = word.charAt(0).toLowerCase();
|
|
31
|
+
if (letter === firstLetter) {
|
|
32
|
+
count++;
|
|
33
|
+
if (count % 20 === 0) list.push(true);
|
|
34
|
+
list.push(word);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
return list;
|
|
39
38
|
});
|
|
40
39
|
</script>
|
|
41
40
|
|
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
<script lang="ts">import Parser from "../../models/chapter/Parser";
|
|
1
|
+
<script lang="ts">import Parser from "../../models/chapter/Parser.js";
|
|
2
2
|
import BookishEditor from "../editor/BookishEditor.svelte";
|
|
3
3
|
import Instructions from "./Instructions.svelte";
|
|
4
4
|
import Format from "../chapter/Format.svelte";
|
|
5
|
-
import {
|
|
6
|
-
getUser,
|
|
7
|
-
getEdition,
|
|
8
|
-
getLeasee,
|
|
9
|
-
isEditionEditable,
|
|
10
|
-
lease
|
|
11
|
-
} from "./Contexts";
|
|
5
|
+
import { getUser, getEdition, getLeasee, isEditionEditable, lease } from "./Contexts";
|
|
12
6
|
import EditableHeader from "./EditableHeader.svelte";
|
|
13
7
|
let auth = getUser();
|
|
14
8
|
let edition = getEdition();
|
|
@@ -2,17 +2,11 @@
|
|
|
2
2
|
import Outline from "./Outline.svelte";
|
|
3
3
|
import Page from "./Page.svelte";
|
|
4
4
|
import Instructions from "./Instructions.svelte";
|
|
5
|
-
import ChapterIDs from "../../models/book/ChapterID";
|
|
5
|
+
import ChapterIDs from "../../models/book/ChapterID.js";
|
|
6
6
|
import Format from "../chapter/Format.svelte";
|
|
7
7
|
import MediaPreview from "./MediaPreview.svelte";
|
|
8
8
|
import { onMount } from "svelte";
|
|
9
|
-
import {
|
|
10
|
-
getBase,
|
|
11
|
-
getBook,
|
|
12
|
-
getEdition,
|
|
13
|
-
isBookEditable,
|
|
14
|
-
isEditionEditable
|
|
15
|
-
} from "./Contexts";
|
|
9
|
+
import { getBase, getBook, getEdition, isBookEditable, isEditionEditable } from "./Contexts";
|
|
16
10
|
import PageHeader from "./PageHeader.svelte";
|
|
17
11
|
import ConfirmButton from "../editor/ConfirmButton.svelte";
|
|
18
12
|
let book = getBook();
|
|
@@ -23,15 +17,14 @@ let images = $state([]);
|
|
|
23
17
|
let embeds = $derived($edition?.getEmbeds() ?? []);
|
|
24
18
|
let media = $derived($book?.getMedia());
|
|
25
19
|
function updateImages(newImages) {
|
|
26
|
-
|
|
20
|
+
images = newImages;
|
|
27
21
|
}
|
|
28
22
|
onMount(() => {
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
// Listen to image changes.
|
|
24
|
+
media?.notify(updateImages);
|
|
25
|
+
return () => media?.stopNotifying(updateImages);
|
|
31
26
|
});
|
|
32
|
-
let unused = $derived(images?.filter(
|
|
33
|
-
(image) => !embeds.some((embed) => image.url.includes(embed.embed.getURL()))
|
|
34
|
-
));
|
|
27
|
+
let unused = $derived(images?.filter((image) => !embeds.some((embed) => image.url.includes(embed.embed.getURL()))));
|
|
35
28
|
</script>
|
|
36
29
|
|
|
37
30
|
{#if $edition}
|
|
@@ -1,25 +1,22 @@
|
|
|
1
1
|
<script lang="ts">import Link from "../Link.svelte";
|
|
2
2
|
import { getBase } from "./Contexts";
|
|
3
|
-
let {
|
|
4
|
-
url,
|
|
5
|
-
alt,
|
|
6
|
-
chapterID,
|
|
7
|
-
children
|
|
8
|
-
} = $props();
|
|
3
|
+
let { url, alt, chapterID, children } = $props();
|
|
9
4
|
let base = getBase();
|
|
10
5
|
let loaded = $state();
|
|
11
|
-
|
|
6
|
+
// Not $state: it's only a guard against re-checking the same URL, and
|
|
7
|
+
// making it reactive would make this effect re-run on its own write.
|
|
8
|
+
let urlChecked = undefined;
|
|
12
9
|
$effect.pre(() => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
10
|
+
if (urlChecked !== url && typeof Image !== "undefined") {
|
|
11
|
+
urlChecked = url;
|
|
12
|
+
let image = new Image();
|
|
13
|
+
image.src = url;
|
|
14
|
+
loaded = image.complete;
|
|
15
|
+
if (!loaded) {
|
|
16
|
+
image.onload = () => loaded = true;
|
|
17
|
+
image.onerror = () => loaded = null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
23
20
|
});
|
|
24
21
|
</script>
|
|
25
22
|
|
|
@@ -1,14 +1,9 @@
|
|
|
1
|
-
<script lang="ts">import { isMobile } from "../../util/isMobile";
|
|
1
|
+
<script lang="ts">import { isMobile } from "../../util/isMobile.js";
|
|
2
2
|
import { onMount } from "svelte";
|
|
3
3
|
import Link from "../Link.svelte";
|
|
4
4
|
import { getBase, getDarkMode } from "./Contexts";
|
|
5
5
|
import DarkToggle from "../controls/DarkToggle.svelte";
|
|
6
|
-
let {
|
|
7
|
-
previous,
|
|
8
|
-
next,
|
|
9
|
-
collapse = false,
|
|
10
|
-
listener = void 0
|
|
11
|
-
} = $props();
|
|
6
|
+
let { previous, next, collapse = false, listener = undefined } = $props();
|
|
12
7
|
let headerString = null;
|
|
13
8
|
let headerIndex = $state(-1);
|
|
14
9
|
let expanded = $state(false);
|
|
@@ -17,80 +12,93 @@ let base = getBase();
|
|
|
17
12
|
let outline = $state(null);
|
|
18
13
|
let headers = $state([]);
|
|
19
14
|
function toggleExpanded() {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
// Don't toggle when in margin mode.
|
|
16
|
+
if (!isMobile()) return;
|
|
17
|
+
const newExpanded = !expanded;
|
|
18
|
+
// Toggle expanded state
|
|
19
|
+
expanded = newExpanded;
|
|
20
|
+
if (listener) listener(newExpanded, layout);
|
|
24
21
|
}
|
|
25
22
|
function toggleReadingMode() {
|
|
26
|
-
|
|
23
|
+
dark.set(!$dark);
|
|
27
24
|
}
|
|
28
25
|
function layout() {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
position();
|
|
27
|
+
highlight();
|
|
28
|
+
updateHeaders();
|
|
32
29
|
}
|
|
33
30
|
function updateHeaders() {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
31
|
+
// When the outline updates (due to the page its on updating), generate a unique string for the current header outline.
|
|
32
|
+
// If it's different from the last rendered state, refresh.
|
|
33
|
+
headers = Array.from(document.getElementsByClassName("page-header"));
|
|
34
|
+
let newHeaderString = headers.reduce((sum, el) => sum + el.outerHTML, "");
|
|
35
|
+
// If the headers change, update the outline.
|
|
36
|
+
if (headerString !== newHeaderString) headerString = newHeaderString;
|
|
40
37
|
}
|
|
41
38
|
function getHighlightThreshold() {
|
|
42
|
-
|
|
39
|
+
return window.innerHeight / 3;
|
|
43
40
|
}
|
|
44
41
|
function position() {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
42
|
+
// Left align the floating outline with the left margin of the chapter
|
|
43
|
+
// and the top of the title, unless we're past it.
|
|
44
|
+
let title = document.getElementsByClassName("bookish-chapter-header-text")[0];
|
|
45
|
+
// If we found them both...
|
|
46
|
+
if (outline && title) {
|
|
47
|
+
// If so, remove the inline position so the footer CSS applies.
|
|
48
|
+
if (isMobile()) {
|
|
49
|
+
outline.style.removeProperty("margin-top");
|
|
50
|
+
} else {
|
|
51
|
+
let titleY = title.getBoundingClientRect().top + window.scrollY;
|
|
52
|
+
// If the title is off screen, anchor it to the top of the window. (CSS is set to do this).
|
|
53
|
+
if (titleY - 50 < window.scrollY) {
|
|
54
|
+
outline.classList.add("outline-fixed-left");
|
|
55
|
+
outline.classList.remove("outline-title-left");
|
|
56
|
+
} else {
|
|
57
|
+
outline.classList.remove("outline-fixed-left");
|
|
58
|
+
outline.classList.add("outline-title-left");
|
|
59
|
+
}
|
|
60
|
+
// Tell any listeners about the repositioning.
|
|
61
|
+
if (listener) listener(false, layout);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
63
64
|
}
|
|
64
65
|
function highlight() {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
66
|
+
const top = window.scrollY;
|
|
67
|
+
const threshold = getHighlightThreshold();
|
|
68
|
+
// Find the header that we're past so we can update the outline.
|
|
69
|
+
let indexOfNearestHeaderAbove = -1;
|
|
70
|
+
Array.from(document.getElementsByClassName("page-header")).forEach((header, index) => {
|
|
71
|
+
// Is this a header we care about?
|
|
72
|
+
if (header.tagName === "H1" || header.tagName === "H2" || header.tagName === "H3") {
|
|
73
|
+
let rect = header.getBoundingClientRect();
|
|
74
|
+
let headerTop = rect.y + top - rect.height;
|
|
75
|
+
// Are we past this header?
|
|
76
|
+
if (top > headerTop - threshold) indexOfNearestHeaderAbove = index;
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
// Update the outline and progress bar.
|
|
80
|
+
headerIndex = indexOfNearestHeaderAbove;
|
|
79
81
|
}
|
|
80
82
|
onMount(() => {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
83
|
+
window.addEventListener("resize", layout);
|
|
84
|
+
window.addEventListener("scroll", layout);
|
|
85
|
+
// This is a bit hacky: we update the headers on every selection change so we
|
|
86
|
+
// can detect any header changes during editing. This isn't necessary during
|
|
87
|
+
// reading, and is only necessary when a header is created, updated, or removed,
|
|
88
|
+
// but we don't have a precise mechanism to listen to chapter changes, so we do this instead.
|
|
89
|
+
document.addEventListener("selectionchange", updateHeaders);
|
|
90
|
+
// Position outline after first render.
|
|
91
|
+
layout();
|
|
92
|
+
// Stop listening!
|
|
93
|
+
return () => {
|
|
94
|
+
window.removeEventListener("scroll", layout);
|
|
95
|
+
window.removeEventListener("resize", layout);
|
|
96
|
+
document.removeEventListener("selectionchange", updateHeaders);
|
|
97
|
+
};
|
|
90
98
|
});
|
|
91
|
-
let previousLabel = "
|
|
92
|
-
let nextLabel = "
|
|
93
|
-
let expandLabel = "
|
|
99
|
+
let previousLabel = "◀︎";
|
|
100
|
+
let nextLabel = "▶︎";
|
|
101
|
+
let expandLabel = "☰";
|
|
94
102
|
</script>
|
|
95
103
|
|
|
96
104
|
<nav
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts">import { onMount } from "svelte";
|
|
2
2
|
import Loading from "./Loading.svelte";
|
|
3
|
-
let { title =
|
|
3
|
+
let { title = undefined, afterLoaded = undefined, children } = $props();
|
|
4
4
|
let fontsLoaded = $state(false);
|
|
5
5
|
let imagesLoaded = $state(false);
|
|
6
6
|
let lastHeight = 0;
|
|
@@ -8,28 +8,34 @@ let intervalID = null;
|
|
|
8
8
|
let mountTime = Date.now();
|
|
9
9
|
let loaded = $derived(fontsLoaded && imagesLoaded);
|
|
10
10
|
function watchLoading() {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
11
|
+
const bodyHeight = document.body.clientHeight;
|
|
12
|
+
// If the height hasn't changed and images are loaded OR it's been 2 seconds, load.
|
|
13
|
+
if (lastHeight === bodyHeight && imagesAreLoaded() || Date.now() - mountTime > 2e3) {
|
|
14
|
+
// Stop watching the images
|
|
15
|
+
stopWatching();
|
|
16
|
+
// Set to loaded to hide the overlay and notify callback if there is one.
|
|
17
|
+
imagesLoaded = true;
|
|
18
|
+
if (afterLoaded) afterLoaded();
|
|
19
|
+
}
|
|
20
|
+
// Remember the last height
|
|
21
|
+
lastHeight = bodyHeight;
|
|
18
22
|
}
|
|
19
23
|
function stopWatching() {
|
|
20
|
-
|
|
24
|
+
if (intervalID) clearInterval(intervalID);
|
|
21
25
|
}
|
|
22
26
|
onMount(() => {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
// Watch the height of the document and wait until it's been stable for a while before scrolling
|
|
28
|
+
// to any targets. We use the data below to monitor the document height over time.
|
|
29
|
+
intervalID = setInterval(() => watchLoading(), 50);
|
|
30
|
+
document.fonts.ready.then(() => fontsLoaded = true);
|
|
31
|
+
return () => stopWatching();
|
|
26
32
|
});
|
|
27
33
|
function imagesAreLoaded() {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
let done = true;
|
|
35
|
+
Array.from(document.getElementsByTagName("img")).forEach((el) => {
|
|
36
|
+
done = done && el.complete;
|
|
37
|
+
});
|
|
38
|
+
return done;
|
|
33
39
|
}
|
|
34
40
|
</script>
|
|
35
41
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<script lang="ts">import Chapter from "./Chapter.svelte";
|
|
2
2
|
import { page } from "$app/state";
|
|
3
|
-
import { getEdition } from "./Contexts";
|
|
3
|
+
import { getEdition } from "./Contexts.js";
|
|
4
4
|
import Unknown from "./Unknown.svelte";
|
|
5
5
|
let edition = $derived(getEdition());
|
|
6
6
|
let chapterID = $derived(page.params.chapterid);
|
|
7
|
-
let chapter = $derived(chapterID ===
|
|
7
|
+
let chapter = $derived(chapterID === undefined ? undefined : $edition?.getChapter(chapterID));
|
|
8
8
|
</script>
|
|
9
9
|
|
|
10
10
|
{#if chapter}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<script lang="ts">import FormatNode from "../../models/chapter/FormatNode";
|
|
1
|
+
<script lang="ts">import FormatNode from "../../models/chapter/FormatNode.js";
|
|
2
2
|
import Format from "../chapter/Format.svelte";
|
|
3
3
|
import Reference from "./Reference.svelte";
|
|
4
4
|
let { node, edit } = $props();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import FormatNode from '../../models/chapter/FormatNode';
|
|
2
|
-
import type Ref from '../../models/book/Reference';
|
|
1
|
+
import FormatNode from '../../models/chapter/FormatNode.js';
|
|
2
|
+
import type Ref from '../../models/book/Reference.js';
|
|
3
3
|
interface Props {
|
|
4
4
|
node: FormatNode | Ref;
|
|
5
5
|
edit: boolean;
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
<script lang="ts">import Chapter from "./Chapter.svelte";
|
|
2
2
|
import { getEdition } from "./Contexts";
|
|
3
|
-
import Parser from "../../models/chapter/Parser";
|
|
3
|
+
import Parser from "../../models/chapter/Parser.js";
|
|
4
4
|
let edition = getEdition();
|
|
5
5
|
let title = $derived($edition ? [
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
$edition.getAuthors().at(0) ?? ""
|
|
11
|
-
).toText() + ($edition.getAuthors().length > 1 ? " et al." : "")
|
|
12
|
-
].filter(Boolean).join(" - ") : void 0);
|
|
6
|
+
$edition.getTitle(),
|
|
7
|
+
`${$edition.getEditionLabel()} Edition`,
|
|
8
|
+
Parser.parseFormat($edition, $edition.getAuthors().at(0) ?? "").toText() + ($edition.getAuthors().length > 1 ? " et al." : "")
|
|
9
|
+
].filter(Boolean).join(" - ") : undefined);
|
|
13
10
|
</script>
|
|
14
11
|
|
|
15
12
|
<svelte:head>
|
|
@@ -1,58 +1,52 @@
|
|
|
1
1
|
<script lang="ts">import Parser from "../../models/chapter/Parser";
|
|
2
2
|
import BookishEditor from "../editor/BookishEditor.svelte";
|
|
3
3
|
import Switch from "../editor/Switch.svelte";
|
|
4
|
-
import {
|
|
5
|
-
getUser,
|
|
6
|
-
getEdition,
|
|
7
|
-
getLeasee,
|
|
8
|
-
isEditionEditable,
|
|
9
|
-
lease
|
|
10
|
-
} from "./Contexts";
|
|
4
|
+
import { getUser, getEdition, getLeasee, isEditionEditable, lease } from "./Contexts";
|
|
11
5
|
import Format from "../chapter/Format.svelte";
|
|
12
6
|
import Note from "../editor/Note.svelte";
|
|
13
7
|
import Instructions from "./Instructions.svelte";
|
|
14
8
|
import Link from "../Link.svelte";
|
|
15
9
|
import { PUBLIC_CONTEXT } from "$env/static/public";
|
|
16
10
|
import Button from "../app/Button.svelte";
|
|
17
|
-
import { publish } from "../../models/CRUD";
|
|
18
11
|
import Feedback from "../app/Feedback.svelte";
|
|
19
12
|
let auth = getUser();
|
|
20
13
|
let edition = getEdition();
|
|
21
14
|
let editable = isEditionEditable();
|
|
22
15
|
let publishing = false;
|
|
23
|
-
let feedback = $state(
|
|
24
|
-
let error = $state(
|
|
25
|
-
let url = $state(
|
|
16
|
+
let feedback = $state(undefined);
|
|
17
|
+
let error = $state(undefined);
|
|
18
|
+
let url = $state(undefined);
|
|
26
19
|
async function requestPublish() {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
20
|
+
if ($edition) {
|
|
21
|
+
publishing = true;
|
|
22
|
+
error = undefined;
|
|
23
|
+
feedback = "Binding the book, this could take a minute...";
|
|
24
|
+
try {
|
|
25
|
+
const { publish } = await import("../../models/CRUD");
|
|
26
|
+
const result = await publish($edition);
|
|
27
|
+
if (typeof result === "string") {
|
|
28
|
+
error = result;
|
|
29
|
+
feedback = undefined;
|
|
30
|
+
} else {
|
|
31
|
+
url = result.url;
|
|
32
|
+
}
|
|
33
|
+
} catch (err) {
|
|
34
|
+
console.log(err);
|
|
35
|
+
feedback = undefined;
|
|
36
|
+
error = "Unable to bundle the book for download :(";
|
|
37
|
+
} finally {
|
|
38
|
+
publishing = false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
47
41
|
}
|
|
48
|
-
let publisher = $state(
|
|
42
|
+
let publisher = $state(undefined);
|
|
49
43
|
async function updateUserClaims() {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
44
|
+
if ($auth === undefined || $auth.user === null) return;
|
|
45
|
+
const token = await $auth.user.getIdTokenResult();
|
|
46
|
+
publisher = "publisher" in token.claims && token.claims.publisher === true;
|
|
53
47
|
}
|
|
54
48
|
$effect(() => {
|
|
55
|
-
|
|
49
|
+
if ($auth && $auth.user) updateUserClaims();
|
|
56
50
|
});
|
|
57
51
|
</script>
|
|
58
52
|
|
|
@@ -70,7 +64,7 @@ $effect(() => {
|
|
|
70
64
|
save={(newSummary) =>
|
|
71
65
|
$edition
|
|
72
66
|
? edition.set(
|
|
73
|
-
$edition.withSummary(newSummary.toBookdown())
|
|
67
|
+
$edition.withSummary(newSummary.toBookdown()),
|
|
74
68
|
)
|
|
75
69
|
: undefined}
|
|
76
70
|
chapter={false}
|
|
@@ -87,7 +81,7 @@ $effect(() => {
|
|
|
87
81
|
edit={(published) =>
|
|
88
82
|
$edition
|
|
89
83
|
? edition.set(
|
|
90
|
-
$edition.asPublished(published === 'published')
|
|
84
|
+
$edition.asPublished(published === 'published'),
|
|
91
85
|
)
|
|
92
86
|
: undefined}
|
|
93
87
|
/>
|
|
@@ -108,7 +102,7 @@ $effect(() => {
|
|
|
108
102
|
<div>
|
|
109
103
|
<Note
|
|
110
104
|
>{#if $edition.published}Last published {new Date(
|
|
111
|
-
$edition.published
|
|
105
|
+
$edition.published,
|
|
112
106
|
).toLocaleDateString('en-us')}{/if}</Note
|
|
113
107
|
>
|
|
114
108
|
</div>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<script lang="ts">import Reference from "../../models/book/Reference";
|
|
1
|
+
<script lang="ts">import Reference from "../../models/book/Reference.js";
|
|
2
2
|
import Button from "../app/Button.svelte";
|
|
3
3
|
import Table from "../app/Table.svelte";
|
|
4
4
|
import ConfirmButton from "../editor/ConfirmButton.svelte";
|
|
@@ -11,20 +11,18 @@ let editable = isEditionEditable();
|
|
|
11
11
|
let edition = getEdition();
|
|
12
12
|
let editing = $state(false);
|
|
13
13
|
function startEditing() {
|
|
14
|
-
|
|
14
|
+
editing = true;
|
|
15
15
|
}
|
|
16
16
|
function stopEditing() {
|
|
17
|
-
|
|
17
|
+
editing = false;
|
|
18
18
|
}
|
|
19
19
|
function move(field, direction) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (newInput) newInput.focus();
|
|
27
|
-
}
|
|
20
|
+
let fields = Array.from(document.querySelectorAll("input[type=\"text\"]"));
|
|
21
|
+
let index = fields.indexOf(field);
|
|
22
|
+
if (index >= 0) {
|
|
23
|
+
const newInput = direction < 0 && index > 0 ? fields[index - 1] : direction > 0 && index < fields.length - 1 ? fields[index + 1] : undefined;
|
|
24
|
+
if (newInput) newInput.focus();
|
|
25
|
+
}
|
|
28
26
|
}
|
|
29
27
|
</script>
|
|
30
28
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">import Header from "./Header.svelte";
|
|
2
2
|
import Outline from "./Outline.svelte";
|
|
3
3
|
import Page from "./Page.svelte";
|
|
4
|
-
import ChapterIDs from "../../models/book/ChapterID";
|
|
4
|
+
import ChapterIDs from "../../models/book/ChapterID.js";
|
|
5
5
|
import BulkReferenceEditor from "./BulkReferenceEditor.svelte";
|
|
6
6
|
import PossibleReference from "./PossibleReference.svelte";
|
|
7
7
|
import { getUser, getEdition, isEditionEditable } from "./Contexts";
|