aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/App.scss48
-rw-r--r--src/App.vue5
-rw-r--r--src/boot/after_store.js15
-rw-r--r--src/components/attachment/attachment.js2
-rw-r--r--src/components/status/status.vue2
-rw-r--r--src/components/timeline/timeline.js5
-rw-r--r--src/components/user_card/user_card.js3
-rw-r--r--src/components/user_card/user_card.vue4
-rw-r--r--src/components/user_card_content/user_card_content.js12
-rw-r--r--src/components/user_card_content/user_card_content.vue5
-rw-r--r--src/components/user_finder/user_finder.vue5
-rw-r--r--src/components/user_profile/user_profile.vue18
-rw-r--r--src/components/user_settings/user_settings.js56
-rw-r--r--src/components/user_settings/user_settings.vue14
-rw-r--r--src/i18n/en.json3
-rw-r--r--src/i18n/ru.json2
-rw-r--r--src/main.js6
-rw-r--r--src/modules/instance.js2
-rw-r--r--src/modules/users.js5
19 files changed, 159 insertions, 53 deletions
diff --git a/src/App.scss b/src/App.scss
index 5355d899..871f193f 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -228,24 +228,23 @@ i[class*=icon-] {
padding: 0 10px 0 10px;
}
-.gaps {
- margin: -1em 0 0 -1em;
-}
-
.item {
flex: 1;
line-height: 50px;
height: 50px;
overflow: hidden;
+ display: flex;
+ flex-wrap: wrap;
.nav-icon {
font-size: 1.1em;
margin-left: 0.4em;
}
-}
-.gaps > .item {
- padding: 1em 0 0 1em;
+ &.right {
+ justify-content: right;
+ padding-right: 20px;
+ }
}
.auto-size {
@@ -293,8 +292,6 @@ nav {
}
.inner-nav {
- padding-left: 20px;
- padding-right: 20px;
display: flex;
align-items: center;
flex-basis: 970px;
@@ -452,6 +449,23 @@ nav {
color: var(--faint, $fallback--faint);
box-shadow: 0px 0px 4px rgba(0,0,0,.6);
box-shadow: var(--topBarShadow);
+
+ .back-button {
+ display: block;
+ max-width: 99px;
+ transition-property: opacity, max-width;
+ transition-duration: 300ms;
+ transition-timing-function: ease-out;
+
+ i {
+ margin: 0 1em;
+ }
+
+ &.hidden {
+ opacity: 0;
+ max-width: 20px;
+ }
+ }
}
.fade-enter-active, .fade-leave-active {
@@ -486,6 +500,7 @@ nav {
display: none;
width: 100%;
height: 46px;
+
button {
display: block;
flex: 1;
@@ -499,6 +514,16 @@ nav {
body {
overflow-y: scroll;
}
+
+ nav {
+ .back-button {
+ display: none;
+ }
+ .site-name {
+ padding-left: 20px;
+ }
+ }
+
.sidebar-bounds {
overflow: hidden;
max-height: 100vh;
@@ -591,11 +616,6 @@ nav {
}
}
-.item.right {
- text-align: right;
- padding-right: 20px;
-}
-
.visibility-tray {
font-size: 1.2em;
padding: 3px;
diff --git a/src/App.vue b/src/App.vue
index 16cd08d4..048c1e77 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -7,7 +7,10 @@
</div>
<div class='inner-nav'>
<div class='item'>
- <router-link :to="{ name: 'root'}">{{sitename}}</router-link>
+ <router-link class="back-button" @click.native="activatePanel('timeline')" :to="{ name: 'root' }" active-class="hidden">
+ <i class="icon-left-open" :title="$t('nav.back')"></i>
+ </router-link>
+ <router-link class="site-name" :to="{ name: 'root' }" active-class="home">{{sitename}}</router-link>
</div>
<div class='item right'>
<user-finder class="nav-icon"></user-finder>
diff --git a/src/boot/after_store.js b/src/boot/after_store.js
index bc1d1acc..24a8d3ac 100644
--- a/src/boot/after_store.js
+++ b/src/boot/after_store.js
@@ -32,6 +32,10 @@ const afterStoreSetup = ({ store, i18n }) => {
store.dispatch('setInstanceOption', { name: 'bannerlimit', value: parseInt(uploadlimit.bannerlimit) })
store.dispatch('setInstanceOption', { name: 'server', value: server })
+ if (data.nsfwCensorImage) {
+ store.dispatch('setInstanceOption', { name: 'nsfwCensorImage', value: data.nsfwCensorImage })
+ }
+
if (vapidPublicKey) {
store.dispatch('setInstanceOption', { name: 'vapidPublicKey', value: vapidPublicKey })
}
@@ -46,8 +50,17 @@ const afterStoreSetup = ({ store, i18n }) => {
return {}
})
.then((staticConfig) => {
+ const overrides = window.___pleromafe_dev_overrides || {}
+ const env = window.___pleromafe_mode.NODE_ENV
+
// This takes static config and overrides properties that are present in apiConfig
- var config = Object.assign({}, staticConfig, apiConfig)
+ let config = {}
+ if (overrides.staticConfigPreference && env === 'development') {
+ console.warn('OVERRIDING API CONFIG WITH STATIC CONFIG')
+ config = Object.assign({}, apiConfig, staticConfig)
+ } else {
+ config = Object.assign({}, staticConfig, apiConfig)
+ }
var theme = (config.theme)
var background = (config.background)
diff --git a/src/components/attachment/attachment.js b/src/components/attachment/attachment.js
index 16114c30..97c4f283 100644
--- a/src/components/attachment/attachment.js
+++ b/src/components/attachment/attachment.js
@@ -11,7 +11,7 @@ const Attachment = {
],
data () {
return {
- nsfwImage,
+ nsfwImage: this.$store.state.config.nsfwCensorImage || nsfwImage,
hideNsfwLocal: this.$store.state.config.hideNsfw,
preloadImage: this.$store.state.config.preloadImage,
loopVideo: this.$store.state.config.loopVideo,
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index 96709084..067980ac 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -54,7 +54,7 @@
</h4>
</div>
<div class="media-heading-right">
- <router-link @click.native="activatePanel('timeline')" :to="{ name: 'conversation', params: { id: status.id } }">
+ <router-link class="timeago" @click.native="activatePanel('timeline')" :to="{ name: 'conversation', params: { id: status.id } }">
<timeago :since="status.created_at" :auto-update="60"></timeago>
</router-link>
<div class="visibility-icon" v-if="status.visibility">
diff --git a/src/components/timeline/timeline.js b/src/components/timeline/timeline.js
index a651f619..f28b85bd 100644
--- a/src/components/timeline/timeline.js
+++ b/src/components/timeline/timeline.js
@@ -2,6 +2,7 @@ import Status from '../status/status.vue'
import timelineFetcher from '../../services/timeline_fetcher/timeline_fetcher.service.js'
import StatusOrConversation from '../status_or_conversation/status_or_conversation.vue'
import UserCard from '../user_card/user_card.vue'
+import { throttle } from 'lodash'
const Timeline = {
props: [
@@ -88,7 +89,7 @@ const Timeline = {
this.paused = false
}
},
- fetchOlderStatuses () {
+ fetchOlderStatuses: throttle(function () {
const store = this.$store
const credentials = store.state.users.currentUser.credentials
store.commit('setLoading', { timeline: this.timelineName, value: true })
@@ -101,7 +102,7 @@ const Timeline = {
userId: this.userId,
tag: this.tag
}).then(() => store.commit('setLoading', { timeline: this.timelineName, value: false }))
- },
+ }, 1000, this),
fetchFollowers () {
const id = this.userId
this.$store.state.api.backendInteractor.fetchFollowers({ id })
diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js
index a019627a..b8eb28e3 100644
--- a/src/components/user_card/user_card.js
+++ b/src/components/user_card/user_card.js
@@ -14,6 +14,9 @@ const UserCard = {
components: {
UserCardContent
},
+ computed: {
+ currentUser () { return this.$store.state.users.currentUser }
+ },
methods: {
toggleUserExpanded () {
this.userExpanded = !this.userExpanded
diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue
index 5a8e5531..eb0d7576 100644
--- a/src/components/user_card/user_card.vue
+++ b/src/components/user_card/user_card.vue
@@ -10,13 +10,13 @@
<div :title="user.name" v-if="user.name_html" class="user-name">
<span v-html="user.name_html"></span>
<span class="follows-you" v-if="!userExpanded && showFollows && user.follows_you">
- {{ $t('user_card.follows_you') }}
+ {{ currentUser.id == user.id ? $t('user_card.its_you') : $t('user_card.follows_you') }}
</span>
</div>
<div :title="user.name" v-else class="user-name">
{{ user.name }}
<span class="follows-you" v-if="!userExpanded && showFollows && user.follows_you">
- {{ $t('user_card.follows_you') }}
+ {{ currentUser.id == user.id ? $t('user_card.its_you') : $t('user_card.follows_you') }}
</span>
</div>
<router-link class='user-screen-name' :to="{ name: 'user-profile', params: { id: user.id } }">
diff --git a/src/components/user_card_content/user_card_content.js b/src/components/user_card_content/user_card_content.js
index e7f19953..be7a2349 100644
--- a/src/components/user_card_content/user_card_content.js
+++ b/src/components/user_card_content/user_card_content.js
@@ -20,10 +20,20 @@ export default {
if (color) {
const rgb = (typeof color === 'string') ? hex2rgb(color) : color
const tintColor = `rgba(${Math.floor(rgb.r)}, ${Math.floor(rgb.g)}, ${Math.floor(rgb.b)}, .5)`
+
+ const gradient = [
+ [tintColor, this.hideBio ? '60%' : ''],
+ this.hideBio ? [
+ color, '100%'
+ ] : [
+ tintColor, ''
+ ]
+ ].map(_ => _.join(' ')).join(', ')
+
return {
backgroundColor: `rgb(${Math.floor(rgb.r * 0.53)}, ${Math.floor(rgb.g * 0.56)}, ${Math.floor(rgb.b * 0.59)})`,
backgroundImage: [
- `linear-gradient(to bottom, ${tintColor}, ${tintColor})`,
+ `linear-gradient(to bottom, ${gradient})`,
`url(${this.user.cover_photo})`
].join(', ')
}
diff --git a/src/components/user_card_content/user_card_content.vue b/src/components/user_card_content/user_card_content.vue
index 18504277..08b25595 100644
--- a/src/components/user_card_content/user_card_content.vue
+++ b/src/components/user_card_content/user_card_content.vue
@@ -90,7 +90,7 @@
</div>
</div>
</div>
- <div class="panel-body profile-panel-body" v-if="switcher">
+ <div class="panel-body profile-panel-body" v-if="!hideBio">
<div v-if="!hideUserStatsLocal || switcher" class="user-counts" :class="{clickable: switcher}">
<div class="user-count" v-on:click.prevent="setProfileView('statuses')" :class="{selected: selected === 'statuses'}">
<h5>{{ $t('user_card.statuses') }}</h5>
@@ -122,6 +122,9 @@
border-radius: var(--panelRadius, $fallback--panelRadius);
overflow: hidden;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+
.panel-heading {
padding: 0.6em 0em;
text-align: center;
diff --git a/src/components/user_finder/user_finder.vue b/src/components/user_finder/user_finder.vue
index 8786f6c7..4d9f6842 100644
--- a/src/components/user_finder/user_finder.vue
+++ b/src/components/user_finder/user_finder.vue
@@ -1,12 +1,12 @@
<template>
- <span class="user-finder-container">
+ <div class="user-finder-container">
<i class="icon-spin4 user-finder-icon animate-spin-slow" v-if="loading" />
<a href="#" v-if="hidden" :title="$t('finder.find_user')" ><i class="icon-user-plus user-finder-icon" @click.prevent.stop="toggleHidden" /></a>
<span v-else>
<input class="user-finder-input" @keyup.enter="findUser(username)" v-model="username" :placeholder="$t('finder.find_user')" id="user-finder-input" type="text"/>
<i class="icon-cancel user-finder-icon" @click.prevent.stop="toggleHidden"/>
</span>
- </span>
+ </div>
</template>
<script src="./user_finder.js"></script>
@@ -15,7 +15,6 @@
@import '../../_variables.scss';
.user-finder-container {
- height: 29px;
max-width: 100%;
}
diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue
index 91d4acd2..4d2853a6 100644
--- a/src/components/user_profile/user_profile.vue
+++ b/src/components/user_profile/user_profile.vue
@@ -3,6 +3,16 @@
<div v-if="user" class="user-profile panel panel-default">
<user-card-content :user="user" :switcher="true" :selected="timeline.viewing"></user-card-content>
</div>
+ <div v-else class="panel user-profile-placeholder">
+ <div class="panel-heading">
+ <div class="title">
+ {{ $t('settings.profile_tab') }}
+ </div>
+ </div>
+ <div class="panel-body">
+ <i class="icon-spin3 animate-spin"></i>
+ </div>
+ </div>
<Timeline :title="$t('user_profile.timeline_title')" :timeline="timeline" :timeline-name="'user'" :user-id="userId"/>
</div>
</template>
@@ -21,4 +31,12 @@
align-items: stretch;
}
}
+.user-profile-placeholder {
+ .panel-body {
+ display: flex;
+ justify-content: center;
+ align-items: middle;
+ padding: 7em;
+ }
+}
</style>
diff --git a/src/components/user_settings/user_settings.js b/src/components/user_settings/user_settings.js
index 43e39b13..ca7bf319 100644
--- a/src/components/user_settings/user_settings.js
+++ b/src/components/user_settings/user_settings.js
@@ -5,11 +5,12 @@ import fileSizeFormatService from '../../services/file_size_format/file_size_for
const UserSettings = {
data () {
return {
- newname: this.$store.state.users.currentUser.name,
- newbio: this.$store.state.users.currentUser.description,
- newlocked: this.$store.state.users.currentUser.locked,
- newnorichtext: this.$store.state.users.currentUser.no_rich_text,
- newdefaultScope: this.$store.state.users.currentUser.default_scope,
+ newName: this.$store.state.users.currentUser.name,
+ newBio: this.$store.state.users.currentUser.description,
+ newLocked: this.$store.state.users.currentUser.locked,
+ newNoRichText: this.$store.state.users.currentUser.no_rich_text,
+ newDefaultScope: this.$store.state.users.currentUser.default_scope,
+ newHideNetwork: this.$store.state.users.currentUser.hide_network,
followList: null,
followImportError: false,
followsImported: false,
@@ -49,31 +50,45 @@ const UserSettings = {
},
vis () {
return {
- public: { selected: this.newdefaultScope === 'public' },
- unlisted: { selected: this.newdefaultScope === 'unlisted' },
- private: { selected: this.newdefaultScope === 'private' },
- direct: { selected: this.newdefaultScope === 'direct' }
+ public: { selected: this.newDefaultScope === 'public' },
+ unlisted: { selected: this.newDefaultScope === 'unlisted' },
+ private: { selected: this.newDefaultScope === 'private' },
+ direct: { selected: this.newDefaultScope === 'direct' }
}
}
},
methods: {
updateProfile () {
const name = this.newname
- const description = this.newbio
- const locked = this.newlocked
+ const description = this.newBio
+ const locked = this.newLocked
+ // Backend notation.
/* eslint-disable camelcase */
- const default_scope = this.newdefaultScope
- const no_rich_text = this.newnorichtext
- this.$store.state.api.backendInteractor.updateProfile({params: {name, description, locked, default_scope, no_rich_text}}).then((user) => {
- if (!user.error) {
- this.$store.commit('addNewUsers', [user])
- this.$store.commit('setCurrentUser', user)
- }
- })
+ const default_scope = this.newDefaultScope
+ const no_rich_text = this.newNoRichText
+ const hide_network = this.newHideNetwork
/* eslint-enable camelcase */
+ this.$store.state.api.backendInteractor
+ .updateProfile({
+ params: {
+ name,
+ description,
+ locked,
+ // Backend notation.
+ /* eslint-disable camelcase */
+ default_scope,
+ no_rich_text,
+ hide_network
+ /* eslint-enable camelcase */
+ }}).then((user) => {
+ if (!user.error) {
+ this.$store.commit('addNewUsers', [user])
+ this.$store.commit('setCurrentUser', user)
+ }
+ })
},
changeVis (visibility) {
- this.newdefaultScope = visibility
+ this.newDefaultScope = visibility
},
uploadFile (slot, e) {
const file = e.target.files[0]
@@ -221,6 +236,7 @@ const UserSettings = {
.fetchFriends({id: this.$store.state.users.currentUser.id})
.then((friendList) => {
this.exportPeople(friendList, 'friends.csv')
+ setTimeout(() => { this.enableFollowsExport = true }, 2000)
})
},
followListChange () {
diff --git a/src/components/user_settings/user_settings.vue b/src/components/user_settings/user_settings.vue
index 1a98b788..67b65b57 100644
--- a/src/components/user_settings/user_settings.vue
+++ b/src/components/user_settings/user_settings.vue
@@ -9,11 +9,11 @@
<div class="setting-item" >
<h2>{{$t('settings.name_bio')}}</h2>
<p>{{$t('settings.name')}}</p>
- <input class='name-changer' id='username' v-model="newname"></input>
+ <input class='name-changer' id='username' v-model="newName"></input>
<p>{{$t('settings.bio')}}</p>
- <textarea class="bio" v-model="newbio"></textarea>
+ <textarea class="bio" v-model="newBio"></textarea>
<p>
- <input type="checkbox" v-model="newlocked" id="account-locked">
+ <input type="checkbox" v-model="newLocked" id="account-locked">
<label for="account-locked">{{$t('settings.lock_account_description')}}</label>
</p>
<div v-if="scopeOptionsEnabled">
@@ -26,10 +26,14 @@
</div>
</div>
<p>
- <input type="checkbox" v-model="newnorichtext" id="account-no-rich-text">
+ <input type="checkbox" v-model="newNoRichText" id="account-no-rich-text">
<label for="account-no-rich-text">{{$t('settings.no_rich_text_description')}}</label>
</p>
- <button :disabled='newname.length <= 0' class="btn btn-default" @click="updateProfile">{{$t('general.submit')}}</button>
+ <p>
+ <input type="checkbox" v-model="newHideNetwork" id="account-hide-network">
+ <label for="account-no-rich-text">{{$t('settings.hide_network_description')}}</label>
+ </p>
+ <button :disabled='newName.length <= 0' class="btn btn-default" @click="updateProfile">{{$t('general.submit')}}</button>
</div>
<div class="setting-item">
<h2>{{$t('settings.avatar')}}</h2>
diff --git a/src/i18n/en.json b/src/i18n/en.json
index ac5eef5a..1ce53796 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -29,6 +29,7 @@
"username": "Username"
},
"nav": {
+ "back": "Back",
"chat": "Local Chat",
"friend_requests": "Follow Requests",
"mentions": "Mentions",
@@ -151,6 +152,7 @@
"notification_visibility_mentions": "Mentions",
"notification_visibility_repeats": "Repeats",
"no_rich_text_description": "Strip rich text formatting from all posts",
+ "hide_network_description": "Don't show who I'm following and who's following me",
"nsfw_clickthrough": "Enable clickthrough NSFW attachment hiding",
"panelRadius": "Panels",
"pause_on_unfocused": "Pause streaming when tab is not focused",
@@ -322,6 +324,7 @@
"followers": "Followers",
"following": "Following!",
"follows_you": "Follows you!",
+ "its_you": "It's you!",
"mute": "Mute",
"muted": "Muted",
"per_day": "per day",
diff --git a/src/i18n/ru.json b/src/i18n/ru.json
index c764005a..80598b0c 100644
--- a/src/i18n/ru.json
+++ b/src/i18n/ru.json
@@ -19,6 +19,7 @@
"username": "Имя пользователя"
},
"nav": {
+ "back": "Назад",
"chat": "Локальный чат",
"mentions": "Упоминания",
"public_tl": "Публичная лента",
@@ -126,6 +127,7 @@
"notification_visibility_mentions": "Упоминания",
"notification_visibility_repeats": "Повторы",
"no_rich_text_description": "Убрать форматирование из всех постов",
+ "hide_network_description": "Не показывать кого я читаю и кто меня читает",
"nsfw_clickthrough": "Включить скрытие NSFW вложений",
"panelRadius": "Панели",
"pause_on_unfocused": "Приостановить загрузку когда вкладка не в фокусе",
diff --git a/src/main.js b/src/main.js
index 23ea854b..bf92e78e 100644
--- a/src/main.js
+++ b/src/main.js
@@ -95,3 +95,9 @@ createPersistedState(persistedStateOptions).then((persistedState) => {
afterStoreSetup({ store, i18n })
})
+
+// These are inlined by webpack's DefinePlugin
+/* eslint-disable */
+window.___pleromafe_mode = process.env
+window.___pleromafe_commit_hash = COMMIT_HASH
+window.___pleromafe_dev_overrides = DEV_OVERRIDES
diff --git a/src/modules/instance.js b/src/modules/instance.js
index 7c27d52a..ab88306f 100644
--- a/src/modules/instance.js
+++ b/src/modules/instance.js
@@ -25,6 +25,8 @@ const defaultState = {
scopeCopy: true,
subjectLineBehavior: 'email',
loginMethod: 'password',
+ nsfwCensorImage: undefined,
+ vapidPublicKey: undefined,
// Nasty stuff
pleromaBackend: true,
diff --git a/src/modules/users.js b/src/modules/users.js
index d2ac95cd..25d1c81f 100644
--- a/src/modules/users.js
+++ b/src/modules/users.js
@@ -17,6 +17,9 @@ export const mergeOrAdd = (arr, obj, item) => {
// This is a new item, prepare it
arr.push(item)
obj[item.id] = item
+ if (item.screen_name && !item.screen_name.includes('@')) {
+ obj[item.screen_name] = item
+ }
return { item, new: true }
}
}
@@ -87,7 +90,7 @@ const users = {
actions: {
fetchUser (store, id) {
store.rootState.api.backendInteractor.fetchUser({ id })
- .then((user) => store.commit('addNewUsers', user))
+ .then((user) => store.commit('addNewUsers', [user]))
},
registerPushNotifications (store) {
const token = store.state.currentUser.credentials