git ssb

3+

arj / patchbook



Tree: bd040e587da9831443f9a4542c1a318f354a7487

Files: bd040e587da9831443f9a4542c1a318f354a7487 / book / html / layout / detail.js

3987 bytesRaw
1const nest = require('depnest')
2const { h, when, computed } = require('mutant')
3var htmlEscape = require('html-escape')
4
5exports.needs = nest({
6 'book.obs.book': 'first',
7 'about.html.image': 'first',
8 'about.obs.name': 'first',
9 'emoji.sync.url': 'first',
10 'message.html': {
11 'markdown': 'first'
12 },
13 'book.html': {
14 'title': 'first',
15 'authors': 'first',
16 'description': 'first',
17 'images': 'first'
18 }
19})
20
21exports.gives = nest('book.html.layout')
22
23exports.create = (api) => {
24 return nest('book.html.layout', bookLayout)
25
26 function renderEmoji (emoji, url) {
27 if (!url) return ':' + emoji + ':'
28 return `
29 <img
30 src="${htmlEscape(url)}"
31 alt=":${htmlEscape(emoji)}:"
32 title=":${htmlEscape(emoji)}:"
33 class="emoji"
34 >
35 `
36 }
37
38 function simpleMarkdown(text) {
39 if (text.startsWith(':'))
40 return renderEmoji(text, api.emoji.sync.url(text.match(/:([^:]*)/)[1]))
41 else
42 return text
43 }
44
45 function valueEdit(isEditing, value) {
46 return when(isEditing,
47 h('input', {'ev-input': e => value.set(e.target.value), value: value }),
48 h('span', { innerHTML: computed(value, simpleMarkdown) }))
49
50 }
51
52 function simpleEdit(isEditing, name, value) {
53 return h('div', { classList: when(computed([value, isEditing], (v, e) => { return v || e }),
54 '-expanded', '-contracted') },
55 [h('span', name + ':'),
56 when(isEditing,
57 h('input', {'ev-input': e => value.set(e.target.value), value: value }),
58 h('span', value))])
59
60 }
61
62 function textEdit(isEditing, name, value) {
63 const markdown = api.message.html.markdown
64 const input = h('textarea', {'ev-input': e => value.set(e.target.value), value: value() })
65
66 return h('div', { classList: when(computed([value, isEditing], (v, e) => { return v || e }),
67 '-expanded', '-contracted') },
68 [h('div', name + ':'),
69 when(isEditing, input, computed(value, markdown))])
70 }
71
72 function bookLayout (msg, opts) {
73 if (!(opts.layout === undefined || opts.layout === 'detail')) return
74
75 const { obs, isEditing, isCard } = opts
76
77 const { title, authors, description, images } = api.book.html
78
79 let reviews = []
80
81 return h('Message -book-detail', [
82 title({ title: obs.title, msg, isEditing, onUpdate: obs.title.set }),
83 authors({authors: obs.authors, isEditing, onUpdate: obs.authors.set}),
84 h('section.content', [
85 images({images: obs.images, isEditing, onUpdate: obs.images.add }),
86 h('section.description',
87 description({description: obs.description, isEditing, onUpdate: obs.description.set})),
88 ]),
89 h('section.subjective', [
90 computed(obs.subjective, subjectives => {
91 let i = 0;
92 Object.keys(subjectives).forEach(user => {
93 if (i++ < reviews.length) return
94 let subjective = obs.subjective.get(user)
95 reviews.push([
96 h('section', [api.about.html.image(user),
97 h('span', [api.about.obs.name(msg.value.author), ' rated ']),
98 valueEdit(isEditing, subjective.rating),
99 valueEdit(isEditing, subjective.ratingType)]),
100 simpleEdit(isEditing, 'Shelve', subjective.shelve),
101 simpleEdit(isEditing, 'Genre', subjective.genre),
102 textEdit(isEditing, 'Review', subjective.review)
103 ])
104 })
105
106 return reviews
107 })
108 ]),
109 h('section.actions', [
110 h('button.edit', { 'ev-click': () => isEditing.set(!isEditing()) },
111 when(isEditing, 'Cancel', 'Edit')),
112 when(isEditing, h('button', {'ev-click': () => save(obs)}, 'Update'))
113 ])
114 ])
115
116 function save (obs) {
117 // FIXME: check if anything changed
118 obs.amend()
119
120 isEditing.set(false)
121 }
122 }
123}
124

Built with git-ssb-web