git ssb

16+

Dominic / patchbay



Commit c431b9f86d04597436c8fd31782d8ab7a1a65f4e

Merge pull request #83 from ssbc/refactor_hypertabs

Refactor hypertabs
mix irving authored on 2/3/2017, 6:30:33 AM
GitHub committed on 2/3/2017, 6:30:33 AM
Parent: 0132c055406a2cc025989cea9154fea161b776c9
Parent: da787189e650087caa476419997849d890f75995

Files changed

keyscroll.jschanged
modules_basic/avatar/avatar.jschanged
modules_basic/message/render.jschanged
modules_basic/scroller.mcsschanged
modules_core/app.jschanged
modules_core/search-box.jschanged
modules_core/style/index.jschanged
modules_core/style/hypertabs.jsadded
modules_core/style/hypertabs.mcssadded
modules_core/suggest-box.csschanged
modules_core/tabs.jschanged
modules_core/app.mcssadded
modules_core/search-box.mcssadded
modules_extra/search.jschanged
package.jsonchanged
style.csschanged
keyscroll.jsView
@@ -23,10 +23,10 @@
2323 curMsgEl = el
2424 }
2525
2626 return function scroll(d) {
27- selectChild(!curMsgEl ? container.firstChild
27 + selectChild((!curMsgEl || d == 'first') ? container.firstChild
28 + : d < 0 ? curMsgEl.previousElementSibling || container.firstChild
2829 : d > 0 ? curMsgEl.nextElementSibling || container.lastChild
29- : d < 0 ? curMsgEl.previousElementSibling || container.firstChild
3030 : curMsgEl)
3131 }
3232 }
modules_basic/avatar/avatar.jsView
@@ -20,8 +20,9 @@
2020 avatar_name_link
2121 }
2222
2323 function avatar (author, classes) {
24 + // ??? BUG
2425 return exports.avatar_image_name_link(author, classes)
2526 }
2627
2728 function avatar_image_name_link (author, classes) {
modules_basic/message/render.jsView
@@ -47,10 +47,10 @@
4747 ])
4848 return msgEl
4949
5050 function navigateToMessageOnEnter (ev) {
51- // on enter, hit first meta.
52- if(ev.keyCode == 13) {
51 + // on enter (or 'o'), hit first meta.
52 + if(ev.keyCode == 13 || ev.keyCode == 79) {
5353
5454 // unless in an input
5555 if (ev.target.nodeName === 'INPUT'
5656 || ev.target.nodeName === 'TEXTAREA') return
modules_basic/scroller.mcssView
@@ -3,8 +3,9 @@
33 flex-direction: column
44
55 overflow: auto
66 width: 100%
7 + height: 100%
78 min-height: 0px
89
910 div.wrapper {
1011 flex: 1
modules_core/app.jsView
@@ -1,46 +1,58 @@
1-var h = require('hyperscript')
2-var insertCss = require('insert-css')
1 +const fs = require('fs')
2 +const h = require('../h')
3 +const { Value } = require('@mmckegg/mutant')
4 +const insertCss = require('insert-css')
35
4-module.exports = {
5- needs: {
6- screen_view: 'first',
7- styles: 'first'
8- },
9- gives: 'app',
10- create: function (api) {
11- return function () {
12- process.nextTick(function () {
13- insertCss(api.styles())
14- })
6 +exports.needs = {
7 + screen_view: 'first',
8 + styles: 'first'
9 +}
1510
16- window.addEventListener('error', window.onError = function (e) {
17- document.body.appendChild(h('div.error',
18- h('h1', e.message),
19- h('big', h('code', e.filename + ':' + e.lineno)),
20- h('pre', e.error ? (e.error.stack || e.error.toString()) : e.toString())))
21- })
11 +exports.gives = {
12 + app: true,
13 + mcss: true
14 +}
2215
23- function hash() {
24- return window.location.hash.substring(1)
25- }
16 +exports.create = function (api) {
17 + return {
18 + app,
19 + mcss: () => fs.readFileSync(__filename.replace(/js$/, 'mcss'), 'utf8')
20 + }
2621
27- var view = api.screen_view(hash() || 'tabs')
22 + function app () {
23 + process.nextTick(() => insertCss(api.styles()))
2824
29- var screen = h('div.screen.column', view)
25 + var view = Value(getView())
26 + var screen = h('App', view)
3027
31- window.onhashchange = function (ev) {
32- var _view = view
33- view = api.screen_view(hash() || 'tabs')
28 + window.onhashchange = () => view.set(getView())
29 + document.body.appendChild(screen)
3430
35- if(_view) screen.replaceChild(view, _view)
36- else document.body.appendChild(view)
37- }
31 + window.addEventListener('error', window.onError = displayError)
3832
39- document.body.appendChild(screen)
33 + return screen
34 + }
4035
41- return screen
42- }
36 + function getView () {
37 + const view = window.location.hash.substring(1) || 'tabs'
38 + return api.screen_view(view)
4339 }
4440 }
4541
42 +function displayError (e) {
43 + document.body.querySelector('.\\.content').appendChild(
44 + h('div.page', [
45 + h('Error', { title: e.message }, [
46 + h('h1', e.message),
47 + h('big', [
48 + h('code', e.filename + ':' + e.lineno)
49 + ]),
50 + h('pre', e.error
51 + ? (e.error.stack || e.error.toString())
52 + : e.toString()
53 + )
54 + ])
55 + ])
56 + )
57 +}
4658
modules_core/search-box.jsView
@@ -1,50 +1,61 @@
11 'use strict'
2-var h = require('hyperscript')
2 +const h = require('../h')
3 +const fs = require('fs')
34
5 +
46 exports.needs = {
57 suggest_search: 'map', //REWRITE
68 build_suggest_box: 'first'
79 }
810
9-exports.gives = 'search_box'
11 +exports.gives = {
12 + search_box: true,
13 + mcss: true
14 +}
1015
1116 exports.create = function (api) {
1217
13- return function (go) {
14-
15- var search = h('input.searchprompt', {
18 + return {
19 + search_box,
20 + mcss: () => fs.readFileSync(__filename.replace(/js$/, 'mcss'), 'utf8')
21 + }
22 +
23 + function search_box (go) {
24 + const input = h('input', {
1625 type: 'search',
1726 placeholder: 'Commands',
18- onkeydown: ev => {
27 + 'ev-keyup': ev => {
1928 switch (ev.keyCode) {
2029 case 13: // enter
2130 ev.stopPropagation()
2231 suggestBox.complete()
2332
24- if (go(search.value.trim(), !ev.ctrlKey))
25- search.blur()
33 + if (go(input.value.trim(), !ev.ctrlKey))
34 + input.blur()
2635 return
2736 case 27: // escape
2837 ev.preventDefault()
29- search.blur()
38 + input.blur()
3039 return
3140 }
3241 }
3342 })
43 + const search = h('Search', input)
3444
45 + search.input = input
3546 search.activate = (sigil, ev) => {
36- search.focus()
47 + input.focus()
3748 ev.preventDefault()
38- if (search.value[0] === sigil) {
39- search.selectionStart = 1
40- search.selectionEnd = search.value.length
49 + if (input.value[0] === sigil) {
50 + input.selectionStart = 1
51 + input.selectionEnd = input.value.length
4152 } else {
42- search.value = sigil
53 + input.value = sigil
4354 }
4455 }
4556
46- var suggestBox = api.build_suggest_box(search, api.suggest_search)
57 + const suggestBox = api.build_suggest_box(input, api.suggest_search)
4758
4859 return search
4960 }
5061
modules_core/style/index.jsView
@@ -1,5 +1,6 @@
11 module.exports = {
2- 'styles': require('./styles'),
3- 'mixins': require('./mixins')
2 + 'hypertabs': require('./hypertabs'),
3 + 'mixins': require('./mixins'),
4 + 'styles': require('./styles')
45 }
56
modules_core/style/hypertabs.jsView
@@ -1,0 +1,13 @@
1 +const fs = require('fs')
2 +
3 +module.exports = {
4 + gives: {
5 + mcss: true
6 + },
7 + create: function (api) {
8 + return {
9 + mcss: () => fs.readFileSync(__filename.replace(/js$/, 'mcss'), 'utf8')
10 + }
11 + }
12 +}
13 +
modules_core/style/hypertabs.mcssView
@@ -1,0 +1,93 @@
1 +Hypertabs {
2 + display: flex
3 + flex-direction: column
4 +
5 + height: 100% /* needed to stop scroller blowing out */
6 +
7 + nav {
8 + display: flex
9 +
10 + background: linear-gradient(to bottom, #efefef, #e5e5e5)
11 +
12 + section.tabs {
13 + flex-grow: 1
14 + display: flex
15 + min-width: 0
16 +
17 + div.tab {
18 + flex-grow: 1
19 +
20 + display: flex
21 + align-items: center
22 + justify-content: space-between
23 +
24 + font-size: .9rem
25 + background-color: #efefef
26 + overflow-x: hidden
27 +
28 + padding: 0 .4rem
29 + margin-left: .6rem
30 + border: 1px gainsboro solid
31 + border-bottom: none
32 +
33 + -selected {
34 + color: #222
35 + background-color: #fff
36 +
37 + a.close {
38 + visibility: visible
39 + }
40 + }
41 +
42 + -notify {
43 + background-color: orange;
44 + }
45 +
46 +
47 + a {
48 + color: #666
49 +
50 + :hover {
51 + color: #0088cc
52 + text-decoration: none
53 + }
54 + }
55 +
56 + a.link {
57 + flex-grow: 1
58 + flex-shrink: 0
59 + overflow-x: hidden
60 + min-width: 0
61 + max-width: 90%
62 + white-space: nowrap
63 + text-overflow: ellipsis
64 + }
65 +
66 + a.close {
67 + visibility: hidden
68 + }
69 + }
70 +
71 + }
72 +
73 + div.extra {
74 + display: flex
75 + align-items: center
76 + }
77 + }
78 +
79 + section.content {
80 + display: flex
81 +
82 + height: 100% /* needed to stop making nav weird */
83 +
84 + div.page {
85 + flex-grow: 1
86 +
87 + display: flex /*hack to get give Scroller context it needs */
88 +
89 + padding-top: .2rem
90 + }
91 + }
92 +}
93 +
modules_core/suggest-box.cssView
@@ -27,9 +27,9 @@
2727 background-color: #fff;
2828 border: 1px gainsboro solid;
2929
3030 padding: .2rem .5rem;
31- margin-top: .7rem;
31 + margin-top: .35rem;
3232 }
3333
3434 body > .suggest-box > ul {
3535 list-style-type: none;
modules_core/tabs.jsView
@@ -1,6 +1,6 @@
11 const Tabs = require('hypertabs')
2-const h = require('hyperscript')
2 +const h = require('../h')
33 const keyscroll = require('../keyscroll')
44 const open = require('open-external')
55 const { webFrame, remote } = require('electron')
66
@@ -24,44 +24,40 @@
2424 return function (path) {
2525 if(path !== 'tabs') return
2626
2727 function setSelected (indexes) {
28- var ids = indexes.map(function (index) {
29- return tabs.get(index).id
30- })
28 + const ids = indexes.map(index => tabs.get(index).content.id)
3129 if(search)
3230 if(ids.length > 1)
33- search.value = 'split('+ids.join(',')+')'
31 + search.input.value = 'split('+ids.join(',')+')'
3432 else
35- search.value = ids[0]
33 + search.input.value = ids[0]
3634 }
3735
38- var search
39- var tabs = Tabs(setSelected)
40-
41- search = api.search_box(function (path, change) {
42-
36 + const tabs = Tabs(setSelected)
37 + const search = api.search_box((path, change) => {
4338 if(tabs.has(path)) {
4439 tabs.select(path)
4540 return true
4641 }
47- var el = api.screen_view(path)
4842
49- if(el) {
50- if(!el.title) el.title = path
51- el.scroll = keyscroll(el.querySelector('.Scroller .\\.content'))
52- tabs.add(el, change)
53- // localStorage.openTabs = JSON.stringify(tabs.tabs)
54- return change
55- }
43 + const el = api.screen_view(path)
44 + if (!el) return
45 +
46 + if(!el.title) el.title = path
47 + el.scroll = keyscroll(el.querySelector('.Scroller .\\.content'))
48 + tabs.add(el, change)
49 +// localStorage.openTabs = JSON.stringify(tabs.tabs)
50 + return change
5651 })
5752
58- //reposition hypertabs menu to inside a container...
59- tabs.insertBefore(h('div.header.row',
60- h('div.header__tabs.row', tabs.firstChild), //tabs
61- h('div.header__search.row.end', [search, api.menu()])
62- ), tabs.firstChild)
63- // tabs.insertBefore(search, tabs.firstChild.nextSibling)
53 + // TODO add options to Tabs : e.g. Tabs(setSelected, { append: el })
54 + tabs.firstChild.appendChild(
55 + h('div.extra', [
56 + search,
57 + api.menu()
58 + ])
59 + )
6460
6561 var saved = []
6662 // try { saved = JSON.parse(localStorage.openTabs) }
6763 // catch (_) { }
@@ -78,8 +74,9 @@
7874 if(el) tabs.add(el, false, false)
7975 })
8076
8177 tabs.select(0)
78 + search.input.value = null // start with an empty field to show placeholder
8279
8380 //handle link clicks
8481 window.onclick = function (ev) {
8582 var link = ancestor(ev.target)
@@ -109,24 +106,34 @@
109106
110107 return false
111108 }
112109
110 + var gPressed = false
113111 window.addEventListener('keydown', function (ev) {
114112 if (ev.target.nodeName === 'INPUT' || ev.target.nodeName === 'TEXTAREA')
115113 return
114 +
115 + // scroll to top
116 + if (ev.keyCode == 71) { // g
117 + if (!gPressed) return gPressed = true
118 + var el = tabs.get(tabs.selected[0]).firstChild.scroll('first')
119 + gPressed = false
120 + } else {
121 + gPressed = false
122 + }
123 +
116124 switch(ev.keyCode) {
117-
118125 // scroll through tabs
119126 case 72: // h
120127 return tabs.selectRelative(-1)
121128 case 76: // l
122129 return tabs.selectRelative(1)
123130
124131 // scroll through messages
125132 case 74: // j
126- return tabs.get(tabs.selected[0]).scroll(1)
133 + return tabs.get(tabs.selected[0]).firstChild.scroll(1)
127134 case 75: // k
128- return tabs.get(tabs.selected[0]).scroll(-1)
135 + return tabs.get(tabs.selected[0]).firstChild.scroll(-1)
129136
130137 // close a tab
131138 case 88: // x
132139 if (tabs.selected) {
modules_core/app.mcssView
@@ -1,0 +1,29 @@
1 +App {
2 + position: absolute
3 +
4 + top: 0
5 + bottom: 0
6 + left: 0
7 + right: 0
8 + overflow: hidden
9 + min-height: 0px
10 +
11 +}
12 +
13 +
14 +Error {
15 + padding: 1rem
16 +
17 + h1 {
18 + color: red
19 + }
20 +
21 + big {
22 + }
23 +
24 + pre {
25 + padding: 1rem
26 + border: 1px gainsboro solid
27 + }
28 +}
29 +
modules_core/search-box.mcssView
@@ -1,0 +1,13 @@
1 +Search {
2 + input {
3 + height: 1.4rem
4 + border-radius: .1rem
5 +
6 + padding-left: .7rem
7 + padding-right: .5rem
8 +
9 + margin-left: 1em
10 + /* margin-right: 1em */
11 + }
12 +}
13 +
modules_extra/search.jsView
@@ -61,8 +61,9 @@
6161 var total = 0, matches = 0
6262
6363 var header = h('div.search_header', '')
6464 var { container, content } = api.build_scroller({ prepend: header})
65 + container.id = path // helps tabs find this tab
6566
6667 function matchesQuery (data) {
6768 total++
6869 var m = _matches(data)
package.jsonView
@@ -29,9 +29,9 @@
2929 "hyperfile": "^1.1.0",
3030 "hyperlightbox": "1.0.0",
3131 "hyperprogress": "0.1.0",
3232 "hyperscript": "^1.4.7",
33- "hypertabs": "^3.0.3",
33 + "hypertabs": "^4.0.0",
3434 "insert-css": "^2.0.0",
3535 "is-visible": "^2.1.1",
3636 "kvgraph": "^0.1.0",
3737 "map-filter-reduce": "^3.0.1",
style.cssView
@@ -28,15 +28,8 @@
2828 color: #005580;
2929 text-decoration: underline;
3030 }
3131
32-.screen {
33- position: absolute;
34- top: 0; bottom: 0;
35- left: 0; right: 0;
36- overflow-y: hidden;
37-}
38-
3932 .column {
4033 display: flex;
4134 flex-direction: column;
4235 min-height:0px;
@@ -65,18 +58,8 @@
6558 .expand {
6659 justify-content: space-between;
6760 }
6861
69-.scroll-y {
70- overflow-y: auto;
71- min-height: 0px;
72-}
73-
74-.scroll-x {
75- overflow-x: auto;
76- min-width: 0px;
77-}
78-
7962 pre {
8063 white-space: pre-wrap;
8164 word-wrap: break-word;
8265 }
@@ -150,21 +133,8 @@
150133 border-radius: .2em;
151134 z-index: 5;
152135 }
153136
154-/* scrolling feeds, threads */
155-
156-.scroller {
157- width: 100%;
158-}
159-
160-.scroller__wrapper {
161- flex: 1;
162- max-width: 600px;
163- margin-left: auto;
164- margin-right: auto;
165-}
166-
167137 /* messages */
168138 /* is .title used any more? */
169139
170140 .title {
@@ -207,21 +177,8 @@
207177 .avatar--fullsize {
208178 width: 50%;
209179 }
210180
211-.profile {
212- padding: .5ex;
213- overflow: auto;
214-}
215-
216-.profile input {
217- width: 100%;
218-}
219-
220-.profile__info {
221- margin-left: .5em;
222-}
223-
224181 /* lightbox - used in message-confirm */
225182
226183 .lightbox {
227184 position: fixed;
@@ -240,22 +197,9 @@
240197 border: 1px solid #eee;
241198 border-radius: .2em;
242199 }
243200
244-/* searchprompt */
245201
246-.searchprompt {
247- float: left;
248- width: 85%;
249- height: 2em;
250- margin-top: .3em;
251- border-radius: 1em;
252- padding-left: .7em;
253- padding-right: 0.5em;
254- margin-left: 1em;
255- margin-right: 1em;
256-}
257-
258202 /* TextNodeSearcher highlights */
259203
260204 highlight {
261205 background: #ff8;
@@ -289,79 +233,16 @@
289233 border-radius: 100%;
290234 background: #08c;
291235 }
292236
293-.error {
294- background: red;
295-}
296-
297237 /* tabs */
298238
299239 .header {
300240 background: #f5f5f5;
301241 border-bottom: 1px inset;
302242 flex-shrink: 0;
303243 }
304244
305-.header__tabs {
306- width: 100%;
307- min-width: 0px;
308-}
309-
310-/* --- hypertabs ------- */
311-
312-.hypertabs__tabs {
313- min-width: 0px;
314- width: 100%;
315-}
316-
317-.hypertabs__tab {
318- overflow-x: hidden;
319- min-width: 0px;
320- width: 100%;
321-}
322-
323-.hypertabs__button {
324- overflow-x: hidden;
325- min-width: 0px;
326- width: 100%;
327-}
328-
329-.hypertabs__tab {
330- color: black;
331- background: #f5f5f5;
332- border-top-left-radius: 5px;
333- margin-left: -3px;
334- border-bottom: none;
335- padding-top: .56em;
336- padding-left: 1em;
337- border-left: 1px solid #ddd;
338- width: 100%;
339-}
340-
341-.hypertabs__tab > a {
342- color: #666;
343- text-decoration: none;
344- white-space: nowrap;
345- font-size: .9em;
346-}
347-
348-.hypertabs--selected {
349- font-weight: bold;
350- background: #eee;
351- border-top-right-radius: 5px;
352- z-index: 1;
353-}
354-
355-.hypertabs__x {
356- display: none;
357- transform: translate(-4px, -3px);
358-}
359-
360-.hypertabs--selected .hypertabs__x {
361- display: block;
362-}
363-
364245 /* progress bar */
365246
366247 .hyperprogress__bar {
367248 background: darkgrey;

Built with git-ssb-web