editable meta and bdey
This commit is contained in:
parent
51eb61180d
commit
2df895ab02
9 changed files with 343 additions and 137 deletions
|
|
@ -115,6 +115,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
.emoji-picker-icon {
|
.emoji-picker-icon {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
import unescape from 'lodash/unescape'
|
import unescape from 'lodash/unescape'
|
||||||
import merge from 'lodash/merge'
|
import merge from 'lodash/merge'
|
||||||
|
import UserCard from 'src/components/user_card/user_card.vue'
|
||||||
import ImageCropper from 'src/components/image_cropper/image_cropper.vue'
|
import ImageCropper from 'src/components/image_cropper/image_cropper.vue'
|
||||||
import ScopeSelector from 'src/components/scope_selector/scope_selector.vue'
|
import ScopeSelector from 'src/components/scope_selector/scope_selector.vue'
|
||||||
import fileSizeFormatService from 'src/components/../services/file_size_format/file_size_format.js'
|
import fileSizeFormatService from 'src/components/../services/file_size_format/file_size_format.js'
|
||||||
import ProgressButton from 'src/components/progress_button/progress_button.vue'
|
import ProgressButton from 'src/components/progress_button/progress_button.vue'
|
||||||
import EmojiInput from 'src/components/emoji_input/emoji_input.vue'
|
import EmojiInput from 'src/components/emoji_input/emoji_input.vue'
|
||||||
import suggestor from 'src/components/emoji_input/suggestor.js'
|
import suggestor from 'src/components/emoji_input/suggestor.js'
|
||||||
import Autosuggest from 'src/components/autosuggest/autosuggest.vue'
|
|
||||||
import Checkbox from 'src/components/checkbox/checkbox.vue'
|
import Checkbox from 'src/components/checkbox/checkbox.vue'
|
||||||
import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue'
|
import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue'
|
||||||
import Select from 'src/components/select/select.vue'
|
import Select from 'src/components/select/select.vue'
|
||||||
|
|
@ -53,10 +53,10 @@ const ProfileTab = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
UserCard,
|
||||||
ScopeSelector,
|
ScopeSelector,
|
||||||
ImageCropper,
|
ImageCropper,
|
||||||
EmojiInput,
|
EmojiInput,
|
||||||
Autosuggest,
|
|
||||||
ProgressButton,
|
ProgressButton,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
BooleanSetting,
|
BooleanSetting,
|
||||||
|
|
@ -88,12 +88,6 @@ const ProfileTab = {
|
||||||
userSuggestor () {
|
userSuggestor () {
|
||||||
return suggestor({ store: this.$store })
|
return suggestor({ store: this.$store })
|
||||||
},
|
},
|
||||||
fieldsLimits () {
|
|
||||||
return this.$store.state.instance.fieldsLimits
|
|
||||||
},
|
|
||||||
maxFields () {
|
|
||||||
return this.fieldsLimits ? this.fieldsLimits.maxFields : 0
|
|
||||||
},
|
|
||||||
defaultAvatar () {
|
defaultAvatar () {
|
||||||
return this.$store.state.instance.server + this.$store.state.instance.defaultAvatar
|
return this.$store.state.instance.server + this.$store.state.instance.defaultAvatar
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -125,9 +125,4 @@
|
||||||
padding: 0 0.5em;
|
padding: 0 0.5em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.birthday-input {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,12 @@
|
||||||
<div class="profile-tab">
|
<div class="profile-tab">
|
||||||
<div class="setting-item">
|
<div class="setting-item">
|
||||||
<h2>{{ $t('settings.name_bio') }}</h2>
|
<h2>{{ $t('settings.name_bio') }}</h2>
|
||||||
|
<UserCard
|
||||||
|
:user-id="user.id"
|
||||||
|
:editable="true"
|
||||||
|
:switcher="false"
|
||||||
|
rounded="top"
|
||||||
|
/>
|
||||||
<p>{{ $t('settings.name') }}</p>
|
<p>{{ $t('settings.name') }}</p>
|
||||||
<EmojiInput
|
<EmojiInput
|
||||||
v-model="newName"
|
v-model="newName"
|
||||||
|
|
@ -41,75 +47,6 @@
|
||||||
</template>
|
</template>
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
</p>
|
</p>
|
||||||
<div>
|
|
||||||
<p>{{ $t('settings.birthday.label') }}</p>
|
|
||||||
<input
|
|
||||||
id="birthday"
|
|
||||||
v-model="newBirthday"
|
|
||||||
type="date"
|
|
||||||
class="input birthday-input"
|
|
||||||
>
|
|
||||||
<Checkbox v-model="showBirthday">
|
|
||||||
{{ $t('settings.birthday.show_birthday') }}
|
|
||||||
</Checkbox>
|
|
||||||
</div>
|
|
||||||
<div v-if="maxFields > 0">
|
|
||||||
<p>{{ $t('settings.profile_fields.label') }}</p>
|
|
||||||
<div
|
|
||||||
v-for="(_, i) in newFields"
|
|
||||||
:key="i"
|
|
||||||
class="profile-fields"
|
|
||||||
>
|
|
||||||
<EmojiInput
|
|
||||||
v-model="newFields[i].name"
|
|
||||||
enable-emoji-picker
|
|
||||||
hide-emoji-button
|
|
||||||
:suggest="userSuggestor"
|
|
||||||
>
|
|
||||||
<template #default="inputProps">
|
|
||||||
<input
|
|
||||||
v-model="newFields[i].name"
|
|
||||||
:placeholder="$t('settings.profile_fields.name')"
|
|
||||||
v-bind="propsToNative(inputProps)"
|
|
||||||
class="input"
|
|
||||||
>
|
|
||||||
</template>
|
|
||||||
</EmojiInput>
|
|
||||||
<EmojiInput
|
|
||||||
v-model="newFields[i].value"
|
|
||||||
enable-emoji-picker
|
|
||||||
hide-emoji-button
|
|
||||||
:suggest="userSuggestor"
|
|
||||||
>
|
|
||||||
<template #default="inputProps">
|
|
||||||
<input
|
|
||||||
v-model="newFields[i].value"
|
|
||||||
:placeholder="$t('settings.profile_fields.value')"
|
|
||||||
v-bind="propsToNative(inputProps)"
|
|
||||||
class="input"
|
|
||||||
>
|
|
||||||
</template>
|
|
||||||
</EmojiInput>
|
|
||||||
<button
|
|
||||||
class="delete-field button-unstyled -hover-highlight"
|
|
||||||
@click="deleteField(i)"
|
|
||||||
>
|
|
||||||
<!-- TODO something is wrong with v-show here -->
|
|
||||||
<FAIcon
|
|
||||||
v-if="newFields.length > 1"
|
|
||||||
icon="times"
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
v-if="newFields.length < maxFields"
|
|
||||||
class="add-field faint button-unstyled -hover-highlight"
|
|
||||||
@click="addField"
|
|
||||||
>
|
|
||||||
<FAIcon icon="plus" />
|
|
||||||
{{ $t("settings.profile_fields.add_field") }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<p>
|
<p>
|
||||||
<label>
|
<label>
|
||||||
{{ $t('settings.actor_type') }}
|
{{ $t('settings.actor_type') }}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
import merge from 'lodash/merge'
|
||||||
|
import unescape from 'lodash/unescape'
|
||||||
|
|
||||||
import ColorInput from 'src/components/color_input/color_input.vue'
|
import ColorInput from 'src/components/color_input/color_input.vue'
|
||||||
import UserAvatar from '../user_avatar/user_avatar.vue'
|
import UserAvatar from '../user_avatar/user_avatar.vue'
|
||||||
import RemoteFollow from '../remote_follow/remote_follow.vue'
|
import RemoteFollow from '../remote_follow/remote_follow.vue'
|
||||||
|
|
@ -10,11 +13,17 @@ import Select from '../select/select.vue'
|
||||||
import UserLink from '../user_link/user_link.vue'
|
import UserLink from '../user_link/user_link.vue'
|
||||||
import RichContent from 'src/components/rich_content/rich_content.jsx'
|
import RichContent from 'src/components/rich_content/rich_content.jsx'
|
||||||
import UserTimedFilterModal from 'src/components/user_timed_filter_modal/user_timed_filter_modal.vue'
|
import UserTimedFilterModal from 'src/components/user_timed_filter_modal/user_timed_filter_modal.vue'
|
||||||
|
import Checkbox from 'src/components/checkbox/checkbox.vue'
|
||||||
|
import EmojiInput from 'src/components/emoji_input/emoji_input.vue'
|
||||||
|
|
||||||
import localeService from 'src/services/locale/locale.service.js'
|
import localeService from 'src/services/locale/locale.service.js'
|
||||||
|
import suggestor from 'src/components/emoji_input/suggestor.js'
|
||||||
|
|
||||||
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 { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
import { usePostStatusStore } from 'src/stores/post_status'
|
import { usePostStatusStore } from 'src/stores/post_status'
|
||||||
|
import { propsToNative } from 'src/services/attributes_helper/attributes_helper.service.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import {
|
import {
|
||||||
faBell,
|
faBell,
|
||||||
|
|
@ -24,13 +33,15 @@ import {
|
||||||
faEdit,
|
faEdit,
|
||||||
faTimes,
|
faTimes,
|
||||||
faExpandAlt,
|
faExpandAlt,
|
||||||
faBirthdayCake
|
faBirthdayCake,
|
||||||
|
faSave
|
||||||
} from '@fortawesome/free-solid-svg-icons'
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
||||||
import { useMediaViewerStore } from '../../stores/media_viewer'
|
import { useMediaViewerStore } from '../../stores/media_viewer'
|
||||||
import { useInterfaceStore } from '../../stores/interface'
|
import { useInterfaceStore } from '../../stores/interface'
|
||||||
|
|
||||||
library.add(
|
library.add(
|
||||||
|
faSave,
|
||||||
faRss,
|
faRss,
|
||||||
faBell,
|
faBell,
|
||||||
faSearchPlus,
|
faSearchPlus,
|
||||||
|
|
@ -43,6 +54,7 @@ library.add(
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: [
|
props: [
|
||||||
|
'editable',
|
||||||
'userId',
|
'userId',
|
||||||
'switcher',
|
'switcher',
|
||||||
'selected',
|
'selected',
|
||||||
|
|
@ -55,6 +67,7 @@ export default {
|
||||||
],
|
],
|
||||||
components: {
|
components: {
|
||||||
UserAvatar,
|
UserAvatar,
|
||||||
|
Checkbox,
|
||||||
RemoteFollow,
|
RemoteFollow,
|
||||||
ModerationTools,
|
ModerationTools,
|
||||||
AccountActions,
|
AccountActions,
|
||||||
|
|
@ -65,13 +78,27 @@ export default {
|
||||||
UserLink,
|
UserLink,
|
||||||
UserNote,
|
UserNote,
|
||||||
UserTimedFilterModal,
|
UserTimedFilterModal,
|
||||||
ColorInput
|
ColorInput,
|
||||||
|
EmojiInput
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
|
const user = this.$store.state.users.currentUser
|
||||||
|
|
||||||
return {
|
return {
|
||||||
followRequestInProgress: false,
|
followRequestInProgress: false,
|
||||||
muteExpiryAmount: 0,
|
muteExpiryAmount: 0,
|
||||||
muteExpiryUnit: 'minutes'
|
muteExpiryUnit: 'minutes',
|
||||||
|
|
||||||
|
// Editable stuff
|
||||||
|
newName: user.name_unescaped,
|
||||||
|
newActorType: user.actor_type,
|
||||||
|
newBio: unescape(user.description),
|
||||||
|
newBirthday: user.birthday,
|
||||||
|
newShowBirthday: user.show_birthday,
|
||||||
|
newFields: user.fields.map(field => ({ name: field.name, value: field.value })),
|
||||||
|
editingFields: false,
|
||||||
|
newLocked: user.locked,
|
||||||
|
newShowRole: user.show_role,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created () {
|
created () {
|
||||||
|
|
@ -114,6 +141,13 @@ export default {
|
||||||
const days = Math.ceil((new Date() - new Date(this.user.created_at)) / (60 * 60 * 24 * 1000))
|
const days = Math.ceil((new Date() - new Date(this.user.created_at)) / (60 * 60 * 24 * 1000))
|
||||||
return Math.round(this.user.statuses_count / days)
|
return Math.round(this.user.statuses_count / days)
|
||||||
},
|
},
|
||||||
|
emoji () {
|
||||||
|
return this.$store.state.instance.customEmoji.map(e => ({
|
||||||
|
shortcode: e.displayText,
|
||||||
|
static_url: e.imageUrl,
|
||||||
|
url: e.imageUrl
|
||||||
|
}))
|
||||||
|
},
|
||||||
userHighlightType: {
|
userHighlightType: {
|
||||||
get () {
|
get () {
|
||||||
const data = this.$store.getters.mergedConfig.highlight[this.user.screen_name]
|
const data = this.$store.getters.mergedConfig.highlight[this.user.screen_name]
|
||||||
|
|
@ -184,6 +218,31 @@ export default {
|
||||||
const browserLocale = localeService.internalToBrowserLocale(this.$i18n.locale)
|
const browserLocale = localeService.internalToBrowserLocale(this.$i18n.locale)
|
||||||
return this.user.birthday && new Date(Date.parse(this.user.birthday)).toLocaleDateString(browserLocale, { timeZone: 'UTC', day: 'numeric', month: 'long', year: 'numeric' })
|
return this.user.birthday && new Date(Date.parse(this.user.birthday)).toLocaleDateString(browserLocale, { timeZone: 'UTC', day: 'numeric', month: 'long', year: 'numeric' })
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Editable stuff
|
||||||
|
fieldsLimits () {
|
||||||
|
return this.$store.state.instance.fieldsLimits
|
||||||
|
},
|
||||||
|
maxFields () {
|
||||||
|
return this.fieldsLimits ? this.fieldsLimits.maxFields : 0
|
||||||
|
},
|
||||||
|
emojiUserSuggestor () {
|
||||||
|
return suggestor({
|
||||||
|
emoji: [
|
||||||
|
...this.$store.getters.standardEmojiList,
|
||||||
|
...this.$store.state.instance.customEmoji
|
||||||
|
],
|
||||||
|
store: this.$store
|
||||||
|
})
|
||||||
|
},
|
||||||
|
emojiSuggestor () {
|
||||||
|
return suggestor({
|
||||||
|
emoji: [
|
||||||
|
...this.$store.getters.standardEmojiList,
|
||||||
|
...this.$store.state.instance.customEmoji
|
||||||
|
]
|
||||||
|
})
|
||||||
|
},
|
||||||
...mapGetters(['mergedConfig'])
|
...mapGetters(['mergedConfig'])
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
@ -238,6 +297,48 @@ export default {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
this.onAvatarClick()
|
this.onAvatarClick()
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
|
// Editable stuff
|
||||||
|
addField () {
|
||||||
|
if (this.newFields.length < this.maxFields) {
|
||||||
|
this.newFields.push({ name: '', value: '' })
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
deleteField (index) {
|
||||||
|
this.newFields.splice(index, 1)
|
||||||
|
},
|
||||||
|
propsToNative (props) {
|
||||||
|
return propsToNative(props)
|
||||||
|
},
|
||||||
|
updateProfile () {
|
||||||
|
const params = {
|
||||||
|
note: this.newBio,
|
||||||
|
locked: this.newLocked,
|
||||||
|
|
||||||
|
// Backend notation.
|
||||||
|
display_name: this.newName,
|
||||||
|
fields_attributes: this.newFields.filter(el => el != null),
|
||||||
|
actor_type: this.actorType,
|
||||||
|
show_role: this.showRole,
|
||||||
|
birthday: this.newBirthday || '',
|
||||||
|
show_birthday: this.showBirthday
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.emailLanguage) {
|
||||||
|
params.language = localeService.internalToBackendLocaleMulti(this.emailLanguage)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$store.state.api.backendInteractor
|
||||||
|
.updateProfile({ params })
|
||||||
|
.then((user) => {
|
||||||
|
this.newFields.splice(user.fields.length)
|
||||||
|
merge(this.newFields, user.fields)
|
||||||
|
this.$store.commit('addNewUsers', [user])
|
||||||
|
this.$store.commit('setCurrentUser', user)
|
||||||
|
})
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,17 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
|
||||||
|
// editing headers
|
||||||
|
h4 {
|
||||||
|
line-height: 2;
|
||||||
|
display: flex;
|
||||||
|
padding: 0 1.0em;
|
||||||
|
|
||||||
|
span {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.user-card-inner {
|
.user-card-inner {
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
@ -179,6 +190,10 @@
|
||||||
padding: 0.6em;
|
padding: 0.6em;
|
||||||
margin: -0.6em;
|
margin: -0.6em;
|
||||||
|
|
||||||
|
&.save-profile-button {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
&:hover .icon {
|
&:hover .icon {
|
||||||
color: var(--textFaint);
|
color: var(--textFaint);
|
||||||
}
|
}
|
||||||
|
|
@ -400,37 +415,64 @@
|
||||||
.user-profile-fields {
|
.user-profile-fields {
|
||||||
margin: 0 0.5em;
|
margin: 0 0.5em;
|
||||||
|
|
||||||
|
--emoji-size: 1.8em;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
max-height: 400px;
|
max-height: 400px;
|
||||||
|
|
||||||
&.emoji {
|
|
||||||
width: 18px;
|
|
||||||
height: 18px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-profile-field-add,
|
||||||
.user-profile-field {
|
.user-profile-field {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
margin: 0.25em;
|
margin: 0.25em;
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
border-radius: var(--roundness);
|
border-radius: var(--roundness);
|
||||||
|
line-height: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-profile-field-add {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-profile-field {
|
||||||
|
.input {
|
||||||
|
text-align: inherit;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-field {
|
||||||
|
display: inline-block;
|
||||||
|
text-align: center;
|
||||||
|
width: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
.user-profile-field-name,
|
.user-profile-field-name,
|
||||||
.user-profile-field-value {
|
.user-profile-field-value,
|
||||||
|
.user-profile-field-add {
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
line-height: 2em;
|
display: inline-flex;
|
||||||
|
|
||||||
|
&.-edit {
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
input {
|
||||||
|
font-weight: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-profile-field-name {
|
.user-profile-field-name {
|
||||||
flex: 0 1 50%;
|
flex: 0 1 50%;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
justify-content: end;
|
||||||
color: var(--lightText);
|
color: var(--lightText);
|
||||||
min-width: 9em;
|
min-width: 9em;
|
||||||
border-right: 1px solid var(--border);
|
border-right: 1px solid var(--border);
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,19 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
<button
|
||||||
|
v-else-if="editable"
|
||||||
|
class="user-info-avatar button-unstyled -link"
|
||||||
|
@click="editAvatar"
|
||||||
|
>
|
||||||
|
<UserAvatar :user="user" />
|
||||||
|
<div class="user-info-avatar -link -overlay">
|
||||||
|
<FAIcon
|
||||||
|
class="fa-scale-110 fa-old-padding"
|
||||||
|
icon="pencil"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
<UserAvatar
|
<UserAvatar
|
||||||
v-else-if="typeof avatarAction === 'function'"
|
v-else-if="typeof avatarAction === 'function'"
|
||||||
class="user-info-avatar"
|
class="user-info-avatar"
|
||||||
|
|
@ -42,9 +55,25 @@
|
||||||
</router-link>
|
</router-link>
|
||||||
<div class="user-summary">
|
<div class="user-summary">
|
||||||
<div class="top-line">
|
<div class="top-line">
|
||||||
<div class="other-actions">
|
<div
|
||||||
|
class="other-actions"
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
v-if="!isOtherUser && user.is_local"
|
v-if="editable"
|
||||||
|
:disabled="newName && newName.length === 0"
|
||||||
|
class="btn button-unstyled save-profile-button"
|
||||||
|
@click="updateProfile"
|
||||||
|
>
|
||||||
|
{{ $t('settings.save') }}
|
||||||
|
<FAIcon
|
||||||
|
fixed-width
|
||||||
|
class="icon"
|
||||||
|
icon="save"
|
||||||
|
:title="$t('user_card.edit_profile')"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
v-else-if="!editable && !isOtherUser && user.is_local"
|
||||||
class="button-unstyled edit-profile-button"
|
class="button-unstyled edit-profile-button"
|
||||||
@click.stop="openProfileTab"
|
@click.stop="openProfileTab"
|
||||||
>
|
>
|
||||||
|
|
@ -100,7 +129,7 @@
|
||||||
<RichContent
|
<RichContent
|
||||||
:title="user.name"
|
:title="user.name"
|
||||||
:html="user.name"
|
:html="user.name"
|
||||||
:emoji="user.emoji"
|
:emoji="editable ? emoji : user.emoji"
|
||||||
/>
|
/>
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -166,7 +195,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="loggedIn && isOtherUser"
|
v-if="!editable && loggedIn && isOtherUser"
|
||||||
class="user-interactions"
|
class="user-interactions"
|
||||||
>
|
>
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
|
|
@ -242,7 +271,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="loggedIn && isOtherUser && (hasNote || !hideBio) && !mergedConfig.userCardHidePersonalMarks"
|
v-if="!editable && loggedIn && isOtherUser && (hasNote || !hideBio) && !mergedConfig.userCardHidePersonalMarks"
|
||||||
class="personal-marks"
|
class="personal-marks"
|
||||||
>
|
>
|
||||||
<UserNote
|
<UserNote
|
||||||
|
|
@ -291,44 +320,127 @@
|
||||||
class="user-card-bio"
|
class="user-card-bio"
|
||||||
:class="{ '-justify-left': mergedConfig.userCardLeftJustify }"
|
:class="{ '-justify-left': mergedConfig.userCardLeftJustify }"
|
||||||
:html="user.description_html"
|
:html="user.description_html"
|
||||||
:emoji="user.emoji"
|
:emoji="editable ? emoji : user.emoji"
|
||||||
:handle-links="true"
|
:handle-links="true"
|
||||||
/>
|
/>
|
||||||
<div
|
<h4 v-if="editable">
|
||||||
v-if="!hideBio && user.fields_html && user.fields_html.length > 0"
|
<span>
|
||||||
class="user-profile-fields"
|
{{ $t('settings.profile_fields.label') }}
|
||||||
>
|
</span>
|
||||||
<dl
|
<button
|
||||||
v-for="(field, index) in user.fields_html"
|
class="button-default"
|
||||||
:key="index"
|
@click="editingFields = !editingFields"
|
||||||
class="user-profile-field"
|
|
||||||
>
|
>
|
||||||
<dt
|
{{ $t('settings.toggle_edit') }}
|
||||||
:title="user.fields_text[index].name"
|
</button>
|
||||||
class="user-profile-field-name"
|
</h4>
|
||||||
|
<template v-if="!editable || !editingFields">
|
||||||
|
<div
|
||||||
|
v-if="!hideBio && user.fields_html && user.fields_html.length > 0"
|
||||||
|
class="user-profile-fields"
|
||||||
|
>
|
||||||
|
<dl
|
||||||
|
v-for="(field, index) in newFields"
|
||||||
|
:key="index"
|
||||||
|
class="user-profile-field"
|
||||||
>
|
>
|
||||||
<RichContent
|
<dt
|
||||||
:html="field.name"
|
:title="field.name"
|
||||||
:emoji="user.emoji"
|
class="user-profile-field-name"
|
||||||
/>
|
>
|
||||||
</dt>
|
<RichContent
|
||||||
<dd
|
:html="field.name"
|
||||||
:title="user.fields_text[index].value"
|
:emoji="editable ? emoji : user.emoji"
|
||||||
class="user-profile-field-value"
|
/>
|
||||||
|
</dt>
|
||||||
|
<dd
|
||||||
|
:title="field.value"
|
||||||
|
class="user-profile-field-value"
|
||||||
|
>
|
||||||
|
<RichContent
|
||||||
|
:html="field.value"
|
||||||
|
:emoji="editable ? emoji : user.emoji"
|
||||||
|
/>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="editingFields">
|
||||||
|
<div
|
||||||
|
v-if="maxFields > 0"
|
||||||
|
class="user-profile-fields"
|
||||||
|
>
|
||||||
|
<dl
|
||||||
|
v-for="(_, i) in newFields"
|
||||||
|
:key="i"
|
||||||
|
class="user-profile-field"
|
||||||
>
|
>
|
||||||
<RichContent
|
<dt
|
||||||
:html="field.value"
|
class="user-profile-field-name -edit"
|
||||||
:emoji="user.emoji"
|
>
|
||||||
/>
|
<EmojiInput
|
||||||
</dd>
|
v-model="newFields[i].name"
|
||||||
</dl>
|
enable-emoji-picker
|
||||||
</div>
|
:suggest="emojiSuggestor"
|
||||||
|
>
|
||||||
|
<template #default="inputProps">
|
||||||
|
<input
|
||||||
|
v-model="newFields[i].name"
|
||||||
|
:placeholder="$t('settings.profile_fields.name')"
|
||||||
|
v-bind="propsToNative(inputProps)"
|
||||||
|
class="input"
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</EmojiInput>
|
||||||
|
</dt>
|
||||||
|
<dd
|
||||||
|
class="user-profile-field-value -edit"
|
||||||
|
>
|
||||||
|
<EmojiInput
|
||||||
|
v-model="newFields[i].value"
|
||||||
|
enable-emoji-picker
|
||||||
|
:suggest="emojiSuggestor"
|
||||||
|
>
|
||||||
|
<template #default="inputProps">
|
||||||
|
<input
|
||||||
|
v-model="newFields[i].value"
|
||||||
|
:placeholder="$t('settings.profile_fields.value')"
|
||||||
|
v-bind="propsToNative(inputProps)"
|
||||||
|
class="input input"
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</EmojiInput>
|
||||||
|
<button
|
||||||
|
class="delete-field button-unstyled -hover-highlight"
|
||||||
|
@click="deleteField(i)"
|
||||||
|
>
|
||||||
|
<!-- TODO something is wrong with v-show here -->
|
||||||
|
<FAIcon
|
||||||
|
v-if="newFields.length > 1"
|
||||||
|
icon="times"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
<p class="user-profile-field-add">
|
||||||
|
<button
|
||||||
|
v-if="newFields.length < maxFields"
|
||||||
|
class="add-field faint button-unstyled -hover-highlight"
|
||||||
|
@click="addField"
|
||||||
|
>
|
||||||
|
<FAIcon icon="plus" />
|
||||||
|
{{ ' ' }}
|
||||||
|
{{ $t("settings.profile_fields.add_field") }}
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
<div
|
<div
|
||||||
v-if="!hideBio"
|
|
||||||
class="user-extras"
|
class="user-extras"
|
||||||
|
v-if="!hideBio"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
v-if="!mergedConfig.hideUserStats"
|
v-if="!editable && !mergedConfig.hideUserStats"
|
||||||
class="user-stats"
|
class="user-stats"
|
||||||
>
|
>
|
||||||
<dl
|
<dl
|
||||||
|
|
@ -365,16 +477,38 @@
|
||||||
<dt>{{ $t('user_card.followers') }}</dt>
|
<dt>{{ $t('user_card.followers') }}</dt>
|
||||||
</dl>
|
</dl>
|
||||||
</span>
|
</span>
|
||||||
<div
|
<template v-if="!hideBio">
|
||||||
v-if="!hideBio && !!user.birthday"
|
<div
|
||||||
class="birthday"
|
v-if="user.birthday && !editable"
|
||||||
>
|
class="birthday"
|
||||||
<FAIcon
|
>
|
||||||
class="fa-old-padding"
|
<FAIcon
|
||||||
icon="birthday-cake"
|
class="fa-old-padding"
|
||||||
/>
|
icon="birthday-cake"
|
||||||
{{ $t('user_card.birthday', { birthday: formattedBirthday }) }}
|
/>
|
||||||
</div>
|
{{ $t('user_card.birthday', { birthday: formattedBirthday }) }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-else-if="editable"
|
||||||
|
class="birthday"
|
||||||
|
>
|
||||||
|
<FAIcon
|
||||||
|
class="fa-old-padding"
|
||||||
|
icon="birthday-cake"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
id="birthday"
|
||||||
|
v-model="newBirthday"
|
||||||
|
type="date"
|
||||||
|
class="input birthday-input"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<Checkbox v-model="showBirthday">
|
||||||
|
{{ $t('settings.birthday.show_birthday') }}
|
||||||
|
</Checkbox>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<teleport to="#modal">
|
<teleport to="#modal">
|
||||||
<UserTimedFilterModal
|
<UserTimedFilterModal
|
||||||
|
|
|
||||||
|
|
@ -394,6 +394,7 @@
|
||||||
"expert_mode": "Show advanced",
|
"expert_mode": "Show advanced",
|
||||||
"save": "Save changes",
|
"save": "Save changes",
|
||||||
"security": "Security",
|
"security": "Security",
|
||||||
|
"toggle_edit": "Toggle edit",
|
||||||
"setting_changed": "Setting is different from default",
|
"setting_changed": "Setting is different from default",
|
||||||
"setting_server_side": "This setting is tied to your profile and affects all sessions and clients",
|
"setting_server_side": "This setting is tied to your profile and affects all sessions and clients",
|
||||||
"enter_current_password_to_confirm": "Enter your current password to confirm your identity",
|
"enter_current_password_to_confirm": "Enter your current password to confirm your identity",
|
||||||
|
|
|
||||||
|
|
@ -139,6 +139,7 @@ const defaultState = {
|
||||||
|
|
||||||
// Nasty stuff
|
// Nasty stuff
|
||||||
customEmoji: [],
|
customEmoji: [],
|
||||||
|
rawCustomEmoji: [],
|
||||||
customEmojiFetched: false,
|
customEmojiFetched: false,
|
||||||
emoji: {},
|
emoji: {},
|
||||||
emojiFetched: false,
|
emojiFetched: false,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue