misskey/packages/frontend/src/pages/avatar-decorations.vue

119 lines
2.9 KiB
Vue

<!--
SPDX-FileCopyrightText: syuilo and misskey-project
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<MkStickyContainer>
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="900">
<div class="_gaps">
<div :class="$style.decorations">
<div
v-for="avatarDecoration in avatarDecorations"
:key="avatarDecoration.id"
v-panel
:class="$style.decoration"
@click="edit(avatarDecoration)"
>
<div :class="$style.decorationName"><MkCondensedLine :minScale="0.5">{{ avatarDecoration.name }}</MkCondensedLine></div>
<MkAvatar style="width: 60px; height: 60px;" :user="$i" :decorations="[{ url: avatarDecoration.url }]" forceShowDecoration/>
</div>
</div>
</div>
</MkSpacer>
</MkStickyContainer>
</template>
<script lang="ts" setup>
import { ref, computed, defineAsyncComponent } from 'vue';
import * as Misskey from 'misskey-js';
import { ensureSignin } from '@/i.js';
import * as os from '@/os.js';
import { misskeyApi } from '@/utility/misskey-api.js';
import { i18n } from '@/i18n.js';
import { definePage } from '@/page.js';
const $i = ensureSignin();
const avatarDecorations = ref<Misskey.entities.AdminAvatarDecorationsListResponse>([]);
function load() {
misskeyApi('admin/avatar-decorations/list').then(_avatarDecorations => {
avatarDecorations.value = _avatarDecorations;
});
}
load();
async function add(ev: MouseEvent) {
const { dispose } = os.popup(defineAsyncComponent(() => import('./avatar-decoration-edit-dialog.vue')), {
}, {
done: result => {
if (result.created) {
avatarDecorations.value.unshift(result.created);
}
},
closed: () => dispose(),
});
}
function edit(avatarDecoration) {
const { dispose } = os.popup(defineAsyncComponent(() => import('./avatar-decoration-edit-dialog.vue')), {
avatarDecoration: avatarDecoration,
}, {
done: result => {
if (result.updated) {
const index = avatarDecorations.value.findIndex(x => x.id === avatarDecoration.id);
avatarDecorations.value[index] = {
...avatarDecorations.value[index],
...result.updated,
};
} else if (result.deleted) {
avatarDecorations.value = avatarDecorations.value.filter(x => x.id !== avatarDecoration.id);
}
},
closed: () => dispose(),
});
}
const headerActions = computed(() => [{
asFullButton: true,
icon: 'ti ti-plus',
text: i18n.ts.add,
handler: add,
}]);
const headerTabs = computed(() => []);
definePage(() => ({
title: i18n.ts.avatarDecorations,
icon: 'ti ti-sparkles',
}));
</script>
<style lang="scss" module>
.decorations {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
grid-gap: 12px;
}
.decoration {
cursor: pointer;
padding: 16px 16px 28px 16px;
border-radius: 8px;
text-align: center;
font-size: 90%;
overflow: clip;
contain: content;
}
.decorationName {
position: relative;
z-index: 10;
font-weight: bold;
margin-bottom: 20px;
}
</style>