mirror of
https://github.com/misskey-dev/misskey.git
synced 2024-12-29 09:58:36 +01:00
bring back profile settings
This commit is contained in:
parent
fae4e6cba8
commit
04ac9f35e2
6 changed files with 167 additions and 32 deletions
19
locales/index.d.ts
vendored
19
locales/index.d.ts
vendored
|
@ -5239,6 +5239,21 @@ export interface Locale extends ILocale {
|
|||
*/
|
||||
"description": string;
|
||||
};
|
||||
"_profileSettings": {
|
||||
/**
|
||||
* プロフィール設定
|
||||
*/
|
||||
"title": string;
|
||||
/**
|
||||
* まずは基本的なプロフィールを設定して、ユーザーにあなたのことを知ってもらえるようにしましょう。
|
||||
*/
|
||||
"description": string;
|
||||
/**
|
||||
* ここで設定した項目は後でいつでも変更できます。
|
||||
* チュートリアル終了後には、更に多彩なプロフィール設定をご利用いただけます!
|
||||
*/
|
||||
"youCanChangeThemLater": string;
|
||||
};
|
||||
"_note": {
|
||||
/**
|
||||
* ノートって何?
|
||||
|
@ -5487,7 +5502,7 @@ export interface Locale extends ILocale {
|
|||
*/
|
||||
"welcomeToX": ParameterizedString<"name">;
|
||||
/**
|
||||
* 「{name}に登録したは良いものの、どう使えばいいか分からない…💦」といったことを防ぐために、まずはMisskeyの基本的な使い方を学びましょう。
|
||||
* プロフィールを設定したり、{name}の基本的な使い方を学んだりして、すぐに使い始められるようにしましょう。
|
||||
*/
|
||||
"description": ParameterizedString<"name">;
|
||||
/**
|
||||
|
@ -5519,7 +5534,7 @@ export interface Locale extends ILocale {
|
|||
*/
|
||||
"profile": string;
|
||||
/**
|
||||
* 他のユーザーが親しみやすいように、プロフィールをつくりましょう。
|
||||
* プロフィールをかんぺきにして、自分をアピールしましょう。
|
||||
*/
|
||||
"profileDescription": string;
|
||||
/**
|
||||
|
|
|
@ -1314,6 +1314,10 @@ _initialTutorial:
|
|||
_landing:
|
||||
title: "チュートリアルへようこそ"
|
||||
description: "ここでは、Misskeyの基本的な使い方や機能を確認できます。"
|
||||
_profileSettings:
|
||||
title: "プロフィール設定"
|
||||
description: "まずは基本的なプロフィールを設定して、ユーザーにあなたのことを知ってもらえるようにしましょう。"
|
||||
youCanChangeThemLater: "ここで設定した項目は後でいつでも変更できます。\nチュートリアル終了後には、更に多彩なプロフィール設定をご利用いただけます!"
|
||||
_note:
|
||||
title: "ノートって何?"
|
||||
description: "Misskeyでの投稿は「ノート」と呼びます。ノートはタイムラインに時系列で並んでいて、リアルタイムで更新されていきます。"
|
||||
|
@ -1383,7 +1387,7 @@ _initialTutorial:
|
|||
_onboardingLanding:
|
||||
accountCreated: "アカウントの作成が完了しました!"
|
||||
welcomeToX: "ようこそ、{name}へ!"
|
||||
description: "「{name}に登録したは良いものの、どう使えばいいか分からない…💦」といったことを防ぐために、まずはMisskeyの基本的な使い方を学びましょう。"
|
||||
description: "プロフィールを設定したり、{name}の基本的な使い方を学んだりして、すぐに使い始められるようにしましょう。"
|
||||
takesAbout: "このチュートリアルの所要時間は{min}分程度です。\nチュートリアルを完了すると実績が解除されます。"
|
||||
adminForcesToTakeTutorial: "このサーバーの管理者は新規ユーザーにチュートリアルを完了することを義務付けています。\nチュートリアルを完了するまでMisskeyを使い始めることはできません。"
|
||||
_onboardingDone:
|
||||
|
@ -1391,7 +1395,7 @@ _initialTutorial:
|
|||
backToOriginalPath: "元のページに戻る"
|
||||
backToOriginalPathDescription: "あなたがアクセスしようとしていたページに戻ります。"
|
||||
profile: "プロフィール設定"
|
||||
profileDescription: "他のユーザーが親しみやすいように、プロフィールをつくりましょう。"
|
||||
profileDescription: "プロフィールをかんぺきにして、自分をアピールしましょう。"
|
||||
exploreDescription: "人気のノートやユーザーを見つけて交流をはじめましょう。"
|
||||
goToTimeline: "ホーム画面に進む"
|
||||
goToTimelineDescription: "設定等を行わず、通常のホーム画面(タイムライン)に進みます。"
|
||||
|
|
102
packages/frontend/src/components/MkTutorial.ProfileSettings.vue
Normal file
102
packages/frontend/src/components/MkTutorial.ProfileSettings.vue
Normal file
|
@ -0,0 +1,102 @@
|
|||
<!--
|
||||
SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div class="_gaps">
|
||||
<div style="word-break: auto-phrase; text-align: center; padding: 0 16px;">{{ i18n.ts._initialTutorial._profileSettings.description }}</div>
|
||||
|
||||
<FormSlot>
|
||||
<template #label>{{ i18n.ts.avatar }}</template>
|
||||
<div v-adaptive-bg :class="$style.avatarSection" class="_panel">
|
||||
<MkAvatar :class="$style.avatar" :user="$i" @click="setAvatar"/>
|
||||
<div style="margin-top: 16px;">
|
||||
<MkButton primary rounded inline @click="setAvatar">{{ i18n.ts._profile.changeAvatar }}</MkButton>
|
||||
</div>
|
||||
</div>
|
||||
</FormSlot>
|
||||
|
||||
<MkInput v-model="name" :max="30" manualSave>
|
||||
<template #label>{{ i18n.ts._profile.name }}</template>
|
||||
</MkInput>
|
||||
|
||||
<MkTextarea v-model="description" :max="500" tall manualSave>
|
||||
<template #label>{{ i18n.ts._profile.description }}</template>
|
||||
</MkTextarea>
|
||||
|
||||
<MkInfo>{{ i18n.ts._initialTutorial._profileSettings.youCanChangeThemLater }}</MkInfo>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from 'vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import MkTextarea from '@/components/MkTextarea.vue';
|
||||
import FormSlot from '@/components/form/slot.vue';
|
||||
import MkInfo from '@/components/MkInfo.vue';
|
||||
import { selectFile } from '@/scripts/select-file.js';
|
||||
import * as os from '@/os.js';
|
||||
import { signinRequired } from '@/account.js';
|
||||
|
||||
const $i = signinRequired();
|
||||
|
||||
const name = ref($i.name ?? '');
|
||||
const description = ref($i.description ?? '');
|
||||
|
||||
watch(name, () => {
|
||||
os.apiWithDialog('i/update', {
|
||||
// 空文字列をnullにしたいので??は使うな
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
||||
name: name.value || null,
|
||||
});
|
||||
});
|
||||
|
||||
watch(description, () => {
|
||||
os.apiWithDialog('i/update', {
|
||||
// 空文字列をnullにしたいので??は使うな
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
||||
description: description.value || null,
|
||||
});
|
||||
});
|
||||
|
||||
function setAvatar(ev: MouseEvent) {
|
||||
selectFile(ev.currentTarget ?? ev.target).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 i = await os.apiWithDialog('i/update', {
|
||||
avatarId: originalOrCropped.id,
|
||||
});
|
||||
$i.avatarId = i.avatarId;
|
||||
$i.avatarUrl = i.avatarUrl;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
.avatarSection {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background: var(--bg);
|
||||
}
|
||||
</style>
|
|
@ -34,11 +34,18 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<div v-else-if="page === 1" key="tutorialPage_1" :class="$style.pageContainer">
|
||||
<div :class="$style.pageRoot">
|
||||
<MkSpacer :marginMin="20" :marginMax="28" :class="$style.pageMain">
|
||||
<XNote phase="aboutNote"/>
|
||||
<XProfileSettings/>
|
||||
</MkSpacer>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="page === 2" key="tutorialPage_2" :class="$style.pageContainer">
|
||||
<div :class="$style.pageRoot">
|
||||
<MkSpacer :marginMin="20" :marginMax="28" :class="$style.pageMain">
|
||||
<XNote phase="aboutNote"/>
|
||||
</MkSpacer>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="page === 3" key="tutorialPage_3" :class="$style.pageContainer">
|
||||
<div :class="$style.pageRoot">
|
||||
<MkSpacer :marginMin="20" :marginMax="28" :class="$style.pageMain">
|
||||
<div class="_gaps">
|
||||
|
@ -48,28 +55,28 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</MkSpacer>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="page === 3" key="tutorialPage_3" :class="$style.pageContainer">
|
||||
<div v-else-if="page === 4" key="tutorialPage_4" :class="$style.pageContainer">
|
||||
<div :class="$style.pageRoot">
|
||||
<MkSpacer :marginMin="20" :marginMax="28" :class="$style.pageMain">
|
||||
<XTimeline/>
|
||||
</MkSpacer>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="page === 4" key="tutorialPage_4" :class="$style.pageContainer">
|
||||
<div v-else-if="page === 5" key="tutorialPage_5" :class="$style.pageContainer">
|
||||
<div :class="$style.pageRoot">
|
||||
<MkSpacer :marginMin="20" :marginMax="28" :class="$style.pageMain">
|
||||
<XFollowUsers/>
|
||||
</MkSpacer>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="page === 5" key="tutorialPage_5" :class="$style.pageContainer">
|
||||
<div v-else-if="page === 6" key="tutorialPage_6" :class="$style.pageContainer">
|
||||
<div :class="$style.pageRoot">
|
||||
<MkSpacer :marginMin="20" :marginMax="28" :class="$style.pageMain">
|
||||
<XPostNote/>
|
||||
</MkSpacer>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="page === 6" key="tutorialPage_6" :class="$style.pageContainer">
|
||||
<div v-else-if="page === 7" key="tutorialPage_7" :class="$style.pageContainer">
|
||||
<div :class="$style.pageRoot">
|
||||
<MkSpacer :marginMin="20" :marginMax="28" :class="$style.pageMain">
|
||||
<div class="_gaps">
|
||||
|
@ -79,7 +86,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</MkSpacer>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="page === 7" key="tutorialPage_7" :class="$style.pageContainer">
|
||||
<div v-else-if="page === 8" key="tutorialPage_8" :class="$style.pageContainer">
|
||||
<div :class="$style.pageRoot">
|
||||
<MkSpacer :marginMin="20" :marginMax="28" :class="$style.pageMain">
|
||||
<div class="_gaps">
|
||||
|
@ -88,7 +95,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</MkSpacer>
|
||||
</div>
|
||||
</div>
|
||||
<slot v-else-if="page === 8" key="tutorialPage_8" name="finish" :close="() => emit('close')" :prev="prev">
|
||||
<slot v-else-if="page === 9" key="tutorialPage_9" name="finish" :close="() => emit('close')" :prev="prev">
|
||||
<div :class="$style.centerPage">
|
||||
<MkAnimBg style="position: absolute; top: 0;" :scale="1.5"/>
|
||||
<MkSpacer :marginMin="20" :marginMax="28">
|
||||
|
@ -124,13 +131,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<script lang="ts">
|
||||
|
||||
// チュートリアルの枚数を増やしたら必ず変更すること!!
|
||||
export const MAX_PAGE = 8;
|
||||
export const MAX_PAGE = 9;
|
||||
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, watch } from 'vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import XProfileSettings from '@/components/MkTutorial.ProfileSettings.vue';
|
||||
import XNote from '@/components/MkTutorial.Note.vue';
|
||||
import XTimeline from '@/components/MkTutorial.Timeline.vue';
|
||||
import XFollowUsers from '@/components/MkTutorial.FollowUsers.vue';
|
||||
|
@ -171,9 +179,9 @@ const isReactionTutorialPushed = ref<boolean>(isTest);
|
|||
const isSensitiveTutorialSucceeded = ref<boolean>(isTest);
|
||||
|
||||
const canContinue = computed(() => {
|
||||
if (page.value === 2) {
|
||||
if (page.value === 3) {
|
||||
return isReactionTutorialPushed.value;
|
||||
} else if (page.value === 6) {
|
||||
} else if (page.value === 7) {
|
||||
return isSensitiveTutorialSucceeded.value;
|
||||
} else {
|
||||
return true;
|
||||
|
@ -181,9 +189,11 @@ const canContinue = computed(() => {
|
|||
});
|
||||
|
||||
function next() {
|
||||
if (page.value === 3 && !props.withSetup) {
|
||||
if (page.value === 0 && !props.withSetup) {
|
||||
page.value += 2;
|
||||
} else if (page.value === 6 && !props.withSetup) {
|
||||
} else if (page.value === 4 && !props.withSetup) {
|
||||
page.value += 2;
|
||||
} else if (page.value === 7 && !props.withSetup) {
|
||||
page.value += 2;
|
||||
} else {
|
||||
page.value++;
|
||||
|
@ -193,9 +203,11 @@ function next() {
|
|||
}
|
||||
|
||||
function prev() {
|
||||
if (page.value === 5 && !props.withSetup) {
|
||||
if (page.value === 2 && !props.withSetup) {
|
||||
page.value -= 2;
|
||||
} else if (page.value === 8 && !props.withSetup) {
|
||||
} else if (page.value === 6 && !props.withSetup) {
|
||||
page.value -= 2;
|
||||
} else if (page.value === 9 && !props.withSetup) {
|
||||
page.value -= 2;
|
||||
} else {
|
||||
page.value--;
|
||||
|
|
|
@ -11,11 +11,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
@close="close(true)"
|
||||
@closed="emit('closed')"
|
||||
>
|
||||
<template v-if="page === 1" #header><i class="ti ti-pencil"></i> {{ i18n.ts._initialTutorial._note.title }}</template>
|
||||
<template v-else-if="page === 2" #header><i class="ti ti-mood-smile"></i> {{ i18n.ts._initialTutorial._reaction.title }}</template>
|
||||
<template v-else-if="page === 3" #header><i class="ti ti-home"></i> {{ i18n.ts._initialTutorial._timeline.title }}</template>
|
||||
<template v-else-if="page === 5" #header><i class="ti ti-pencil-plus"></i> {{ i18n.ts._initialTutorial._postNote.title }}</template>
|
||||
<template v-else-if="page === 6" #header><i class="ti ti-eye-exclamation"></i> {{ i18n.ts._initialTutorial._howToMakeAttachmentsSensitive.title }}</template>
|
||||
<template v-if="page === 2" #header><i class="ti ti-pencil"></i> {{ i18n.ts._initialTutorial._note.title }}</template>
|
||||
<template v-else-if="page === 3" #header><i class="ti ti-mood-smile"></i> {{ i18n.ts._initialTutorial._reaction.title }}</template>
|
||||
<template v-else-if="page === 4" #header><i class="ti ti-home"></i> {{ i18n.ts._initialTutorial._timeline.title }}</template>
|
||||
<template v-else-if="page === 6" #header><i class="ti ti-pencil-plus"></i> {{ i18n.ts._initialTutorial._postNote.title }}</template>
|
||||
<template v-else-if="page === 7" #header><i class="ti ti-eye-exclamation"></i> {{ i18n.ts._initialTutorial._howToMakeAttachmentsSensitive.title }}</template>
|
||||
<template v-else #header>{{ i18n.ts._initialTutorial.title }}</template>
|
||||
|
||||
<XTutorial
|
||||
|
|
|
@ -9,13 +9,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<div :class="[$style.onboardingContainer]">
|
||||
<div :class="[$style.tutorialTitle, { [$style.showing]: (page !== 0) }]">
|
||||
<div :class="$style.text">
|
||||
<span v-if="page === 1"><i class="ti ti-pencil"></i> {{ i18n.ts._initialTutorial._note.title }}</span>
|
||||
<span v-else-if="page === 2"><i class="ti ti-mood-smile"></i> {{ i18n.ts._initialTutorial._reaction.title }}</span>
|
||||
<span v-else-if="page === 3"><i class="ti ti-home"></i> {{ i18n.ts._initialTutorial._timeline.title }}</span>
|
||||
<span v-else-if="page === 4"><i class="ti ti-user-plus"></i> {{ i18n.ts.follow }}</span>
|
||||
<span v-else-if="page === 5"><i class="ti ti-pencil-plus"></i> {{ i18n.ts._initialTutorial._postNote.title }}</span>
|
||||
<span v-else-if="page === 6"><i class="ti ti-eye-exclamation"></i> {{ i18n.ts._initialTutorial._howToMakeAttachmentsSensitive.title }}</span>
|
||||
<span v-else-if="page === 7"><i class="ti ti-lock"></i> {{ i18n.ts.privacy }}</span>
|
||||
<span v-if="page === 1"><i class="ti ti-user-edit"></i> {{ i18n.ts._initialTutorial._profileSettings.title }}</span>
|
||||
<span v-else-if="page === 2"><i class="ti ti-pencil"></i> {{ i18n.ts._initialTutorial._note.title }}</span>
|
||||
<span v-else-if="page === 3"><i class="ti ti-mood-smile"></i> {{ i18n.ts._initialTutorial._reaction.title }}</span>
|
||||
<span v-else-if="page === 4"><i class="ti ti-home"></i> {{ i18n.ts._initialTutorial._timeline.title }}</span>
|
||||
<span v-else-if="page === 5"><i class="ti ti-user-plus"></i> {{ i18n.ts.follow }}</span>
|
||||
<span v-else-if="page === 6"><i class="ti ti-pencil-plus"></i> {{ i18n.ts._initialTutorial._postNote.title }}</span>
|
||||
<span v-else-if="page === 7"><i class="ti ti-eye-exclamation"></i> {{ i18n.ts._initialTutorial._howToMakeAttachmentsSensitive.title }}</span>
|
||||
<span v-else-if="page === 8"><i class="ti ti-lock"></i> {{ i18n.ts.privacy }}</span>
|
||||
<span v-else-if="page === MAX_PAGE"><!-- なんもなし --></span>
|
||||
<span v-else>{{ i18n.ts._initialTutorial.title }}</span>
|
||||
</div>
|
||||
|
@ -219,7 +220,8 @@ onMounted(() => {
|
|||
setTimeout(() => {
|
||||
animationPhase.value = 4;
|
||||
confetti({
|
||||
spread: 70,
|
||||
spread: 75,
|
||||
particleCount: 100,
|
||||
origin: { y: 0.5 },
|
||||
});
|
||||
}, 1000);
|
||||
|
@ -232,7 +234,7 @@ onMounted(() => {
|
|||
// #endregion
|
||||
|
||||
definePageMetadata(() => ({
|
||||
title: 'Onboarding',
|
||||
title: i18n.tsx._initialTutorial._onboardingLanding.welcomeToX({ name: instance.name ?? host }),
|
||||
description: 'Welcome to Misskey!',
|
||||
}));
|
||||
</script>
|
||||
|
|
Loading…
Reference in a new issue