Files: 286f58e95fb08e5233963b593bb28cd72bf2655a / views / audio-post.js
5462 bytesRaw
1 | var h = require('../lib/h') |
2 | var MutantMap = require('@mmckegg/mutant/map') |
3 | var computed = require('@mmckegg/mutant/computed') |
4 | var when = require('@mmckegg/mutant/when') |
5 | var renderMiniProfile = require('../widgets/mini-profile') |
6 | var contextMenu = require('../lib/context-menu') |
7 | var magnet = require('magnet-uri') |
8 | var send = require('@mmckegg/mutant/send') |
9 | var AudioOverview = require('../widgets/audio-overview') |
10 | var markdown = require('../lib/markdown') |
11 | var colorHash = require('../lib/color-hash') |
12 | var humanTime = require('human-time') |
13 | var TorrentStatusWidget = require('../widgets/torrent-status') |
14 | |
15 | module.exports = AudioPostView |
16 | |
17 | function AudioPostView (context, postId) { |
18 | var post = context.api.getPost(postId) |
19 | var rankedLikedIds = context.api.rankProfileIds(post.likes, 12) |
20 | var likes = MutantMap(rankedLikedIds, id => context.api.getProfile(id)) |
21 | var likesCount = computed(post.likes, (list) => list.length) |
22 | var repostsCount = computed(post.reposters, (list) => list.length) |
23 | var player = context.player |
24 | var infoHash = computed(post.audioSrc, (src) => magnet.decode(src).infoHash) |
25 | var profile = context.api.getProfile(context.api.id) |
26 | var reposted = computed([profile.posts, post.id], (posts, id) => posts.includes(id)) |
27 | var liked = computed([profile.likes, postId], (likes, id) => likes.includes(id)) |
28 | var isOwner = context.api.id === post.author.id |
29 | var color = colorHash.hex(postId) |
30 | |
31 | var url = computed(post.artworkSrc, context.api.getBlobUrl) |
32 | |
33 | return h('AudioPostView', { |
34 | 'ev-contextmenu': contextMenu.bind(null, context, post), |
35 | classList: [ |
36 | computed(post.state, (s) => `-${s}`) |
37 | ] |
38 | }, [ |
39 | h('header', [ |
40 | h('div.main', [ |
41 | h('div.title', [ |
42 | h('a.play', { 'ev-click': send(player.togglePlay, post), href: '#' }), |
43 | h('header', [ |
44 | h('a.feedTitle', { |
45 | href: '#', 'ev-click': send(context.actions.viewProfile, post.author.id) |
46 | }, [post.author.displayName]), h('br'), |
47 | h('span.title', [post.title]) |
48 | ]), |
49 | h('div.timestamp', [ |
50 | humanTime(Date.now() / 1000 - post.timestamp() / 1000) |
51 | ]) |
52 | ]), |
53 | h('div.display', { |
54 | hooks: [ |
55 | SetPositionHook(context, post) |
56 | ] |
57 | }, [ |
58 | AudioOverview(post.overview, 600, 100), |
59 | h('div.progress', { |
60 | style: { |
61 | width: computed([post.position, post.duration], (pos, dur) => Math.round(pos / dur * 1000) / 10 + '%') |
62 | } |
63 | }), |
64 | when(post.position, h('span.position', computed(post.position, formatTime))), |
65 | h('span.duration', computed(post.duration, formatTime)) |
66 | ]), |
67 | h('div.options', [ |
68 | h('a.like', { |
69 | href: '#', |
70 | 'ev-click': send(toggleLike, { liked, context, post }), |
71 | classList: [ |
72 | when(liked, '-active') |
73 | ] |
74 | }, [ |
75 | '๐ ', when(likesCount, likesCount, 'Like') |
76 | ]), |
77 | when(isOwner, |
78 | h('a.repost -disabled', [ |
79 | '๐ก ', when(repostsCount, repostsCount, 'Repost') |
80 | ]), |
81 | h('a.repost', { |
82 | href: '#', |
83 | 'ev-click': send(toggleRepost, { reposted, context, post }), |
84 | classList: [ |
85 | when(reposted, '-active') |
86 | ] |
87 | }, [ |
88 | '๐ก ', when(repostsCount, repostsCount, 'Repost') |
89 | ]) |
90 | ), |
91 | when(isOwner, |
92 | h('a.edit', { href: '#', 'ev-click': edit }, 'โจ Edit') |
93 | ), |
94 | h('a.save', { href: '#', 'ev-click': send(context.actions.saveFile, post) }, '๐พ Save'), |
95 | TorrentStatusWidget(context, infoHash) |
96 | ]) |
97 | ]), |
98 | |
99 | h('div.artwork', { style: { |
100 | 'background-image': computed(url, (src) => src ? `url("${src}")` : ''), |
101 | 'background-color': color |
102 | }}) |
103 | ]), |
104 | h('section', [ |
105 | h('div.main', [ |
106 | markdown(post.description) |
107 | ]), |
108 | h('div.side', [ |
109 | when(likesCount, [ |
110 | h('h2', ['Liked by ', h('span.sub', [likesCount])]), |
111 | MutantMap(likes, (item) => renderMiniProfile(context, item), { maxTime: 5 }) |
112 | ]) |
113 | ]) |
114 | ]) |
115 | ]) |
116 | |
117 | // scoped |
118 | |
119 | function edit () { |
120 | context.actions.editPost({ |
121 | id: post.id, |
122 | item: post() |
123 | }) |
124 | } |
125 | } |
126 | |
127 | function percent (value) { |
128 | return Math.round(value * 100) + '%' |
129 | } |
130 | |
131 | function toggleLike (opts) { |
132 | if (opts.liked()) { |
133 | opts.context.api.unlike(opts.post.id) |
134 | } else { |
135 | opts.context.api.like(opts.post.id) |
136 | } |
137 | } |
138 | |
139 | function toggleRepost (opts) { |
140 | if (opts.reposted()) { |
141 | opts.context.api.unrepost(opts.post.id) |
142 | } else { |
143 | opts.context.api.repost(opts.post.id) |
144 | } |
145 | } |
146 | |
147 | function SetPositionHook (context, item) { |
148 | return function (element) { |
149 | element.onmousemove = element.onmousedown = function (ev) { |
150 | if (ev.buttons && ev.button === 0) { |
151 | var box = ev.currentTarget.getBoundingClientRect() |
152 | var x = ev.clientX - box.left |
153 | if (x < 5) { |
154 | x = 0 |
155 | } |
156 | setPosition(x / box.width * item.duration()) |
157 | } |
158 | } |
159 | } |
160 | |
161 | function setPosition (position) { |
162 | if (context.player.currentItem.get() === item) { |
163 | context.player.audioElement.currentTime = position |
164 | } |
165 | item.position.set(position) |
166 | } |
167 | } |
168 | |
169 | function formatTime (value) { |
170 | var minutes = Math.floor(value / 60) |
171 | var seconds = Math.floor(value % 60) |
172 | return minutes + ':' + ('0' + seconds).slice(-2) |
173 | } |
174 |
Built with git-ssb-web