merge: Feat: Implement "Show Below Avatar" for Avatar Decorations (!645)

View MR for information: https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/645

Approved-by: dakkar <dakkar@thenautilus.net>
Approved-by: Marie <github@yuugi.dev>
This commit is contained in:
Marie 2024-10-03 20:40:34 +00:00
commit ac1e5a0fb5
12 changed files with 36 additions and 1 deletions

View file

@ -1279,6 +1279,7 @@ detach: "Remove"
detachAll: "Remove All" detachAll: "Remove All"
angle: "Angle" angle: "Angle"
flip: "Flip" flip: "Flip"
showBelowAvatar: "Show Below Avatar"
showAvatarDecorations: "Show avatar decorations" showAvatarDecorations: "Show avatar decorations"
releaseToRefresh: "Release to refresh" releaseToRefresh: "Release to refresh"
refreshing: "Refreshing..." refreshing: "Refreshing..."

4
locales/index.d.ts vendored
View file

@ -5133,6 +5133,10 @@ export interface Locale extends ILocale {
* *
*/ */
"flip": string; "flip": string;
/**
*
*/
"showBelowAvatar": string;
/** /**
* *
*/ */

View file

@ -1279,6 +1279,7 @@ detach: "外す"
detachAll: "全て外す" detachAll: "全て外す"
angle: "角度" angle: "角度"
flip: "反転" flip: "反転"
showBelowAvatar: "アイコンの後ろに表示"
showAvatarDecorations: "アイコンのデコレーションを表示" showAvatarDecorations: "アイコンのデコレーションを表示"
releaseToRefresh: "離してリロード" releaseToRefresh: "離してリロード"
refreshing: "リロード中" refreshing: "リロード中"

View file

@ -525,6 +525,7 @@ export class UserEntityService implements OnModuleInit {
flipH: ud.flipH || undefined, flipH: ud.flipH || undefined,
offsetX: ud.offsetX || undefined, offsetX: ud.offsetX || undefined,
offsetY: ud.offsetY || undefined, offsetY: ud.offsetY || undefined,
showBelow: ud.showBelow || undefined,
url: decorations.find(d => d.id === ud.id)!.url, url: decorations.find(d => d.id === ud.id)!.url,
}))) : [], }))) : [],
isBot: user.isBot, isBot: user.isBot,

View file

@ -170,6 +170,7 @@ export class MiUser {
flipH?: boolean; flipH?: boolean;
offsetX?: number; offsetX?: number;
offsetY?: number; offsetY?: number;
showBelow?: boolean;
}[]; }[];
@Index() @Index()

View file

@ -104,6 +104,10 @@ export const packedUserLiteSchema = {
type: 'number', type: 'number',
nullable: false, optional: true, nullable: false, optional: true,
}, },
showBelow: {
type: 'boolean',
nullable: false, optional: true,
},
}, },
}, },
}, },

View file

@ -159,6 +159,7 @@ export const paramDef = {
flipH: { type: 'boolean', nullable: true }, flipH: { type: 'boolean', nullable: true },
offsetX: { type: 'number', nullable: true, maximum: 0.25, minimum: -0.25 }, offsetX: { type: 'number', nullable: true, maximum: 0.25, minimum: -0.25 },
offsetY: { 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'], required: ['id'],
} }, } },
@ -417,6 +418,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
flipH: d.flipH ?? false, flipH: d.flipH ?? false,
offsetX: d.offsetX ?? 0, offsetX: d.offsetX ?? 0,
offsetY: d.offsetY ?? 0, offsetY: d.offsetY ?? 0,
showBelow: d.showBelow ?? false,
})); }));
} }

View file

