Move post interface to NewPost, add Feed Preview
This commit is contained in:
parent
7c0545874a
commit
d88f7ab1d9
38
src/components/FeedChooser.vue
Normal file
38
src/components/FeedChooser.vue
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<template>
|
||||||
|
<div class="result">
|
||||||
|
<div class="image is-48x48"><img :src="feed.photo" alt="" class="feed-icon"/></div>
|
||||||
|
<div class="feed-name" v-text="feed.name"></div>
|
||||||
|
<button :class="buttonClasses" @click="showFeed">Show feed</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'feed-chooser',
|
||||||
|
props: ['feed'],
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
buttonClasses() {
|
||||||
|
return {'button': true, 'is-loading': this.feed.loading}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
showFeed(feed) {
|
||||||
|
this.$emit('showFeed', feed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.result {
|
||||||
|
margin-top: 6px;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
border: 1px solid #eee;
|
||||||
|
padding: 6px;
|
||||||
|
}
|
||||||
|
</style>
|
128
src/components/FeedFollower.vue
Normal file
128
src/components/FeedFollower.vue
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
<template>
|
||||||
|
<div :class="modalClasses">
|
||||||
|
<div class="modal-background"></div>
|
||||||
|
<div class="modal-card">
|
||||||
|
<header class="modal-card-head">
|
||||||
|
<p class="modal-card-title">Add feed to channel</p>
|
||||||
|
<button class="delete" aria-label="close" @click="close"></button>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="modal-card-body">
|
||||||
|
<div class="field has-addons">
|
||||||
|
<div class="control is-expanded">
|
||||||
|
<input type="text" class="input is-expanded" id="query" placeholder="Search for feed" v-model="query"
|
||||||
|
ref="query" @keypress.enter="search"/>
|
||||||
|
</div>
|
||||||
|
<div class="control">
|
||||||
|
<button :class="searchClasses" @click="search">Search</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="results">
|
||||||
|
<feed-chooser :feed="feed" @showFeed="showFeed(feed)" v-for="(feed, i) in feeds" :key="i"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Timeline class="timeline" :timeline="timeline" :channel="channel"></Timeline>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="modal-card-foot">
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Timeline from '../components/Timeline';
|
||||||
|
import FeedChooser from "./FeedChooser";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "FeedFollower",
|
||||||
|
components: {FeedChooser, Timeline},
|
||||||
|
props: ['isOpen'],
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
feeds: [],
|
||||||
|
timeline: {items: [], paging: {}},
|
||||||
|
channel: {},
|
||||||
|
query: '',
|
||||||
|
loading: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
modalClasses() {
|
||||||
|
return {'modal': true, 'is-active': this.isOpen}
|
||||||
|
},
|
||||||
|
searchClasses() {
|
||||||
|
return {'button': true, 'is-primary': true, 'is-loading': this.loading}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
isOpen(newVal, oldVal) {
|
||||||
|
if (newVal) {
|
||||||
|
this.$nextTick(function () {
|
||||||
|
this.$refs.query.focus()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
close() {
|
||||||
|
this.feeds = []
|
||||||
|
this.timeline = {items: [], paging: {}}
|
||||||
|
this.channel = {}
|
||||||
|
this.query = ''
|
||||||
|
this.loading = false
|
||||||
|
|
||||||
|
this.$emit('close')
|
||||||
|
},
|
||||||
|
search() {
|
||||||
|
let url = this.$store.state.microsubEndpoint + '?action=search&query=' + encodeURIComponent(this.query)
|
||||||
|
this.loading = true
|
||||||
|
return fetch(url, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer ' + this.$store.state.access_token
|
||||||
|
}
|
||||||
|
}).then((res) => {
|
||||||
|
return res.json()
|
||||||
|
}).then((res) => {
|
||||||
|
res.results.forEach(item => {
|
||||||
|
item.loading = false
|
||||||
|
})
|
||||||
|
this.feeds = res.results
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
showFeed(feed) {
|
||||||
|
feed.loading = true
|
||||||
|
let url = this.$store.state.microsubEndpoint + '?action=preview&url=' + encodeURIComponent(feed.url)
|
||||||
|
return fetch(url, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer ' + this.$store.state.access_token
|
||||||
|
}
|
||||||
|
}).then((res) => {
|
||||||
|
return res.json()
|
||||||
|
}).then((res) => {
|
||||||
|
this.channel = feed
|
||||||
|
this.timeline = res
|
||||||
|
feed.loading = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
.results {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
50
src/components/NewPost.vue
Normal file
50
src/components/NewPost.vue
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
<template>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="card-header-title">What are you thinking about?</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-content">
|
||||||
|
<div class="media">
|
||||||
|
<div class="media-content">
|
||||||
|
<div class="field">
|
||||||
|
<div class="control">
|
||||||
|
<textarea class="textarea" v-model="newPost"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<div class="control">
|
||||||
|
<button class="button is-primary" @click="post">Post</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "NewPost",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
newPost: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
post() {
|
||||||
|
this.$store.dispatch('micropubPost', {
|
||||||
|
'type': ['h-entry'],
|
||||||
|
'properties': {
|
||||||
|
'content': [this.newPost]
|
||||||
|
},
|
||||||
|
}).then(() => {
|
||||||
|
this.newPost = '';
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
|
@ -1,31 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div :class="this.className">
|
<div :class="this.className">
|
||||||
<div class="mb-20">
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-header">
|
|
||||||
<div class="card-header-title">What are you thinking about?</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-content">
|
|
||||||
<div class="media">
|
|
||||||
<div class="media-content">
|
|
||||||
<div class="field">
|
|
||||||
<div class="control">
|
|
||||||
<textarea class="textarea" v-model="newPost"></textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="field">
|
|
||||||
<div class="control">
|
|
||||||
<button class="button is-primary" @click="post">Post</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<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" @debug="debug" @markRead="markRead(channel.uid, ...arguments)" :is-main-entry="true"/>
|
<TimelineEntry :item="item" @debug="debug" @markRead="markRead(channel.uid, ...arguments)"
|
||||||
|
:is-main-entry="true"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="level">
|
<div class="level">
|
||||||
<div class="level-item">
|
<div class="level-item">
|
||||||
|
@ -52,7 +29,6 @@
|
||||||
return {
|
return {
|
||||||
showDebug: false,
|
showDebug: false,
|
||||||
debugItem: null,
|
debugItem: null,
|
||||||
newPost: '',
|
|
||||||
state: 'new'
|
state: 'new'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -66,16 +42,6 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
post() {
|
|
||||||
this.$store.dispatch('micropubPost', {
|
|
||||||
'type': ['h-entry'],
|
|
||||||
'properties': {
|
|
||||||
'content': [this.newPost]
|
|
||||||
},
|
|
||||||
}).then(() => {
|
|
||||||
this.newPost = '';
|
|
||||||
})
|
|
||||||
},
|
|
||||||
debug(item) {
|
debug(item) {
|
||||||
this.debugItem = item
|
this.debugItem = item
|
||||||
this.showDebug = true
|
this.showDebug = true
|
||||||
|
@ -136,8 +102,9 @@
|
||||||
.timeline--item {
|
.timeline--item {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.has-buttons {
|
.has-buttons {
|
||||||
justify-content: end;
|
justify-content: end;
|
||||||
padding:12px;
|
padding: 12px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
|
@ -1,4 +1,7 @@
|
||||||
|
|
||||||
.mb-20 {
|
.mb-20 {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
.mt-20 {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
|
@ -6,27 +6,41 @@
|
||||||
</div>
|
</div>
|
||||||
</Channels>
|
</Channels>
|
||||||
|
|
||||||
<Timeline class="timeline" :timeline="this.$store.state.timeline" :channel="this.$store.state.channel"
|
<div class="timeline">
|
||||||
@getPage="getPage"></Timeline>
|
<button class="button" @click="openFeedFollower">Add feed</button>
|
||||||
|
<new-post class="mt-20"></new-post>
|
||||||
|
<Timeline style="margin-top:20px" :timeline="this.$store.state.timeline" :channel="this.$store.state.channel"
|
||||||
|
@getPage="getPage"></Timeline>
|
||||||
|
</div>
|
||||||
|
|
||||||
<channel-creator :is-open="this.$store.state.channelCreatorIsOpen"></channel-creator>
|
<channel-creator :is-open="this.$store.state.channelCreatorIsOpen"></channel-creator>
|
||||||
|
<feed-follower :is-open="feedFollowerIsOpen" @close="closeFeedFollower"></feed-follower>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// @ is an alias to /src
|
import Timeline from '../components/Timeline.vue'
|
||||||
import Timeline from '@/components/Timeline.vue'
|
import Channels from '../components/Channels.vue'
|
||||||
import Channels from '@/components/Channels.vue'
|
import Channel from '../components/Channel.vue'
|
||||||
import Channel from '@/components/Channel.vue'
|
import ChannelCreator from '../components/ChannelCreator.vue'
|
||||||
import ChannelCreator from '@/components/ChannelCreator.vue'
|
import FeedFollower from "../components/FeedFollower"
|
||||||
|
import NewPost from "../components/NewPost"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'home',
|
name: 'home',
|
||||||
components: {
|
components: {
|
||||||
|
FeedFollower,
|
||||||
Timeline,
|
Timeline,
|
||||||
Channels,
|
Channels,
|
||||||
Channel,
|
Channel,
|
||||||
ChannelCreator
|
ChannelCreator,
|
||||||
|
NewPost
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
feedFollowerIsOpen: false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -36,6 +50,12 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
openFeedFollower() {
|
||||||
|
this.feedFollowerIsOpen = true
|
||||||
|
},
|
||||||
|
closeFeedFollower() {
|
||||||
|
this.feedFollowerIsOpen = false
|
||||||
|
},
|
||||||
selectChannel(channel) {
|
selectChannel(channel) {
|
||||||
this.$store.dispatch('switchChannel', channel).then(() => {
|
this.$store.dispatch('switchChannel', channel).then(() => {
|
||||||
this.$store.dispatch('fetchTimeline', channel).then(() => {
|
this.$store.dispatch('fetchTimeline', channel).then(() => {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user