From 1946661911c97651ba5356db22a0ddd00ba04864 Mon Sep 17 00:00:00 2001
From: Ariadne Conill
Date: Sat, 9 Nov 2019 00:27:09 -0600
Subject: [PATCH 001/129] update terms of service instructions
---
static/terms-of-service.html | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/static/terms-of-service.html b/static/terms-of-service.html
index c02cb7198..c880b72c2 100644
--- a/static/terms-of-service.html
+++ b/static/terms-of-service.html
@@ -1,7 +1,8 @@
Terms of Service
-This is a placeholder ToS.
+This is the default placeholder ToS. You should change it to fit the needs of your instance.
-Edit "/static/terms-of-service.html"
to make it fit the needs of your instance.
+To do so, place a file at "/instance/static/terms-of-service.html"
in your
+ Pleroma install containing the real ToS for your instance.
-
+
From ca4d5950d08aec6fe016b56f7125f7328c1e19a1 Mon Sep 17 00:00:00 2001
From: kPherox
Date: Sat, 16 Nov 2019 03:12:16 +0900
Subject: [PATCH 002/129] Display user profile fields
---
src/components/user_profile/user_profile.js | 8 ++++
src/components/user_profile/user_profile.vue | 50 ++++++++++++++++++++
2 files changed, 58 insertions(+)
diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js
index 000557073..c5ab5f26a 100644
--- a/src/components/user_profile/user_profile.js
+++ b/src/components/user_profile/user_profile.js
@@ -123,6 +123,14 @@ const UserProfile = {
onTabSwitch (tab) {
this.tab = tab
this.$router.replace({ query: { tab } })
+ },
+ linkClicked ({ target }) {
+ if (target.tagName === 'SPAN') {
+ target = target.parentNode
+ }
+ if (target.tagName === 'A') {
+ window.open(target.href, '_blank')
+ }
}
},
watch: {
diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue
index 14082e839..f979eff46 100644
--- a/src/components/user_profile/user_profile.vue
+++ b/src/components/user_profile/user_profile.vue
@@ -11,6 +11,44 @@
:allow-zooming-avatar="true"
rounded="top"
/>
+
+
+
+ -
+ {{ field.name }}
+
+ -
+ {{ field.value }}
+
+
+
Date: Mon, 18 Nov 2019 00:27:14 +0900
Subject: [PATCH 003/129] Fix emoji size
---
src/components/user_profile/user_profile.vue | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue
index f979eff46..d5aa514e3 100644
--- a/src/components/user_profile/user_profile.vue
+++ b/src/components/user_profile/user_profile.vue
@@ -152,6 +152,18 @@
flex-basis: 500px;
.user-profile-fields {
+ img {
+ object-fit: contain;
+ vertical-align: middle;
+ max-width: 100%;
+ max-height: 400px;
+
+ &.emoji {
+ width: 32px;
+ height: 32px;
+ }
+ }
+
dl {
margin: 1em 1.5em;
From 004827a7f17a0bc349baf1257aa5debe3c6f6060 Mon Sep 17 00:00:00 2001
From: kPherox
Date: Mon, 18 Nov 2019 02:16:37 +0900
Subject: [PATCH 004/129] Change profile fields design to horizontal
---
src/components/user_profile/user_profile.vue | 20 ++++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue
index d5aa514e3..fdff0385f 100644
--- a/src/components/user_profile/user_profile.vue
+++ b/src/components/user_profile/user_profile.vue
@@ -159,15 +159,31 @@
max-height: 400px;
&.emoji {
- width: 32px;
- height: 32px;
+ width: 18px;
+ height: 18px;
}
}
dl {
+ display: flex;
margin: 1em 1.5em;
+ dt {
+ flex: 0 0 auto;
+ font-weight: 500;
+ color: var(--lightText);
+ width: 30%;
+ min-width: 120px;
+ }
+
+ dd {
+ flex: 1 1 auto;
+ color: var(--text);
+ margin-left: 10px;
+ }
+
dt, dd {
+ line-height: 18px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
From 87940ead8a9bedd312f10635462933a02e0ffb1c Mon Sep 17 00:00:00 2001
From: kPherox
Date: Wed, 20 Nov 2019 18:59:37 +0900
Subject: [PATCH 005/129] Change css selectors to classname from elementname
---
src/components/user_profile/user_profile.vue | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue
index fdff0385f..c13374119 100644
--- a/src/components/user_profile/user_profile.vue
+++ b/src/components/user_profile/user_profile.vue
@@ -18,6 +18,7 @@
-
Date: Wed, 20 Nov 2019 19:18:19 +0900
Subject: [PATCH 006/129] Add tooltip
---
src/components/user_profile/user_profile.vue | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue
index c13374119..20a644092 100644
--- a/src/components/user_profile/user_profile.vue
+++ b/src/components/user_profile/user_profile.vue
@@ -22,11 +22,13 @@
>
-
Date: Wed, 20 Nov 2019 19:22:20 +0900
Subject: [PATCH 007/129] Use fields_html only
---
src/components/user_profile/user_profile.vue | 16 ----------------
1 file changed, 16 deletions(-)
diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue
index 20a644092..0268e5da3 100644
--- a/src/components/user_profile/user_profile.vue
+++ b/src/components/user_profile/user_profile.vue
@@ -36,22 +36,6 @@
-
-
- -
- {{ field.name }}
-
- -
- {{ field.value }}
-
-
-
Date: Wed, 20 Nov 2019 19:25:11 +0900
Subject: [PATCH 008/129] Change field name to right justify
---
src/components/user_profile/user_profile.vue | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue
index 0268e5da3..5bffba3ac 100644
--- a/src/components/user_profile/user_profile.vue
+++ b/src/components/user_profile/user_profile.vue
@@ -158,6 +158,7 @@
.user-profile-field-name {
flex: 0 0 auto;
font-weight: 500;
+ text-align: right;
color: var(--lightText);
width: 30%;
min-width: 120px;
From da55b0d4352d2daf4a8d9f4130d34546e9f01555 Mon Sep 17 00:00:00 2001
From: kPherox
Date: Wed, 19 Feb 2020 20:57:58 +0900
Subject: [PATCH 009/129] Add fields_text for tooltip
---
.../entity_normalizer/entity_normalizer.service.js | 6 ++++++
.../entity_normalizer/entity_normalizer.spec.js | 13 +++++++++++++
2 files changed, 19 insertions(+)
diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js
index ca79df6f6..ca2075a46 100644
--- a/src/services/entity_normalizer/entity_normalizer.service.js
+++ b/src/services/entity_normalizer/entity_normalizer.service.js
@@ -53,6 +53,12 @@ export const parseUser = (data) => {
value: addEmojis(field.value, data.emojis)
}
})
+ output.fields_text = data.fields.map(field => {
+ return {
+ name: field.name.replace(/<[^>]*>/g, ''),
+ value: field.value.replace(/<[^>]*>/g, '')
+ }
+ })
// Utilize avatar_static for gif avatars?
output.profile_image_url = data.avatar
diff --git a/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js b/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js
index cfb380baf..9df84575d 100644
--- a/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js
+++ b/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js
@@ -290,6 +290,19 @@ describe('API Entities normalizer', () => {
expect(field).to.have.property('value').that.contains('
{
+ const user = makeMockUserMasto({ emojis: makeMockEmojiMasto(), fields: [{ name: 'user', value: '@user' }] })
+
+ const parsedUser = parseUser(user)
+
+ expect(parsedUser).to.have.property('fields_text').to.be.an('array')
+
+ const field = parsedUser.fields_text[0]
+
+ expect(field).to.have.property('name').that.equal('user')
+ expect(field).to.have.property('value').that.equal('@user')
+ })
+
it('adds hide_follows and hide_followers user settings', () => {
const user = makeMockUserMasto({ pleroma: { hide_followers: true, hide_follows: false, hide_followers_count: false, hide_follows_count: true } })
From 064b59812c715d60526727d42c124375a2bc89d5 Mon Sep 17 00:00:00 2001
From: kPherox
Date: Wed, 19 Feb 2020 21:00:39 +0900
Subject: [PATCH 010/129] Change to use tags removed fields instead of raw
fields
---
src/components/user_profile/user_profile.vue | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue
index 5bffba3ac..54f2d4b3e 100644
--- a/src/components/user_profile/user_profile.vue
+++ b/src/components/user_profile/user_profile.vue
@@ -22,13 +22,13 @@
>
Date: Wed, 25 Mar 2020 20:06:48 +0300
Subject: [PATCH 011/129] after_store: Remove most of StatusNet config usage
Information under `pleromafe` key is equivalent to the one under
`pleroma_fe` key in `/api/pleroma/frontend_configurations`.
All other information had equivalents in `/nodeinfo/2.0.json`, except
`textlimit` and `vapidPublicKey`.
---
src/boot/after_store.js | 51 ++++++++++++++++++++++++++---------------
1 file changed, 33 insertions(+), 18 deletions(-)
diff --git a/src/boot/after_store.js b/src/boot/after_store.js
index d70e10584..b943ed95e 100644
--- a/src/boot/after_store.js
+++ b/src/boot/after_store.js
@@ -13,28 +13,13 @@ const getStatusnetConfig = async ({ store }) => {
const res = await window.fetch('/api/statusnet/config.json')
if (res.ok) {
const data = await res.json()
- const { name, closed: registrationClosed, textlimit, uploadlimit, server, vapidPublicKey, safeDMMentionsEnabled } = data.site
+ const { textlimit, vapidPublicKey } = data.site
- store.dispatch('setInstanceOption', { name: 'name', value: name })
- store.dispatch('setInstanceOption', { name: 'registrationOpen', value: (registrationClosed === '0') })
store.dispatch('setInstanceOption', { name: 'textlimit', value: parseInt(textlimit) })
- store.dispatch('setInstanceOption', { name: 'server', value: server })
- store.dispatch('setInstanceOption', { name: 'safeDM', value: safeDMMentionsEnabled !== '0' })
-
- // TODO: default values for this stuff, added if to not make it break on
- // my dev config out of the box.
- if (uploadlimit) {
- store.dispatch('setInstanceOption', { name: 'uploadlimit', value: parseInt(uploadlimit.uploadlimit) })
- store.dispatch('setInstanceOption', { name: 'avatarlimit', value: parseInt(uploadlimit.avatarlimit) })
- store.dispatch('setInstanceOption', { name: 'backgroundlimit', value: parseInt(uploadlimit.backgroundlimit) })
- store.dispatch('setInstanceOption', { name: 'bannerlimit', value: parseInt(uploadlimit.bannerlimit) })
- }
if (vapidPublicKey) {
store.dispatch('setInstanceOption', { name: 'vapidPublicKey', value: vapidPublicKey })
}
-
- return data.site.pleromafe
} else {
throw (res)
}
@@ -44,6 +29,21 @@ const getStatusnetConfig = async ({ store }) => {
}
}
+const getBackendProvidedConfig = async ({ store }) => {
+ try {
+ const res = await window.fetch('/api/pleroma/frontend_configurations')
+ if (res.ok) {
+ const data = await res.json()
+ return data.pleroma_fe
+ } else {
+ throw (res)
+ }
+ } catch (error) {
+ console.error('Could not load backend-provided frontend config, potentially fatal')
+ console.error(error)
+ }
+}
+
const getStaticConfig = async () => {
try {
const res = await window.fetch('/static/config.json')
@@ -200,13 +200,22 @@ const getNodeInfo = async ({ store }) => {
const data = await res.json()
const metadata = data.metadata
const features = metadata.features
+ store.dispatch('setInstanceOption', { name: 'name', value: metadata.nodeName })
+ 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: 'chatAvailable', value: features.includes('chat') })
store.dispatch('setInstanceOption', { name: 'gopherAvailable', value: features.includes('gopher') })
store.dispatch('setInstanceOption', { name: 'pollsAvailable', value: features.includes('polls') })
store.dispatch('setInstanceOption', { name: 'pollLimits', value: metadata.pollLimits })
store.dispatch('setInstanceOption', { name: 'mailerEnabled', value: metadata.mailerEnabled })
+ const uploadLimits = metadata.uploadLimits
+ store.dispatch('setInstanceOption', { name: 'uploadlimit', value: parseInt(uploadLimits.general) })
+ store.dispatch('setInstanceOption', { name: 'avatarlimit', value: parseInt(uploadLimits.avatar) })
+ store.dispatch('setInstanceOption', { name: 'backgroundlimit', value: parseInt(uploadLimits.background) })
+ store.dispatch('setInstanceOption', { name: 'bannerlimit', value: parseInt(uploadLimits.banner) })
+
store.dispatch('setInstanceOption', { name: 'restrictedNicknames', value: metadata.restrictedNicknames })
store.dispatch('setInstanceOption', { name: 'postFormats', value: metadata.postFormats })
@@ -254,7 +263,7 @@ const getNodeInfo = async ({ store }) => {
const setConfig = async ({ store }) => {
// apiConfig, staticConfig
- const configInfos = await Promise.all([getStatusnetConfig({ store }), getStaticConfig()])
+ const configInfos = await Promise.all([getBackendProvidedConfig({ store }), getStaticConfig()])
const apiConfig = configInfos[0]
const staticConfig = configInfos[1]
@@ -277,6 +286,11 @@ const checkOAuthToken = async ({ store }) => {
const afterStoreSetup = async ({ store, i18n }) => {
const width = windowWidth()
store.dispatch('setMobileLayout', width <= 800)
+
+ const overrides = window.___pleromafe_dev_overrides || {}
+ const server = (typeof overrides.target !== 'undefined') ? overrides.target : window.location.origin
+ store.dispatch('setInstanceOption', { name: 'server', value: server })
+
await setConfig({ store })
const { customTheme, customThemeSource } = store.state.config
@@ -301,7 +315,8 @@ const afterStoreSetup = async ({ store, i18n }) => {
getTOS({ store }),
getInstancePanel({ store }),
getStickers({ store }),
- getNodeInfo({ store })
+ getNodeInfo({ store }),
+ getStatusnetConfig({ store })
])
const router = new VueRouter({
From 54fdc220017122c8e30e0fb16f0dd2534fc60947 Mon Sep 17 00:00:00 2001
From: kPherox
Date: Wed, 10 Jun 2020 03:24:55 +0900
Subject: [PATCH 012/129] Add profile fields form
---
src/boot/after_store.js | 2 +
.../settings_modal/tabs/profile_tab.js | 21 +++++++++
.../settings_modal/tabs/profile_tab.scss | 17 +++++++
.../settings_modal/tabs/profile_tab.vue | 46 +++++++++++++++++++
4 files changed, 86 insertions(+)
diff --git a/src/boot/after_store.js b/src/boot/after_store.js
index 0db035475..87c92a8a7 100644
--- a/src/boot/after_store.js
+++ b/src/boot/after_store.js
@@ -207,6 +207,8 @@ const getNodeInfo = async ({ store }) => {
store.dispatch('setInstanceOption', { name: 'pollLimits', value: metadata.pollLimits })
store.dispatch('setInstanceOption', { name: 'mailerEnabled', value: metadata.mailerEnabled })
+ store.dispatch('setInstanceOption', { name: 'fieldsLimits', value: metadata.fieldsLimits })
+
store.dispatch('setInstanceOption', { name: 'restrictedNicknames', value: metadata.restrictedNicknames })
store.dispatch('setInstanceOption', { name: 'postFormats', value: metadata.postFormats })
diff --git a/src/components/settings_modal/tabs/profile_tab.js b/src/components/settings_modal/tabs/profile_tab.js
index 8658b0977..896ff5081 100644
--- a/src/components/settings_modal/tabs/profile_tab.js
+++ b/src/components/settings_modal/tabs/profile_tab.js
@@ -1,4 +1,5 @@
import unescape from 'lodash/unescape'
+import merge from 'lodash/merge'
import ImageCropper from 'src/components/image_cropper/image_cropper.vue'
import ScopeSelector from 'src/components/scope_selector/scope_selector.vue'
import fileSizeFormatService from 'src/components/../services/file_size_format/file_size_format.js'
@@ -16,6 +17,7 @@ const ProfileTab = {
newLocked: this.$store.state.users.currentUser.locked,
newNoRichText: this.$store.state.users.currentUser.no_rich_text,
newDefaultScope: this.$store.state.users.currentUser.default_scope,
+ newFields: this.$store.state.users.currentUser.fields.map(field => ({ name: field.name, value: field.value })),
hideFollows: this.$store.state.users.currentUser.hide_follows,
hideFollowers: this.$store.state.users.currentUser.hide_followers,
hideFollowsCount: this.$store.state.users.currentUser.hide_follows_count,
@@ -62,6 +64,12 @@ const ProfileTab = {
...this.$store.state.instance.emoji,
...this.$store.state.instance.customEmoji
] })
+ },
+ fieldsLimits () {
+ return this.$store.state.instance.fieldsLimits
+ },
+ maxFields () {
+ return this.fieldsLimits ? this.fieldsLimits.maxFields : 0
}
},
methods: {
@@ -74,6 +82,7 @@ const ProfileTab = {
// Backend notation.
/* eslint-disable camelcase */
display_name: this.newName,
+ fields_attributes: this.newFields.filter(el => el != null),
default_scope: this.newDefaultScope,
no_rich_text: this.newNoRichText,
hide_follows: this.hideFollows,
@@ -85,6 +94,8 @@ const ProfileTab = {
show_role: this.showRole
/* eslint-enable camelcase */
} }).then((user) => {
+ this.newFields.splice(user.fields.length)
+ merge(this.newFields, user.fields)
this.$store.commit('addNewUsers', [user])
this.$store.commit('setCurrentUser', user)
})
@@ -92,6 +103,16 @@ const ProfileTab = {
changeVis (visibility) {
this.newDefaultScope = visibility
},
+ addField () {
+ if (this.newFields.length < this.maxFields) {
+ this.newFields.push({ name: '', value: '' })
+ return true
+ }
+ return false
+ },
+ deleteField (index, event) {
+ this.$delete(this.newFields, index)
+ },
uploadFile (slot, e) {
const file = e.target.files[0]
if (!file) { return }
diff --git a/src/components/settings_modal/tabs/profile_tab.scss b/src/components/settings_modal/tabs/profile_tab.scss
index 4aab81eb7..b3dcf42c8 100644
--- a/src/components/settings_modal/tabs/profile_tab.scss
+++ b/src/components/settings_modal/tabs/profile_tab.scss
@@ -79,4 +79,21 @@
.setting-subitem {
margin-left: 1.75em;
}
+
+ .profile-fields {
+ display: flex;
+
+ &>.emoji-input {
+ flex: 1 1 auto;
+ margin: 0 .2em .5em;
+ }
+
+ &>.icon-container {
+ width: 20px;
+
+ &>.icon-cancel {
+ vertical-align: sub;
+ }
+ }
+ }
}
diff --git a/src/components/settings_modal/tabs/profile_tab.vue b/src/components/settings_modal/tabs/profile_tab.vue
index fff4f970c..2fa3021e6 100644
--- a/src/components/settings_modal/tabs/profile_tab.vue
+++ b/src/components/settings_modal/tabs/profile_tab.vue
@@ -95,6 +95,52 @@
{{ $t('settings.discoverable') }}
+
+
+
{{ $t("nav.dms") }}
+
+
+ {{ $t("nav.bookmarks") }}
+
+
{{ $t("nav.friend_requests") }}
diff --git a/src/components/side_drawer/side_drawer.vue b/src/components/side_drawer/side_drawer.vue
index f253742d1..0ac53b347 100644
--- a/src/components/side_drawer/side_drawer.vue
+++ b/src/components/side_drawer/side_drawer.vue
@@ -65,6 +65,14 @@
{{ $t("nav.timeline") }}
+
+
+ {{ $t("nav.bookmarks") }}
+
+
{
+ }).then(({ statuses }) => {
store.commit('setLoading', { timeline: this.timelineName, value: false })
if (statuses && statuses.length === 0) {
this.bottomedOut = true
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 59f69e576..2e48c4738 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -120,6 +120,7 @@
"public_tl": "Public Timeline",
"timeline": "Timeline",
"twkn": "The Whole Known Network",
+ "bookmarks": "Bookmarks",
"user_search": "User Search",
"search": "Search",
"who_to_follow": "Who to follow",
@@ -629,6 +630,8 @@
"pin": "Pin on profile",
"unpin": "Unpin from profile",
"pinned": "Pinned",
+ "bookmark": "Bookmark",
+ "unbookmark": "Unbookmark",
"delete_confirm": "Do you really want to delete this status?",
"reply_to": "Reply to",
"replies_list": "Replies:",
@@ -724,7 +727,8 @@
"add_reaction": "Add Reaction",
"user_settings": "User Settings",
"accept_follow_request": "Accept follow request",
- "reject_follow_request": "Reject follow request"
+ "reject_follow_request": "Reject follow request",
+ "bookmark": "Bookmark"
},
"upload": {
"error": {
diff --git a/src/i18n/ru.json b/src/i18n/ru.json
index aa78db26e..08f05d18e 100644
--- a/src/i18n/ru.json
+++ b/src/i18n/ru.json
@@ -45,7 +45,8 @@
"timeline": "Лента",
"twkn": "Федеративная лента",
"search": "Поиск",
- "friend_requests": "Запросы на чтение"
+ "friend_requests": "Запросы на чтение",
+ "bookmarks": "Закладки"
},
"notifications": {
"broken_favorite": "Неизвестный статус, ищем...",
@@ -366,6 +367,10 @@
"show_new": "Показать новые",
"up_to_date": "Обновлено"
},
+ "status": {
+ "bookmark": "В закладки",
+ "unbookmark": "Удалить из закладок"
+ },
"user_card": {
"block": "Заблокировать",
"blocked": "Заблокирован",
diff --git a/src/modules/statuses.js b/src/modules/statuses.js
index 4d3f80314..7fbf685cf 100644
--- a/src/modules/statuses.js
+++ b/src/modules/statuses.js
@@ -62,7 +62,8 @@ export const defaultState = () => ({
publicAndExternal: emptyTl(),
friends: emptyTl(),
tag: emptyTl(),
- dms: emptyTl()
+ dms: emptyTl(),
+ bookmarks: emptyTl()
}
})
@@ -163,8 +164,7 @@ const removeStatusFromGlobalStorage = (state, status) => {
}
}
-const addNewStatuses = (state, { statuses, showImmediately = false, timeline, user = {},
- noIdUpdate = false, userId }) => {
+const addNewStatuses = (state, { statuses, showImmediately = false, timeline, user = {}, noIdUpdate = false, userId, pagination = {} }) => {
// Sanity check
if (!isArray(statuses)) {
return false
@@ -173,8 +173,13 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us
const allStatuses = state.allStatuses
const timelineObject = state.timelines[timeline]
- const maxNew = statuses.length > 0 ? maxBy(statuses, 'id').id : 0
- const minNew = statuses.length > 0 ? minBy(statuses, 'id').id : 0
+ // Mismatch between API pagination and our internal minId/maxId tracking systems:
+ // pagination.maxId is the oldest of the returned statuses when fetching older,
+ // and pagination.minId is the newest when fetching newer. The names come directly
+ // from the arguments they're supposed to be passed as for the next fetch.
+ const minNew = pagination.maxId || (statuses.length > 0 ? minBy(statuses, 'id').id : 0)
+ const maxNew = pagination.minId || (statuses.length > 0 ? maxBy(statuses, 'id').id : 0)
+
const newer = timeline && (maxNew > timelineObject.maxId || timelineObject.maxId === 0) && statuses.length > 0
const older = timeline && (minNew < timelineObject.minId || timelineObject.minId === 0) && statuses.length > 0
@@ -315,7 +320,7 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us
})
// Keep the visible statuses sorted
- if (timeline) {
+ if (timeline && !(timeline === 'bookmarks')) {
sortTimeline(timelineObject)
}
}
@@ -463,6 +468,14 @@ export const mutations = {
newStatus.rebloggedBy.push(user)
}
},
+ setBookmarked (state, { status, value }) {
+ const newStatus = state.allStatusesObject[status.id]
+ newStatus.bookmarked = value
+ },
+ setBookmarkedConfirm (state, { status }) {
+ const newStatus = state.allStatusesObject[status.id]
+ newStatus.bookmarked = status.bookmarked
+ },
setDeleted (state, { status }) {
const newStatus = state.allStatusesObject[status.id]
newStatus.deleted = true
@@ -590,8 +603,8 @@ export const mutations = {
const statuses = {
state: defaultState(),
actions: {
- addNewStatuses ({ rootState, commit }, { statuses, showImmediately = false, timeline = false, noIdUpdate = false, userId }) {
- commit('addNewStatuses', { statuses, showImmediately, timeline, noIdUpdate, user: rootState.users.currentUser, userId })
+ addNewStatuses ({ rootState, commit }, { statuses, showImmediately = false, timeline = false, noIdUpdate = false, userId, pagination }) {
+ commit('addNewStatuses', { statuses, showImmediately, timeline, noIdUpdate, user: rootState.users.currentUser, userId, pagination })
},
addNewNotifications ({ rootState, commit, dispatch, rootGetters }, { notifications, older }) {
commit('addNewNotifications', { visibleNotificationTypes: visibleNotificationTypes(rootState), dispatch, notifications, older, rootGetters })
@@ -666,6 +679,20 @@ const statuses = {
rootState.api.backendInteractor.unretweet({ id: status.id })
.then(status => commit('setRetweetedConfirm', { status, user: rootState.users.currentUser }))
},
+ bookmark ({ rootState, commit }, status) {
+ commit('setBookmarked', { status, value: true })
+ rootState.api.backendInteractor.bookmarkStatus({ id: status.id })
+ .then(status => {
+ commit('setBookmarkedConfirm', { status })
+ })
+ },
+ unbookmark ({ rootState, commit }, status) {
+ commit('setBookmarked', { status, value: false })
+ rootState.api.backendInteractor.unbookmarkStatus({ id: status.id })
+ .then(status => {
+ commit('setBookmarkedConfirm', { status })
+ })
+ },
queueFlush ({ rootState, commit }, { timeline, id }) {
commit('queueFlush', { timeline, id })
},
diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js
index 7e5e9645e..c9ec88b76 100644
--- a/src/services/api/api.service.js
+++ b/src/services/api/api.service.js
@@ -1,5 +1,5 @@
import { each, map, concat, last, get } from 'lodash'
-import { parseStatus, parseUser, parseNotification, parseAttachment } from '../entity_normalizer/entity_normalizer.service.js'
+import { parseStatus, parseUser, parseNotification, parseAttachment, parseLinkHeaderPagination } from '../entity_normalizer/entity_normalizer.service.js'
import { RegistrationError, StatusCodeError } from '../errors/errors'
/* eslint-env browser */
@@ -50,6 +50,7 @@ const MASTODON_USER_URL = '/api/v1/accounts'
const MASTODON_USER_RELATIONSHIPS_URL = '/api/v1/accounts/relationships'
const MASTODON_USER_TIMELINE_URL = id => `/api/v1/accounts/${id}/statuses`
const MASTODON_TAG_TIMELINE_URL = tag => `/api/v1/timelines/tag/${tag}`
+const MASTODON_BOOKMARK_TIMELINE_URL = '/api/v1/bookmarks'
const MASTODON_USER_BLOCKS_URL = '/api/v1/blocks/'
const MASTODON_USER_MUTES_URL = '/api/v1/mutes/'
const MASTODON_BLOCK_USER_URL = id => `/api/v1/accounts/${id}/block`
@@ -58,6 +59,8 @@ const MASTODON_MUTE_USER_URL = id => `/api/v1/accounts/${id}/mute`
const MASTODON_UNMUTE_USER_URL = id => `/api/v1/accounts/${id}/unmute`
const MASTODON_SUBSCRIBE_USER = id => `/api/v1/pleroma/accounts/${id}/subscribe`
const MASTODON_UNSUBSCRIBE_USER = id => `/api/v1/pleroma/accounts/${id}/unsubscribe`
+const MASTODON_BOOKMARK_STATUS_URL = id => `/api/v1/statuses/${id}/bookmark`
+const MASTODON_UNBOOKMARK_STATUS_URL = id => `/api/v1/statuses/${id}/unbookmark`
const MASTODON_POST_STATUS_URL = '/api/v1/statuses'
const MASTODON_MEDIA_UPLOAD_URL = '/api/v1/media'
const MASTODON_VOTE_URL = id => `/api/v1/polls/${id}/votes`
@@ -510,7 +513,8 @@ const fetchTimeline = ({
user: MASTODON_USER_TIMELINE_URL,
media: MASTODON_USER_TIMELINE_URL,
favorites: MASTODON_USER_FAVORITES_TIMELINE_URL,
- tag: MASTODON_TAG_TIMELINE_URL
+ tag: MASTODON_TAG_TIMELINE_URL,
+ bookmarks: MASTODON_BOOKMARK_TIMELINE_URL
}
const isNotifications = timeline === 'notifications'
const params = []
@@ -539,7 +543,7 @@ const fetchTimeline = ({
if (timeline === 'public' || timeline === 'publicAndExternal') {
params.push(['only_media', false])
}
- if (timeline !== 'favorites') {
+ if (timeline !== 'favorites' && timeline !== 'bookmarks') {
params.push(['with_muted', withMuted])
}
if (replyVisibility !== 'all') {
@@ -552,16 +556,20 @@ const fetchTimeline = ({
url += `?${queryString}`
let status = ''
let statusText = ''
+ let pagination = {}
return fetch(url, { headers: authHeaders(credentials) })
.then((data) => {
status = data.status
statusText = data.statusText
+ pagination = parseLinkHeaderPagination(data.headers.get('Link'), {
+ flakeId: timeline !== 'bookmarks' && timeline !== 'notifications'
+ })
return data
})
.then((data) => data.json())
.then((data) => {
if (!data.error) {
- return data.map(isNotifications ? parseNotification : parseStatus)
+ return { data: data.map(isNotifications ? parseNotification : parseStatus), pagination }
} else {
data.status = status
data.statusText = statusText
@@ -612,6 +620,22 @@ const unretweet = ({ id, credentials }) => {
.then((data) => parseStatus(data))
}
+const bookmarkStatus = ({ id, credentials }) => {
+ return promisedRequest({
+ url: MASTODON_BOOKMARK_STATUS_URL(id),
+ headers: authHeaders(credentials),
+ method: 'POST'
+ })
+}
+
+const unbookmarkStatus = ({ id, credentials }) => {
+ return promisedRequest({
+ url: MASTODON_UNBOOKMARK_STATUS_URL(id),
+ headers: authHeaders(credentials),
+ method: 'POST'
+ })
+}
+
const postStatus = ({
credentials,
status,
@@ -1150,6 +1174,8 @@ const apiService = {
unfavorite,
retweet,
unretweet,
+ bookmarkStatus,
+ unbookmarkStatus,
postStatus,
deleteStatus,
uploadMedia,
diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js
index 3bdb92f3f..0d27dc972 100644
--- a/src/services/entity_normalizer/entity_normalizer.service.js
+++ b/src/services/entity_normalizer/entity_normalizer.service.js
@@ -1,4 +1,5 @@
import escape from 'escape-html'
+import parseLinkHeader from 'parse-link-header'
import { isStatusNotification } from '../notification_utils/notification_utils.js'
const qvitterStatusType = (status) => {
@@ -232,6 +233,8 @@ export const parseStatus = (data) => {
output.repeated = data.reblogged
output.repeat_num = data.reblogs_count
+ output.bookmarked = data.bookmarked
+
output.type = data.reblog ? 'retweet' : 'status'
output.nsfw = data.sensitive
@@ -381,3 +384,16 @@ const isNsfw = (status) => {
const nsfwRegex = /#nsfw/i
return (status.tags || []).includes('nsfw') || !!(status.text || '').match(nsfwRegex)
}
+
+export const parseLinkHeaderPagination = (linkHeader, opts = {}) => {
+ const flakeId = opts.flakeId
+ const parsedLinkHeader = parseLinkHeader(linkHeader)
+ if (!parsedLinkHeader) return
+ const maxId = parsedLinkHeader.next.max_id
+ const minId = parsedLinkHeader.prev.min_id
+
+ return {
+ maxId: flakeId ? maxId : parseInt(maxId, 10),
+ minId: flakeId ? minId : parseInt(minId, 10)
+ }
+}
diff --git a/src/services/notifications_fetcher/notifications_fetcher.service.js b/src/services/notifications_fetcher/notifications_fetcher.service.js
index 64499a1b6..4644e4493 100644
--- a/src/services/notifications_fetcher/notifications_fetcher.service.js
+++ b/src/services/notifications_fetcher/notifications_fetcher.service.js
@@ -41,7 +41,7 @@ const fetchAndUpdate = ({ store, credentials, older = false }) => {
const fetchNotifications = ({ store, args, older }) => {
return apiService.fetchTimeline(args)
- .then((notifications) => {
+ .then(({ data: notifications }) => {
update({ store, notifications, older })
return notifications
}, () => store.dispatch('setNotificationsError', { value: true }))
diff --git a/src/services/timeline_fetcher/timeline_fetcher.service.js b/src/services/timeline_fetcher/timeline_fetcher.service.js
index 30fb26bdc..214294eb5 100644
--- a/src/services/timeline_fetcher/timeline_fetcher.service.js
+++ b/src/services/timeline_fetcher/timeline_fetcher.service.js
@@ -2,7 +2,7 @@ import { camelCase } from 'lodash'
import apiService from '../api/api.service.js'
-const update = ({ store, statuses, timeline, showImmediately, userId }) => {
+const update = ({ store, statuses, timeline, showImmediately, userId, pagination }) => {
const ccTimeline = camelCase(timeline)
store.dispatch('setError', { value: false })
@@ -12,7 +12,8 @@ const update = ({ store, statuses, timeline, showImmediately, userId }) => {
timeline: ccTimeline,
userId,
statuses,
- showImmediately
+ showImmediately,
+ pagination
})
}
@@ -47,16 +48,18 @@ const fetchAndUpdate = ({
const numStatusesBeforeFetch = timelineData.statuses.length
return apiService.fetchTimeline(args)
- .then((statuses) => {
- if (statuses.error) {
- store.dispatch('setErrorData', { value: statuses })
+ .then(response => {
+ if (response.error) {
+ store.dispatch('setErrorData', { value: response })
return
}
+
+ const { data: statuses, pagination } = response
if (!older && statuses.length >= 20 && !timelineData.loading && numStatusesBeforeFetch > 0) {
store.dispatch('queueFlush', { timeline: timeline, id: timelineData.maxId })
}
- update({ store, statuses, timeline, showImmediately, userId })
- return statuses
+ update({ store, statuses, timeline, showImmediately, userId, pagination })
+ return { statuses, pagination }
}, () => store.dispatch('setError', { value: true }))
}
diff --git a/static/fontello.json b/static/fontello.json
old mode 100755
new mode 100644
index ac3f0a18c..6083c0bfa
--- a/static/fontello.json
+++ b/static/fontello.json
@@ -375,6 +375,18 @@
"css": "download",
"code": 59429,
"src": "fontawesome"
+ },
+ {
+ "uid": "f04a5d24e9e659145b966739c4fde82a",
+ "css": "bookmark",
+ "code": 59430,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "2f5ef6f6b7aaebc56458ab4e865beff5",
+ "css": "bookmark-empty",
+ "code": 61591,
+ "src": "fontawesome"
}
]
}
\ No newline at end of file
diff --git a/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js b/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js
index ccb57942c..e1f7a958f 100644
--- a/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js
+++ b/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js
@@ -1,4 +1,4 @@
-import { parseStatus, parseUser, parseNotification, addEmojis } from '../../../../../src/services/entity_normalizer/entity_normalizer.service.js'
+import { parseStatus, parseUser, parseNotification, addEmojis, parseLinkHeaderPagination } from '../../../../../src/services/entity_normalizer/entity_normalizer.service.js'
import mastoapidata from '../../../../fixtures/mastoapi.json'
import qvitterapidata from '../../../../fixtures/statuses.json'
@@ -383,4 +383,24 @@ describe('API Entities normalizer', () => {
expect(result).to.include('title=\':[a-z] {|}*:\'')
})
})
+
+ describe('Link header pagination', () => {
+ it('Parses min and max ids as integers', () => {
+ const linkHeader = '; rel="next", ; rel="prev"'
+ const result = parseLinkHeaderPagination(linkHeader)
+ expect(result).to.eql({
+ 'maxId': 861676,
+ 'minId': 861741
+ })
+ })
+
+ it('Parses min and max ids as flakes', () => {
+ const linkHeader = '; rel="next", ; rel="prev"'
+ const result = parseLinkHeaderPagination(linkHeader, { flakeId: true })
+ expect(result).to.eql({
+ 'maxId': '9waQx5IIS48qVue2Ai',
+ 'minId': '9wi61nIPnfn674xgie'
+ })
+ })
+ })
})
diff --git a/yarn.lock b/yarn.lock
index f05b00b15..093168631 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5751,6 +5751,13 @@ parse-json@^4.0.0:
error-ex "^1.3.1"
json-parse-better-errors "^1.0.1"
+parse-link-header@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/parse-link-header/-/parse-link-header-1.0.1.tgz#bedfe0d2118aeb84be75e7b025419ec8a61140a7"
+ integrity sha1-vt/g0hGK64S+deewJUGeyKYRQKc=
+ dependencies:
+ xtend "~4.0.1"
+
parseqs@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d"
From 9b40cf43d80f61d2afdaed757e4f873bf2dfd0a4 Mon Sep 17 00:00:00 2001
From: kPherox
Date: Sat, 4 Jul 2020 18:42:15 +0900
Subject: [PATCH 107/129] fix height for emoji panel of settings modal
---
src/components/settings_modal/settings_modal.scss | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/settings_modal/settings_modal.scss b/src/components/settings_modal/settings_modal.scss
index 833ff89a5..0da4d9a85 100644
--- a/src/components/settings_modal/settings_modal.scss
+++ b/src/components/settings_modal/settings_modal.scss
@@ -30,7 +30,7 @@
height: 100vh;
}
- .panel-body {
+ >.panel-body {
height: 100%;
overflow-y: hidden;
From 9178908c1ea8d0ad99b4a631abb9594edc3765bf Mon Sep 17 00:00:00 2001
From: Shpuld Shpludson
Date: Sun, 5 Jul 2020 06:54:12 +0000
Subject: [PATCH 108/129] Apply suggestion to
src/components/notifications/notifications.js
---
src/components/notifications/notifications.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js
index 30187072d..d8a327b05 100644
--- a/src/components/notifications/notifications.js
+++ b/src/components/notifications/notifications.js
@@ -30,7 +30,7 @@ const Notifications = {
created () {
const store = this.$store
const credentials = store.state.users.currentUser.credentials
- notificationsFetcher.fetchAndUpdate({ store: this.$store, credentials })
+ notificationsFetcher.fetchAndUpdate({ store, credentials })
},
computed: {
mainClass () {
From f254a847d2fa7e57c3686a3b51fef234fcf253bd Mon Sep 17 00:00:00 2001
From: Shpuld Shpuldson
Date: Mon, 6 Jul 2020 10:53:03 +0300
Subject: [PATCH 109/129] move translation strings to correct place, translate
error message
---
src/components/post_status_form/post_status_form.js | 4 ++--
src/components/post_status_form/post_status_form.vue | 2 +-
src/i18n/en.json | 5 +++--
3 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js
index 1bf5dae3e..186612354 100644
--- a/src/components/post_status_form/post_status_form.js
+++ b/src/components/post_status_form/post_status_form.js
@@ -192,7 +192,7 @@ const PostStatusForm = {
if (this.posting) { return }
if (this.submitDisabled) { return }
if (this.emptyStatus) {
- this.error = 'Cannot post an empty status with no files'
+ this.error = this.$t('post_status.empty_status_error')
return
}
@@ -240,7 +240,7 @@ const PostStatusForm = {
},
previewStatus () {
if (this.emptyStatus && this.newStatus.spoilerText.trim() === '') {
- this.preview = { error: this.$t('status.preview_empty') }
+ this.preview = { error: this.$t('post_status.preview_empty') }
this.previewLoading = false
return
}
diff --git a/src/components/post_status_form/post_status_form.vue b/src/components/post_status_form/post_status_form.vue
index 0cebd36ef..94729f75b 100644
--- a/src/components/post_status_form/post_status_form.vue
+++ b/src/components/post_status_form/post_status_form.vue
@@ -21,7 +21,7 @@
class="preview-toggle faint"
@click.stop.prevent="togglePreview"
>
- {{ $t('status.preview') }}
+ {{ $t('post_status.preview') }}
Date: Mon, 6 Jul 2020 11:12:33 +0300
Subject: [PATCH 110/129] remove contenttype check from content type watcher
---
src/components/post_status_form/post_status_form.js | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js
index 186612354..3d731ae4e 100644
--- a/src/components/post_status_form/post_status_form.js
+++ b/src/components/post_status_form/post_status_form.js
@@ -176,12 +176,8 @@ const PostStatusForm = {
...mapGetters(['mergedConfig'])
},
watch: {
- 'newStatus.contentType': function (newType) {
- if (newType === 'text/plain') {
- this.closePreview()
- } else if (this.preview) {
- this.previewStatus(this.newStatus)
- }
+ 'newStatus.contentType': function () {
+ this.autoPreview()
},
'newStatus.spoilerText': function () {
this.autoPreview()
From ada5a3806b3c36ad67d3a76f41bc1a9f18445759 Mon Sep 17 00:00:00 2001
From: Shpuld Shpuldson
Date: Mon, 6 Jul 2020 11:36:35 +0300
Subject: [PATCH 111/129] don't close preview on post, move visibility notices
above the preview where they belong
---
.../post_status_form/post_status_form.js | 2 +-
.../post_status_form/post_status_form.vue | 76 +++++++++----------
2 files changed, 39 insertions(+), 39 deletions(-)
diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js
index 3d731ae4e..daadc10f5 100644
--- a/src/components/post_status_form/post_status_form.js
+++ b/src/components/post_status_form/post_status_form.js
@@ -227,7 +227,7 @@ const PostStatusForm = {
el.style.height = 'auto'
el.style.height = undefined
this.error = null
- this.closePreview()
+ this.previewStatus()
} else {
this.error = data.error
}
diff --git a/src/components/post_status_form/post_status_form.vue b/src/components/post_status_form/post_status_form.vue
index 94729f75b..60dc4a21d 100644
--- a/src/components/post_status_form/post_status_form.vue
+++ b/src/components/post_status_form/post_status_form.vue
@@ -16,44 +16,6 @@
@drop.stop="fileDrop"
/>
From 84d728b9708fbb64f20de1f65f9bb1af7f426d59 Mon Sep 17 00:00:00 2001
From: Shpuld Shpuldson
Date: Tue, 7 Jul 2020 11:31:24 +0300
Subject: [PATCH 116/129] fix issue on posting another status
---
src/components/post_status_form/post_status_form.js | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js
index 48c3615dd..18f02eba3 100644
--- a/src/components/post_status_form/post_status_form.js
+++ b/src/components/post_status_form/post_status_form.js
@@ -230,7 +230,8 @@ const PostStatusForm = {
files: [],
visibility: newStatus.visibility,
contentType: newStatus.contentType,
- poll: {}
+ poll: {},
+ mediaDescriptions: {}
}
this.pollFormVisible = false
this.$refs.mediaUpload.clearFile()
@@ -240,7 +241,7 @@ const PostStatusForm = {
el.style.height = 'auto'
el.style.height = undefined
this.error = null
- this.previewStatus()
+ if (this.preview) this.previewStatus()
} else {
this.error = data.error
}
From 97c62587d06d3bf657973e4c2d8fce2fb9707d85 Mon Sep 17 00:00:00 2001
From: Shpuld Shpuldson
Date: Tue, 7 Jul 2020 11:34:40 +0300
Subject: [PATCH 117/129] remove console log
---
src/components/status_content/status_content.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/components/status_content/status_content.js b/src/components/status_content/status_content.js
index 2b9ea50cb..67d9bd3ca 100644
--- a/src/components/status_content/status_content.js
+++ b/src/components/status_content/status_content.js
@@ -100,7 +100,6 @@ const StatusContent = {
)
},
attachmentTypes () {
- console.log(this.status.attachments)
return this.status.attachments.map(file => fileType.fileType(file.mimetype))
},
maxThumbnails () {
From 1f97f36e1ccded9a1cab1e777427cfea0cff4964 Mon Sep 17 00:00:00 2001
From: lain
Date: Tue, 7 Jul 2020 13:17:25 +0200
Subject: [PATCH 118/129] After Store: Correctly handle preloaded HTML
---
src/boot/after_store.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/boot/after_store.js b/src/boot/after_store.js
index 1796eb1be..d9f2da786 100644
--- a/src/boot/after_store.js
+++ b/src/boot/after_store.js
@@ -29,7 +29,7 @@ const preloadFetch = async (request) => {
return {
ok: true,
json: () => JSON.parse(requestData),
- text: () => requestData
+ text: () => JSON.parse(requestData)
}
}
From f7f8181dcf5d2a699c0d870bd8873cbe7784a6af Mon Sep 17 00:00:00 2001
From: Shpuld Shpuldson
Date: Tue, 7 Jul 2020 14:46:53 +0300
Subject: [PATCH 119/129] fix preview opening automatically
---
src/components/post_status_form/post_status_form.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js
index daadc10f5..62e0d7e45 100644
--- a/src/components/post_status_form/post_status_form.js
+++ b/src/components/post_status_form/post_status_form.js
@@ -227,7 +227,7 @@ const PostStatusForm = {
el.style.height = 'auto'
el.style.height = undefined
this.error = null
- this.previewStatus()
+ if (this.preview) this.previewStatus()
} else {
this.error = data.error
}
From 7c9ba8995ca49c0fa4eb987467bc1aab13fc67f3 Mon Sep 17 00:00:00 2001
From: lain
Date: Tue, 7 Jul 2020 11:47:01 +0000
Subject: [PATCH 120/129] Apply suggestion to src/boot/after_store.js
---
src/boot/after_store.js | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/boot/after_store.js b/src/boot/after_store.js
index d9f2da786..47524112a 100644
--- a/src/boot/after_store.js
+++ b/src/boot/after_store.js
@@ -25,11 +25,11 @@ const preloadFetch = async (request) => {
if (!data || !data[request]) {
return window.fetch(request)
}
- const requestData = atob(data[request])
+ const requestData = JSON.parse(atob(data[request]))
return {
ok: true,
- json: () => JSON.parse(requestData),
- text: () => JSON.parse(requestData)
+ json: () => requestData,
+ text: () => requestData
}
}
From 431b3f527deb318b723e3d2a41f560b970697dff Mon Sep 17 00:00:00 2001
From: lain
Date: Tue, 7 Jul 2020 14:39:43 +0200
Subject: [PATCH 121/129] StaffPanel: Move staff loading to panel creation.
---
src/boot/after_store.js | 1 -
src/components/staff_panel/staff_panel.js | 4 ++++
src/modules/users.js | 5 +++++
3 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/src/boot/after_store.js b/src/boot/after_store.js
index 47524112a..302b278c5 100644
--- a/src/boot/after_store.js
+++ b/src/boot/after_store.js
@@ -215,7 +215,6 @@ const getAppSecret = async ({ store }) => {
const resolveStaffAccounts = ({ store, accounts }) => {
const nicknames = accounts.map(uri => uri.split('/').pop())
- nicknames.map(nickname => store.dispatch('fetchUser', nickname))
store.dispatch('setInstanceOption', { name: 'staffAccounts', value: nicknames })
}
diff --git a/src/components/staff_panel/staff_panel.js b/src/components/staff_panel/staff_panel.js
index 4f98fff61..8c2abcd8d 100644
--- a/src/components/staff_panel/staff_panel.js
+++ b/src/components/staff_panel/staff_panel.js
@@ -2,6 +2,10 @@ import map from 'lodash/map'
import BasicUserCard from '../basic_user_card/basic_user_card.vue'
const StaffPanel = {
+ created() {
+ const nicknames = this.$store.state.instance.staffAccounts
+ nicknames.forEach(nickname => this.$store.dispatch('fetchUserIfMissing', nickname))
+ },
components: {
BasicUserCard
},
diff --git a/src/modules/users.js b/src/modules/users.js
index 68d029315..7e136c612 100644
--- a/src/modules/users.js
+++ b/src/modules/users.js
@@ -266,6 +266,11 @@ const users = {
mutations,
getters,
actions: {
+ fetchUserIfMissing (store, id) {
+ if (!store.getters.findUser(id)) {
+ store.dispatch('fetchUser', id)
+ }
+ },
fetchUser (store, id) {
return store.rootState.api.backendInteractor.fetchUser({ id })
.then((user) => {
From 7d881d97fe7ac96ecfa58b18a87b5d9379858b4c Mon Sep 17 00:00:00 2001
From: Shpuld Shpludson
Date: Tue, 7 Jul 2020 12:44:29 +0000
Subject: [PATCH 122/129] Apply suggestion to
src/components/staff_panel/staff_panel.js
---
src/components/staff_panel/staff_panel.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/staff_panel/staff_panel.js b/src/components/staff_panel/staff_panel.js
index 8c2abcd8d..8665648a5 100644
--- a/src/components/staff_panel/staff_panel.js
+++ b/src/components/staff_panel/staff_panel.js
@@ -2,7 +2,7 @@ import map from 'lodash/map'
import BasicUserCard from '../basic_user_card/basic_user_card.vue'
const StaffPanel = {
- created() {
+ created () {
const nicknames = this.$store.state.instance.staffAccounts
nicknames.forEach(nickname => this.$store.dispatch('fetchUserIfMissing', nickname))
},
From e9be206a65564243e0196da5cb0a9cd33e4c01c7 Mon Sep 17 00:00:00 2001
From: Ben Is
Date: Tue, 7 Jul 2020 00:43:21 +0000
Subject: [PATCH 123/129] Translated using Weblate (Finnish)
Currently translated at 95.4% (610 of 639 strings)
Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/fi/
---
src/i18n/fi.json | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/src/i18n/fi.json b/src/i18n/fi.json
index 99a1b53a6..c4ad43995 100644
--- a/src/i18n/fi.json
+++ b/src/i18n/fi.json
@@ -66,7 +66,7 @@
"search": "Haku"
},
"notifications": {
- "broken_favorite": "Viestiä ei löydetty...",
+ "broken_favorite": "Viestiä ei löydetty…",
"favorited_you": "tykkäsi viestistäsi",
"followed_you": "seuraa sinua",
"load_older": "Lataa vanhempia ilmoituksia",
@@ -101,7 +101,7 @@
},
"post_status": {
"new_status": "Uusi viesti",
- "account_not_locked_warning": "Tilisi ei ole {0}. Kuka vain voi seurata sinua nähdäksesi 'vain-seuraajille' -viestisi",
+ "account_not_locked_warning": "Tilisi ei ole {0}. Kuka vain voi seurata sinua nähdäksesi 'vain-seuraajille' -viestisi.",
"account_not_locked_warning_link": "lukittu",
"attachments_sensitive": "Merkkaa liitteet arkaluonteisiksi",
"content_type": {
@@ -288,7 +288,7 @@
"authentication_methods": "Todennus",
"warning_of_generate_new_codes": "Luodessasi uudet palautuskoodit, vanhat koodisi lakkaavat toimimasta.",
"recovery_codes": "Palautuskoodit.",
- "waiting_a_recovery_codes": "Odotetaan palautuskoodeja...",
+ "waiting_a_recovery_codes": "Odotetaan palautuskoodeja…",
"recovery_codes_warning": "Kirjoita koodit ylös tai tallenna ne turvallisesti, muuten et näe niitä uudestaan. Jos et voi käyttää monivaihetodennusta ja sinulla ei ole palautuskoodeja, et voi enää kirjautua sisään tilillesi.",
"scan": {
"title": "Skannaa",
@@ -575,7 +575,7 @@
"statuses": "Viestit",
"hidden": "Piilotettu",
"media": "Media",
- "block_progress": "Estetään...",
+ "block_progress": "Estetään…",
"admin_menu": {
"grant_admin": "Anna Ylläpitöoikeudet",
"force_nsfw": "Merkitse kaikki viestit NSFW:nä",
@@ -601,10 +601,10 @@
"subscribe": "Tilaa",
"unsubscribe": "Poista tilaus",
"unblock": "Poista esto",
- "unblock_progress": "Postetaan estoa...",
+ "unblock_progress": "Postetaan estoa…",
"unmute": "Poista mykistys",
- "unmute_progress": "Poistetaan mykistystä...",
- "mute_progress": "Mykistetään...",
+ "unmute_progress": "Poistetaan mykistystä…",
+ "mute_progress": "Mykistetään…",
"hide_repeats": "Piilota toistot",
"show_repeats": "Näytä toistot"
},
@@ -674,8 +674,8 @@
"domain_mute_card": {
"mute": "Mykistä",
"unmute": "Poista mykistys",
- "mute_progress": "Mykistetään...",
- "unmute_progress": "Poistetaan mykistyst..."
+ "mute_progress": "Mykistetään…",
+ "unmute_progress": "Poistetaan mykistyst…"
},
"exporter": {
"export": "Vie",
From 5b48954644d36a12c3a7d46553469f86fa177fbc Mon Sep 17 00:00:00 2001
From: Ben Is
Date: Mon, 6 Jul 2020 20:50:19 +0000
Subject: [PATCH 124/129] Translated using Weblate (Italian)
Currently translated at 75.1% (480 of 639 strings)
Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/it/
---
src/i18n/it.json | 46 ++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 42 insertions(+), 4 deletions(-)
diff --git a/src/i18n/it.json b/src/i18n/it.json
index 7311f0b69..35bbeabff 100644
--- a/src/i18n/it.json
+++ b/src/i18n/it.json
@@ -34,7 +34,8 @@
"user_search": "Ricerca utenti",
"search": "Ricerca",
"who_to_follow": "Chi seguire",
- "preferences": "Preferenze"
+ "preferences": "Preferenze",
+ "bookmarks": "Segnalibri"
},
"notifications": {
"followed_you": "ti segue",
@@ -271,10 +272,34 @@
"shadow_id": "Ombra numero {value}",
"override": "Sostituisci",
"component": "Componente",
- "_tab_label": "Luci ed ombre"
+ "_tab_label": "Luci ed ombre",
+ "components": {
+ "avatarStatus": "Icona utente (vista messaggio)",
+ "avatar": "Icona utente (vista profilo)",
+ "topBar": "Barra superiore",
+ "panelHeader": "Intestazione pannello",
+ "panel": "Pannello",
+ "input": "Campo d'immissione",
+ "buttonPressedHover": "Pulsante (puntato e premuto)",
+ "buttonPressed": "Pulsante (premuto)",
+ "buttonHover": "Pulsante (puntato)",
+ "button": "Pulsante",
+ "popup": "Sbalzi e suggerimenti"
+ },
+ "filter_hint": {
+ "inset_classic": "Le ombre incluse usano {0}",
+ "spread_zero": "Lo spandimento maggiore di zero si azzera sulle ombre",
+ "avatar_inset": "Tieni presente che combinare ombre (sia incluse che non) sulle icone utente potrebbe dare risultati strani con quelle trasparenti.",
+ "drop_shadow_syntax": "{0} non supporta il parametro {1} né la keyword {2}.",
+ "always_drop_shadow": "Attenzione: quest'ombra usa sempre {0} se il tuo browser lo supporta."
+ },
+ "hintV3": "Per le ombre puoi anche usare la sintassi {0} per sfruttare il secondo colore."
},
"radii": {
"_tab_label": "Raggio"
+ },
+ "fonts": {
+ "_tab_label": "Font"
}
},
"enable_web_push_notifications": "Abilita notifiche web push",
@@ -336,7 +361,14 @@
"emoji_reactions_on_timeline": "Mostra emoji di reazione sulle sequenze",
"pad_emoji": "Affianca spazi agli emoji inseriti tramite selettore",
"notification_blocks": "Bloccando un utente non riceverai più le sue notifiche né lo seguirai più.",
- "mutes_and_blocks": "Zittiti e bloccati"
+ "mutes_and_blocks": "Zittiti e bloccati",
+ "profile_fields": {
+ "value": "Contenuto",
+ "name": "Etichetta",
+ "add_field": "Aggiungi campo",
+ "label": "Metadati profilo"
+ },
+ "bot": "Questo profilo è di un robot"
},
"timeline": {
"error_fetching": "Errore nell'aggiornamento",
@@ -425,7 +457,10 @@
},
"direct_warning_to_first_only": "Questo messaggio sarà visibile solo agli utenti menzionati all'inizio.",
"direct_warning_to_all": "Questo messaggio sarà visibile a tutti i menzionati.",
- "new_status": "Nuovo messaggio"
+ "new_status": "Nuovo messaggio",
+ "empty_status_error": "Non puoi pubblicare messaggi vuoti senza allegati",
+ "preview_empty": "Vuoto",
+ "preview": "Anteprima"
},
"registration": {
"bio": "Introduzione",
@@ -548,5 +583,8 @@
"error": "Non trovato.",
"searching_for": "Cerco",
"remote_user_resolver": "Cerca utenti remoti"
+ },
+ "errors": {
+ "storage_unavailable": "Pleroma non ha potuto accedere ai dati del tuo browser. Le tue credenziali o le tue impostazioni locali non potranno essere salvate e potresti incontrare strani errori. Prova ad abilitare i cookie."
}
}
From a6606df01a47fa2afbfc9dbb9ca4979c71b63c96 Mon Sep 17 00:00:00 2001
From: Ben Is
Date: Tue, 7 Jul 2020 00:39:45 +0000
Subject: [PATCH 125/129] Translated using Weblate (Chinese (Simplified))
Currently translated at 88.2% (564 of 639 strings)
Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/zh_Hans/
---
src/i18n/zh.json | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/src/i18n/zh.json b/src/i18n/zh.json
index f95dc4987..7e620bdf7 100644
--- a/src/i18n/zh.json
+++ b/src/i18n/zh.json
@@ -85,7 +85,7 @@
"administration": "管理员"
},
"notifications": {
- "broken_favorite": "未知的状态,正在搜索中...",
+ "broken_favorite": "未知的状态,正在搜索中…",
"favorited_you": "收藏了你的状态",
"followed_you": "关注了你",
"load_older": "加载更早的通知",
@@ -185,7 +185,7 @@
"generate_new_recovery_codes": "生成新的恢复码",
"warning_of_generate_new_codes": "当你生成新的恢复码时,你的旧恢复码就失效了。",
"recovery_codes": "恢复码。",
- "waiting_a_recovery_codes": "正在接收备份码……",
+ "waiting_a_recovery_codes": "正在接收备份码…",
"recovery_codes_warning": "抄写这些号码,或者保存在安全的地方。这些号码不会再次显示。如果你无法访问你的 2FA app,也丢失了你的恢复码,你的账号就再也无法登录了。",
"authentication_methods": "身份验证方法",
"scan": {
@@ -564,11 +564,11 @@
"subscribe": "订阅",
"unsubscribe": "退订",
"unblock": "取消拉黑",
- "unblock_progress": "取消拉黑中...",
- "block_progress": "拉黑中...",
+ "unblock_progress": "取消拉黑中…",
+ "block_progress": "拉黑中…",
"unmute": "取消隐藏",
- "unmute_progress": "取消隐藏中...",
- "mute_progress": "隐藏中...",
+ "unmute_progress": "取消隐藏中…",
+ "mute_progress": "隐藏中…",
"admin_menu": {
"moderation": "权限",
"grant_admin": "赋予管理权限",
@@ -690,9 +690,9 @@
}
},
"domain_mute_card": {
- "unmute_progress": "正在取消隐藏……",
+ "unmute_progress": "正在取消隐藏…",
"unmute": "取消隐藏",
- "mute_progress": "隐藏中……",
+ "mute_progress": "隐藏中…",
"mute": "隐藏"
}
}
From 0ab6d92ab8c60aa47fd17a42e19b51bc6674a0f5 Mon Sep 17 00:00:00 2001
From: Ben Is
Date: Tue, 7 Jul 2020 01:10:06 +0000
Subject: [PATCH 126/129] Translated using Weblate (Italian)
Currently translated at 85.2% (545 of 639 strings)
Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/it/
---
src/i18n/it.json | 81 ++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 78 insertions(+), 3 deletions(-)
diff --git a/src/i18n/it.json b/src/i18n/it.json
index 35bbeabff..ed78e6562 100644
--- a/src/i18n/it.json
+++ b/src/i18n/it.json
@@ -299,7 +299,32 @@
"_tab_label": "Raggio"
},
"fonts": {
- "_tab_label": "Font"
+ "_tab_label": "Font",
+ "custom": "Personalizzato",
+ "weight": "Peso (grassettatura)",
+ "size": "Dimensione (in pixel)",
+ "family": "Nome font",
+ "components": {
+ "postCode": "Font a spaziatura fissa incluso in un messaggio",
+ "post": "Testo del messaggio",
+ "input": "Campi d'immissione",
+ "interface": "Interfaccia"
+ },
+ "help": "Seleziona il font da usare per gli elementi dell'interfaccia. Se scegli \"personalizzato\" devi inserire il suo nome di sistema."
+ },
+ "preview": {
+ "link": "un bel collegamentino",
+ "checkbox": "Ho dato uno sguardo a termini e condizioni",
+ "header_faint": "Tutto bene",
+ "fine_print": "Leggi il nostro {0} per imparare un bel niente!",
+ "faint_link": "utilissimo manuale",
+ "input": "Sono appena atterrato a Fiumicino.",
+ "mono": "contenuto",
+ "text": "Altro {0} e {1}",
+ "content": "Contenuto",
+ "button": "Pulsante",
+ "error": "Errore d'esempio",
+ "header": "Anteprima"
}
},
"enable_web_push_notifications": "Abilita notifiche web push",
@@ -368,7 +393,12 @@
"add_field": "Aggiungi campo",
"label": "Metadati profilo"
},
- "bot": "Questo profilo è di un robot"
+ "bot": "Questo profilo è di un robot",
+ "version": {
+ "frontend_version": "Versione interfaccia",
+ "backend_version": "Versione backend",
+ "title": "Versione"
+ }
},
"timeline": {
"error_fetching": "Errore nell'aggiornamento",
@@ -378,7 +408,10 @@
"collapse": "Riduci",
"conversation": "Conversazione",
"no_retweet_hint": "Il messaggio è diretto o solo per seguaci e non può essere condiviso",
- "repeated": "condiviso"
+ "repeated": "condiviso",
+ "no_statuses": "Nessun messaggio",
+ "no_more_statuses": "Fine dei messaggi",
+ "reload": "Ricarica"
},
"user_card": {
"follow": "Segui",
@@ -586,5 +619,47 @@
},
"errors": {
"storage_unavailable": "Pleroma non ha potuto accedere ai dati del tuo browser. Le tue credenziali o le tue impostazioni locali non potranno essere salvate e potresti incontrare strani errori. Prova ad abilitare i cookie."
+ },
+ "status": {
+ "pinned": "Intestato",
+ "unpin": "De-intesta",
+ "pin": "Intesta al profilo",
+ "delete": "Elimina messaggio",
+ "repeats": "Condivisi",
+ "favorites": "Preferiti"
+ },
+ "time": {
+ "years_short": "{0}a",
+ "year_short": "{0}a",
+ "years": "{0} anni",
+ "year": "{0} anno",
+ "weeks_short": "{0}set",
+ "week_short": "{0}set",
+ "seconds_short": "{0}sec",
+ "second_short": "{0}sec",
+ "weeks": "{0} settimane",
+ "week": "{0} settimana",
+ "seconds": "{0} secondi",
+ "second": "{0} secondo",
+ "now_short": "ora",
+ "now": "adesso",
+ "months_short": "{0}me",
+ "month_short": "{0}me",
+ "months": "{0} mesi",
+ "month": "{0} mese",
+ "minutes_short": "{0}min",
+ "minute_short": "{0}min",
+ "minutes": "{0} minuti",
+ "minute": "{0} minuto",
+ "in_past": "{0} fa",
+ "in_future": "fra {0}",
+ "hours_short": "{0}h",
+ "days_short": "{0}g",
+ "hour_short": "{0}h",
+ "hours": "{0} ore",
+ "hour": "{0} ora",
+ "day_short": "{0}g",
+ "days": "{0} giorni",
+ "day": "{0} giorno"
}
}
From 1767ee01d08545ea7b15867732c4988ab1b54e68 Mon Sep 17 00:00:00 2001
From: Dym Sohin
Date: Tue, 7 Jul 2020 19:34:45 +0000
Subject: [PATCH 127/129] corrected tos.html location
---
static/terms-of-service.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/static/terms-of-service.html b/static/terms-of-service.html
index b2c668151..3b6bbb36b 100644
--- a/static/terms-of-service.html
+++ b/static/terms-of-service.html
@@ -2,7 +2,7 @@
This is the default placeholder ToS. You should copy it over to your static folder and edit it to fit the needs of your instance.
-To do so, place a file at "/instance/static/terms-of-service.html"
in your
+
To do so, place a file at "/instance/static/static/terms-of-service.html"
in your
Pleroma install containing the real ToS for your instance.
See the Pleroma documentation for more information.
From eea002e6f5e3da4c4415d45cffd9cff64fd6c052 Mon Sep 17 00:00:00 2001
From: Shpuld Shpludson
Date: Wed, 8 Jul 2020 10:11:17 +0000
Subject: [PATCH 128/129] streamline profile image api, update reset ui for all
profile images to match avatar, remove unnecessary stuff
---
CHANGELOG.md | 1 +
.../settings_modal/tabs/profile_tab.js | 61 ++++++++++++++++---
.../settings_modal/tabs/profile_tab.scss | 39 ++++++++++--
.../settings_modal/tabs/profile_tab.vue | 51 +++++++++++-----
src/components/user_avatar/user_avatar.js | 16 ++---
src/components/user_avatar/user_avatar.vue | 2 +-
.../who_to_follow_panel.js | 17 +++---
src/i18n/en.json | 8 ++-
src/modules/instance.js | 2 +
src/services/api/api.service.js | 32 ++--------
10 files changed, 153 insertions(+), 76 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9f54352db..49ec550cd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Autocomplete domains from list of known instances
- 'Bot' settings option and badge
- Added profile meta data fields that can be set in profile settings
+- Added option to reset avatar/banner in profile settings
- Descriptions can be set on uploaded files before posting
- Added status preview option to preview your statuses before posting
- When a post is a reply to an unavailable post, the 'Reply to'-text has a strike-through style
diff --git a/src/components/settings_modal/tabs/profile_tab.js b/src/components/settings_modal/tabs/profile_tab.js
index e6db802dd..bd6bef6ab 100644
--- a/src/components/settings_modal/tabs/profile_tab.js
+++ b/src/components/settings_modal/tabs/profile_tab.js
@@ -77,6 +77,33 @@ const ProfileTab = {
},
maxFields () {
return this.fieldsLimits ? this.fieldsLimits.maxFields : 0
+ },
+ defaultAvatar () {
+ return this.$store.state.instance.server + this.$store.state.instance.defaultAvatar
+ },
+ defaultBanner () {
+ return this.$store.state.instance.server + this.$store.state.instance.defaultBanner
+ },
+ isDefaultAvatar () {
+ const baseAvatar = this.$store.state.instance.defaultAvatar
+ return !(this.$store.state.users.currentUser.profile_image_url) ||
+ this.$store.state.users.currentUser.profile_image_url.includes(baseAvatar)
+ },
+ isDefaultBanner () {
+ const baseBanner = this.$store.state.instance.defaultBanner
+ return !(this.$store.state.users.currentUser.cover_photo) ||
+ this.$store.state.users.currentUser.cover_photo.includes(baseBanner)
+ },
+ isDefaultBackground () {
+ return !(this.$store.state.users.currentUser.background_image)
+ },
+ avatarImgSrc () {
+ const src = this.$store.state.users.currentUser.profile_image_url_original
+ return (!src) ? this.defaultAvatar : src
+ },
+ bannerImgSrc () {
+ const src = this.$store.state.users.currentUser.cover_photo
+ return (!src) ? this.defaultBanner : src
}
},
methods: {
@@ -150,11 +177,29 @@ const ProfileTab = {
}
reader.readAsDataURL(file)
},
+ resetAvatar () {
+ const confirmed = window.confirm(this.$t('settings.reset_avatar_confirm'))
+ if (confirmed) {
+ this.submitAvatar(undefined, '')
+ }
+ },
+ resetBanner () {
+ const confirmed = window.confirm(this.$t('settings.reset_banner_confirm'))
+ if (confirmed) {
+ this.submitBanner('')
+ }
+ },
+ resetBackground () {
+ const confirmed = window.confirm(this.$t('settings.reset_background_confirm'))
+ if (confirmed) {
+ this.submitBackground('')
+ }
+ },
submitAvatar (cropper, file) {
const that = this
return new Promise((resolve, reject) => {
function updateAvatar (avatar) {
- that.$store.state.api.backendInteractor.updateAvatar({ avatar })
+ that.$store.state.api.backendInteractor.updateProfileImages({ avatar })
.then((user) => {
that.$store.commit('addNewUsers', [user])
that.$store.commit('setCurrentUser', user)
@@ -172,11 +217,11 @@ const ProfileTab = {
}
})
},
- submitBanner () {
- if (!this.bannerPreview) { return }
+ submitBanner (banner) {
+ if (!this.bannerPreview && banner !== '') { return }
this.bannerUploading = true
- this.$store.state.api.backendInteractor.updateBanner({ banner: this.banner })
+ this.$store.state.api.backendInteractor.updateProfileImages({ banner })
.then((user) => {
this.$store.commit('addNewUsers', [user])
this.$store.commit('setCurrentUser', user)
@@ -187,11 +232,11 @@ const ProfileTab = {
})
.then(() => { this.bannerUploading = false })
},
- submitBg () {
- if (!this.backgroundPreview) { return }
- let background = this.background
+ submitBackground (background) {
+ if (!this.backgroundPreview && background !== '') { return }
+
this.backgroundUploading = true
- this.$store.state.api.backendInteractor.updateBg({ background }).then((data) => {
+ this.$store.state.api.backendInteractor.updateProfileImages({ background }).then((data) => {
if (!data.error) {
this.$store.commit('addNewUsers', [data])
this.$store.commit('setCurrentUser', data)
diff --git a/src/components/settings_modal/tabs/profile_tab.scss b/src/components/settings_modal/tabs/profile_tab.scss
index b3dcf42c8..e14cf054c 100644
--- a/src/components/settings_modal/tabs/profile_tab.scss
+++ b/src/components/settings_modal/tabs/profile_tab.scss
@@ -13,8 +13,14 @@
height: auto;
}
- .banner {
+ .banner-background-preview {
max-width: 100%;
+ width: 300px;
+ position: relative;
+
+ img {
+ width: 100%;
+ }
}
.uploading {
@@ -26,18 +32,40 @@
width: 100%;
}
- .bg {
- max-width: 100%;
+ .current-avatar-container {
+ position: relative;
+ width: 150px;
+ height: 150px;
}
.current-avatar {
display: block;
- width: 150px;
- height: 150px;
+ width: 100%;
+ height: 100%;
border-radius: $fallback--avatarRadius;
border-radius: var(--avatarRadius, $fallback--avatarRadius);
}
+ .reset-button {
+ position: absolute;
+ top: 0.2em;
+ right: 0.2em;
+ border-radius: $fallback--tooltipRadius;
+ border-radius: var(--tooltipRadius, $fallback--tooltipRadius);
+ background-color: rgba(0, 0, 0, 0.6);
+ opacity: 0.7;
+ color: white;
+ width: 1.5em;
+ height: 1.5em;
+ text-align: center;
+ line-height: 1.5em;
+ font-size: 1.5em;
+ cursor: pointer;
+ &:hover {
+ opacity: 1;
+ }
+ }
+
.oauth-tokens {
width: 100%;
@@ -86,6 +114,7 @@
&>.emoji-input {
flex: 1 1 auto;
margin: 0 .2em .5em;
+ min-width: 0;
}
&>.icon-container {
diff --git a/src/components/settings_modal/tabs/profile_tab.vue b/src/components/settings_modal/tabs/profile_tab.vue
index 0f9210a6d..cf88c4e4f 100644
--- a/src/components/settings_modal/tabs/profile_tab.vue
+++ b/src/components/settings_modal/tabs/profile_tab.vue
@@ -161,11 +161,19 @@
{{ $t('settings.avatar_size_instruction') }}
- {{ $t('settings.current_avatar') }}
-
+
+
![]()
+
+
{{ $t('settings.set_new_avatar') }}