Skip to content

Commit

Permalink
Mod: プロキシアカウントの設定画面で名前,概要,アバター,バナーを変更可能に
Browse files Browse the repository at this point in the history
  • Loading branch information
sakuhanight committed Nov 22, 2024
1 parent 0d6cbf6 commit 00c0ad6
Showing 1 changed file with 122 additions and 6 deletions.
128 changes: 122 additions & 6 deletions packages/frontend/src/pages/admin/settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -238,15 +238,33 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkFolder>
<template #icon><i class="ti ti-ghost"></i></template>
<template #label>{{ i18n.ts.proxyAccount }}</template>
<template v-if="proxyAccountForm.modified.value" #footer>
<MkFormFooter :form="proxyAccountForm"/>
</template>

<div class="_gaps">
<MkInfo>{{ i18n.ts.proxyAccountDescription }}</MkInfo>
<MkKeyValue>
<template #key>{{ i18n.ts.proxyAccount }}</template>
<template #value>{{ proxyAccount ? `@${proxyAccount.username}` : i18n.ts.none }}</template>
</MkKeyValue>

<MkButton primary @click="chooseProxyAccount">{{ i18n.ts.selectAccount }}</MkButton>
<div class="_panel">
<div :class="$style.banner" :style="{ backgroundImage: proxyAccount.bannerUrl ? `url(${ proxyAccount.bannerUrl })` : null }">
<MkButton primary rounded :class="$style.bannerEdit" @click="changeProxyAccountBanner">{{ i18n.ts._profile.changeBanner }}</MkButton>
</div>
<div :class="$style.avatarContainer">
<MkAvatar :class="$style.avatar" :user="proxyAccount" forceShowDecoration @click="changeProxyAccountAvatar"/>
<div class="_buttonsCenter">
<MkButton primary rounded @click="changeProxyAccountAvatar">{{ i18n.ts._profile.changeAvatar }}</MkButton>
</div>
</div>
</div>

<MkInput v-model="proxyAccountForm.state.name" :max="30" :mfmAutocomplete="['emoji']">
<template #label>{{ i18n.ts._profile.name }}</template>
</MkInput>

<MkTextarea v-model="proxyAccountForm.state.description" :max="500" tall mfmAutocomplete :mfmPreview="true">
<template #label>{{ i18n.ts._profile.description }}</template>
<template #caption>{{ i18n.ts._profile.youCanIncludeHashtags }}</template>
</MkTextarea>
</div>
</MkFolder>
</div>
Expand All @@ -256,7 +274,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>

<script lang="ts" setup>
import { ref, computed } from 'vue';
import { ref, computed, reactive } from 'vue';
import XHeader from './_header_.vue';
import MkSwitch from '@/components/MkSwitch.vue';
import MkInput from '@/components/MkInput.vue';
Expand All @@ -274,10 +292,17 @@ import MkKeyValue from '@/components/MkKeyValue.vue';
import { useForm } from '@/scripts/use-form.js';
import MkFormFooter from '@/components/MkFormFooter.vue';
import MkRadios from '@/components/MkRadios.vue';
import { selectFile } from '@/scripts/select-file.js';
import { globalEvents } from '@/events.js';
import { claimAchievement } from '@/scripts/achievements.js';

const meta = await misskeyApi('admin/meta');

const proxyAccount = ref(meta.proxyAccountId ? await misskeyApi('users/show', { userId: meta.proxyAccountId }) : null);
const proxyAccountProfile = reactive({
name: proxyAccount.value.name,
description: proxyAccount.value.description,
});

const infoForm = useForm({
name: meta.name ?? '',
Expand Down Expand Up @@ -378,6 +403,69 @@ const federationForm = useForm({
fetchInstance(true);
});

const proxyAccountForm = useForm({
name: proxyAccountProfile.name,
description: proxyAccountProfile.description,
}, async (state) => {
await os.apiWithDialog('admin/update-proxy-account', {
name: state.name,
description: state.description,
});
fetchInstance(true);
});

function changeProxyAccountAvatar(ev) {
selectFile(ev.currentTarget ?? ev.target, i18n.ts.avatar).then(async (file) => {
let originalOrCropped = file;

const { canceled } = await os.confirm({
type: 'question',
text: i18n.ts.cropImageAsk,
okText: i18n.ts.cropYes,
cancelText: i18n.ts.cropNo,
});

if (!canceled) {
originalOrCropped = await os.cropImage(file, {
aspectRatio: 1,
});
}

const proxy = await os.apiWithDialog('admin/update-proxy-account', {
avatarId: originalOrCropped.id,
});
proxyAccount.value.avatarId = proxy.avatarId;
proxyAccount.value.avatarUrl = proxy.avatarUrl;
globalEvents.emit('requestClearPageCache');
});
}

function changeProxyAccountBanner(ev) {
selectFile(ev.currentTarget ?? ev.target, i18n.ts.banner).then(async (file) => {
let originalOrCropped = file;

const { canceled } = await os.confirm({
type: 'question',
text: i18n.ts.cropImageAsk,
okText: i18n.ts.cropYes,
cancelText: i18n.ts.cropNo,
});

if (!canceled) {
originalOrCropped = await os.cropImage(file, {
aspectRatio: 2,
});
}

const proxy = await os.apiWithDialog('admin/update-proxy-account', {
bannerId: originalOrCropped.id,
});
proxyAccount.value.bannerId = proxy.bannerId;
proxyAccount.value.bannerUrl = proxy.bannerUrl;
globalEvents.emit('requestClearPageCache');
});
}

function chooseProxyAccount() {
os.selectUser({ localOnly: true }).then(user => {
proxyAccount.value = user;
Expand All @@ -402,4 +490,32 @@ definePageMetadata(() => ({
font-size: 0.85em;
color: var(--MI_THEME-fgTransparentWeak);
}

.banner {
position: relative;
height: 130px;
background-size: cover;
background-position: center;
border-bottom: solid 1px var(--MI_THEME-divider);
overflow: clip;
}

.avatarContainer {
margin-top: -50px;
padding-bottom: 16px;
text-align: center;
}

.avatar {
display: inline-block;
width: 72px;
height: 72px;
margin: 0 auto 16px auto;
}

.bannerEdit {
position: absolute;
top: 16px;
right: 16px;
}
</style>

0 comments on commit 00c0ad6

Please sign in to comment.