Add initial profile background image handling

This commit is contained in:
Johannes Zellner
2025-03-25 15:05:08 +01:00
parent 1f8cdbaf62
commit 23dd575ce1
6 changed files with 53 additions and 6 deletions
+5
View File
@@ -186,6 +186,11 @@ onMounted(async () => {
window.document.title = result.cloudronName;
document.getElementById('favicon').href = `${API_ORIGIN}/api/v1/cloudron/avatar?ts=${Date.now()}`;
if (profile.value.hasBackgroundImage) {
window.document.body.style.backgroundImage = `url('${profile.value.backgroundImageUrl}')`;
window.document.body.classList.add('has-background');
}
ready.value = true;
});
+3 -3
View File
@@ -4,7 +4,7 @@ import { useTemplateRef, ref } from 'vue';
const fileInput = useTemplateRef('fileInput');
const props = defineProps(['src', 'fallbackSrc', 'size', 'maxSize', 'displayHeight']);
const props = defineProps(['src', 'fallbackSrc', 'size', 'maxSize', 'displayHeight', 'displayWidth']);
const emits = defineEmits(['changed']);
defineExpose({
clear(originalSrc = '') {
@@ -117,7 +117,7 @@ function onError() {
<input @change="onChanged($event)" type="file" ref="fileInput" style="display: none" accept="image/*"/>
<div ref="image" class="image-picker" @click="onShowIconSelector()">
<img :src="internalSrc || src" @error="onError" :style="{ height: displayHeight || null }" />
<img :src="internalSrc || src" @error="onError" :style="{ height: displayHeight || null, width: displayWidth || null }">
<i class="image-picker-edit-indicator fa fa-pencil-alt"></i>
</div>
</div>
@@ -134,7 +134,7 @@ function onError() {
.image-picker > img {
display: block;
height: 320px;
/* height: 320px;*/
border-radius: 10px;
}
+6
View File
@@ -33,6 +33,12 @@ export default {
margin-bottom: 50px;
}
body.has-background .section {
background-color: rgba(255,255,255,0.2);
backdrop-filter: blur(10px);
border-radius: 10px;
}
.section-header {
display: flex;
flex-wrap: wrap;
+18
View File
@@ -35,6 +35,8 @@ function create() {
result.body.isAtLeastAdmin = [ ROLES.OWNER, ROLES.ADMIN ].indexOf(result.body.role) !== -1;
result.body.isAtLeastOwner = [ ROLES.OWNER ].indexOf(result.body.role) !== -1;
result.body.backgroundImageUrl = result.body.hasBackgroundImage ? `${API_ORIGIN}/api/v1/profile/background_image?access_token=${accessToken}&bustcache=${Date.now()}` : '';
return [null, result.body];
},
async setPassword(password, newPassword) {
@@ -118,6 +120,22 @@ function create() {
return null;
},
async setBackgroundImage(file) {
const fd = new FormData();
if (file) fd.append('backgroundImage', file);
let error, result;
try {
result = await fetcher.post(`${API_ORIGIN}/api/v1/profile/background_image`, fd, { access_token: accessToken });
} catch (e) {
error = e;
}
if (error) return error;
if (result.status !== 202) return result;
return null;
},
async sendPasswordReset(identifier) {
let error, result;
try {
+3 -1
View File
@@ -27,8 +27,10 @@ html, body {
width: 100%;
padding: 0;
margin: 0;
background-color: white;
color: var(--pankow-text-color);
background-color: white;
background-position: center;
background-size: cover;
}
@media (prefers-color-scheme: dark) {
+18 -2
View File
@@ -117,6 +117,18 @@ async function onAvatarChanged(file) {
user.value.avatarUrl = u.toString();
}
async function onBackgroundChanged(file) {
await profileModel.setBackgroundImage(file);
await refreshProfile();
if (file) {
window.document.body.style.backgroundImage = `url('${user.value.backgroundImageUrl}')`;
window.document.body.classList.add('has-background');
} else {
window.document.body.style.backgroundImage = 'None';
window.document.body.classList.remove('has-background');
}
}
// Password changes
async function onPasswordChange() {
@@ -268,8 +280,12 @@ onMounted(async () => {
</template>
<div style="display: flex; flex-wrap: wrap">
<div style="width: 150px;">
<ImagePicker :src="user.avatarUrl" fallback-src="/img/appicon_fallback.png" size="512" @changed="onAvatarChanged" display-height="128px"/>
<div style="width: 150px; display: flex; flex-direction: column; justify-content: space-between;">
<ImagePicker :src="user.avatarUrl" fallback-src="/img/background-image-placeholder.svg" :size="512" @changed="onAvatarChanged" display-width="128px"/>
<div>
<ImagePicker :src="user.backgroundImageUrl" fallback-src="/img/background-image-placeholder.svg" :max-size="1280" @changed="onBackgroundChanged" display-width="128px"/>
<div v-if="user.hasBackgroundImage" class="actionable" @click="onBackgroundChanged(null)">Clear</div>
</div>
</div>
<div style="flex-grow: 1;">
<SettingsItem>