Commit 4f38a991eff961ff071507e747fd5dba7a2a5e94
Merge branch 'master' of github.com:ssbc/patchbay into npm-dependency-updates
Christian Bundy committed on 10/19/2018, 7:43:06 PMParent: c5835557d006a50602b898335246296708f5138a
Parent: 2ed843ec43ce4c8195cf646b049ce93812ab2a5e
Files changed
about/html/avatar.js | changed |
about/html/avatar.mcss | changed |
about/pull/updates.js | added |
app/html/modal.mcss | changed |
app/html/scroller.js | changed |
app/html/search-bar.js | changed |
app/page/blob.mcss | changed |
app/page/notifications.js | changed |
app/page/query.js | changed |
app/page/thread.js | changed |
app/page/thread.mcss | changed |
app/styles/mcss/button.mcss | changed |
app/styles/mcss/marama.js | changed |
app/styles/mcss/markdown.mcss | changed |
main.js | changed |
message/html/compose.js | changed |
message/html/compose.mcss | changed |
message/html/confirm.js | changed |
message/html/decorate/data-root.js | changed |
message/html/layout/default.mcss | changed |
message/html/layout/mini.js | changed |
message/html/layout/mini.mcss | changed |
package-lock.json | changed |
package.json | changed |
router/async/normalise.js | changed |
router/sync/routes.js | changed |
about/html/avatar.js | |||
---|---|---|---|
@@ -13,17 +13,20 @@ | |||
13 | 13 … | ||
14 | 14 … | exports.create = function (api) { | |
15 | 15 … | return nest('about.html.avatar', avatar) | |
16 | 16 … | ||
17 | - function avatar (id) { | ||
17 … | + function avatar (id, size = 4) { | ||
18 | 18 … | const src = api.about.obs.imageUrl(id) | |
19 | 19 … | const color = computed(src, src => src.match(/^http/) ? 'rgba(0,0,0,0)' : api.about.obs.color(id)) | |
20 | 20 … | ||
21 | - return api.about.html.link(id, | ||
21 … | + const avatar = api.about.html.link(id, | ||
22 | 22 … | h('img', { | |
23 | - className: 'Avatar', | ||
24 | 23 … | style: { 'background-color': color }, | |
25 | 24 … | src | |
26 | 25 … | }) | |
27 | 26 … | ) | |
27 … | + avatar.classList.add('Avatar') | ||
28 … | + avatar.style.setProperty('--avatar-size', isNaN(size) ? size : `${size}rem`) | ||
29 … | + | ||
30 … | + return avatar | ||
28 | 31 … | } | |
29 | 32 … | } |
about/html/avatar.mcss | ||
---|---|---|
@@ -1,6 +1,13 @@ | ||
1 | 1 … | Avatar { |
2 | - width: 4rem | |
3 | - height: 4rem | |
2 … | + --avatar-size: 4rem | |
4 | 3 … | |
4 … | + width: var(--avatar-size) | |
5 … | + height: var(--avatar-size) | |
6 … | + | |
5 | 7 … | transition: background-color .15s ease-out |
8 … | + | |
9 … | + img { | |
10 … | + width: var(--avatar-size) | |
11 … | + height: var(--avatar-size) | |
12 … | + } | |
6 | 13 … | } |
about/pull/updates.js | ||
---|---|---|
@@ -1,0 +1,65 @@ | ||
1 … | +const nest = require('depnest') | |
2 … | +const pull = require('pull-stream') | |
3 … | +const Notify = require('pull-notify') | |
4 … | +const { isMsg, isFeed } = require('ssb-ref') | |
5 … | + | |
6 … | +exports.gives = nest('about.pull.updates') | |
7 … | + | |
8 … | +exports.needs = nest({ | |
9 … | + 'keys.sync.id': 'first', | |
10 … | + 'message.obs.likes': 'first', | |
11 … | + 'sbot.pull.stream': 'first' | |
12 … | +}) | |
13 … | + | |
14 … | +exports.create = (api) => { | |
15 … | + const cache = {} | |
16 … | + var listening = false | |
17 … | + | |
18 … | + return nest('about.pull.updates', updates) | |
19 … | + | |
20 … | + function updates (key) { | |
21 … | + if (!(isMsg(key) || isFeed(key))) throw new Error(`about.pull.updates expects a valid message/ feed key, got ${key}`) | |
22 … | + startListening() | |
23 … | + | |
24 … | + if (!cache[key]) cache[key] = Notify() | |
25 … | + return cache[key].listen() | |
26 … | + } | |
27 … | + | |
28 … | + function startListening () { | |
29 … | + if (listening) return | |
30 … | + | |
31 … | + const opts = { | |
32 … | + live: true, | |
33 … | + old: false, | |
34 … | + query: [{ | |
35 … | + $filter: { | |
36 … | + value: { | |
37 … | + timestamp: { $gt: 0 }, | |
38 … | + content: { | |
39 … | + type: 'about', | |
40 … | + about: { $truthy: true } | |
41 … | + } | |
42 … | + } | |
43 … | + } | |
44 … | + }, { | |
45 … | + $map: { | |
46 … | + about: ['value', 'content', 'about'] | |
47 … | + } | |
48 … | + }] | |
49 … | + } | |
50 … | + pull( | |
51 … | + api.sbot.pull.stream(server => server.query.read(opts)), | |
52 … | + pull.filter(m => !m.sync), | |
53 … | + pull.drain( | |
54 … | + ({ about }) => { | |
55 … | + if (!cache[about]) return | |
56 … | + | |
57 … | + cache[about](1) // emit a minimal update! | |
58 … | + }, | |
59 … | + (err) => console.error(err) | |
60 … | + ) | |
61 … | + ) | |
62 … | + | |
63 … | + listening = true | |
64 … | + } | |
65 … | +} |
app/html/modal.mcss | ||
---|---|---|
@@ -1,29 +1,32 @@ | ||
1 | 1 … | Modal { |
2 | - display: flex | |
3 | - flex-direction: row | |
4 | 2 … | position: fixed |
5 | - z-index: 90 | |
6 | - | |
7 | 3 … | top: var(--app-border-width) |
8 | 4 … | bottom: var(--app-border-width) |
9 | 5 … | left: var(--app-border-width) |
10 | 6 … | right: var(--app-border-width) |
7 … | + z-index: 90 | |
8 … | + | |
11 | 9 … | background: rgba(15, 0, 25, 0.78) |
12 | 10 … | |
11 … | + display: grid | |
12 … | + justify-content: center | |
13 … | + align-content: center | |
14 … | + | |
13 | 15 … | div.content { |
14 | 16 … | max-width: 90vw |
15 | 17 … | max-height: 90vh |
16 | 18 … | overflow: auto |
17 | 19 … | |
18 | 20 … | $backgroundPrimary |
19 | 21 … | box-shadow: rgba(0,0,0,.34) 2px 6px 10px |
20 | - margin: auto | |
22 … | + margin: calc(var(--app-border-width) + 2.3rem) auto var(--app-border-width) auto | |
23 … | + /* 2.3rem is height of Hypertabs > nav */ | |
21 | 24 … | $dontSelect |
22 | 25 … | } |
23 | 26 … | |
24 | 27 … | -open { |
25 | - display: flex | |
28 … | + display: grid | |
26 | 29 … | } |
27 | 30 … | |
28 | 31 … | -close { |
29 | 32 … | display: none |
app/html/scroller.js | ||
---|---|---|
@@ -6,18 +6,18 @@ | ||
6 | 6 … | exports.create = function (api) { |
7 | 7 … | return nest('app.html.scroller', Scroller) |
8 | 8 … | |
9 | 9 … | function Scroller (opts = {}) { |
10 | - const { prepend = [], content = null, append = [], classList = [], className = '', title = '' } = opts | |
10 … | + const { prepend, content = null, append, classList = [], className = '', title = '' } = opts | |
11 | 11 … | |
12 | 12 … | const contentSection = h('section.content', { title: '' }, content) |
13 | 13 … | |
14 | 14 … | const container = h('Scroller', |
15 | 15 … | { classList, className, title, style: { 'overflow-y': 'scroll', 'overflow-x': 'auto' } }, |
16 | 16 … | [ |
17 | - h('section.top', prepend), | |
17 … | + prepend ? h('section.top', prepend) : null, | |
18 | 18 … | contentSection, |
19 | - h('section.bottom', append) | |
19 … | + append ? h('section.bottom', append) : null | |
20 | 20 … | ] |
21 | 21 … | ) |
22 | 22 … | |
23 | 23 … | container.scroll = keyscroll(contentSection) |
@@ -46,13 +46,14 @@ | ||
46 | 46 … | } |
47 | 47 … | } |
48 | 48 … | |
49 | 49 … | return function scroll (d) { |
50 | - selectChild((!curMsgEl || d === 'first') ? content.firstChild | |
50 … | + const child = (!curMsgEl || d === 'first') ? content.firstChild | |
51 | 51 … | : (!curMsgEl || d === 'last') ? content.lastChild |
52 | 52 … | : d < 0 ? curMsgEl.previousElementSibling || content.firstChild |
53 | 53 … | : d > 0 ? curMsgEl.nextElementSibling || content.lastChild |
54 | - : curMsgEl) | |
54 … | + : curMsgEl | |
55 … | + selectChild(child) | |
55 | 56 … | |
56 | 57 … | return curMsgEl |
57 | 58 … | } |
58 | 59 … |
app/html/search-bar.js | ||
---|---|---|
@@ -67,15 +67,15 @@ | ||
67 | 67 … | |
68 | 68 … | if (char === '@') api.about.async.suggest(word, cb) |
69 | 69 … | if (char === '#') api.channel.async.suggest(word, cb) |
70 | 70 … | if (char === '/') cb(null, getPagesSuggestions(word)) |
71 | - }, {cls: 'PatchSuggest'}) | |
71 … | + }, { cls: 'PatchSuggest' }) | |
72 | 72 … | |
73 | 73 … | // TODO extract |
74 | 74 … | function getPagesSuggestions (word) { |
75 | 75 … | const pages = [ |
76 | 76 … | 'blogs', 'calendar', 'posts', 'public', 'private', 'inbox', 'profile', 'notifications', 'settings', |
77 | - 'gatherings', 'chess', 'books', 'imageSearch', 'polls', 'query', 'dark-crystal', 'postRank' | |
77 … | + 'gatherings', 'chess', 'books', 'imageSearch', 'polls', 'query', 'dark-crystal', 'postRank', 'scry/new' | |
78 | 78 … | ] |
79 | 79 … | |
80 | 80 … | return pages |
81 | 81 … | .filter(page => ~page.indexOf(word)) |
app/page/blob.mcss | ||
---|---|---|
@@ -1,13 +1,18 @@ | ||
1 | 1 … | Blob { |
2 | - position: relative | |
3 | 2 … | width: 100% |
4 | 3 … | height: 100% |
5 | 4 … | |
5 … | + display: grid | |
6 … | + grid: 1fr / 1fr | |
7 … | + align-items: stretch | |
8 … | + justify-items: stretch | |
9 … | + | |
6 | 10 … | iframe { |
7 | - position: absolute | |
8 | - width: 100% | |
9 | - height: 100% | |
10 | 11 … | border: 0 |
12 … | + | |
13 … | + /* don't think these work */ | |
14 … | + object-fit: scale-down | |
15 … | + object-position: 50% 50% | |
11 | 16 … | } |
12 | 17 … | } |
13 | 18 … |
app/page/notifications.js | ||
---|---|---|
@@ -39,15 +39,15 @@ | ||
39 | 39 … | function draw () { |
40 | 40 … | resetFeed({ container, content }) |
41 | 41 … | |
42 | 42 … | pull( |
43 | - pullMentions({old: false, live: true}), | |
43 … | + pullMentions({ old: false, live: true }), | |
44 | 44 … | filterDownThrough(), |
45 | 45 … | Scroller(container, content, api.message.html.render, true, false) |
46 | 46 … | ) |
47 | 47 … | |
48 | 48 … | pull( |
49 | - pullMentions({reverse: true, live: false}), | |
49 … | + pullMentions({ reverse: true, live: false }), | |
50 | 50 … | filterUpThrough(), |
51 | 51 … | Scroller(container, content, api.message.html.render, false, false) |
52 | 52 … | ) |
53 | 53 … | } |
@@ -56,17 +56,24 @@ | ||
56 | 56 … | container.title = '/notifications' |
57 | 57 … | return container |
58 | 58 … | } |
59 | 59 … | |
60 | - // NOTE - this currently hits mentions AND the patchwork message replies | |
60 … | + // NOTE - currently this stream is know to pick up: | |
61 … | + // - post mentions (public) | |
62 … | + // - patchwork replies (public) | |
63 … | + // - scry (public, private) | |
64 … | + | |
61 | 65 … | function pullMentions (opts) { |
62 | 66 … | const query = [{ |
63 | 67 … | $filter: { |
64 | 68 … | dest: api.keys.sync.id(), |
65 | - timestamp: {$gt: 0}, | |
69 … | + timestamp: { $gt: 0 } | |
70 … | + } | |
71 … | + }, { | |
72 … | + $filter: { | |
66 | 73 … | value: { |
67 | - author: {$ne: api.keys.sync.id()}, // not my messages! | |
68 | - private: {$ne: true} // not private mentions | |
74 … | + author: { $ne: api.keys.sync.id() } // not my messages! | |
75 … | + // NOTE putting this in second filter might be necessary to stop index trying to use this author value | |
69 | 76 … | } |
70 | 77 … | } |
71 | 78 … | }] |
72 | 79 … | |
@@ -78,8 +85,12 @@ | ||
78 | 85 … | |
79 | 86 … | return api.sbot.pull.stream(server => { |
80 | 87 … | return pull( |
81 | 88 … | next(server.backlinks.read, _opts, ['timestamp']), |
89 … | + pull.filter(m => { | |
90 … | + if (m.value.content.type !== 'post') return true | |
91 … | + return !m.value.private // no private posts | |
92 … | + }), | |
82 | 93 … | pull.filter(m => !api.message.sync.isBlocked(m)) |
83 | 94 … | ) |
84 | 95 … | }) |
85 | 96 … | } |
app/page/query.js | ||
---|---|---|
@@ -3,8 +3,9 @@ | ||
3 | 3 … | const Scroller = require('mutant-scroll') |
4 | 4 … | const next = require('pull-next-query') |
5 | 5 … | const json5 = require('json5') |
6 | 6 … | const get = require('lodash/get') |
7 … | +const isEqual = require('lodash/isEqual') | |
7 | 8 … | |
8 | 9 … | exports.gives = nest({ |
9 | 10 … | 'app.html.menuItem': true, |
10 | 11 … | 'app.page.query': true |
@@ -43,9 +44,12 @@ | ||
43 | 44 … | } catch (err) { |
44 | 45 … | // console.error(err) |
45 | 46 … | return err |
46 | 47 … | } |
47 | - if (isValidOpts(newOpts)) state.opts.set(newOpts) | |
48 … | + // NOTE - this is the piece which auto-runs the quers | |
49 … | + if (!isValidOpts(newOpts)) return | |
50 … | + if (isEqual(resolve(state.opts), newOpts)) return | |
51 … | + state.opts.set(newOpts) | |
48 | 52 … | }) |
49 | 53 … | |
50 | 54 … | const activateQuery = () => state.opts.set(json5.parse(resolve(state.input))) |
51 | 55 … | |
@@ -66,8 +70,9 @@ | ||
66 | 70 … | comparer: (a, b) => { |
67 | 71 … | if (a && b && a.key && b.key) return a.key === b.key |
68 | 72 … | return a === b |
69 | 73 … | } |
74 … | + // cb: console.error // TODO better error catching with stream | |
70 | 75 … | }) |
71 | 76 … | }) |
72 | 77 … | ]) |
73 | 78 … | ]) |
@@ -212,9 +217,9 @@ | ||
212 | 217 … | |
213 | 218 … | // regex lifted from ssb-ref |
214 | 219 … | var arr = chunk.split(/((?:@|%|&)[A-Za-z0-9/+]{43}=\.[\w\d]+)/g) |
215 | 220 … | for (var i = 1; i < arr.length; i += 2) { |
216 | - arr[i] = h('a', {href: arr[i]}, arr[i]) | |
221 … | + arr[i] = h('a', { href: arr[i] }, arr[i]) | |
217 | 222 … | } |
218 | 223 … | newArray = [...newArray, ...arr] |
219 | 224 … | }) |
220 | 225 … |
app/page/thread.js | ||
---|---|---|
@@ -22,9 +22,9 @@ | ||
22 | 22 … | exports.create = function (api) { |
23 | 23 … | return nest('app.page.thread', threadPage) |
24 | 24 … | |
25 | 25 … | function threadPage (location) { |
26 | - const root = get(location, 'value.content.root', location.key) | |
26 … | + const root = get(location, 'value.content.root') || get(location, 'value.content.about') || location.key | |
27 | 27 … | const msg = location.key |
28 | 28 … | if (msg !== root) scrollDownToMessage(msg) |
29 | 29 … | |
30 | 30 … | const { messages, isPrivate, rootId, lastId, channel, recps } = api.feed.obs.thread(root) |
app/page/thread.mcss | ||
---|---|---|
@@ -1,7 +1,7 @@ | ||
1 | 1 … | Thread { |
2 | 2 … | section.top { |
3 | - border-bottom: solid 1px gainsboro | |
3 … | + /* border-bottom: solid 1px gainsboro */ | |
4 | 4 … | |
5 | 5 … | section.recipients { |
6 | 6 … | display: flex |
7 | 7 … | justify-content: center |
app/styles/mcss/button.mcss | ||
---|---|---|
@@ -37,16 +37,14 @@ | ||
37 | 37 … | } |
38 | 38 … | |
39 | 39 … | :disabled { |
40 | 40 … | color: grey |
41 | - background: #fff | |
41 … | + background: rgba(255,255,255,.3) | |
42 … | + cursor: not-allowed | |
43 … | + border: none | |
42 | 44 … | |
43 | - cursor: initial | |
44 | - | |
45 | 45 … | :hover { |
46 | - color: grey | |
47 | - background: #fff | |
48 | - border: 1px #b9b9b9 solid | |
46 … | + background: rgba(255,0,0,.3) | |
49 | 47 … | } |
50 | 48 … | } |
51 | 49 … | |
52 | 50 … | -subtle { |
app/styles/mcss/marama.js | ||
---|---|---|
@@ -1,11 +1,11 @@ | ||
1 | 1 … | const nest = require('depnest') |
2 | -const { assign } = Object | |
3 | 2 … | const getMCSS = require('marama/lib/get-mcss') |
4 | 3 … | |
5 | 4 … | exports.gives = nest('styles.mcss') |
6 | 5 … | |
7 | 6 … | exports.create = function (api) { |
8 | 7 … | return nest('styles.mcss', (sofar = {}) => { |
9 | - return assign(sofar, { marama: getMCSS() }) | |
8 … | + sofar.marama = getMCSS() | |
9 … | + return sofar | |
10 | 10 … | }) |
11 | 11 … | } |
app/styles/mcss/markdown.mcss | ||
---|---|---|
@@ -2,8 +2,11 @@ | ||
2 | 2 … | p, ul, ol { |
3 | 3 … | } |
4 | 4 … | |
5 | 5 … | p { |
6 … | + :first-of-type { margin-top: 0 } | |
7 … | + :last-of-type { margin-bottom: 0 } | |
8 … | + | |
6 | 9 … | a { |
7 | 10 … | img { margin 0 .5rem } |
8 | 11 … | |
9 | 12 … | :only-of-type { |
@@ -77,9 +80,18 @@ | ||
77 | 80 … | vertical-align: middle |
78 | 81 … | margin-top: -0.2em |
79 | 82 … | } |
80 | 83 … | |
84 … | + (p) { | |
85 … | + img.emoji { | |
86 … | + :only-child { | |
87 … | + width: 3rem | |
88 … | + height: 3rem | |
89 … | + } | |
90 … | + } | |
91 … | + } | |
81 | 92 … | |
93 … | + | |
82 | 94 … | h1, h2, h3, h4, h5, h6 { |
83 | 95 … | margin: 0 |
84 | 96 … | } |
85 | 97 … | h1, h2 { |
main.js | ||
---|---|---|
@@ -38,9 +38,9 @@ | ||
38 | 38 … | const sockets = combine( |
39 | 39 … | require('patchbay-scry'), |
40 | 40 … | require('patchbay-dark-crystal'), |
41 | 41 … | require('patchbay-poll'), |
42 | - require('ssb-chess'), | |
42 … | + require('ssb-chess-mithril'), | |
43 | 43 … | require('patchbay-gatherings'), |
44 | 44 … | require('patchbay-book'), |
45 | 45 … | patchbay, |
46 | 46 … | require('patchcore'), |
message/html/compose.js | ||
---|---|---|
@@ -1,23 +1,25 @@ | ||
1 | -const { h, when, send, resolve, Value, computed } = require('mutant') | |
1 … | +const { h, when, send, resolve, Value, Array: MutantArray, computed } = require('mutant') | |
2 | 2 … | const nest = require('depnest') |
3 | 3 … | const ssbMentions = require('ssb-mentions') |
4 | 4 … | const extend = require('xtend') |
5 | 5 … | const addSuggest = require('suggest-box') |
6 … | +const blobFiles = require('ssb-blob-files') | |
7 … | +const get = require('lodash/get') | |
6 | 8 … | |
7 | 9 … | exports.gives = nest('message.html.compose') |
8 | 10 … | |
9 | 11 … | exports.needs = nest({ |
10 | 12 … | 'about.async.suggest': 'first', |
11 | 13 … | 'channel.async.suggest': 'first', |
12 | 14 … | 'emoji.async.suggest': 'first', |
13 | 15 … | 'meme.async.suggest': 'first', |
14 | - 'blob.html.input': 'first', | |
15 | 16 … | 'message.html.confirm': 'first', |
16 | 17 … | 'drafts.sync.get': 'first', |
17 | 18 … | 'drafts.sync.set': 'first', |
18 | 19 … | 'drafts.sync.remove': 'first', |
19 | - 'settings.obs.get': 'first' | |
20 … | + 'settings.obs.get': 'first', | |
21 … | + 'sbot.obs.connection': 'first' | |
20 | 22 … | }) |
21 | 23 … | |
22 | 24 … | exports.create = function (api) { |
23 | 25 … | return nest({ 'message.html.compose': compose }) |
@@ -80,8 +82,17 @@ | ||
80 | 82 … | clearTimeout(blurTimeout) |
81 | 83 … | blurTimeout = setTimeout(() => textAreaFocused.set(false), 200) |
82 | 84 … | }, |
83 | 85 … | 'ev-focus': send(textAreaFocused.set, true), |
86 … | + 'ev-paste': ev => { | |
87 … | + const files = get(ev, 'clipboardData.files') | |
88 … | + if (!files || !files.length) return | |
89 … | + const opts = { | |
90 … | + stripExif: api.settings.obs.get('patchbay.removeExif', true), | |
91 … | + isPrivate | |
92 … | + } | |
93 … | + blobFiles(files, api.sbot.obs.connection, opts, afterBlobed) | |
94 … | + }, | |
84 | 95 … | placeholder |
85 | 96 … | }) |
86 | 97 … | textArea.publish = publish // TODO: fix - clunky api for the keyboard shortcut to target |
87 | 98 … | |
@@ -92,46 +103,60 @@ | ||
92 | 103 … | hasContent.set(true) |
93 | 104 … | } |
94 | 105 … | |
95 | 106 … | var isPrivate = location.page === 'private' || |
96 | - (location.key && !location.value) || | |
97 | - (location.value && location.value.private) | |
107 … | + (location.key && !location.value) || | |
108 … | + (location.value && location.value.private) | |
98 | 109 … | |
99 | - var warningMessage = Value(null) | |
100 | - var warning = h('section.warning', | |
101 | - { className: when(warningMessage, '-open', '-closed') }, | |
102 | - [ | |
103 | - h('div.warning', warningMessage), | |
104 | - h('div.close', { 'ev-click': () => warningMessage.set(null) }, 'x') | |
105 | - ] | |
106 | - ) | |
107 | - var fileInput = api.blob.html.input(file => { | |
108 | - const megabytes = file.size / 1024 / 1024 | |
109 | - if (megabytes >= 5) { | |
110 | - const rounded = Math.floor(megabytes * 100) / 100 | |
111 | - warningMessage.set([ | |
110 … | + var warningMessages = MutantArray([]) | |
111 … | + var warning = computed(warningMessages, msgs => { | |
112 … | + if (!msgs.length) return | |
113 … | + | |
114 … | + return h('section.warnings', msgs.map((m, i) => { | |
115 … | + return h('div.warning', [ | |
112 | 116 … | h('i.fa.fa-exclamation-triangle'), |
113 | - h('strong', file.name), | |
114 | - ` is ${rounded}MB - the current limit is 5MB` | |
117 … | + h('div.message', m), | |
118 … | + h('i.fa.fa-times', { 'ev-click': () => warningMessages.deleteAt(i) }) | |
115 | 119 … | ]) |
120 … | + })) | |
121 … | + }) | |
122 … | + | |
123 … | + var fileInput = h('input', { | |
124 … | + type: 'file', | |
125 … | + // accept, | |
126 … | + attributes: { multiple: true }, | |
127 … | + 'ev-click': () => hasContent.set(true), | |
128 … | + 'ev-change': (ev) => { | |
129 … | + warningMessages.set([]) | |
130 … | + | |
131 … | + const files = ev.target.files | |
132 … | + const opts = { | |
133 … | + stripExif: api.settings.obs.get('patchbay.removeExif', true), | |
134 … | + isPrivate | |
135 … | + } | |
136 … | + blobFiles(files, api.sbot.obs.connection, opts, afterBlobed) | |
137 … | + } | |
138 … | + }) | |
139 … | + function afterBlobed (err, result) { | |
140 … | + if (err) { | |
141 … | + console.error(err) | |
142 … | + warningMessages.push(err.message) | |
116 | 143 … | return |
117 | 144 … | } |
118 | 145 … | |
119 | - files.push(file) | |
120 | - filesById[file.link] = file | |
146 … | + files.push(result) | |
147 … | + filesById[result.link] = result | |
121 | 148 … | |
122 | 149 … | const pos = textArea.selectionStart |
123 | - const embed = file.type.match(/^image/) ? '!' : '' | |
150 … | + const embed = result.type.match(/^image/) ? '!' : '' | |
124 | 151 … | const spacer = embed ? '\n' : ' ' |
125 | - const insertLink = spacer + embed + '[' + file.name + ']' + '(' + file.link + ')' + spacer | |
152 … | + const insertLink = spacer + embed + '[' + result.name + ']' + '(' + result.link + ')' + spacer | |
126 | 153 … | |
127 | 154 … | textArea.value = textArea.value.slice(0, pos) + insertLink + textArea.value.slice(pos) |
128 | 155 … | |
129 | - console.log('added:', file) | |
130 | - }, { private: isPrivate, removeExif: api.settings.obs.get('patchbay.removeExif', true) }) | |
156 … | + console.log('added:', result) | |
157 … | + } | |
131 | 158 … | |
132 | - fileInput.onclick = () => hasContent.set(true) | |
133 | - | |
134 | 159 … | var publishBtn = h('button', { 'ev-click': publish }, isPrivate ? 'Reply' : 'Publish') |
135 | 160 … | |
136 | 161 … | var actions = h('section.actions', [ |
137 | 162 … | fileInput, |
@@ -164,9 +189,9 @@ | ||
164 | 189 … | addSuggest(channelInput, (inputText, cb) => { |
165 | 190 … | if (inputText[0] === '#') { |
166 | 191 … | api.channel.async.suggest(inputText.slice(1), cb) |
167 | 192 … | } |
168 | - }, {cls: 'PatchSuggest'}) | |
193 … | + }, { cls: 'PatchSuggest' }) | |
169 | 194 … | channelInput.addEventListener('suggestselect', ev => { |
170 | 195 … | channelInput.value = ev.detail.id // HACK : this over-rides the markdown value |
171 | 196 … | }) |
172 | 197 … | |
@@ -177,9 +202,9 @@ | ||
177 | 202 … | if (char === '@') api.about.async.suggest(wordFragment, feedIdsInThread, cb) |
178 | 203 … | if (char === '#') api.channel.async.suggest(wordFragment, cb) |
179 | 204 … | if (char === ':') api.emoji.async.suggest(wordFragment, cb) |
180 | 205 … | if (char === '&') api.meme.async.suggest(wordFragment, cb) |
181 | - }, {cls: 'PatchSuggest'}) | |
206 … | + }, { cls: 'PatchSuggest' }) | |
182 | 207 … | |
183 | 208 … | return composer |
184 | 209 … | |
185 | 210 … | // scoped |
message/html/compose.mcss | ||
---|---|---|
@@ -26,32 +26,30 @@ | ||
26 | 26 … | cursor: not-allowed |
27 | 27 … | } |
28 | 28 … | } |
29 | 29 … | |
30 | - section.warning { | |
30 … | + section.warnings { | |
31 | 31 … | color: #fff |
32 | - background-color: red | |
33 | 32 … | |
34 | - height: 0 | |
35 | - padding: 0 .5rem | |
36 | - transition: all ease-in .1s | |
33 … | + div.warning { | |
34 … | + background-color: red | |
35 … | + padding: .5rem | |
36 … | + margin-bottom: 5px | |
37 | 37 … | |
38 | - display: flex | |
39 | - justify-content: space-between | |
38 … | + display: flex | |
39 … | + justify-content: start | |
40 … | + align-items: center | |
40 | 41 … | |
42 … | + i.fa-exclamation-triangle { margin-right: .5rem } | |
41 | 43 … | |
42 | - -open { | |
43 | - padding: .5rem | |
44 | - height: initial | |
45 | - } | |
44 … | + div.message { | |
45 … | + flex-grow: 1 | |
46 … | + font-weight: 600 | |
47 … | + margin-right: .3rem | |
48 … | + } | |
46 | 49 … | |
47 | - i.fa { margin-right: .5rem } | |
48 | - div.warning { | |
49 | - strong { margin-right: .3rem } | |
50 … | + i.fa-times { cursor: pointer } | |
50 | 51 … | } |
51 | - div.close { | |
52 | - cursor: pointer | |
53 | - } | |
54 | 52 … | } |
55 | 53 … | |
56 | 54 … | section.actions { |
57 | 55 … | display: flex |
message/html/confirm.js | ||
---|---|---|
@@ -38,19 +38,17 @@ | ||
38 | 38 … | var okay = h('button.okay', { |
39 | 39 … | 'ev-click': () => { |
40 | 40 … | lb.remove() |
41 | 41 … | api.message.async.publish(content, cb) |
42 | - }}, | |
43 | - 'okay' | |
44 | - ) | |
42 … | + } | |
43 … | + }, 'okay') | |
45 | 44 … | |
46 | 45 … | var cancel = h('button.cancel.-subtle', { |
47 | 46 … | 'ev-click': () => { |
48 | 47 … | lb.remove() |
49 | 48 … | cb(null) |
50 | - }}, | |
51 | - 'cancel' | |
52 | - ) | |
49 … | + } | |
50 … | + }, 'cancel') | |
53 | 51 … | |
54 | 52 … | okay.addEventListener('keydown', (ev) => { |
55 | 53 … | if (ev.keyCode === 27) cancel.click() // escape |
56 | 54 … | }) |
message/html/decorate/data-root.js | ||
---|---|---|
@@ -4,7 +4,8 @@ | ||
4 | 4 … | |
5 | 5 … | exports.create = (api) => { |
6 | 6 … | return nest('message.html.decorate', function (element, { msg }) { |
7 | 7 … | if (msg.value.content.root) element.dataset.root = msg.value.content.root |
8 … | + if (msg.value.content.about) element.dataset.root = msg.value.content.about | |
8 | 9 … | return element |
9 | 10 … | }) |
10 | 11 … | } |
message/html/layout/default.mcss | ||
---|---|---|
@@ -2,8 +2,9 @@ | ||
2 | 2 … | padding: 1rem .5rem |
3 | 3 … | |
4 | 4 … | display: grid |
5 | 5 … | grid-template-columns: 5rem auto |
6 … | + grid-row-gap: .5rem | |
6 | 7 … | |
7 | 8 … | section.avatar { |
8 | 9 … | grid-column: 1 / 2 |
9 | 10 … | grid-row: 1 / span 4 |
@@ -45,10 +46,8 @@ | ||
45 | 46 … | section.content { |
46 | 47 … | grid-column: 2 / 3 |
47 | 48 … | grid-row: 2 / span 1 |
48 | 49 … | |
49 | - margin-bottom: .5rem | |
50 | - | |
51 | 50 … | (img) { |
52 | 51 … | max-width: 100% |
53 | 52 … | } |
54 | 53 … | (video) { |
message/html/layout/mini.js | ||
---|---|---|
@@ -1,12 +1,13 @@ | ||
1 | 1 … | const nest = require('depnest') |
2 | 2 … | const { h, Value } = require('mutant') |
3 | 3 … | |
4 | -exports.needs = nest('message.html', { | |
5 | - backlinks: 'first', | |
6 | - author: 'first', | |
7 | - meta: 'map', | |
8 | - timestamp: 'first' | |
4 … | +exports.needs = nest({ | |
5 … | + 'app.sync.goTo': 'first', | |
6 … | + 'message.html.backlinks': 'first', | |
7 … | + 'message.html.author': 'first', | |
8 … | + 'message.html.meta': 'map', | |
9 … | + 'message.html.timestamp': 'first' | |
9 | 10 … | }) |
10 | 11 … | |
11 | 12 … | exports.gives = nest('message.html.layout') |
12 | 13 … | |
@@ -25,9 +26,9 @@ | ||
25 | 26 … | }, [ |
26 | 27 … | h('section.timestamp', {}, api.message.html.timestamp(msg)), |
27 | 28 … | h('header.author', {}, api.message.html.author(msg, { size: 'mini' })), |
28 | 29 … | h('section.meta', {}, api.message.html.meta(msg, { rawMessage })), |
29 | - h('section.content', {}, opts.content), | |
30 … | + h('section.content', { 'ev-click': () => api.app.sync.goTo(msg) }, opts.content), | |
30 | 31 … | h('section.raw-content', rawMessage) |
31 | 32 … | ]) |
32 | 33 … | } |
33 | 34 … | } |
message/html/layout/mini.mcss | ||
---|---|---|
@@ -4,8 +4,9 @@ | ||
4 | 4 … | padding: .25rem .5rem |
5 | 5 … | min-height: inherit |
6 | 6 … | |
7 | 7 … | display: flex |
8 … | + flex-wrap: wrap | |
8 | 9 … | |
9 | 10 … | /* TODO - bring style inline with default.mcss */ |
10 | 11 … | |
11 | 12 … | section.timestamp { |
@@ -29,8 +30,9 @@ | ||
29 | 30 … | order: 2 |
30 | 31 … | flex-basis: initial |
31 | 32 … | flex-grow: 1 |
32 | 33 … | |
34 … | + cursor: pointer | |
33 | 35 … | margin-top: 0 |
34 | 36 … | } |
35 | 37 … | |
36 | 38 … | section.meta { |
@@ -48,6 +50,23 @@ | ||
48 | 50 … | |
49 | 51 … | section.raw-content { |
50 | 52 … | order: 4 |
51 | 53 … | margin-left: 0 |
54 … | + | |
55 … | + pre { | |
56 … | + border: 1px gainsboro solid | |
57 … | + padding: .8rem | |
58 … | + background-color: #f5f5f5 | |
59 … | + color: #c121dc | |
60 … | + padding: .3rem | |
61 … | + white-space: pre-wrap | |
62 … | + word-wrap: break-word | |
63 … | + | |
64 … | + span { | |
65 … | + font-weight: 600 | |
66 … | + } | |
67 … | + a { | |
68 … | + word-break: break-all | |
69 … | + } | |
70 … | + } | |
52 | 71 … | } |
53 | 72 … | } |
package-lock.json | ||
---|---|---|
The diff is too large to show. Use a local git client to view these changes. Old file size: 360896 bytes New file size: 397617 bytes |
package.json | ||
---|---|---|
@@ -1,7 +1,7 @@ | ||
1 | 1 … | { |
2 | 2 … | "name": "patchbay", |
3 | - "version": "7.14.0", | |
3 … | + "version": "7.15.0", | |
4 | 4 … | "description": "patchbay 2, built on patchcore", |
5 | 5 … | "main": "index.js", |
6 | 6 … | "scripts": { |
7 | 7 … | "lint": "standard --fix", |
@@ -65,19 +65,20 @@ | ||
65 | 65 … | "open-external": "^0.1.1", |
66 | 66 … | "patch-context": "^2.0.1", |
67 | 67 … | "patch-drafts": "0.0.6", |
68 | 68 … | "patch-history": "^1.0.0", |
69 | - "patch-inbox": "^1.1.8", | |
69 … | + "patch-inbox": "^1.1.9", | |
70 | 70 … | "patch-settings": "^1.1.2", |
71 | 71 … | "patch-suggest": "^2.0.2", |
72 | 72 … | "patchbay-book": "^1.0.8", |
73 | - "patchbay-dark-crystal": "^1.0.3", | |
74 | - "patchbay-gatherings": "^2.0.2", | |
75 | - "patchbay-poll": "^1.0.9", | |
76 | - "patchbay-scry": "^1.1.1", | |
73 … | + "patchbay-dark-crystal": "^1.0.5", | |
74 … | + "patchbay-gatherings": "^3.2.1", | |
75 … | + "patchbay-poll": "^1.1.1", | |
76 … | + "patchbay-scry": "^1.2.0", | |
77 | 77 … | "patchcore": "^1.28.1", |
78 | 78 … | "pull-abortable": "^4.1.1", |
79 | 79 … | "pull-next-query": "^1.0.0", |
80 … | + "pull-notify": "^0.1.1", | |
80 | 81 … | "pull-scroll": "^1.0.9", |
81 | 82 … | "pull-stream": "^3.6.9", |
82 | 83 … | "read-directory": "^3.0.0", |
83 | 84 … | "require-style": "^1.0.1", |
@@ -86,11 +87,12 @@ | ||
86 | 87 … | "scuttlebot": "^12.1.0", |
87 | 88 … | "setimmediate": "^1.0.5", |
88 | 89 … | "ssb-about": "^0.1.2", |
89 | 90 … | "ssb-backlinks": "^0.7.3", |
91 … | + "ssb-blob-files": "^1.1.1", | |
90 | 92 … | "ssb-blobs": "^1.1.5", |
91 | - "ssb-chess": "^2.3.13", | |
92 | - "ssb-chess-db": "^1.0.3", | |
93 … | + "ssb-chess-db": "^1.0.4", | |
94 … | + "ssb-chess-mithril": "1.0.6", | |
93 | 95 … | "ssb-config": "^2.3.0", |
94 | 96 … | "ssb-ebt": "^5.2.3", |
95 | 97 … | "ssb-friends": "^3.1.3", |
96 | 98 … | "ssb-keys": "^7.0.15", |
@@ -98,9 +100,9 @@ | ||
98 | 100 … | "ssb-mentions": "^0.5.0", |
99 | 101 … | "ssb-mutual": "^0.1.0", |
100 | 102 … | "ssb-private": "^0.2.3", |
101 | 103 … | "ssb-query": "^2.1.0", |
102 | - "ssb-ref": "^2.11.1", | |
104 … | + "ssb-ref": "^2.12.0", | |
103 | 105 … | "ssb-search": "^1.1.2", |
104 | 106 … | "ssb-sort": "^1.1.0", |
105 | 107 … | "ssb-unread": "^1.0.1", |
106 | 108 … | "ssb-ws": "^2.1.1", |
router/async/normalise.js | ||
---|---|---|
@@ -1,6 +1,6 @@ | ||
1 | 1 … | const nest = require('depnest') |
2 | -const { isBlob, isFeed, isMsg } = require('ssb-ref') | |
2 … | +const { isBlobLink, isFeed, isMsg } = require('ssb-ref') | |
3 | 3 … | |
4 | 4 … | exports.gives = nest('router.async.normalise') |
5 | 5 … | |
6 | 6 … | exports.needs = nest({ |
@@ -26,13 +26,16 @@ | ||
26 | 26 … | api.sbot.async.get(location, (err, value) => { |
27 | 27 … | if (err) cb(err) |
28 | 28 … | else { |
29 | 29 … | if (typeof value.content === 'string') value = api.message.sync.unbox(value) |
30 | - cb(null, {key: location, value}) | |
30 … | + cb(null, { key: location, value }) | |
31 | 31 … | } |
32 | 32 … | }) |
33 | - } else if (isBlob(location)) cb(null, { blob: location }) | |
34 | - else if (isChannel(location)) cb(null, { channel: location }) | |
33 … | + } else if (isBlobLink(location)) { | |
34 … | + // handles public & private blobs | |
35 … | + // TODO - parse into link and query? | |
36 … | + cb(null, { blob: location }) | |
37 … | + } else if (isChannel(location)) cb(null, { channel: location }) | |
35 | 38 … | else if (isFeed(location)) cb(null, { feed: location }) |
36 | 39 … | else if (isPage(location)) cb(null, { page: location.substring(1) }) |
37 | 40 … | |
38 | 41 … | return true |
router/sync/routes.js | ||
---|---|---|
@@ -1,6 +1,6 @@ | ||
1 | 1 … | const nest = require('depnest') |
2 | -const { isBlob, isFeed, isMsg } = require('ssb-ref') | |
2 … | +const { isBlobLink, isFeed, isMsg } = require('ssb-ref') | |
3 | 3 … | |
4 | 4 … | exports.gives = nest('router.sync.routes') |
5 | 5 … | |
6 | 6 … | exports.needs = nest({ |
@@ -45,9 +45,9 @@ | ||
45 | 45 … | [ loc => loc.page === 'query', pages.query ], |
46 | 46 … | [ loc => loc.page === 'search' && loc.query, pages.search ], |
47 | 47 … | [ loc => loc.page === 'settings', pages.settings ], |
48 | 48 … | |
49 | - [ loc => isBlob(loc.blob), pages.blob ], | |
49 … | + [ loc => loc.blob && isBlobLink(loc.blob), pages.blob ], | |
50 | 50 … | [ loc => isPresent(loc.channel), pages.channel ], |
51 | 51 … | [ loc => isFeed(loc.feed), pages.profile ], |
52 | 52 … | [ loc => isMsg(loc.key), pages.thread ] |
53 | 53 … | ] |
Built with git-ssb-web