bookish-press 0.4.23 → 0.4.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/components/Auth.svelte +11 -13
  2. package/components/BookPreview.svelte +12 -14
  3. package/components/app/Feedback.svelte +12 -10
  4. package/components/app/Head.svelte +4 -1
  5. package/components/app/Head.svelte.d.ts +6 -15
  6. package/components/app/Paragraph.svelte +1 -0
  7. package/components/app/{Writing.svelte → Section.svelte} +0 -1
  8. package/components/app/Section.svelte.d.ts +27 -0
  9. package/components/app/TextInput.svelte +1 -0
  10. package/components/chapter/Block.svelte +3 -1
  11. package/components/chapter/CaptionedCode.svelte +2 -2
  12. package/components/chapter/ChapterBody.svelte +2 -1
  13. package/components/chapter/ChapterBody.svelte.d.ts +1 -0
  14. package/components/chapter/Comment.svelte +2 -2
  15. package/components/chapter/Embed.svelte +3 -3
  16. package/components/chapter/Embed.svelte.d.ts +1 -0
  17. package/components/chapter/Figure.svelte +2 -2
  18. package/components/chapter/Format.svelte +5 -3
  19. package/components/chapter/Format.svelte.d.ts +1 -0
  20. package/components/chapter/InlineCode.svelte +2 -2
  21. package/components/chapter/Label.svelte +2 -2
  22. package/components/chapter/Link.svelte +2 -2
  23. package/components/chapter/Marginal.svelte +2 -2
  24. package/components/chapter/Paragraph.svelte +5 -0
  25. package/components/chapter/Table.svelte +2 -2
  26. package/components/chapter/Text.svelte +2 -2
  27. package/components/editor/BookishEditor.svelte +51 -28
  28. package/components/editor/BookishEditor.svelte.d.ts +4 -1
  29. package/components/editor/CaretView.svelte +3 -1
  30. package/components/editor/CaretView.svelte.d.ts +1 -0
  31. package/components/editor/ConfirmButton.svelte +1 -1
  32. package/components/editor/Note.svelte +1 -0
  33. package/components/editor/Permissions.svelte +95 -0
  34. package/components/editor/Permissions.svelte.d.ts +20 -0
  35. package/components/editor/Toolbar.svelte +0 -1
  36. package/components/editor/ToolbarGroup.svelte +0 -1
  37. package/components/page/Acknowledgements.svelte +13 -11
  38. package/components/page/Authors.svelte +5 -8
  39. package/components/page/Authors.svelte.d.ts +1 -0
  40. package/components/page/BookLoader.svelte +59 -0
  41. package/components/page/BookLoader.svelte.d.ts +16 -0
  42. package/components/page/BulkReferenceEditor.svelte +8 -8
  43. package/components/page/Chapter.svelte +43 -10
  44. package/components/page/Contexts.d.ts +14 -5
  45. package/components/page/Contexts.js +88 -6
  46. package/components/page/DefinitionView.svelte +18 -8
  47. package/components/page/Description.svelte +12 -9
  48. package/components/page/Edition.svelte +8 -8
  49. package/components/page/Edition.svelte.d.ts +0 -1
  50. package/components/page/EditionLoader.svelte +99 -0
  51. package/components/page/EditionLoader.svelte.d.ts +18 -0
  52. package/components/page/Editions.svelte +92 -143
  53. package/components/page/Glossary.svelte +13 -6
  54. package/components/page/Header.svelte +22 -20
  55. package/components/page/Header.svelte.d.ts +2 -0
  56. package/components/page/Index.svelte +6 -4
  57. package/components/page/Instructions.svelte +1 -2
  58. package/components/page/Instructions.svelte.d.ts +3 -1
  59. package/components/page/License.svelte +20 -12
  60. package/components/page/Media.svelte +14 -12
  61. package/components/page/Publish.svelte +120 -0
  62. package/components/page/Publish.svelte.d.ts +14 -0
  63. package/components/page/Reference.svelte +16 -17
  64. package/components/page/References.svelte +8 -3
  65. package/components/page/Search.svelte +3 -1
  66. package/components/page/Status.svelte +18 -19
  67. package/components/page/SubdomainEditor.svelte +3 -2
  68. package/components/page/TableOfContents.svelte +70 -30
  69. package/components/page/TableOfContentsRow.svelte +4 -4
  70. package/components/page/ThemeEditor.svelte +8 -5
  71. package/components/page/Unknown.svelte +5 -2
  72. package/models/CRUD.d.ts +19 -11
  73. package/models/CRUD.js +177 -122
  74. package/models/Firebase.js +12 -8
  75. package/models/book/Book.d.ts +19 -14
  76. package/models/book/Book.js +47 -54
  77. package/models/book/Chapter.d.ts +5 -1
  78. package/models/book/Chapter.js +24 -15
  79. package/models/book/Edition.d.ts +31 -7
  80. package/models/book/Edition.js +101 -32
  81. package/models/chapter/Parser.d.ts +2 -2
  82. package/models/chapter/Parser.js +26 -24
  83. package/package.json +18 -15
  84. package/components/app/Writing.svelte.d.ts +0 -27
  85. package/models/loadEdition.d.ts +0 -5
  86. package/models/loadEdition.js +0 -20
