Merge branch 'threecolumn' into shigusegubu-vue3
* threecolumn: fix new post button not working day1, minor stylistic fixes layout fixes fix extra padding in thread view chat fixes more fixes fix timeline scroll-to-top fix scrollable columns revert layout back to scrollable body revert timeline changes
This commit is contained in:
commit
cfa876d01a
12 changed files with 86 additions and 142 deletions
14
src/App.js
14
src/App.js
|
@ -50,6 +50,16 @@ export default {
|
||||||
window.removeEventListener('resize', this.updateMobileState)
|
window.removeEventListener('resize', this.updateMobileState)
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
classes () {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
'-reverse': this.reverseLayout,
|
||||||
|
'-no-sticky-headers': this.noSticky,
|
||||||
|
'-has-new-post-button': this.newPostButtonShown
|
||||||
|
},
|
||||||
|
'-' + this.layoutType
|
||||||
|
]
|
||||||
|
},
|
||||||
currentUser () { return this.$store.state.users.currentUser },
|
currentUser () { return this.$store.state.users.currentUser },
|
||||||
userBackground () { return this.currentUser.background_image },
|
userBackground () { return this.currentUser.background_image },
|
||||||
instanceBackground () {
|
instanceBackground () {
|
||||||
|
@ -72,6 +82,10 @@ export default {
|
||||||
!this.$store.getters.mergedConfig.hideISP &&
|
!this.$store.getters.mergedConfig.hideISP &&
|
||||||
this.$store.state.instance.instanceSpecificPanelContent
|
this.$store.state.instance.instanceSpecificPanelContent
|
||||||
},
|
},
|
||||||
|
newPostButtonShown () {
|
||||||
|
if (this.$route.name === 'chat' || this.$route.name === 'chats') return false
|
||||||
|
return this.$store.getters.mergedConfig.alwaysShowNewPostButton || this.layoutType === 'mobile'
|
||||||
|
},
|
||||||
showFeaturesPanel () { return this.$store.state.instance.showFeaturesPanel },
|
showFeaturesPanel () { return this.$store.state.instance.showFeaturesPanel },
|
||||||
shoutboxPosition () {
|
shoutboxPosition () {
|
||||||
return this.$store.getters.mergedConfig.showNewPostButton || false
|
return this.$store.getters.mergedConfig.showNewPostButton || false
|
||||||
|
|
94
src/App.scss
94
src/App.scss
|
@ -1,16 +1,15 @@
|
||||||
// stylelint-disable rscss/class-format
|
// stylelint-disable rscss/class-format
|
||||||
@import './_variables.scss';
|
@import './_variables.scss';
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--navbar-height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
overflow: hidden;
|
|
||||||
max-height: 100vh;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
overflow: hidden;
|
|
||||||
max-height: 100vh;
|
|
||||||
max-width: 100vw;
|
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
font-family: var(--interfaceFont, sans-serif);
|
font-family: var(--interfaceFont, sans-serif);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -19,6 +18,7 @@ body {
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
overscroll-behavior-y: none;
|
||||||
|
|
||||||
&.hidden {
|
&.hidden {
|
||||||
display: none;
|
display: none;
|
||||||
|
@ -26,6 +26,10 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (any-pointer: fine) {
|
@media (any-pointer: fine) {
|
||||||
|
body {
|
||||||
|
background: var(--bg);
|
||||||
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
scrollbar-color: var(--btn) transparent;
|
scrollbar-color: var(--btn) transparent;
|
||||||
|
|
||||||
|
@ -106,33 +110,26 @@ nav {
|
||||||
box-shadow: var(--topBarShadow);
|
box-shadow: var(--topBarShadow);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
height: var(--navbar-height);
|
height: var(--navbar-height);
|
||||||
}
|
position: fixed;
|
||||||
|
|
||||||
#app-loaded {
|
|
||||||
min-height: 100vh;
|
|
||||||
min-width: 100vw;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
--navbar-height: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#content {
|
|
||||||
overscroll-behavior-y: none;
|
|
||||||
overflow-y: scroll;
|
|
||||||
overflow-x: hidden;
|
|
||||||
position: sticky;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#sidebar {
|
#sidebar {
|
||||||
grid-area: sidebar;
|
grid-area: sidebar;
|
||||||
}
|
}
|
||||||
|
|
||||||
#notifs-column {
|
.column.-scrollable {
|
||||||
grid-area: notifs;
|
top: var(--navbar-height);
|
||||||
|
position: sticky;
|
||||||
}
|
}
|
||||||
|
|
||||||
#main-scroller {
|
#main-scroller {
|
||||||
|
margin-top: var(--navbar-height);
|
||||||
grid-area: content;
|
grid-area: content;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
#notifs-column {
|
||||||
|
grid-area: notifs;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-bg-wrapper {
|
.app-bg-wrapper {
|
||||||
|
@ -175,11 +172,11 @@ nav {
|
||||||
grid-template-rows: 1fr;
|
grid-template-rows: 1fr;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
height: calc(100vh - var(--navbar-height));
|
|
||||||
align-content: flex-start;
|
align-content: flex-start;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
padding: 0 10px;
|
padding: 0 calc(var(--columnGap) / 2);
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
|
||||||
.column {
|
.column {
|
||||||
--___columnMargin: var(--columnGap);
|
--___columnMargin: var(--columnGap);
|
||||||
|
@ -187,19 +184,19 @@ nav {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 100%;
|
grid-template-columns: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding-top: 10px;
|
|
||||||
grid-row-start: 1;
|
grid-row-start: 1;
|
||||||
grid-row-end: 1;
|
grid-row-end: 1;
|
||||||
margin: 0 calc(var(--___columnMargin) / 2);
|
margin: 0 calc(var(--___columnMargin) / 2);
|
||||||
|
padding: calc(var(--___columnMargin) / 2) 0;
|
||||||
row-gap: var(--___columnMargin);
|
row-gap: var(--___columnMargin);
|
||||||
align-content: start;
|
align-content: start;
|
||||||
|
|
||||||
&.-scrollable {
|
&.-scrollable {
|
||||||
--___paddingIncrease: calc(var(--columnGap) / 2);
|
--___paddingIncrease: calc(var(--columnGap) / 2);
|
||||||
|
|
||||||
padding-top: 10px;
|
padding-top: calc(var(--columnGap) / 2);
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: var(--navbar-height);
|
||||||
max-height: calc(100vh - var(--navbar-height));
|
max-height: calc(100vh - var(--navbar-height));
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
@ -220,11 +217,17 @@ nav {
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel-heading.-sticky {
|
.panel-heading.-sticky {
|
||||||
top: -10px;
|
top: calc(var(--columnGap) / -2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.-has-new-post-button {
|
||||||
|
.column {
|
||||||
|
padding-bottom: 20em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.-no-sticky-headers {
|
&.-no-sticky-headers {
|
||||||
.column {
|
.column {
|
||||||
.panel-heading.-sticky {
|
.panel-heading.-sticky {
|
||||||
|
@ -271,6 +274,12 @@ nav {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.-normal {
|
||||||
|
#notifs-column {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-center {
|
.text-center {
|
||||||
|
@ -728,35 +737,6 @@ i[class*=icon-],
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media all and (min-width: 800px) {
|
|
||||||
.sidebar-bounds {
|
|
||||||
overflow: hidden;
|
|
||||||
max-height: 100vh;
|
|
||||||
width: 345px;
|
|
||||||
position: fixed;
|
|
||||||
margin-top: -10px;
|
|
||||||
|
|
||||||
.sidebar-scroller {
|
|
||||||
height: 96vh;
|
|
||||||
width: 365px;
|
|
||||||
padding-top: 10px;
|
|
||||||
padding-right: 50px;
|
|
||||||
overflow-x: hidden;
|
|
||||||
overflow-y: scroll;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar {
|
|
||||||
width: 345px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-flexer {
|
|
||||||
max-height: 96vh;
|
|
||||||
flex-shrink: 0;
|
|
||||||
flex-grow: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media all and (max-width: 800px) {
|
@media all and (max-width: 800px) {
|
||||||
.mobile-hidden {
|
.mobile-hidden {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
<div
|
<div
|
||||||
id="content"
|
id="content"
|
||||||
class="app-layout container"
|
class="app-layout container"
|
||||||
:class="[{ '-reverse': reverseLayout, '-no-sticky-headers': noSticky }, '-' + layoutType]"
|
:class="classes"
|
||||||
>
|
>
|
||||||
<div class="underlay"/>
|
<div class="underlay"/>
|
||||||
<div id="sidebar" class="column -scrollable" :class="{ '-show-scrollbar': showScrollbars }">
|
<div id="sidebar" class="column -scrollable" :class="{ '-show-scrollbar': showScrollbars }">
|
||||||
|
|
|
@ -19,8 +19,6 @@ library.add(
|
||||||
faChevronLeft
|
faChevronLeft
|
||||||
)
|
)
|
||||||
|
|
||||||
const scroller = () => document.getElementById('content')
|
|
||||||
|
|
||||||
const BOTTOMED_OUT_OFFSET = 10
|
const BOTTOMED_OUT_OFFSET = 10
|
||||||
const JUMP_TO_BOTTOM_BUTTON_VISIBILITY_OFFSET = 10
|
const JUMP_TO_BOTTOM_BUTTON_VISIBILITY_OFFSET = 10
|
||||||
const SAFE_RESIZE_TIME_OFFSET = 100
|
const SAFE_RESIZE_TIME_OFFSET = 100
|
||||||
|
@ -45,10 +43,9 @@ const Chat = {
|
||||||
},
|
},
|
||||||
created () {
|
created () {
|
||||||
this.startFetching()
|
this.startFetching()
|
||||||
window.addEventListener('resize', this.handleLayoutChange)
|
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
scroller().addEventListener('scroll', this.handleScroll)
|
window.addEventListener('scroll', this.handleScroll)
|
||||||
if (typeof document.hidden !== 'undefined') {
|
if (typeof document.hidden !== 'undefined') {
|
||||||
document.addEventListener('visibilitychange', this.handleVisibilityChange, false)
|
document.addEventListener('visibilitychange', this.handleVisibilityChange, false)
|
||||||
}
|
}
|
||||||
|
@ -56,12 +53,9 @@ const Chat = {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.handleResize()
|
this.handleResize()
|
||||||
})
|
})
|
||||||
this.setChatLayout()
|
|
||||||
},
|
},
|
||||||
unmounted () {
|
unmounted () {
|
||||||
scroller().removeEventListener('scroll', this.handleScroll)
|
window.removeEventListener('scroll', this.handleScroll)
|
||||||
window.removeEventListener('resize', this.handleLayoutChange)
|
|
||||||
this.unsetChatLayout()
|
|
||||||
if (typeof document.hidden !== 'undefined') document.removeEventListener('visibilitychange', this.handleVisibilityChange, false)
|
if (typeof document.hidden !== 'undefined') document.removeEventListener('visibilitychange', this.handleVisibilityChange, false)
|
||||||
this.$store.dispatch('clearCurrentChat')
|
this.$store.dispatch('clearCurrentChat')
|
||||||
},
|
},
|
||||||
|
@ -97,8 +91,7 @@ const Chat = {
|
||||||
...mapState({
|
...mapState({
|
||||||
backendInteractor: state => state.api.backendInteractor,
|
backendInteractor: state => state.api.backendInteractor,
|
||||||
mastoUserSocketStatus: state => state.api.mastoUserSocketStatus,
|
mastoUserSocketStatus: state => state.api.mastoUserSocketStatus,
|
||||||
mobileLayout: state => state.interface.mobileLayout,
|
mobileLayout: state => state.interface.layoutType === 'mobile',
|
||||||
layoutHeight: state => state.interface.layoutHeight,
|
|
||||||
currentUser: state => state.users.currentUser
|
currentUser: state => state.users.currentUser
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
@ -116,9 +109,6 @@ const Chat = {
|
||||||
'$route': function () {
|
'$route': function () {
|
||||||
this.startFetching()
|
this.startFetching()
|
||||||
},
|
},
|
||||||
layoutHeight () {
|
|
||||||
this.handleResize({ expand: true })
|
|
||||||
},
|
|
||||||
mastoUserSocketStatus (newValue) {
|
mastoUserSocketStatus (newValue) {
|
||||||
if (newValue === WSConnectionStatus.JOINED) {
|
if (newValue === WSConnectionStatus.JOINED) {
|
||||||
this.fetchChat({ isFirstFetch: true })
|
this.fetchChat({ isFirstFetch: true })
|
||||||
|
@ -142,30 +132,6 @@ const Chat = {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
setChatLayout () {
|
|
||||||
// This is a hacky way to adjust the global layout to the mobile chat (without modifying the rest of the app).
|
|
||||||
// This layout prevents empty spaces from being visible at the bottom
|
|
||||||
// of the chat on iOS Safari (`safe-area-inset`) when
|
|
||||||
// - the on-screen keyboard appears and the user starts typing
|
|
||||||
// - the user selects the text inside the input area
|
|
||||||
// - the user selects and deletes the text that is multiple lines long
|
|
||||||
// TODO: unify the chat layout with the global layout.
|
|
||||||
let html = document.querySelector('html')
|
|
||||||
if (html) {
|
|
||||||
html.classList.add('chat-layout')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
unsetChatLayout () {
|
|
||||||
let html = document.querySelector('html')
|
|
||||||
if (html) {
|
|
||||||
html.classList.remove('chat-layout')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleLayoutChange () {
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.scrollDown()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// Preserves the scroll position when OSK appears or the posting form changes its height.
|
// Preserves the scroll position when OSK appears or the posting form changes its height.
|
||||||
handleResize (opts = {}) {
|
handleResize (opts = {}) {
|
||||||
const { expand = false, delayed = false } = opts
|
const { expand = false, delayed = false } = opts
|
||||||
|
@ -179,25 +145,20 @@ const Chat = {
|
||||||
|
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
const { offsetHeight = undefined } = this.lastScrollPosition
|
const { offsetHeight = undefined } = this.lastScrollPosition
|
||||||
this.lastScrollPosition = getScrollPosition(scroller())
|
this.lastScrollPosition = getScrollPosition()
|
||||||
|
|
||||||
const diff = this.lastScrollPosition.offsetHeight - offsetHeight
|
const diff = this.lastScrollPosition.offsetHeight - offsetHeight
|
||||||
if (diff < 0 || (!this.bottomedOut() && expand)) {
|
if (diff < 0 || (!this.bottomedOut() && expand)) {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
scroller().scrollTo({
|
window.scrollTo({ top: window.scrollY - diff })
|
||||||
top: scroller().scrollTop - diff,
|
|
||||||
left: 0
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
scrollDown (options = {}) {
|
scrollDown (options = {}) {
|
||||||
const { behavior = 'auto', forceRead = false } = options
|
const { behavior = 'auto', forceRead = false } = options
|
||||||
const scrollable = scroller()
|
|
||||||
if (!scrollable) { return }
|
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
scrollable.scrollTo({ top: scrollable.scrollHeight, left: 0, behavior })
|
window.scrollTo({ top: document.documentElement.scrollHeight, behavior })
|
||||||
})
|
})
|
||||||
if (forceRead) {
|
if (forceRead) {
|
||||||
this.readChat()
|
this.readChat()
|
||||||
|
@ -213,11 +174,10 @@ const Chat = {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
bottomedOut (offset) {
|
bottomedOut (offset) {
|
||||||
return isBottomedOut(scroller(), offset)
|
return isBottomedOut(offset)
|
||||||
},
|
},
|
||||||
reachedTop () {
|
reachedTop () {
|
||||||
const scrollable = scroller()
|
return window.scrollY <= 0
|
||||||
return scrollable && scrollable.scrollTop <= 0
|
|
||||||
},
|
},
|
||||||
cullOlderCheck () {
|
cullOlderCheck () {
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
|
@ -248,10 +208,9 @@ const Chat = {
|
||||||
}
|
}
|
||||||
}, 200),
|
}, 200),
|
||||||
handleScrollUp (positionBeforeLoading) {
|
handleScrollUp (positionBeforeLoading) {
|
||||||
const positionAfterLoading = getScrollPosition(scroller())
|
const positionAfterLoading = getScrollPosition()
|
||||||
scroller().scrollTo({
|
window.scrollTo({
|
||||||
top: getNewTopPosition(positionBeforeLoading, positionAfterLoading),
|
top: getNewTopPosition(positionBeforeLoading, positionAfterLoading)
|
||||||
left: 0
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
fetchChat ({ isFirstFetch = false, fetchLatest = false, maxId }) {
|
fetchChat ({ isFirstFetch = false, fetchLatest = false, maxId }) {
|
||||||
|
@ -270,7 +229,7 @@ const Chat = {
|
||||||
chatService.clear(chatMessageService)
|
chatService.clear(chatMessageService)
|
||||||
}
|
}
|
||||||
|
|
||||||
const positionBeforeUpdate = getScrollPosition(scroller())
|
const positionBeforeUpdate = getScrollPosition()
|
||||||
this.$store.dispatch('addChatMessages', { chatId, messages }).then(() => {
|
this.$store.dispatch('addChatMessages', { chatId, messages }).then(() => {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
if (fetchOlderMessages) {
|
if (fetchOlderMessages) {
|
||||||
|
@ -281,7 +240,7 @@ const Chat = {
|
||||||
// full height of the scrollable container.
|
// full height of the scrollable container.
|
||||||
// If this is the case, we want to fetch the messages until the scrollable container
|
// If this is the case, we want to fetch the messages until the scrollable container
|
||||||
// is fully populated so that the user has the ability to scroll up and load the history.
|
// is fully populated so that the user has the ability to scroll up and load the history.
|
||||||
if (!isScrollable(scroller()) && messages.length > 0) {
|
if (!isScrollable() && messages.length > 0) {
|
||||||
this.fetchChat({ maxId: this.currentChatMessageService.minId })
|
this.fetchChat({ maxId: this.currentChatMessageService.minId })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
.chat-view {
|
.chat-view {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
// Stick the form to the top/bottom of screen
|
||||||
|
margin-bottom: calc(var(--___columnMargin) / -2);
|
||||||
|
margin-top: calc(var(--___columnMargin) / -2);
|
||||||
|
|
||||||
.chat-view-inner {
|
.chat-view-inner {
|
||||||
height: auto;
|
height: auto;
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
<div class="chat-view">
|
<div class="chat-view">
|
||||||
<div class="chat-view-inner">
|
<div class="chat-view-inner">
|
||||||
<div
|
<div
|
||||||
id="nav"
|
|
||||||
ref="inner"
|
ref="inner"
|
||||||
class="panel-default panel chat-view-body"
|
class="panel-default panel chat-view-body"
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
// Captures a scroll position
|
// Captures a scroll position
|
||||||
export const getScrollPosition = (el) => {
|
export const getScrollPosition = () => {
|
||||||
return {
|
return {
|
||||||
scrollTop: el.scrollTop,
|
scrollTop: window.scrollY,
|
||||||
scrollHeight: el.scrollHeight,
|
scrollHeight: document.documentElement.scrollHeight,
|
||||||
offsetHeight: el.offsetHeight
|
offsetHeight: window.innerHeight
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,21 +13,12 @@ export const getNewTopPosition = (previousPosition, newPosition) => {
|
||||||
return previousPosition.scrollTop + (newPosition.scrollHeight - previousPosition.scrollHeight)
|
return previousPosition.scrollTop + (newPosition.scrollHeight - previousPosition.scrollHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isBottomedOut = (el, offset = 0) => {
|
export const isBottomedOut = (offset = 0) => {
|
||||||
if (!el) { return }
|
const scrollHeight = window.scrollY + offset
|
||||||
const scrollHeight = el.scrollTop + offset
|
const totalHeight = document.documentElement.scrollHeight - window.innerHeight
|
||||||
const totalHeight = el.scrollHeight - el.offsetHeight
|
|
||||||
return totalHeight <= scrollHeight
|
return totalHeight <= scrollHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
// Height of the scrollable container. The dynamic height is needed to ensure the mobile browser panel doesn't overlap or hide the posting form.
|
|
||||||
export const scrollableContainerHeight = (inner, header, footer) => {
|
|
||||||
return inner.offsetHeight - header.clientHeight - footer.clientHeight
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns whether or not the scrollbar is visible.
|
// Returns whether or not the scrollbar is visible.
|
||||||
export const isScrollable = (el) => {
|
export const isScrollable = () => {
|
||||||
if (!el) return
|
return document.documentElement.scrollHeight > window.innerHeight
|
||||||
|
|
||||||
return el.scrollHeight > el.clientHeight
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
id="nav"
|
|
||||||
class="panel-default panel chat-new"
|
class="panel-default panel chat-new"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -270,7 +270,8 @@
|
||||||
border-radius: 0 0 var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius);
|
border-radius: 0 0 var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius);
|
||||||
border-bottom: 1px solid var(--border, $fallback--border);
|
border-bottom: 1px solid var(--border, $fallback--border);
|
||||||
}
|
}
|
||||||
&.-expanded {
|
|
||||||
|
&.-expanded.status-fadein {
|
||||||
margin: calc(var(--status-margin, $status-margin) / 2);
|
margin: calc(var(--status-margin, $status-margin) / 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ const MobilePostStatusButton = {
|
||||||
return this.autohideFloatingPostButton && (this.hidden || this.inputActive)
|
return this.autohideFloatingPostButton && (this.hidden || this.inputActive)
|
||||||
},
|
},
|
||||||
isPersistent () {
|
isPersistent () {
|
||||||
return !!this.$store.getters.mergedConfig.showNewPostButton
|
return !!this.$store.getters.mergedConfig.alwaysShowNewPostButton
|
||||||
},
|
},
|
||||||
autohideFloatingPostButton () {
|
autohideFloatingPostButton () {
|
||||||
return !!this.$store.getters.mergedConfig.autohideFloatingPostButton
|
return !!this.$store.getters.mergedConfig.autohideFloatingPostButton
|
||||||
|
|
|
@ -12,8 +12,6 @@ library.add(
|
||||||
faCog
|
faCog
|
||||||
)
|
)
|
||||||
|
|
||||||
const scroller = () => document.getElementById('content')
|
|
||||||
|
|
||||||
const Timeline = {
|
const Timeline = {
|
||||||
props: [
|
props: [
|
||||||
'timeline',
|
'timeline',
|
||||||
|
@ -91,7 +89,7 @@ const Timeline = {
|
||||||
const credentials = store.state.users.currentUser.credentials
|
const credentials = store.state.users.currentUser.credentials
|
||||||
const showImmediately = this.timeline.visibleStatuses.length === 0
|
const showImmediately = this.timeline.visibleStatuses.length === 0
|
||||||
|
|
||||||
scroller() && scroller().addEventListener('scroll', this.handleScroll)
|
window.addEventListener('scroll', this.handleScroll)
|
||||||
|
|
||||||
if (store.state.api.fetchers[this.timelineName]) { return false }
|
if (store.state.api.fetchers[this.timelineName]) { return false }
|
||||||
|
|
||||||
|
@ -113,7 +111,7 @@ const Timeline = {
|
||||||
setTimeout(this.determineVisibleStatuses, 250)
|
setTimeout(this.determineVisibleStatuses, 250)
|
||||||
},
|
},
|
||||||
unmounted () {
|
unmounted () {
|
||||||
scroller().removeEventListener('scroll', this.handleScroll)
|
window.removeEventListener('scroll', this.handleScroll)
|
||||||
window.removeEventListener('keydown', this.handleShortKey)
|
window.removeEventListener('keydown', this.handleShortKey)
|
||||||
if (typeof document.hidden !== 'undefined') document.removeEventListener('visibilitychange', this.handleVisibilityChange, false)
|
if (typeof document.hidden !== 'undefined') document.removeEventListener('visibilitychange', this.handleVisibilityChange, false)
|
||||||
this.$store.commit('setLoading', { timeline: this.timelineName, value: false })
|
this.$store.commit('setLoading', { timeline: this.timelineName, value: false })
|
||||||
|
@ -143,7 +141,7 @@ const Timeline = {
|
||||||
this.$store.commit('showNewStatuses', { timeline: this.timelineName })
|
this.$store.commit('showNewStatuses', { timeline: this.timelineName })
|
||||||
this.paused = false
|
this.paused = false
|
||||||
}
|
}
|
||||||
scroller().scrollTop = 0
|
window.scrollTo({ top: 0 })
|
||||||
},
|
},
|
||||||
fetchOlderStatuses: throttle(function () {
|
fetchOlderStatuses: throttle(function () {
|
||||||
const store = this.$store
|
const store = this.$store
|
||||||
|
@ -231,8 +229,8 @@ const Timeline = {
|
||||||
}
|
}
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
// only 'stream' them when you're scrolled to the top
|
// only 'stream' them when you're scrolled to the top
|
||||||
const doc = document.getElementById('content')
|
const doc = document.documentElement
|
||||||
const top = (doc.scrollTop) - (doc.clientTop || 0)
|
const top = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0)
|
||||||
if (top < 15 &&
|
if (top < 15 &&
|
||||||
!this.paused &&
|
!this.paused &&
|
||||||
!(this.unfocused && this.$store.getters.mergedConfig.pauseOnUnfocused)
|
!(this.unfocused && this.$store.getters.mergedConfig.pauseOnUnfocused)
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
|
|
||||||
&.-sticky {
|
&.-sticky {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: var(--navbar-height);
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue