Commit e4aaa311b7efe7bf2540be819c77348f258eb18d
add working addressBook sections, styling
mix committed on 1/30/2018, 3:44:32 AMParent: 0b0275502152a806a995b36fd4d29e8c3df1195e
Files changed
app/html/sideNav/sideNavAddressBook.js | changed |
app/html/topNav/topNavAddressBook.js | changed |
app/html/topNav/topNavAddressBook.mcss | changed |
app/page/addressBook.js | changed |
app/page/addressBook.mcss | changed |
contact/html/follow.js | changed |
styles/button.mcss | changed |
translations/en.js | changed |
app/html/sideNav/sideNavAddressBook.js | ||
---|---|---|
@@ -14,9 +14,9 @@ | ||
14 | 14 | // 'app.html.scroller': 'first', |
15 | 15 | // 'about.html.avatar': 'first', |
16 | 16 | // 'about.obs.name': 'first', |
17 | 17 | // 'feed.pull.private': 'first', |
18 | - // 'history.sync.push': 'first', | |
18 | + 'history.sync.push': 'first', | |
19 | 19 | // 'message.html.subject': 'first', |
20 | 20 | // 'sbot.obs.localPeers': 'first', |
21 | 21 | 'translations.sync.strings': 'first', |
22 | 22 | // 'unread.sync.isUnread': 'first' |
@@ -28,10 +28,12 @@ | ||
28 | 28 | }) |
29 | 29 | |
30 | 30 | function sideNav (location, relationships) { |
31 | 31 | if (location.page !== 'addressBook') return |
32 | + if (!location.section) location.section = 'friends' | |
32 | 33 | |
33 | 34 | const strings = api.translations.sync.strings().addressBook |
35 | + const goTo = (loc) => () => api.history.sync.push(loc) | |
34 | 36 | |
35 | 37 | // TODO - show local peers? |
36 | 38 | // var nearby = api.sbot.obs.localPeers() |
37 | 39 | |
@@ -39,40 +41,47 @@ | ||
39 | 41 | LevelOneSideNav(), |
40 | 42 | ]) |
41 | 43 | |
42 | 44 | function LevelOneSideNav () { |
43 | - function count (relationshipType) { | |
44 | - return computed(relationships, rels => rels[relationshipType].length) | |
45 | - } | |
46 | - | |
47 | 45 | return h('div.level.-one', [ |
48 | 46 | h('section', [ |
49 | - h('Option', [ | |
50 | - h('Button -primary', {}, strings.action.addUser), | |
47 | + SectionOption('search', [ | |
48 | + h('Button -primary', {}, strings.action.addUser) | |
51 | 49 | ]), |
52 | 50 | h('hr'), |
53 | 51 | ]), |
54 | 52 | |
55 | 53 | //Friends |
56 | 54 | h('section', [ |
57 | 55 | h('header',strings.heading.people), |
58 | - h('Option', [ | |
59 | - h('i.fa.fa-angle-right'), | |
60 | - strings.section.friends, | |
61 | - h('div.count', count('friends')) | |
62 | - ]), | |
63 | - h('Option',[ | |
64 | - h('i.fa.fa-angle-right'), | |
65 | - strings.section.following, | |
66 | - h('div.count', count('following')) | |
67 | - ]), | |
68 | - h('Option',[ | |
69 | - h('i.fa.fa-angle-right'), | |
70 | - strings.section.followers, | |
71 | - h('div.count', count('followers')) | |
72 | - ]), | |
56 | + SectionOption('friends'), | |
57 | + SectionOption('following'), | |
58 | + SectionOption('followers'), | |
73 | 59 | ]) |
74 | 60 | ]) |
75 | 61 | } |
62 | + | |
63 | + function SectionOption (section, body) { | |
64 | + const className = section === location.section | |
65 | + ? '-selected' | |
66 | + : '' | |
67 | + return h('Option', | |
68 | + { className, 'ev-click': goTo({page: 'addressBook', section }) }, | |
69 | + body || defaulBody(section) | |
70 | + ) | |
71 | + | |
72 | + function defaulBody (section) { | |
73 | + return [ | |
74 | + h('i.fa.fa-angle-right'), | |
75 | + strings.section[section], | |
76 | + h('div.count', count(section)) | |
77 | + ] | |
78 | + } | |
79 | + } | |
80 | + | |
81 | + function count (relationshipType) { | |
82 | + return computed(relationships, rels => rels[relationshipType].length) | |
83 | + } | |
76 | 84 | } |
77 | 85 | } |
78 | 86 | |
87 | + |
app/html/topNav/topNavAddressBook.js | ||
---|---|---|
@@ -17,9 +17,9 @@ | ||
17 | 17 | return h('TopNav -addressBook', [ |
18 | 18 | h('div.search', [ |
19 | 19 | h('i.fa.fa-search'), |
20 | 20 | h('input', { |
21 | - placeholder: strings.userFind.action.findAUser, | |
21 | + placeholder: strings.addressBook.action.find[location.section], | |
22 | 22 | autofocus: 'autofocus', |
23 | 23 | 'ev-input': e => input.set(e.target.value) |
24 | 24 | }), |
25 | 25 | ]) |
app/html/topNav/topNavAddressBook.mcss | ||
---|---|---|
@@ -1,6 +1,7 @@ | ||
1 | 1 | TopNav -addressBook { |
2 | 2 | div.search { |
3 | + flex-grow: 1 | |
3 | 4 | $backgroundPrimaryText |
4 | 5 | |
5 | 6 | margin-bottom: .5rem |
6 | 7 |
app/page/addressBook.js | ||
---|---|---|
@@ -12,12 +12,14 @@ | ||
12 | 12 | |
13 | 13 | exports.needs = nest({ |
14 | 14 | 'about.html.avatar': 'first', |
15 | 15 | 'about.async.suggest': 'first', |
16 | + 'about.obs.name': 'first', | |
16 | 17 | 'app.html.topNav': 'first', |
17 | 18 | // 'app.html.scroller': 'first', |
18 | 19 | 'app.html.sideNav': 'first', |
19 | 20 | 'app.html.topNav': 'first', |
21 | + 'contact.html.follow': 'first', | |
20 | 22 | 'contact.obs.relationships': 'first', |
21 | 23 | 'history.sync.push': 'first', |
22 | 24 | 'keys.sync.id': 'first', |
23 | 25 | 'translations.sync.strings': 'first', |
@@ -37,26 +39,37 @@ | ||
37 | 39 | |
38 | 40 | const input = Value() |
39 | 41 | |
40 | 42 | const suggester = api.about.async.suggest() |
41 | - const users = computed(input, input => suggester(input)) | |
42 | - // might further prune this based on section | |
43 | + const users = computed([relationships, input], (relationships, input) => { | |
44 | + if (section === SEARCH) | |
45 | + return suggester(input) | |
46 | + else { | |
47 | + const sectionRels = relationships[section] | |
48 | + if (!input) // show all e.g. friends | |
49 | + return sectionRels.map(id => { | |
50 | + return { id, title: api.about.obs.name(id) } | |
51 | + }) | |
52 | + else // show suggestions, and filter just the ones we want e.g. friends | |
53 | + return suggester(input).filter(user => sectionRels.includes(user.id)) | |
54 | + } | |
55 | + }) | |
43 | 56 | |
57 | + const goTo = (loc) => () => api.history.sync.push(loc) | |
44 | 58 | |
45 | - // const goTo = (loc) => () => api.history.sync.push(loc) | |
46 | - | |
47 | 59 | return h('Page -addressBook', [ |
48 | 60 | api.app.html.sideNav(location, relationships), |
49 | 61 | h('Scroller.content', [ |
50 | 62 | h('section.top', [ |
51 | 63 | api.app.html.topNav(location, input), |
52 | 64 | ]), |
53 | 65 | h('section.content', [ |
54 | 66 | h('div.results', map(users, user => { |
55 | - return h('div.result', [ | |
67 | + return h('div.result', { 'ev-click': goTo({page: 'userShow', feed: user.id}) }, [ | |
56 | 68 | api.about.html.avatar(user.id), |
57 | 69 | h('div.alias', user.title), |
58 | - h('pre.key', user.id), | |
70 | + // h('pre.key', user.id), | |
71 | + api.contact.html.follow(user.id) | |
59 | 72 | ]) |
60 | 73 | })), |
61 | 74 | ]) |
62 | 75 | ]) |
app/page/addressBook.mcss | ||
---|---|---|
@@ -6,13 +6,18 @@ | ||
6 | 6 | position: sticky |
7 | 7 | } |
8 | 8 | |
9 | 9 | section.content { |
10 | + $maxWidthSmaller | |
11 | + | |
10 | 12 | div.results { |
13 | + flex-grow: 1 | |
14 | + | |
11 | 15 | $maxWidthSmaller |
12 | 16 | |
13 | 17 | div.result { |
14 | 18 | $backgroundPrimaryText |
19 | + cursor: pointer | |
15 | 20 | |
16 | 21 | padding: .5rem |
17 | 22 | |
18 | 23 | display: flex |
@@ -32,8 +37,10 @@ | ||
32 | 37 | color: #999 |
33 | 38 | |
34 | 39 | } |
35 | 40 | |
41 | + div.Follow {} | |
42 | + | |
36 | 43 | :hover { |
37 | 44 | background-color: #eee |
38 | 45 | |
39 | 46 | } |
contact/html/follow.js | ||
---|---|---|
@@ -23,16 +23,23 @@ | ||
23 | 23 | const { followers } = api.contact.obs |
24 | 24 | const theirFollowers = followers(feed) |
25 | 25 | const youFollowThem = computed(theirFollowers, followers => followers.includes(myId)) |
26 | 26 | |
27 | - const { unfollow, follow } = api.contact.async | |
28 | 27 | const className = when(youFollowThem, '-following') |
28 | + const follow = (feed) => ev => { | |
29 | + ev.stopPropagation() | |
30 | + api.contact.async.follow(feed) | |
31 | + } | |
32 | + const unfollow = (feed) => ev => { | |
33 | + ev.stopPropagation() | |
34 | + api.contact.async.unfollow(feed) | |
35 | + } | |
29 | 36 | |
30 | 37 | return h('Follow', { className }, |
31 | 38 | when(theirFollowers.sync, |
32 | 39 | when(youFollowThem, |
33 | - h('Button', { 'ev-click': () => unfollow(feed) }, strings.userShow.action.unfollow), | |
34 | - h('Button', { 'ev-click': () => follow(feed) }, strings.userShow.action.follow) | |
40 | + h('Button', { 'ev-click': unfollow(feed) }, strings.userShow.action.unfollow), | |
41 | + h('Button -strong', { 'ev-click': follow(feed) }, strings.userShow.action.follow) | |
35 | 42 | ), |
36 | 43 | h('Button', { disabled: 'disabled' }, strings.loading ) |
37 | 44 | ) |
38 | 45 | ) |
styles/button.mcss | ||
---|---|---|
@@ -36,9 +36,8 @@ | ||
36 | 36 | -strong { |
37 | 37 | $colorPrimary |
38 | 38 | $font |
39 | 39 | $borderPrimary |
40 | - | |
41 | 40 | } |
42 | 41 | |
43 | 42 | -channel { |
44 | 43 | $backgroundPrimary |
translations/en.js | ||
---|---|---|
@@ -62,9 +62,15 @@ | ||
62 | 62 | } |
63 | 63 | }, |
64 | 64 | addressBook: { |
65 | 65 | action: { |
66 | - addUser: 'Add a user' | |
66 | + addUser: 'Add a user', | |
67 | + find: { | |
68 | + friends: 'Search your friends', | |
69 | + following: "Search people you're following", | |
70 | + followers: 'Search your followers', | |
71 | + search: 'Search for a user', | |
72 | + } | |
67 | 73 | }, |
68 | 74 | heading: { |
69 | 75 | people: 'People' |
70 | 76 | }, |
Built with git-ssb-web