enhance(frontend): tweak avatar decoration setting ui
This commit is contained in:
parent
c167f20643
commit
776eea736a
1
locales/index.d.ts
vendored
1
locales/index.d.ts
vendored
|
@ -1183,6 +1183,7 @@ export interface Locale {
|
||||||
"remainingN": string;
|
"remainingN": string;
|
||||||
"overwriteContentConfirm": string;
|
"overwriteContentConfirm": string;
|
||||||
"seasonalScreenEffect": string;
|
"seasonalScreenEffect": string;
|
||||||
|
"decorate": string;
|
||||||
"_announcement": {
|
"_announcement": {
|
||||||
"forExistingUsers": string;
|
"forExistingUsers": string;
|
||||||
"forExistingUsersDescription": string;
|
"forExistingUsersDescription": string;
|
||||||
|
|
|
@ -1180,6 +1180,7 @@ reloadRequiredToApplySettings: "設定の反映にはリロードが必要です
|
||||||
remainingN: "残り: {n}"
|
remainingN: "残り: {n}"
|
||||||
overwriteContentConfirm: "現在の内容に上書きされますがよろしいですか?"
|
overwriteContentConfirm: "現在の内容に上書きされますがよろしいですか?"
|
||||||
seasonalScreenEffect: "季節に応じた画面の演出"
|
seasonalScreenEffect: "季節に応じた画面の演出"
|
||||||
|
decorate: "デコる"
|
||||||
|
|
||||||
_announcement:
|
_announcement:
|
||||||
forExistingUsers: "既存ユーザーのみ"
|
forExistingUsers: "既存ユーザーのみ"
|
||||||
|
|
|
@ -4,51 +4,56 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="!loading" class="_gaps">
|
<div>
|
||||||
<MkInfo>{{ i18n.t('_profile.avatarDecorationMax', { max: $i.policies.avatarDecorationLimit }) }} ({{ i18n.t('remainingN', { n: $i.policies.avatarDecorationLimit - $i.avatarDecorations.length }) }})</MkInfo>
|
<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>
|
||||||
|
|
||||||
<div v-if="$i.avatarDecorations.length > 0" v-panel :class="$style.current" class="_gaps_s">
|
<MkAvatar :class="$style.avatar" :user="$i" forceShowDecoration/>
|
||||||
<div>{{ i18n.ts.inUse }}</div>
|
|
||||||
|
<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">
|
<div :class="$style.decorations">
|
||||||
<XDecoration
|
<XDecoration
|
||||||
v-for="(avatarDecoration, i) in $i.avatarDecorations"
|
v-for="avatarDecoration in avatarDecorations"
|
||||||
:decoration="avatarDecorations.find(d => d.id === avatarDecoration.id)"
|
:key="avatarDecoration.id"
|
||||||
:angle="avatarDecoration.angle"
|
:decoration="avatarDecoration"
|
||||||
:flipH="avatarDecoration.flipH"
|
@click="openDecoration(avatarDecoration)"
|
||||||
:offsetX="avatarDecoration.offsetX"
|
|
||||||
:offsetY="avatarDecoration.offsetY"
|
|
||||||
:active="true"
|
|
||||||
@click="openDecoration(avatarDecoration, i)"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<MkButton danger @click="detachAllDecorations">{{ i18n.ts.detachAll }}</MkButton>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else>
|
||||||
<div :class="$style.decorations">
|
<MkLoading/>
|
||||||
<XDecoration
|
|
||||||
v-for="avatarDecoration in avatarDecorations"
|
|
||||||
:key="avatarDecoration.id"
|
|
||||||
:decoration="avatarDecoration"
|
|
||||||
@click="openDecoration(avatarDecoration)"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
|
||||||
<MkLoading/>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, defineAsyncComponent } from 'vue';
|
import { ref, defineAsyncComponent, computed } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import XDecoration from './profile.avatar-decoration.decoration.vue';
|
import XDecoration from './avatar-decoration.decoration.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import MkInfo from '@/components/MkInfo.vue';
|
import MkInfo from '@/components/MkInfo.vue';
|
||||||
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
|
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
const avatarDecorations = ref<Misskey.entities.GetAvatarDecorationsResponse>([]);
|
const avatarDecorations = ref<Misskey.entities.GetAvatarDecorationsResponse>([]);
|
||||||
|
@ -59,7 +64,7 @@ os.api('get-avatar-decorations').then(_avatarDecorations => {
|
||||||
});
|
});
|
||||||
|
|
||||||
function openDecoration(avatarDecoration, index?: number) {
|
function openDecoration(avatarDecoration, index?: number) {
|
||||||
os.popup(defineAsyncComponent(() => import('./profile.avatar-decoration.dialog.vue')), {
|
os.popup(defineAsyncComponent(() => import('./avatar-decoration.dialog.vue')), {
|
||||||
decoration: avatarDecoration,
|
decoration: avatarDecoration,
|
||||||
usingIndex: index,
|
usingIndex: index,
|
||||||
}, {
|
}, {
|
||||||
|
@ -115,9 +120,25 @@ function detachAllDecorations() {
|
||||||
$i.avatarDecorations = [];
|
$i.avatarDecorations = [];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const headerActions = computed(() => []);
|
||||||
|
|
||||||
|
const headerTabs = computed(() => []);
|
||||||
|
|
||||||
|
definePageMetadata({
|
||||||
|
title: i18n.ts.avatarDecorations,
|
||||||
|
icon: 'ti ti-sparkles',
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" module>
|
<style lang="scss" module>
|
||||||
|
.avatar {
|
||||||
|
display: inline-block;
|
||||||
|
width: 72px;
|
||||||
|
height: 72px;
|
||||||
|
margin: 16px auto;
|
||||||
|
}
|
||||||
|
|
||||||
.current {
|
.current {
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
|
@ -5,12 +5,17 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="_gaps_m">
|
<div class="_gaps_m">
|
||||||
<div :class="$style.avatarAndBanner" :style="{ backgroundImage: $i.bannerUrl ? `url(${ $i.bannerUrl })` : null }">
|
<div class="_panel">
|
||||||
|
<div :class="$style.banner" :style="{ backgroundImage: $i.bannerUrl ? `url(${ $i.bannerUrl })` : null }">
|
||||||
|
<MkButton primary rounded :class="$style.bannerEdit" @click="changeBanner">{{ i18n.ts._profile.changeBanner }}</MkButton>
|
||||||
|
</div>
|
||||||
<div :class="$style.avatarContainer">
|
<div :class="$style.avatarContainer">
|
||||||
<MkAvatar :class="$style.avatar" :user="$i" forceShowDecoration @click="changeAvatar"/>
|
<MkAvatar :class="$style.avatar" :user="$i" forceShowDecoration @click="changeAvatar"/>
|
||||||
<MkButton primary rounded @click="changeAvatar">{{ i18n.ts._profile.changeAvatar }}</MkButton>
|
<div class="_buttonsCenter">
|
||||||
|
<MkButton primary rounded @click="changeAvatar">{{ i18n.ts._profile.changeAvatar }}</MkButton>
|
||||||
|
<MkButton primary rounded link to="/settings/avatar-decoration">{{ i18n.ts.decorate }} <i class="ti ti-sparkles"></i></MkButton>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<MkButton primary rounded :class="$style.bannerEdit" @click="changeBanner">{{ i18n.ts._profile.changeBanner }}</MkButton>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<MkInput v-model="profile.name" :max="30" manualSave :mfmAutocomplete="['emoji']">
|
<MkInput v-model="profile.name" :max="30" manualSave :mfmAutocomplete="['emoji']">
|
||||||
|
@ -83,13 +88,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template #caption>{{ i18n.ts._profile.metadataDescription }}</template>
|
<template #caption>{{ i18n.ts._profile.metadataDescription }}</template>
|
||||||
</FormSlot>
|
</FormSlot>
|
||||||
|
|
||||||
<MkFolder>
|
|
||||||
<template #icon><i class="ti ti-sparkles"></i></template>
|
|
||||||
<template #label>{{ i18n.ts.avatarDecorations }}</template>
|
|
||||||
|
|
||||||
<XAvatarDecoration/>
|
|
||||||
</MkFolder>
|
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts.advancedSettings }}</template>
|
<template #label>{{ i18n.ts.advancedSettings }}</template>
|
||||||
|
|
||||||
|
@ -264,19 +262,19 @@ definePageMetadata({
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" module>
|
<style lang="scss" module>
|
||||||
.avatarAndBanner {
|
.banner {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
height: 130px;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
border: solid 1px var(--divider);
|
border-bottom: solid 1px var(--divider);
|
||||||
border-radius: 10px;
|
|
||||||
overflow: clip;
|
overflow: clip;
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatarContainer {
|
.avatarContainer {
|
||||||
display: inline-block;
|
margin-top: -50px;
|
||||||
|
padding-bottom: 16px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 16px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatar {
|
.avatar {
|
||||||
|
|
|
@ -54,6 +54,10 @@ export const routes = [{
|
||||||
path: '/profile',
|
path: '/profile',
|
||||||
name: 'profile',
|
name: 'profile',
|
||||||
component: page(() => import('./pages/settings/profile.vue')),
|
component: page(() => import('./pages/settings/profile.vue')),
|
||||||
|
}, {
|
||||||
|
path: '/avatar-decoration',
|
||||||
|
name: 'avatarDecoration',
|
||||||
|
component: page(() => import('./pages/settings/avatar-decoration.vue')),
|
||||||
}, {
|
}, {
|
||||||
path: '/roles',
|
path: '/roles',
|
||||||
name: 'roles',
|
name: 'roles',
|
||||||
|
|
Loading…
Reference in a new issue