Compare commits
18 commits
Author | SHA1 | Date | |
---|---|---|---|
smitten | 1cf5ac4497 | ||
smitten | f5215990bd | ||
smitten | 4d44030ca7 | ||
c047646188 | |||
383a8b1907 | |||
8c122cfaf7 | |||
28d180e944 | |||
smitten | 0a56cf37a9 | ||
smitten | 14e789cf7a | ||
smitten | 904e90e060 | ||
smitten | 68f0150712 | ||
smitten | 9638a642c7 | ||
smitten | b842f17fd2 | ||
smitten | 0e7f4586ed | ||
smitten | 28d6daf524 | ||
smitten | 1eb15e58bb | ||
smitten | 852fed047a | ||
smitten | 2cd1cd422c |
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -9,4 +9,5 @@ selenium-debug.log
|
||||||
config/local.json
|
config/local.json
|
||||||
config/local.*.json
|
config/local.*.json
|
||||||
docs/site/
|
docs/site/
|
||||||
.vscode/
|
.vscode/
|
||||||
|
.yarn/
|
17
README.md
17
README.md
|
@ -1,3 +1,20 @@
|
||||||
|
A soft fork of Akkoma-FE fixing a few minor but longstanding annoyances.
|
||||||
|
|
||||||
|
Hopefully most of these will be merged upstream when I learn how to do PRs.
|
||||||
|
|
||||||
|
## Comprehensive List of Fixes and Changes
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Support for 'Fedi Links' web+ap addresses on user profiles and posts
|
||||||
|
- Approve and deny follow request buttons to the user profile page
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Styling adjustments for the user profile to avoid some ellipsing in the notifications panel
|
||||||
|
- Settings backup when the word filters contain non-ASCII characters
|
||||||
|
- The hover color of the checkmark icon on follow request notifications
|
||||||
|
|
||||||
# Akkoma-FE
|
# Akkoma-FE
|
||||||
|
|
||||||
![English OK](https://img.shields.io/badge/English-OK-blueviolet) ![日本語OK](https://img.shields.io/badge/%E6%97%A5%E6%9C%AC%E8%AA%9E-OK-blueviolet)
|
![English OK](https://img.shields.io/badge/English-OK-blueviolet) ![日本語OK](https://img.shields.io/badge/%E6%97%A5%E6%9C%AC%E8%AA%9E-OK-blueviolet)
|
||||||
|
|
13
src/assets/icons/activity-pub.js
Normal file
13
src/assets/icons/activity-pub.js
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
const facActivityPub = {
|
||||||
|
prefix: "fac",
|
||||||
|
iconName: "activity-pub",
|
||||||
|
icon: [
|
||||||
|
448,
|
||||||
|
512,
|
||||||
|
[],
|
||||||
|
"",
|
||||||
|
"M 253.31024,102.2775 -10,254.04683 v 60.95152 L 200.28249,193.7048 v 243.19662 l 53.02775,29.86625 z m 52.41823,0 v 60.95153 L 516.62048,284.52259 305.72847,406.42564 v 60.34203 L 569.03871,314.99835 v -60.95152 z m 0,121.90308 V 345.47412 L 411.17449,284.52259 Z M 147.86424,284.52259 42.418248,345.47412 147.86424,406.42564 Z"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default facActivityPub
|
|
@ -1,5 +1,6 @@
|
||||||
import Popover from '../popover/popover.vue'
|
import Popover from '../popover/popover.vue'
|
||||||
import ConfirmModal from '../confirm_modal/confirm_modal.vue'
|
import ConfirmModal from '../confirm_modal/confirm_modal.vue'
|
||||||
|
import facActivityPub from '../../assets/icons/activity-pub'
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import {
|
import {
|
||||||
faEllipsisH,
|
faEllipsisH,
|
||||||
|
@ -9,7 +10,7 @@ import {
|
||||||
faShareAlt,
|
faShareAlt,
|
||||||
faExternalLinkAlt,
|
faExternalLinkAlt,
|
||||||
faHistory,
|
faHistory,
|
||||||
faFilePen
|
faFilePen,
|
||||||
} from '@fortawesome/free-solid-svg-icons'
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
import {
|
import {
|
||||||
faBookmark as faBookmarkReg,
|
faBookmark as faBookmarkReg,
|
||||||
|
@ -25,6 +26,7 @@ library.add(
|
||||||
faThumbtack,
|
faThumbtack,
|
||||||
faShareAlt,
|
faShareAlt,
|
||||||
faExternalLinkAlt,
|
faExternalLinkAlt,
|
||||||
|
facActivityPub,
|
||||||
faFlag,
|
faFlag,
|
||||||
faHistory,
|
faHistory,
|
||||||
faFilePen
|
faFilePen
|
||||||
|
@ -95,6 +97,11 @@ const ExtraButtons = {
|
||||||
.then(() => this.$emit('onSuccess'))
|
.then(() => this.$emit('onSuccess'))
|
||||||
.catch(err => this.$emit('onError', err.error.error))
|
.catch(err => this.$emit('onError', err.error.error))
|
||||||
},
|
},
|
||||||
|
copyFediLink () {
|
||||||
|
navigator.clipboard.writeText(this.fediLinkURL)
|
||||||
|
.then(() => this.$emit('onSuccess'))
|
||||||
|
.catch(err => this.$emit('onError', err.error.error))
|
||||||
|
},
|
||||||
bookmarkStatus () {
|
bookmarkStatus () {
|
||||||
this.$store.dispatch('bookmark', { id: this.status.id })
|
this.$store.dispatch('bookmark', { id: this.status.id })
|
||||||
.then(() => this.$emit('onSuccess'))
|
.then(() => this.$emit('onSuccess'))
|
||||||
|
@ -170,7 +177,7 @@ const ExtraButtons = {
|
||||||
canPin () {
|
canPin () {
|
||||||
return this.ownStatus && (this.status.visibility === 'public' || this.status.visibility === 'unlisted')
|
return this.ownStatus && (this.status.visibility === 'public' || this.status.visibility === 'unlisted')
|
||||||
},
|
},
|
||||||
canMute () {
|
loggedIn () {
|
||||||
return !!this.currentUser
|
return !!this.currentUser
|
||||||
},
|
},
|
||||||
canTranslate () {
|
canTranslate () {
|
||||||
|
@ -186,6 +193,16 @@ const ExtraButtons = {
|
||||||
return this.status.external_url
|
return this.status.external_url
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
showFediLinks () {
|
||||||
|
return this.$store.getters.mergedConfig.showFediLinks === true
|
||||||
|
},
|
||||||
|
fediLinkURL () {
|
||||||
|
try {
|
||||||
|
return this.status.external_uri.replace(/^https?/, 'web+ap')
|
||||||
|
} catch (e) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
},
|
||||||
shouldConfirmDelete () {
|
shouldConfirmDelete () {
|
||||||
return this.$store.getters.mergedConfig.modalOnDelete
|
return this.$store.getters.mergedConfig.modalOnDelete
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<template v-slot:content="{close}">
|
<template v-slot:content="{close}">
|
||||||
<div class="dropdown-menu">
|
<div class="dropdown-menu">
|
||||||
<button
|
<button
|
||||||
v-if="canMute && !status.thread_muted"
|
v-if="loggedIn && !status.thread_muted"
|
||||||
class="button-default dropdown-item dropdown-item-icon"
|
class="button-default dropdown-item dropdown-item-icon"
|
||||||
@click.prevent="muteConversation"
|
@click.prevent="muteConversation"
|
||||||
>
|
>
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
/><span>{{ $t("status.mute_conversation") }}</span>
|
/><span>{{ $t("status.mute_conversation") }}</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="canMute && status.thread_muted"
|
v-if="loggedIn && status.thread_muted"
|
||||||
class="button-default dropdown-item dropdown-item-icon"
|
class="button-default dropdown-item dropdown-item-icon"
|
||||||
@click.prevent="unmuteConversation"
|
@click.prevent="unmuteConversation"
|
||||||
>
|
>
|
||||||
|
@ -52,7 +52,7 @@
|
||||||
/><span>{{ $t("status.unpin") }}</span>
|
/><span>{{ $t("status.unpin") }}</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="!status.bookmarked"
|
v-if="loggedIn && !status.bookmarked"
|
||||||
class="button-default dropdown-item dropdown-item-icon"
|
class="button-default dropdown-item dropdown-item-icon"
|
||||||
@click.prevent="bookmarkStatus"
|
@click.prevent="bookmarkStatus"
|
||||||
@click="close"
|
@click="close"
|
||||||
|
@ -63,7 +63,7 @@
|
||||||
/><span>{{ $t("status.bookmark") }}</span>
|
/><span>{{ $t("status.bookmark") }}</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="status.bookmarked"
|
v-if="loggedIn && status.bookmarked"
|
||||||
class="button-default dropdown-item dropdown-item-icon"
|
class="button-default dropdown-item dropdown-item-icon"
|
||||||
@click.prevent="unbookmarkStatus"
|
@click.prevent="unbookmarkStatus"
|
||||||
@click="close"
|
@click="close"
|
||||||
|
@ -127,6 +127,17 @@
|
||||||
icon="share-alt"
|
icon="share-alt"
|
||||||
/><span>{{ $t("status.copy_link") }}</span>
|
/><span>{{ $t("status.copy_link") }}</span>
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
v-if="fediLinkURL && showFediLinks && loggedIn"
|
||||||
|
class="button-default dropdown-item dropdown-item-icon"
|
||||||
|
@click.prevent="copyFediLink"
|
||||||
|
@click="close"
|
||||||
|
>
|
||||||
|
<FAIcon
|
||||||
|
fixed-width
|
||||||
|
:icon="['fac', 'activity-pub']"
|
||||||
|
/><span>{{ $t("status.copy_fedi_link") }}</span>
|
||||||
|
</button>
|
||||||
<a
|
<a
|
||||||
v-if="!status.is_local"
|
v-if="!status.is_local"
|
||||||
class="button-default dropdown-item dropdown-item-icon"
|
class="button-default dropdown-item dropdown-item-icon"
|
||||||
|
@ -139,6 +150,18 @@
|
||||||
icon="external-link-alt"
|
icon="external-link-alt"
|
||||||
/><span>{{ $t("status.external_source") }}</span>
|
/><span>{{ $t("status.external_source") }}</span>
|
||||||
</a>
|
</a>
|
||||||
|
<a
|
||||||
|
v-if="fediLinkURL && showFediLinks && !loggedIn"
|
||||||
|
class="button-default dropdown-item dropdown-item-icon"
|
||||||
|
title="Source"
|
||||||
|
:href="fediLinkURL"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<FAIcon
|
||||||
|
fixed-width
|
||||||
|
:icon="['fac', 'activity-pub']"
|
||||||
|
/><span>{{ $t("status.open_fedi_link") }}</span>
|
||||||
|
</a>
|
||||||
<button
|
<button
|
||||||
class="button-default dropdown-item dropdown-item-icon"
|
class="button-default dropdown-item dropdown-item-icon"
|
||||||
@click.prevent="reportStatus"
|
@click.prevent="reportStatus"
|
||||||
|
|
|
@ -65,8 +65,8 @@
|
||||||
|
|
||||||
.follow-request-accept {
|
.follow-request-accept {
|
||||||
&:hover {
|
&:hover {
|
||||||
color: $fallback--text;
|
color: $fallback--cGreen;
|
||||||
color: var(--text, $fallback--text);
|
color: var(--cGreen, $fallback--text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -146,6 +146,14 @@
|
||||||
{{ $t('settings.show_wider_shortcuts') }}
|
{{ $t('settings.show_wider_shortcuts') }}
|
||||||
</BooleanSetting>
|
</BooleanSetting>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<BooleanSetting
|
||||||
|
path="showFediLinks"
|
||||||
|
expert="1"
|
||||||
|
>
|
||||||
|
{{ $t('settings.show_fedi_links') }}
|
||||||
|
</BooleanSetting>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<BooleanSetting path="stopGifs">
|
<BooleanSetting path="stopGifs">
|
||||||
{{ $t('settings.stop_gifs') }}
|
{{ $t('settings.stop_gifs') }}
|
||||||
|
|
|
@ -8,6 +8,8 @@ import Select from '../select/select.vue'
|
||||||
import RichContent from 'src/components/rich_content/rich_content.jsx'
|
import RichContent from 'src/components/rich_content/rich_content.jsx'
|
||||||
import ConfirmModal from '../confirm_modal/confirm_modal.vue'
|
import ConfirmModal from '../confirm_modal/confirm_modal.vue'
|
||||||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||||
|
import facActivityPub from '../../assets/icons/activity-pub'
|
||||||
|
import { notificationsFromStore } from 'src/services/notification_utils/notification_utils.js'
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import {
|
import {
|
||||||
|
@ -15,7 +17,7 @@ import {
|
||||||
faRss,
|
faRss,
|
||||||
faSearchPlus,
|
faSearchPlus,
|
||||||
faExternalLinkAlt,
|
faExternalLinkAlt,
|
||||||
faEdit
|
faEdit,
|
||||||
} from '@fortawesome/free-solid-svg-icons'
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
||||||
library.add(
|
library.add(
|
||||||
|
@ -23,7 +25,8 @@ library.add(
|
||||||
faBell,
|
faBell,
|
||||||
faSearchPlus,
|
faSearchPlus,
|
||||||
faExternalLinkAlt,
|
faExternalLinkAlt,
|
||||||
faEdit
|
faEdit,
|
||||||
|
facActivityPub
|
||||||
)
|
)
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -34,7 +37,9 @@ export default {
|
||||||
return {
|
return {
|
||||||
followRequestInProgress: false,
|
followRequestInProgress: false,
|
||||||
betterShadow: this.$store.state.interface.browserSupport.cssFilter,
|
betterShadow: this.$store.state.interface.browserSupport.cssFilter,
|
||||||
showingConfirmMute: false
|
showingConfirmMute: false,
|
||||||
|
showingApproveConfirmDialog: false,
|
||||||
|
showingDenyConfirmDialog: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created () {
|
created () {
|
||||||
|
@ -44,6 +49,16 @@ export default {
|
||||||
user () {
|
user () {
|
||||||
return this.$store.getters.findUser(this.userId)
|
return this.$store.getters.findUser(this.userId)
|
||||||
},
|
},
|
||||||
|
showFediLinks () {
|
||||||
|
return this.$store.getters.mergedConfig.showFediLinks === true
|
||||||
|
},
|
||||||
|
fediLinkURL () {
|
||||||
|
try {
|
||||||
|
return this.user._original.pleroma.ap_id.replace(/^https?/, 'web+ap')
|
||||||
|
} catch (e) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
},
|
||||||
relationship () {
|
relationship () {
|
||||||
return this.$store.getters.relationship(this.userId)
|
return this.$store.getters.relationship(this.userId)
|
||||||
},
|
},
|
||||||
|
@ -117,6 +132,12 @@ export default {
|
||||||
shouldConfirmMute () {
|
shouldConfirmMute () {
|
||||||
return this.mergedConfig.modalOnMute
|
return this.mergedConfig.modalOnMute
|
||||||
},
|
},
|
||||||
|
shouldConfirmApprove () {
|
||||||
|
return this.mergedConfig.modalOnApproveFollow
|
||||||
|
},
|
||||||
|
shouldConfirmDeny () {
|
||||||
|
return this.mergedConfig.modalOnDenyFollow
|
||||||
|
},
|
||||||
...mapGetters(['mergedConfig'])
|
...mapGetters(['mergedConfig'])
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
@ -193,6 +214,58 @@ export default {
|
||||||
},
|
},
|
||||||
mentionUser () {
|
mentionUser () {
|
||||||
this.$store.dispatch('openPostStatusModal', { replyTo: true, repliedUser: this.user })
|
this.$store.dispatch('openPostStatusModal', { replyTo: true, repliedUser: this.user })
|
||||||
|
},
|
||||||
|
showApproveConfirmDialog () {
|
||||||
|
this.showingApproveConfirmDialog = true
|
||||||
|
},
|
||||||
|
hideApproveConfirmDialog () {
|
||||||
|
this.showingApproveConfirmDialog = false
|
||||||
|
},
|
||||||
|
showDenyConfirmDialog () {
|
||||||
|
this.showingDenyConfirmDialog = true
|
||||||
|
},
|
||||||
|
hideDenyConfirmDialog () {
|
||||||
|
this.showingDenyConfirmDialog = false
|
||||||
|
},
|
||||||
|
approveUser () {
|
||||||
|
if (this.shouldConfirmApprove) {
|
||||||
|
this.showApproveConfirmDialog()
|
||||||
|
} else {
|
||||||
|
this.doApprove()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
doApprove () {
|
||||||
|
const notifId = this.findFollowRequestNotificationId()
|
||||||
|
this.$store.dispatch('approveUser', this.user.id)
|
||||||
|
this.$store.dispatch('markSingleNotificationAsSeen', { id: notifId })
|
||||||
|
this.$store.dispatch('updateNotification', {
|
||||||
|
id: notifId,
|
||||||
|
updater: notification => {
|
||||||
|
notification.type = 'follow'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.hideApproveConfirmDialog()
|
||||||
|
},
|
||||||
|
denyUser () {
|
||||||
|
if (this.shouldConfirmDeny) {
|
||||||
|
this.showDenyConfirmDialog()
|
||||||
|
} else {
|
||||||
|
this.doDeny()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
doDeny () {
|
||||||
|
const notifId = this.findFollowRequestNotificationId()
|
||||||
|
this.$store.dispatch('denyUser', this.user.id)
|
||||||
|
.then(() => {
|
||||||
|
this.$store.dispatch('dismissNotificationLocal', { id: notifId })
|
||||||
|
})
|
||||||
|
this.hideDenyConfirmDialog()
|
||||||
|
},
|
||||||
|
findFollowRequestNotificationId () {
|
||||||
|
const notif = notificationsFromStore(this.$store).find(
|
||||||
|
(notif) => notif.from_profile.id === this.user.id && notif.type === 'follow_request'
|
||||||
|
)
|
||||||
|
return notif && notif.id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,14 +97,13 @@
|
||||||
.user-info {
|
.user-info {
|
||||||
color: $fallback--lightText;
|
color: $fallback--lightText;
|
||||||
color: var(--lightText, $fallback--lightText);
|
color: var(--lightText, $fallback--lightText);
|
||||||
padding: 0 26px;
|
padding: 0 1.5em;
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
padding: 16px 0 6px;
|
padding: 16px 0 6px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
max-height: 56px;
|
|
||||||
|
|
||||||
> * {
|
> * {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
@ -165,7 +164,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-summary {
|
.user-summary {
|
||||||
display: block;
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
margin-left: 0.6em;
|
margin-left: 0.6em;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
@ -184,6 +184,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-names {
|
||||||
|
flex-grow: 1;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.user-name {
|
.user-name {
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
@ -228,6 +233,13 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button-line {
|
||||||
|
display: flex;
|
||||||
|
min-width: 10em;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
.user-meta {
|
.user-meta {
|
||||||
margin-bottom: .15em;
|
margin-bottom: .15em;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -242,6 +254,12 @@
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.requested_by {
|
||||||
|
.btn {
|
||||||
|
margin-right: .25em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.highlighter {
|
.highlighter {
|
||||||
flex: 0 1 auto;
|
flex: 0 1 auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
@ -1,175 +1,108 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div class="user-card" :class="classes">
|
||||||
class="user-card"
|
<div :class="{ 'hide-bio': hideBio }" :style="style" class="background-image" />
|
||||||
:class="classes"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
:class="{ 'hide-bio': hideBio }"
|
|
||||||
:style="style"
|
|
||||||
class="background-image"
|
|
||||||
/>
|
|
||||||
<div class="panel-heading -flexible-height">
|
<div class="panel-heading -flexible-height">
|
||||||
<div class="user-info">
|
<div class="user-info">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a
|
<a v-if="allowZoomingAvatar" class="user-info-avatar-link" @click="zoomAvatar">
|
||||||
v-if="allowZoomingAvatar"
|
<UserAvatar :better-shadow="betterShadow" :user="user" />
|
||||||
class="user-info-avatar-link"
|
|
||||||
@click="zoomAvatar"
|
|
||||||
>
|
|
||||||
<UserAvatar
|
|
||||||
:better-shadow="betterShadow"
|
|
||||||
:user="user"
|
|
||||||
/>
|
|
||||||
<div class="user-info-avatar-link-overlay">
|
<div class="user-info-avatar-link-overlay">
|
||||||
<FAIcon
|
<FAIcon class="fa-scale-110 fa-old-padding" icon="search-plus" />
|
||||||
class="fa-scale-110 fa-old-padding"
|
|
||||||
icon="search-plus"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<router-link
|
<router-link v-else :to="userProfileLink(user)">
|
||||||
v-else
|
<UserAvatar :better-shadow="betterShadow" :user="user" />
|
||||||
:to="userProfileLink(user)"
|
|
||||||
>
|
|
||||||
<UserAvatar
|
|
||||||
:better-shadow="betterShadow"
|
|
||||||
:user="user"
|
|
||||||
/>
|
|
||||||
</router-link>
|
</router-link>
|
||||||
<div class="user-summary">
|
<div class="user-summary">
|
||||||
<div class="top-line">
|
<div class="user-names">
|
||||||
<RichContent
|
<div class="top-line">
|
||||||
:title="user.name"
|
<RichContent :title="user.name" class="user-name" :html="user.name" :emoji="user.emoji" />
|
||||||
class="user-name"
|
</div>
|
||||||
:html="user.name"
|
<div class="bottom-line">
|
||||||
:emoji="user.emoji"
|
<router-link class="user-screen-name" :title="user.screen_name_ui" :to="userProfileLink(user)">
|
||||||
/>
|
@{{ user.screen_name_ui }}
|
||||||
<button
|
</router-link>
|
||||||
v-if="!isOtherUser && user.is_local"
|
<template v-if="!hideBio">
|
||||||
class="button-unstyled edit-profile-button"
|
<span v-if="user.deactivated" class="alert user-role">
|
||||||
@click.stop="openProfileTab"
|
{{ $t('user_card.deactivated') }}
|
||||||
>
|
</span>
|
||||||
<FAIcon
|
<span v-if="!!visibleRole" class="alert user-role">
|
||||||
fixed-width
|
{{ $t(`general.role.${visibleRole}`) }}
|
||||||
class="icon"
|
</span>
|
||||||
icon="edit"
|
<span v-if="user.bot" class="alert user-role">
|
||||||
:title="$t('user_card.edit_profile')"
|
{{ $t('user_card.bot') }}
|
||||||
/>
|
</span>
|
||||||
</button>
|
</template>
|
||||||
<a
|
<span v-if="user.locked">
|
||||||
v-if="isOtherUser && !user.is_local"
|
<FAIcon class="lock-icon" icon="lock" size="sm" />
|
||||||
:href="user.statusnet_profile_url"
|
</span>
|
||||||
target="_blank"
|
<span v-if="!mergedConfig.hideUserStats && !hideBio" class="dailyAvg">{{ dailyAvg }} {{
|
||||||
class="button-unstyled external-link-button"
|
$t('user_card.per_day') }}</span>
|
||||||
>
|
</div>
|
||||||
<FAIcon
|
|
||||||
class="icon"
|
|
||||||
icon="external-link-alt"
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
v-if="isOtherUser"
|
|
||||||
:href="user.statusnet_profile_url + '.rss'"
|
|
||||||
target="_blank"
|
|
||||||
class="button-unstyled external-link-button"
|
|
||||||
>
|
|
||||||
<FAIcon
|
|
||||||
class="icon"
|
|
||||||
icon="rss"
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
<AccountActions
|
|
||||||
v-if="isOtherUser && loggedIn"
|
|
||||||
:user="user"
|
|
||||||
:relationship="relationship"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="bottom-line">
|
<div class="button-line">
|
||||||
<router-link
|
<button v-if="!isOtherUser && user.is_local" class="button-unstyled edit-profile-button"
|
||||||
class="user-screen-name"
|
@click.stop="openProfileTab">
|
||||||
:title="user.screen_name_ui"
|
<FAIcon fixed-width class="icon" icon="edit" :title="$t('user_card.edit_profile')" />
|
||||||
:to="userProfileLink(user)"
|
</button>
|
||||||
>
|
<a v-if="isOtherUser && !user.is_local" :href="user.statusnet_profile_url" target="_blank"
|
||||||
@{{ user.screen_name_ui }}
|
class="button-unstyled external-link-button" :title="$t('user_card.external_source')">
|
||||||
</router-link>
|
<FAIcon class="icon" icon="external-link-alt" />
|
||||||
<template v-if="!hideBio">
|
</a>
|
||||||
<span
|
<a v-if="fediLinkURL && showFediLinks && !hideBio" :href="fediLinkURL" target="_blank"
|
||||||
v-if="user.deactivated"
|
class="button-unstyled external-link-button" :title="$t('user_card.open_fedi_link')">
|
||||||
class="alert user-role"
|
<FAIcon class="icon" :icon="['fac', 'activity-pub']" />
|
||||||
>
|
</a>
|
||||||
{{ $t('user_card.deactivated') }}
|
<a v-if="isOtherUser" :href="user.statusnet_profile_url + '.rss'" target="_blank"
|
||||||
</span>
|
class="button-unstyled external-link-button">
|
||||||
<span
|
<FAIcon class="icon" icon="rss" />
|
||||||
v-if="!!visibleRole"
|
</a>
|
||||||
class="alert user-role"
|
<AccountActions v-if="isOtherUser && loggedIn" :user="user" :relationship="relationship" />
|
||||||
>
|
|
||||||
{{ $t(`general.role.${visibleRole}`) }}
|
|
||||||
</span>
|
|
||||||
<span
|
|
||||||
v-if="user.bot"
|
|
||||||
class="alert user-role"
|
|
||||||
>
|
|
||||||
{{ $t('user_card.bot') }}
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
<span v-if="user.locked">
|
|
||||||
<FAIcon
|
|
||||||
class="lock-icon"
|
|
||||||
icon="lock"
|
|
||||||
size="sm"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
<span
|
|
||||||
v-if="!mergedConfig.hideUserStats && !hideBio"
|
|
||||||
class="dailyAvg"
|
|
||||||
>{{ dailyAvg }} {{ $t('user_card.per_day') }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="user-meta">
|
<div class="user-meta">
|
||||||
<div
|
<div v-if="relationship.blocked_by && loggedIn && isOtherUser" class="blocking">
|
||||||
v-if="relationship.blocked_by && loggedIn && isOtherUser"
|
|
||||||
class="blocking"
|
|
||||||
>
|
|
||||||
{{ $t('user_card.blocks_you') }}
|
{{ $t('user_card.blocks_you') }}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-if="relationship.followed_by && loggedIn && isOtherUser" class="following">
|
||||||
v-if="relationship.followed_by && loggedIn && isOtherUser"
|
|
||||||
class="following"
|
|
||||||
>
|
|
||||||
{{ $t('user_card.follows_you') }}
|
{{ $t('user_card.follows_you') }}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="relationship.requested_by && loggedIn && isOtherUser"
|
v-if="relationship.requested_by && loggedIn && isOtherUser"
|
||||||
class="requested_by"
|
class="requested_by"
|
||||||
|
style="white-space: nowrap;"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.requested_by') }}
|
{{ $t('user_card.requested_by') }}
|
||||||
|
<button
|
||||||
|
class="btn button-default"
|
||||||
|
:title="$t('tool_tip.accept_follow_request')"
|
||||||
|
@click="approveUser()"
|
||||||
|
>
|
||||||
|
<FAIcon
|
||||||
|
icon="check"
|
||||||
|
class="fa-scale-110 fa-old-padding follow-request-accept"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="btn button-default"
|
||||||
|
:title="$t('tool_tip.reject_follow_request')"
|
||||||
|
@click="denyUser()"
|
||||||
|
>
|
||||||
|
<FAIcon
|
||||||
|
icon="times"
|
||||||
|
class="fa-scale-110 fa-old-padding follow-request-reject"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-if="isOtherUser && (loggedIn || !switcher)" class="highlighter">
|
||||||
v-if="isOtherUser && (loggedIn || !switcher)"
|
|
||||||
class="highlighter"
|
|
||||||
>
|
|
||||||
<!-- id's need to be unique, otherwise vue confuses which user-card checkbox belongs to -->
|
<!-- id's need to be unique, otherwise vue confuses which user-card checkbox belongs to -->
|
||||||
<input
|
<input v-if="userHighlightType !== 'disabled'" :id="'userHighlightColorTx' + user.id"
|
||||||
v-if="userHighlightType !== 'disabled'"
|
v-model="userHighlightColor" class="userHighlightText" type="text">
|
||||||
:id="'userHighlightColorTx'+user.id"
|
<input v-if="userHighlightType !== 'disabled'" :id="'userHighlightColor' + user.id" v-model="userHighlightColor"
|
||||||
v-model="userHighlightColor"
|
class="userHighlightCl" type="color">
|
||||||
class="userHighlightText"
|
|
||||||
type="text"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
v-if="userHighlightType !== 'disabled'"
|
|
||||||
:id="'userHighlightColor'+user.id"
|
|
||||||
v-model="userHighlightColor"
|
|
||||||
class="userHighlightCl"
|
|
||||||
type="color"
|
|
||||||
>
|
|
||||||
{{ ' ' }}
|
{{ ' ' }}
|
||||||
<Select
|
<Select :id="'userHighlightSel' + user.id" v-model="userHighlightType" class="userHighlightSel">
|
||||||
:id="'userHighlightSel'+user.id"
|
|
||||||
v-model="userHighlightType"
|
|
||||||
class="userHighlightSel"
|
|
||||||
>
|
|
||||||
<option value="disabled">
|
<option value="disabled">
|
||||||
{{ $t('user_card.highlight.disabled') }}
|
{{ $t('user_card.highlight.disabled') }}
|
||||||
</option>
|
</option>
|
||||||
|
@ -185,144 +118,93 @@
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-if="loggedIn && isOtherUser" class="user-interactions">
|
||||||
v-if="loggedIn && isOtherUser"
|
|
||||||
class="user-interactions"
|
|
||||||
>
|
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<FollowButton
|
<FollowButton :relationship="relationship" :user="user" :disabled="relationship.blocked_by" />
|
||||||
:relationship="relationship"
|
|
||||||
:user="user"
|
|
||||||
:disabled="relationship.blocked_by"
|
|
||||||
/>
|
|
||||||
<template v-if="relationship.following">
|
<template v-if="relationship.following">
|
||||||
<ProgressButton
|
<ProgressButton v-if="!relationship.subscribing" class="btn button-default" :click="subscribeUser"
|
||||||
v-if="!relationship.subscribing"
|
:title="$t('user_card.subscribe')">
|
||||||
class="btn button-default"
|
|
||||||
:click="subscribeUser"
|
|
||||||
:title="$t('user_card.subscribe')"
|
|
||||||
>
|
|
||||||
<FAIcon icon="bell" />
|
<FAIcon icon="bell" />
|
||||||
</ProgressButton>
|
</ProgressButton>
|
||||||
<ProgressButton
|
<ProgressButton v-else class="btn button-default toggled" :click="unsubscribeUser"
|
||||||
v-else
|
:title="$t('user_card.unsubscribe')">
|
||||||
class="btn button-default toggled"
|
|
||||||
:click="unsubscribeUser"
|
|
||||||
:title="$t('user_card.unsubscribe')"
|
|
||||||
>
|
|
||||||
<FALayers>
|
<FALayers>
|
||||||
<FAIcon
|
<FAIcon icon="rss" transform="left-5 shrink-6 up-3 rotate-20" flip="horizontal" />
|
||||||
icon="rss"
|
<FAIcon icon="rss" transform="right-5 shrink-6 up-3 rotate-20" />
|
||||||
transform="left-5 shrink-6 up-3 rotate-20"
|
|
||||||
flip="horizontal"
|
|
||||||
/>
|
|
||||||
<FAIcon
|
|
||||||
icon="rss"
|
|
||||||
transform="right-5 shrink-6 up-3 rotate-20"
|
|
||||||
/>
|
|
||||||
<FAIcon icon="bell" />
|
<FAIcon icon="bell" />
|
||||||
</FALayers>
|
</FALayers>
|
||||||
</ProgressButton>
|
</ProgressButton>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button v-if="relationship.muting" class="btn button-default btn-block toggled" :disabled="user.deactivated"
|
||||||
v-if="relationship.muting"
|
@click="unmuteUser">
|
||||||
class="btn button-default btn-block toggled"
|
|
||||||
:disabled="user.deactivated"
|
|
||||||
@click="unmuteUser"
|
|
||||||
>
|
|
||||||
{{ $t('user_card.muted') }}
|
{{ $t('user_card.muted') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button v-else class="btn button-default btn-block" :disabled="user.deactivated" @click="muteUser">
|
||||||
v-else
|
|
||||||
class="btn button-default btn-block"
|
|
||||||
:disabled="user.deactivated"
|
|
||||||
@click="muteUser"
|
|
||||||
>
|
|
||||||
{{ $t('user_card.mute') }}
|
{{ $t('user_card.mute') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button class="btn button-default btn-block" :disabled="user.deactivated" @click="mentionUser">
|
||||||
class="btn button-default btn-block"
|
|
||||||
:disabled="user.deactivated"
|
|
||||||
@click="mentionUser"
|
|
||||||
>
|
|
||||||
{{ $t('user_card.mention') }}
|
{{ $t('user_card.mention') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<ModerationTools
|
<ModerationTools v-if="loggedIn.role === 'admin'" :user="user" />
|
||||||
v-if="loggedIn.role === 'admin'"
|
|
||||||
:user="user"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-if="!loggedIn && user.is_local" class="user-interactions">
|
||||||
v-if="!loggedIn && user.is_local"
|
|
||||||
class="user-interactions"
|
|
||||||
>
|
|
||||||
<RemoteFollow :user="user" />
|
<RemoteFollow :user="user" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-if="!hideBio" class="panel-body">
|
||||||
v-if="!hideBio"
|
<div v-if="!mergedConfig.hideUserStats && switcher" class="user-counts">
|
||||||
class="panel-body"
|
<div class="user-count" @click.prevent="setProfileView('statuses')">
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-if="!mergedConfig.hideUserStats && switcher"
|
|
||||||
class="user-counts"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="user-count"
|
|
||||||
@click.prevent="setProfileView('statuses')"
|
|
||||||
>
|
|
||||||
<h5>{{ $t('user_card.statuses') }}</h5>
|
<h5>{{ $t('user_card.statuses') }}</h5>
|
||||||
<span>{{ user.statuses_count }} <br></span>
|
<span>{{ user.statuses_count }} <br></span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="user-count" @click.prevent="setProfileView('friends')">
|
||||||
class="user-count"
|
|
||||||
@click.prevent="setProfileView('friends')"
|
|
||||||
>
|
|
||||||
<h5>{{ $t('user_card.followees') }}</h5>
|
<h5>{{ $t('user_card.followees') }}</h5>
|
||||||
<span>{{ hideFollowsCount ? $t('user_card.hidden') : user.friends_count }}</span>
|
<span>{{ hideFollowsCount ? $t('user_card.hidden') : user.friends_count }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="user-count" @click.prevent="setProfileView('followers')">
|
||||||
class="user-count"
|
|
||||||
@click.prevent="setProfileView('followers')"
|
|
||||||
>
|
|
||||||
<h5>{{ $t('user_card.followers') }}</h5>
|
<h5>{{ $t('user_card.followers') }}</h5>
|
||||||
<span>{{ hideFollowersCount ? $t('user_card.hidden') : user.followers_count }}</span>
|
<span>{{ hideFollowersCount ? $t('user_card.hidden') : user.followers_count }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<RichContent
|
<RichContent v-if="!hideBio" class="user-card-bio" :html="user.description_html" :emoji="user.emoji"
|
||||||
v-if="!hideBio"
|
:handle-links="true" />
|
||||||
class="user-card-bio"
|
|
||||||
:html="user.description_html"
|
|
||||||
:emoji="user.emoji"
|
|
||||||
:handle-links="true"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<teleport to="#modal">
|
<teleport to="#modal">
|
||||||
<confirm-modal
|
<confirm-modal v-if="showingConfirmMute" :title="$t('user_card.mute_confirm_title')"
|
||||||
v-if="showingConfirmMute"
|
|
||||||
:title="$t('user_card.mute_confirm_title')"
|
|
||||||
:confirm-text="$t('user_card.mute_confirm_accept_button')"
|
:confirm-text="$t('user_card.mute_confirm_accept_button')"
|
||||||
:cancel-text="$t('user_card.mute_confirm_cancel_button')"
|
:cancel-text="$t('user_card.mute_confirm_cancel_button')" @accepted="doMuteUser" @cancelled="hideConfirmMute">
|
||||||
@accepted="doMuteUser"
|
<i18n-t keypath="user_card.mute_confirm" tag="span">
|
||||||
@cancelled="hideConfirmMute"
|
|
||||||
>
|
|
||||||
<i18n-t
|
|
||||||
keypath="user_card.mute_confirm"
|
|
||||||
tag="span"
|
|
||||||
>
|
|
||||||
<template #user>
|
<template #user>
|
||||||
<span
|
<span v-text="user.screen_name_ui" />
|
||||||
v-text="user.screen_name_ui"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
</i18n-t>
|
</i18n-t>
|
||||||
</confirm-modal>
|
</confirm-modal>
|
||||||
|
<confirm-modal
|
||||||
|
v-if="showingApproveConfirmDialog"
|
||||||
|
:title="$t('user_card.approve_confirm_title')"
|
||||||
|
:confirm-text="$t('user_card.approve_confirm_accept_button')"
|
||||||
|
:cancel-text="$t('user_card.approve_confirm_cancel_button')"
|
||||||
|
@accepted="doApprove"
|
||||||
|
@cancelled="hideApproveConfirmDialog"
|
||||||
|
>
|
||||||
|
{{ $t('user_card.approve_confirm', { user: user.screen_name_ui }) }}
|
||||||
|
</confirm-modal>
|
||||||
|
<confirm-modal
|
||||||
|
v-if="showingDenyConfirmDialog"
|
||||||
|
:title="$t('user_card.deny_confirm_title')"
|
||||||
|
:confirm-text="$t('user_card.deny_confirm_accept_button')"
|
||||||
|
:cancel-text="$t('user_card.deny_confirm_cancel_button')"
|
||||||
|
@accepted="doDeny"
|
||||||
|
@cancelled="hideDenyConfirmDialog"
|
||||||
|
>
|
||||||
|
{{ $t('user_card.deny_confirm', { user: user.screen_name_ui }) }}
|
||||||
|
</confirm-modal>
|
||||||
</teleport>
|
</teleport>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -750,6 +750,7 @@
|
||||||
"show_panel_nav_shortcuts": "Show timeline navigation shortcuts at the top of the panel",
|
"show_panel_nav_shortcuts": "Show timeline navigation shortcuts at the top of the panel",
|
||||||
"show_scrollbars": "Show side column's scrollbars",
|
"show_scrollbars": "Show side column's scrollbars",
|
||||||
"show_wider_shortcuts": "Show wider gap between top panel shortcuts",
|
"show_wider_shortcuts": "Show wider gap between top panel shortcuts",
|
||||||
|
"show_fedi_links": "Show Fedi Links (web+ap URLs)",
|
||||||
"show_yous": "Show (You)s",
|
"show_yous": "Show (You)s",
|
||||||
"stop_gifs": "Pause animated images until you hover on them",
|
"stop_gifs": "Pause animated images until you hover on them",
|
||||||
"streaming": "Automatically show new posts when scrolled to the top",
|
"streaming": "Automatically show new posts when scrolled to the top",
|
||||||
|
@ -961,6 +962,7 @@
|
||||||
"bookmark": "Bookmark",
|
"bookmark": "Bookmark",
|
||||||
"collapse_attachments": "Collapse attachments",
|
"collapse_attachments": "Collapse attachments",
|
||||||
"copy_link": "Copy link to post",
|
"copy_link": "Copy link to post",
|
||||||
|
"copy_fedi_link": "Copy fedi link",
|
||||||
"delete": "Delete post",
|
"delete": "Delete post",
|
||||||
"delete_confirm": "Do you really want to delete this post?",
|
"delete_confirm": "Do you really want to delete this post?",
|
||||||
"delete_confirm_accept_button": "Yes, delete it",
|
"delete_confirm_accept_button": "Yes, delete it",
|
||||||
|
@ -972,6 +974,7 @@
|
||||||
"edited_at": "Edited {time}",
|
"edited_at": "Edited {time}",
|
||||||
"expand": "Expand",
|
"expand": "Expand",
|
||||||
"external_source": "External source",
|
"external_source": "External source",
|
||||||
|
"open_fedi_link": "Open fedi link",
|
||||||
"favorites": "Favorites",
|
"favorites": "Favorites",
|
||||||
"hide_attachment": "Hide attachment",
|
"hide_attachment": "Hide attachment",
|
||||||
"hide_content": "Hide content",
|
"hide_content": "Hide content",
|
||||||
|
@ -1138,6 +1141,7 @@
|
||||||
"deny_confirm_title": "Deny follow request",
|
"deny_confirm_title": "Deny follow request",
|
||||||
"domain_muted": "Unblock domain",
|
"domain_muted": "Unblock domain",
|
||||||
"edit_profile": "Edit profile",
|
"edit_profile": "Edit profile",
|
||||||
|
"external_source": "External source",
|
||||||
"favorites": "Favorites",
|
"favorites": "Favorites",
|
||||||
"follow": "Follow",
|
"follow": "Follow",
|
||||||
"follow_cancel": "Cancel request",
|
"follow_cancel": "Cancel request",
|
||||||
|
@ -1171,6 +1175,7 @@
|
||||||
"mute_progress": "Muting…",
|
"mute_progress": "Muting…",
|
||||||
"muted": "Muted",
|
"muted": "Muted",
|
||||||
"note": "Private note",
|
"note": "Private note",
|
||||||
|
"open_fedi_link": "Open fedi link",
|
||||||
"per_day": "per day",
|
"per_day": "per day",
|
||||||
"remote_follow": "Remote follow",
|
"remote_follow": "Remote follow",
|
||||||
"remove_follower": "Remove follower",
|
"remove_follower": "Remove follower",
|
||||||
|
|
|
@ -41,6 +41,7 @@ export const defaultState = {
|
||||||
showNavShortcuts: undefined, // instance default
|
showNavShortcuts: undefined, // instance default
|
||||||
showPanelNavShortcuts: undefined, // instance default
|
showPanelNavShortcuts: undefined, // instance default
|
||||||
showWiderShortcuts: undefined, // instance default
|
showWiderShortcuts: undefined, // instance default
|
||||||
|
showFediLinks: true,
|
||||||
hideSiteFavicon: undefined, // instance default
|
hideSiteFavicon: undefined, // instance default
|
||||||
hideSiteName: undefined, // instance default
|
hideSiteName: undefined, // instance default
|
||||||
hideAttachments: false,
|
hideAttachments: false,
|
||||||
|
|
|
@ -54,6 +54,26 @@ const unblockUser = (store, id) => {
|
||||||
.then((relationship) => store.commit('updateUserRelationship', [relationship]))
|
.then((relationship) => store.commit('updateUserRelationship', [relationship]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const approveUser = (store, id) => {
|
||||||
|
const predictedRelationship = store.state.relationships[id] || { id }
|
||||||
|
predictedRelationship.requested_by = false
|
||||||
|
predictedRelationship.followed_by = true
|
||||||
|
store.commit('updateUserRelationship', [predictedRelationship])
|
||||||
|
|
||||||
|
return store.rootState.api.backendInteractor.approveUser({ id })
|
||||||
|
.then((relationship) => store.commit('updateUserRelationship', [relationship]))
|
||||||
|
}
|
||||||
|
|
||||||
|
const denyUser = (store, id) => {
|
||||||
|
const predictedRelationship = store.state.relationships[id] || { id }
|
||||||
|
predictedRelationship.requested_by = false
|
||||||
|
predictedRelationship.followed_by = false
|
||||||
|
store.commit('updateUserRelationship', [predictedRelationship])
|
||||||
|
|
||||||
|
return store.rootState.api.backendInteractor.denyUser({ id })
|
||||||
|
.then((relationship) => store.commit('updateUserRelationship', [relationship]))
|
||||||
|
}
|
||||||
|
|
||||||
const removeUserFromFollowers = (store, id) => {
|
const removeUserFromFollowers = (store, id) => {
|
||||||
return store.rootState.api.backendInteractor.removeUserFromFollowers({ id })
|
return store.rootState.api.backendInteractor.removeUserFromFollowers({ id })
|
||||||
.then((relationship) => store.commit('updateUserRelationship', [relationship]))
|
.then((relationship) => store.commit('updateUserRelationship', [relationship]))
|
||||||
|
@ -344,6 +364,12 @@ const users = {
|
||||||
unblockUser (store, id) {
|
unblockUser (store, id) {
|
||||||
return unblockUser(store, id)
|
return unblockUser(store, id)
|
||||||
},
|
},
|
||||||
|
approveUser (store, id) {
|
||||||
|
return approveUser(store, id)
|
||||||
|
},
|
||||||
|
denyUser (store, id) {
|
||||||
|
return denyUser(store, id)
|
||||||
|
},
|
||||||
removeUserFromFollowers (store, id) {
|
removeUserFromFollowers (store, id) {
|
||||||
return removeUserFromFollowers(store, id)
|
return removeUserFromFollowers(store, id)
|
||||||
},
|
},
|
||||||
|
|
|
@ -316,6 +316,7 @@ export const parseStatus = (data) => {
|
||||||
|
|
||||||
output.summary_raw_html = escape(data.spoiler_text)
|
output.summary_raw_html = escape(data.spoiler_text)
|
||||||
output.external_url = data.url
|
output.external_url = data.url
|
||||||
|
output.external_uri = data.uri
|
||||||
output.poll = data.poll
|
output.poll = data.poll
|
||||||
if (output.poll) {
|
if (output.poll) {
|
||||||
output.poll.options = (output.poll.options || []).map(field => ({
|
output.poll.options = (output.poll.options || []).map(field => ({
|
||||||
|
|
|
@ -4,11 +4,14 @@ export const newExporter = ({
|
||||||
}) => ({
|
}) => ({
|
||||||
exportData () {
|
exportData () {
|
||||||
const stringified = JSON.stringify(getExportedObject(), null, 2) // Pretty-print and indent with 2 spaces
|
const stringified = JSON.stringify(getExportedObject(), null, 2) // Pretty-print and indent with 2 spaces
|
||||||
|
const bytes = new TextEncoder().encode(stringified)
|
||||||
|
const ascii = Array.from(bytes, (x) => String.fromCodePoint(x)).join("")
|
||||||
|
const data = window.btoa(ascii)
|
||||||
|
|
||||||
// Create an invisible link with a data url and simulate a click
|
// Create an invisible link with a data url and simulate a click
|
||||||
const e = document.createElement('a')
|
const e = document.createElement('a')
|
||||||
e.setAttribute('download', `${filename}.json`)
|
e.setAttribute('download', `${filename}.json`)
|
||||||
e.setAttribute('href', 'data:application/json;base64,' + window.btoa(stringified))
|
e.setAttribute('href', 'data:application/json;base64,' + data)
|
||||||
e.style.display = 'none'
|
e.style.display = 'none'
|
||||||
|
|
||||||
document.body.appendChild(e)
|
document.body.appendChild(e)
|
||||||
|
@ -33,7 +36,9 @@ export const newImporter = ({
|
||||||
const reader = new FileReader()
|
const reader = new FileReader()
|
||||||
reader.onload = ({ target }) => {
|
reader.onload = ({ target }) => {
|
||||||
try {
|
try {
|
||||||
const parsed = JSON.parse(target.result)
|
const bytes = Uint8Array.from(target.result, (x) => x.codePointAt(0))
|
||||||
|
const data = new TextDecoder().decode(bytes)
|
||||||
|
const parsed = JSON.parse(data)
|
||||||
const validationResult = validator(parsed)
|
const validationResult = validator(parsed)
|
||||||
if (validationResult === true) {
|
if (validationResult === true) {
|
||||||
onImport(parsed)
|
onImport(parsed)
|
||||||
|
|
Loading…
Reference in a new issue