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,158 +1,107 @@
1
- <script>import Parser from '../../models/chapter/Parser';
2
- import { createNewEdition, publish } from '../../models/CRUD';
3
- import Format from '../chapter/Format.svelte';
4
- import BookishEditor from '../editor/BookishEditor.svelte';
1
+ <script>import { createNewEdition } from '../../models/CRUD';
5
2
  import Instructions from './Instructions.svelte';
6
3
  import Note from '../editor/Note.svelte';
7
- import { getBook, getEdition, isEditable } from './Contexts';
4
+ import { getUser, getBook, isBookEditable } from './Contexts';
8
5
  import Button from '../app/Button.svelte';
9
- import Link from '../Link.svelte';
10
- import PageHeader from './PageHeader.svelte';
11
- import Rows from './Rows.svelte';
12
- let edition = getEdition();
13
- let editable = isEditable();
6
+ import Link from '../app/Link.svelte';
7
+ import Format from '../chapter/Format.svelte';
8
+ import Parser from '../../models/chapter/Parser';
9
+ import Permissions from '../editor/Permissions.svelte';
14
10
  let book = getBook();
15
- // Book revisions
16
- $: bookEditions = $book?.getEditions();
17
- let publishing = new Map();
11
+ let editable = isBookEditable();
12
+ let auth = getUser();
13
+ $: editions = $book?.getEditions();
14
+ $: latestPublishedID = $book?.getLatestPublishedEditionID();
18
15
  async function handleDraftEdition() {
19
16
  if ($book === undefined)
20
17
  return;
21
18
  book.set(await createNewEdition($book));
22
19
  }
23
- async function handlePublish(index) {
24
- if ($book) {
25
- publishing.set(index, true);
26
- const error = await publish($book, index);
27
- if (error)
28
- publishing.set(index, error);
29
- else
30
- publishing.delete(index);
31
- publishing = new Map(publishing);
32
- }
33
- }
34
20
  </script>
35
21
 
