git ssb

2+

mixmix / ticktack



Commit 49bee78f3c1fec7174a11ee2c7277f5c9a7f47fc

Merge pull request #6 from ticktackim/homescreen_styling

homescreen - box model + mcss work
mix irving authored on 8/11/2017, 9:15:31 AM
GitHub committed on 8/11/2017, 9:15:31 AM
Parent: f7dff5dea73ce76928756982a627d93d49cb1968
Parent: ad32665d634a45be6ccf3a7db98533610b061176

Files changed

app/html/thread.mcsschanged
app/page/home.jschanged
app/page/home.mcsschanged
app/page/page.mcsschanged
app/page/private.jschanged
styles/mixins.jschanged
app/html/thread.mcssView
@@ -1,19 +1,13 @@
11 Thread {
2- background-color: #f7f7f7
3- font-family: 'arial'
4- padding: 1rem
5-
6- max-width: 1400px
7-
82 display: flex
93 flex-direction: column
104
115 div.my-chunk {
126 $chunk
137
148 justify-content: space-between
15-
9+
1610 div.avatar {
1711 visibility: hidden
1812 }
1913
@@ -21,46 +15,24 @@
2115 div.msg-row {
2216 div.msg {
2317 $primaryColor
2418
25- border-bottom-left-radius: .9rem
26- border-top-left-radius: .9rem
19+ (a) { color: #4d3568 }
20+ $roundLeft
2721 }
28- :first-child {
29- div.msg {
30- border-top-right-radius: .9rem
31- }
32- }
33- :last-child {
34- div.msg {
35- border-bottom-right-radius: .9rem
36- }
37- }
3822 }
3923 }
4024 }
4125
4226 div.other-chunk {
4327 $chunk
4428
4529 div.msgs {
46-
4730 div.msg-row {
4831 div.msg {
4932 border: 1.5px #ddd solid
50- border-bottom-right-radius: .9rem
51- border-top-right-radius: .9rem
33+ $roundRight
5234 }
53- :first-child {
54- div.msg {
55- border-top-left-radius: .9rem
56- }
57- }
58- :last-child {
59- div.msg {
60- border-bottom-left-radius: .9rem
61- }
62- }
6335 }
6436 }
6537 }
6638 }
@@ -84,13 +56,20 @@
8456 max-width: 80%
8557 div.msg-row {
8658 display: flex
8759
60+ :first-child {
61+ div.msg { $roundTop }
62+ }
63+ :last-child {
64+ div.msg { $roundBottom }
65+ }
66+
8867 div.msg {
8968 line-height: 1.2rem
9069 background-color: #fff
9170 padding: 0 .7rem
92- margin-bottom: .1rem
71+ margin-bottom: .1rem
9372 border-radius: .3rem
9473 }
9574 div.msg-spacer {
9675 flex-grow: grow
app/page/home.jsView
@@ -1,6 +1,6 @@
11 const nest = require('depnest')
2-const { h } = require('mutant')
2+const { h, computed } = require('mutant')
33 const {threadReduce} = require('ssb-reduce-stream')
44 const pull = require('pull-stream')
55 const isObject = require('lodash/isObject')
66 const isString = require('lodash/isString')
@@ -10,20 +10,47 @@
1010 exports.gives = nest('app.page.home')
1111
1212 exports.needs = nest({
1313 'about.html.image': 'first',
14+ 'about.obs.name': 'first',
1415 'app.html.nav': 'first',
1516 'feed.pull.public': 'first',
1617 'history.sync.push': 'first',
18+ 'keys.sync.id': 'first',
1719 'message.sync.unbox': 'first',
20+ 'message.html.markdown': 'first'
1821 })
1922
2023 function firstLine (text) {
2124 if(text.length < 80 && !~text.indexOf('\n')) return text
2225
23- return text.split('\n')[0].substring(0, 80)
26+ var line = ''
27+ var lineNumber = 0
28+ while (line.length === 0) {
29+ const rawLine = text.split('\n')[lineNumber]
30+ line = trimLeadingMentions(rawLine)
31+
32+ lineNumber++
33+ }
34+
35+ var sample = line.substring(0, 80)
36+ if (hasBrokenLink(sample))
37+ sample = sample + line.substring(81).match(/[^\)]*\)/)[0]
38+
39+ const ellipsis = (sample.length < line.length) ? '...' : ''
40+ return sample + ellipsis
2441 }
2542
43+function trimLeadingMentions (str) {
44+ return str.replace(/^(\s*\[@[^\)]+\)\s*)*/, '')
45+ // deletes any number of pattern " [@...) " from start of line
46+}
47+
48+function hasBrokenLink (str) {
49+ return /\[[^\]]*\]\([^\)]*$/.test(str)
50+ // matches "[name](start_of_link"
51+}
52+
2653 exports.create = (api) => {
2754 return nest('app.page.home', home)
2855
2956 function home (location) {
@@ -32,37 +59,65 @@
3259 var container = h('div.container', [])
3360
3461 function subject (msg) {
3562 const { subject, text } = msg.value.content
36- return firstLine(subject|| text)
63+ return api.message.html.markdown(firstLine(subject|| text))
3764 }
3865
3966 function link(location) {
4067 return {'ev-click': () => api.history.sync.push(location)}
4168 }
4269
43- function item (name, thread) {
70+ function item (context, thread, opts = {}) {
4471 if(!thread.value) return
72+
73+ const subjectEl = h('div.subject', [
74+ opts.nameRecipients
75+ ? h('div.recps', buildRecipientNames(thread).map(recp => h('div.recp', recp)))
76+ : null,
77+ subject(thread)
78+ ])
79+
4580 const lastReply = thread.replies && last(thread.replies)
81+ const replyEl = lastReply
82+ ? h('div.reply', [
83+ h('div.replySymbol', '► '),
84+ subject(lastReply)
85+ ])
86+ : null
4687
47- return h('div.threadLink', link(thread), [
48- name,
49- h('div.subject', [subject(thread)]),
50- lastReply ? h('div.reply', [subject(lastReply)]) : null
88+
89+ // REFACTOR: move this to a template?
90+ function buildRecipientNames (thread) {
91+ const myId = api.keys.sync.id()
92+
93+ return thread.value.content.recps
94+ .map(link => isString(link) ? link : link.link)
95+ .filter(link => link !== myId)
96+ .map(api.about.obs.name)
97+ }
98+
99+ return h('div.thread', link(thread), [
100+ h('div.context', context),
101+ h('div.content', [
102+ subjectEl,
103+ replyEl
104+ ])
51105 ])
52106 }
53107
54- function threadGroup (threads, obj, toName) {
108+ function threadGroup (threads, obj, toContext, opts) {
55109 // threads = a state object for all the types of threads
56110 // obj = a map of keys to root ids, where key ∈ (channel | group | concatenated list of pubkeys)
57- // toName = fn that derives a name from a particular thread
58-
59- var groupEl = h('div.group')
111+ // toContext = fn that derives the context of the group
112+ // opts = { nameRecipients }
113+
114+ var groupEl = h('div.threads')
60115 for(var k in obj) {
61116 var id = obj[k]
62117 var thread = get(threads, ['roots', id])
63118 if(thread && thread.value) {
64- var el = item(toName(k, thread), thread)
119+ var el = item(toContext(k, thread), thread, opts)
65120 if(el) groupEl.appendChild(el)
66121 }
67122 }
68123 return groupEl
@@ -79,27 +134,48 @@
79134 })
80135 .filter(Boolean)
81136 .reduce(threadReduce, null)
82137
83- container.appendChild(threadGroup(
84- threads,
85- threads.private,
86- function (_, msg) {
87- // NB: msg passed in is actually a 'thread', but only care about root msg
88-
89- return h('div.recps', [
90- msg.value.content.recps.map(function (link) {
91- return api.about.html.image(isString(link) ? link : link.link)
92- })
93- ])
94- }
95- ))
138+ const privateUpdatesSection = h('section.updates -directMessage', [
139+ h('h2', 'Direct Messages'),
140+ threadGroup(
141+ threads,
142+ threads.private,
143+ function (_, msg) {
144+ // NB: msg passed in is actually a 'thread', but only care about root msg
145+ const myId = api.keys.sync.id()
96146
97- container.appendChild(threadGroup(
98- threads,
99- threads.channels,
100- ch => h('h2.title', '#'+ch)
101- ))
147+ return msg.value.content.recps
148+ .map(link => isString(link) ? link : link.link)
149+ .filter(link => link !== myId)
150+ .map(api.about.html.image)
151+ },
152+ { nameRecipients: true }
153+ )
154+ ])
155+
156+ const channelUpdatesSection = h('section.updates -channel', [
157+ h('h2', 'Channels'),
158+ threadGroup(
159+ threads,
160+ threads.channels,
161+ ch => '#'+ch
162+ )
163+ ])
164+
165+ const groupUpdatesSection = h('section.updates -group', [
166+ h('h2', 'Groups'),
167+ 'TODO: complete + enable when groups are live'
168+ // threadGroup(
169+ // threads,
170+ // threads.groups,
171+ // toName ...
172+ // )
173+ ])
174+
175+ container.appendChild(privateUpdatesSection)
176+ container.appendChild(channelUpdatesSection)
177+ container.appendChild(groupUpdatesSection)
102178 })
103179 )
104180
105181 return h('Page -home', [
app/page/home.mcssView
@@ -1,17 +1,115 @@
11 Page -home {
2- h1 {}
32
43 div.container {
5- div.group {
6- div.threadLink {
7- div.recps {
8- img {
9- $smallAvatar
4+ $primaryBackground
5+
6+ section.updates {
7+
8+ -directMessage {
9+ $homePageSection
10+
11+ div.threads {
12+ div.thread {
13+ div.content {
14+ div.subject {
15+ display: flex
16+
17+ div.recps {
18+ display: flex
19+ font-weight: 600
20+ margin-right: .4rem
21+
22+ div.recp {
23+ margin-right: .4rem
24+ }
25+ }
26+ }
27+ }
1028 }
1129 }
1230 }
31+
32+ -channel {
33+ $homePageSection
34+
35+ div.threads {
36+ div.thread {
37+ div.context {
38+ background: #fff
39+ min-width: 8rem
40+ padding: .1rem .3rem
41+ border: 1px solid #ddd
42+ border-radius: 2px
43+ }
44+ }
45+ }
46+ }
47+
48+ -group {
49+ $homePageSection
50+ }
1351 }
1452 }
1553 }
1654
55+$homePageSection {
56+ display: flex
57+ flex-direction: column
58+ align-items: center
59+ margin-bottom: 1.5rem
1760
61+ h2 {
62+ color: #888
63+ font-size: 1rem
64+ text-align: center
65+ padding-bottom: .3rem
66+ width: 420px
67+ margin-top: 0
68+ margin-bottom: .4rem
69+ }
70+
71+ div.threads {
72+ div.thread {
73+ display: flex
74+ align-items: center
75+
76+ margin-bottom: .5rem
77+
78+ div.context {
79+ display: flex
80+ margin-right: 1rem
81+
82+ img {
83+ $smallAvatar
84+ margin-right: .5rem
85+ }
86+ }
87+
88+ div.content {
89+ flex-grow: 1
90+ background: #fff
91+ padding: 1rem
92+ border: 1px solid #ddd
93+ border-radius: 2px
94+
95+ div.subject {
96+ font-size: 1.2rem
97+ margin-bottom: .3rem
98+
99+ $largeMarkdown
100+ }
101+ div.reply {
102+ display: flex
103+ color: #444
104+
105+ div.replySymbol {
106+ margin-left: .7rem
107+ margin-right: .3rem
108+ }
109+
110+ $smallMarkdown
111+ }
112+ }
113+ }
114+ }
115+}
app/page/page.mcssView
@@ -2,6 +2,15 @@
22 h1 {
33 margin-left: 1rem
44 }
55
6+ div.Nav {}
7+
8+ div.container {
9+ $primaryBackground
10+ padding: 1rem
11+
12+ max-width: 1400px
13+
14+ }
615 }
716
app/page/private.jsView
@@ -18,8 +18,8 @@
1818
1919 return h('Page -private', [
2020 h('h1', 'Private message'),
2121 api.app.html.nav(),
22- thread
22+ h('div.container', thread)
2323 ])
2424 }
2525 }
styles/mixins.jsView
@@ -18,8 +18,12 @@
1818 $colorSubtle {
1919 color: #222
2020 }
2121
22+$primaryBackground {
23+ background-color: #f7f7f7
24+}
25+
2226 $smallAvatar {
2327 width: 3rem
2428 height: 3rem
2529 border-radius: 1.5rem
@@ -29,5 +33,45 @@
2933 width: 6rem
3034 height: 6rem
3135 border-radius: 3rem
3236 }
37+
38+$smallMarkdown {
39+ div.Markdown {
40+ h1, h2, h3, h4, h5, h6, p {
41+ font-size: 1rem
42+ font-weight: 300
43+ margin: 0
44+ }
45+ }
46+}
47+
48+$largeMarkdown {
49+ div.Markdown {
50+ h1, h2, h3, h4, h5, h6, p {
51+ font-size: 1.2rem
52+ font-weight: 300
53+ margin: 0
54+ }
55+ }
56+}
57+
58+$roundLeft {
59+ border-top-left-radius: .9rem
60+ border-bottom-left-radius: .9rem
61+}
62+
63+$roundRight {
64+ border-top-right-radius: .9rem
65+ border-bottom-right-radius: .9rem
66+}
67+
68+$roundTop {
69+ border-top-left-radius: .9rem
70+ border-top-right-radius: .9rem
71+}
72+
73+$roundBottom {
74+ border-bottom-left-radius: .9rem
75+ border-bottom-right-radius: .9rem
76+}
3377 `

Built with git-ssb-web