enhance: アイコンデコレーションの位置を微調整できるように
This commit is contained in:
		| @@ -362,6 +362,8 @@ export class UserEntityService implements OnModuleInit { | ||||
| 				id: ud.id, | ||||
| 				angle: ud.angle || undefined, | ||||
| 				flipH: ud.flipH || undefined, | ||||
| 				offsetX: ud.offsetX || undefined, | ||||
| 				offsetY: ud.offsetY || undefined, | ||||
| 				url: decorations.find(d => d.id === ud.id)!.url, | ||||
| 			}))) : [], | ||||
| 			isBot: user.isBot, | ||||
|   | ||||
| @@ -143,8 +143,10 @@ export class MiUser { | ||||
| 	}) | ||||
| 	public avatarDecorations: { | ||||
| 		id: string; | ||||
| 		angle: number; | ||||
| 		flipH: boolean; | ||||
| 		angle?: number; | ||||
| 		flipH?: boolean; | ||||
| 		offsetX?: number; | ||||
| 		offsetY?: number; | ||||
| 	}[]; | ||||
|  | ||||
| 	@Index() | ||||
|   | ||||
| @@ -143,6 +143,8 @@ export const paramDef = { | ||||
| 				id: { type: 'string', format: 'misskey:id' }, | ||||
| 				angle: { type: 'number', nullable: true, maximum: 0.5, minimum: -0.5 }, | ||||
| 				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 }, | ||||
| 			}, | ||||
| 			required: ['id'], | ||||
| 		} }, | ||||
| @@ -341,6 +343,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | ||||
| 					id: d.id, | ||||
| 					angle: d.angle ?? 0, | ||||
| 					flipH: d.flipH ?? false, | ||||
| 					offsetX: d.offsetX ?? 0, | ||||
| 					offsetY: d.offsetY ?? 0, | ||||
| 				})); | ||||
| 			} | ||||
|  | ||||
|   | ||||
| @@ -31,6 +31,7 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| 			:style="{ | ||||
| 				rotate: getDecorationAngle(decoration), | ||||
| 				scale: getDecorationScale(decoration), | ||||
| 				translate: getDecorationOffset(decoration), | ||||
| 			}" | ||||
| 			alt="" | ||||
| 		> | ||||
| @@ -99,6 +100,12 @@ function getDecorationScale(decoration: Omit<Misskey.entities.UserDetailed['avat | ||||
| 	return scaleX === 1 ? undefined : `${scaleX} 1`; | ||||
| } | ||||
|  | ||||
| function getDecorationOffset(decoration: Omit<Misskey.entities.UserDetailed['avatarDecorations'][number], 'id'>) { | ||||
| 	const offsetX = decoration.offsetX ?? 0; | ||||
| 	const offsetY = decoration.offsetY ?? 0; | ||||
| 	return offsetX === 0 && offsetY === 0 ? undefined : `${offsetX * 100}% ${offsetY * 100}%`; | ||||
| } | ||||
|  | ||||
| const color = ref<string | undefined>(); | ||||
|  | ||||
| watch(() => props.user.avatarBlurhash, () => { | ||||
|   | ||||
| @@ -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 }]" forceShowDecoration/> | ||||
| 	<MkAvatar style="width: 60px; height: 60px;" :user="$i" :decorations="[{ url: decoration.url, angle, flipH, offsetX, offsetY }]" 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> | ||||
| @@ -28,6 +28,8 @@ const props = defineProps<{ | ||||
| 	}; | ||||
| 	angle?: number; | ||||
| 	flipH?: boolean; | ||||
| 	offsetX?: number; | ||||
| 	offsetY?: number; | ||||
| }>(); | ||||
|  | ||||
| const emit = defineEmits<{ | ||||
|   | ||||
| @@ -23,6 +23,12 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| 				<MkRange v-model="angle" continuousUpdate :min="-0.5" :max="0.5" :step="0.025" :textConverter="(v) => `${Math.floor(v * 360)}°`"> | ||||
| 					<template #label>{{ i18n.ts.angle }}</template> | ||||
| 				</MkRange> | ||||
| 				<MkRange v-model="offsetX" continuousUpdate :min="-0.25" :max="0.25" :step="0.025" :textConverter="(v) => `${Math.floor(v * 100)}%`"> | ||||
| 					<template #label>X {{ i18n.ts.position }}</template> | ||||
| 				</MkRange> | ||||
| 				<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="flipH"> | ||||
| 					<template #label>{{ i18n.ts.flip }}</template> | ||||
| 				</MkSwitch> | ||||
| @@ -64,10 +70,14 @@ const emit = defineEmits<{ | ||||
| 	(ev: 'attach', payload: { | ||||
| 		angle: number; | ||||
| 		flipH: boolean; | ||||
| 		offsetX: number; | ||||
| 		offsetY: number; | ||||
| 	}): void; | ||||
| 	(ev: 'update', payload: { | ||||
| 		angle: number; | ||||
| 		flipH: boolean; | ||||
| 		offsetX: number; | ||||
| 		offsetY: number; | ||||
| 	}): void; | ||||
| 	(ev: 'detach'): void; | ||||
| }>(); | ||||
| @@ -76,6 +86,8 @@ const dialog = shallowRef<InstanceType<typeof MkModalWindow>>(); | ||||
| const exceeded = computed(() => ($i.policies.avatarDecorationLimit - $i.avatarDecorations.length) <= 0); | ||||
| const angle = ref((props.usingIndex != null ? $i.avatarDecorations[props.usingIndex].angle : null) ?? 0); | ||||
| 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 decorationsForPreview = computed(() => { | ||||
| 	const decoration = { | ||||
| @@ -83,6 +95,8 @@ const decorationsForPreview = computed(() => { | ||||
| 		url: props.decoration.url, | ||||
| 		angle: angle.value, | ||||
| 		flipH: flipH.value, | ||||
| 		offsetX: offsetX.value, | ||||
| 		offsetY: offsetY.value, | ||||
| 	}; | ||||
| 	const decorations = [...$i.avatarDecorations]; | ||||
| 	if (props.usingIndex != null) { | ||||
| @@ -101,6 +115,8 @@ async function update() { | ||||
| 	emit('update', { | ||||
| 		angle: angle.value, | ||||
| 		flipH: flipH.value, | ||||
| 		offsetX: offsetX.value, | ||||
| 		offsetY: offsetY.value, | ||||
| 	}); | ||||
| 	dialog.value.close(); | ||||
| } | ||||
| @@ -109,6 +125,8 @@ async function attach() { | ||||
| 	emit('attach', { | ||||
| 		angle: angle.value, | ||||
| 		flipH: flipH.value, | ||||
| 		offsetX: offsetX.value, | ||||
| 		offsetY: offsetY.value, | ||||
| 	}); | ||||
| 	dialog.value.close(); | ||||
| } | ||||
|   | ||||
| @@ -16,6 +16,8 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| 				:decoration="avatarDecorations.find(d => d.id === avatarDecoration.id)" | ||||
| 				:angle="avatarDecoration.angle" | ||||
| 				:flipH="avatarDecoration.flipH" | ||||
| 				:offsetX="avatarDecoration.offsetX" | ||||
| 				:offsetY="avatarDecoration.offsetY" | ||||
| 				:active="true" | ||||
| 				@click="openDecoration(avatarDecoration, i)" | ||||
| 			/> | ||||
| @@ -66,6 +68,8 @@ function openDecoration(avatarDecoration, index?: number) { | ||||
| 				id: avatarDecoration.id, | ||||
| 				angle: payload.angle, | ||||
| 				flipH: payload.flipH, | ||||
| 				offsetX: payload.offsetX, | ||||
| 				offsetY: payload.offsetY, | ||||
| 			}; | ||||
| 			const update = [...$i.avatarDecorations, decoration]; | ||||
| 			await os.apiWithDialog('i/update', { | ||||
| @@ -78,6 +82,8 @@ function openDecoration(avatarDecoration, index?: number) { | ||||
| 				id: avatarDecoration.id, | ||||
| 				angle: payload.angle, | ||||
| 				flipH: payload.flipH, | ||||
| 				offsetX: payload.offsetX, | ||||
| 				offsetY: payload.offsetY, | ||||
| 			}; | ||||
| 			const update = [...$i.avatarDecorations]; | ||||
| 			update[index] = decoration; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 syuilo
					syuilo