story-content: Added tag add/remove modal
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
const moment = require("moment")
|
||||
|
||||
const {storyApi} = require("../../../../../rpdata/api/Story")
|
||||
|
||||
module.exports = class {
|
||||
onCreate(input) {
|
||||
this.state = {
|
||||
error: null,
|
||||
loading: false,
|
||||
}
|
||||
}
|
||||
|
||||
change(key, ev) {
|
||||
this.state.values[key] = ev.target.value
|
||||
}
|
||||
|
||||
close() {
|
||||
this.emit("close")
|
||||
}
|
||||
|
||||
addTag(tag) {
|
||||
this.state.error = null
|
||||
|
||||
storyApi.addTag({id: this.input.story.id, tag}).then(({tags}) => {
|
||||
this.emit("tags", tags)
|
||||
}).catch(errs => {
|
||||
this.state.error = errs.message || errs[0].message || "Add tag failed"
|
||||
})
|
||||
}
|
||||
|
||||
removeTag(tag) {
|
||||
this.state.error = null
|
||||
|
||||
storyApi.removeTag({id: this.input.story.id, tag}).then(({tags}) => {
|
||||
this.emit("tags", tags)
|
||||
}).catch(errs => {
|
||||
this.state.error = errs.message || errs[0].message || "Remove tag failed"
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<modal class="modal color-text nolabel" key="modal2" enabled=(input.enabled) closable on-close("close") >
|
||||
<h1>Edit Tags</h1>
|
||||
|
||||
<p key="error" class="color-error">${state.error}</p>
|
||||
|
||||
<story-tag-options tags=input.story.tags loading=state.loading on-remove("removeTag") on-add("addTag") />
|
||||
</modal>
|
||||
@@ -48,8 +48,6 @@ module.exports = class {
|
||||
}
|
||||
|
||||
menuSelect(kind, id) {
|
||||
console.log(kind, id)
|
||||
|
||||
switch (kind) {
|
||||
case "add":
|
||||
this.open("chapter.add")
|
||||
@@ -57,6 +55,11 @@ module.exports = class {
|
||||
}
|
||||
}
|
||||
|
||||
updateStoryTags(tags) {
|
||||
this.state.story.tags = tags
|
||||
this.refreshStory()
|
||||
}
|
||||
|
||||
refreshStory() {
|
||||
this.state.story = Object.assign({}, this.state.story)
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
<main>
|
||||
<div class="story-content">
|
||||
<h1 class="color-primary">${state.story.name}</h1>
|
||||
<story-tags tags=state.story.tags />
|
||||
<story-tags tags=state.story.tags on-select("open", "story.tags")/>
|
||||
<chapter for(chapter in state.story.chapters) key=chapter.id chapter=chapter on-edit("updateChapter", chapter.id) on-remove("removeChapter", chapter.id)/>
|
||||
</div>
|
||||
|
||||
<create-chapter-modal storyId=state.story.id enabled=(state.modal === "chapter.add") chapter=input.chapter on-close("close") on-add("addChapter") />
|
||||
|
||||
<edit-story-tags-modal enabled=(state.modal === "story.tags") story=state.story on-tags("updateStoryTags") on-close("close") />
|
||||
</main>
|
||||
@@ -0,0 +1,62 @@
|
||||
const {tagApi} = require("../../../../../rpdata/api/Tag")
|
||||
|
||||
module.exports = class {
|
||||
onCreate() {
|
||||
this.state = {
|
||||
values: {
|
||||
name: "",
|
||||
kind: "Event",
|
||||
},
|
||||
tags: [],
|
||||
suggestions: [],
|
||||
}
|
||||
}
|
||||
|
||||
onMount() {
|
||||
tagApi.list().then(list => {
|
||||
this.state.tags = list
|
||||
}).catch(err => {})
|
||||
|
||||
this.getEl("name").addEventListener("keydown", ev => {
|
||||
setTimeout(() => {
|
||||
const name = this.getEl("name").value
|
||||
const kind = this.getEl("kind").value
|
||||
const search = name.toLowerCase()
|
||||
|
||||
this.state.values = {name, kind}
|
||||
this.state.suggestions = []
|
||||
|
||||
const suggestions = this.state.tags.filter(t => t.name.toLowerCase().includes(search))
|
||||
if (suggestions.length > 0 && suggestions.length < 10) {
|
||||
if (suggestions.length > 1 || suggestions[0].name !== name) {
|
||||
this.state.suggestions = suggestions
|
||||
}
|
||||
}
|
||||
}, 100)
|
||||
})
|
||||
}
|
||||
|
||||
add(tag) {
|
||||
this.state.values = {
|
||||
kind: "Event",
|
||||
name: "",
|
||||
}
|
||||
|
||||
this.emit("add", tag)
|
||||
}
|
||||
|
||||
change(key, ev) {
|
||||
const value = ev.target.value
|
||||
|
||||
this.state.values[key] = value
|
||||
}
|
||||
|
||||
applySuggestion(tag) {
|
||||
this.state.values = {
|
||||
name: tag.name,
|
||||
kind: tag.kind,
|
||||
}
|
||||
|
||||
this.state.suggestions = []
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<div class="tag-options">
|
||||
<input key="name" placeholder="Name" class="big" on-change("change", "name") value=state.values.name />
|
||||
<select key="kind" placeholder="Kind" class="big" on-change("change", "kind") value=state.values.kind>
|
||||
<option value="Character" selected=(state.values.kind === "Character")>Character</option>
|
||||
<option value="Event" selected=(state.values.kind === "Event")>Event</option>
|
||||
<option value="Location" selected=(state.values.kind === "Location")>Location</option>
|
||||
<option value="Organization" selected=(state.values.kind === "Organization")>Organization</option>
|
||||
<option value="Series" selected=(state.values.kind === "Series")>Series</option>
|
||||
</select>
|
||||
<div class="suggestion-list" if(state.suggestions.length > 0)>
|
||||
<div class="header color-menu">Suggestions:</div>
|
||||
<a for(tag in state.suggestions) on-click("applySuggestion", tag) class=["tag", "color-tag-" + tag.kind.toLowerCase()]>${tag.name}</a>
|
||||
</div>
|
||||
|
||||
<button disabled=(input.loading) on-click("add", state.values)>Add</button>
|
||||
|
||||
<div for(tag in (input.tags || [])) class="tag" key=(tag.kind+":"+tag.name)>
|
||||
<div class=("content color-tag-"+tag.kind.toLowerCase())>${tag.name}</div>
|
||||
<button on-click("emit", "remove", tag)>Remove</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,46 @@
|
||||
div.tag-options {
|
||||
div.tag {
|
||||
padding: 0.25em;
|
||||
border-bottom: 1px solid rgba(0, 220, 255, 0.125);
|
||||
|
||||
div.content {
|
||||
width: 80%;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
button {
|
||||
width: 20%;
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
div.suggestion-list {
|
||||
margin-top: 1em;
|
||||
|
||||
a.tag {
|
||||
display: inline-block;
|
||||
margin: 0.5em 0.5ch;
|
||||
padding: 0.0625em 0.5ch;
|
||||
|
||||
outline: 1px solid;
|
||||
opacity: 0.75;
|
||||
|
||||
user-select: none;
|
||||
}
|
||||
a.tag:hover {
|
||||
opacity: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
div.header {
|
||||
display: inline-block;
|
||||
margin: 0.5em 0.5ch;
|
||||
padding: 0.0625em 0.5ch;
|
||||
|
||||
opacity: 0.5;
|
||||
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
module.exports = class {
|
||||
select(kind) {
|
||||
this.emit("select", kind)
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
<div class="story-tags">
|
||||
<a for(tag in input.tags) href=("/story/by-tag/" + tag.kind + "/" + encodeURIComponent(tag.name)) class=["tag", "color-tag-" + tag.kind.toLowerCase()]>${tag.name}</a>
|
||||
<a on-click("select", "edit") class="option color-menu">Edit</a>
|
||||
</div>
|
||||
@@ -17,4 +17,18 @@ div.story-tags {
|
||||
opacity: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
a.option {
|
||||
display: inline-block;
|
||||
margin: 0.5em 0.5ch;
|
||||
padding: 0.0625em 0.5ch;
|
||||
|
||||
opacity: 0.5;
|
||||
|
||||
user-select: none;
|
||||
}
|
||||
a.option:hover {
|
||||
opacity: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user