Files: 6e4c70b8d1f36db6aa1bba43786d168752b19240 / app / html / blogCard.js
4172 bytesRaw
1 | var nest = require('depnest') |
2 | var { h, Array: MutantArray } = require('mutant') |
3 | // var maxBy = require('lodash/maxBy') |
4 | // var markdown = require('ssb-markdown') |
5 | // var ref = require('ssb-ref') |
6 | // var htmlEscape = require('html-escape') |
7 | |
8 | // function renderEmoji (emoji, url) { |
9 | // if (!url) return ':' + emoji + ':' |
10 | // return ` |
11 | // <img |
12 | // src="${htmlEscape(url)}" |
13 | // alt=":${htmlEscape(emoji)}:" |
14 | // title=":${htmlEscape(emoji)}:" |
15 | // class="emoji" |
16 | // > |
17 | // ` |
18 | // } |
19 | |
20 | exports.gives = nest('app.html.blogCard', true) |
21 | |
22 | exports.needs = nest({ |
23 | 'keys.sync.id': 'first', |
24 | 'history.sync.push': 'first', |
25 | 'about.obs.color': 'first', |
26 | 'about.obs.name': 'first', |
27 | 'about.html.avatar': 'first', |
28 | 'unread.sync.isUnread': 'first', |
29 | 'message.html.channel': 'first', |
30 | 'message.html.timeago': 'first', |
31 | 'blob.sync.url': 'first', |
32 | 'emoji.sync.url': 'first', |
33 | |
34 | 'blog.html.title': 'first', |
35 | 'blog.html.summary': 'first', |
36 | 'blog.html.thumbnail': 'first' |
37 | }) |
38 | |
39 | exports.create = function (api) { |
40 | // render markdown, but don't support patchwork@2 style mentions or custom emoji right now. |
41 | // function render (source) { |
42 | // return markdown.block(source, { |
43 | // emoji: (emoji) => { |
44 | // return renderEmoji(emoji, api.emoji.sync.url(emoji)) |
45 | // }, |
46 | // toUrl: (id) => { |
47 | // if (ref.isBlob(id)) return api.blob.sync.url(id) |
48 | // return id |
49 | // }, |
50 | // imageLink: (id) => id |
51 | // }) |
52 | // } |
53 | |
54 | // render the icon for a blog. |
55 | // it would be more depjecty to split this |
56 | // into two methods, one in a private plugin |
57 | // one in a channel plugin |
58 | // function blogIcon (msg) { |
59 | // if (msg.value.private) { |
60 | // const myId = api.keys.sync.id() |
61 | |
62 | // return msg.value.content.recps |
63 | // .map(link => isString(link) ? link : link.link) |
64 | // .filter(link => link !== myId) |
65 | // .map(link => api.about.html.avatar) |
66 | // } else if (msg.value.content.channel) { return '#' + msg.value.content.channel } |
67 | // } |
68 | |
69 | // REFACTOR: move this to a template? |
70 | // function buildRecipientNames (blog) { |
71 | // const myId = api.keys.sync.id() |
72 | |
73 | // return blog.value.content.recps |
74 | // .map(link => isString(link) ? link : link.link) |
75 | // .filter(link => link !== myId) |
76 | // .map(api.about.obs.name) |
77 | // } |
78 | |
79 | return nest('app.html.blogCard', (blog, opts = {}) => { |
80 | if (!blog.value) return |
81 | |
82 | // const lastReply = blog.replies && maxBy(blog.replies, r => r.timestamp) |
83 | |
84 | const goToBlog = () => api.history.sync.push(blog) |
85 | const onClick = opts.onClick || goToBlog |
86 | const id = `${blog.key.replace(/[^a-z0-9]/gi, '')}` // -${JSON.stringify(opts)}` |
87 | // id is only here to help morphdom morph accurately |
88 | |
89 | const { content, author } = blog.value |
90 | |
91 | var img = h('Thumbnail') |
92 | |
93 | var image = api.blog.html.thumbnail(blog) |
94 | |
95 | if (image) { |
96 | // Hey this works! fit an image into a specific size (see blog-card.mcss) |
97 | // centered, and scaled to fit the square (works with both landscape and portrait!) |
98 | // This is functional css not opinionated css, so all embedded. |
99 | img.style = 'background-image: url("' + api.blob.sync.url(image) + '"); background-position:center; background-size: cover;' |
100 | } else { |
101 | var style = { 'background-color': api.about.obs.color(blog.key) } |
102 | img = h('Thumbnail -empty', { style }, [ |
103 | h('i.fa.fa-file-text-o') |
104 | ]) |
105 | } |
106 | |
107 | var classList = MutantArray(['-arriving']) |
108 | if (blog.unread) classList.push('-unread') |
109 | |
110 | var b = h('BlogCard', { id, classList, 'ev-click': onClick }, [ |
111 | h('div.context', [ |
112 | api.about.html.avatar(author, 'tiny'), |
113 | h('div.name', api.about.obs.name(author)), |
114 | api.message.html.timeago(blog) |
115 | ]), |
116 | h('div.content', [ |
117 | img, |
118 | h('div.text', [ |
119 | h('h2', api.blog.html.title(blog)), |
120 | content.channel |
121 | ? api.message.html.channel(blog) |
122 | : '', |
123 | h('div.summary', api.blog.html.summary(blog)) |
124 | ]) |
125 | ]) |
126 | ]) |
127 | |
128 | arrive() |
129 | return b |
130 | |
131 | function arrive () { |
132 | if (!b.parentNode) return setTimeout(arrive, 100) |
133 | classList.delete('-arriving') |
134 | } |
135 | }) |
136 | } |
137 |
Built with git-ssb-web