fix(scrolling): use body as scrolling container (#656)
* fix(scrolling): use body as scrolling container Fixes #526 * fixup tests and focus
This commit is contained in:
parent
c1820f62f7
commit
b7f5d04b4c
|
@ -1,6 +1,6 @@
|
||||||
<Nav {page} />
|
<Nav {page} />
|
||||||
|
|
||||||
<div class="container" tabindex="0" ref:container>
|
<div class="main-content">
|
||||||
<main>
|
<main>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</main>
|
</main>
|
||||||
|
@ -13,22 +13,12 @@
|
||||||
import { store } from '../_store/store'
|
import { store } from '../_store/store'
|
||||||
import InformationalFooter from './InformationalFooter.html'
|
import InformationalFooter from './InformationalFooter.html'
|
||||||
|
|
||||||
// Only focus the `.container` div on first load so it does not intefere
|
|
||||||
// with other desired behaviours (e.g. you click a toot, you navigate from
|
|
||||||
// a timeline view to a thread view, you press the back button, and now
|
|
||||||
// you're still focused on the toot).
|
|
||||||
let firstTime = true
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
Nav,
|
Nav,
|
||||||
InformationalFooter
|
InformationalFooter
|
||||||
},
|
},
|
||||||
oncreate () {
|
oncreate () {
|
||||||
if (firstTime) {
|
|
||||||
firstTime = false
|
|
||||||
this.refs.container.focus()
|
|
||||||
}
|
|
||||||
let { page } = this.get()
|
let { page } = this.get()
|
||||||
this.store.set({ currentPage: page })
|
this.store.set({ currentPage: page })
|
||||||
},
|
},
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
z-index: 10;
|
z-index: 20;
|
||||||
contain: content; /* see https://www.w3.org/TR/2018/CR-css-contain-1-20181108/#valdef-contain-content */
|
contain: content; /* see https://www.w3.org/TR/2018/CR-css-contain-1-20181108/#valdef-contain-content */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -159,6 +159,7 @@
|
||||||
import { on, emit } from '../_utils/eventBus'
|
import { on, emit } from '../_utils/eventBus'
|
||||||
import { mark, stop } from '../_utils/marks'
|
import { mark, stop } from '../_utils/marks'
|
||||||
import { doubleRAF } from '../_utils/doubleRAF'
|
import { doubleRAF } from '../_utils/doubleRAF'
|
||||||
|
import { getScrollContainer } from '../_utils/scrollContainer'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
oncreate () {
|
oncreate () {
|
||||||
|
@ -219,7 +220,7 @@
|
||||||
}
|
}
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
smoothScrollToTop(document.getElementsByClassName('container')[0])
|
smoothScrollToTop(getScrollContainer())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,7 +76,7 @@
|
||||||
.compose-box-button-wrapper.compose-button-sticky {
|
.compose-box-button-wrapper.compose-button-sticky {
|
||||||
position: -webkit-sticky;
|
position: -webkit-sticky;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 10px;
|
top: 52px; /* padding-top for .main-content plus 10px */
|
||||||
z-index: 5000;
|
z-index: 5000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +95,12 @@
|
||||||
max-width: calc(100vw - 40px);
|
max-width: calc(100vw - 40px);
|
||||||
}
|
}
|
||||||
.compose-box-button-wrapper.compose-button-sticky {
|
.compose-box-button-wrapper.compose-button-sticky {
|
||||||
top: 5px;
|
top: 57px; /* padding-top for .main-content plus 5px */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (max-width: 991px) {
|
||||||
|
.compose-box-button-wrapper.compose-button-sticky {
|
||||||
|
top: 62px; /* padding-top for .main-content plus 10px */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
<script>
|
<script>
|
||||||
import ListLazyItem from './ListLazyItem.html'
|
import ListLazyItem from './ListLazyItem.html'
|
||||||
import { listStore } from './listStore'
|
import { listStore } from './listStore'
|
||||||
|
import { getScrollContainer } from '../../_utils/scrollContainer'
|
||||||
|
import { getMainTopMargin } from '../../_utils/getMainTopMargin'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
oncreate () {
|
oncreate () {
|
||||||
|
@ -42,7 +44,9 @@
|
||||||
let element = document.getElementById(`list-item-${scrollToItem}`)
|
let element = document.getElementById(`list-item-${scrollToItem}`)
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
console.log('scrolling element into view')
|
console.log('scrolling element into view')
|
||||||
|
// TODO: this is hacky
|
||||||
element.scrollIntoView(true)
|
element.scrollIntoView(true)
|
||||||
|
getScrollContainer().scrollTop -= (getMainTopMargin() + 10) // 10 is the status-article padding top
|
||||||
this.fire('initialized')
|
this.fire('initialized')
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
<svelte:component this={result.listComponent}
|
<svelte:component this={result.listComponent}
|
||||||
component={result.listItemComponent}
|
component={result.listItemComponent}
|
||||||
realm="{$currentInstance + '/' + timeline}"
|
realm="{$currentInstance + '/' + timeline}"
|
||||||
containerQuery=".container"
|
|
||||||
{makeProps}
|
{makeProps}
|
||||||
items={$timelineItemIds}
|
items={$timelineItemIds}
|
||||||
showFooter={true}
|
showFooter={true}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<VirtualListContainer {realm} {containerQuery} on:initialized on:noNeedToScroll >
|
<VirtualListContainer {realm} on:initialized on:noNeedToScroll >
|
||||||
<div class="virtual-list"
|
<div class="virtual-list"
|
||||||
style="height: {$height}px;"
|
style="height: {$height}px;"
|
||||||
ref:node >
|
ref:node >
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
import { mark, stop } from '../../_utils/marks'
|
import { mark, stop } from '../../_utils/marks'
|
||||||
import { doubleRAF } from '../../_utils/doubleRAF'
|
import { doubleRAF } from '../../_utils/doubleRAF'
|
||||||
import { observe } from 'svelte-extras'
|
import { observe } from 'svelte-extras'
|
||||||
|
import { addScrollListener, removeScrollListener, getScrollContainer } from '../../_utils/scrollContainer'
|
||||||
|
|
||||||
const SCROLL_EVENT_DELAY = 300
|
const SCROLL_EVENT_DELAY = 300
|
||||||
|
|
||||||
|
@ -13,23 +14,21 @@
|
||||||
oncreate () {
|
oncreate () {
|
||||||
mark('onCreate VirtualListContainer')
|
mark('onCreate VirtualListContainer')
|
||||||
let {
|
let {
|
||||||
realm,
|
realm
|
||||||
containerQuery
|
|
||||||
} = this.get()
|
} = this.get()
|
||||||
this.store.setCurrentRealm(realm)
|
this.store.setCurrentRealm(realm)
|
||||||
let node = document.querySelector(containerQuery)
|
this.setupScroll()
|
||||||
this.setupScroll(node)
|
|
||||||
this.setupFullscreen()
|
this.setupFullscreen()
|
||||||
let { scrollTop } = this.store.get()
|
let { scrollTop } = this.store.get()
|
||||||
if (scrollTop > 0) {
|
if (scrollTop > 0) {
|
||||||
this.observe('allVisibleItemsHaveHeight', allVisibleItemsHaveHeight => {
|
this.observe('allVisibleItemsHaveHeight', allVisibleItemsHaveHeight => {
|
||||||
console.log('allVisibleItemsHaveHeight', allVisibleItemsHaveHeight)
|
console.log('allVisibleItemsHaveHeight', allVisibleItemsHaveHeight)
|
||||||
let { initializedScrollTop } = this.get()
|
let { initializedScrollTop } = this.get()
|
||||||
if (!initializedScrollTop && allVisibleItemsHaveHeight && node) {
|
if (!initializedScrollTop && allVisibleItemsHaveHeight) {
|
||||||
this.set({ 'initializedScrollTop': true })
|
this.set({ 'initializedScrollTop': true })
|
||||||
mark('set scrollTop')
|
mark('set scrollTop')
|
||||||
console.log('forcing scroll top to ', scrollTop)
|
console.log('forcing scroll top to ', scrollTop)
|
||||||
node.scrollTop = scrollTop
|
getScrollContainer().scrollTop = scrollTop
|
||||||
stop('set scrollTop')
|
stop('set scrollTop')
|
||||||
doubleRAF(() => {
|
doubleRAF(() => {
|
||||||
console.log('initialized VirtualList')
|
console.log('initialized VirtualList')
|
||||||
|
@ -46,8 +45,8 @@
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.store.setForRealm({
|
this.store.setForRealm({
|
||||||
scrollHeight: node.scrollHeight,
|
scrollHeight: getScrollContainer().scrollHeight,
|
||||||
offsetHeight: node.offsetHeight
|
offsetHeight: getScrollContainer().offsetHeight
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
stop('onCreate VirtualListContainer')
|
stop('onCreate VirtualListContainer')
|
||||||
|
@ -60,28 +59,21 @@
|
||||||
store: () => virtualListStore,
|
store: () => virtualListStore,
|
||||||
methods: {
|
methods: {
|
||||||
observe,
|
observe,
|
||||||
setupScroll (node) {
|
setupScroll () {
|
||||||
if (!node) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.scrollListener = throttle(event => {
|
this.scrollListener = throttle(event => {
|
||||||
let { fullscreen } = this.get()
|
let { fullscreen } = this.get()
|
||||||
if (fullscreen) {
|
if (fullscreen) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.onScroll(event)
|
this.onScroll()
|
||||||
}, SCROLL_EVENT_DELAY, {
|
}, SCROLL_EVENT_DELAY, {
|
||||||
leading: true,
|
leading: true,
|
||||||
trailing: true
|
trailing: true
|
||||||
})
|
})
|
||||||
node.addEventListener('scroll', this.scrollListener)
|
addScrollListener(this.scrollListener)
|
||||||
},
|
},
|
||||||
teardownScroll () {
|
teardownScroll () {
|
||||||
let { containerQuery } = this.get()
|
removeScrollListener(this.scrollListener)
|
||||||
let node = document.querySelector(containerQuery)
|
|
||||||
if (node) {
|
|
||||||
node.removeEventListener('scroll', this.scrollListener)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
setupFullscreen () {
|
setupFullscreen () {
|
||||||
this.onFullscreenChange = this.onFullscreenChange.bind(this)
|
this.onFullscreenChange = this.onFullscreenChange.bind(this)
|
||||||
|
@ -90,8 +82,8 @@
|
||||||
teardownFullscreen () {
|
teardownFullscreen () {
|
||||||
detachFullscreenListener(this.onFullscreenChange)
|
detachFullscreenListener(this.onFullscreenChange)
|
||||||
},
|
},
|
||||||
onScroll (event) {
|
onScroll () {
|
||||||
let { scrollTop, scrollHeight } = event.target
|
let { scrollTop, scrollHeight } = getScrollContainer()
|
||||||
|
|
||||||
doubleRAF(() => {
|
doubleRAF(() => {
|
||||||
mark('onScroll -> setForRealm()')
|
mark('onScroll -> setForRealm()')
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
import { mark, stop } from './marks'
|
import { mark, stop } from './marks'
|
||||||
import debounce from 'lodash-es/debounce'
|
import debounce from 'lodash-es/debounce'
|
||||||
import throttle from 'lodash-es/throttle'
|
import throttle from 'lodash-es/throttle'
|
||||||
|
import { getScrollContainer } from './scrollContainer'
|
||||||
|
|
||||||
const map = new Map()
|
const map = new Map()
|
||||||
let createEvent = (name) => new Event(name, { bubbles: true })
|
let createEvent = (name) => new Event(name, { bubbles: true })
|
||||||
|
@ -16,7 +17,7 @@ function assign (ta) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: hack - grab our scroll container so we can maintain the scrollTop
|
// TODO: hack - grab our scroll container so we can maintain the scrollTop
|
||||||
let container = document.getElementsByClassName('container')[0]
|
let container = getScrollContainer()
|
||||||
let heightOffset = null
|
let heightOffset = null
|
||||||
let cachedHeight = null
|
let cachedHeight = null
|
||||||
|
|
||||||
|
|
10
routes/_utils/getMainTopMargin.js
Normal file
10
routes/_utils/getMainTopMargin.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
// should be kept in sync with global.scss
|
||||||
|
export function getMainTopMargin () {
|
||||||
|
if (window.matchMedia('(max-width: 767px)').matches) {
|
||||||
|
return 62
|
||||||
|
} else if (window.matchMedia('(max-width: 991px').matches) {
|
||||||
|
return 52
|
||||||
|
} else {
|
||||||
|
return 42
|
||||||
|
}
|
||||||
|
}
|
11
routes/_utils/scrollContainer.js
Normal file
11
routes/_utils/scrollContainer.js
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
export function getScrollContainer () {
|
||||||
|
return document.scrollingElement
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addScrollListener (listener) {
|
||||||
|
document.addEventListener('scroll', listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function removeScrollListener (listener) {
|
||||||
|
document.removeEventListener('scroll', listener)
|
||||||
|
}
|
|
@ -6,23 +6,20 @@ body {
|
||||||
color: var(--body-text-color);
|
color: var(--body-text-color);
|
||||||
background: var(--body-bg);
|
background: var(--body-bg);
|
||||||
-webkit-tap-highlight-color: transparent; /* fix for blue background on spoiler tap on Chrome for Android */
|
-webkit-tap-highlight-color: transparent; /* fix for blue background on spoiler tap on Chrome for Android */
|
||||||
|
//-webkit-overflow-scrolling: touch;
|
||||||
|
//overflow-y: auto;
|
||||||
|
//overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.main-content {
|
||||||
overflow-y: auto;
|
// these margins should be kept in sync with getMainTopMargin.js
|
||||||
overflow-x: hidden;
|
padding-top: 42px;
|
||||||
-webkit-overflow-scrolling: touch;
|
|
||||||
position: absolute;
|
|
||||||
top: 42px;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
contain: content; /* see https://www.w3.org/TR/2018/CR-css-contain-1-20181108/#valdef-contain-content */
|
contain: content; /* see https://www.w3.org/TR/2018/CR-css-contain-1-20181108/#valdef-contain-content */
|
||||||
@media (max-width: 991px) {
|
@media (max-width: 991px) {
|
||||||
top: 52px;
|
padding-top: 52px;
|
||||||
}
|
}
|
||||||
@media (max-width: 767px) {
|
@media (max-width: 767px) {
|
||||||
top: 62px;
|
padding-top: 62px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
<style>
|
<style>
|
||||||
/* auto-generated w/ build-sass.js */
|
/* auto-generated w/ build-sass.js */
|
||||||
body{--button-primary-bg: #6081e6;--button-primary-text: #fff;--button-primary-border: #132c76;--button-primary-bg-active: #456ce2;--button-primary-bg-hover: #6988e7;--button-bg: #e6e6e6;--button-text: #333;--button-border: #a7a7a7;--button-bg-active: #bfbfbf;--button-bg-hover: #f2f2f2;--input-border: #dadada;--anchor-text: #4169e1;--main-bg: #fff;--body-bg: #e8edfb;--body-text-color: #333;--main-border: #dadada;--svg-fill: #4169e1;--form-bg: #f7f7f7;--form-border: #c1c1c1;--nav-bg: #4169e1;--nav-border: #214cce;--nav-a-border: #4169e1;--nav-a-selected-border: #fff;--nav-a-selected-bg: #6d8ce8;--nav-svg-fill: #fff;--nav-text-color: #fff;--nav-a-selected-border-hover: #fff;--nav-a-selected-bg-hover: #839deb;--nav-a-bg-hover: #577ae4;--nav-a-border-hover: #4169e1;--nav-svg-fill-hover: #fff;--nav-text-color-hover: #fff;--action-button-fill-color: #90a8ee;--action-button-fill-color-hover: #a2b6f0;--action-button-fill-color-active: #577ae4;--action-button-fill-color-pressed: #2351dc;--action-button-fill-color-pressed-hover: #3862e0;--action-button-fill-color-pressed-active: #1d44b8;--action-button-deemphasized-fill-color: #666;--action-button-deemphasized-fill-color-hover: #9e9e9e;--action-button-deemphasized-fill-color-active: #737373;--action-button-deemphasized-fill-color-pressed: #545454;--action-button-deemphasized-fill-color-pressed-hover: #616161;--action-button-deemphasized-fill-color-pressed-active: #404040;--settings-list-item-bg: #fff;--settings-list-item-text: #4169e1;--settings-list-item-text-hover: #4169e1;--settings-list-item-border: #dadada;--settings-list-item-bg-active: #e6e6e6;--settings-list-item-bg-hover: #fafafa;--toast-bg: #333;--toast-border: #fafafa;--toast-text: #fff;--mask-bg: #333;--mask-svg-fill: #fff;--mask-opaque-bg: rgba(51,51,51,0.8);--loading-bg: #ededed;--account-profile-bg-backdrop-filter: rgba(255,255,255,0.7);--account-profile-bg: rgba(255,255,255,0.9);--deemphasized-text-color: #666;--focus-outline: #c5d1f6;--very-deemphasized-link-color: rgba(65,105,225,0.6);--very-deemphasized-text-color: rgba(102,102,102,0.6);--status-direct-background: #d2dcf8;--main-theme-color: #4169e1;--warning-color: #e01f19;--alt-input-bg: rgba(255,255,255,0.7);--muted-modal-bg: transparent;--muted-modal-focus: #999;--muted-modal-hover: rgba(255,255,255,0.2);--compose-autosuggest-item-hover: #ced8f7;--compose-autosuggest-item-active: #b8c7f4;--compose-autosuggest-outline: #dbe3f9;--compose-button-halo: rgba(255,255,255,0.1)}
|
body{--button-primary-bg: #6081e6;--button-primary-text: #fff;--button-primary-border: #132c76;--button-primary-bg-active: #456ce2;--button-primary-bg-hover: #6988e7;--button-bg: #e6e6e6;--button-text: #333;--button-border: #a7a7a7;--button-bg-active: #bfbfbf;--button-bg-hover: #f2f2f2;--input-border: #dadada;--anchor-text: #4169e1;--main-bg: #fff;--body-bg: #e8edfb;--body-text-color: #333;--main-border: #dadada;--svg-fill: #4169e1;--form-bg: #f7f7f7;--form-border: #c1c1c1;--nav-bg: #4169e1;--nav-border: #214cce;--nav-a-border: #4169e1;--nav-a-selected-border: #fff;--nav-a-selected-bg: #6d8ce8;--nav-svg-fill: #fff;--nav-text-color: #fff;--nav-a-selected-border-hover: #fff;--nav-a-selected-bg-hover: #839deb;--nav-a-bg-hover: #577ae4;--nav-a-border-hover: #4169e1;--nav-svg-fill-hover: #fff;--nav-text-color-hover: #fff;--action-button-fill-color: #90a8ee;--action-button-fill-color-hover: #a2b6f0;--action-button-fill-color-active: #577ae4;--action-button-fill-color-pressed: #2351dc;--action-button-fill-color-pressed-hover: #3862e0;--action-button-fill-color-pressed-active: #1d44b8;--action-button-deemphasized-fill-color: #666;--action-button-deemphasized-fill-color-hover: #9e9e9e;--action-button-deemphasized-fill-color-active: #737373;--action-button-deemphasized-fill-color-pressed: #545454;--action-button-deemphasized-fill-color-pressed-hover: #616161;--action-button-deemphasized-fill-color-pressed-active: #404040;--settings-list-item-bg: #fff;--settings-list-item-text: #4169e1;--settings-list-item-text-hover: #4169e1;--settings-list-item-border: #dadada;--settings-list-item-bg-active: #e6e6e6;--settings-list-item-bg-hover: #fafafa;--toast-bg: #333;--toast-border: #fafafa;--toast-text: #fff;--mask-bg: #333;--mask-svg-fill: #fff;--mask-opaque-bg: rgba(51,51,51,0.8);--loading-bg: #ededed;--account-profile-bg-backdrop-filter: rgba(255,255,255,0.7);--account-profile-bg: rgba(255,255,255,0.9);--deemphasized-text-color: #666;--focus-outline: #c5d1f6;--very-deemphasized-link-color: rgba(65,105,225,0.6);--very-deemphasized-text-color: rgba(102,102,102,0.6);--status-direct-background: #d2dcf8;--main-theme-color: #4169e1;--warning-color: #e01f19;--alt-input-bg: rgba(255,255,255,0.7);--muted-modal-bg: transparent;--muted-modal-focus: #999;--muted-modal-hover: rgba(255,255,255,0.2);--compose-autosuggest-item-hover: #ced8f7;--compose-autosuggest-item-active: #b8c7f4;--compose-autosuggest-outline: #dbe3f9;--compose-button-halo: rgba(255,255,255,0.1)}
|
||||||
body{margin:0;font-family:system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;font-size:14px;line-height:1.4;color:var(--body-text-color);background:var(--body-bg);-webkit-tap-highlight-color:transparent}.container{overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch;position:absolute;top:42px;left:0;right:0;bottom:0;contain:content}@media (max-width: 991px){.container{top:52px}}@media (max-width: 767px){.container{top:62px}}main{position:relative;width:602px;max-width:100vw;padding:0;box-sizing:border-box;margin:30px auto 15px;background:var(--main-bg);border:1px solid var(--main-border);border-radius:1px;min-height:70vh}@media (max-width: 767px){main{margin:5px auto 15px}}footer{width:602px;max-width:100vw;box-sizing:border-box;margin:15px auto;border-radius:1px;background:var(--main-bg);font-size:0.9em;padding:20px;border:1px solid var(--main-border)}h1,h2,h3,h4,h5,h6{margin:0 0 0.5em 0;font-weight:400;line-height:1.2}h1{font-size:2em}a{color:var(--anchor-text);text-decoration:none}a:visited{color:var(--anchor-text)}a:hover{text-decoration:underline}input{border:1px solid var(--input-border);padding:5px;box-sizing:border-box}input[type=search]{-webkit-appearance:none}input,textarea{background:inherit;color:inherit}button,.button{font-size:1.2em;background:var(--button-bg);border-radius:2px;padding:10px 15px;border:1px solid var(--button-border);cursor:pointer;color:var(--button-text)}button:hover,.button:hover{background:var(--button-bg-hover);text-decoration:none}button:active,.button:active{background:var(--button-bg-active)}button[disabled],.button[disabled]{opacity:0.35;pointer-events:none;cursor:not-allowed}button.primary,.button.primary{border:1px solid var(--button-primary-border);background:var(--button-primary-bg);color:var(--button-primary-text)}button.primary:hover,.button.primary:hover{background:var(--button-primary-bg-hover)}button.primary:active,.button.primary:active{background:var(--button-primary-bg-active)}p,label,input{font-size:1.3em}ul,li,p{padding:0;margin:0}.hidden{opacity:0}*:focus{outline:2px solid var(--focus-outline)}.container:focus{outline:none}button::-moz-focus-inner{border:0}input:required,input:invalid{box-shadow:none}textarea{font-family:inherit;font-size:inherit;box-sizing:border-box}@keyframes spin{0%{transform:rotate(0deg)}25%{transform:rotate(90deg)}50%{transform:rotate(180deg)}75%{transform:rotate(270deg)}100%{transform:rotate(360deg)}}.spin{animation:spin 1.5s infinite linear}.ellipsis::after{content:"\2026"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.inline-custom-emoji{width:1.4em;height:1.4em;margin:-0.1em 0;object-fit:contain;vertical-align:middle}
|
body{margin:0;font-family:system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;font-size:14px;line-height:1.4;color:var(--body-text-color);background:var(--body-bg);-webkit-tap-highlight-color:transparent}.main-content{padding-top:42px;contain:content}@media (max-width: 991px){.main-content{padding-top:52px}}@media (max-width: 767px){.main-content{padding-top:62px}}main{position:relative;width:602px;max-width:100vw;padding:0;box-sizing:border-box;margin:30px auto 15px;background:var(--main-bg);border:1px solid var(--main-border);border-radius:1px;min-height:70vh}@media (max-width: 767px){main{margin:5px auto 15px}}footer{width:602px;max-width:100vw;box-sizing:border-box;margin:15px auto;border-radius:1px;background:var(--main-bg);font-size:0.9em;padding:20px;border:1px solid var(--main-border)}h1,h2,h3,h4,h5,h6{margin:0 0 0.5em 0;font-weight:400;line-height:1.2}h1{font-size:2em}a{color:var(--anchor-text);text-decoration:none}a:visited{color:var(--anchor-text)}a:hover{text-decoration:underline}input{border:1px solid var(--input-border);padding:5px;box-sizing:border-box}input[type=search]{-webkit-appearance:none}input,textarea{background:inherit;color:inherit}button,.button{font-size:1.2em;background:var(--button-bg);border-radius:2px;padding:10px 15px;border:1px solid var(--button-border);cursor:pointer;color:var(--button-text)}button:hover,.button:hover{background:var(--button-bg-hover);text-decoration:none}button:active,.button:active{background:var(--button-bg-active)}button[disabled],.button[disabled]{opacity:0.35;pointer-events:none;cursor:not-allowed}button.primary,.button.primary{border:1px solid var(--button-primary-border);background:var(--button-primary-bg);color:var(--button-primary-text)}button.primary:hover,.button.primary:hover{background:var(--button-primary-bg-hover)}button.primary:active,.button.primary:active{background:var(--button-primary-bg-active)}p,label,input{font-size:1.3em}ul,li,p{padding:0;margin:0}.hidden{opacity:0}*:focus{outline:2px solid var(--focus-outline)}.container:focus{outline:none}button::-moz-focus-inner{border:0}input:required,input:invalid{box-shadow:none}textarea{font-family:inherit;font-size:inherit;box-sizing:border-box}@keyframes spin{0%{transform:rotate(0deg)}25%{transform:rotate(90deg)}50%{transform:rotate(180deg)}75%{transform:rotate(270deg)}100%{transform:rotate(360deg)}}.spin{animation:spin 1.5s infinite linear}.ellipsis::after{content:"\2026"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.inline-custom-emoji{width:1.4em;height:1.4em;margin:-0.1em 0;object-fit:contain;vertical-align:middle}
|
||||||
body.the-body.offline{--button-primary-bg: #ababab;--button-primary-text: #fff;--button-primary-border: #4d4d4d;--button-primary-bg-active: #9c9c9c;--button-primary-bg-hover: #b0b0b0;--button-bg: #e6e6e6;--button-text: #333;--button-border: #a7a7a7;--button-bg-active: #bfbfbf;--button-bg-hover: #f2f2f2;--input-border: #dadada;--anchor-text: #999;--main-bg: #fff;--body-bg: #fafafa;--body-text-color: #333;--main-border: #dadada;--svg-fill: #999;--form-bg: #f7f7f7;--form-border: #c1c1c1;--nav-bg: #999;--nav-border: gray;--nav-a-border: #999;--nav-a-selected-border: #fff;--nav-a-selected-bg: #b3b3b3;--nav-svg-fill: #fff;--nav-text-color: #fff;--nav-a-selected-border-hover: #fff;--nav-a-selected-bg-hover: #bfbfbf;--nav-a-bg-hover: #a6a6a6;--nav-a-border-hover: #999;--nav-svg-fill-hover: #fff;--nav-text-color-hover: #fff;--action-button-fill-color: #c7c7c7;--action-button-fill-color-hover: #d1d1d1;--action-button-fill-color-active: #a6a6a6;--action-button-fill-color-pressed: #878787;--action-button-fill-color-pressed-hover: #949494;--action-button-fill-color-pressed-active: #737373;--action-button-deemphasized-fill-color: #666;--action-button-deemphasized-fill-color-hover: #9e9e9e;--action-button-deemphasized-fill-color-active: #737373;--action-button-deemphasized-fill-color-pressed: #545454;--action-button-deemphasized-fill-color-pressed-hover: #616161;--action-button-deemphasized-fill-color-pressed-active: #404040;--settings-list-item-bg: #fff;--settings-list-item-text: #999;--settings-list-item-text-hover: #999;--settings-list-item-border: #dadada;--settings-list-item-bg-active: #e6e6e6;--settings-list-item-bg-hover: #fafafa;--toast-bg: #333;--toast-border: #fafafa;--toast-text: #fff;--mask-bg: #333;--mask-svg-fill: #fff;--mask-opaque-bg: rgba(51,51,51,0.8);--loading-bg: #ededed;--account-profile-bg-backdrop-filter: rgba(255,255,255,0.7);--account-profile-bg: rgba(255,255,255,0.9);--deemphasized-text-color: #666;--focus-outline: #bfbfbf;--very-deemphasized-link-color: rgba(153,153,153,0.6);--very-deemphasized-text-color: rgba(102,102,102,0.6);--status-direct-background: #ededed;--main-theme-color: #999;--warning-color: #e01f19;--alt-input-bg: rgba(255,255,255,0.7);--muted-modal-bg: transparent;--muted-modal-focus: #999;--muted-modal-hover: rgba(255,255,255,0.2);--compose-autosuggest-item-hover: #c4c4c4;--compose-autosuggest-item-active: #b8b8b8;--compose-autosuggest-outline: #ccc;--compose-button-halo: rgba(255,255,255,0.1)}
|
body.the-body.offline{--button-primary-bg: #ababab;--button-primary-text: #fff;--button-primary-border: #4d4d4d;--button-primary-bg-active: #9c9c9c;--button-primary-bg-hover: #b0b0b0;--button-bg: #e6e6e6;--button-text: #333;--button-border: #a7a7a7;--button-bg-active: #bfbfbf;--button-bg-hover: #f2f2f2;--input-border: #dadada;--anchor-text: #999;--main-bg: #fff;--body-bg: #fafafa;--body-text-color: #333;--main-border: #dadada;--svg-fill: #999;--form-bg: #f7f7f7;--form-border: #c1c1c1;--nav-bg: #999;--nav-border: gray;--nav-a-border: #999;--nav-a-selected-border: #fff;--nav-a-selected-bg: #b3b3b3;--nav-svg-fill: #fff;--nav-text-color: #fff;--nav-a-selected-border-hover: #fff;--nav-a-selected-bg-hover: #bfbfbf;--nav-a-bg-hover: #a6a6a6;--nav-a-border-hover: #999;--nav-svg-fill-hover: #fff;--nav-text-color-hover: #fff;--action-button-fill-color: #c7c7c7;--action-button-fill-color-hover: #d1d1d1;--action-button-fill-color-active: #a6a6a6;--action-button-fill-color-pressed: #878787;--action-button-fill-color-pressed-hover: #949494;--action-button-fill-color-pressed-active: #737373;--action-button-deemphasized-fill-color: #666;--action-button-deemphasized-fill-color-hover: #9e9e9e;--action-button-deemphasized-fill-color-active: #737373;--action-button-deemphasized-fill-color-pressed: #545454;--action-button-deemphasized-fill-color-pressed-hover: #616161;--action-button-deemphasized-fill-color-pressed-active: #404040;--settings-list-item-bg: #fff;--settings-list-item-text: #999;--settings-list-item-text-hover: #999;--settings-list-item-border: #dadada;--settings-list-item-bg-active: #e6e6e6;--settings-list-item-bg-hover: #fafafa;--toast-bg: #333;--toast-border: #fafafa;--toast-text: #fff;--mask-bg: #333;--mask-svg-fill: #fff;--mask-opaque-bg: rgba(51,51,51,0.8);--loading-bg: #ededed;--account-profile-bg-backdrop-filter: rgba(255,255,255,0.7);--account-profile-bg: rgba(255,255,255,0.9);--deemphasized-text-color: #666;--focus-outline: #bfbfbf;--very-deemphasized-link-color: rgba(153,153,153,0.6);--very-deemphasized-text-color: rgba(102,102,102,0.6);--status-direct-background: #ededed;--main-theme-color: #999;--warning-color: #e01f19;--alt-input-bg: rgba(255,255,255,0.7);--muted-modal-bg: transparent;--muted-modal-focus: #999;--muted-modal-hover: rgba(255,255,255,0.2);--compose-autosuggest-item-hover: #c4c4c4;--compose-autosuggest-item-active: #b8b8b8;--compose-autosuggest-outline: #ccc;--compose-button-halo: rgba(255,255,255,0.1)}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -6,7 +6,7 @@ fixture`001-basic-spec.js`
|
||||||
|
|
||||||
test('has the correct <h1>', async t => {
|
test('has the correct <h1>', async t => {
|
||||||
await t
|
await t
|
||||||
.expect($('.container h1').innerText).eql('Pinafore')
|
.expect($('.main-content h1').innerText).eql('Pinafore')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('navigates to about', async t => {
|
test('navigates to about', async t => {
|
||||||
|
@ -15,7 +15,7 @@ test('navigates to about', async t => {
|
||||||
.expect(getUrl()).contains('/settings')
|
.expect(getUrl()).contains('/settings')
|
||||||
.click('a[href="/settings/about"]')
|
.click('a[href="/settings/about"]')
|
||||||
.expect(getUrl()).contains('/about')
|
.expect(getUrl()).contains('/about')
|
||||||
.expect($('.container h1').innerText).eql('About Pinafore')
|
.expect($('.main-content h1').innerText).eql('About Pinafore')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('navigates to /settings/instances/add', async t => {
|
test('navigates to /settings/instances/add', async t => {
|
||||||
|
@ -28,6 +28,6 @@ test('navigates to settings/instances', async t => {
|
||||||
.expect(getUrl()).contains('/settings')
|
.expect(getUrl()).contains('/settings')
|
||||||
.click($('a').withText('Instances'))
|
.click($('a').withText('Instances'))
|
||||||
.expect(getUrl()).contains('/settings/instances')
|
.expect(getUrl()).contains('/settings/instances')
|
||||||
.expect($('.container').innerText)
|
.expect($('.main-content').innerText)
|
||||||
.contains("You're not logged in to any instances")
|
.contains("You're not logged in to any instances")
|
||||||
})
|
})
|
||||||
|
|
|
@ -55,6 +55,6 @@ test('Logs in and logs out of localhost:3000', async t => {
|
||||||
.expect($('.acct-display-name').innerText).eql('foobar')
|
.expect($('.acct-display-name').innerText).eql('foobar')
|
||||||
.click($('button').withText('Log out'))
|
.click($('button').withText('Log out'))
|
||||||
.click($('.modal-dialog button').withText('OK'))
|
.click($('.modal-dialog button').withText('OK'))
|
||||||
.expect($('.container').innerText)
|
.expect($('.main-content').innerText)
|
||||||
.contains("You're not logged in to any instances")
|
.contains("You're not logged in to any instances")
|
||||||
})
|
})
|
||||||
|
|
|
@ -38,7 +38,7 @@ test('Scrolls to proper point in thread', async t => {
|
||||||
.expect(getUrl()).contains('/statuses/')
|
.expect(getUrl()).contains('/statuses/')
|
||||||
.expect(getNthStatus(16).innerText).contains('unlisted thread 17')
|
.expect(getNthStatus(16).innerText).contains('unlisted thread 17')
|
||||||
.expect(Math.round(getNthStatus(16).boundingClientRect.top))
|
.expect(Math.round(getNthStatus(16).boundingClientRect.top))
|
||||||
.eql(Math.round($('.container').boundingClientRect.top))
|
.eql(Math.round($('.main-content').boundingClientRect.top))
|
||||||
})
|
})
|
||||||
|
|
||||||
async function navigateToBazAccount (t) {
|
async function navigateToBazAccount (t) {
|
||||||
|
|
|
@ -103,6 +103,6 @@ test('reply preserves focus and moves focus to the text input', async t => {
|
||||||
.expect(getActiveElementClass()).contains('compose-box-input')
|
.expect(getActiveElementClass()).contains('compose-box-input')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('focus .container div on index page load', async t => {
|
test('focus .main-content div on index page load', async t => {
|
||||||
await t.expect(getActiveElementClass()).contains('container')
|
await t.expect(getActiveElementClass()).contains('the-body')
|
||||||
})
|
})
|
||||||
|
|
|
@ -96,7 +96,7 @@ export const getBodyClassList = exec(() => (
|
||||||
)
|
)
|
||||||
|
|
||||||
export const scrollContainerToTop = exec(() => {
|
export const scrollContainerToTop = exec(() => {
|
||||||
document.getElementsByClassName('container')[0].scrollTop = 0
|
document.scrollingElement.scrollTop = 0
|
||||||
})
|
})
|
||||||
|
|
||||||
export const uploadKittenImage = i => (exec(() => {
|
export const uploadKittenImage = i => (exec(() => {
|
||||||
|
|
Loading…
Reference in a new issue