Commit 38af2fdb5719a156793f1114d29328b6f0386cd7
Merge branch 'master' into themes
Charles Lehner committed on 9/9/2016, 4:08:39 PMParent: 8298966ab96c8c27a2242f7a6f9f09269869b1c9
Parent: 7d994cda047fc045d76893bc013c17e2098c3b19
Files changed
README.md | changed |
modules/app.js | changed |
modules/avatar-image.js | changed |
modules/compose.js | changed |
modules/feed.js | changed |
modules/search-box.js | changed |
modules/tabs.js | changed |
modules/avatar_fallback.png | added |
modules/menu.js | added |
package.json | changed |
style.css | changed |
README.md | ||
---|---|---|
@@ -1,56 +1,19 @@ | ||
1 | 1 … | # patchbay |
2 | 2 … | |
3 | 3 … | Prototype of a pluggable patchwork. |
4 | 4 … | |
5 | -Patchbay uses [depject](https://npm.im/depject) to provide | |
6 | -a highly composable api. all scripts in the `./modules` directory | |
7 | -are loaded and combined using [depject](https://npm.im/depject) | |
5 … | +`patchbay` is an secure-scuttlebutt client interface | |
6 … | +that is fully compatible with [patchwork](https://github.com/ssbc/patchwork) | |
8 | 7 … | |
8 … | +I started `patchbay` to experiment with a different internal architecture | |
9 … | +based on [depject](https://github.com/dominictarr/depject). The goal was | |
10 … | +to make it easier to develop new features, and enable or disable features. | |
11 … | +This has so far been quite successful! | |
12 … | + | |
9 | 13 … | This makes in very easy to create say, a renderer for a new message type, |
10 | 14 … | or switch to a different method for choosing user names. |
11 | 15 … | |
12 | -## overview | |
13 | - | |
14 | -Currently, the main module is `tabs.js` which plugs into | |
15 | -the `app` socket, and provides the `screen_view` socket. | |
16 | -when you click a link, `screen_view` socket with the link path, | |
17 | -which returns a html element which becomes a new tab. | |
18 | - | |
19 | -currently, `main.js` `feed.js` and `thread.js` plug into `screen_view` | |
20 | -and then in turn, call the `message_render` socket, which calls | |
21 | -`message_content` `avatar` `message_meta` `message_action` and `message_link`. | |
22 | - | |
23 | -`avatar.js` plugs into `avatar`, and provides the `avatar_name` socket. | |
24 | -it just returns a link to the public key, labled with what it gets back | |
25 | -from `avatar_name` socket. this is in turn provided by the `names.js` module. | |
26 | - | |
27 | -Two modules plug into `message_content`, `post.js` and `like.js` | |
28 | - | |
29 | -No plugs into the `message_action` socket have been implemented yet, | |
30 | -but whatever is returned from this will inserted into the dom at the bottom | |
31 | -of the message (by the `message` module) so this would be the plug to | |
32 | -use for implementing a like/+1/fav/dig/yup button, or a reply button. | |
33 | - | |
34 | -## other ideas | |
35 | - | |
36 | -Editable messages would probably need to plug into several sockets. | |
37 | -firstly they would render content differently, so probably use the `message_content` socket. | |
38 | -secondly they would need to show edit state, which would probably use `message_meta` | |
39 | -and finially they'd need to provide the ability to edit the message! | |
40 | -that would use `message_action` | |
41 | - | |
42 | -Implementing a "events" message type would be easy, just implement another | |
43 | -plug for `message_content`, that renders events. | |
44 | - | |
45 | -Instead of reading all the modules in a directory, it would be better | |
46 | -to load these from configuration. Then, modules could be distributed | |
47 | -as browserify bundles, and distributed over ssb. Configuration | |
48 | -could just be a list of hashes - but you could also disable specific | |
49 | -sockets or plugs if necessary (leaving them unconnected). | |
50 | - | |
51 | -Then, that configuration could be shared over ssb! | |
52 | - | |
53 | 16 … | ## Running |
54 | 17 … | |
55 | 18 … | ``` |
56 | 19 … | npm install scuttlebot@latest -g |
@@ -75,10 +38,21 @@ | ||
75 | 38 … | npm run build |
76 | 39 … | electro index.js |
77 | 40 … | ``` |
78 | 41 … | |
79 | -## modules | |
42 … | +## how to add a feature | |
80 | 43 … | |
44 … | +To add a new message type, add add a js to `./modules/` that | |
45 … | +exports a function named `message_content` (it should return an html element) | |
46 … | +To add a new tab, export a function named `screen_view` (returns an html element) | |
47 … | + | |
48 … | +To add a new detail, that appears above a message, | |
49 … | +export a function named `message_meta`. | |
50 … | + | |
51 … | +see the code for more examples. | |
52 … | + | |
53 … | +## module graph | |
54 … | + | |
81 | 55 … | patchbay uses [depject](http://github.com/dominictarr/depject) to manage it's modules. |
82 | 56 … | here is a graph of the current connections between them. (round shows module, |
83 | 57 … | square shows api, arrow direction points from user to provider) |
84 | 58 … | |
@@ -86,4 +60,9 @@ | ||
86 | 60 … | |
87 | 61 … | ## License |
88 | 62 … | |
89 | 63 … | MIT |
64 … | + | |
65 … | + | |
66 … | + | |
67 … | + | |
68 … | + |
modules/app.js | ||
---|---|---|
@@ -1,39 +1,19 @@ | ||
1 | 1 … | var plugs = require('../plugs') |
2 | 2 … | var h = require('hyperscript') |
3 | 3 … | |
4 | 4 … | var screen_view = plugs.first(exports.screen_view = []) |
5 | -var menu_items = plugs.map(exports.menu_items = []) | |
6 | 5 … | |
7 | -var status = h('div.status.error') //start off disconnected | |
8 | -var list = h('div.column', {style: 'display: none;'}) | |
9 | 6 … | |
10 | -var menu = h('div.menu.row', list, status, { | |
11 | - onmouseover: function (e) { | |
12 | - list.style.display = 'flex' | |
13 | - }, onmouseout: function () { | |
14 | - list.style.display = 'none' | |
15 | - } | |
16 | -}) | |
17 | - | |
18 | -exports.connection_status = function (err) { | |
19 | - if(err) status.classList.add('error') | |
20 | - else status.classList.remove('error') | |
21 | -} | |
22 | - | |
23 | 7 … | exports.app = function () { |
24 | 8 … | function hash() { |
25 | 9 … | return window.location.hash.substring(1) |
26 | 10 … | } |
27 | 11 … | |
28 | 12 … | var view = screen_view(hash() || 'tabs') |
29 | 13 … | |
30 | - var screen = h('div.screen.column', menu, view) | |
14 … | + var screen = h('div.screen.column', view) | |
31 | 15 … | |
32 | - menu_items().forEach(function (el) { | |
33 | - list.appendChild(el) | |
34 | - }) | |
35 | - | |
36 | 16 … | window.onhashchange = function (ev) { |
37 | 17 … | var _view = view |
38 | 18 … | view = screen_view(hash() || 'tabs') |
39 | 19 … | |
@@ -69,4 +49,9 @@ | ||
69 | 49 … | |
70 | 50 … | |
71 | 51 … | |
72 | 52 … | |
53 … | + | |
54 … | + | |
55 … | + | |
56 … | + | |
57 … | + |
modules/avatar-image.js | ||
---|---|---|
@@ -1,8 +1,9 @@ | ||
1 | 1 … | |
2 | 2 … | var getAvatar = require('ssb-avatar') |
3 | 3 … | var h = require('hyperscript') |
4 | 4 … | var ref = require('ssb-ref') |
5 … | +var path = require('path') | |
5 | 6 … | |
6 | 7 … | var plugs = require('../plugs') |
7 | 8 … | var sbot_query = plugs.first(exports.sbot_query = []) |
8 | 9 … | var blob_url = require('../plugs').first(exports.blob_url = []) |
@@ -10,9 +11,9 @@ | ||
10 | 11 … | var pull = require('pull-stream') |
11 | 12 … | |
12 | 13 … | var id = require('../keys').id |
13 | 14 … | |
14 | -var default_avatar = '&qjeAs8+uMXLlyovT4JnEpMwTNDx/QXHfOl2nv2u0VCM=.sha256' | |
15 … | +var default_avatar = path.join(__dirname, 'avatar_fallback.png') | |
15 | 16 … | |
16 | 17 … | var avatars = AVATARS = {} |
17 | 18 … | |
18 | 19 … | function isFunction (f) { |
@@ -77,9 +78,9 @@ | ||
77 | 78 … | exports.avatar_image = function (author, classes) { |
78 | 79 … | classes = classes || '' |
79 | 80 … | if(classes && 'string' === typeof classes) classes = '.avatar--'+classes |
80 | 81 … | |
81 | - var img = h('img'+classes, {src: blob_url(default_avatar)}) | |
82 … | + var img = h('img'+classes, {src: default_avatar}) | |
82 | 83 … | // getAvatar({links: sbot_links}, id, author, function (err, avatar) { |
83 | 84 … | // if (err) return console.error(err) |
84 | 85 … | // if(ref.isBlob(avatar.image)) |
85 | 86 … | // img.src = blob_url(avatar.image) |
modules/compose.js | ||
---|---|---|
@@ -22,9 +22,9 @@ | ||
22 | 22 … | sbot = prepublish, prepublish = id |
23 | 23 … | var accessories |
24 | 24 … | meta = meta || {} |
25 | 25 … | if(!meta.type) throw new Error('message must have type') |
26 | - var ta = h('textarea') | |
26 … | + var ta = h('textarea', {placeholder: 'Write a message'}) | |
27 | 27 … | |
28 | 28 … | var blur |
29 | 29 … | ta.addEventListener('focus', function () { |
30 | 30 … | clearTimeout(blur) |
modules/feed.js | ||
---|---|---|
@@ -8,8 +8,9 @@ | ||
8 | 8 … | var plugs = require('../plugs') |
9 | 9 … | var sbot_user_feed = plugs.first(exports.sbot_user_feed = []) |
10 | 10 … | var message_render = plugs.first(exports.message_render = []) |
11 | 11 … | var avatar_profile = plugs.first(exports.avatar_profile = []) |
12 … | +var signifier = plugs.first(exports.signifier = []) | |
12 | 13 … | |
13 | 14 … | exports.screen_view = function (id) { |
14 | 15 … | //TODO: header of user info, avatars, names, follows. |
15 | 16 … | |
@@ -23,8 +24,13 @@ | ||
23 | 24 … | content |
24 | 25 … | ) |
25 | 26 … | ) |
26 | 27 … | |
28 … | + signifier(id, function (_, names) { | |
29 … | + if(names.length) div.title = names[0].name | |
30 … | + }) | |
31 … | + | |
32 … | + | |
27 | 33 … | pull( |
28 | 34 … | sbot_user_feed({id: id, old: false, live: true}), |
29 | 35 … | Scroller(div, content, message_render, true, false) |
30 | 36 … | ) |
@@ -47,6 +53,4 @@ | ||
47 | 53 … | |
48 | 54 … | |
49 | 55 … | |
50 | 56 … | |
51 | - | |
52 | - |
modules/search-box.js | ||
---|---|---|
@@ -14,8 +14,9 @@ | ||
14 | 14 … | |
15 | 15 … | var suggestBox |
16 | 16 … | var search = h('input.searchprompt', { |
17 | 17 … | type: 'search', |
18 … | + placeholder: '?word, @key, #channel', | |
18 | 19 … | onkeydown: function (ev) { |
19 | 20 … | switch (ev.keyCode) { |
20 | 21 … | case 13: // enter |
21 | 22 … | if (suggestBox && suggestBox.active) { |
modules/tabs.js | ||
---|---|---|
@@ -13,37 +13,52 @@ | ||
13 | 13 … | |
14 | 14 … | var plugs = require('../plugs') |
15 | 15 … | var screen_view = plugs.first(exports._screen_view = []) |
16 | 16 … | var search_box = plugs.first(exports.search_box = []) |
17 … | +var menu = plugs.first(exports.menu = []) | |
17 | 18 … | |
18 | 19 … | exports.message_render = [] |
19 | 20 … | |
20 | 21 … | exports.screen_view = function (path) { |
21 | 22 … | if(path !== 'tabs') |
22 | 23 … | return |
23 | 24 … | |
25 … | + function setSelected (indexes) { | |
26 … | + var ids = indexes.map(function (index) { | |
27 … | + return tabs.get(index).id | |
28 … | + }) | |
29 … | + if(ids.length > 1) | |
30 … | + search.value = 'split('+ids.join(',')+')' | |
31 … | + else | |
32 … | + search.value = ids[0] | |
33 … | + } | |
34 … | + | |
24 | 35 … | var search |
25 | - var tabs = Tabs(function (name) { | |
26 | - search.value = name | |
27 | -// sessionStorage.selectedTab = tabs.selected | |
28 | - }) | |
29 | -// tabs.classList.add('screen') | |
36 … | + var tabs = Tabs(setSelected) | |
30 | 37 … | |
31 | 38 … | search = search_box(function (path, change) { |
39 … | + | |
32 | 40 … | if(tabs.has(path)) { |
33 | 41 … | tabs.select(path) |
34 | 42 … | return true |
35 | 43 … | } |
36 | 44 … | var el = screen_view(path) |
45 … | + | |
37 | 46 … | if(el) { |
47 … | + if(!el.title) el.title = path | |
38 | 48 … | el.scroll = keyscroll(el.querySelector('.scroller__content')) |
39 | - tabs.add(path, el, change) | |
49 … | + tabs.add(el, change) | |
40 | 50 … | // localStorage.openTabs = JSON.stringify(tabs.tabs) |
41 | 51 … | return change |
42 | 52 … | } |
43 | 53 … | }) |
44 | 54 … | |
45 | - tabs.insertBefore(search, tabs.firstChild.nextSibling) | |
55 … | + //reposition hypertabs menu to inside a container... | |
56 … | + tabs.insertBefore(h('div.header.row', | |
57 … | + h('div.header__tabs.row', tabs.firstChild), //tabs | |
58 … | + h('div.header__search.row.end', h('div', search), menu()) | |
59 … | + ), tabs.firstChild) | |
60 … | +// tabs.insertBefore(search, tabs.firstChild.nextSibling) | |
46 | 61 … | |
47 | 62 … | var saved = [] |
48 | 63 … | // try { saved = JSON.parse(localStorage.openTabs) } |
49 | 64 … | // catch (_) { } |
@@ -52,16 +67,17 @@ | ||
52 | 67 … | saved = ['/public', '/private', '/notifications'] |
53 | 68 … | |
54 | 69 … | saved.forEach(function (path) { |
55 | 70 … | var el = screen_view(path) |
71 … | + el.id = el.id || path | |
56 | 72 … | if (!el) return |
57 | 73 … | el.scroll = keyscroll(el.querySelector('.scroller__content')) |
58 | - if(el) tabs.add(path, el, false) | |
74 … | + if(el) tabs.add(el, false, false) | |
59 | 75 … | }) |
60 | 76 … | |
61 | -// tabs.select(sessionStorage.selectedTab || saved[0] || '/public') | |
62 | - tabs.select('/public') | |
77 … | + tabs.select(0) | |
63 | 78 … | |
79 … | + //handle link clicks | |
64 | 80 … | window.onclick = function (ev) { |
65 | 81 … | var link = ancestor(ev.target) |
66 | 82 … | if(!link) return |
67 | 83 … | var path = link.hash.substring(1) |
@@ -72,14 +88,16 @@ | ||
72 | 88 … | //open external links. |
73 | 89 … | //this ought to be made into something more runcible |
74 | 90 … | if(open.isExternal(link.href)) return open(link.href) |
75 | 91 … | |
76 | - if(tabs.has(path)) return tabs.select(path) | |
77 | - | |
92 … | + if(tabs.has(path)) | |
93 … | + return tabs.select(path, !ev.ctrlKey, !!ev.shiftKey) | |
94 … | + | |
78 | 95 … | var el = screen_view(path) |
79 | 96 … | if(el) { |
97 … | + el.id = el.id || path | |
80 | 98 … | el.scroll = keyscroll(el.querySelector('.scroller__content')) |
81 | - tabs.add(path, el, !ev.ctrlKey) | |
99 … | + tabs.add(el, !ev.ctrlKey, !!ev.shiftKey) | |
82 | 100 … | // localStorage.openTabs = JSON.stringify(tabs.tabs) |
83 | 101 … | } |
84 | 102 … | |
85 | 103 … | return false |
@@ -97,19 +115,19 @@ | ||
97 | 115 … | return tabs.selectRelative(1) |
98 | 116 … | |
99 | 117 … | // scroll through messages |
100 | 118 … | case 74: // j |
101 | - return tabs.selectedTab.scroll(1) | |
119 … | + return tabs.get(tabs.selected[0]).scroll(1) | |
102 | 120 … | case 75: // k |
103 | - return tabs.selectedTab.scroll(-1) | |
121 … | + return tabs.get(tabs.selected[0]).scroll(-1) | |
104 | 122 … | |
105 | 123 … | // close a tab |
106 | 124 … | case 88: // x |
107 | - if (tabs.selected/* && tabs.selected[0] !== '/'*/) { | |
125 … | + if (tabs.selected) { | |
108 | 126 … | var sel = tabs.selected |
109 | - tabs.selectRelative(-1) | |
127 … | + var i = sel.reduce(function (a, b) { return Math.min(a, b) }) | |
110 | 128 … | tabs.remove(sel) |
111 | -// localStorage.openTabs = JSON.stringify(tabs.tabs) | |
129 … | + tabs.select(Math.max(i-1, 0)) | |
112 | 130 … | } |
113 | 131 … | return |
114 | 132 … | |
115 | 133 … | // activate the search field |
@@ -154,4 +172,13 @@ | ||
154 | 172 … | }) |
155 | 173 … | |
156 | 174 … | return tabs |
157 | 175 … | } |
176 … | + | |
177 … | + | |
178 … | + | |
179 … | + | |
180 … | + | |
181 … | + | |
182 … | + | |
183 … | + | |
184 … | + |
modules/avatar_fallback.png |
---|
modules/menu.js | ||
---|---|---|
@@ -1,0 +1,31 @@ | ||
1 … | +var plugs = require('../plugs') | |
2 … | +var h = require('hyperscript') | |
3 … | + | |
4 … | +var menu_items = plugs.map(exports.menu_items = []) | |
5 … | + | |
6 … | +var status = h('div.status.error') //start off disconnected | |
7 … | + var list = h('div.column', {style: 'display: none;'}) | |
8 … | + | |
9 … | +var menu = h('div.menu.column', status, list , { | |
10 … | + onmouseover: function (e) { | |
11 … | + list.style.display = 'flex' | |
12 … | + }, onmouseout: function () { | |
13 … | + list.style.display = 'none' | |
14 … | + } | |
15 … | +}) | |
16 … | + | |
17 … | +exports.connection_status = function (err) { | |
18 … | + if(err) status.classList.add('error') | |
19 … | + else status.classList.remove('error') | |
20 … | +} | |
21 … | + | |
22 … | +exports.menu = function () { | |
23 … | + menu_items().forEach(function (el) { | |
24 … | + list.appendChild(el) | |
25 … | + }) | |
26 … | + | |
27 … | + return menu | |
28 … | +} | |
29 … | + | |
30 … | + | |
31 … | + |
package.json | ||
---|---|---|
@@ -1,8 +1,8 @@ | ||
1 | 1 … | { |
2 | 2 … | "name": "patchbay", |
3 | 3 … | "description": "a pluggable patchwork", |
4 | - "version": "2.6.0", | |
4 … | + "version": "3.0.1", | |
5 | 5 … | "homepage": "https://github.com/dominictarr/patchbay", |
6 | 6 … | "repository": { |
7 | 7 … | "type": "git", |
8 | 8 … | "url": "git://github.com/dominictarr/patchbay.git" |
@@ -18,9 +18,9 @@ | ||
18 | 18 … | "hyperfile": "^1.1.0", |
19 | 19 … | "hyperlightbox": "^0.1.3", |
20 | 20 … | "hyperprogress": "0.1.0", |
21 | 21 … | "hyperscript": "^1.4.7", |
22 | - "hypertabs": "^1.2.0", | |
22 … | + "hypertabs": "^2.2.0", | |
23 | 23 … | "is-visible": "^2.0.4", |
24 | 24 … | "map-filter-reduce": "^3.0.1", |
25 | 25 … | "mime-types": "^2.1.11", |
26 | 26 … | "moment": "^2.13.0", |
style.css | ||
---|---|---|
@@ -1,8 +1,12 @@ | ||
1 | 1 … | body { |
2 | 2 … | font-family: sans-serif; |
3 | 3 … | } |
4 | 4 … | |
5 … | +* { | |
6 … | + word-break: break-word; | |
7 … | +} | |
8 … | + | |
5 | 9 … | .screen { |
6 | 10 … | position: absolute; |
7 | 11 … | top: 0px; bottom: 0px; |
8 | 12 … | left: 0px; right: 0px; |
@@ -11,28 +15,41 @@ | ||
11 | 15 … | |
12 | 16 … | .column { |
13 | 17 … | display: flex; |
14 | 18 … | flex-direction: column; |
15 | - min-height: 0px; | |
16 | 19 … | } |
17 | 20 … | |
18 | 21 … | .row { |
19 | 22 … | display: flex; |
20 | 23 … | flex-direction: row; |
21 | 24 … | } |
22 | 25 … | |
26 … | +.end { | |
27 … | + justify-content: flex-end; | |
28 … | +} | |
29 … | + | |
23 | 30 … | .wrap { |
24 | 31 … | display: flex; |
25 | 32 … | flex-direction: row; |
26 | 33 … | flex-wrap: wrap; |
27 | 34 … | } |
28 | 35 … | |
36 … | +.no-shrink { | |
37 … | + flex-shrink: 0; | |
38 … | +} | |
39 … | + | |
40 … | +.expand { | |
41 … | + justify-content: space-between; | |
42 … | +} | |
43 … | + | |
29 | 44 … | .scroll-y { |
30 | 45 … | overflow-y: auto; |
46 … | + min-height: 0px; | |
31 | 47 … | } |
32 | 48 … | |
33 | 49 … | .scroll-x { |
34 | 50 … | overflow-x: auto; |
51 … | + min-width: 0px; | |
35 | 52 … | } |
36 | 53 … | |
37 | 54 … | pre { |
38 | 55 … | white-space: pre-wrap; |
@@ -67,34 +84,8 @@ | ||
67 | 84 … | margin-left: auto; |
68 | 85 … | margin-right: auto; |
69 | 86 … | } |
70 | 87 … | |
71 | -/* --- hypertabs ------- */ | |
72 | - | |
73 | -.hypertabs__tabs { | |
74 | - overflow-y: hide; | |
75 | -} | |
76 | - | |
77 | -.hypertabs > .row { | |
78 | - flex-grow: 0; | |
79 | - flex-shrink: 0; | |
80 | - margin: 0; | |
81 | -} | |
82 | - | |
83 | -.hypertabs__tabs > * { | |
84 | - max-width: 4em; | |
85 | - overflow-x: hidden; | |
86 | - margin-right: .5ex; | |
87 | - padding-top: .1ex; | |
88 | -} | |
89 | - | |
90 | -.hypertabs--selected { | |
91 | - max-width: 4em; | |
92 | - background: yellow; | |
93 | - padding-left: .5ex; | |
94 | - padding-right: .5ex; | |
95 | -} | |
96 | - | |
97 | 88 … | /* compose */ |
98 | 89 … | |
99 | 90 … | .compose { |
100 | 91 … | width: 100%; |
@@ -156,15 +147,11 @@ | ||
156 | 147 … | |
157 | 148 … | /* -- suggest box */ |
158 | 149 … | |
159 | 150 … | .suggest-box > * { |
160 | - margin: .5ex; | |
151 … | + display: block; | |
161 | 152 … | } |
162 | 153 … | |
163 | -.suggest-box { | |
164 | - width: 5em; | |
165 | -} | |
166 | - | |
167 | 154 … | .suggest-box ul { |
168 | 155 … | list-style-type: none; |
169 | 156 … | padding-left: -2em; |
170 | 157 … | } |
@@ -172,8 +159,13 @@ | ||
172 | 159 … | .suggest-box .selected { |
173 | 160 … | background: yellow; |
174 | 161 … | } |
175 | 162 … | |
163 … | +.suggest-box { | |
164 … | + width: max-content; | |
165 … | + background: white; | |
166 … | +} | |
167 … | + | |
176 | 168 … | /* avatar */ |
177 | 169 … | |
178 | 170 … | .avatar { |
179 | 171 … | display: flex; |
@@ -218,37 +210,18 @@ | ||
218 | 210 … | |
219 | 211 … | /* searchprompt */ |
220 | 212 … | |
221 | 213 … | .searchprompt { |
222 | - width: 17em; | |
223 | - margin-left: .5ex; | |
224 | - margin-bottom: .5ex; | |
214 … | + width: 100%; | |
215 … | + height: 2.55em; | |
225 | 216 … | } |
226 | 217 … | |
227 | 218 … | /* TextNodeSearcher highlights */ |
228 | 219 … | |
229 | 220 … | .highlight { |
230 | 221 … | background: yellow; |
231 | 222 … | } |
232 | 223 … | |
233 | -/* --- network status --- */ | |
234 | - | |
235 | -.status { | |
236 | - width: 20px; | |
237 | - height: 20px; | |
238 | - background: green; | |
239 | -} | |
240 | - | |
241 | -.menu { | |
242 | - position: fixed; | |
243 | - right: 10px; | |
244 | - top: 10px; | |
245 | -} | |
246 | - | |
247 | -.error { | |
248 | - background: red; | |
249 | -} | |
250 | - | |
251 | 224 … | /* avatar editor */ |
252 | 225 … | |
253 | 226 … | .hypercrop__canvas { |
254 | 227 … | width: 100%; |
@@ -271,11 +244,9 @@ | ||
271 | 244 … | |
272 | 245 … | .status { |
273 | 246 … | width: .7em; |
274 | 247 … | height: .7em; |
275 | - position: fixed; | |
276 | - right: .8em; | |
277 | - top: .8em; | |
248 … | + margin: .7em; | |
278 | 249 … | border-radius: 100%; |
279 | 250 … | background: green; |
280 | 251 … | } |
281 | 252 … | |
@@ -300,6 +271,69 @@ | ||
300 | 271 … | margin: 1ex; |
301 | 272 … | } |
302 | 273 … | |
303 | 274 … | |
275 … | +/* tabs */ | |
304 | 276 … | |
277 … | +.header { | |
278 … | + background: lightgray; | |
279 … | + border-bottom: 2px inset; | |
280 … | + flex-shrink: 0; | |
281 … | +} | |
305 | 282 … | |
283 … | +.header__tabs { | |
284 … | + width: 100%; | |
285 … | + min-width: 0px; | |
286 … | +} | |
287 … | + | |
288 … | +/* --- hypertabs ------- */ | |
289 … | + | |
290 … | +.hypertabs__tabs { | |
291 … | + min-width: 0px; | |
292 … | + width: 100%; | |
293 … | +} | |
294 … | + | |
295 … | +.hypertabs__tab { | |
296 … | + overflow-x: hidden; | |
297 … | + min-width: 0px; | |
298 … | + width: 100%; | |
299 … | +} | |
300 … | + | |
301 … | +.hypertabs__button { | |
302 … | + overflow-x: hidden; | |
303 … | + min-width: 0px; | |
304 … | + width: 100%; | |
305 … | +} | |
306 … | + | |
307 … | +.hypertabs__tab { | |
308 … | + color: black; | |
309 … | + background: lightgray; | |
310 … | + border-right: 1px solid #ccc; | |
311 … | + border-top-left-radius: 5px; | |
312 … | + margin-left: -3px; | |
313 … | + border-bottom: none; | |
314 … | + padding-top: .35em; | |
315 … | + padding-left: .5em; | |
316 … | + width: 100%; | |
317 … | +} | |
318 … | + | |
319 … | +.hypertabs__tab > a { | |
320 … | + color: black; | |
321 … | + text-decoration: none; | |
322 … | + white-space: nowrap; | |
323 … | +} | |
324 … | + | |
325 … | +.hypertabs--selected { | |
326 … | + background: #E7E7E7; | |
327 … | + border-top-right-radius: 3px; | |
328 … | + z-index: 1; | |
329 … | +} | |
330 … | + | |
331 … | +.hypertabs__x { | |
332 … | + display: none; | |
333 … | + transform: translate(-5px, -3px); | |
334 … | +} | |
335 … | + | |
336 … | +.hypertabs--selected .hypertabs__x { | |
337 … | + display: block; | |
338 … | +} | |
339 … | + |
Built with git-ssb-web