Compare commits
3 Commits
0316db4072
...
8aa4f6882a
| Author | SHA1 | Date | |
|---|---|---|---|
| 8aa4f6882a | |||
| cf65818eb4 | |||
| cc70df90af |
622
package-lock.json
generated
622
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
|
@ -8,15 +8,17 @@
|
|||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@primer/css": "^14.1.0",
|
||||
"bulma": "^0.7.5",
|
||||
"event-source-polyfill": "0.0.16",
|
||||
"isomorphic-fetch": "^2.2.1",
|
||||
"lodash": "latest",
|
||||
"micropub-helper": "^1.4.0",
|
||||
"moment": "^2.22.2",
|
||||
"node-sass": "^4.12.0",
|
||||
"node-sass": "^4.14.1",
|
||||
"rel-scraper": "github:grantcodes/rel-scraper",
|
||||
"sass-loader": "^7.2.0",
|
||||
"tailwindcss": "1.1.4",
|
||||
"vue": "^2.5.17",
|
||||
"vue-router": "^3.0.1",
|
||||
"vuex": "^3.0.1"
|
||||
|
|
@ -25,6 +27,8 @@
|
|||
"@vue/cli-plugin-babel": "^3.10.0",
|
||||
"@vue/cli-plugin-eslint": "^3.0.0-rc.10",
|
||||
"@vue/cli-service": "^3.10.0",
|
||||
"postcss-node-sass": "^2.1.8",
|
||||
"postcss-scss": "^2.0.0",
|
||||
"vue-template-compiler": "^2.5.17"
|
||||
},
|
||||
"eslintConfig": {
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
if (item) {
|
||||
let loginData = JSON.parse(item)
|
||||
this.$store.dispatch('isLoggedIn', loginData)
|
||||
this.$store.dispatch('startEventListening', '?action=events')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
</div>
|
||||
|
||||
<h3 class="title is-6" v-if="currentItem.name" v-text="currentItem.name"></h3>
|
||||
<div class="content is-pre" v-html="main_content"></div>
|
||||
<div class="content" v-html="main_content"></div>
|
||||
|
||||
<div class="photos">
|
||||
<div class="photo" v-for="photo in photo_rest" :key="photo">
|
||||
|
|
@ -42,6 +42,7 @@
|
|||
<a @click="like">Like</a>
|
||||
· <a @click.prevent="openReply">Reply</a>
|
||||
· <a @click.prevent="repost">Repost</a>
|
||||
· <a @click.prevent="openBookmark">Bookmark</a>
|
||||
· <a @click.prevent="$emit('followFeed', author_url)" title="Try to follow the feed this item comes from">Follow</a>
|
||||
· <a @click.prevent="debug">Debug</a>
|
||||
</span>
|
||||
|
|
@ -64,23 +65,53 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="media" v-if="bookmarking">
|
||||
<div class="media-content">
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input type="text" class="input" placeholder="Title" v-model="bookmarkTitle">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label">Add a note</label>
|
||||
<div class="control">
|
||||
<textarea class="textarea" v-model="bookmarkDescription"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<syndication-buttons v-model="selected" :targets="targets"/>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<button class="button is-primary" @click="bookmark">Bookmark</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment'
|
||||
import moment from 'moment'
|
||||
import SyndicationButtons from "@/components/SyndicationButtons";
|
||||
|
||||
export default {
|
||||
export default {
|
||||
name: "Entry",
|
||||
components: {SyndicationButtons},
|
||||
props: ['item'],
|
||||
|
||||
data() {
|
||||
return {
|
||||
'replying': false,
|
||||
'replyText': '',
|
||||
'showFooterButtons': true
|
||||
'showFooterButtons': true,
|
||||
bookmarking: false,
|
||||
bookmarkTitle: '',
|
||||
bookmarkDescription: '',
|
||||
targets: [],
|
||||
selected: []
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -122,6 +153,30 @@
|
|||
},
|
||||
})
|
||||
},
|
||||
openBookmark() {
|
||||
this.bookmarking = true
|
||||
this.bookmarkTitle = this.author_name + ' - ' + this.currentItem.name
|
||||
this.bookmarkDescription = ''
|
||||
this.selected = []
|
||||
this.$store.dispatch('fetchSyndicationTargets')
|
||||
.then(res => this.targets = res['syndicate-to'])
|
||||
},
|
||||
bookmark() {
|
||||
this.$store.dispatch('micropubPost', {
|
||||
'type': ['h-entry'],
|
||||
'properties': {
|
||||
'bookmark-of': [this.currentItem.url],
|
||||
'name': [this.bookmarkTitle],
|
||||
'content': [this.bookmarkDescription ],
|
||||
'mp-syndicate-to': this.selected
|
||||
},
|
||||
}).then(() => {
|
||||
this.bookmarkTitle = '';
|
||||
this.bookmarkDescription = '';
|
||||
this.selected = []
|
||||
this.bookmarking = false
|
||||
})
|
||||
},
|
||||
hasRef(key) {
|
||||
if (this.item.hasOwnProperty(key) && this.item.hasOwnProperty('refs')) {
|
||||
if (this.item.refs.hasOwnProperty(this.item[key])) {
|
||||
|
|
@ -289,4 +344,5 @@
|
|||
.is-pre {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
@ -11,6 +11,9 @@
|
|||
<textarea class="textarea" v-model="newPost"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<syndication-buttons v-model="selectedTargets" :targets="targets"/>
|
||||
</div>
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
|
|
@ -33,20 +36,30 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import SyndicationButtons from "@/components/SyndicationButtons";
|
||||
export default {
|
||||
name: "NewPost",
|
||||
components:{
|
||||
SyndicationButtons
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
newPost: '',
|
||||
tags: [{name:"twitter"},{name:"instagram"}]
|
||||
targets: [],
|
||||
selectedTargets: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$store.dispatch('fetchSyndicationTargets')
|
||||
.then(res => this.targets = res['syndicate-to'])
|
||||
},
|
||||
methods: {
|
||||
post() {
|
||||
this.$store.dispatch('micropubPost', {
|
||||
'type': ['h-entry'],
|
||||
'properties': {
|
||||
'content': [this.newPost]
|
||||
'content': [this.newPost],
|
||||
'mp-syndicate-to': this.selectedTargets,
|
||||
},
|
||||
}).then(() => {
|
||||
this.newPost = '';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div style="margin-top: 20px">
|
||||
<div class="short-timeline">
|
||||
<div class="box small-item" style="margin-bottom: 4px" v-for="(item, i) in timeline.items" :key="i">
|
||||
<div class="name" v-text="text(item)"></div>
|
||||
<div class="time" v-text="niceTime(item)"></div>
|
||||
|
|
@ -36,8 +36,13 @@
|
|||
</script>
|
||||
|
||||
<style scoped>
|
||||
.short-timeline {
|
||||
margin-top: 20px;
|
||||
position: fixed;
|
||||
max-width: 280px;
|
||||
}
|
||||
.small-item {
|
||||
font-size: 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
.box {
|
||||
padding: 6px;
|
||||
|
|
|
|||
43
src/components/SyndicationButtons.vue
Normal file
43
src/components/SyndicationButtons.vue
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<template>
|
||||
<div>
|
||||
<div v-for="(target, i) in targets" :key="i" style="display: inline-block; margin: 0 3px 3px 0">
|
||||
<label>
|
||||
<input type="checkbox" class="is-hidden cb-target" v-model="selected" :value="target.uid"/>
|
||||
<span class="tag is-light" v-text="target.name"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'syndication-buttons',
|
||||
data() {
|
||||
return {
|
||||
selected: [],
|
||||
}
|
||||
},
|
||||
props: {
|
||||
value: [],
|
||||
targets: {}
|
||||
},
|
||||
mounted() {
|
||||
this.selected = this.value
|
||||
},
|
||||
watch: {
|
||||
selected(newSelection) {
|
||||
this.$emit('update', newSelection)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
|
||||
.tag {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cb-target:checked + .tag {
|
||||
background-color: #23d160;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -59,7 +59,7 @@
|
|||
.then(() => {
|
||||
item._is_read = true
|
||||
}).then(() => {
|
||||
this.$store.dispatch('fetchChannels')
|
||||
// this.$store.dispatch('fetchChannels')
|
||||
})
|
||||
},
|
||||
handleScroll() {
|
||||
|
|
@ -77,7 +77,7 @@
|
|||
child.$props.item._is_read = true
|
||||
let item = child.$props.item
|
||||
this.markRead(this.channel.uid, item).then(() => {
|
||||
this.$store.dispatch('fetchChannels')
|
||||
// this.$store.dispatch('fetchChannels')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import router from './router'
|
|||
import store from './store'
|
||||
import 'bulma'
|
||||
import '@/styles.scss'
|
||||
import '@primer/css/utilities/index.scss';
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
|
|
|
|||
57
src/store.js
57
src/store.js
|
|
@ -63,6 +63,9 @@ export default new Vuex.Store({
|
|||
state.microsubEndpoint = endpoints.microsubEndpoint
|
||||
},
|
||||
createEventSource(state, url) {
|
||||
if (state.eventSource !== null) {
|
||||
state.eventSource.close()
|
||||
}
|
||||
state.eventSource = new EventSource(state.microsubEndpoint + url + "&access_token=" + state.access_token, {
|
||||
// headers: {
|
||||
// 'Authorization': 'Bearer ' + this.state.access_token
|
||||
|
|
@ -83,15 +86,24 @@ export default new Vuex.Store({
|
|||
state.eventSource.addEventListener('error', evt => {
|
||||
// eslint-disable-next-line
|
||||
console.log(evt)
|
||||
if (evt.message === "network error") {
|
||||
state.eventSource.close()
|
||||
}
|
||||
})
|
||||
state.eventSource.addEventListener('new item', evt => {
|
||||
// eslint-disable-next-line
|
||||
console.log(evt)
|
||||
|
||||
let item = JSON.parse(evt.data)
|
||||
// eslint-disable-next-line
|
||||
state.timeline.items = [...state.timeline.items, item]
|
||||
state.globalTimeline.items = _.take([item, ...state.globalTimeline.items], 10)
|
||||
|
||||
try {
|
||||
let newItemMsg = JSON.parse(evt.data)
|
||||
if (state.channel.uid === newItemMsg.channel) {
|
||||
state.timeline.items = [...state.timeline.items, newItemMsg.item]
|
||||
}
|
||||
state.globalTimeline.items = _.takeRight([...state.globalTimeline.items, newItemMsg.item], 10)
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line
|
||||
console.log(e)
|
||||
}
|
||||
})
|
||||
state.eventSource.addEventListener('new item in channel', evt => {
|
||||
// eslint-disable-next-line
|
||||
|
|
@ -152,7 +164,13 @@ export default new Vuex.Store({
|
|||
commit('newAccessToken', response)
|
||||
},
|
||||
markRead(x, {channel, entry}) {
|
||||
let url = this.state.microsubEndpoint + '?action=timeline&method=mark_read&channel=' + encodeURIComponent(channel) + '&entry=' + encodeURIComponent(entry);
|
||||
let entries = '';
|
||||
if (Array.isArray(entry)) {
|
||||
entries = _(entry).map(uid => '&entry[]='+encodeURIComponent(uid)).join("")
|
||||
} else {
|
||||
entries = '&entry=' + encodeURIComponent(entry)
|
||||
}
|
||||
let url = this.state.microsubEndpoint + '?action=timeline&method=mark_read&channel=' + encodeURIComponent(channel) + entries;
|
||||
return fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
|
|
@ -160,6 +178,13 @@ export default new Vuex.Store({
|
|||
}
|
||||
})
|
||||
},
|
||||
fetchSyndicationTargets() {
|
||||
let micropub = new Micropub({
|
||||
token: this.state.access_token,
|
||||
micropubEndpoint: this.state.micropubEndpoint
|
||||
})
|
||||
return micropub.query('syndicate-to')
|
||||
},
|
||||
micropubPost(_, mf2post) {
|
||||
let micropub = new Micropub({
|
||||
token: this.state.access_token,
|
||||
|
|
@ -193,21 +218,23 @@ export default new Vuex.Store({
|
|||
})
|
||||
},
|
||||
bottomReached() {
|
||||
let count = 0
|
||||
let uids = []
|
||||
// eslint-disable-next-line
|
||||
console.log('bottomReached')
|
||||
|
||||
let items = this.state.timeline.items
|
||||
uids = _.map(_.filter(items, item => !item._is_read), item => item._id)
|
||||
// eslint-disable-next-line
|
||||
console.log(items)
|
||||
let uids = _(items).reject('_is_read').map('_id').value()
|
||||
// eslint-disable-next-line
|
||||
console.log(uids)
|
||||
|
||||
items.forEach((item) => {
|
||||
if (item && !item._is_read) {
|
||||
item._is_read = true
|
||||
count++;
|
||||
}
|
||||
})
|
||||
if (count > 0) {
|
||||
this.dispatch('markRead', {channel: this.state.channel.uid, 'entry[]': uids})
|
||||
.then(() => {
|
||||
this.dispatch('fetchChannels')
|
||||
})
|
||||
if (uids.length > 0) {
|
||||
return this.dispatch('markRead', {channel: this.state.channel.uid, 'entry': uids})
|
||||
}
|
||||
},
|
||||
startEventListening({commit}, url) {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
@import 'bulmaswatch.min.css';
|
||||
//@import 'bulmaswatch.min.css';
|
||||
|
||||
.mb-20 {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.mt-20 {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -111,7 +111,6 @@
|
|||
|
||||
mounted() {
|
||||
if (this.$store.state.logged_in) {
|
||||
this.$store.dispatch('startEventListening', '?action=events')
|
||||
this.$store.dispatch('fetchChannels')
|
||||
this.$store.dispatch('fetchTimeline', {uid: this.uid})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user