diff --git a/marko/components/modal/style.less b/marko/components/modal/style.less
index e833695..c5ebfaa 100644
--- a/marko/components/modal/style.less
+++ b/marko/components/modal/style.less
@@ -23,7 +23,9 @@ div.overlay {
label {
display: block;
margin-top: 1em;
+ margin-left: 0.5ch;
font-size: 0.75em;
+ opacity: 0.5;
}
input {
diff --git a/marko/components/toggle/component.js b/marko/components/toggle/component.js
new file mode 100644
index 0000000..a3adbca
--- /dev/null
+++ b/marko/components/toggle/component.js
@@ -0,0 +1,7 @@
+module.exports = class {
+ set(value) {
+ if (value !== this.input.value) {
+ this.emit("change", {target: {value}})
+ }
+ }
+}
\ No newline at end of file
diff --git a/marko/components/toggle/index.marko b/marko/components/toggle/index.marko
new file mode 100644
index 0000000..5973501
--- /dev/null
+++ b/marko/components/toggle/index.marko
@@ -0,0 +1,7 @@
+
+
+
${input.value ? input.onDesc : input.offDesc}
+
\ No newline at end of file
diff --git a/marko/components/toggle/style.less b/marko/components/toggle/style.less
new file mode 100644
index 0000000..5cb5f7b
--- /dev/null
+++ b/marko/components/toggle/style.less
@@ -0,0 +1,27 @@
+div.toggle {
+ div.toggle-pill {
+ display: inline-block;
+ margin: 0.5em;
+ margin-bottom: 0;
+
+ a.toggle-option {
+ padding: 0.125em 0.5ch;
+ display: inline-block;
+ width: 8ch;
+ text-align: center;
+ outline: 0.5px dotted;
+ cursor: pointer;
+ opacity: 0.75;
+ }
+ a.toggle-option.color-highlight-primary {
+ outline: 1px solid;
+ }
+ a.toggle-option:hover {
+ opacity: 1;
+ }
+ }
+
+ div.toggle-content {
+ display: inline-block;
+ }
+}
\ No newline at end of file
diff --git a/marko/page/story-content/components/edit-story-modal/component.js b/marko/page/story-content/components/edit-story-modal/component.js
new file mode 100644
index 0000000..84136d1
--- /dev/null
+++ b/marko/page/story-content/components/edit-story-modal/component.js
@@ -0,0 +1,79 @@
+const moment = require("moment")
+
+const {storyApi} = require("../../../../../rpdata/api/Story")
+
+module.exports = class {
+ onCreate() {
+ this.state = {
+ error: null,
+ values: {
+ name: "",
+ fictionalDate: "",
+ category: "",
+ open: "",
+ listed: "",
+ },
+ loading: false,
+ }
+
+ this.filled = false
+ }
+
+ onInput(input) {
+ if (!this.filled) {
+ this.state.values = {
+ name: input.story.name,
+ category: input.story.category,
+ open: input.story.open,
+ listed: input.story.listed,
+ }
+
+ if (input.story.fictionalDate != null) {
+ this.state.values.fictionalDate = moment.utc(input.story.fictionalDate).format("MMM D, YYYY")
+ }
+
+ this.filled = true
+ }
+ }
+
+ change(key, ev) {
+ this.state.values[key] = ev.target.value
+ this.state.values = Object.assign({}, this.state.values)
+ }
+
+ save() {
+ const values = this.state.values
+
+ let fictionalDate = new Date(values.fictionalDate + " UTC")
+ if (values.fictionalDate != "") {
+ if (Number.isNaN(fictionalDate)) {
+ this.state.error = `Could not parse ${values.fictionalDate} as date`
+ return
+ }
+ } else {
+ fictionalDate = null
+ }
+
+ const input = {id: this.input.story.id, name: values.name, category: values.category, open: values.open, listed: values.listed}
+ if (fictionalDate != null) {
+ input.fictionalDate = fictionalDate
+ } else {
+ input.clearFictionalDate = true
+ }
+
+ this.state.loading = true
+ storyApi.edit(input).then(data => {
+ this.emit("edit", data)
+ this.emit("close")
+ }).catch(errs => {
+ console.warn("Failed to edit:", errs)
+ this.state.error = "Failed to edit: " + errs[0].message
+ }).then(() => {
+ this.state.loading = false
+ })
+ }
+
+ close() {
+ this.emit("close")
+ }
+}
\ No newline at end of file
diff --git a/marko/page/story-content/components/edit-story-modal/index.marko b/marko/page/story-content/components/edit-story-modal/index.marko
new file mode 100644
index 0000000..d2def41
--- /dev/null
+++ b/marko/page/story-content/components/edit-story-modal/index.marko
@@ -0,0 +1,28 @@
+
+ Edit Story
+
+ ${state.error}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/marko/page/story-content/components/page/component.js b/marko/page/story-content/components/page/component.js
index ae1b90b..483bc62 100644
--- a/marko/page/story-content/components/page/component.js
+++ b/marko/page/story-content/components/page/component.js
@@ -15,6 +15,10 @@ module.exports = class {
this.state.modal = null
}
+ updateStory(data) {
+ this.state.story = Object.assign(Object.assign({}, this.state.story), data)
+ }
+
addChapter(chapter) {
this.state.story.chapters.push(chapter)
this.refreshStory()
diff --git a/marko/page/story-content/components/page/index.marko b/marko/page/story-content/components/page/index.marko
index 6f493b5..f3c5b09 100644
--- a/marko/page/story-content/components/page/index.marko
+++ b/marko/page/story-content/components/page/index.marko
@@ -18,5 +18,6 @@
+
\ No newline at end of file
diff --git a/marko/page/story-content/components/page/style.less b/marko/page/story-content/components/page/style.less
index 8afacbf..7f70b4b 100644
--- a/marko/page/story-content/components/page/style.less
+++ b/marko/page/story-content/components/page/style.less
@@ -14,7 +14,6 @@
margin-bottom: 1em;
h1 {
- vertical-align: middle;
display: block;
margin-bottom: 0;
}
diff --git a/marko/page/story-content/view.marko b/marko/page/story-content/view.marko
index f6a78c5..eebd5ab 100644
--- a/marko/page/story-content/view.marko
+++ b/marko/page/story-content/view.marko
@@ -1,6 +1,6 @@
<@body>
-
+
@body>
\ No newline at end of file
diff --git a/middleware/locals.js b/middleware/locals.js
index d4d5720..188c936 100644
--- a/middleware/locals.js
+++ b/middleware/locals.js
@@ -11,6 +11,10 @@ module.exports = (req, res, next) => {
}
}
} catch(err) {
+ if (JSON.stringify(err) === "{}") {
+ return next(err)
+ }
+
return res.status(404).json(err)
}
diff --git a/routes/story-content/index.js b/routes/story-content/index.js
index 59d662d..9ede535 100644
--- a/routes/story-content/index.js
+++ b/routes/story-content/index.js
@@ -8,6 +8,7 @@ const viewTemplate = require("../../marko/page/story-content/view.marko")
module.exports = async(req, res, next) => {
res.markoAsync(viewTemplate, {
story: storyApi.find(req.params.id),
+ categories: storyApi.categories(),
selected: {index: true},
})
}
\ No newline at end of file
diff --git a/rpdata/api/Story.js b/rpdata/api/Story.js
index ac1f20b..65c6a35 100644
--- a/rpdata/api/Story.js
+++ b/rpdata/api/Story.js
@@ -10,17 +10,21 @@ class Story {
* @param {string} name
* @param {string} author
* @param {"Info"|"News"|"Document"|"Background"|"Story"} category Story's category
+ * @param {boolean} listed
+ * @param {boolean} open
* @param {string} createdDate
* @param {string} updatedDate
* @param {string} fictionalDate
* @param {{kind:string, name:string}[]} tags
* @param {Chapter[]} chapters
*/
- constructor(id, name, author, category, createdDate, updatedDate, fictionalDate, tags, chapters) {
+ constructor(id, name, author, category, listed, open, createdDate, updatedDate, fictionalDate, tags, chapters) {
this.id = id
this.name = name
this.author = author
this.category = category
+ this.listed = listed
+ this.open = open
this.createdDate = new Date(createdDate)
this.updatedDate = new Date(updatedDate)
this.fictionalDate = fictionalDate != null ? new Date(fictionalDate) : null
@@ -69,13 +73,15 @@ const storyApi = {
kind
name
}
+ listed
+ open
createdDate
fictionalDate
updatedDate
}
}
`, {filter}).then(({stories}) => {
- return stories.map(d => new Story(d.id, d.name, d.author, d.category, d.createdDate, d.updatedDate, d.fictionalDate, d.tags))
+ return stories.map(d => new Story(d.id, d.name, d.author, d.category, d.listed, d.open, d.createdDate, d.updatedDate, d.fictionalDate, d.tags))
})
},
@@ -95,6 +101,8 @@ const storyApi = {
kind
name
}
+ listed
+ open
createdDate
fictionalDate
updatedDate
@@ -112,6 +120,7 @@ const storyApi = {
`, {id}).then(({story}) => {
return new Story(
story.id, story.name, story.author, story.category,
+ story.listed, story.open,
story.createdDate, story.updatedDate, story.fictionalDate,
story.tags, story.chapters
)
@@ -185,6 +194,30 @@ const storyApi = {
})
},
+ /**
+ * Call `editStory(input)` mutation, returns the changable fields.
+ *
+ * @param {{id:string, name:string, category:string, author:string, open:boolean, listed:boolean, fictionalDate:Date, clearFictionalDate:boolean}} input
+ * @returns {Promise<{id:string, name:string, category:string, author:string, open:boolean, listed:boolean, fictionalDate:Date}>}
+ */
+ edit(input) {
+ return query(`
+ mutation EditStory($input: StoryEditInput!) {
+ editStory(input:$input) {
+ id
+ name
+ category
+ author
+ open
+ listed
+ fictionalDate
+ }
+ }
+ `, {input}, {permissions: ["member", "story.edit"]}).then(({editStory}) => {
+ return editStory
+ })
+ },
+
/**
* Call `removeStory(input)` mutation, returns the id.
*