Files: 752e1d3cb8c1b68e0801e1e9b4d8d4715fcd8409 / app / page / imageSearch.js
3889 bytesRaw
1 | const nest = require('depnest') |
2 | const { h, Dict, Value, watch, throttle, computed, map, onceTrue } = require('mutant') |
3 | |
4 | exports.gives = nest({ |
5 | 'app.page.imageSearch': true, |
6 | 'app.html.menuItem': true |
7 | }) |
8 | |
9 | exports.needs = nest({ |
10 | 'sbot.obs.connection': 'first', |
11 | 'blob.sync.url': 'first', |
12 | 'app.html.modal': 'first', |
13 | 'app.sync.goTo': 'first', |
14 | 'about.obs.name': 'first', |
15 | 'backlinks.obs.for': 'first' |
16 | }) |
17 | |
18 | exports.create = function (api) { |
19 | return nest({ |
20 | 'app.html.menuItem': menuItem, |
21 | 'app.page.imageSearch': searchPage |
22 | }) |
23 | |
24 | function menuItem () { |
25 | return h('a', { |
26 | 'ev-click': () => api.app.sync.goTo('/imageSearch') |
27 | }, '/imageSearch') |
28 | } |
29 | |
30 | function searchPage (location) { |
31 | const query = Value('') |
32 | const results = Dict({}) |
33 | |
34 | watch(throttle(query, 300), q => { |
35 | if (q && q.length < 3) return |
36 | onceTrue(api.sbot.obs.connection, sbot => { |
37 | sbot.meme.search(q, (err, data) => { |
38 | if (err) return console.error(err) |
39 | results.set(data) |
40 | }) |
41 | }) |
42 | }) |
43 | |
44 | const focusedBlob = Value() |
45 | const modal = Modal({ |
46 | results, |
47 | focusedBlob, |
48 | blobUrl: api.blob.sync.url, |
49 | name: api.about.obs.name, |
50 | goTo: api.app.sync.goTo, |
51 | createModal: api.app.html.modal, |
52 | backlinks: api.backlinks.obs.for |
53 | }) |
54 | |
55 | const page = h('Page -imageSearch', [ |
56 | modal, |
57 | h('section.settings', [ |
58 | h('input', { |
59 | 'placeholder': 'search image by name', |
60 | 'ev-input': ev => query.set(ev.target.value) |
61 | }) |
62 | ]), |
63 | h('section.results', computed([results, query], (results, query) => { |
64 | if (!Object.keys(results).length && query.length >= 3) return h('p', '0 results') |
65 | |
66 | return Object.keys(results).map(blob => { |
67 | return h('div', { 'ev-click': () => focusedBlob.set(blob) }, [ |
68 | h('img', { src: api.blob.sync.url(blob) }) |
69 | ]) |
70 | }) |
71 | })) |
72 | ]) |
73 | |
74 | page.title = '/imageSearch' |
75 | |
76 | return page |
77 | } |
78 | } |
79 | |
80 | function Modal ({ results, focusedBlob, blobUrl, name, goTo, createModal, backlinks }) { |
81 | const onClick = (link) => () => { |
82 | isOpen.set(false) |
83 | goTo(link) |
84 | } |
85 | |
86 | const isOpen = Value(false) |
87 | focusedBlob(blob => { |
88 | if (blob) isOpen.set(true) |
89 | }) |
90 | const modalContent = computed([focusedBlob], (blob) => { |
91 | if (!blob) return |
92 | |
93 | const entries = computed(backlinks(blob), msgs => { |
94 | return msgs.reduce((soFar, msg) => { |
95 | const entries = getMentions(msg) |
96 | .filter(mention => mention.link === blob) |
97 | // .filter(mention => mention.name) |
98 | .map(mention => { return { name: mention.name, author: msg.value.author, msg: msg.key, ts: msg.value.timestamp } }) |
99 | return [...soFar, ...entries] |
100 | }, []) |
101 | }) |
102 | |
103 | const imageName = Value('CHOOSE YOUR OWN NAME') |
104 | |
105 | return h('ImageSearchDetails', [ |
106 | h('img', { src: blobUrl(blob) }), |
107 | h('div.md', [ |
108 | 'Copy markdown: ', |
109 | h('pre', ['![', imageName, '](', blob, ')']) |
110 | ]), |
111 | h('table', map(entries, entry => { |
112 | return h('tr', { 'ev-mouseover': () => entry.name && imageName.set(entry.name) }, [ |
113 | h('td', entry.name), |
114 | h('td.msg', h('a', { href: '#', 'ev-click': onClick(entry.msg) }, entry.msg.substring(0, 10) + '...')), |
115 | h('td', h('a', { href: '#', 'ev-click': onClick(entry.author) }, ['@', name(entry.author)])), |
116 | h('td', JSON.stringify(new Date(entry.ts)).substring(1, 11)) // I am a bad human D: |
117 | ]) |
118 | })), |
119 | h('button', { |
120 | 'ev-click': () => { |
121 | focusedBlob.set() |
122 | isOpen.set(false) |
123 | } |
124 | }, 'Close') |
125 | ]) |
126 | }) |
127 | return createModal(modalContent, { isOpen }) |
128 | } |
129 | |
130 | function getMentions (msg) { |
131 | if (!msg.value.content.mentions) return [] |
132 | else if (!Array.isArray(msg.value.content.mentions)) return [msg.value.content.mentions] |
133 | else return msg.value.content.mentions |
134 | } |
135 |
Built with git-ssb-web