Page MenuHomePhorge

No OneTemporary

Size
15 KB
Referenced Files
None
Subscribers
None
diff --git a/src/App.js b/src/App.js
index e924896727..a052e058ea 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,43 +1,46 @@
import UserPanel from './components/user_panel/user_panel.vue'
import NavPanel from './components/nav_panel/nav_panel.vue'
import Notifications from './components/notifications/notifications.vue'
import UserFinder from './components/user_finder/user_finder.vue'
+import WhoToFollowPanel from './components/who_to_follow_panel/who_to_follow_panel.vue'
import InstanceSpecificPanel from './components/instance_specific_panel/instance_specific_panel.vue'
import ChatPanel from './components/chat_panel/chat_panel.vue'
export default {
name: 'app',
components: {
UserPanel,
NavPanel,
Notifications,
UserFinder,
- ChatPanel,
- InstanceSpecificPanel
+ WhoToFollowPanel,
+ InstanceSpecificPanel,
+ ChatPanel
},
data: () => ({
mobileActivePanel: 'timeline'
}),
computed: {
currentUser () { return this.$store.state.users.currentUser },
background () {
return this.currentUser.background_image || this.$store.state.config.background
},
logoStyle () { return { 'background-image': `url(${this.$store.state.config.logo})` } },
style () { return { 'background-image': `url(${this.background})` } },
sitename () { return this.$store.state.config.name },
chat () { return this.$store.state.chat.channel.state === 'joined' },
+ showWhoToFollowPanel () { return this.$store.state.config.showWhoToFollowPanel },
showInstanceSpecificPanel () { return this.$store.state.config.showInstanceSpecificPanel }
},
methods: {
activatePanel (panelName) {
this.mobileActivePanel = panelName
},
scrollToTop () {
window.scrollTo(0, 0)
},
logout () {
this.$store.dispatch('logout')
}
}
}
diff --git a/src/App.vue b/src/App.vue
index a8d17fa7e9..923d411b1e 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,43 +1,44 @@
<template>
<div id="app" v-bind:style="style">
<nav class='container' @click="scrollToTop()" id="nav">
<div class='inner-nav' :style="logoStyle">
<div class='item'>
<router-link :to="{ name: 'root'}">{{sitename}}</router-link>
</div>
<div class='item right'>
<user-finder class="nav-icon"></user-finder>
<router-link :to="{ name: 'settings'}"><i class="icon-cog nav-icon"></i></router-link>
<a href="#" v-if="currentUser" @click.prevent="logout"><i class="icon-logout nav-icon" :title="$t('login.logout')"></i></a>
</div>
</div>
</nav>
<div class="container" id="content">
<div class="panel-switcher">
<button @click="activatePanel('sidebar')">Sidebar</button>
<button @click="activatePanel('timeline')">Timeline</button>
</div>
<div class="sidebar-flexer" :class="{ 'mobile-hidden': mobileActivePanel != 'sidebar'}">
<div class="sidebar-bounds">
<div class="sidebar-scroller">
<div class="sidebar">
<user-panel></user-panel>
<nav-panel></nav-panel>
<instance-specific-panel v-if="showInstanceSpecificPanel"></instance-specific-panel>
+ <who-to-follow-panel v-if="currentUser && showWhoToFollowPanel"></who-to-follow-panel>
<notifications v-if="currentUser"></notifications>
</div>
</div>
</div>
</div>
<div class="main" :class="{ 'mobile-hidden': mobileActivePanel != 'timeline' }">
<transition name="fade">
<router-view></router-view>
</transition>
</div>
</div>
<chat-panel v-if="currentUser && chat" class="floating-chat mobile-hidden"></chat-panel>
</div>
</template>
<script src="./App.js"></script>
<style lang="scss" src="./App.scss"></style>
diff --git a/src/components/who_to_follow_panel/who_to_follow_panel.js b/src/components/who_to_follow_panel/who_to_follow_panel.js
new file mode 100644
index 0000000000..47952d212f
--- /dev/null
+++ b/src/components/who_to_follow_panel/who_to_follow_panel.js
@@ -0,0 +1,130 @@
+function showWhoToFollow (panel, users, aHost, aUser) {
+ var cn
+ var index = 0
+ var random = Math.floor(Math.random() * 10)
+ for (cn = random; cn < users.length; cn = cn + 10) {
+ var user
+ user = users[cn]
+ var host
+ host = user.host
+ var username
+ if (user.username) {
+ username = user.username
+ } else {
+ username = user.user
+ }
+ var img
+ if (user.avatar) {
+ img = user.avatar
+ } else {
+ img = '/images/avi.png'
+ }
+ var name = username + '@' + host
+ if ((!user.following) &&
+ (!user.blacklisted) &&
+ (!(host === aHost && username === aUser))) {
+ if (index === 0) {
+ panel.img1 = img
+ panel.name1 = name
+ panel.$store.state.api.backendInteractor.externalProfile(name)
+ .then((externalUser) => {
+ if (!externalUser.error) {
+ panel.$store.commit('addNewUsers', [externalUser])
+ panel.id1 = externalUser.id
+ }
+ })
+ } else if (index === 1) {
+ panel.img2 = img
+ panel.name2 = name
+ panel.$store.state.api.backendInteractor.externalProfile(name)
+ .then((externalUser) => {
+ if (!externalUser.error) {
+ panel.$store.commit('addNewUsers', [externalUser])
+ panel.id2 = externalUser.id
+ }
+ })
+ } else if (index === 2) {
+ panel.img3 = img
+ panel.name3 = name
+ panel.$store.state.api.backendInteractor.externalProfile(name)
+ .then((externalUser) => {
+ if (!externalUser.error) {
+ panel.$store.commit('addNewUsers', [externalUser])
+ panel.id3 = externalUser.id
+ }
+ })
+ }
+ index = index + 1
+ if (index > 2) {
+ break
+ }
+ }
+ }
+}
+
+function getWhoToFollow (panel) {
+ var user = panel.$store.state.users.currentUser.screen_name
+ if (user) {
+ panel.name1 = 'Loading...'
+ panel.name2 = 'Loading...'
+ panel.name3 = 'Loading...'
+ var host = window.location.hostname
+ var url = 'https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-simple-api.cgi?' +
+ encodeURIComponent(host) + '+' + encodeURIComponent(user)
+ window.fetch(url, {mode: 'cors'}).then(function (response) {
+ if (response.ok) {
+ return response.json()
+ } else {
+ panel.name1 = ''
+ panel.name2 = ''
+ panel.name3 = ''
+ }
+ }).then(function (users) {
+ showWhoToFollow(panel, users, host, user)
+ })
+ }
+}
+
+const WhoToFollowPanel = {
+ data: () => ({
+ img1: '/images/avi.png',
+ name1: '',
+ id1: 0,
+ img2: '/images/avi.png',
+ name2: '',
+ id2: 0,
+ img3: '/images/avi.png',
+ name3: '',
+ id3: 0
+ }),
+ computed: {
+ user: function () {
+ return this.$store.state.users.currentUser.screen_name
+ },
+ moreUrl: function () {
+ var host = window.location.hostname
+ var user = this.user
+ var url = 'https://vinayaka.distsn.org/?' +
+ encodeURIComponent(host) + '+' + encodeURIComponent(user)
+ return url
+ },
+ showWhoToFollowPanel () {
+ return this.$store.state.config.showWhoToFollowPanel
+ }
+ },
+ watch: {
+ user: function (user, oldUser) {
+ if (this.showWhoToFollowPanel) {
+ getWhoToFollow(this)
+ }
+ }
+ },
+ mounted:
+ function () {
+ if (this.showWhoToFollowPanel) {
+ getWhoToFollow(this)
+ }
+ }
+}
+
+export default WhoToFollowPanel
diff --git a/src/components/who_to_follow_panel/who_to_follow_panel.vue b/src/components/who_to_follow_panel/who_to_follow_panel.vue
new file mode 100644
index 0000000000..021b95576f
--- /dev/null
+++ b/src/components/who_to_follow_panel/who_to_follow_panel.vue
@@ -0,0 +1,37 @@
+<template>
+ <div class="who-to-follow-panel">
+ <div class="panel panel-default base01-background">
+ <div class="panel-heading timeline-heading base02-background base04">
+ <div class="title">
+ Who to follow
+ </div>
+ </div>
+ <div class="panel-body who-to-follow">
+ <p>
+ <img v-bind:src="img1"/><router-link :to="{ name: 'user-profile', params: { id: id1 } }">{{ name1 }}</router-link><br>
+ <img v-bind:src="img2"/><router-link :to="{ name: 'user-profile', params: { id: id2 } }">{{ name2 }}</router-link><br>
+ <img v-bind:src="img3"/><router-link :to="{ name: 'user-profile', params: { id: id3 } }">{{ name3 }}</router-link><br>
+ <img v-bind:src="$store.state.config.logo"> <a v-bind:href="moreUrl" target="_blank">More</a>
+ </p>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script src="./who_to_follow_panel.js" ></script>
+
+<style lang="scss">
+ .who-to-follow * {
+ vertical-align: middle;
+ }
+ .who-to-follow img {
+ width: 32px;
+ height: 32px;
+ }
+ .who-to-follow p {
+ line-height: 40px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+</style>
diff --git a/src/main.js b/src/main.js
index 7ca34adf96..a40c51f2fc 100644
--- a/src/main.js
+++ b/src/main.js
@@ -1,179 +1,180 @@
import Vue from 'vue'
import VueRouter from 'vue-router'
import Vuex from 'vuex'
import App from './App.vue'
import PublicTimeline from './components/public_timeline/public_timeline.vue'
import PublicAndExternalTimeline from './components/public_and_external_timeline/public_and_external_timeline.vue'
import FriendsTimeline from './components/friends_timeline/friends_timeline.vue'
import TagTimeline from './components/tag_timeline/tag_timeline.vue'
import ConversationPage from './components/conversation-page/conversation-page.vue'
import Mentions from './components/mentions/mentions.vue'
import UserProfile from './components/user_profile/user_profile.vue'
import Settings from './components/settings/settings.vue'
import Registration from './components/registration/registration.vue'
import UserSettings from './components/user_settings/user_settings.vue'
import statusesModule from './modules/statuses.js'
import usersModule from './modules/users.js'
import apiModule from './modules/api.js'
import configModule from './modules/config.js'
import chatModule from './modules/chat.js'
import VueTimeago from 'vue-timeago'
import VueI18n from 'vue-i18n'
import createPersistedState from './lib/persisted_state.js'
import messages from './i18n/messages.js'
import VueChatScroll from 'vue-chat-scroll'
const currentLocale = (window.navigator.language || 'en').split('-')[0]
Vue.use(Vuex)
Vue.use(VueRouter)
Vue.use(VueTimeago, {
locale: currentLocale === 'ja' ? 'ja' : 'en',
locales: {
'en': require('../static/timeago-en.json'),
'ja': require('../static/timeago-ja.json')
}
})
Vue.use(VueI18n)
Vue.use(VueChatScroll)
const persistedStateOptions = {
paths: [
'config.hideAttachments',
'config.hideAttachmentsInConv',
'config.hideNsfw',
'config.autoLoad',
'config.hoverPreview',
'config.streaming',
'config.muteWords',
'config.customTheme',
'users.lastLoginName'
]
}
const store = new Vuex.Store({
modules: {
statuses: statusesModule,
users: usersModule,
api: apiModule,
config: configModule,
chat: chatModule
},
plugins: [createPersistedState(persistedStateOptions)],
strict: false // Socket modifies itself, let's ignore this for now.
// strict: process.env.NODE_ENV !== 'production'
})
const i18n = new VueI18n({
locale: currentLocale,
fallbackLocale: 'en',
messages
})
window.fetch('/api/statusnet/config.json')
.then((res) => res.json())
.then((data) => {
const {name, closed: registrationClosed, textlimit} = data.site
store.dispatch('setOption', { name: 'name', value: name })
store.dispatch('setOption', { name: 'registrationOpen', value: (registrationClosed === '0') })
store.dispatch('setOption', { name: 'textlimit', value: parseInt(textlimit) })
})
window.fetch('/static/config.json')
.then((res) => res.json())
.then((data) => {
- const {theme, background, logo, showInstanceSpecificPanel} = data
+ const {theme, background, logo, showWhoToFollowPanel, showInstanceSpecificPanel} = data
store.dispatch('setOption', { name: 'theme', value: theme })
store.dispatch('setOption', { name: 'background', value: background })
store.dispatch('setOption', { name: 'logo', value: logo })
+ store.dispatch('setOption', { name: 'showWhoToFollowPanel', value: showWhoToFollowPanel })
store.dispatch('setOption', { name: 'showInstanceSpecificPanel', value: showInstanceSpecificPanel })
if (data['chatDisabled']) {
store.dispatch('disableChat')
}
const routes = [
{ name: 'root',
path: '/',
redirect: to => {
var redirectRootLogin = data['redirectRootLogin']
var redirectRootNoLogin = data['redirectRootNoLogin']
return (store.state.users.currentUser ? redirectRootLogin : redirectRootNoLogin) || '/main/all'
}},
{ path: '/main/all', component: PublicAndExternalTimeline },
{ path: '/main/public', component: PublicTimeline },
{ path: '/main/friends', component: FriendsTimeline },
{ path: '/tag/:tag', component: TagTimeline },
{ name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } },
{ name: 'user-profile', path: '/users/:id', component: UserProfile },
{ name: 'mentions', path: '/:username/mentions', component: Mentions },
{ name: 'settings', path: '/settings', component: Settings },
{ name: 'registration', path: '/registration', component: Registration },
{ name: 'user-settings', path: '/user-settings', component: UserSettings }
]
const router = new VueRouter({
mode: 'history',
routes,
scrollBehavior: (to, from, savedPosition) => {
if (to.matched.some(m => m.meta.dontScroll)) {
return false
}
return savedPosition || { x: 0, y: 0 }
}
})
/* eslint-disable no-new */
new Vue({
router,
store,
i18n,
el: '#app',
render: h => h(App)
})
})
window.fetch('/static/terms-of-service.html')
.then((res) => res.text())
.then((html) => {
store.dispatch('setOption', { name: 'tos', value: html })
})
window.fetch('/api/pleroma/emoji.json')
.then(
(res) => res.json()
.then(
(values) => {
const emoji = Object.keys(values).map((key) => {
return { shortcode: key, image_url: values[key] }
})
store.dispatch('setOption', { name: 'customEmoji', value: emoji })
store.dispatch('setOption', { name: 'pleromaBackend', value: true })
},
(failure) => {
store.dispatch('setOption', { name: 'pleromaBackend', value: false })
}
),
(error) => console.log(error)
)
window.fetch('/static/emoji.json')
.then((res) => res.json())
.then((values) => {
const emoji = Object.keys(values).map((key) => {
return { shortcode: key, image_url: false, 'utf': values[key] }
})
store.dispatch('setOption', { name: 'emoji', value: emoji })
})
window.fetch('/instance/panel.html')
.then((res) => res.text())
.then((html) => {
store.dispatch('setOption', { name: 'instanceSpecificPanelContent', value: html })
})
diff --git a/static/config.json b/static/config.json
index 5cf4cdeca0..2c49514295 100644
--- a/static/config.json
+++ b/static/config.json
@@ -1,9 +1,10 @@
{
"theme": "pleroma-dark",
"background": "/static/aurora_borealis.jpg",
"logo": "/static/logo.png",
"redirectRootNoLogin": "/main/all",
"redirectRootLogin": "/main/friends",
"chatDisabled": false,
+ "showWhoToFollowPanel": false,
"showInstanceSpecificPanel": false
}

File Metadata

Mime Type
text/x-diff
Expires
Sun, Aug 30, 9:49 PM (1 d, 18 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1738175
Default Alt Text
(15 KB)

Event Timeline