bookish-press 0.4.23 → 0.4.24
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/components/Auth.svelte +9 -11
- package/components/BookPreview.svelte +12 -14
- package/components/app/Feedback.svelte +12 -10
- package/components/app/Head.svelte +4 -1
- package/components/app/Head.svelte.d.ts +6 -15
- package/components/app/Paragraph.svelte +1 -0
- package/components/app/{Writing.svelte → Section.svelte} +0 -1
- package/components/app/Section.svelte.d.ts +27 -0
- package/components/app/TextInput.svelte +1 -0
- package/components/chapter/Block.svelte +3 -1
- package/components/chapter/CaptionedCode.svelte +2 -2
- package/components/chapter/ChapterBody.svelte +2 -1
- package/components/chapter/ChapterBody.svelte.d.ts +1 -0
- package/components/chapter/Comment.svelte +2 -2
- package/components/chapter/Embed.svelte +3 -3
- package/components/chapter/Embed.svelte.d.ts +1 -0
- package/components/chapter/Figure.svelte +2 -2
- package/components/chapter/Format.svelte +5 -3
- package/components/chapter/Format.svelte.d.ts +1 -0
- package/components/chapter/InlineCode.svelte +2 -2
- package/components/chapter/Label.svelte +2 -2
- package/components/chapter/Link.svelte +2 -2
- package/components/chapter/Marginal.svelte +2 -2
- package/components/chapter/Paragraph.svelte +5 -0
- package/components/chapter/Table.svelte +2 -2
- package/components/chapter/Text.svelte +2 -2
- package/components/editor/BookishEditor.svelte +51 -28
- package/components/editor/BookishEditor.svelte.d.ts +4 -1
- package/components/editor/CaretView.svelte +3 -1
- package/components/editor/CaretView.svelte.d.ts +1 -0
- package/components/editor/ConfirmButton.svelte +1 -1
- package/components/editor/Note.svelte +1 -0
- package/components/editor/Permissions.svelte +95 -0
- package/components/editor/Permissions.svelte.d.ts +20 -0
- package/components/editor/Toolbar.svelte +0 -1
- package/components/editor/ToolbarGroup.svelte +0 -1
- package/components/page/Acknowledgements.svelte +13 -11
- package/components/page/Authors.svelte +5 -8
- package/components/page/Authors.svelte.d.ts +1 -0
- package/components/page/BookLoader.svelte +59 -0
- package/components/page/BookLoader.svelte.d.ts +16 -0
- package/components/page/BulkReferenceEditor.svelte +8 -8
- package/components/page/Chapter.svelte +43 -10
- package/components/page/Contexts.d.ts +11 -2
- package/components/page/Contexts.js +85 -3
- package/components/page/DefinitionView.svelte +18 -8
- package/components/page/Description.svelte +12 -9
- package/components/page/Edition.svelte +8 -8
- package/components/page/Edition.svelte.d.ts +0 -1
- package/components/page/EditionLoader.svelte +99 -0
- package/components/page/EditionLoader.svelte.d.ts +18 -0
- package/components/page/Editions.svelte +92 -143
- package/components/page/Glossary.svelte +13 -6
- package/components/page/Header.svelte +22 -20
- package/components/page/Header.svelte.d.ts +2 -0
- package/components/page/Index.svelte +6 -4
- package/components/page/Instructions.svelte +1 -2
- package/components/page/Instructions.svelte.d.ts +3 -1
- package/components/page/License.svelte +20 -12
- package/components/page/Media.svelte +14 -12
- package/components/page/Publish.svelte +120 -0
- package/components/page/Publish.svelte.d.ts +14 -0
- package/components/page/Reference.svelte +16 -17
- package/components/page/References.svelte +8 -3
- package/components/page/Search.svelte +3 -1
- package/components/page/Status.svelte +18 -19
- package/components/page/SubdomainEditor.svelte +3 -2
- package/components/page/TableOfContents.svelte +70 -30
- package/components/page/TableOfContentsRow.svelte +4 -4
- package/components/page/ThemeEditor.svelte +8 -5
- package/components/page/Unknown.svelte +5 -2
- package/models/CRUD.d.ts +19 -11
- package/models/CRUD.js +177 -122
- package/models/Firebase.js +12 -8
- package/models/book/Book.d.ts +19 -14
- package/models/book/Book.js +47 -54
- package/models/book/Chapter.d.ts +5 -1
- package/models/book/Chapter.js +24 -15
- package/models/book/Edition.d.ts +31 -7
- package/models/book/Edition.js +101 -32
- package/models/chapter/Parser.d.ts +2 -2
- package/models/chapter/Parser.js +26 -24
- package/package.json +18 -15
- package/components/app/Writing.svelte.d.ts +0 -27
- package/models/loadEdition.d.ts +0 -5
- package/models/loadEdition.js +0 -20
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
<script>import Parser from '../../models/chapter/Parser';
|
|
2
|
+
import BookishEditor from '../editor/BookishEditor.svelte';
|
|
3
|
+
import Switch from '../editor/Switch.svelte';
|
|
4
|
+
import { getAuth, getEdition, getLeasee, isEditionEditable, lease, } from './Contexts';
|
|
5
|
+
import Format from '../chapter/Format.svelte';
|
|
6
|
+
import Note from '../editor/Note.svelte';
|
|
7
|
+
import Instructions from './Instructions.svelte';
|
|
8
|
+
import Link from '../Link.svelte';
|
|
9
|
+
import { PUBLIC_CONTEXT } from '$env/static/public';
|
|
10
|
+
import Button from '../app/Button.svelte';
|
|
11
|
+
import { publish } from '../../models/CRUD';
|
|
12
|
+
import Feedback from '../app/Feedback.svelte';
|
|
13
|
+
let auth = getAuth();
|
|
14
|
+
let edition = getEdition();
|
|
15
|
+
let editable = isEditionEditable();
|
|
16
|
+
let publishing = false;
|
|
17
|
+
let feedback = undefined;
|
|
18
|
+
async function requestPublish() {
|
|
19
|
+
if ($edition) {
|
|
20
|
+
publishing = true;
|
|
21
|
+
feedback = 'Assembling book...';
|
|
22
|
+
try {
|
|
23
|
+
feedback = await publish($edition);
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
console.log(err);
|
|
27
|
+
feedback = 'Unable to publish the book :(';
|
|
28
|
+
}
|
|
29
|
+
finally {
|
|
30
|
+
publishing = false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
let publisher = undefined;
|
|
35
|
+
$: {
|
|
36
|
+
if ($auth && $auth.user)
|
|
37
|
+
updateUserClaims();
|
|
38
|
+
}
|
|
39
|
+
async function updateUserClaims() {
|
|
40
|
+
if ($auth === undefined || $auth.user === null)
|
|
41
|
+
return;
|
|
42
|
+
const token = await $auth.user.getIdTokenResult();
|
|
43
|
+
publisher =
|
|
44
|
+
'publisher' in token.claims && token.claims.publisher === true;
|
|
45
|
+
}
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
{#if $edition && (publisher === true || PUBLIC_CONTEXT === 'local')}
|
|
49
|
+
<Instructions {editable}>
|
|
50
|
+
Ready to publish this edition? Write a summary then hit the switch.
|
|
51
|
+
</Instructions>
|
|
52
|
+
|
|
53
|
+
<div class="publisher">
|
|
54
|
+
<div class="summary">
|
|
55
|
+
<BookishEditor
|
|
56
|
+
text={$edition.summary}
|
|
57
|
+
parser={(text) =>
|
|
58
|
+
Parser.parseFormat(undefined, text).withTextIfEmpty()}
|
|
59
|
+
save={(newSummary) =>
|
|
60
|
+
$edition
|
|
61
|
+
? edition.set(
|
|
62
|
+
$edition.withSummary(newSummary.toBookdown())
|
|
63
|
+
)
|
|
64
|
+
: undefined}
|
|
65
|
+
chapter={false}
|
|
66
|
+
component={Format}
|
|
67
|
+
placeholder="Summarize this edition's changes to publish."
|
|
68
|
+
leasee={getLeasee(auth, edition, 'summary')}
|
|
69
|
+
lease={(lock) => lease(auth, edition, 'summary', lock)}
|
|
70
|
+
/>
|
|
71
|
+
</div>
|
|
72
|
+
<Switch
|
|
73
|
+
options={['hidden', 'published']}
|
|
74
|
+
enabled={$edition.published !== null || $edition.summary.length > 0}
|
|
75
|
+
value={$edition.published !== null ? 'published' : 'hidden'}
|
|
76
|
+
edit={(published) =>
|
|
77
|
+
$edition
|
|
78
|
+
? edition.set(
|
|
79
|
+
$edition.asPublished(published === 'published')
|
|
80
|
+
)
|
|
81
|
+
: undefined}
|
|
82
|
+
/>
|
|
83
|
+
<Button
|
|
84
|
+
tooltip="Publish the book online"
|
|
85
|
+
disabled={publishing}
|
|
86
|
+
command={() => requestPublish()}
|
|
87
|
+
>{publishing ? 'publishing...' : 'publish'}</Button
|
|
88
|
+
>
|
|
89
|
+
</div>
|
|
90
|
+
{#if feedback}
|
|
91
|
+
<Feedback error>{feedback}</Feedback>
|
|
92
|
+
{/if}
|
|
93
|
+
<div>
|
|
94
|
+
<Note
|
|
95
|
+
>{#if $edition.published}Last published {new Date(
|
|
96
|
+
$edition.published
|
|
97
|
+
).toLocaleDateString('en-us')}{/if}</Note
|
|
98
|
+
>
|
|
99
|
+
</div>
|
|
100
|
+
{:else}
|
|
101
|
+
<Instructions {editable}>
|
|
102
|
+
You don't yet have publishing privileges. <Link
|
|
103
|
+
to="mailto:amy@amyjko.com">Write Amy</Link
|
|
104
|
+
> to schedule a chat about your book and ask for publishing privileges.
|
|
105
|
+
</Instructions>
|
|
106
|
+
{/if}
|
|
107
|
+
|
|
108
|
+
<style>
|
|
109
|
+
.publisher {
|
|
110
|
+
display: flex;
|
|
111
|
+
flex-direction: row;
|
|
112
|
+
flex-wrap: nowrap;
|
|
113
|
+
width: 100%;
|
|
114
|
+
align-items: baseline;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.summary {
|
|
118
|
+
flex: 1;
|
|
119
|
+
}
|
|
120
|
+
</style>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
declare const __propDef: {
|
|
3
|
+
props: Record<string, never>;
|
|
4
|
+
events: {
|
|
5
|
+
[evt: string]: CustomEvent<any>;
|
|
6
|
+
};
|
|
7
|
+
slots: {};
|
|
8
|
+
};
|
|
9
|
+
export type PublishProps = typeof __propDef.props;
|
|
10
|
+
export type PublishEvents = typeof __propDef.events;
|
|
11
|
+
export type PublishSlots = typeof __propDef.slots;
|
|
12
|
+
export default class Publish extends SvelteComponentTyped<PublishProps, PublishEvents, PublishSlots> {
|
|
13
|
+
}
|
|
14
|
+
export {};
|
|
@@ -5,12 +5,11 @@ import Button from '../app/Button.svelte';
|
|
|
5
5
|
import Table from '../app/Table.svelte';
|
|
6
6
|
import ConfirmButton from '../editor/ConfirmButton.svelte';
|
|
7
7
|
import TextEditor from '../editor/TextEditor.svelte';
|
|
8
|
-
import { getEdition,
|
|
8
|
+
import { getEdition, isEditionEditable } from './Contexts';
|
|
9
9
|
import Link from '../Link.svelte';
|
|
10
10
|
import Note from '../editor/Note.svelte';
|
|
11
|
-
import Parser from '../../models/chapter/Parser';
|
|
12
11
|
export let reference;
|
|
13
|
-
let editable =
|
|
12
|
+
let editable = isEditionEditable();
|
|
14
13
|
let edition = getEdition();
|
|
15
14
|
let editing = false;
|
|
16
15
|
function startEditing() {
|
|
@@ -94,8 +93,8 @@ function move(field, direction) {
|
|
|
94
93
|
<td>
|
|
95
94
|
<TextEditor
|
|
96
95
|
text={reference.citationID}
|
|
97
|
-
label={'
|
|
98
|
-
placeholder="
|
|
96
|
+
label={'reference ID'}
|
|
97
|
+
placeholder="reference ID"
|
|
99
98
|
saveOnExit
|
|
100
99
|
valid={(text) => {
|
|
101
100
|
if (text.length === 0)
|
|
@@ -128,8 +127,8 @@ function move(field, direction) {
|
|
|
128
127
|
<td>
|
|
129
128
|
<TextEditor
|
|
130
129
|
text={reference.authors}
|
|
131
|
-
label={'
|
|
132
|
-
placeholder="
|
|
130
|
+
label={'author list editor'}
|
|
131
|
+
placeholder="authors"
|
|
133
132
|
valid={(text) => {
|
|
134
133
|
if (text.length === 0) return "Authors can't be empty.";
|
|
135
134
|
}}
|
|
@@ -151,8 +150,8 @@ function move(field, direction) {
|
|
|
151
150
|
<td>
|
|
152
151
|
<TextEditor
|
|
153
152
|
text={reference.year}
|
|
154
|
-
label={'
|
|
155
|
-
placeholder="
|
|
153
|
+
label={'year editor'}
|
|
154
|
+
placeholder="year"
|
|
156
155
|
valid={(text) => {
|
|
157
156
|
if (text.length === 0) return "Year can't be empty";
|
|
158
157
|
if (!/1?[0-9)[0-9]{2}/.test(text))
|
|
@@ -176,8 +175,8 @@ function move(field, direction) {
|
|
|
176
175
|
<td>
|
|
177
176
|
<TextEditor
|
|
178
177
|
text={reference.title}
|
|
179
|
-
label={'
|
|
180
|
-
placeholder="
|
|
178
|
+
label={'title editor'}
|
|
179
|
+
placeholder="title"
|
|
181
180
|
valid={(text) => {
|
|
182
181
|
if (text.length === 0) return "Title can't be empty.";
|
|
183
182
|
}}
|
|
@@ -200,8 +199,8 @@ function move(field, direction) {
|
|
|
200
199
|
<em>
|
|
201
200
|
<TextEditor
|
|
202
201
|
text={reference.source}
|
|
203
|
-
label={'
|
|
204
|
-
placeholder="
|
|
202
|
+
label={'source editor'}
|
|
203
|
+
placeholder="source"
|
|
205
204
|
valid={(text) => {
|
|
206
205
|
if (text.length === 0)
|
|
207
206
|
return "Source can't be empty";
|
|
@@ -225,8 +224,8 @@ function move(field, direction) {
|
|
|
225
224
|
<td>
|
|
226
225
|
<TextEditor
|
|
227
226
|
text={reference.url}
|
|
228
|
-
label={'
|
|
229
|
-
placeholder="
|
|
227
|
+
label={'url editor'}
|
|
228
|
+
placeholder="url"
|
|
230
229
|
valid={() => undefined}
|
|
231
230
|
save={(text) =>
|
|
232
231
|
$edition
|
|
@@ -245,8 +244,8 @@ function move(field, direction) {
|
|
|
245
244
|
<td>
|
|
246
245
|
<TextEditor
|
|
247
246
|
text={reference.summary}
|
|
248
|
-
label={'
|
|
249
|
-
placeholder="
|
|
247
|
+
label={'summary editor'}
|
|
248
|
+
placeholder="summary"
|
|
250
249
|
valid={() => undefined}
|
|
251
250
|
save={(text) =>
|
|
252
251
|
$edition
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
<script>import Header from './Header.svelte';
|
|
2
2
|
import Outline from './Outline.svelte';
|
|
3
3
|
import Page from './Page.svelte';
|
|
4
|
-
import Parser from '../../models/chapter/Parser';
|
|
5
4
|
import ChapterIDs from '../../models/book/ChapterID';
|
|
6
5
|
import BulkReferenceEditor from './BulkReferenceEditor.svelte';
|
|
7
6
|
import PossibleReference from './PossibleReference.svelte';
|
|
8
|
-
import { getEdition,
|
|
7
|
+
import { getAuth, getEdition, isEditionEditable } from './Contexts';
|
|
8
|
+
let auth = getAuth();
|
|
9
9
|
let edition = getEdition();
|
|
10
|
-
let editable =
|
|
10
|
+
let editable = isEditionEditable();
|
|
11
11
|
$: references = $edition?.hasReferences() ? $edition.getReferences() : null;
|
|
12
12
|
// Otherwise, map references to a list with letter headers.
|
|
13
13
|
if (references !== null) {
|
|
@@ -17,7 +17,12 @@ if (references !== null) {
|
|
|
17
17
|
{#if $edition}
|
|
18
18
|
<Page title={`${$edition.getTitle()} - References`}>
|
|
19
19
|
<Header
|
|
20
|
+
editable={isEditionEditable() ||
|
|
21
|
+
($auth !== undefined &&
|
|
22
|
+
$auth.user !== null &&
|
|
23
|
+
$edition.isChapterEditor($auth.user.uid))}
|
|
20
24
|
label="References title"
|
|
25
|
+
id="references"
|
|
21
26
|
getImage={() => $edition?.getImage(ChapterIDs.ReferencesID) ?? null}
|
|
22
27
|
setImage={(embed) =>
|
|
23
28
|
$edition
|
|
@@ -4,7 +4,7 @@ import Page from './Page.svelte';
|
|
|
4
4
|
import Link from '../Link.svelte';
|
|
5
5
|
import Chapter from '../../models/book/Chapter';
|
|
6
6
|
import ChapterIDs from '../../models/book/ChapterID';
|
|
7
|
-
import { getBase, getEdition } from './Contexts';
|
|
7
|
+
import { getBase, getEdition, isEditionEditable } from './Contexts';
|
|
8
8
|
import TextInput from '../app/TextInput.svelte';
|
|
9
9
|
import ChapterTitle from './ChapterTitle.svelte';
|
|
10
10
|
import ChapterNumber from './ChapterNumber.svelte';
|
|
@@ -61,6 +61,7 @@ $: {
|
|
|
61
61
|
{#if $edition}
|
|
62
62
|
<Page title={`${$edition.getTitle()} - Search`}>
|
|
63
63
|
<Header
|
|
64
|
+
editable={isEditionEditable()}
|
|
64
65
|
label="Search title"
|
|
65
66
|
getImage={() => $edition?.getImage(ChapterIDs.SearchID) ?? null}
|
|
66
67
|
setImage={(embed) =>
|
|
@@ -70,6 +71,7 @@ $: {
|
|
|
70
71
|
)
|
|
71
72
|
: undefined}
|
|
72
73
|
header="Search"
|
|
74
|
+
id="search"
|
|
73
75
|
tags={$edition.getTags()}
|
|
74
76
|
>
|
|
75
77
|
<Outline
|
|
@@ -4,11 +4,11 @@ let status = getStatus();
|
|
|
4
4
|
</script>
|
|
5
5
|
|
|
6
6
|
<span
|
|
7
|
-
class={`
|
|
7
|
+
class={`status ${
|
|
8
8
|
$status === BookSaveStatus.Saving
|
|
9
|
-
? '
|
|
9
|
+
? 'saving'
|
|
10
10
|
: $status === BookSaveStatus.Error
|
|
11
|
-
? '
|
|
11
|
+
? 'error'
|
|
12
12
|
: ''
|
|
13
13
|
}`}
|
|
14
14
|
>
|
|
@@ -19,39 +19,38 @@ let status = getStatus();
|
|
|
19
19
|
: $status === BookSaveStatus.Saved
|
|
20
20
|
? '\u2713 Saved'
|
|
21
21
|
: $status === BookSaveStatus.Error
|
|
22
|
-
?
|
|
22
|
+
? '\u2715 Not saved'
|
|
23
23
|
: ''}
|
|
24
24
|
</span>
|
|
25
25
|
|
|
26
26
|
<style>
|
|
27
|
-
.
|
|
28
|
-
color: var(--app-
|
|
27
|
+
.status {
|
|
28
|
+
color: var(--app-font-color-inverted);
|
|
29
29
|
font-family: var(--app-font);
|
|
30
30
|
white-space: nowrap;
|
|
31
|
+
background-color: var(--app-interactive-color);
|
|
32
|
+
padding: calc(var(--app-chrome-padding) / 2);
|
|
33
|
+
border-radius: var(--app-chrome-roundedness);
|
|
31
34
|
}
|
|
32
35
|
|
|
33
|
-
.
|
|
34
|
-
color: var(--app-error-color);
|
|
36
|
+
.error {
|
|
37
|
+
background-color: var(--app-error-color);
|
|
35
38
|
animation: failure 100ms infinite;
|
|
36
39
|
}
|
|
37
40
|
|
|
38
|
-
.
|
|
39
|
-
animation: waiting
|
|
41
|
+
.saving {
|
|
42
|
+
animation: waiting 1s infinite;
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
@keyframes waiting {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
transform: scale(1, 1);
|
|
46
|
-
}
|
|
47
|
-
25% {
|
|
48
|
-
transform: scale(1, 1.2);
|
|
46
|
+
0% {
|
|
47
|
+
transform: rotate(-3deg);
|
|
49
48
|
}
|
|
50
49
|
50% {
|
|
51
|
-
transform:
|
|
50
|
+
transform: rotate(3deg);
|
|
52
51
|
}
|
|
53
|
-
|
|
54
|
-
transform:
|
|
52
|
+
100% {
|
|
53
|
+
transform: rotate(-3deg);
|
|
55
54
|
}
|
|
56
55
|
}
|
|
57
56
|
</style>
|
|
@@ -7,6 +7,7 @@ const invalidNames = [
|
|
|
7
7
|
'email',
|
|
8
8
|
'login',
|
|
9
9
|
'confirm',
|
|
10
|
+
'about',
|
|
10
11
|
'read',
|
|
11
12
|
'write',
|
|
12
13
|
];
|
|
@@ -25,7 +26,7 @@ const invalidNames = [
|
|
|
25
26
|
else throw Error("Domain isn't available");
|
|
26
27
|
}
|
|
27
28
|
}}
|
|
28
|
-
placeholder="
|
|
29
|
+
placeholder="book id"
|
|
29
30
|
valid={(newDomain) =>
|
|
30
31
|
// If not the empty string, must be a valid URL subdomain, and none of the existing routes.
|
|
31
32
|
invalidNames.includes(newDomain) ||
|
|
@@ -33,7 +34,7 @@ const invalidNames = [
|
|
|
33
34
|
!/^[A-Za-z0-9](?:[A-Za-z0-9\-]{0,61}[A-Za-z0-9])?$/.test(
|
|
34
35
|
newDomain
|
|
35
36
|
))
|
|
36
|
-
? `Book
|
|
37
|
+
? `Book IDs must be fewer than 63 characters, made of symbols a-z, A-Z, and 0-9, and not one of ${invalidNames.join(
|
|
37
38
|
', '
|
|
38
39
|
)}.`
|
|
39
40
|
: undefined}
|
|
@@ -10,19 +10,23 @@ import SubdomainEditor from './SubdomainEditor.svelte';
|
|
|
10
10
|
import Description from './Description.svelte';
|
|
11
11
|
import Acknowledgements from './Acknowledgements.svelte';
|
|
12
12
|
import License from './License.svelte';
|
|
13
|
-
import Revisions from './Editions.svelte';
|
|
14
13
|
import Authors from './Authors.svelte';
|
|
15
14
|
import TextEditor from '../editor/TextEditor.svelte';
|
|
16
15
|
import Toggle from '../editor/Toggle.svelte';
|
|
17
|
-
import { getBase, getEdition,
|
|
16
|
+
import { getAuth, getBase, getBook, getEdition, isBookEditable, isEditionEditable, isEditionPartiallyEditable, setChapter, } from './Contexts';
|
|
18
17
|
import Muted from './Muted.svelte';
|
|
19
18
|
import Button from '../app/Button.svelte';
|
|
20
19
|
import PageHeader from './PageHeader.svelte';
|
|
21
20
|
import Rows from './Rows.svelte';
|
|
22
21
|
import PageParagraph from './PageParagraph.svelte';
|
|
22
|
+
import Note from '../editor/Note.svelte';
|
|
23
|
+
import Permissions from '../editor/Permissions.svelte';
|
|
24
|
+
import Publish from './Publish.svelte';
|
|
25
|
+
let auth = getAuth();
|
|
26
|
+
let book = getBook();
|
|
23
27
|
let edition = getEdition();
|
|
24
28
|
let base = getBase();
|
|
25
|
-
let editable =
|
|
29
|
+
let editable = isEditionEditable();
|
|
26
30
|
function getProgressDescription(progress) {
|
|
27
31
|
if (progress === null)
|
|
28
32
|
return '';
|
|
@@ -59,9 +63,10 @@ function addChapter() {
|
|
|
59
63
|
}
|
|
60
64
|
</script>
|
|
61
65
|
|
|
62
|
-
{#if $edition}
|
|
66
|
+
{#if $edition && $book}
|
|
63
67
|
<Page title={$edition.getTitle()}>
|
|
64
68
|
<Header
|
|
69
|
+
editable={isEditionEditable()}
|
|
65
70
|
label="Book title"
|
|
66
71
|
getImage={() => $edition?.getImage('cover') ?? null}
|
|
67
72
|
setImage={(embed) =>
|
|
@@ -69,6 +74,7 @@ function addChapter() {
|
|
|
69
74
|
? edition.set($edition.withImage('cover', embed))
|
|
70
75
|
: undefined}
|
|
71
76
|
header={title}
|
|
77
|
+
id="toc"
|
|
72
78
|
{subtitle}
|
|
73
79
|
tags={$edition.getTags()}
|
|
74
80
|
save={(text) =>
|
|
@@ -84,36 +90,44 @@ function addChapter() {
|
|
|
84
90
|
previous={null}
|
|
85
91
|
next={$edition.getNextChapterID('')}
|
|
86
92
|
/>
|
|
87
|
-
<
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
93
|
+
<div slot="after">
|
|
94
|
+
<Authors
|
|
95
|
+
editable={isBookEditable()}
|
|
96
|
+
authors={$edition.getAuthors()}
|
|
97
|
+
add={() =>
|
|
98
|
+
$edition
|
|
99
|
+
? edition.set($edition.withAuthor(''))
|
|
100
|
+
: undefined}
|
|
101
|
+
edit={(index, text) =>
|
|
102
|
+
$edition
|
|
103
|
+
? edition.set($edition.withAuthorName(index, text))
|
|
104
|
+
: undefined}
|
|
105
|
+
remove={(index) =>
|
|
106
|
+
$edition
|
|
107
|
+
? edition.set($edition.withoutAuthor(index))
|
|
108
|
+
: undefined}
|
|
109
|
+
/>
|
|
110
|
+
{#if $book.getPublishedEditionCount() > 1}
|
|
111
|
+
<Note>{$edition.getEditionLabel()} edition</Note>
|
|
112
|
+
{/if}
|
|
113
|
+
</div>
|
|
101
114
|
</Header>
|
|
102
115
|
|
|
103
|
-
<Instructions>
|
|
104
|
-
|
|
116
|
+
<Instructions {editable}>
|
|
117
|
+
Edit this book's cover image, ID, title, and authors above. The book
|
|
118
|
+
ID appears in the book's URL (e.g., bookish.press/<em>bookid</em>).
|
|
105
119
|
</Instructions>
|
|
106
120
|
|
|
107
121
|
<Description />
|
|
108
122
|
|
|
109
|
-
<Instructions>
|
|
123
|
+
<Instructions {editable}>
|
|
110
124
|
This will appear on the <Link to={$base + 'read'}
|
|
111
125
|
>book browsing</Link
|
|
112
126
|
> page and in your table of contents. Write an informative description
|
|
113
127
|
of what your book is about.
|
|
114
128
|
</Instructions>
|
|
115
129
|
|
|
116
|
-
<Instructions>
|
|
130
|
+
<Instructions {editable}>
|
|
117
131
|
Add, remove, and reorder chapters here. You can add optional book
|
|
118
132
|
sections to each chapter, toggle chapters as numbered/unnumbered or
|
|
119
133
|
published/forthcoming. Click the title to edit the chapter.
|
|
@@ -160,7 +174,7 @@ function addChapter() {
|
|
|
160
174
|
<TextEditor
|
|
161
175
|
label={'Chapter section editor'}
|
|
162
176
|
text={section ? section : ''}
|
|
163
|
-
placeholder="
|
|
177
|
+
placeholder="section"
|
|
164
178
|
valid={() => undefined}
|
|
165
179
|
save={(text) =>
|
|
166
180
|
setChapter(
|
|
@@ -170,6 +184,9 @@ function addChapter() {
|
|
|
170
184
|
)}
|
|
171
185
|
/>
|
|
172
186
|
{:else if section}{section}{/if}
|
|
187
|
+
{#if !editable && $auth !== undefined && $auth.user !== null && chapter.uids.includes($auth.user.uid)}
|
|
188
|
+
You can edit this chapter.
|
|
189
|
+
{/if}
|
|
173
190
|
</span>
|
|
174
191
|
<span slot="etc">
|
|
175
192
|
<Muted>
|
|
@@ -233,9 +250,9 @@ function addChapter() {
|
|
|
233
250
|
|
|
234
251
|
<PageHeader id="print">Print</PageHeader>
|
|
235
252
|
|
|
236
|
-
<Instructions>
|
|
237
|
-
This
|
|
238
|
-
|
|
253
|
+
<Instructions {editable}>
|
|
254
|
+
This link will generate the entire book on a single page, suitable
|
|
255
|
+
for printing.
|
|
239
256
|
</Instructions>
|
|
240
257
|
|
|
241
258
|
<PageParagraph>
|
|
@@ -246,9 +263,8 @@ function addChapter() {
|
|
|
246
263
|
|
|
247
264
|
<PageHeader id="citation">Citation</PageHeader>
|
|
248
265
|
|
|
249
|
-
<Instructions>
|
|
250
|
-
This citation is
|
|
251
|
-
title, and date.
|
|
266
|
+
<Instructions {editable}>
|
|
267
|
+
This citation is created from the current authors, title, and date.
|
|
252
268
|
</Instructions>
|
|
253
269
|
|
|
254
270
|
<!-- Book citation -->
|
|
@@ -264,6 +280,30 @@ function addChapter() {
|
|
|
264
280
|
<em>retrieved {new Date().toLocaleDateString('en-US')}</em>.
|
|
265
281
|
</PageParagraph>
|
|
266
282
|
|
|
267
|
-
|
|
283
|
+
{#if editable}
|
|
284
|
+
<PageHeader id="publish">Publish</PageHeader>
|
|
285
|
+
<Publish />
|
|
286
|
+
{/if}
|
|
287
|
+
|
|
288
|
+
{#if editable || isEditionPartiallyEditable()}
|
|
289
|
+
<PageHeader>Editors</PageHeader>
|
|
290
|
+
<Instructions {editable}>
|
|
291
|
+
These authors can edit this edition and its chapters. To give
|
|
292
|
+
book-level permissions, edit the book editors on the <Link
|
|
293
|
+
to="/write/{$book.ref.id}/editions">editions</Link
|
|
294
|
+
>
|
|
295
|
+
page. To give chapter-level permissions, navigate to the chapter.
|
|
296
|
+
</Instructions>
|
|
297
|
+
<Permissions
|
|
298
|
+
uids={$edition.uids}
|
|
299
|
+
inheriteduids={$book.uids}
|
|
300
|
+
atleastone={false}
|
|
301
|
+
writable={editable}
|
|
302
|
+
change={(uids) =>
|
|
303
|
+
$edition
|
|
304
|
+
? edition.set($edition.withEditors(uids))
|
|
305
|
+
: undefined}
|
|
306
|
+
/>
|
|
307
|
+
{/if}
|
|
268
308
|
</Page>
|
|
269
309
|
{/if}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script>import TableOfContentsImage from './TableOfContentsImage.svelte';
|
|
2
2
|
import Toggle from '../editor/Toggle.svelte';
|
|
3
3
|
import ConfirmButton from '../editor/ConfirmButton.svelte';
|
|
4
|
-
import { getBase, getEdition,
|
|
4
|
+
import { getBase, getEdition, isEditionEditable, setChapter, } from './Contexts';
|
|
5
5
|
import Muted from './Muted.svelte';
|
|
6
6
|
import ChapterNumber from './ChapterNumber.svelte';
|
|
7
7
|
import Button from '../app/Button.svelte';
|
|
@@ -13,7 +13,7 @@ export let number = undefined;
|
|
|
13
13
|
export let forthcoming = false;
|
|
14
14
|
let edition = getEdition();
|
|
15
15
|
let base = getBase();
|
|
16
|
-
let editable =
|
|
16
|
+
let editable = isEditionEditable();
|
|
17
17
|
function moveUp() {
|
|
18
18
|
if ($edition && chapter)
|
|
19
19
|
edition.set($edition.withMovedChapter(chapter.getID(), -1));
|
|
@@ -63,13 +63,13 @@ function moveDown() {
|
|
|
63
63
|
<td class="controls">
|
|
64
64
|
{#if chapter}
|
|
65
65
|
<Button
|
|
66
|
-
tooltip="move chapter up"
|
|
66
|
+
tooltip="move chapter {title} up"
|
|
67
67
|
disabled={$edition.getChapterPosition(chapter.getID()) ===
|
|
68
68
|
0}
|
|
69
69
|
command={moveUp}>{'↑'}</Button
|
|
70
70
|
>
|
|
71
71
|
<Button
|
|
72
|
-
tooltip="move chapter down"
|
|
72
|
+
tooltip="move chapter {title} down"
|
|
73
73
|
disabled={$edition.getChapterPosition(chapter.getID()) ===
|
|
74
74
|
$edition.getChapterCount() - 1}
|
|
75
75
|
command={moveDown}>{'↓'}</Button
|
|
@@ -6,7 +6,7 @@ import ConfirmButton from '../editor/ConfirmButton.svelte';
|
|
|
6
6
|
import Instructions from './Instructions.svelte';
|
|
7
7
|
import ThemeSetEditor from './ThemeSetEditor.svelte';
|
|
8
8
|
import ThemeEditorPreview from './ThemeEditorPreview.svelte';
|
|
9
|
-
import { getEdition } from './Contexts';
|
|
9
|
+
import { getEdition, isEditionEditable } from './Contexts';
|
|
10
10
|
import TextEditor from '../editor/TextEditor.svelte';
|
|
11
11
|
import Button from '../app/Button.svelte';
|
|
12
12
|
import Switch from '../editor/Switch.svelte';
|
|
@@ -20,6 +20,7 @@ const themes = {
|
|
|
20
20
|
Sketchy: SketchyTheme,
|
|
21
21
|
Critical: CriticalTheme,
|
|
22
22
|
};
|
|
23
|
+
let editable = isEditionEditable();
|
|
23
24
|
let edition = getEdition();
|
|
24
25
|
$: theme = $edition ? $edition.getTheme() : null;
|
|
25
26
|
$: isDefault =
|
|
@@ -35,7 +36,9 @@ function getEmptyGroup(group) {
|
|
|
35
36
|
{#if theme && $edition}
|
|
36
37
|
<Page title={`${$edition?.getTitle()} - Theme`}>
|
|
37
38
|
<Header
|
|
39
|
+
editable={isEditionEditable()}
|
|
38
40
|
label="Theme"
|
|
41
|
+
id="theme"
|
|
39
42
|
getImage={() => null}
|
|
40
43
|
setImage={() => undefined}
|
|
41
44
|
header="Theme"
|
|
@@ -43,7 +46,7 @@ function getEmptyGroup(group) {
|
|
|
43
46
|
<Outline slot="outline" previous={null} next={null} />
|
|
44
47
|
</Header>
|
|
45
48
|
|
|
46
|
-
<Instructions>
|
|
49
|
+
<Instructions {editable}>
|
|
47
50
|
This is the theme editor. You can use it to choose from existing
|
|
48
51
|
themes or create a custom theme for your book's appearance. To use
|
|
49
52
|
it, you'll need to know a bit about how to format CSS <Link
|
|
@@ -83,7 +86,7 @@ function getEmptyGroup(group) {
|
|
|
83
86
|
>
|
|
84
87
|
{:else}
|
|
85
88
|
<ConfirmButton
|
|
86
|
-
tooltip="
|
|
89
|
+
tooltip="change theme to the default"
|
|
87
90
|
commandLabel="- theme"
|
|
88
91
|
confirmLabel="delete your theme?"
|
|
89
92
|
command={() =>
|
|
@@ -139,7 +142,7 @@ function getEmptyGroup(group) {
|
|
|
139
142
|
</td>
|
|
140
143
|
<td style="text-align:right;">
|
|
141
144
|
<Button
|
|
142
|
-
tooltip="
|
|
145
|
+
tooltip="add CSS URL import"
|
|
143
146
|
command={() => {
|
|
144
147
|
if (theme === null) return;
|
|
145
148
|
if (theme.imports === undefined)
|
|
@@ -171,7 +174,7 @@ function getEmptyGroup(group) {
|
|
|
171
174
|
</td>
|
|
172
175
|
<td style="text-align: right">
|
|
173
176
|
<Button
|
|
174
|
-
tooltip="Remove
|
|
177
|
+
tooltip="Remove CSS URL import"
|
|
175
178
|
command={() => {
|
|
176
179
|
theme?.imports?.splice(index, 1);
|
|
177
180
|
if ($edition)
|