Add scrolling and marking as read (local only)

This commit is contained in:
Peter Stuifzand 2018-08-27 22:21:20 +02:00
parent 2b9d086948
commit 746ef03a63
6 changed files with 77 additions and 34 deletions

View File

@ -7,7 +7,7 @@
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>ekstereye</title>
</head>
<body>
<body class="has-navbar-fixed-top">
<noscript>
<strong>We're sorry but ekstereye doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>

View File

@ -1,6 +1,6 @@
<template>
<div id="app">
<nav id="nav" class="navbar is-primary">
<nav id="nav" class="navbar is-primary is-fixed-top">
<div class="container">
<div class="navbar-brand">
<router-link to="/" class="navbar-item">Ekster</router-link>
@ -19,9 +19,8 @@
</nav>
<div class="container">
<router-view/>
<LoginModal :active="!this.$store.state.logged_in"></LoginModal>
</div>
<LoginModal :active="!this.$store.state.logged_in"></LoginModal>
</div>
</template>

View File

@ -1,7 +1,7 @@
<template>
<div class="entry card">
<div :class="classes">
<div class="card-image" v-if="photo_first">
<figure class="image is-4by3">
<figure class="image">
<img :src="photo_first"/>
</figure>
</div>
@ -27,7 +27,7 @@
<div class="debug" v-text="item" v-if="this.$store.state.debug"></div>
<a :href="item.url">
<a :href="item.url" target="_new">
<span class="published" v-html="item.published"></span>
</a>
</div>
@ -42,6 +42,9 @@
props: ['item'],
computed: {
classes() {
return {'entry': true, 'card': true, 'unread': !this.item._is_read}
},
main_content() {
let content = this.item.content
if (content) {
@ -89,6 +92,11 @@
<style scoped>
.entry {
border: 1px solid #ccc;
}
.unread {
box-shadow: 0 4px 8px 0 rgba(255, 255, 0, 0.8), 0 6px 20px 0 rgba(255, 255, 0, 0.5);
}
.photos {

View File

@ -3,7 +3,6 @@
<div class="timeline--item" v-for="item in items" :key="item.id">
<TimelineEntry :item="item"/>
</div>
<div class="level">
<div class="level-item">
<button class="button" @click="prevPage" v-if="timeline.paging.before">Prev Page</button>
@ -24,7 +23,7 @@
components: {TimelineEntry},
computed: {
items () {
items() {
return this.timeline.items.filter((item) => {
return item.type === 'entry';
})
@ -33,11 +32,32 @@
methods: {
nextPage() {
this.$emit('getPage', {uid: this.channel.uid, after: this.timeline.paging.after})
if (this.timeline.paging.after) {
this.$emit('getPage', {uid: this.channel.uid, after: this.timeline.paging.after})
}
},
prevPage() {
this.$emit('getPage', {uid: this.channel.uid, before: this.timeline.paging.before})
}
},
mounted() {
window.onscroll = () => {
// let bottomOfWindow = document.documentElement.scrollTop + window.innerHeight === document.documentElement.offsetHeight;
let bottomOfWindow = document.documentElement.scrollTop + window.innerHeight === this.$el.offsetHeight + document.documentElement.offsetHeight + 20;
if (bottomOfWindow) {
this.$children.forEach((child) => {
child.$props.item._is_read = true
})
}
this.$children.forEach((child) => {
let rect = child.$el.getBoundingClientRect()
if (rect.top+rect.height < 100) {
child.$props.item._is_read = true
}
})
}
}
}
</script>

View File

@ -22,14 +22,21 @@ export default new Vuex.Store({
state.channels = channels
},
newTimeline(state, {channel, timeline}) {
state.timeline = timeline
state.channel = channel
state.timeline = timeline
},
newAccessToken(state, {me, access_token, scope}) {
state.logged_in = true
state.scope = scope
state.me = me
state.access_token = access_token
},
clearTimeline(state, {channel}) {
state.channel = channel
state.timeline = {
items: [],
paging: {}
}
}
},
@ -45,6 +52,9 @@ export default new Vuex.Store({
commit('newChannels', response.channels)
})
},
switchChannel({commit}, channel) {
commit('clearTimeline', {channel: channel})
},
fetchTimeline({commit}, channel) {
let url = 'https://microsub.stuifzandapp.com/microsub?action=timeline&channel=' + channel.uid
if (channel.after) {

View File

@ -1,18 +1,13 @@
<template>
<div class="home">
<div class="columns">
<div class="column is-2">
<Channels class="channels" :channels="this.$store.state.channels">
<div slot-scope="{ channel }">
<Channel :channel="channel" @channel-selected="selectChannel"></Channel>
</div>
</Channels>
<Channels class="channels" :channels="this.$store.state.channels">
<div slot-scope="{ channel }">
<Channel :channel="channel" @channel-selected="selectChannel"></Channel>
</div>
<div class="column">
<Timeline class="timeline" :timeline="this.$store.state.timeline" :channel="this.$store.state.channel"
@getPage="getPage"></Timeline>
</div>
</div>
</Channels>
<Timeline class="timeline" :timeline="this.$store.state.timeline" :channel="this.$store.state.channel"
@getPage="getPage"></Timeline>
</div>
</template>
@ -30,12 +25,6 @@
Channel
},
data() {
return {
showChannels: false
}
},
computed: {
uid() {
return this.$route.params.uid || 'home';
@ -44,13 +33,16 @@
methods: {
selectChannel(channel) {
this.$store.dispatch('fetchTimeline', channel)
this.showChannels = false
window.scrollTo({top: 0})
this.$store.dispatch('switchChannel', channel).then(() => {
this.$store.dispatch('fetchTimeline', channel).then(() => {
window.scrollTo({top: 0})
})
})
},
getPage(next) {
this.$store.dispatch('fetchTimeline', next)
window.scrollTo({top: 0})
this.$store.dispatch('fetchTimeline', next).then(() => {
window.scrollTo({top: 0})
})
}
},
@ -67,5 +59,19 @@
.timeline {
margin-top: 20px;
width: 600px;
position: absolute;
left: 270px;
padding-bottom: 100px;
}
.channels {
position: fixed;
top: 52px;
height: calc(100vh - 52px);
width: 250px;
overflow-y: scroll;
overflow-x: hidden;
padding-bottom: 100px;
}
</style>