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">
|
||||
<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>
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>
|
||||
|
|
12
src/store.js
12
src/store.js
|
@ -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) {
|
||||
|
|
|
@ -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>
|
Loading…
Reference in New Issue
Block a user