Commit 271995b29180d065f2acc8b818aa0c1205347eff
/settings - gather settings into "groups"
mixmix committed on 6/2/2019, 10:06:32 AMParent: 9f3a1ffa087ad2ef7a4480ade6674f675f2d109d
Files changed
app/html/settings/default-tabs.js | ||
---|---|---|
@@ -19,12 +19,13 @@ | ||
19 | 19 | function defaultTabs () { |
20 | 20 | const defaultTabs = api.settings.obs.get('patchbay.defaultTabs', '') |
21 | 21 | const setDefaultTabs = (ev) => { |
22 | 22 | const tabs = ev.target.value.split(',').map(s => s.trim()).filter(Boolean) |
23 | - api.settings.sync.set({patchbay: {defaultTabs: tabs}}) | |
23 | + api.settings.sync.set({ patchbay: { defaultTabs: tabs } }) | |
24 | 24 | } |
25 | 25 | |
26 | 26 | return { |
27 | + group: 'general', | |
27 | 28 | title: 'Default Tabs', |
28 | 29 | body: h('DefaultTabs', [ |
29 | 30 | h('p', 'Comma-seperated list of tabs which will open on startup.'), |
30 | 31 | h('p', [ |
app/html/settings/friend-hops.js | ||
---|---|---|
@@ -29,8 +29,9 @@ | ||
29 | 29 | updateConfig(hops) |
30 | 30 | }) |
31 | 31 | |
32 | 32 | return { |
33 | + group: 'gossip', | |
33 | 34 | title: 'Friend Hops', |
34 | 35 | body: h('FriendHops', [ |
35 | 36 | h('div.description', [ |
36 | 37 | 'What you replicate (store a local copy of) is based on how many "hops" you replicate. If you replicate out to 1 hop, you are replicating the people you follow, at 2 hops, it is your follows and people they follow. Play with the slider to see this visualised in the graphic below!' |
app/html/settings/friend-pub.js | ||
---|---|---|
@@ -32,8 +32,9 @@ | ||
32 | 32 | updatePubs(hops) |
33 | 33 | }) |
34 | 34 | |
35 | 35 | return { |
36 | + group: 'gossip', | |
36 | 37 | title: 'Pub gossip', |
37 | 38 | body: h('FriendPub', [ |
38 | 39 | h('div.description', [ |
39 | 40 | 'Limit gossip with pubs based on who owns the pub' |
app/html/settings/remove-exif.js | ||
---|---|---|
@@ -18,13 +18,14 @@ | ||
18 | 18 | |
19 | 19 | function removeExif () { |
20 | 20 | const removeExif = api.settings.obs.get('patchbay.removeExif', true) |
21 | 21 | const toggleRemoveExif = (ev) => { |
22 | - api.settings.sync.set({patchbay: {removeExif: ev.target.checked}}) | |
22 | + api.settings.sync.set({ patchbay: { removeExif: ev.target.checked } }) | |
23 | 23 | } |
24 | 24 | |
25 | 25 | return { |
26 | - title: 'Exif metadata', | |
26 | + group: 'attachments', | |
27 | + title: 'Image metadata', | |
27 | 28 | body: h('DefaultTabs', [ |
28 | 29 | h('p', [ |
29 | 30 | 'Remove exif metadata from images such as GPS coordinates, phone/camera brand etc.', |
30 | 31 | h('input', { |
app/html/settings/tor-only.js | ||
---|---|---|
@@ -26,8 +26,9 @@ | ||
26 | 26 | updateConfig(torOnly) |
27 | 27 | }) |
28 | 28 | |
29 | 29 | return { |
30 | + group: 'gossip', | |
30 | 31 | title: 'Tor only connections', |
31 | 32 | body: h('TorOnly', [ |
32 | 33 | h('p', [ |
33 | 34 | 'Preserve your ip privacy by only connecting to other nodes using tor', |
app/html/settings/zz-version.js | ||
---|---|---|
@@ -12,8 +12,9 @@ | ||
12 | 12 | }) |
13 | 13 | |
14 | 14 | function versionsData () { |
15 | 15 | return { |
16 | + group: 'general', | |
16 | 17 | title: 'Installer version', |
17 | 18 | body: h('Version', [ |
18 | 19 | h('p', [ |
19 | 20 | h('code', process.platform), |
app/page/settings.js | ||
---|---|---|
@@ -1,6 +1,6 @@ | ||
1 | 1 | const nest = require('depnest') |
2 | -const { h } = require('mutant') | |
2 | +const { h, Value, computed } = require('mutant') | |
3 | 3 | |
4 | 4 | exports.gives = nest({ |
5 | 5 | 'app.html.menuItem': true, |
6 | 6 | 'app.page.settings': true |
@@ -24,23 +24,55 @@ | ||
24 | 24 | }, '/settings') |
25 | 25 | } |
26 | 26 | |
27 | 27 | function settingsPage (location) { |
28 | + const groups = groupSettings(api.app.html.settings()) | |
29 | + const groupNames = Object.keys(groups) | |
30 | + .sort((a, b) => { | |
31 | + if (a === 'general') return -1 | |
32 | + else if (b === 'general') return 1 | |
33 | + else return a < b ? -1 : +1 | |
34 | + }) | |
35 | + const activeGroup = Value('general') // NOTE this assume this group exists! | |
36 | + | |
28 | 37 | var page = h('SettingsPage', { title: '/settings' }, [ |
29 | - h('div.container', [ | |
30 | - h('h1', 'Settings'), | |
31 | - api.app.html.settings().map(setting => { | |
32 | - if (!setting.title && !setting.body) throw new Error('app.html.settings requires settings in form { title, body }') | |
38 | + h('div.container', computed(activeGroup, _activeGroup => { | |
39 | + return [ | |
40 | + h('section.groups', groupNames.map(group => { | |
41 | + return h('div.group', | |
42 | + { | |
43 | + 'className': group === _activeGroup ? '-active' : '', | |
44 | + 'ev-click': () => activeGroup.set(group) | |
45 | + }, | |
46 | + group | |
47 | + ) | |
48 | + })), | |
49 | + h('section.group-settings', groups[_activeGroup].map(Setting)) | |
50 | + ] | |
51 | + })) | |
52 | + ]) | |
33 | 53 | |
34 | - return h('section', [ | |
35 | - h('h2', setting.title), | |
36 | - setting.body | |
37 | - ]) | |
38 | - }) | |
54 | + function Setting (setting) { | |
55 | + return h('div.setting', [ | |
56 | + h('h2', setting.title), | |
57 | + setting.body | |
39 | 58 | ]) |
40 | - ]) | |
59 | + } | |
41 | 60 | |
42 | 61 | var { container } = api.app.html.scroller({ prepend: page }) |
43 | 62 | container.title = '/settings' |
44 | 63 | return container |
45 | 64 | } |
46 | 65 | } |
66 | + | |
67 | +function groupSettings (settings) { | |
68 | + return settings | |
69 | + .reduce((acc, setting) => { | |
70 | + if (!setting.title || !setting.body) throw new Error('setting sections require title, body') | |
71 | + | |
72 | + const group = (setting.group || setting.title).toLowerCase() | |
73 | + if (acc[group]) acc[group].push(setting) | |
74 | + else acc[group] = [setting] | |
75 | + | |
76 | + return acc | |
77 | + }, {}) | |
78 | +} |
app/page/settings.mcss | ||
---|---|---|
@@ -1,55 +1,75 @@ | ||
1 | 1 | SettingsPage { |
2 | - flex-grow: 1 | |
3 | - | |
4 | - display: flex | |
5 | - justify-content: center | |
6 | - | |
7 | 2 | div.container { |
8 | 3 | background-color: hsla(0, 0%, 100%, .3) |
9 | 4 | padding: 1rem |
10 | 5 | margin: 1rem 0 |
11 | 6 | |
12 | - h1 { | |
13 | - text-transform: uppercase | |
14 | - font-size: .8rem | |
15 | - letter-spacing: 3.4px | |
16 | - margin-bottom: 3rem | |
17 | - margin-left: .3rem | |
18 | - } | |
7 | + display: grid | |
8 | + grid-template-columns: 8rem 1fr | |
9 | + grid-gap: 2rem | |
19 | 10 | |
20 | - section { | |
21 | - margin-bottom: 3rem | |
22 | - h2 { | |
23 | - margin: 0 | |
24 | - margin-left: .3rem | |
25 | - font-size: 1rem | |
26 | - text-transform: uppercase | |
27 | - letter-spacing: 2px | |
28 | - } | |
11 | + section.groups { | |
12 | + display: grid | |
13 | + align-content: start | |
14 | + grid-gap: 1px | |
29 | 15 | |
30 | 16 | div { |
31 | - p, div { | |
32 | - margin-top: .2rem | |
33 | - margin-left: .3rem | |
17 | + background: #fff | |
18 | + cursor: pointer | |
19 | + | |
20 | + padding: .3rem .5rem | |
21 | + | |
22 | + -active { | |
23 | + background: #000 | |
24 | + color: #fff | |
34 | 25 | } |
35 | 26 | |
36 | - textarea { | |
37 | - min-width: 400px | |
38 | - width: 600px | |
39 | - max-width: 600px | |
40 | - min-height: 200px | |
41 | - border: 1px solid gainsboro | |
27 | + :hover { | |
28 | + background: #000 | |
29 | + color: #fff | |
42 | 30 | } |
31 | + } | |
32 | + } | |
43 | 33 | |
44 | - input { | |
34 | + section.group-settings { | |
35 | + display: grid | |
36 | + grid-gap: 1rem | |
37 | + | |
38 | + div.setting { | |
39 | + margin-bottom: 3rem | |
40 | + h2 { | |
45 | 41 | font-size: 1rem |
42 | + text-transform: uppercase | |
43 | + letter-spacing: 2px | |
46 | 44 | |
47 | - padding: .5rem | |
48 | - border: 1px solid gainsboro | |
45 | + margin: 0 0 1rem .3rem | |
46 | + border-bottom: 2px solid #3e3e3e | |
47 | + } | |
49 | 48 | |
50 | - width: 600px | |
51 | - max-width: 600px | |
49 | + div { | |
50 | + p, div { | |
51 | + margin-top: .2rem | |
52 | + margin-left: .3rem | |
53 | + } | |
54 | + | |
55 | + textarea { | |
56 | + min-width: 400px | |
57 | + width: 600px | |
58 | + max-width: 600px | |
59 | + min-height: 200px | |
60 | + border: 1px solid gainsboro | |
61 | + } | |
62 | + | |
63 | + input { | |
64 | + font-size: 1rem | |
65 | + | |
66 | + padding: .5rem | |
67 | + border: 1px solid gainsboro | |
68 | + | |
69 | + width: 600px | |
70 | + max-width: 600px | |
71 | + } | |
52 | 72 | } |
53 | 73 | } |
54 | 74 | } |
55 | 75 | } |
Built with git-ssb-web