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
|
@@ -4,38 +4,54 @@ import { writable } from "svelte/store";
|
|
|
4
4
|
import { auth } from "../models/Firebase";
|
|
5
5
|
import { USER } from "./page/Contexts";
|
|
6
6
|
let { children } = $props();
|
|
7
|
+
// Track the user and user loading status in state
|
|
7
8
|
let loading = $state(true);
|
|
9
|
+
// The store that tracks the auth context.
|
|
8
10
|
const authentication = writable({
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
user: null,
|
|
12
|
+
loading: true,
|
|
13
|
+
login,
|
|
14
|
+
logout
|
|
13
15
|
});
|
|
16
|
+
// Login using Firebase's password-less email verification
|
|
14
17
|
async function login(email) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
// If connected to firebase...
|
|
19
|
+
if (auth) {
|
|
20
|
+
const actionCodeSettings = {
|
|
21
|
+
url: location.origin + "/confirm",
|
|
22
|
+
handleCodeInApp: true
|
|
23
|
+
};
|
|
24
|
+
// Ask Firebase to log in with the given email
|
|
25
|
+
await sendSignInLinkToEmail(auth, email, actionCodeSettings);
|
|
26
|
+
// Remember the email in local storage so we don't have to ask for it again
|
|
27
|
+
// after returning to the link above.
|
|
28
|
+
window.localStorage.setItem("email", email);
|
|
29
|
+
}
|
|
23
30
|
}
|
|
24
31
|
function updateAuth(user) {
|
|
25
|
-
|
|
32
|
+
authentication.set({
|
|
33
|
+
user,
|
|
34
|
+
loading,
|
|
35
|
+
login,
|
|
36
|
+
logout
|
|
37
|
+
});
|
|
26
38
|
}
|
|
39
|
+
// Logout using Firebase's authentication framework.
|
|
27
40
|
function logout() {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
41
|
+
if (auth) {
|
|
42
|
+
return auth.signOut().then(() => updateAuth(null));
|
|
43
|
+
}
|
|
31
44
|
}
|
|
45
|
+
// On mount, subscribe to authentication changes.
|
|
32
46
|
if (auth) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
47
|
+
const unsubscribe = auth.onAuthStateChanged((user) => {
|
|
48
|
+
loading = false;
|
|
49
|
+
updateAuth(user);
|
|
50
|
+
});
|
|
51
|
+
// On unmount, stop subscribing.
|
|
52
|
+
onDestroy(unsubscribe);
|
|
38
53
|
}
|
|
54
|
+
// Expose the state and the login/logout functionality.
|
|
39
55
|
setContext(USER, authentication);
|
|
40
56
|
</script>
|
|
41
57
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
<script lang="ts">import EmbedNode from "../models/chapter/EmbedNode";
|
|
2
|
-
import Parser from "../models/chapter/Parser";
|
|
1
|
+
<script lang="ts">import EmbedNode from "../models/chapter/EmbedNode.js";
|
|
2
|
+
import Parser from "../models/chapter/Parser.js";
|
|
3
3
|
import ChapterBody from "./chapter/ChapterBody.svelte";
|
|
4
4
|
import Embed from "./chapter/Embed.svelte";
|
|
5
5
|
import Link from "./app/Link.svelte";
|
|
@@ -10,8 +10,8 @@ let authors = $derived(book.getAuthors());
|
|
|
10
10
|
let description = $derived(book.getDescription());
|
|
11
11
|
let subdomain = $derived(book.getSubdomain());
|
|
12
12
|
let title = $derived(book.getTitle());
|
|
13
|
-
let embed = $derived(cover === null ? null : Parser.parseEmbed(
|
|
14
|
-
let url = $derived(subdomain === null || write ? refID ===
|
|
13
|
+
let embed = $derived(cover === null ? null : Parser.parseEmbed(undefined, cover));
|
|
14
|
+
let url = $derived(subdomain === null || write ? refID === undefined ? "" : (write ? "/write/" : "/") + refID : `/${subdomain}`);
|
|
15
15
|
</script>
|
|
16
16
|
|
|
17
17
|
<article class="book-preview">
|
|
@@ -2,18 +2,25 @@
|
|
|
2
2
|
let { to, linked = true, children } = $props();
|
|
3
3
|
let link = $state();
|
|
4
4
|
function scroll(event) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
5
|
+
// No element? Bail.
|
|
6
|
+
if (link === undefined) return;
|
|
7
|
+
// No hash? No scroll.
|
|
8
|
+
const hash = new URL(link.href).hash;
|
|
9
|
+
if (hash === "") return;
|
|
10
|
+
// Prevent the browser from scrolling.
|
|
11
|
+
event.preventDefault();
|
|
12
|
+
// Get the anchor
|
|
13
|
+
const anchorId = new URL(link.href).hash.replace("#", "");
|
|
14
|
+
const anchor = document.getElementById(anchorId);
|
|
15
|
+
// No anchor? Bail.
|
|
16
|
+
if (anchor === null) return;
|
|
17
|
+
// Scroll to the anchor.
|
|
18
|
+
window.scrollTo({
|
|
19
|
+
top: anchor.offsetTop,
|
|
20
|
+
behavior: "smooth"
|
|
21
|
+
});
|
|
22
|
+
// Update the hash (without scrolling)
|
|
23
|
+
history.pushState({}, "", hash);
|
|
17
24
|
}
|
|
18
25
|
</script>
|
|
19
26
|
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
<script lang="ts">let {
|
|
2
|
-
type = null,
|
|
3
|
-
tooltip,
|
|
4
|
-
disabled = false,
|
|
5
|
-
command,
|
|
6
|
-
class: classes,
|
|
7
|
-
children
|
|
8
|
-
} = $props();
|
|
1
|
+
<script lang="ts">let { type = null, tooltip, disabled = false, command, class: classes, children } = $props();
|
|
9
2
|
</script>
|
|
10
3
|
|
|
11
4
|
<button
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
<script lang="ts">import { page } from "$app/state";
|
|
2
|
-
let {
|
|
3
|
-
to,
|
|
4
|
-
before = void 0,
|
|
5
|
-
title = void 0,
|
|
6
|
-
external = false,
|
|
7
|
-
children
|
|
8
|
-
} = $props();
|
|
2
|
+
let { to, before = undefined, title = undefined, external = false, children } = $props();
|
|
9
3
|
let at = $derived(to === page.url.pathname);
|
|
10
4
|
</script>
|
|
11
5
|
|
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
<script lang="ts">let {
|
|
2
|
-
options,
|
|
3
|
-
changed,
|
|
4
|
-
value = $bindable(),
|
|
5
|
-
label
|
|
6
|
-
} = $props();
|
|
1
|
+
<script lang="ts">let { options, changed, value = $bindable(), label } = $props();
|
|
7
2
|
</script>
|
|
8
3
|
|
|
9
4
|
<select bind:value onchange={() => changed(value)} aria-label={label}>
|
|
@@ -1,13 +1,7 @@
|
|
|
1
|
-
<script lang="ts">let {
|
|
2
|
-
text = $bindable(""),
|
|
3
|
-
autocomplete = null,
|
|
4
|
-
type,
|
|
5
|
-
placeholder,
|
|
6
|
-
disabled
|
|
7
|
-
} = $props();
|
|
1
|
+
<script lang="ts">let { text = $bindable(""), autocomplete = null, type, placeholder, disabled } = $props();
|
|
8
2
|
let input = $state();
|
|
9
3
|
export function value() {
|
|
10
|
-
|
|
4
|
+
return text;
|
|
11
5
|
}
|
|
12
6
|
</script>
|
|
13
7
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
<script lang="ts">import { getCaret } from "../page/Contexts";
|
|
1
|
+
<script lang="ts">import { getCaret } from "../page/Contexts.js";
|
|
2
2
|
let { node, children } = $props();
|
|
3
3
|
let caret = getCaret();
|
|
4
|
+
// Is the caret on this link?
|
|
4
5
|
let selected = $derived($caret && $caret.range && $caret.range.start.node === node);
|
|
5
6
|
</script>
|
|
6
7
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
<script lang="ts">import CalloutNode from "../../models/chapter/CalloutNode";
|
|
2
|
-
import CodeNode from "../../models/chapter/CodeNode";
|
|
3
|
-
import EmbedNode from "../../models/chapter/EmbedNode";
|
|
4
|
-
import ErrorNode from "../../models/chapter/ErrorNode";
|
|
5
|
-
import ListNode from "../../models/chapter/ListNode";
|
|
6
|
-
import ParagraphNode from "../../models/chapter/ParagraphNode";
|
|
7
|
-
import QuoteNode from "../../models/chapter/QuoteNode";
|
|
8
|
-
import RuleNode from "../../models/chapter/RuleNode";
|
|
9
|
-
import TableNode from "../../models/chapter/TableNode";
|
|
1
|
+
<script lang="ts">import CalloutNode from "../../models/chapter/CalloutNode.js";
|
|
2
|
+
import CodeNode from "../../models/chapter/CodeNode.js";
|
|
3
|
+
import EmbedNode from "../../models/chapter/EmbedNode.js";
|
|
4
|
+
import ErrorNode from "../../models/chapter/ErrorNode.js";
|
|
5
|
+
import ListNode from "../../models/chapter/ListNode.js";
|
|
6
|
+
import ParagraphNode from "../../models/chapter/ParagraphNode.js";
|
|
7
|
+
import QuoteNode from "../../models/chapter/QuoteNode.js";
|
|
8
|
+
import RuleNode from "../../models/chapter/RuleNode.js";
|
|
9
|
+
import TableNode from "../../models/chapter/TableNode.js";
|
|
10
10
|
import Callout from "./Callout.svelte";
|
|
11
11
|
import CaptionedCode from "./CaptionedCode.svelte";
|
|
12
12
|
import Embed from "./Embed.svelte";
|
|
@@ -7,6 +7,7 @@ import Button from "../app/Button.svelte";
|
|
|
7
7
|
let { node } = $props();
|
|
8
8
|
let language = $derived(node.getLanguage());
|
|
9
9
|
let editable = isChapterEditable();
|
|
10
|
+
// const languages = [ "C", "C++", "CSS", "Go", "HTML", "Java", "JavaScript", "Markdown", "Plaintext", "Python", "TypeScript" ];
|
|
10
11
|
let editing = $state(true);
|
|
11
12
|
</script>
|
|
12
13
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<script lang="ts">import ParagraphNode from "../../models/chapter/ParagraphNode";
|
|
1
|
+
<script lang="ts">import ParagraphNode from "../../models/chapter/ParagraphNode.js";
|
|
2
2
|
import { writable } from "svelte/store";
|
|
3
3
|
import { setContext, untrack } from "svelte";
|
|
4
4
|
import { ROOT } from "../page/Contexts";
|
|
@@ -8,10 +8,13 @@ import Problem from "./Problem.svelte";
|
|
|
8
8
|
let { node, placeholder = "", editable = false } = $props();
|
|
9
9
|
let errors = $derived(node.getErrors());
|
|
10
10
|
let blocks = $derived(node.getBlocks());
|
|
11
|
+
// Make this chapter node available to all children in a reactive store.
|
|
12
|
+
// The store is deliberately seeded with the initial node (untracked);
|
|
13
|
+
// the effect below keeps it in sync when the prop changes.
|
|
11
14
|
let root = writable(untrack(() => node));
|
|
12
15
|
setContext(ROOT, root);
|
|
13
16
|
$effect.pre(() => {
|
|
14
|
-
|
|
17
|
+
root.set(node);
|
|
15
18
|
});
|
|
16
19
|
</script>
|
|
17
20
|
|
|
@@ -2,10 +2,10 @@ import { beforeAll, expect, test, vi } from 'vitest';
|
|
|
2
2
|
import { render } from '@testing-library/svelte';
|
|
3
3
|
import { tick } from 'svelte';
|
|
4
4
|
import { writable } from 'svelte/store';
|
|
5
|
-
import Parser from '../../models/chapter/Parser';
|
|
6
|
-
import Chapter from '../../models/book/Chapter';
|
|
5
|
+
import Parser from '../../models/chapter/Parser.js';
|
|
6
|
+
import Chapter from '../../models/book/Chapter.js';
|
|
7
7
|
import ChapterBody from './ChapterBody.svelte';
|
|
8
|
-
import { CARET, CHAPTER, EDITION } from '../page/Contexts';
|
|
8
|
+
import { CARET, CHAPTER, EDITION } from '../page/Contexts.js';
|
|
9
9
|
// The page state only exists inside a running SvelteKit app; Contexts.ts
|
|
10
10
|
// reads it to decide whether a route is editable.
|
|
11
11
|
vi.mock('$app/state', () => ({
|
|
@@ -7,23 +7,24 @@ let { node } = $props();
|
|
|
7
7
|
let chapter = getChapter();
|
|
8
8
|
let edition = getEdition();
|
|
9
9
|
let root = getRoot();
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
10
|
+
// Sort citations numerically, however they're numbered.
|
|
11
|
+
let citations = $derived(node.getMeta().sort((a, b) => {
|
|
12
|
+
if ($root === undefined) return 0;
|
|
13
|
+
let aNumber = $root.getCitationNumber(a);
|
|
14
|
+
let bNumber = $root.getCitationNumber(b);
|
|
15
|
+
if (aNumber === null) {
|
|
16
|
+
if (bNumber === null) return 0;
|
|
17
|
+
else return 1;
|
|
18
|
+
} else {
|
|
19
|
+
if (bNumber === null) return -1;
|
|
20
|
+
else return aNumber - bNumber;
|
|
21
|
+
}
|
|
22
|
+
}));
|
|
23
|
+
// Whenever anything that affects these citations' rendered size or
|
|
24
|
+
// position changes, request a chapter-wide marginal layout pass.
|
|
24
25
|
$effect(() => {
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
void citations;
|
|
27
|
+
$chapter?.requestLayout();
|
|
27
28
|
});
|
|
28
29
|
</script>
|
|
29
30
|
|
|
@@ -1,22 +1,16 @@
|
|
|
1
1
|
<script lang="ts">import Prism from "./ExtendedPrism";
|
|
2
|
-
let {
|
|
3
|
-
editable,
|
|
4
|
-
inline,
|
|
5
|
-
nodeID,
|
|
6
|
-
edited = void 0,
|
|
7
|
-
language = void 0,
|
|
8
|
-
code
|
|
9
|
-
} = $props();
|
|
2
|
+
let { editable, inline, nodeID, edited = undefined, language = undefined, code } = $props();
|
|
10
3
|
let element = $state(null);
|
|
4
|
+
// Whenever the code or language changes, re-highlight the element.
|
|
11
5
|
$effect(() => {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
6
|
+
void code;
|
|
7
|
+
void language;
|
|
8
|
+
if (element) {
|
|
9
|
+
Prism.highlightElement(element);
|
|
10
|
+
}
|
|
17
11
|
});
|
|
18
12
|
function handleChange() {
|
|
19
|
-
|
|
13
|
+
if (element && edited) edited(element.innerText);
|
|
20
14
|
}
|
|
21
15
|
</script>
|
|
22
16
|
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
<script lang="ts">import Atom from "./Atom.svelte";
|
|
2
2
|
import Marginal from "./Marginal.svelte";
|
|
3
3
|
import Format from "./Format.svelte";
|
|
4
|
-
import {
|
|
5
|
-
getChapter,
|
|
6
|
-
isChapterEditable,
|
|
7
|
-
getCaret,
|
|
8
|
-
getRoot
|
|
9
|
-
} from "../page/Contexts";
|
|
4
|
+
import { getChapter, isChapterEditable, getCaret, getRoot } from "../page/Contexts.js";
|
|
10
5
|
import Icon from "../editor/Icon.svelte";
|
|
11
6
|
import CommentIcon from "../editor/icons/comment.svg?raw";
|
|
12
7
|
let { node } = $props();
|
|
@@ -14,13 +9,13 @@ let chapter = getChapter();
|
|
|
14
9
|
let editable = isChapterEditable();
|
|
15
10
|
let root = getRoot();
|
|
16
11
|
let caret = getCaret();
|
|
17
|
-
let focused = $derived(
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
let focused = $derived($caret && $caret.range && node.contains($caret.range.start.node));
|
|
13
|
+
// Whenever anything that affects this comment's rendered size or
|
|
14
|
+
// position changes, request a chapter-wide marginal layout pass.
|
|
20
15
|
$effect(() => {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
void node;
|
|
17
|
+
void focused;
|
|
18
|
+
$chapter?.requestLayout();
|
|
24
19
|
});
|
|
25
20
|
</script>
|
|
26
21
|
|
|
@@ -1,25 +1,24 @@
|
|
|
1
|
-
<script lang="ts">import Parser from "../../models/chapter/Parser";
|
|
1
|
+
<script lang="ts">import Parser from "../../models/chapter/Parser.js";
|
|
2
2
|
import Text from "./Text.svelte";
|
|
3
3
|
import Format from "./Format.svelte";
|
|
4
4
|
import Marginal from "./Marginal.svelte";
|
|
5
5
|
import Problem from "./Problem.svelte";
|
|
6
|
-
import {
|
|
7
|
-
getChapter,
|
|
8
|
-
getEdition,
|
|
9
|
-
isChapterEditable
|
|
10
|
-
} from "../page/Contexts";
|
|
6
|
+
import { getChapter, getEdition, isChapterEditable } from "../page/Contexts";
|
|
11
7
|
let { node } = $props();
|
|
12
8
|
let editable = isChapterEditable();
|
|
13
9
|
let edition = getEdition();
|
|
14
10
|
let chapter = getChapter();
|
|
11
|
+
// Find the definition.
|
|
15
12
|
let glossaryID = $derived(node.getMeta());
|
|
16
13
|
let phrase = $derived(node.getText());
|
|
17
14
|
let glossary = $derived($edition?.getGlossary() ?? {});
|
|
18
15
|
let entry = $derived(glossary[glossaryID]);
|
|
16
|
+
// Whenever anything that affects this definition's rendered size or
|
|
17
|
+
// position changes, request a chapter-wide marginal layout pass.
|
|
19
18
|
$effect(() => {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
void phrase;
|
|
20
|
+
void entry;
|
|
21
|
+
$chapter?.requestLayout();
|
|
23
22
|
});
|
|
24
23
|
</script>
|
|
25
24
|
|
|
@@ -1,87 +1,67 @@
|
|
|
1
|
-
<script lang="ts">import {
|
|
2
|
-
import {
|
|
3
|
-
getCaret,
|
|
4
|
-
getBook,
|
|
5
|
-
getBase,
|
|
6
|
-
isEditionEditable
|
|
7
|
-
} from "../page/Contexts";
|
|
1
|
+
<script lang="ts">import { getCaret, getBook, getBase, isEditionEditable } from "../page/Contexts.js";
|
|
8
2
|
import Figure from "./Figure.svelte";
|
|
9
3
|
import { getContext } from "svelte";
|
|
10
|
-
let {
|
|
11
|
-
node,
|
|
12
|
-
editable = true,
|
|
13
|
-
placeholder = "",
|
|
14
|
-
imageOnly = false
|
|
15
|
-
} = $props();
|
|
4
|
+
let { node, editable = true, placeholder = "", imageOnly = false } = $props();
|
|
16
5
|
let url = $derived(node.getURL());
|
|
17
6
|
let description = $derived(node.getDescription());
|
|
18
7
|
let caret = getCaret();
|
|
19
8
|
let book = getBook();
|
|
20
9
|
let base = getBase();
|
|
21
10
|
let editionEditable = isEditionEditable();
|
|
11
|
+
// Bookish editor should have passed down a way to set the active editor.
|
|
22
12
|
let claimCaret = getContext("claimeditor");
|
|
23
13
|
let dragging = $state(false);
|
|
24
|
-
let dragFeedback = $state(
|
|
14
|
+
let dragFeedback = $state(undefined);
|
|
25
15
|
let imageError = $state(false);
|
|
26
16
|
$effect.pre(() => {
|
|
27
|
-
|
|
17
|
+
if (node) imageError = false;
|
|
28
18
|
});
|
|
29
19
|
function handleDrop(event) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
(url2, thumbnails) => {
|
|
54
|
-
$caret?.edit(
|
|
55
|
-
node,
|
|
56
|
-
node.withURLs(url2, thumbnails).withDescription("")
|
|
57
|
-
);
|
|
58
|
-
dragging = false;
|
|
59
|
-
dragFeedback = void 0;
|
|
60
|
-
}
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
20
|
+
event.preventDefault();
|
|
21
|
+
if (event.dataTransfer?.items) {
|
|
22
|
+
// Get the files and convert them to file opens, then filter by allowed file extensions
|
|
23
|
+
const imageFiles = [...event.dataTransfer.items].filter((item) => item.kind === "file").map((item) => item.getAsFile()).filter((file) => file !== null && /.*\.(jpg|jpeg|png)/i.test(file.name));
|
|
24
|
+
if (imageFiles.length === 0) dragFeedback = "Only JPEG or PNG images are allowed.";
|
|
25
|
+
else if (imageFiles.length > 1) dragFeedback = "Only one image at a time please!";
|
|
26
|
+
else {
|
|
27
|
+
dragFeedback = "Uploading…";
|
|
28
|
+
const file = imageFiles[0];
|
|
29
|
+
const media = $book?.getMedia();
|
|
30
|
+
if (file === null) return;
|
|
31
|
+
if (media === undefined) return;
|
|
32
|
+
media.upload(file, (progress) => dragFeedback = `${progress}% done`, (error) => {
|
|
33
|
+
dragFeedback = error;
|
|
34
|
+
dragging = false;
|
|
35
|
+
}, (url, thumbnails) => {
|
|
36
|
+
// Upload completed successfully, now we can get the download URL
|
|
37
|
+
$caret?.edit(node, node.withURLs(url, thumbnails).withDescription(""));
|
|
38
|
+
dragging = false;
|
|
39
|
+
dragFeedback = undefined;
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
64
43
|
}
|
|
65
44
|
function handleDrag(event) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
45
|
+
event?.preventDefault();
|
|
46
|
+
dragging = true;
|
|
47
|
+
dragFeedback = "Drop to upload…";
|
|
48
|
+
// If we have a way to claim the caret, claim it, since we want to be able to make an edit with the active caret.
|
|
49
|
+
if (claimCaret) claimCaret();
|
|
70
50
|
}
|
|
71
51
|
function handleDragLeave(event) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
52
|
+
if (event.target !== event.currentTarget) return;
|
|
53
|
+
event?.preventDefault();
|
|
54
|
+
dragging = false;
|
|
55
|
+
dragFeedback = undefined;
|
|
76
56
|
}
|
|
77
57
|
function handleLoad() {
|
|
78
|
-
|
|
58
|
+
imageError = false;
|
|
79
59
|
}
|
|
80
60
|
function handleError() {
|
|
81
|
-
|
|
61
|
+
imageError = true;
|
|
82
62
|
}
|
|
83
63
|
function handleClick() {
|
|
84
|
-
|
|
64
|
+
if (claimCaret) claimCaret();
|
|
85
65
|
}
|
|
86
66
|
</script>
|
|
87
67
|
|
|
@@ -134,7 +114,7 @@ function handleClick() {
|
|
|
134
114
|
frameBorder="0"
|
|
135
115
|
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
|
|
136
116
|
allowFullScreen
|
|
137
|
-
></iframe>
|
|
117
|
+
></iframe>
|
|
138
118
|
</article>
|
|
139
119
|
{:else}
|
|
140
120
|
<img
|