summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCenTdemeern1 <timo.herngreen@gmail.com>2024-10-02 23:49:30 +0200
committerCenTdemeern1 <timo.herngreen@gmail.com>2024-10-02 23:49:30 +0200
commit28aa99b2737fd3d66f8c438477c96aa94b0059ed (patch)
treeff687fd19300d0ac62461c4bc19d7dba13451566
parentmerge: Merge stable into develop (!636) (diff)
downloadsharkey-28aa99b2737fd3d66f8c438477c96aa94b0059ed.tar.gz
sharkey-28aa99b2737fd3d66f8c438477c96aa94b0059ed.tar.bz2
sharkey-28aa99b2737fd3d66f8c438477c96aa94b0059ed.zip
Implement "Show Below Avatar" for Avatar Decorations
-rw-r--r--locales/en-US.yml1
-rw-r--r--packages/backend/src/core/entities/UserEntityService.ts1
-rw-r--r--packages/backend/src/models/User.ts1
-rw-r--r--packages/backend/src/models/json-schema/user.ts4
-rw-r--r--packages/backend/src/server/api/endpoints/i/update.ts2
-rw-r--r--packages/frontend/src/components/global/MkAvatar.vue32
-rw-r--r--packages/frontend/src/pages/settings/avatar-decoration.decoration.vue3
-rw-r--r--packages/frontend/src/pages/settings/avatar-decoration.dialog.vue9
-rw-r--r--packages/frontend/src/pages/settings/avatar-decoration.vue3
9 files changed, 42 insertions, 14 deletions
diff --git a/locales/en-US.yml b/locales/en-US.yml
index 6d24bb5b41..2d3c5c53b6 100644
--- a/locales/en-US.yml
+++ b/locales/en-US.yml
@@ -1277,6 +1277,7 @@ detach: "Remove"
detachAll: "Remove All"
angle: "Angle"
flip: "Flip"
+showBelowAvatar: "Show Below Avatar"
showAvatarDecorations: "Show avatar decorations"
releaseToRefresh: "Release to refresh"
refreshing: "Refreshing..."
diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts
index 2b1c4d5c63..40830f86b4 100644
--- a/packages/backend/src/core/entities/UserEntityService.ts
+++ b/packages/backend/src/core/entities/UserEntityService.ts
@@ -525,6 +525,7 @@ export class UserEntityService implements OnModuleInit {
flipH: ud.flipH || undefined,
offsetX: ud.offsetX || undefined,
offsetY: ud.offsetY || undefined,
+ showBelow: ud.showBelow || undefined,
url: decorations.find(d => d.id === ud.id)!.url,
}))) : [],
isBot: user.isBot,
diff --git a/packages/backend/src/models/User.ts b/packages/backend/src/models/User.ts
index b0910133c9..cbebd0102d 100644
--- a/packages/backend/src/models/User.ts
+++ b/packages/backend/src/models/User.ts
@@ -170,6 +170,7 @@ export class MiUser {
flipH?: boolean;
offsetX?: number;
offsetY?: number;
+ showBelow?: boolean;
}[];
@Index()
diff --git a/packages/backend/src/models/json-schema/user.ts b/packages/backend/src/models/json-schema/user.ts
index 33a3efd453..249b9bba38 100644
--- a/packages/backend/src/models/json-schema/user.ts
+++ b/packages/backend/src/models/json-schema/user.ts
@@ -104,6 +104,10 @@ export const packedUserLiteSchema = {
type: 'number',
nullable: false, optional: true,
},
+ showBelow: {
+ type: 'boolean',
+ nullable: false, optional: true,
+ },
},
},
},
diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts
index 6cc22e7994..f9b8061249 100644
--- a/packages/backend/src/server/api/endpoints/i/update.ts
+++ b/packages/backend/src/server/api/endpoints/i/update.ts
@@ -159,6 +159,7 @@ export const paramDef = {
flipH: { type: 'boolean', nullable: true },
offsetX: { type: 'number', nullable: true, maximum: 0.25, minimum: -0.25 },
offsetY: { type: 'number', nullable: true, maximum: 0.25, minimum: -0.25 },
+ showBelow: { type: 'boolean', nullable: true },
},
required: ['id'],
} },
@@ -417,6 +418,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
flipH: d.flipH ?? false,
offsetX: d.offsetX ?? 0,
offsetY: d.offsetY ?? 0,
+ showBelow: d.showBelow ?? false,
}));
}
diff --git a/packages/frontend/src/components/global/MkAvatar.vue b/packages/frontend/src/components/global/MkAvatar.vue
index de62fe12a9..ce6985d907 100644
--- a/packages/frontend/src/components/global/MkAvatar.vue
+++ b/packages/frontend/src/components/global/MkAvatar.vue
@@ -7,6 +7,20 @@ SPDX-License-Identifier: AGPL-3.0-only
<component :is="link ? MkA : 'span'" v-user-preview="preview ? user.id : undefined" v-bind="bound" class="_noSelect" :class="[$style.root, { [$style.animation]: animation, [$style.cat]: user.isCat, [$style.square]: squareAvatars }]" :style="{ color }" :title="acct(user)" @click="onClick">
<MkImgWithBlurhash :class="$style.inner" :src="url" :hash="user.avatarBlurhash" :cover="true" :onlyAvgColor="true"/>
<MkUserOnlineIndicator v-if="indicator" :class="$style.indicator" :user="user"/>
+ <template v-if="showDecoration">
+ <img
+ v-for="decoration in decorations ?? user.avatarDecorations"
+ :class="[$style.decoration]"
+ :src="getDecorationUrl(decoration)"
+ :style="{
+ rotate: getDecorationAngle(decoration),
+ scale: getDecorationScale(decoration),
+ translate: getDecorationOffset(decoration),
+ zIndex: getDecorationZIndex(decoration),
+ }"
+ alt=""
+ >
+ </template>
<div v-if="user.isCat" :class="[$style.ears]">
<div :class="$style.earLeft">
<div v-if="false" :class="$style.layer">
@@ -23,19 +37,6 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
</div>
</div>
- <template v-if="showDecoration">
- <img
- v-for="decoration in decorations ?? user.avatarDecorations"
- :class="[$style.decoration]"
- :src="getDecorationUrl(decoration)"
- :style="{
- rotate: getDecorationAngle(decoration),
- scale: getDecorationScale(decoration),
- translate: getDecorationOffset(decoration),
- }"
- alt=""
- >
- </template>
</component>
</template>
@@ -113,6 +114,11 @@ function getDecorationOffset(decoration: Omit<Misskey.entities.UserDetailed['ava
return offsetX === 0 && offsetY === 0 ? undefined : `${offsetX * 100}% ${offsetY * 100}%`;
}
+function getDecorationZIndex(decoration: Omit<Misskey.entities.UserDetailed['avatarDecorations'][number], 'id'>) {
+ const zIndex = decoration.showBelow ? 0 : 1;
+ return zIndex === 1 ? undefined : `${zIndex}`;
+}
+
const color = ref<string | undefined>();
watch(() => props.user.avatarBlurhash, () => {
diff --git a/packages/frontend/src/pages/settings/avatar-decoration.decoration.vue b/packages/frontend/src/pages/settings/avatar-decoration.decoration.vue
index 0767fa7864..9f7852a71d 100644
--- a/packages/frontend/src/pages/settings/avatar-decoration.decoration.vue
+++ b/packages/frontend/src/pages/settings/avatar-decoration.decoration.vue
@@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only
@click="emit('click')"
>
<div :class="$style.name"><MkCondensedLine :minScale="0.5">{{ decoration.name }}</MkCondensedLine></div>
- <MkAvatar style="width: 60px; height: 60px;" :user="$i" :decorations="[{ url: decoration.url, angle, flipH, offsetX, offsetY }]" forceShowDecoration/>
+ <MkAvatar style="width: 60px; height: 60px;" :user="$i" :decorations="[{ url: decoration.url, angle, flipH, offsetX, offsetY, showBelow }]" forceShowDecoration/>
<i v-if="decoration.roleIdsThatCanBeUsedThisDecoration.length > 0 && !$i.roles.some(r => decoration.roleIdsThatCanBeUsedThisDecoration.includes(r.id))" :class="$style.lock" class="ti ti-lock"></i>
</div>
</template>
@@ -32,6 +32,7 @@ const props = defineProps<{
flipH?: boolean;
offsetX?: number;
offsetY?: number;
+ showBelow?: boolean;
}>();
const emit = defineEmits<{
diff --git a/packages/frontend/src/pages/settings/avatar-decoration.dialog.vue b/packages/frontend/src/pages/settings/avatar-decoration.dialog.vue
index ce1d4e48d8..400b365ca6 100644
--- a/packages/frontend/src/pages/settings/avatar-decoration.dialog.vue
+++ b/packages/frontend/src/pages/settings/avatar-decoration.dialog.vue
@@ -29,6 +29,9 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkRange v-model="offsetY" continuousUpdate :min="-0.25" :max="0.25" :step="0.025" :textConverter="(v) => `${Math.floor(v * 100)}%`">
<template #label>Y {{ i18n.ts.position }}</template>
</MkRange>
+ <MkSwitch v-model="showBelow">
+ <template #label>{{ i18n.ts.showBelowAvatar }}</template>
+ </MkSwitch>
<MkSwitch v-model="flipH">
<template #label>{{ i18n.ts.flip }}</template>
</MkSwitch>
@@ -71,12 +74,14 @@ const emit = defineEmits<{
flipH: boolean;
offsetX: number;
offsetY: number;
+ showBelow: boolean;
}): void;
(ev: 'update', payload: {
angle: number;
flipH: boolean;
offsetX: number;
offsetY: number;
+ showBelow: boolean;
}): void;
(ev: 'detach'): void;
}>();
@@ -87,6 +92,7 @@ const angle = ref((props.usingIndex != null ? $i.avatarDecorations[props.usingIn
const flipH = ref((props.usingIndex != null ? $i.avatarDecorations[props.usingIndex].flipH : null) ?? false);
const offsetX = ref((props.usingIndex != null ? $i.avatarDecorations[props.usingIndex].offsetX : null) ?? 0);
const offsetY = ref((props.usingIndex != null ? $i.avatarDecorations[props.usingIndex].offsetY : null) ?? 0);
+const showBelow = ref((props.usingIndex != null ? $i.avatarDecorations[props.usingIndex].showBelow : null) ?? false);
const decorationsForPreview = computed(() => {
const decoration = {
@@ -96,6 +102,7 @@ const decorationsForPreview = computed(() => {
flipH: flipH.value,
offsetX: offsetX.value,
offsetY: offsetY.value,
+ showBelow: showBelow.value,
};
const decorations = [...$i.avatarDecorations];
if (props.usingIndex != null) {
@@ -116,6 +123,7 @@ async function update() {
flipH: flipH.value,
offsetX: offsetX.value,
offsetY: offsetY.value,
+ showBelow: showBelow.value,
});
dialog.value.close();
}
@@ -126,6 +134,7 @@ async function attach() {
flipH: flipH.value,
offsetX: offsetX.value,
offsetY: offsetY.value,
+ showBelow: showBelow.value,
});
dialog.value.close();
}
diff --git a/packages/frontend/src/pages/settings/avatar-decoration.vue b/packages/frontend/src/pages/settings/avatar-decoration.vue
index 77229d3349..5324a6b7f7 100644
--- a/packages/frontend/src/pages/settings/avatar-decoration.vue
+++ b/packages/frontend/src/pages/settings/avatar-decoration.vue
@@ -21,6 +21,7 @@ SPDX-License-Identifier: AGPL-3.0-only
:flipH="avatarDecoration.flipH"
:offsetX="avatarDecoration.offsetX"
:offsetY="avatarDecoration.offsetY"
+ :showBelow="avatarDecoration.showBelow"
:active="true"
@click="openDecoration(avatarDecoration, i)"
/>
@@ -78,6 +79,7 @@ function openDecoration(avatarDecoration, index?: number) {
flipH: payload.flipH,
offsetX: payload.offsetX,
offsetY: payload.offsetY,
+ showBelow: payload.showBelow,
};
const update = [...$i.avatarDecorations, decoration];
await os.apiWithDialog('i/update', {
@@ -92,6 +94,7 @@ function openDecoration(avatarDecoration, index?: number) {
flipH: payload.flipH,
offsetX: payload.offsetX,
offsetY: payload.offsetY,
+ showBelow: payload.showBelow,
};
const update = [...$i.avatarDecorations];
update[index] = decoration;