mirror of
https://github.com/styppo/hamstr.git
synced 2024-10-18 13:33:22 +00:00
* Fix some mobile layout issues
* More hacks to fix scrolling a bit
This commit is contained in:
parent
342764c458
commit
bef9fad696
@ -44,11 +44,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div style="position: sticky; bottom: 0">
|
||||||
<ProfilePopup v-if="$store.getters.isSignedIn" />
|
<ProfilePopup v-if="$store.getters.isSignedIn" />
|
||||||
<div v-else class="sign-in" @click="signIn">
|
<div v-else class="sign-in" @click="signIn">
|
||||||
<q-icon class="icon" name="login" size="sm" />
|
<q-icon class="icon" name="login" size="sm" />
|
||||||
<div class="label">Log in</div>
|
<div class="label">Log in</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="mobile-close-menu-button"
|
class="mobile-close-menu-button"
|
||||||
@ -116,11 +118,11 @@ menu {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
padding-inline-start: 0;
|
padding-inline-start: 0;
|
||||||
.menu {
|
.menu {
|
||||||
|
height: 100%;
|
||||||
&-nav {
|
&-nav {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 0 1rem;
|
padding: 0 1rem;
|
||||||
}
|
}
|
||||||
height: 100%;
|
|
||||||
&-logo {
|
&-logo {
|
||||||
margin: 1rem 0;
|
margin: 1rem 0;
|
||||||
svg, img {
|
svg, img {
|
||||||
|
@ -14,9 +14,9 @@
|
|||||||
<div class="addon">
|
<div class="addon">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
<div class="logo">
|
<router-link class="logo" to="/">
|
||||||
<Logo />
|
<Logo />
|
||||||
</div>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -107,6 +107,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
@media screen and (max-width: $phone) {
|
@media screen and (max-width: $phone) {
|
||||||
.page-header {
|
.page-header {
|
||||||
|
padding: .4rem 1rem;
|
||||||
.logo {
|
.logo {
|
||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -127,8 +127,8 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
formatPostDate(ts) {
|
formatPostDate(timestamp) {
|
||||||
const date = new Date(ts)
|
const date = new Date(timestamp)
|
||||||
const month = this.$t(MONTHS[date.getMonth()])
|
const month = this.$t(MONTHS[date.getMonth()])
|
||||||
|
|
||||||
const sameYear = date.getFullYear() === (new Date().getFullYear())
|
const sameYear = date.getFullYear() === (new Date().getFullYear())
|
||||||
@ -136,8 +136,8 @@ export default {
|
|||||||
|
|
||||||
return `${date.getDate()} ${month}${year}`
|
return `${date.getDate()} ${month}${year}`
|
||||||
},
|
},
|
||||||
formatPostTime(ts) {
|
formatPostTime(timestamp) {
|
||||||
const date = new Date(ts)
|
const date = new Date(timestamp)
|
||||||
return `${date.getHours()}:${date.getMinutes()}`
|
return `${date.getHours()}:${date.getMinutes()}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,16 +18,14 @@
|
|||||||
<p>
|
<p>
|
||||||
<BaseUserName :pubkey="post.author" @click.stop />
|
<BaseUserName :pubkey="post.author" @click.stop />
|
||||||
<span>·</span>
|
<span>·</span>
|
||||||
<span class="created-at">{{ moment(post.createdAt).fromNow() }}</span>
|
<span class="created-at">{{ formatPostDate(post.createdAt) }}</span>
|
||||||
</p>
|
</p>
|
||||||
<p v-if="ancestor" class="in-reply-to">
|
<p v-if="ancestor" class="in-reply-to">
|
||||||
Replying to <a @click.stop="toEvent(ancestor)">{{ shorten(ancestor) }}</a>
|
Replying to <a @click.stop="toEvent(ancestor)">{{ shorten(ancestor) }}</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="post-content-body">
|
<div class="post-content-body">
|
||||||
<p>
|
|
||||||
<BaseMarkdown :content="post.content" />
|
<BaseMarkdown :content="post.content" />
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-if="actions" class="post-content-actions">
|
<div v-if="actions" class="post-content-actions">
|
||||||
<div class="action-item comment" @click.stop="$store.dispatch('createPost', {replyTo})">
|
<div class="action-item comment" @click.stop="$store.dispatch('createPost', {replyTo})">
|
||||||
@ -135,7 +133,23 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
moment,
|
formatPostDate(timestamp) {
|
||||||
|
return this.$q.screen.lt.md
|
||||||
|
? this.shortDateFromNow(timestamp)
|
||||||
|
: moment(timestamp).fromNow()
|
||||||
|
},
|
||||||
|
shortDateFromNow(timestamp) {
|
||||||
|
const now = Date.now()
|
||||||
|
const diff = Math.round(Math.max(now - timestamp, 0) / 1000)
|
||||||
|
const formatDiff = (div, offset) => Math.max(Math.floor((diff + offset) / div), 1)
|
||||||
|
|
||||||
|
if (diff < 45) return `${formatDiff(1, 0)}s`
|
||||||
|
if (diff < 60 * 45) return `${formatDiff(60, 15)}m`
|
||||||
|
if (diff < 60 * 60 * 22) return `${formatDiff(60 * 60, 60 * 15)}h`
|
||||||
|
if (diff < 60 * 60 * 24 * 26) return `${formatDiff(60 * 60 * 24, 60 * 60 * 2)}d`
|
||||||
|
if (diff < 60 * 60 * 24 * 30 * 320) return `${formatDiff(60 * 60 * 24 * 30, 60 * 60 * 24 * 4)}mo`
|
||||||
|
return `${formatDiff(60 * 60 * 24 * 30 * 365, 60 * 60 * 24 * 45)}y`
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -175,10 +189,13 @@ export default {
|
|||||||
}
|
}
|
||||||
&-content {
|
&-content {
|
||||||
margin-left: 12px;
|
margin-left: 12px;
|
||||||
padding: 1rem 0;
|
padding: 1rem 0 .4rem;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
max-width: 570px;
|
max-width: 570px;
|
||||||
&-header {
|
&-header {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
.in-reply-to {
|
.in-reply-to {
|
||||||
color: $color-dark-gray;
|
color: $color-dark-gray;
|
||||||
a {
|
a {
|
||||||
@ -212,25 +229,7 @@ export default {
|
|||||||
}
|
}
|
||||||
&-body {
|
&-body {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
&-images {
|
margin-bottom: 1rem;
|
||||||
&-wrapper {
|
|
||||||
border-radius: 10px;
|
|
||||||
overflow: hidden;
|
|
||||||
border: $border-light;
|
|
||||||
display: flex;
|
|
||||||
.post-content-image-item {
|
|
||||||
cursor: zoom-in;
|
|
||||||
& + .post-content-image-item {
|
|
||||||
border-left: $border-light;
|
|
||||||
}
|
|
||||||
flex-grow: 1;
|
|
||||||
img {
|
|
||||||
vertical-align: middle;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
&-actions {
|
&-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -287,18 +286,11 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: $phone) {
|
@media screen and (max-width: $phone) {
|
||||||
.post{
|
.post {
|
||||||
&-content {
|
&-content {
|
||||||
&-header {
|
&-header {
|
||||||
span{
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.created-at {
|
|
||||||
display: block;
|
|
||||||
color: rgba($color: $color-dark-gray, $alpha: 0.5);
|
|
||||||
margin: 5px 0;
|
|
||||||
}
|
|
||||||
.nip05 {
|
.nip05 {
|
||||||
display: unset;
|
display: unset;
|
||||||
color: $color-dark-gray;
|
color: $color-dark-gray;
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
<div class="layout-flow">
|
<div class="layout-flow">
|
||||||
<q-page-container ref="pageContainer">
|
<q-page-container ref="pageContainer">
|
||||||
<router-view v-slot="{ Component }">
|
<router-view v-slot="{ Component }">
|
||||||
<keep-alive :include="['Feed', 'Messages', 'Notifications']">
|
<keep-alive :include="cachedPages">
|
||||||
<component :is="Component" :key="$route.path" @scroll-to-rect="scrollToRect" />
|
<component :is="Component" :key="$route.path" @scroll-to-rect="scrollToRect" />
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
</router-view>
|
</router-view>
|
||||||
@ -31,6 +31,7 @@
|
|||||||
>
|
>
|
||||||
<BaseIcon icon="hamburger" />
|
<BaseIcon icon="hamburger" />
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="mobileMenuOpen" class="mobile-menu-backdrop fixed-full" v-close-popup></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SignInDialog />
|
<SignInDialog />
|
||||||
@ -66,14 +67,19 @@ export default defineComponent({
|
|||||||
|
|
||||||
setup () {
|
setup () {
|
||||||
const $q = useQuasar()
|
const $q = useQuasar()
|
||||||
// const cachedPages = ref(['feed', 'notifications', 'messages'])
|
$q.screen.setSizes({
|
||||||
|
// FIXME Needs to be in sync with assets/variables.scss
|
||||||
|
sm: 414,
|
||||||
|
md: 755,
|
||||||
|
lg: 1113,
|
||||||
|
xl: 1310,
|
||||||
|
})
|
||||||
return $q
|
return $q
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
cachedPages: ['Feed', 'Notifications', 'Messages'],
|
cachedPages: ['Feed', 'Notifications', 'Messages', 'Inbox', 'Settings', 'DevTools'],
|
||||||
middlePagePos: {},
|
middlePagePos: {},
|
||||||
broadcastChannel: new BroadcastChannel('hamstr'),
|
broadcastChannel: new BroadcastChannel('hamstr'),
|
||||||
activeWindow: false,
|
activeWindow: false,
|
||||||
@ -118,8 +124,8 @@ export default defineComponent({
|
|||||||
|
|
||||||
// setup scrolling
|
// setup scrolling
|
||||||
// document.querySelector('#left-drawer').addEventListener('wheel', this.redirectScroll)
|
// document.querySelector('#left-drawer').addEventListener('wheel', this.redirectScroll)
|
||||||
this.$router.beforeEach((to, from) => { this.preserveScrollPos(to, from) })
|
// this.$router.beforeEach((to, from) => { this.preserveScrollPos(to, from) })
|
||||||
this.$router.afterEach((to, from) => { this.restoreScrollPos(to, from) })
|
// this.$router.afterEach((to, from) => { this.restoreScrollPos(to, from) })
|
||||||
|
|
||||||
// destroy streams before unloading window
|
// destroy streams before unloading window
|
||||||
window.onbeforeunload = async () => {
|
window.onbeforeunload = async () => {
|
||||||
@ -147,7 +153,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
scrollToRect(rect) {
|
scrollToRect(rect) {
|
||||||
let offset = Math.max(rect.top, 0) - 78
|
let offset = Math.max(rect.top, 0)
|
||||||
setVerticalScrollPosition(this.scrollingContainer, offset, 0)
|
setVerticalScrollPosition(this.scrollingContainer, offset, 0)
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -355,6 +361,12 @@ export default defineComponent({
|
|||||||
fill: #fff;
|
fill: #fff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.mobile-menu-backdrop {
|
||||||
|
z-index: 750;
|
||||||
|
pointer-events: all;
|
||||||
|
outline: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-page>
|
<q-page>
|
||||||
|
<div class="page-header-container">
|
||||||
<PageHeader>
|
<PageHeader>
|
||||||
<div class="addon-menu">
|
<div class="addon-menu">
|
||||||
<div class="addon-menu-icon">
|
<div class="addon-menu-icon">
|
||||||
@ -17,8 +18,11 @@
|
|||||||
</q-menu>
|
</q-menu>
|
||||||
</div>
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
</div>
|
||||||
|
|
||||||
<PostEditor class="post-editor" v-if="$store.getters.isSignedIn" />
|
<div class="post-editor" v-if="$store.getters.isSignedIn">
|
||||||
|
<PostEditor />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="feed-tabs">
|
<div class="feed-tabs">
|
||||||
<q-tabs
|
<q-tabs
|
||||||
@ -42,7 +46,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="feed">
|
<div class="feed">
|
||||||
<div class="load-more-container">
|
<div class="load-more-container" :class="{'more-available': unreadFeed[tab].length}">
|
||||||
<BaseButtonLoadMore
|
<BaseButtonLoadMore
|
||||||
v-if="unreadFeed[tab].length"
|
v-if="unreadFeed[tab].length"
|
||||||
:loading="loadingUnread"
|
:loading="loadingUnread"
|
||||||
@ -342,9 +346,21 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: $phone) {
|
@media screen and (max-width: $phone) {
|
||||||
|
.page-header-container {
|
||||||
|
border-bottom: $border-dark;
|
||||||
|
}
|
||||||
.post-editor {
|
.post-editor {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
.feed {
|
||||||
|
.load-more-container {
|
||||||
|
border: 0;
|
||||||
|
min-height: 0;
|
||||||
|
&.more-available {
|
||||||
|
border-bottom: $border-dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -23,8 +23,8 @@
|
|||||||
:connector="ancestorsCompiled.length > 0"
|
:connector="ancestorsCompiled.length > 0"
|
||||||
@add-event="processChildEvent"
|
@add-event="processChildEvent"
|
||||||
/>
|
/>
|
||||||
<div v-else>
|
<div v-else style="padding-left: 1.5rem">
|
||||||
{{ $t('event') }} {{ $route.params.eventId }}
|
<q-spinner size="sm" style="margin-right: .5rem"/> Loading...
|
||||||
</div>
|
</div>
|
||||||
</q-item>
|
</q-item>
|
||||||
|
|
||||||
@ -106,6 +106,8 @@ export default defineComponent({
|
|||||||
this.scrollToMainEvent()
|
this.scrollToMainEvent()
|
||||||
})
|
})
|
||||||
this.resizeObserver.observe(this.$refs.page.$el)
|
this.resizeObserver.observe(this.$refs.page.$el)
|
||||||
|
|
||||||
|
setTimeout(() => this.resizeObserver.disconnect(), 2000)
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeUnmount() {
|
beforeUnmount() {
|
||||||
@ -200,12 +202,14 @@ export default defineComponent({
|
|||||||
const el = this.$refs.main?.$el
|
const el = this.$refs.main?.$el
|
||||||
if (!el) return
|
if (!el) return
|
||||||
|
|
||||||
const offset = Math.max(el.offsetTop - 78, 0)
|
// TODO Clean up
|
||||||
|
const offset = this.$q.screen.xs ? 61 : 78
|
||||||
|
const position = Math.max(el.offsetTop - offset, 0)
|
||||||
|
|
||||||
if (this.scrollTimeout) {
|
if (this.scrollTimeout) {
|
||||||
clearTimeout(this.scrollTimeout)
|
clearTimeout(this.scrollTimeout)
|
||||||
}
|
}
|
||||||
this.scrollTimeout = setTimeout(() => window.scrollTo(0, offset), 100)
|
this.scrollTimeout = setTimeout(() => window.scrollTo(0, position), 100)
|
||||||
},
|
},
|
||||||
|
|
||||||
addEventAncestors(event) {
|
addEventAncestors(event) {
|
||||||
|
Loading…
Reference in New Issue
Block a user