Add scrolling and marking as read (local only)
This commit is contained in:
parent
2b9d086948
commit
746ef03a63
|
|
@ -7,7 +7,7 @@
|
||||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||||
<title>ekstereye</title>
|
<title>ekstereye</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body class="has-navbar-fixed-top">
|
||||||
<noscript>
|
<noscript>
|
||||||
<strong>We're sorry but ekstereye doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
<strong>We're sorry but ekstereye doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||||
</noscript>
|
</noscript>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div id="app">
|
<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="container">
|
||||||
<div class="navbar-brand">
|
<div class="navbar-brand">
|
||||||
<router-link to="/" class="navbar-item">Ekster</router-link>
|
<router-link to="/" class="navbar-item">Ekster</router-link>
|
||||||
|
|
@ -19,9 +19,8 @@
|
||||||
</nav>
|
</nav>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<router-view/>
|
<router-view/>
|
||||||
|
|
||||||
<LoginModal :active="!this.$store.state.logged_in"></LoginModal>
|
|
||||||
</div>
|
</div>
|
||||||
|
<LoginModal :active="!this.$store.state.logged_in"></LoginModal>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="entry card">
|
<div :class="classes">
|
||||||
<div class="card-image" v-if="photo_first">
|
<div class="card-image" v-if="photo_first">
|
||||||
<figure class="image is-4by3">
|
<figure class="image">
|
||||||
<img :src="photo_first"/>
|
<img :src="photo_first"/>
|
||||||
</figure>
|
</figure>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
<div class="debug" v-text="item" v-if="this.$store.state.debug"></div>
|
<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>
|
<span class="published" v-html="item.published"></span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -42,6 +42,9 @@
|
||||||
props: ['item'],
|
props: ['item'],
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
classes() {
|
||||||
|
return {'entry': true, 'card': true, 'unread': !this.item._is_read}
|
||||||
|
},
|
||||||
main_content() {
|
main_content() {
|
||||||
let content = this.item.content
|
let content = this.item.content
|
||||||
if (content) {
|
if (content) {
|
||||||
|
|
@ -89,6 +92,11 @@
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.entry {
|
.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 {
|
.photos {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
<div class="timeline--item" v-for="item in items" :key="item.id">
|
<div class="timeline--item" v-for="item in items" :key="item.id">
|
||||||
<TimelineEntry :item="item"/>
|
<TimelineEntry :item="item"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="level">
|
<div class="level">
|
||||||
<div class="level-item">
|
<div class="level-item">
|
||||||
<button class="button" @click="prevPage" v-if="timeline.paging.before">Prev Page</button>
|
<button class="button" @click="prevPage" v-if="timeline.paging.before">Prev Page</button>
|
||||||
|
|
@ -24,7 +23,7 @@
|
||||||
components: {TimelineEntry},
|
components: {TimelineEntry},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
items () {
|
items() {
|
||||||
return this.timeline.items.filter((item) => {
|
return this.timeline.items.filter((item) => {
|
||||||
return item.type === 'entry';
|
return item.type === 'entry';
|
||||||
})
|
})
|
||||||
|
|
@ -33,11 +32,32 @@
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
nextPage() {
|
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() {
|
prevPage() {
|
||||||
this.$emit('getPage', {uid: this.channel.uid, before: this.timeline.paging.before})
|
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>
|
</script>
|
||||||
|
|
|
||||||
12
src/store.js
12
src/store.js
|
|
@ -22,14 +22,21 @@ export default new Vuex.Store({
|
||||||
state.channels = channels
|
state.channels = channels
|
||||||
},
|
},
|
||||||
newTimeline(state, {channel, timeline}) {
|
newTimeline(state, {channel, timeline}) {
|
||||||
state.timeline = timeline
|
|
||||||
state.channel = channel
|
state.channel = channel
|
||||||
|
state.timeline = timeline
|
||||||
},
|
},
|
||||||
newAccessToken(state, {me, access_token, scope}) {
|
newAccessToken(state, {me, access_token, scope}) {
|
||||||
state.logged_in = true
|
state.logged_in = true
|
||||||
state.scope = scope
|
state.scope = scope
|
||||||
state.me = me
|
state.me = me
|
||||||
state.access_token = access_token
|
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)
|
commit('newChannels', response.channels)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
switchChannel({commit}, channel) {
|
||||||
|
commit('clearTimeline', {channel: channel})
|
||||||
|
},
|
||||||
fetchTimeline({commit}, channel) {
|
fetchTimeline({commit}, channel) {
|
||||||
let url = 'https://microsub.stuifzandapp.com/microsub?action=timeline&channel=' + channel.uid
|
let url = 'https://microsub.stuifzandapp.com/microsub?action=timeline&channel=' + channel.uid
|
||||||
if (channel.after) {
|
if (channel.after) {
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="home">
|
<div class="home">
|
||||||
<div class="columns">
|
<Channels class="channels" :channels="this.$store.state.channels">
|
||||||
<div class="column is-2">
|
<div slot-scope="{ channel }">
|
||||||
<Channels class="channels" :channels="this.$store.state.channels">
|
<Channel :channel="channel" @channel-selected="selectChannel"></Channel>
|
||||||
<div slot-scope="{ channel }">
|
|
||||||
<Channel :channel="channel" @channel-selected="selectChannel"></Channel>
|
|
||||||
</div>
|
|
||||||
</Channels>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="column">
|
</Channels>
|
||||||
<Timeline class="timeline" :timeline="this.$store.state.timeline" :channel="this.$store.state.channel"
|
|
||||||
@getPage="getPage"></Timeline>
|
<Timeline class="timeline" :timeline="this.$store.state.timeline" :channel="this.$store.state.channel"
|
||||||
</div>
|
@getPage="getPage"></Timeline>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -30,12 +25,6 @@
|
||||||
Channel
|
Channel
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
showChannels: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
uid() {
|
uid() {
|
||||||
return this.$route.params.uid || 'home';
|
return this.$route.params.uid || 'home';
|
||||||
|
|
@ -44,13 +33,16 @@
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
selectChannel(channel) {
|
selectChannel(channel) {
|
||||||
this.$store.dispatch('fetchTimeline', channel)
|
this.$store.dispatch('switchChannel', channel).then(() => {
|
||||||
this.showChannels = false
|
this.$store.dispatch('fetchTimeline', channel).then(() => {
|
||||||
window.scrollTo({top: 0})
|
window.scrollTo({top: 0})
|
||||||
|
})
|
||||||
|
})
|
||||||
},
|
},
|
||||||
getPage(next) {
|
getPage(next) {
|
||||||
this.$store.dispatch('fetchTimeline', next)
|
this.$store.dispatch('fetchTimeline', next).then(() => {
|
||||||
window.scrollTo({top: 0})
|
window.scrollTo({top: 0})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -67,5 +59,19 @@
|
||||||
.timeline {
|
.timeline {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
width: 600px;
|
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>
|
</style>
|
||||||
Loading…
Reference in New Issue
Block a user