enhance(frontend): tweak avatar decoration setting ui
This commit is contained in:
152
packages/frontend/src/pages/settings/avatar-decoration.vue
Normal file
152
packages/frontend/src/pages/settings/avatar-decoration.vue
Normal file
@@ -0,0 +1,152 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: syuilo and other misskey contributors
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="!loading" class="_gaps">
|
||||
<MkInfo>{{ i18n.t('_profile.avatarDecorationMax', { max: $i.policies.avatarDecorationLimit }) }} ({{ i18n.t('remainingN', { n: $i.policies.avatarDecorationLimit - $i.avatarDecorations.length }) }})</MkInfo>
|
||||
|
||||
<MkAvatar :class="$style.avatar" :user="$i" forceShowDecoration/>
|
||||
|
||||
<div v-if="$i.avatarDecorations.length > 0" v-panel :class="$style.current" class="_gaps_s">
|
||||
<div>{{ i18n.ts.inUse }}</div>
|
||||
|
||||
<div :class="$style.decorations">
|
||||
<XDecoration
|
||||
v-for="(avatarDecoration, i) in $i.avatarDecorations"
|
||||
: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)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<MkButton danger @click="detachAllDecorations">{{ i18n.ts.detachAll }}</MkButton>
|
||||
</div>
|
||||
|
||||
<div :class="$style.decorations">
|
||||
<XDecoration
|
||||
v-for="avatarDecoration in avatarDecorations"
|
||||
:key="avatarDecoration.id"
|
||||
:decoration="avatarDecoration"
|
||||
@click="openDecoration(avatarDecoration)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<MkLoading/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, defineAsyncComponent, computed } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import XDecoration from './avatar-decoration.decoration.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import * as os from '@/os.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { $i } from '@/account.js';
|
||||
import MkInfo from '@/components/MkInfo.vue';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
|
||||
const loading = ref(true);
|
||||
const avatarDecorations = ref<Misskey.entities.GetAvatarDecorationsResponse>([]);
|
||||
|
||||
os.api('get-avatar-decorations').then(_avatarDecorations => {
|
||||
avatarDecorations.value = _avatarDecorations;
|
||||
loading.value = false;
|
||||
});
|
||||
|
||||
function openDecoration(avatarDecoration, index?: number) {
|
||||
os.popup(defineAsyncComponent(() => import('./avatar-decoration.dialog.vue')), {
|
||||
decoration: avatarDecoration,
|
||||
usingIndex: index,
|
||||
}, {
|
||||
'attach': async (payload) => {
|
||||
const decoration = {
|
||||
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', {
|
||||
avatarDecorations: update,
|
||||
});
|
||||
$i.avatarDecorations = update;
|
||||
},
|
||||
'update': async (payload) => {
|
||||
const decoration = {
|
||||
id: avatarDecoration.id,
|
||||
angle: payload.angle,
|
||||
flipH: payload.flipH,
|
||||
offsetX: payload.offsetX,
|
||||
offsetY: payload.offsetY,
|
||||
};
|
||||
const update = [...$i.avatarDecorations];
|
||||
update[index] = decoration;
|
||||
await os.apiWithDialog('i/update', {
|
||||
avatarDecorations: update,
|
||||
});
|
||||
$i.avatarDecorations = update;
|
||||
},
|
||||
'detach': async () => {
|
||||
const update = [...$i.avatarDecorations];
|
||||
update.splice(index, 1);
|
||||
await os.apiWithDialog('i/update', {
|
||||
avatarDecorations: update,
|
||||
});
|
||||
$i.avatarDecorations = update;
|
||||
},
|
||||
}, 'closed');
|
||||
}
|
||||
|
||||
function detachAllDecorations() {
|
||||
os.confirm({
|
||||
type: 'warning',
|
||||
text: i18n.ts.areYouSure,
|
||||
}).then(async ({ canceled }) => {
|
||||
if (canceled) return;
|
||||
await os.apiWithDialog('i/update', {
|
||||
avatarDecorations: [],
|
||||
});
|
||||
$i.avatarDecorations = [];
|
||||
});
|
||||
}
|
||||
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.avatarDecorations,
|
||||
icon: 'ti ti-sparkles',
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
.avatar {
|
||||
display: inline-block;
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
margin: 16px auto;
|
||||
}
|
||||
|
||||
.current {
|
||||
padding: 16px;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
|
||||
.decorations {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
|
||||
grid-gap: 12px;
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user