diff --git a/src/App.js b/src/App.js
index d4b3b41a..6ebb401a 100644
--- a/src/App.js
+++ b/src/App.js
@@ -3,6 +3,7 @@ import NavPanel from './components/nav_panel/nav_panel.vue'
import InstanceSpecificPanel from './components/instance_specific_panel/instance_specific_panel.vue'
import FeaturesPanel from './components/features_panel/features_panel.vue'
import WhoToFollowPanel from './components/who_to_follow_panel/who_to_follow_panel.vue'
+import ShoutPanel from './components/shout_panel/shout_panel.vue'
import SettingsModal from './components/settings_modal/settings_modal.vue'
import MediaModal from './components/media_modal/media_modal.vue'
import ModModal from './components/mod_modal/mod_modal.vue'
@@ -28,6 +29,7 @@ export default {
InstanceSpecificPanel,
FeaturesPanel,
WhoToFollowPanel,
+ ShoutPanel,
MediaModal,
SideDrawer,
MobilePostStatusButton,
@@ -79,17 +81,28 @@ export default {
}
}
},
+ shout () { return this.$store.state.shout.joined },
suggestionsEnabled () { return this.$store.state.instance.suggestionsEnabled },
showInstanceSpecificPanel () {
return this.$store.state.instance.showInstanceSpecificPanel &&
!this.$store.getters.mergedConfig.hideISP &&
this.$store.state.instance.instanceSpecificPanelContent
},
+ isChats () {
+ return this.$route.name === 'chat' || this.$route.name === 'chats'
+ },
newPostButtonShown () {
+ if (this.isChats) return false
return this.$store.getters.mergedConfig.alwaysShowNewPostButton || this.layoutType === 'mobile'
},
showFeaturesPanel () { return this.$store.state.instance.showFeaturesPanel },
editingAvailable () { return this.$store.state.instance.editingAvailable },
+ shoutboxPosition () {
+ return this.$store.getters.mergedConfig.alwaysShowNewPostButton || false
+ },
+ hideShoutbox () {
+ return this.$store.getters.mergedConfig.hideShoutbox
+ },
layoutType () { return this.$store.state.interface.layoutType },
privateMode () { return this.$store.state.instance.private },
reverseLayout () {
diff --git a/src/App.vue b/src/App.vue
index 80ebb525..fb6adca9 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -33,7 +33,7 @@
+
diff --git a/src/_variables.scss b/src/_variables.scss
index 65ce4027..099d3606 100644
--- a/src/_variables.scss
+++ b/src/_variables.scss
@@ -27,6 +27,7 @@ $fallback--tooltipRadius: 5px;
$fallback--avatarRadius: 4px;
$fallback--avatarAltRadius: 10px;
$fallback--attachmentRadius: 10px;
+$fallback--chatMessageRadius: 10px;
$fallback--buttonShadow: 0px 0px 2px 0px rgba(0, 0, 0, 1), 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset, 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset;
diff --git a/src/boot/after_store.js b/src/boot/after_store.js
index 60671135..9023210c 100644
--- a/src/boot/after_store.js
+++ b/src/boot/after_store.js
@@ -276,6 +276,9 @@ const getNodeInfo = async ({ store }) => {
store.dispatch('setInstanceOption', { name: 'registrationOpen', value: data.openRegistrations })
store.dispatch('setInstanceOption', { name: 'mediaProxyAvailable', value: features.includes('media_proxy') })
store.dispatch('setInstanceOption', { name: 'safeDM', value: features.includes('safe_dm_mentions') })
+ store.dispatch('setInstanceOption', { name: 'shoutAvailable', value: features.includes('chat') })
+ store.dispatch('setInstanceOption', { name: 'pleromaChatMessagesAvailable', value: features.includes('pleroma_chat_messages') })
+ store.dispatch('setInstanceOption', { name: 'gopherAvailable', value: features.includes('gopher') })
store.dispatch('setInstanceOption', { name: 'pollsAvailable', value: features.includes('polls') })
store.dispatch('setInstanceOption', { name: 'editingAvailable', value: features.includes('editing') })
store.dispatch('setInstanceOption', { name: 'pollLimits', value: metadata.pollLimits })
diff --git a/src/boot/routes.js b/src/boot/routes.js
index 93a94a9b..2f0c8d3d 100644
--- a/src/boot/routes.js
+++ b/src/boot/routes.js
@@ -7,6 +7,8 @@ import BookmarkTimeline from 'components/bookmark_timeline/bookmark_timeline.vue
import ConversationPage from 'components/conversation-page/conversation-page.vue'
import Interactions from 'components/interactions/interactions.vue'
import DMs from 'components/dm_timeline/dm_timeline.vue'
+import ChatList from 'components/chat_list/chat_list.vue'
+import Chat from 'components/chat/chat.vue'
import UserProfile from 'components/user_profile/user_profile.vue'
import Search from 'components/search/search.vue'
import Registration from 'components/registration/registration.vue'
@@ -15,6 +17,7 @@ import FollowRequests from 'components/follow_requests/follow_requests.vue'
import OAuthCallback from 'components/oauth_callback/oauth_callback.vue'
import Notifications from 'components/notifications/notifications.vue'
import AuthForm from 'components/auth_form/auth_form.js'
+import ShoutPanel from 'components/shout_panel/shout_panel.vue'
import WhoToFollow from 'components/who_to_follow/who_to_follow.vue'
import About from 'components/about/about.vue'
import RemoteUserResolver from 'components/remote_user_resolver/remote_user_resolver.vue'
@@ -71,6 +74,7 @@ export default (store) => {
{ name: 'friend-requests', path: '/friend-requests', component: FollowRequests, beforeEnter: validateAuthenticatedRoute },
{ name: 'notifications', path: '/:username/notifications', component: Notifications, props: () => ({ disableTeleport: true }), beforeEnter: validateAuthenticatedRoute },
{ name: 'login', path: '/login', component: AuthForm },
+ { name: 'shout-panel', path: '/shout-panel', component: ShoutPanel, props: () => ({ floating: false }) },
{ name: 'oauth-callback', path: '/oauth-callback', component: OAuthCallback, props: (route) => ({ code: route.query.code }) },
{ name: 'search', path: '/search', component: Search, props: (route) => ({ query: route.query.query }) },
{ name: 'who-to-follow', path: '/who-to-follow', component: WhoToFollow, beforeEnter: validateAuthenticatedRoute },
@@ -82,5 +86,12 @@ export default (store) => {
{ name: 'user-profile', path: '/:_(users)?/:name', component: UserProfile, meta: { dontScroll: true } }
]
+ if (store.state.instance.pleromaChatMessagesAvailable) {
+ routes = routes.concat([
+ { name: 'chat', path: '/users/:username/chats/:recipient_id', component: Chat, meta: { dontScroll: false }, beforeEnter: validateAuthenticatedRoute },
+ { name: 'chats', path: '/users/:username/chats', component: ChatList, meta: { dontScroll: false }, beforeEnter: validateAuthenticatedRoute }
+ ])
+ }
+
return routes
}
diff --git a/src/components/account_actions/account_actions.js b/src/components/account_actions/account_actions.js
index 0f348474..f679742a 100644
--- a/src/components/account_actions/account_actions.js
+++ b/src/components/account_actions/account_actions.js
@@ -1,8 +1,8 @@
+import { mapState } from 'vuex'
import ProgressButton from '../progress_button/progress_button.vue'
import Popover from '../popover/popover.vue'
import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
-import { mapState } from 'vuex'
import {
faEllipsisV
} from '@fortawesome/free-solid-svg-icons'
@@ -61,6 +61,12 @@ const AccountActions = {
reportUser () {
this.$store.dispatch('openUserReportingModal', { userId: this.user.id })
},
+ openChat () {
+ this.$router.push({
+ name: 'chat',
+ params: { username: this.$store.state.users.currentUser.screen_name, recipient_id: this.user.id }
+ })
+ },
muteDomain () {
this.$store.dispatch('muteDomain', this.user.screen_name.split('@')[1])
.then(() => this.refetchRelationship())
diff --git a/src/components/account_actions/account_actions.vue b/src/components/account_actions/account_actions.vue
index 126f6fa9..4eb838ff 100644
--- a/src/components/account_actions/account_actions.vue
+++ b/src/components/account_actions/account_actions.vue
@@ -54,6 +54,13 @@
@click="reportUser"
>
{{ $t('user_card.report') }}
+
+