36
- {#if $edition}
37
- {#if $book && bookEditions}
38
- <PageHeader id="revisions"
39
- >Editions {#if editable}<Button
40
- tooltip="Create a new edition"
41
- command={handleDraftEdition}>+</Button
42
- >{/if}</PageHeader
43
- >
44
- <Instructions>
45
- Each book has one or more editions, allowing you to track revisions
46
- and ensure previous versions remain available. When you're ready to
47
- revise, make a new edition, then publish it when you're done. The
48
- edition with a * is the default edition readers will see, unless
49
- they explicitly choose to view a previous edition.
50
- </Instructions>
51
- <Rows>
52
- {#each bookEditions as bookEdition, index (bookEdition.ref)}
53
- {@const editionNumber =
54
- bookEditions === undefined
55
- ? -1
56
- : bookEditions.length - index}
57
- {@const editionLabel =
58
- editionNumber +
59
- (editionNumber === 1
60
- ? 'st'
61
- : editionNumber === 2
62
- ? 'nd'
63
- : editionNumber === 3
64
- ? 'rd'
65
- : 'th')}
66
- {@const viewing = bookEdition.ref.id === $edition.getRef()?.id}
67
-
68
- {#if $book && (editable || bookEdition.published)}
69
- <tr>
70
- <td>
71
- {#if viewing}
72
- <strong class="viewing">{editionLabel}</strong>
73
- {:else}
74
- <Link
75
- to={`/write/${$book.ref.id}/${
76
- bookEditions.length - index
77
- }`}>{editionLabel}</Link
78
- >
79
- {/if}
80
- <Note
81
- >{new Date(bookEdition.time).toLocaleDateString(
82
- 'en-us'
83
- )}</Note
84
- >
85
- </td>
86
- <td>
87
- {#if editable}
88
- <BookishEditor
89
- ast={Parser.parseFormat(
90
- undefined,
91
- bookEdition.summary
92
- ).withTextIfEmpty()}
93
- save={(newSummary) =>
94
- $book
95
- ? book.set(
96
- $book.withEditionSummary(
97
- newSummary.toBookdown(),
98
- index
99
- )
100
- )
101
- : undefined}
102
- chapter={false}
103
- component={Format}
104
- placeholder="Summarize this edition's changes."
105
- />
106
- {:else if bookEdition.summary === ''}
107
- <em>No summary of changes</em>
108
- {:else}
109
- {bookEdition.summary}
110
- {/if}
111
- </td>
112
- <td style="whitespace: nowrap">
113
- {#if editable}
114
- <!-- <Switch
115
- options={['hidden', 'published']}
116
- enabled={bookEdition.published ||
117
- bookEdition.summary !== ''}
118
- value={bookEdition.published
119
- ? 'published'
120
- : 'hidden'}
121
- edit={(published) =>
122
- handlePublish(
123
- index,
124
- published === 'published'
125
- )}
126
- /> -->
127
- <Button
128
- tooltip="publish edition"
129
- command={() => handlePublish(index)}
130
- disabled={publishing.has(index)}
131
- >publish</Button
132
- >
133
- {#if typeof publishing.get(index) === 'string'}
134
- {publishing.get(index)}
135
- {/if}
136
- {/if}
137
- </td>
138
- </tr>
139
- {/if}
140
- {/each}
141
- </Rows>
22
+ {#if $book && editions}
23
+ {#if editable}
24
+ <p>
25
+ <Button tooltip="create new edition" command={handleDraftEdition}
26
+ >+ edition</Button
27
+ >
28
+ </p>
142
29
  {/if}
143
- {/if}
30
+ <Instructions {editable}>
31
+ Each book has one or more editions, allowing you to track revisions and
32
+ ensure previous versions remain available. When you're ready to revise,
33
+ add a new edition here; it will copy the latest edition, which you can
34
+ then edit. When you're ready to publish an edition, write a summary here
35
+ and then publish. By default, readers will see the latest published
36
+ edition, but they can access older editions here.
37
+ </Instructions>
38
+ {#each editions as bookEdition, index (bookEdition.ref)}
39
+ {@const editionNumber =
40
+ editions === undefined ? -1 : editions.length - index}
41
+ {@const editionLabel =
42
+ editionNumber +
43
+ (editionNumber === 1
44
+ ? 'st'
45
+ : editionNumber === 2
46
+ ? 'nd'
47
+ : editionNumber === 3
48
+ ? 'rd'
49
+ : 'th')}
144
50
 
145
- <style>
146
- .viewing {
147
- border-bottom: var(--app-chrome-border-size) solid
148
- var(--app-border-color);
149
- }
51
+ {#if $book && (editable || bookEdition.published)}
52
+ <section class="edition">
53
+ <h3
54
+ >{editionLabel}
55
+ <Note
56
+ >{#if bookEdition.published}{new Date(
57
+ bookEdition.published
58
+ ).toLocaleDateString(
59
+ 'en-us'
60
+ )}{:else}unpublished{/if}
61
+ &nbsp;
62
+ <Link
63
+ to={latestPublishedID === bookEdition.ref.id &&
64
+ $book.getSubdomain() !== undefined
65
+ ? `/${$book.getSubdomain()}`
66
+ : `/${$book.ref.id}/${editions.length - index}`}
67
+ >read</Link
68
+ >
69
+ {#if editable}
70
+ &nbsp;
71
+ <Link
72
+ to={`/write/${$book.ref.id}/${
73
+ editions.length - index
74
+ }`}>edit</Link
75
+ >
76
+ {/if}
77
+ </Note>
78
+ </h3>
79
+ <p
80
+ >{#if bookEdition.summary !== ''}<Format
81
+ node={Parser.parseFormat(
82
+ undefined,
83
+ bookEdition.summary
84
+ )}
85
+ />{:else}&mdash{/if}</p
86
+ >
87
+ </section>
88
+ {/if}
89
+ {/each}
150
90
 
151
- td:first-child {
152
- width: 5%;
153
- }
91
+ {#if editable}
92
+ <h2>Editors</h2>
93
+ <Instructions {editable}>
94
+ These authors can edit any aspect of the book and any of its
95
+ editions.
96
+ </Instructions>
154
97
 
155
- td:last-child {
156
- width: 30%;
157
- }
158
- </style>
98
+ <Permissions
99
+ uids={$book.uids}
100
+ inheriteduids={[]}
101
+ atleastone={true}
102
+ writable={editable}
103
+ change={(uids) =>
104
+ $book ? book.set($book.withEditors(uids)) : undefined}
105
+ />
106
+ {/if}
107
+ {/if}
@@ -3,12 +3,12 @@ import Outline from './Outline.svelte';
3
3
  import Page from './Page.svelte';
4
4
  import ChapterIDs from '../../models/book/ChapterID';
5
5
  import DefinitionView from './DefinitionView.svelte';
6
- import { getEdition, isEditable } from './Contexts';
6
+ import { getUser, getEdition, isEditionEditable } from './Contexts';
7
7
  import Instructions from './Instructions.svelte';
8
8
  import Button from '../app/Button.svelte';
9
- import Rows from './Rows.svelte';
9
+ let auth = getUser();
10
10
  let edition = getEdition();
11
- let editable = isEditable();
11
+ let editable = isEditionEditable();
12
12
  $: glossary = $edition?.getGlossary() ?? {};
13
13
  // Sort by canonical phrases
14
14
  $: keys =
@@ -32,7 +32,12 @@ function addEmptyDefinition() {
32
32
  {#if $edition}
33
33
  <Page title={`${$edition.getTitle()} - Glossary`}>
34
34
  <Header
35
+ editable={isEditionEditable() ||
36
+ ($auth !== undefined &&
37
+ $auth.user !== null &&
38
+ $edition.isChapterEditor($auth.user.uid))}
35
39
  label="Glossary title"
40
+ id="glossary"
36
41
  getImage={() => $edition?.getImage(ChapterIDs.GlossaryID) ?? null}
37
42
  setImage={(embed) =>
38
43
  $edition
@@ -50,10 +55,12 @@ function addEmptyDefinition() {
50
55
  />
51
56
  </Header>
52
57
  {#if editable}
53
- <Instructions>
54
- Add definitions and then link to them in a chapter's text.
58
+ <Instructions {editable}>
59
+ Build a glossary here, adding terms, phrases, definitions, and
60
+ synonyms. Then, in a chapter, you can select any text and link
61
+ it to a definition.
55
62
  </Instructions>
56
- <Button tooltip="Add a glossary entry" command={addEmptyDefinition}
63
+ <Button tooltip="add glossary entry" command={addEmptyDefinition}
57
64
  >+ definition</Button
58
65
  >
59
66
  {/if}
@@ -1,15 +1,16 @@
1
- <script>import EmbedNode from '../../models/chapter/EmbedNode';
2
- import Parser from '../../models/chapter/Parser';
1
+ <script>import Parser from '../../models/chapter/Parser';
3
2
  import Embed from '../chapter/Embed.svelte';
4
- import ErrorMessage from '../chapter/ErrorMessage.svelte';
5
3
  import BookishEditor from '../editor/BookishEditor.svelte';
6
4
  import Title from './Title.svelte';
7
5
  import { onMount } from 'svelte';
8
6
  import TextEditor from '../editor/TextEditor.svelte';
9
- import { getEdition, isEditable } from './Contexts';
7
+ import { getUser, getEdition, getLeasee, lease } from './Contexts';
10
8
  import Button from '../app/Button.svelte';
9
+ /** True if an author should be able to edit this header. */
10
+ export let editable;
11
11
  export let label;
12
12
  export let header;
13
+ export let id;
13
14
  export let subtitle = undefined;
14
15
  export let print = false;
15
16
  export let tags = undefined;
@@ -18,8 +19,8 @@ export let setImage;
18
19
  export let save = null;
19
20
  let title = null;
20
21
  let showReminder = true;
22
+ let auth = getUser();
21
23
  let edition = getEdition();
22
- let editable = isEditable();
23
24
  function updateScrollReminder() {
24
25
  // If the bottom of the window is below the top of the title, hide the reminder.
25
26
  if (title)
@@ -48,29 +49,30 @@ onMount(() => {
48
49
  };
49
50
  });
50
51
  // Get the embed, update when getImage function prop changes.
51
- let embedNode = undefined;
52
- $: {
53
- let embed = getImage();
54
- embedNode = embed ? Parser.parseEmbed($edition, embed) : undefined;
55
- }
52
+ let embed;
53
+ $: embed = getImage();
56
54
  </script>
57
55
 
58
56
  <header class="bookish-chapter-header">
59
- {#if embedNode}
57
+ {#if embed}
60
58
  <div class="bookish-figure-full">
61
- {#if edition && editable && embedNode instanceof EmbedNode}
59
+ {#if $edition && editable}
62
60
  <BookishEditor
63
- ast={embedNode}
61
+ text={embed}
62
+ parser={(text) => Parser.parseEmbed($edition, text)}
64
63
  save={(node) =>
65
64
  setImage ? setImage(node.toBookdown()) : undefined}
66
65
  chapter={false}
67
66
  component={Embed}
68
67
  placeholder=""
68
+ leasee={getLeasee(auth, edition, `embed-${id}`)}
69
+ lease={(lock) => lease(auth, edition, `embed-${id}`, lock)}
69
70
  />
70
- {:else if embedNode instanceof EmbedNode}
71
- <Embed node={embedNode} />
72
71
  {:else}
73
- <ErrorMessage node={embedNode} />
72
+ <Embed
73
+ node={Parser.parseEmbed($edition, embed)}
74
+ editable={false}
75
+ />
74
76
  {/if}
75
77
  {#if !print && showReminder}
76
78
  <div class="bookish-scroll-reminder" />
@@ -84,12 +86,12 @@ $: {
84
86
  <slot name="outline" />
85
87
  {/if}
86
88
  {#if editable}
87
- {#if embedNode === undefined}
88
- <Button tooltip="add cover image to page" command={addCover}
89
+ {#if embed === null}
90
+ <Button tooltip="add cover image" command={addCover}
89
91
  >+ cover image</Button
90
92
  >
91
93
  {:else}
92
- <Button tooltip="remove cover image from page" command={removeCover}
94
+ <Button tooltip="remove cover image" command={removeCover}
93
95
  >- cover image</Button
94
96
  >
95
97
  {/if}
@@ -101,7 +103,7 @@ $: {
101
103
  <TextEditor
102
104
  {label}
103
105
  text={header + (subtitle ? ': ' + subtitle : '')}
104
- placeholder="Title"
106
+ placeholder="title"
105
107
  valid={(text) =>
106
108
  text.length === 0
107
109
  ? 'Titles have to be at least one character long.'
@@ -1,8 +1,10 @@
1
1
  import { SvelteComponentTyped } from "svelte";
2
2
  declare const __propDef: {
3
3
  props: {
4
+ /** True if an author should be able to edit this header. */ editable: boolean;
4
5
  label: string;
5
6
  header: string;
7
+ id: string;
6
8
  subtitle?: string | undefined;
7
9
  print?: boolean | undefined;
8
10
  tags?: string[] | undefined;
@@ -4,13 +4,14 @@ import Page from './Page.svelte';
4
4
  import Instructions from './Instructions.svelte';
5
5
  import ChapterIDs from '../../models/book/ChapterID';
6
6
  import Link from '../Link.svelte';
7
- import { getBase, getEdition } from './Contexts';
7
+ import { getBase, getEdition, isEditionEditable } from './Contexts';
8
8
  import { page } from '$app/stores';
9
9
  import Muted from './Muted.svelte';
10
10
  import ChapterTitle from './ChapterTitle.svelte';
11
11
  import ChapterNumber from './ChapterNumber.svelte';
12
12
  import PageHeader from './PageHeader.svelte';
13
13
  import Rows from './Rows.svelte';
14
+ let editable = isEditionEditable();
14
15
  let edition = getEdition();
15
16
  let base = getBase();
16
17
  // What letter are we matching?
@@ -43,7 +44,9 @@ $: {
43
44
  {#if $edition}
44
45
  <Page title={`${$edition.getTitle()} - Index`}>
45
46
  <Header
47
+ editable={isEditionEditable()}
46
48
  label="Index title"
49
+ id="index"
47
50
  getImage={() => $edition?.getImage(ChapterIDs.IndexID) ?? null}
48
51
  setImage={(embed) =>
49
52
  $edition
@@ -59,9 +62,8 @@ $: {
59
62
  />
60
63
  </Header>
61
64
 
62
- <Instructions>
63
- This index is created automatically. It's not perfect; we may add
64
- more control over it in the future.
65
+ <Instructions {editable}>
66
+ This index is created automatically using the words in the chapters.
65
67
  </Instructions>
66
68
 
67
69
  <p
@@ -1,5 +1,4 @@
1
- <script>import { isEditable } from './Contexts';
2
- let editable = isEditable();
1
+ <script>export let editable;
3
2
  </script>
4
3
 
5
4
  {#if editable}
@@ -1,6 +1,8 @@
1
1
  import { SvelteComponentTyped } from "svelte";
2
2
  declare const __propDef: {
3
- props: Record<string, never>;
3
+ props: {
4
+ editable: boolean;
5
+ };
4
6
  events: {
5
7
  [evt: string]: CustomEvent<any>;
6
8
  };
@@ -2,36 +2,44 @@
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 { getEdition, isEditable } from './Contexts';
5
+ import { getUser, getEdition, getLeasee, isEditionEditable, lease, } from './Contexts';
6
6
  import PageHeader from './PageHeader.svelte';
7
+ let auth = getUser();
7
8
  let edition = getEdition();
8
- let editable = isEditable();
9
- $: formatNode = $edition
10
- ? Parser.parseFormat($edition, $edition.getLicense()).withTextIfEmpty()
11
- : undefined;
9
+ let editable = isEditionEditable();
12
10
  </script>
13
11
 
14
12
  <PageHeader id="license">License</PageHeader>
15
13
 
16
- <Instructions>
17
- By default of U.S. Copyright Law, your content copyrighted and owned by all
18
- authors. Edit this if you'd like to grant different rights.
14
+ <Instructions {editable}>
15
+ Do you want to specify rights other than your region's default copyrights?
16
+ Edit them here.
19
17
  </Instructions>
20
18
 
21
- {#if $edition && formatNode}
19
+ {#if $edition}
22
20
  <!-- If editable, show acknowledgements even if they're empty, otherwise hide -->
23
21
  {#if editable}
22
+ <!-- svelte-ignore missing-declaration -->
24
23
  <BookishEditor
25
- ast={formatNode}
24
+ text={$edition.getLicense()}
25
+ parser={(text) =>
26
+ Parser.parseFormat($edition, text).withTextIfEmpty()}
26
27
  save={(node) =>
27
28
  $edition
28
29
  ? edition.set($edition.setLicense(node.toBookdown()))
29
30
  : undefined}
30
31
  chapter={false}
31
32
  component={Format}
32
- placeholder="In the U.S., all rights reserved by default. Want to offer different rights to readers?"
33
+ placeholder="license"
34
+ leasee={getLeasee(auth, edition, `license`)}
35
+ lease={(lock) => lease(auth, edition, `license`, lock)}
33
36
  />
34
37
  {:else}
35
- <Format node={formatNode} />
38
+ <Format
39
+ node={Parser.parseFormat(
40
+ $edition,
41
+ $edition.getLicense()
42
+ ).withTextIfEmpty()}
43
+ />
36
44
  {/if}
37
45
  {/if}
@@ -6,12 +6,12 @@ import ChapterIDs from '../../models/book/ChapterID';
6
6
  import Format from '../chapter/Format.svelte';
7
7
  import MediaPreview from './MediaPreview.svelte';
8
8
  import { onMount } from 'svelte';
9
- import { getBook, getEdition, isEditable } from './Contexts';
9
+ import { getBook, getEdition, isBookEditable, isEditionEditable, } from './Contexts';
10
10
  import Button from '../app/Button.svelte';
11
11
  import PageHeader from './PageHeader.svelte';
12
12
  let book = getBook();
13
13
  let edition = getEdition();
14
- let editable = isEditable();
14
+ let editable = isBookEditable();
15
15
  let images = [];
16
16
  $: embeds = $edition?.getEmbeds() ?? [];
17
17
  $: media = $book?.getMedia();
@@ -29,7 +29,9 @@ $: unused = images?.filter((image) => embeds.find((embed) => embed.getURL() ===
29
29
  {#if $edition}
30
30
  <Page title={`${$edition.getTitle()} - Media`}>
31
31
  <Header
32
+ editable={isEditionEditable()}
32
33
  label="Media title"
34
+ id="media"
33
35
  getImage={() => $edition?.getImage(ChapterIDs.MediaID) ?? null}
34
36
  setImage={(embed) =>
35
37
  $edition
@@ -44,11 +46,11 @@ $: unused = images?.filter((image) => embeds.find((embed) => embed.getURL() ===
44
46
  next={$edition.getNextChapterID(ChapterIDs.MediaID)}
45
47
  />
46
48
  </Header>
47
- <Instructions>
48
- This page shows readers an index of the media in the book. Writers
49
- can use this page to manage any images that are linked or uploaded
50
- for this book. Note: images are shared between all editions, so if
51
- you delete one not used in this edition, it might be used in others.
49
+ <Instructions {editable}>
50
+ These are a sequential index of the media in the book. You can use
51
+ this page to manage any images that are linked or uploaded for this
52
+ book. Note: images are shared between all editions, so if you delete
53
+ one not used in this edition, it might be used in others.
52
54
  </Instructions>
53
55
 
54
56
  {#if embeds.length === 0}
@@ -78,16 +80,16 @@ $: unused = images?.filter((image) => embeds.find((embed) => embed.getURL() ===
78
80
  {/each}
79
81
  {#if editable && unused !== undefined && unused.length > 0}
80
82
  <PageHeader id="unused">Unused</PageHeader>
81
- <Instructions>
82
- These images are uploaded to this book, but not used. Delete
83
- them if you don't need them. Note, however, that these images
84
- may be used in other editions of this book.
83
+ <Instructions {editable}>
84
+ These images are uploaded for this book, but not used in this
85
+ edition. Delete them if you don't need them. Warning: images may
86
+ be used in other editions of this book.
85
87
  </Instructions>
86
88
  {#each unused as image}
87
89
  <MediaPreview url={image.url} alt={''}>
88
90
  <span
89
91
  >uploaded <Button
90
- tooltip="delete this unused image"
92
+ tooltip="delete unused image"
91
93
  command={() =>
92
94
  media
93
95
  ?.remove(image)