git ssb

3+

arj / patchbook



Tree: 59b2150aa65f622113a8aae8016eb849a7345690

Files: 59b2150aa65f622113a8aae8016eb849a7345690 / book / html / layout / detail.js

5642 bytesRaw
1const nest = require('depnest')
2const { h, when, computed, Value } = require('mutant')
3var htmlEscape = require('html-escape')
4const addSuggest = require('suggest-box')
5
6exports.needs = nest({
7 'book.obs.book': 'first',
8 'about.html.image': 'first',
9 'about.obs.name': 'first',
10 'keys.sync.id': 'first',
11 'emoji.async.suggest': 'first',
12 'emoji.sync.url': 'first',
13 'message.html': {
14 'markdown': 'first'
15 },
16 'book.html': {
17 'title': 'first',
18 'authors': 'first',
19 'description': 'first',
20 'images': 'first'
21 }
22})
23
24exports.gives = nest('book.html.layout')
25
26exports.create = (api) => {
27 return nest('book.html.layout', bookLayout)
28
29 function renderEmoji (emoji, url) {
30 if (!url) return ':' + emoji + ':'
31 return `
32 <img
33 src="${htmlEscape(url)}"
34 alt=":${htmlEscape(emoji)}:"
35 title=":${htmlEscape(emoji)}:"
36 class="emoji"
37 >
38 `
39 }
40
41 function simpleMarkdown(text) {
42 if (text.startsWith(':'))
43 return renderEmoji(text, api.emoji.sync.url(text.match(/:([^:]*)/)[1]))
44 else
45 return text
46 }
47
48 function ratingEdit(isEditing, value) {
49 return when(isEditing,
50 h('input', {'ev-input': e => value.set(e.target.value), value: value,
51 placeholder: 'your rating' }),
52 h('span.text', { innerHTML: computed(value, simpleMarkdown) }))
53 }
54
55 function ratingTypeEdit(isEditing, value) {
56 let getEmojiSuggestions = api.emoji.async.suggest()
57
58 let ratingTypeInput = h('input', {'ev-input': e => value.set(e.target.value),
59 value: value, placeholder: 'rating type' })
60
61 let suggestWrapper = h('span.ratingType', ratingTypeInput)
62
63 addSuggest(ratingTypeInput, (inputText, cb) => {
64 if (inputText[0] === ':') {
65 cb(null, getEmojiSuggestions(inputText.slice(1)))
66 }
67 }, {cls: 'PatchSuggest'})
68
69 return when(isEditing, suggestWrapper,
70 h('span.text', { innerHTML: computed(value, simpleMarkdown) }))
71 }
72
73 function simpleEdit(isEditing, name, value) {
74 return h('div', { classList: when(computed([value, isEditing], (v, e) => { return v || e }),
75 '-expanded', '-contracted') },
76 [h('span', name + ':'),
77 when(isEditing,
78 h('input', {'ev-input': e => value.set(e.target.value), value: value }),
79 h('span', value))])
80
81 }
82
83 function textEdit(isEditing, name, value) {
84 const markdown = api.message.html.markdown
85 const input = h('textarea', {'ev-input': e => value.set(e.target.value), value: value })
86
87 return h('div', { classList: when(computed([value, isEditing], (v, e) => { return v || e }),
88 '-expanded', '-contracted') },
89 [h('div', name + ':'),
90 when(isEditing, input, computed(value, markdown))])
91 }
92
93 function bookLayout (msg, opts) {
94 if (!(opts.layout === undefined || opts.layout === 'detail')) return
95
96 const { obs, isEditing, isCard } = opts
97
98 const { title, authors, description, images } = api.book.html
99
100 let isEditingSubjective = Value(false)
101 let reviews = []
102
103 return [h('Message -book-detail', [
104 title({ title: obs.title, msg, isEditing, onUpdate: obs.title.set }),
105 authors({authors: obs.authors, isEditing, onUpdate: obs.authors.set}),
106 h('section.content', [
107 images({images: obs.images, isEditing, onUpdate: obs.images.add }),
108 h('section.description',
109 description({description: obs.description, isEditing, onUpdate: obs.description.set})),
110 ]),
111 h('section.actions', [
112 h('button.edit', { 'ev-click': () => isEditing.set(!isEditing()) },
113 when(isEditing, 'Cancel', 'Edit book')),
114 when(isEditing, h('button', {'ev-click': () => saveBook(obs)}, 'Update book'))
115 ]),
116 h('section.subjective', [
117 computed(obs.subjective, subjectives => {
118 let i = 0;
119 Object.keys(subjectives).forEach(user => {
120 if (i++ < reviews.length) return
121 let subjective = obs.subjective.get(user)
122 let isMe = Value(api.keys.sync.id() == user)
123 let isOwnEditingSubj = computed([isEditingSubjective, isMe],
124 (e, me) => { return e && me })
125 reviews.push([
126 h('section', [api.about.html.image(user),
127 when(computed([subjective.rating, isEditingSubjective],
128 (v, e) => { return v || e }),
129 h('span.text', [api.about.obs.name(user), ' rated '])),
130 ratingEdit(isOwnEditingSubj, subjective.rating),
131 ratingTypeEdit(isOwnEditingSubj, subjective.ratingType)]),
132 simpleEdit(isOwnEditingSubj, 'Shelve', subjective.shelve),
133 simpleEdit(isOwnEditingSubj, 'Genre', subjective.genre),
134 textEdit(isOwnEditingSubj, 'Review', subjective.review)
135 ])
136 })
137
138 return reviews
139 })
140 ]),
141 h('section.actions', [
142 h('button.subjective', { 'ev-click': () => isEditingSubjective.set(!isEditingSubjective()) },
143 when(isEditingSubjective, 'Cancel', 'Edit rating')),
144 when(isEditingSubjective, h('button', { 'ev-click': () => saveSubjective(obs) }, 'Update rating'))
145 ]),
146 ])]
147
148 function saveBook(obs) {
149 obs.amend()
150
151 isEditing.set(false)
152 }
153
154 function saveSubjective(obs) {
155 obs.updateSubjective()
156
157 isEditingSubjective.set(false)
158 }
159 }
160}
161

Built with git-ssb-web