@ -32,6 +32,7 @@ SPDX-License-Identifier: AGPL-3.0-only
rotate: getDecorationAngle(decoration), rotate: getDecorationAngle(decoration),
scale: getDecorationScale(decoration), scale: getDecorationScale(decoration),
translate: getDecorationOffset(decoration), translate: getDecorationOffset(decoration),
zIndex: getDecorationZIndex(decoration),
}" }"
alt="" alt=""
> >
@ -113,6 +114,10 @@ function getDecorationOffset(decoration: Omit<Misskey.entities.UserDetailed['ava
return offsetX === 0 && offsetY === 0 ? undefined : `${offsetX * 100}% ${offsetY * 100}%`; return offsetX === 0 && offsetY === 0 ? undefined : `${offsetX * 100}% ${offsetY * 100}%`;
} }
function getDecorationZIndex(decoration: Omit<Misskey.entities.UserDetailed['avatarDecorations'][number], 'id'>) {
return decoration.showBelow ? '-1' : undefined;
}
const color = ref<string | undefined>(); const color = ref<string | undefined>();
watch(() => props.user.avatarBlurhash, () => { watch(() => props.user.avatarBlurhash, () => {
@ -159,6 +164,7 @@ watch(() => props.user.avatarBlurhash, () => {
flex-shrink: 0; flex-shrink: 0;
border-radius: 100%; // sharkey: controlled by square avatars setting! border-radius: 100%; // sharkey: controlled by square avatars setting!
line-height: 16px; line-height: 16px;
z-index: 0; // sharkey: starts stacking context to help with showing decorations behind the avatar
} }
.inner { .inner {

View file

@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only
@click="emit('click')" @click="emit('click')"
> >
<div :class="$style.name"><MkCondensedLine :minScale="0.5">{{ decoration.name }}</MkCondensedLine></div> <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> <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> </div>
</template> </template>
@ -32,6 +32,7 @@ const props = defineProps<{
flipH?: boolean; flipH?: boolean;
offsetX?: number; offsetX?: number;
offsetY?: number; offsetY?: number;
showBelow?: boolean;
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{

View file

@ -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)}%`"> <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> <template #label>Y {{ i18n.ts.position }}</template>
</MkRange> </MkRange>
<MkSwitch v-model="showBelow">
<template #label>{{ i18n.ts.showBelowAvatar }}</template>
</MkSwitch>
<MkSwitch v-model="flipH"> <MkSwitch v-model="flipH">
<template #label>{{ i18n.ts.flip }}</template> <template #label>{{ i18n.ts.flip }}</template>
</MkSwitch> </MkSwitch>
@ -71,12 +74,14 @@ const emit = defineEmits<{
flipH: boolean; flipH: boolean;
offsetX: number; offsetX: number;
offsetY: number; offsetY: number;
showBelow: boolean;
}): void; }): void;
(ev: 'update', payload: { (ev: 'update', payload: {
angle: number; angle: number;
flipH: boolean; flipH: boolean;
offsetX: number; offsetX: number;
offsetY: number; offsetY: number;
showBelow: boolean;
}): void; }): void;
(ev: 'detach'): 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 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 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 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 decorationsForPreview = computed(() => {
const decoration = { const decoration = {
@ -96,6 +102,7 @@ const decorationsForPreview = computed(() => {
flipH: flipH.value, flipH: flipH.value,
offsetX: offsetX.value, offsetX: offsetX.value,
offsetY: offsetY.value, offsetY: offsetY.value,
showBelow: showBelow.value,
}; };
const decorations = [...$i.avatarDecorations]; const decorations = [...$i.avatarDecorations];
if (props.usingIndex != null) { if (props.usingIndex != null) {
@ -116,6 +123,7 @@ async function update() {
flipH: flipH.value, flipH: flipH.value,
offsetX: offsetX.value, offsetX: offsetX.value,
offsetY: offsetY.value, offsetY: offsetY.value,
showBelow: showBelow.value,
}); });
dialog.value.close(); dialog.value.close();
} }
@ -126,6 +134,7 @@ async function attach() {
flipH: flipH.value, flipH: flipH.value,
offsetX: offsetX.value, offsetX: offsetX.value,
offsetY: offsetY.value, offsetY: offsetY.value,
showBelow: showBelow.value,
}); });
dialog.value.close(); dialog.value.close();
} }

View file

@ -21,6 +21,7 @@ SPDX-License-Identifier: AGPL-3.0-only
:flipH="avatarDecoration.flipH" :flipH="avatarDecoration.flipH"
:offsetX="avatarDecoration.offsetX" :offsetX="avatarDecoration.offsetX"
:offsetY="avatarDecoration.offsetY" :offsetY="avatarDecoration.offsetY"
:showBelow="avatarDecoration.showBelow"
:active="true" :active="true"
@click="openDecoration(avatarDecoration, i)" @click="openDecoration(avatarDecoration, i)"
/> />
@ -78,6 +79,7 @@ function openDecoration(avatarDecoration, index?: number) {
flipH: payload.flipH, flipH: payload.flipH,
offsetX: payload.offsetX, offsetX: payload.offsetX,
offsetY: payload.offsetY, offsetY: payload.offsetY,
showBelow: payload.showBelow,
}; };
const update = [...$i.avatarDecorations, decoration]; const update = [...$i.avatarDecorations, decoration];
await os.apiWithDialog('i/update', { await os.apiWithDialog('i/update', {
@ -92,6 +94,7 @@ function openDecoration(avatarDecoration, index?: number) {
flipH: payload.flipH, flipH: payload.flipH,
offsetX: payload.offsetX, offsetX: payload.offsetX,
offsetY: payload.offsetY, offsetY: payload.offsetY,
showBelow: payload.showBelow,
}; };
const update = [...$i.avatarDecorations]; const update = [...$i.avatarDecorations];
update[index] = decoration; update[index] = decoration;

View file

@ -3814,6 +3814,7 @@ export type components = {
url: string; url: string;
offsetX?: number; offsetX?: number;
offsetY?: number; offsetY?: number;
showBelow?: boolean;
}[]; }[];
/** @default false */ /** @default false */
isAdmin?: boolean; isAdmin?: boolean;
@ -20227,6 +20228,7 @@ export type operations = {
flipH?: boolean | null; flipH?: boolean | null;
offsetX?: number | null; offsetX?: number | null;
offsetY?: number | null; offsetY?: number | null;
showBelow?: boolean | null;
})[]; })[];
/** Format: misskey:id */ /** Format: misskey:id */
bannerId?: string | null; bannerId?: string | null;