Merge branch 'profile-edit' into shigusegubu-themes3

This commit is contained in:
Henry Jameson 2025-08-08 10:18:02 +03:00
commit 651ce2080e
8 changed files with 159 additions and 107 deletions

View file

@ -45,10 +45,10 @@
inset: 0; inset: 0;
justify-content: center; justify-content: center;
place-items: center center; place-items: center center;
overflow: auto;
} }
.dialog-modal.panel { .dialog-modal.panel {
max-height: 80vh;
max-width: 90vw; max-width: 90vw;
z-index: 2001; z-index: 2001;
cursor: default; cursor: default;

View file

@ -13,7 +13,7 @@
v-if="!$store.state.users.currentUser.locked && newStatus.visibility == 'private' && !disableLockWarning" v-if="!$store.state.users.currentUser.locked && newStatus.visibility == 'private' && !disableLockWarning"
keypath="post_status.account_not_locked_warning" keypath="post_status.account_not_locked_warning"
tag="p" tag="p"
class="alert neutral" class="visibility-notice"
scope="global" scope="global"
> >
<button <button
@ -25,52 +25,52 @@
</i18n-t> </i18n-t>
<p <p
v-if="!hideScopeNotice && newStatus.visibility === 'public'" v-if="!hideScopeNotice && newStatus.visibility === 'public'"
class="alert neutral notice-dismissible" class="visibility-notice notice-dismissible"
> >
<span>{{ $t('post_status.scope_notice.public') }}</span> <span>{{ $t('post_status.scope_notice.public') }}</span>
<button <a
class="fa-scale-110 button-unstyled fa-old-padding dismiss" class="fa-scale-110 fa-old-padding dismiss"
:title="$t('post_status.scope_notice_dismiss')" :title="$t('post_status.scope_notice_dismiss')"
role="button" role="button"
tabindex="0" tabindex="0"
@click.prevent="dismissScopeNotice()" @click.prevent="dismissScopeNotice()"
> >
<FAIcon icon="times" /> <FAIcon icon="times" />
</button> </a>
</p> </p>
<p <p
v-else-if="!hideScopeNotice && newStatus.visibility === 'unlisted'" v-else-if="!hideScopeNotice && newStatus.visibility === 'unlisted'"
class="alert neutral notice-dismissible" class="visibility-notice notice-dismissible"
> >
<span>{{ $t('post_status.scope_notice.unlisted') }}</span> <span>{{ $t('post_status.scope_notice.unlisted') }}</span>
<button <a
class="fa-scale-110 button-unstyled fa-old-padding dismiss" class="fa-scale-110 fa-old-padding dismiss"
:title="$t('post_status.scope_notice_dismiss')" :title="$t('post_status.scope_notice_dismiss')"
role="button" role="button"
tabindex="0" tabindex="0"
@click.prevent="dismissScopeNotice()" @click.prevent="dismissScopeNotice()"
> >
<FAIcon icon="times" /> <FAIcon icon="times" />
</button> </a>
</p> </p>
<p <p
v-else-if="!hideScopeNotice && newStatus.visibility === 'private' && $store.state.users.currentUser.locked" v-else-if="!hideScopeNotice && newStatus.visibility === 'private' && $store.state.users.currentUser.locked"
class="alert neutral notice-dismissible" class="visibility-notice notice-dismissible"
> >
<span>{{ $t('post_status.scope_notice.private') }}</span> <span>{{ $t('post_status.scope_notice.private') }}</span>
<button <a
class="fa-scale-110 button-unstyled fa-old-padding dismiss" class="fa-scale-110 fa-old-padding dismiss"
:title="$t('post_status.scope_notice_dismiss')" :title="$t('post_status.scope_notice_dismiss')"
role="button" role="button"
tabindex="0" tabindex="0"
@click.prevent="dismissScopeNotice()" @click.prevent="dismissScopeNotice()"
> >
<FAIcon icon="times" /> <FAIcon icon="times" />
</button> </a>
</p> </p>
<p <p
v-else-if="newStatus.visibility === 'direct'" v-else-if="newStatus.visibility === 'direct'"
class="alert neutral" class="visibility-notice"
> >
<span v-if="safeDMEnabled">{{ $t('post_status.direct_warning_to_first_only') }}</span> <span v-if="safeDMEnabled">{{ $t('post_status.direct_warning_to_first_only') }}</span>
<span v-else>{{ $t('post_status.direct_warning_to_all') }}</span> <span v-else>{{ $t('post_status.direct_warning_to_all') }}</span>

View file

@ -412,6 +412,10 @@
display: flex; display: flex;
padding: 0; padding: 0;
margin: 0; margin: 0;
.user-info {
margin: 1em;
}
} }
.side-drawer ul { .side-drawer ul {

View file

@ -186,14 +186,6 @@ export default {
relationship () { relationship () {
return this.$store.getters.relationship(this.userId) return this.$store.getters.relationship(this.userId)
}, },
style () {
return {
backgroundImage: [
'linear-gradient(to bottom, var(--profileTint), var(--profileTint))',
`url(${this.bannerImgSrc})`
].join(', ')
}
},
isOtherUser () { isOtherUser () {
return this.user.id !== this.$store.state.users.currentUser.id return this.user.id !== this.$store.state.users.currentUser.id
}, },
@ -290,12 +282,14 @@ export default {
// Editable stuff // Editable stuff
avatarImgSrc () { avatarImgSrc () {
const currentUrl = this.user.profile_image_url_original || this.defaultAvatar const currentUrl = this.user.profile_image_url_original || this.defaultAvatar
const newUrl = this.newAvatar === '' ? this.defaultAvatar : this.newAvatar if (!this.editable) return currentUrl
const newUrl = this.newAvatar === null ? this.defaultAvatar : this.newAvatar
return (this.newAvatar === null) ? currentUrl : newUrl return (this.newAvatar === null) ? currentUrl : newUrl
}, },
bannerImgSrc () { bannerImgSrc () {
const currentUrl = this.user.cover_photo || this.defaultBanner const currentUrl = this.user.cover_photo || this.defaultBanner
const newUrl = this.newBanner === '' ? this.defaultBanner : this.newBanner if (!this.editable) return currentUrl
const newUrl = this.newBanner === null ? this.defaultBanner : this.newBanner
return (this.newBanner === null) ? currentUrl : newUrl return (this.newBanner === null) ? currentUrl : newUrl
}, },
defaultAvatar () { defaultAvatar () {
@ -419,11 +413,11 @@ export default {
}, },
resetImage () { resetImage () {
if (this.editImage === 'avatar') { if (this.editImage === 'avatar') {
this.newAvatar = '' this.newAvatar = null
this.newAvatarFile = '' this.newAvatarFile = null
} else { } else {
this.newBanner = '' this.newBanner = null
this.newBannerFile = '' this.newBannerFile = null
} }
this.editImage = false this.editImage = false
}, },
@ -438,6 +432,9 @@ export default {
propsToNative (props) { propsToNative (props) {
return propsToNative(props) return propsToNative(props)
}, },
cancelImageText () {
return
},
resetState () { resetState () {
const user = this.$store.state.users.currentUser const user = this.$store.state.users.currentUser

View file

@ -111,7 +111,8 @@
} }
} }
.background-image { .banner-overlay,
.banner-image {
position: absolute; position: absolute;
inset: 0; inset: 0;
right: -1.2em; right: -1.2em;
@ -119,11 +120,24 @@
top: -1.4em; top: -1.4em;
padding: 0; padding: 0;
mask: linear-gradient(to top, transparent 0, white 5em) bottom no-repeat; mask: linear-gradient(to top, transparent 0, white 5em) bottom no-repeat;
background-size: cover;
background-color: var(--profileBg);
border-top-left-radius: calc(var(--roundness) - 1px); border-top-left-radius: calc(var(--roundness) - 1px);
border-top-right-radius: calc(var(--roundness) - 1px); border-top-right-radius: calc(var(--roundness) - 1px);
}
.banner-image {
z-index: -2; z-index: -2;
img {
object-fit: cover;
height: 100%;
width: 100%;
}
}
.banner-overlay {
background-color: var(--profileTint);
pointer-events: none; // let user copy bg url
z-index: -1;
} }
.bottom-buttons { .bottom-buttons {
@ -491,6 +505,8 @@
.edit-image { .edit-image {
.panel-body { .panel-body {
text-align: center; text-align: center;
display: flex;
flex-direction: column;
} }
.current-avatar { .current-avatar {
@ -499,9 +515,19 @@
.image-container { .image-container {
display: flex; display: flex;
margin: 0 1em 0.5em; align-self: center;
margin: 0 0 1em;
max-height: 30em;
max-width: 100%;
flex: 1 0 20em;
aspect-ratio: 1;
gap: 0.5em; gap: 0.5em;
&.-banner {
aspect-ratio: 3;
max-width: 100%;
}
.new-image { .new-image {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -509,6 +535,7 @@
.cropper { .cropper {
flex: 1; flex: 1;
overflow-x: auto;
} }
> * { > * {
@ -546,4 +573,16 @@
aspect-ratio: unset; aspect-ratio: unset;
} }
} }
#modal.-mobile & {
#pick-image {
height: 3em;
}
.image-container {
&.-banner {
max-height: 10em;
}
}
}
} }

View file

@ -3,10 +3,15 @@
<div class="user-card-inner"> <div class="user-card-inner">
<div class="user-info"> <div class="user-info">
<div class="user-identity"> <div class="user-identity">
<div class="banner-image">
<img
:src="bannerImgSrc"
:class="{ 'hide-bio': hideBio }"
>
</div>
<div <div
class="banner-overlay"
:class="{ 'hide-bio': hideBio }" :class="{ 'hide-bio': hideBio }"
:style="style"
class="background-image"
/> />
<a <a
v-if="avatarAction === 'zoom'" v-if="avatarAction === 'zoom'"
@ -222,74 +227,72 @@
</div> </div>
</div> </div>
<div <div
v-if="loggedIn" v-if="loggedIn && isOtherUser"
class="user-interactions" class="user-interactions"
> >
<template v-if="isOtherUser"> <div class="btn-group">
<div class="btn-group"> <FollowButton
<FollowButton :relationship="relationship"
:relationship="relationship"
:user="user"
/>
<template v-if="relationship.following">
<ProgressButton
v-if="!relationship.notifying"
class="btn button-default"
:click="subscribeUser"
:title="$t('user_card.subscribe')"
>
<FAIcon icon="bell" />
</ProgressButton>
<ProgressButton
v-else
class="btn button-default toggled"
:click="unsubscribeUser"
:title="$t('user_card.unsubscribe')"
>
<FALayers>
<FAIcon
icon="rss"
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" />
</FALayers>
</ProgressButton>
</template>
</div>
<button
v-if="relationship.muting"
class="btn button-default btn-mute toggled"
:disabled="user.deactivated"
@click="unmuteUser"
>
{{ $t('user_card.muted') }}
</button>
<button
v-else
class="btn button-default btn-mute"
:disabled="user.deactivated"
@click="muteUser"
>
{{ $t('user_card.mute') }}
</button>
<button
class="btn button-default btn-mention"
:disabled="user.deactivated"
@click="mentionUser"
>
{{ $t('user_card.mention') }}
</button>
<ModerationTools
v-if="showModerationMenu"
class="moderation-menu"
:user="user" :user="user"
/> />
</template> <template v-if="relationship.following">
<ProgressButton
v-if="!relationship.notifying"
class="btn button-default"
:click="subscribeUser"
:title="$t('user_card.subscribe')"
>
<FAIcon icon="bell" />
</ProgressButton>
<ProgressButton
v-else
class="btn button-default toggled"
:click="unsubscribeUser"
:title="$t('user_card.unsubscribe')"
>
<FALayers>
<FAIcon
icon="rss"
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" />
</FALayers>
</ProgressButton>
</template>
</div>
<button
v-if="relationship.muting"
class="btn button-default btn-mute toggled"
:disabled="user.deactivated"
@click="unmuteUser"
>
{{ $t('user_card.muted') }}
</button>
<button
v-else
class="btn button-default btn-mute"
:disabled="user.deactivated"
@click="muteUser"
>
{{ $t('user_card.mute') }}
</button>
<button
class="btn button-default btn-mention"
:disabled="user.deactivated"
@click="mentionUser"
>
{{ $t('user_card.mention') }}
</button>
<ModerationTools
v-if="showModerationMenu"
class="moderation-menu"
:user="user"
/>
</div> </div>
<div <div
v-if="!loggedIn && user.is_local" v-if="!loggedIn && user.is_local"
@ -455,8 +458,7 @@
> >
<template #default="inputProps"> <template #default="inputProps">
<input <input
v-model="newFields[i].name" v-model="newFields[i].name" :placeholder="$t('settings.profile_fields.name')"
:placeholder="$t('settings.profile_fields.name')"
v-bind="propsToNative(inputProps)" v-bind="propsToNative(inputProps)"
class="input" class="input"
> >
@ -653,7 +655,13 @@
<template #header> <template #header>
{{ editImage === 'avatar' ? $t('settings.change_avatar') : $t('settings.change_banner') }} {{ editImage === 'avatar' ? $t('settings.change_avatar') : $t('settings.change_banner') }}
</template> </template>
<div class="image-container"> <p>
{{ editImage === 'avatar' ? $t('settings.avatar_size_instruction') : $t('settings.banner_size_instruction' ) }}
</p>
<div
class="image-container"
:class="{ '-banner': editImage === 'banner' }"
>
<image-cropper <image-cropper
ref="cropper" ref="cropper"
class="cropper" class="cropper"
@ -667,11 +675,8 @@
type="button" type="button"
@click="() => $refs.cropper.pickImage()" @click="() => $refs.cropper.pickImage()"
> >
{{ $t('settings.upload_picture') }} {{ $t('settings.select_picture') }}
</button> </button>
<p class="visibility-notice">
{{ editImage === 'avatar' ? $t('settings.avatar_size_instruction') : $t('settings.banner_size_instruction' ) }}
</p>
<template #footer> <template #footer>
<button <button
class="button-default btn" class="button-default btn"

View file

@ -28,7 +28,7 @@
} }
.user-info { .user-info {
margin: 0.6em; margin: 0.6em 0.6em 0;
.Avatar { .Avatar {
width: 5em; width: 5em;
@ -38,6 +38,12 @@
} }
} }
.post-status-form {
form {
margin-top: 0;
}
}
.signed-in { .signed-in {
z-index: 10; z-index: 10;
} }

View file

@ -787,6 +787,7 @@
"type_domains_to_mute": "Search domains to mute", "type_domains_to_mute": "Search domains to mute",
"upload_a_photo": "Upload a photo", "upload_a_photo": "Upload a photo",
"upload_picture": "Upload picture", "upload_picture": "Upload picture",
"select_picture": "Select picture",
"user_settings": "User Settings", "user_settings": "User Settings",
"values": { "values": {
"false": "no", "false": "no",