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