@@ -1,8 +1,8 @@
1
1
  <script>import { sendSignInLinkToEmail } from 'firebase/auth';
2
- import { onMount, setContext } from 'svelte';
2
+ import { onDestroy, setContext } from 'svelte';
3
3
  import { writable } from 'svelte/store';
4
4
  import { auth } from '../models/Firebase';
5
- import { AUTH } from './page/Contexts';
5
+ import { USER } from './page/Contexts';
6
6
  // Track the user and user loading status in state
7
7
  let loading = true;
8
8
  // The store that tracks the auth context.
@@ -37,18 +37,16 @@ function logout() {
37
37
  }
38
38
  }
39
39
  // On mount, subscribe to authentication changes.
40
- onMount(() => {
41
- if (auth) {
42
- const unsubscribe = auth.onAuthStateChanged((user) => {
43
- loading = false;
44
- updateAuth(user);
45
- });
46
- // On unmount, stop subscribing.
47
- return unsubscribe;
48
- }
49
- });
40
+ if (auth) {
41
+ const unsubscribe = auth.onAuthStateChanged((user) => {
42
+ loading = false;
43
+ updateAuth(user);
44
+ });
45
+ // On unmount, stop subscribing.
46
+ onDestroy(unsubscribe);
47
+ }
50
48
  // Expose the state and the login/logout functionality.
51
- setContext(AUTH, authentication);
49
+ setContext(USER, authentication);
52
50
  </script>
53
51
 
54
52
  <!-- Wrap whatever children are given in this context. -->
@@ -12,26 +12,24 @@ $: cover = book.getCover();
12
12
  $: authors = book.getAuthors();
13
13
  $: description = book.getDescription();
14
14
  $: subdomain = book.getSubdomain();
15
- $: title = book.getTitle() === '' ? 'Untitled' : book.getTitle();
15
+ $: title = book.getTitle();
16
16
  $: embed = cover === null ? null : Parser.parseEmbed(undefined, cover);
17
+ $: url =
18
+ subdomain === undefined || write
19
+ ? refID === undefined
20
+ ? ''
21
+ : (write ? '/write/' : '/') + refID
22
+ : `/${subdomain}`;
17
23
  </script>
18
24
 
19
25
  <article class="book-preview">
20
26
  <div class="cover" class:empty={embed === null}>
21
27
  {#if embed instanceof EmbedNode}
22
- <Embed node={embed} imageOnly />
23
- {:else if embed instanceof ErrorNode}
24
- <ErrorMessage node={embed} />
28
+ <Embed node={embed} imageOnly editable={false} />
25
29
  {/if}
26
30
  </div>
27
31
  <div class="content">
28
- <Link
29
- to={subdomain === undefined || write
30
- ? refID === undefined
31
- ? ''
32
- : (write ? '/write/' : '/') + refID
33
- : `/${subdomain}`}><h2 class="title">{title}</h2></Link
34
- >
32
+ <Link to={url}><h2 class="title">{title}</h2></Link>
35
33
  <p class="authors">
36
34
  {#each authors as author, index}
37
35
  <span
@@ -41,7 +39,7 @@ $: embed = cover === null ? null : Parser.parseEmbed(undefined, cover);
41
39
  <em>No authors</em>
42
40
  {/each}
43
41
  </p>
44
- <p class="description">
42
+ <div class="description">
45
43
  {#if description.length === 0}
46
44
  <em>No description</em>
47
45
  {:else}
@@ -49,7 +47,8 @@ $: embed = cover === null ? null : Parser.parseEmbed(undefined, cover);
49
47
  node={Parser.parseChapter(undefined, description)}
50
48
  />
51
49
  {/if}
52
- </p>
50
+ </div>
51
+ <Link to={`${url}/editions`}>Editions</Link>
53
52
  </div>
54
53
  </article>
55
54
 
@@ -100,6 +99,5 @@ $: embed = cover === null ? null : Parser.parseEmbed(undefined, cover);
100
99
  margin-top: 0;
101
100
  overflow: hidden;
102
101
  text-overflow: ellipsis;
103
- height: 5em;
104
102
  }
105
103
  </style>
@@ -1,11 +1,18 @@
1
- <script>import Large from './Large.svelte';
1
+ <script>import { onMount } from 'svelte';
2
+ import Large from './Large.svelte';
2
3
  export let error = false;
4
+ let visible = error;
5
+ onMount(() => {
6
+ setTimeout(() => (visible = true), 1000);
7
+ });
3
8
  </script>
4
9
 
5
- {#if error}
6
- <p role="alert"><slot /></p>
7
- {:else}
8
- <p role="status" aria-live="polite"><Large><slot /></Large></p>
10
+ {#if visible}
11
+ {#if error}
12
+ <p role="alert"><slot /></p>
13
+ {:else}
14
+ <p role="status" aria-live="polite"><Large><slot /></Large></p>
15
+ {/if}
9
16
  {/if}
10
17
 
11
18
  <style>
@@ -21,11 +28,6 @@ export let error = false;
21
28
  color: var(--app-error-color);
22
29
  }
23
30
 
24
- p[role='alert']:before {
25
- content: '! ';
26
- font-size: 200%;
27
- }
28
-
29
31
  p[role='status'] {
30
32
  color: var(--app-font-color);
31
33
  animation: waiting 1s infinite;
@@ -1,4 +1,7 @@
1
- <h2><slot /></h2>
1
+ <script>export let id = null;
2
+ </script>
3
+
4
+ <h2 {id}><slot /></h2>
2
5
 
3
6
  <style>
4
7
  h2 {
@@ -1,21 +1,7 @@
1
- /** @typedef {typeof __propDef.props} HeadProps */
2
- /** @typedef {typeof __propDef.events} HeadEvents */
3
- /** @typedef {typeof __propDef.slots} HeadSlots */
4
- export default class Head extends SvelteComponentTyped<{
5
- [x: string]: never;
6
- }, {
7
- [evt: string]: CustomEvent<any>;
8
- }, {
9
- default: {};
10
- }> {
11
- }
12
- export type HeadProps = typeof __propDef.props;
13
- export type HeadEvents = typeof __propDef.events;
14
- export type HeadSlots = typeof __propDef.slots;
15
1
  import { SvelteComponentTyped } from "svelte";
16
2
  declare const __propDef: {
17
3
  props: {
18
- [x: string]: never;
4
+ id?: string | null | undefined;
19
5
  };
20
6
  events: {
21
7
  [evt: string]: CustomEvent<any>;
@@ -24,4 +10,9 @@ declare const __propDef: {
24
10
  default: {};
25
11
  };
26
12
  };
13
+ export type HeadProps = typeof __propDef.props;
14
+ export type HeadEvents = typeof __propDef.events;
15
+ export type HeadSlots = typeof __propDef.slots;
16
+ export default class Head extends SvelteComponentTyped<HeadProps, HeadEvents, HeadSlots> {
17
+ }
27
18
  export {};
@@ -15,5 +15,6 @@
15
15
 
16
16
  .aside {
17
17
  font-style: italic;
18
+ font-size: 90%;
18
19
  }
19
20
  </style>
@@ -7,7 +7,6 @@
7
7
  margin: auto;
8
8
  padding-left: 2rem;
9
9
  padding-right: 2rem;
10
- min-width: 30rem;
11
10
  max-width: 40rem;
12
11
  }
13
12
  </style>
@@ -0,0 +1,27 @@
1
+ /** @typedef {typeof __propDef.props} SectionProps */
2
+ /** @typedef {typeof __propDef.events} SectionEvents */
3
+ /** @typedef {typeof __propDef.slots} SectionSlots */
4
+ export default class Section extends SvelteComponentTyped<{
5
+ [x: string]: never;
6
+ }, {
7
+ [evt: string]: CustomEvent<any>;
8
+ }, {
9
+ default: {};
10
+ }> {
11
+ }
12
+ export type SectionProps = typeof __propDef.props;
13
+ export type SectionEvents = typeof __propDef.events;
14
+ export type SectionSlots = typeof __propDef.slots;
15
+ import { SvelteComponentTyped } from "svelte";
16
+ declare const __propDef: {
17
+ props: {
18
+ [x: string]: never;
19
+ };
20
+ events: {
21
+ [evt: string]: CustomEvent<any>;
22
+ };
23
+ slots: {
24
+ default: {};
25
+ };
26
+ };
27
+ export {};
@@ -14,6 +14,7 @@ export function value() {
14
14
  {type}
15
15
  {placeholder}
16
16
  {disabled}
17
+ value={text}
17
18
  bind:this={input}
18
19
  on:input={() => (text = input.value)}
19
20
  />
@@ -19,12 +19,14 @@ import Quote from './Quote.svelte';
19
19
  import Rule from './Rule.svelte';
20
20
  import Table from './Table.svelte';
21
21
  import Problem from './Problem.svelte';
22
+ import { isChapterEditable } from '../page/Contexts';
22
23
  export let node;
24
+ let editable = isChapterEditable();
23
25
  </script>
24
26
 
25
27
  {#if node instanceof ParagraphNode}<Paragraph {node} />
26
28
  {:else if node instanceof ListNode}<List {node} />
27
- {:else if node instanceof EmbedNode}<Embed {node} />
29
+ {:else if node instanceof EmbedNode}<Embed {node} {editable} />
28
30
  {:else if node instanceof CalloutNode}<Callout {node} />
29
31
  {:else if node instanceof QuoteNode}<Quote {node} />
30
32
  {:else if node instanceof CodeNode}<CaptionedCode {node} />
@@ -3,12 +3,12 @@
3
3
  <script>import Code from './Code.svelte';
4
4
  import Python from './Python.svelte';
5
5
  import Text from './Text.svelte';
6
- import { isEditable } from '../page/Contexts';
6
+ import { isChapterEditable } from '../page/Contexts';
7
7
  import Figure from './Figure.svelte';
8
8
  import { getCaret } from '../page/Contexts';
9
9
  export let node;
10
10
  $: language = node.getLanguage();
11
- let editable = isEditable();
11
+ let editable = isChapterEditable();
12
12
  // const languages = [ "C", "C++", "CSS", "Go", "HTML", "Java", "JavaScript", "Markdown", "Plaintext", "Python", "TypeScript" ];
13
13
  let caret = getCaret();
14
14
  $: inside =
@@ -6,12 +6,13 @@ import Paragraph from './Paragraph.svelte';
6
6
  import Problem from './Problem.svelte';
7
7
  export let node;
8
8
  export let placeholder = '';
9
+ export let editable = false;
9
10
  $: errors = node.getErrors();
10
11
  $: blocks = node.getBlocks();
11
12
  </script>
12
13
 
13
14
  <section class="bookish-chapter-body" data-nodeid={node.nodeID}>
14
- {#if errors.length > 0}
15
+ {#if editable && errors.length > 0}
15
16
  <p>
16
17
  <Problem
17
18
  >{errors.length +
@@ -4,6 +4,7 @@ declare const __propDef: {
4
4
  props: {
5
5
  node: ChapterNode;
6
6
  placeholder?: string | undefined;
7
+ editable?: boolean | undefined;
7
8
  };
8
9
  events: {
9
10
  [evt: string]: CustomEvent<any>;
@@ -3,14 +3,14 @@
3
3
  <script>import Atom from './Atom.svelte';
4
4
  import Marginal from './Marginal.svelte';
5
5
  import Format from './Format.svelte';
6
- import { getChapter, isEditable, getCaret, getEdition, } from '../page/Contexts';
6
+ import { getChapter, isChapterEditable, getCaret, getEdition, } from '../page/Contexts';
7
7
  import { afterUpdate } from 'svelte';
8
8
  import Icon from '../editor/Icon.svelte';
9
9
  import CommentIcon from '../editor/icons/comment.svg?raw';
10
10
  export let node;
11
11
  let chapter = getChapter();
12
12
  let edition = getEdition();
13
- let editable = isEditable();
13
+ let editable = isChapterEditable();
14
14
  let caret = getCaret();
15
15
  $: chapterNode =
16
16
  $edition && $chapter ? $chapter.chapter.getAST($edition) : undefined;
@@ -1,17 +1,17 @@
1
1
  <svelte:options immutable={true} />
2
2
 
3
3
  <script>import { storage } from '../../models/Firebase';
4
- import { isEditable, getCaret, getBook, } from '../page/Contexts';
4
+ import { getCaret, getBook } from '../page/Contexts';
5
5
  import Figure from './Figure.svelte';
6
6
  import { getContext } from 'svelte';
7
7
  export let node;
8
+ export let editable = false;
8
9
  export let placeholder = '';
9
10
  export let imageOnly = false;
10
11
  $: url = node.getURL();
11
12
  $: description = node.getDescription();
12
13
  let caret = getCaret();
13
14
  let book = getBook();
14
- let editable = isEditable();
15
15
  // Bookish editor should have passed down a way to set the active editor.
16
16
  let claimCaret = getContext('claimeditor');
17
17
  let dragging = false;
@@ -114,7 +114,7 @@ function handleClick() {
114
114
  : 'Click or drag to choose or upload an image, or enter an image or video URL.'}
115
115
  </p>
116
116
  {:else}
117
- <p class="bookish-figure-unspecified">Missing image or video</p>
117
+ <p class="bookish-figure-unspecified">No image or video</p>
118
118
  {/if}
119
119
  {:else if url.includes('https://www.youtube.com') || url.includes('https://youtu.be') || url.includes('https://www.tiktok.com') || url.includes('vimeo.com')}
120
120
  <article class="bookish-figure-embed">
@@ -3,6 +3,7 @@ import type EmbedNode from '../../models/chapter/EmbedNode';
3
3
  declare const __propDef: {
4
4
  props: {
5
5
  node: EmbedNode;
6
+ editable?: boolean | undefined;
6
7
  placeholder?: string | undefined;
7
8
  imageOnly?: boolean | undefined;
8
9
  };
@@ -2,11 +2,11 @@
2
2
 
3
3
  <script>import Format from './Format.svelte';
4
4
  import Positioned from './Positioned.svelte';
5
- import { getCaret, isEditable } from '../page/Contexts';
5
+ import { getCaret, isChapterEditable } from '../page/Contexts';
6
6
  export let node;
7
7
  export let caption;
8
8
  export let credit = undefined;
9
- let editable = isEditable();
9
+ let editable = isChapterEditable();
10
10
  let caret = getCaret();
11
11
  $: selected = $caret?.range?.start.node === node;
12
12
  function focusFigure() {
@@ -19,10 +19,10 @@ import Link from './Link.svelte';
19
19
  import Comment from './Comment.svelte';
20
20
  import Text from './Text.svelte';
21
21
  import Format from './Format.svelte';
22
- import { isEditable } from '../page/Contexts';
22
+ import { isChapterEditable } from '../page/Contexts';
23
23
  export let node;
24
+ export let editable = false;
24
25
  export let placeholder = undefined;
25
- let editable = isEditable();
26
26
  $: format = node.getFormat();
27
27
  $: tag =
28
28
  format === '*'
@@ -35,7 +35,9 @@ $: tag =
35
35
  ? 'sub'
36
36
  : 'span';
37
37
  $: showPlaceholder =
38
- node.isEmptyText() && placeholder !== undefined && editable;
38
+ node.isEmptyText() &&
39
+ placeholder !== undefined &&
40
+ (editable || isChapterEditable());
39
41
  </script>
40
42
 
41
43
  <svelte:element
@@ -3,6 +3,7 @@ import FormatNode from '../../models/chapter/FormatNode';
3
3
  declare const __propDef: {
4
4
  props: {
5
5
  node: FormatNode;
6
+ editable?: boolean | undefined;
6
7
  placeholder?: string | undefined;
7
8
  };
8
9
  events: {
@@ -1,10 +1,10 @@
1
1
  <svelte:options immutable={true} />
2
2
 
3
- <script>import { isEditable } from '../page/Contexts';
3
+ <script>import { isChapterEditable } from '../page/Contexts';
4
4
  import Code from './Code.svelte';
5
5
  import Text from './Text.svelte';
6
6
  export let node;
7
- let editable = isEditable();
7
+ let editable = isChapterEditable();
8
8
  </script>
9
9
 
10
10
  {#if editable}
@@ -1,10 +1,10 @@
1
1
  <svelte:options immutable={true} />
2
2
 
3
3
  <script>import Atom from './Atom.svelte';
4
- import { getChapter, getEdition, isEditable } from '../page/Contexts';
4
+ import { getChapter, getEdition, isChapterEditable, } from '../page/Contexts';
5
5
  import Problem from './Problem.svelte';
6
6
  export let node;
7
- let editable = isEditable();
7
+ let editable = isChapterEditable();
8
8
  let chapter = getChapter();
9
9
  let edition = getEdition();
10
10
  $: ast =
@@ -1,11 +1,11 @@
1
1
  <svelte:options immutable={true} />
2
2
 
3
- <script>import { getBase, getEdition, isEditable } from '../page/Contexts';
3
+ <script>import { getBase, getEdition, isChapterEditable } from '../page/Contexts';
4
4
  import Text from './Text.svelte';
5
5
  import Problem from './Problem.svelte';
6
6
  export let node;
7
7
  let base = getBase();
8
- let editable = isEditable();
8
+ let editable = isChapterEditable();
9
9
  let edition = getEdition();
10
10
  $: url = node.getMeta();
11
11
  $: content = node.getText();
@@ -2,13 +2,13 @@
2
2
 
3
3
  <script>import { isMobile, watchMobile } from '../../util/isMobile';
4
4
  import { onMount } from 'svelte';
5
- import { getCaret, getChapter, isEditable, } from '../page/Contexts';
5
+ import { getCaret, getChapter, isChapterEditable, } from '../page/Contexts';
6
6
  export let node;
7
7
  export let id;
8
8
  export let label;
9
9
  let hovered = false;
10
10
  let chapter = getChapter();
11
- $: editable = isEditable();
11
+ $: editable = isChapterEditable();
12
12
  let caret = getCaret();
13
13
  // If there's no marginal selected or this is different from the current selection, this is hidden.
14
14
  $: selectedMarginal = $chapter?.marginal;
@@ -56,6 +56,11 @@ $: classes =
56
56
  min-height: var(--bookish-paragraph-line-height);
57
57
  }
58
58
 
59
+ .placeholder {
60
+ color: var(--bookish-muted-color);
61
+ font-style: italic;
62
+ }
63
+
59
64
  h2,
60
65
  h3,
61
66
  h4,
@@ -3,9 +3,9 @@
3
3
  <script>import Figure from './Figure.svelte';
4
4
  import Format from './Format.svelte';
5
5
  import Rows from '../page/Rows.svelte';
6
- import { isEditable } from '../page/Contexts';
6
+ import { isChapterEditable } from '../page/Contexts';
7
7
  export let node;
8
- let editable = isEditable();
8
+ let editable = isChapterEditable();
9
9
  $: rows = node.getRows();
10
10
  </script>
11
11
 
@@ -1,11 +1,11 @@
1
1
  <svelte:options immutable={true} />
2
2
 
3
- <script>import { getChapter, isEditable } from '../page/Contexts';
3
+ <script>import { getChapter, isChapterEditable } from '../page/Contexts';
4
4
  export let node;
5
5
  export let placeholder = undefined;
6
6
  $: text = node.getText();
7
7
  let context = getChapter();
8
- let editable = isEditable();
8
+ let editable = isChapterEditable();
9
9
  function replaceMultipleSpacesWithNonBreakingSpaces(original) {
10
10
  let revisedText = '';
11
11
  for (let i = 0; i < original.length; i++) {