parent
8d86f67a93
commit
105f41796b
|
@ -37,6 +37,7 @@ import { useStream } from '@/stream';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
import { claimAchievement } from '@/scripts/achievements';
|
import { claimAchievement } from '@/scripts/achievements';
|
||||||
import { $i } from '@/account';
|
import { $i } from '@/account';
|
||||||
|
import {userName} from "@/filters/user";
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
user: Misskey.entities.UserDetailed,
|
user: Misskey.entities.UserDetailed,
|
||||||
|
@ -73,7 +74,7 @@ async function onClick() {
|
||||||
if (isFollowing) {
|
if (isFollowing) {
|
||||||
const { canceled } = await os.confirm({
|
const { canceled } = await os.confirm({
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
text: i18n.t('unfollowConfirm', { name: props.user.name || props.user.username }),
|
text: i18n.t('unfollowConfirm', { name: userName(props.user) }),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (canceled) return;
|
if (canceled) return;
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<Mfm :text="user.name ?? user.username" :author="user" :plain="true" :nowrap="nowrap" :emojiUrls="user.emojis"/>
|
<Mfm :text="userName(user)" :author="user" :plain="true" :nowrap="nowrap" :emojiUrls="user.emojis"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { } from 'vue';
|
import { } from 'vue';
|
||||||
import * as misskey from 'cherrypick-js';
|
import * as misskey from 'cherrypick-js';
|
||||||
|
import { userName } from '@/filters/user';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
user: misskey.entities.User;
|
user: misskey.entities.User;
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
import * as misskey from 'cherrypick-js';
|
import * as misskey from 'cherrypick-js';
|
||||||
import * as Acct from 'cherrypick-js/built/acct';
|
import * as Acct from 'cherrypick-js/built/acct';
|
||||||
import { url } from '@/config';
|
import { url } from '@/config';
|
||||||
|
import {defaultStore} from "@/store";
|
||||||
|
|
||||||
export const acct = (user: misskey.Acct) => {
|
export const acct = (user: misskey.Acct) => {
|
||||||
return Acct.toString(user);
|
return Acct.toString(user);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const userName = (user: misskey.entities.User) => {
|
export const userName = (user: misskey.entities.User) => {
|
||||||
return user.name || user.username;
|
if (!defaultStore.state.nicknameEnabled) {
|
||||||
|
return user.name || user.username;
|
||||||
|
}
|
||||||
|
return defaultStore.reactiveState.nicknameMap.value[user.id] || user.name || user.username;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const userPage = (user: misskey.Acct, path?, absolute = false) => {
|
export const userPage = (user: misskey.Acct, path?, absolute = false) => {
|
||||||
|
|
|
@ -9,11 +9,12 @@ import * as Acct from 'cherrypick-js/built/acct';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import { mainRouter } from '@/router';
|
import { mainRouter } from '@/router';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
|
import {userName} from "@/filters/user";
|
||||||
|
|
||||||
async function follow(user): Promise<void> {
|
async function follow(user): Promise<void> {
|
||||||
const { canceled } = await os.confirm({
|
const { canceled } = await os.confirm({
|
||||||
type: 'question',
|
type: 'question',
|
||||||
text: i18n.t('followConfirm', { name: user.name || user.username }),
|
text: i18n.t('followConfirm', { name: userName(user) }),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (canceled) {
|
if (canceled) {
|
||||||
|
|
135
packages/frontend/src/pages/settings/cherrypick.vue
Normal file
135
packages/frontend/src/pages/settings/cherrypick.vue
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
<template>
|
||||||
|
<div class="_gaps_m">
|
||||||
|
<h1>CherryPick</h1>
|
||||||
|
<FormSection>
|
||||||
|
<template #label>独自機能</template>
|
||||||
|
<div class="_gaps_m">
|
||||||
|
<div>Ebisskeyが追加する独自機能を有効・無効にします。</div>
|
||||||
|
|
||||||
|
<MkSwitch v-model="nicknameEnabled">
|
||||||
|
ニックネーム機能
|
||||||
|
<template #caption>
|
||||||
|
ユーザーの名前を任意に変更できるようになります。変更は自分にのみ反映されます。<br>
|
||||||
|
頻繁に名前を変更するユーザーを識別するときなどに使えます。
|
||||||
|
</template>
|
||||||
|
</MkSwitch>
|
||||||
|
<MkSwitch v-model="numberQuoteEnabled">
|
||||||
|
数字引用機能
|
||||||
|
<template #caption>
|
||||||
|
ノートをコピーした上で末尾に数字をつけて投稿する機能。数字が本文の末尾にある場合はそれ+1、なければ「2」になります。
|
||||||
|
</template>
|
||||||
|
</MkSwitch>
|
||||||
|
<MkSwitch v-model="stealEnabled">
|
||||||
|
パクる機能
|
||||||
|
<template #caption>
|
||||||
|
ノートをコピーしてそのまま投稿する機能。
|
||||||
|
</template>
|
||||||
|
</MkSwitch>
|
||||||
|
</div>
|
||||||
|
</FormSection>
|
||||||
|
<FormSection>
|
||||||
|
<template #label>パッチ</template>
|
||||||
|
<div class="_gaps_m">
|
||||||
|
<div>Misskeyの機能に変更を加えます。</div>
|
||||||
|
|
||||||
|
<MkSwitch v-model="infoButtonForNoteActionsEnabled">
|
||||||
|
ノートに詳細表示ボタンを表示する
|
||||||
|
<template #caption>
|
||||||
|
オプション「ノートの操作部をホバー時のみ表示する」をオンにしたときに適用されます。
|
||||||
|
</template>
|
||||||
|
</MkSwitch>
|
||||||
|
<MkSwitch v-model="rememberPostFormToggleStateEnabled">
|
||||||
|
投稿フォームにて、プレビューのオン・オフを記憶する
|
||||||
|
</MkSwitch>
|
||||||
|
<MkSwitch v-model="reactableRemoteReactionEnabled">
|
||||||
|
リモートのカスタム絵文字リアクションでも、このサーバーに同じ名前の絵文字があればリアクションできるようにする
|
||||||
|
</MkSwitch>
|
||||||
|
</div>
|
||||||
|
</FormSection>
|
||||||
|
<FormSection>
|
||||||
|
<template #label><i class="ti ti-flask"/> Ebisskey Labs</template>
|
||||||
|
<div class="_gaps_m">
|
||||||
|
<div>まだ開発中の機能を試してみませんか。一部の機能はちゃんと動かないかもしれません。</div>
|
||||||
|
|
||||||
|
<MkSwitch v-model="usePostFormWindow">
|
||||||
|
投稿フォームをウィンドウとして表示
|
||||||
|
</MkSwitch>
|
||||||
|
<MkSwitch v-model="ebiNoteViewEnabled">
|
||||||
|
新しいノートUIを試す
|
||||||
|
</MkSwitch>
|
||||||
|
<MkNote :note="noteMock" />
|
||||||
|
</div>
|
||||||
|
</FormSection>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, ref, watch } from 'vue';
|
||||||
|
import MkSwitch from '@/components/MkSwitch.vue';
|
||||||
|
import FormSection from '@/components/form/section.vue';
|
||||||
|
import { defaultStore } from '@/store';
|
||||||
|
import * as os from '@/os';
|
||||||
|
import { unisonReload } from '@/scripts/unison-reload';
|
||||||
|
import { i18n } from '@/i18n';
|
||||||
|
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||||
|
import MkNote from "@/components/MkNote.vue";
|
||||||
|
import {Note, User} from "misskey-js/built/entities";
|
||||||
|
import {$i} from "@/account";
|
||||||
|
|
||||||
|
async function reloadAsk() {
|
||||||
|
const { canceled } = await os.confirm({
|
||||||
|
type: 'info',
|
||||||
|
text: i18n.ts.reloadToApplySetting,
|
||||||
|
});
|
||||||
|
if (canceled) return;
|
||||||
|
|
||||||
|
unisonReload();
|
||||||
|
}
|
||||||
|
|
||||||
|
const nicknameEnabled = computed(defaultStore.makeGetterSetter('nicknameEnabled'));
|
||||||
|
const numberQuoteEnabled = computed(defaultStore.makeGetterSetter('numberQuoteEnabled'));
|
||||||
|
const stealEnabled = computed(defaultStore.makeGetterSetter('stealEnabled'));
|
||||||
|
const infoButtonForNoteActionsEnabled = computed(defaultStore.makeGetterSetter('infoButtonForNoteActionsEnabled'));
|
||||||
|
const reactableRemoteReactionEnabled = computed(defaultStore.makeGetterSetter('reactableRemoteReactionEnabled'));
|
||||||
|
const rememberPostFormToggleStateEnabled = computed(defaultStore.makeGetterSetter('rememberPostFormToggleStateEnabled'));
|
||||||
|
const usePostFormWindow = computed(defaultStore.makeGetterSetter('usePostFormWindow'));
|
||||||
|
const ebiNoteViewEnabled = computed(defaultStore.makeGetterSetter('ebiNoteViewEnabledLab'));
|
||||||
|
|
||||||
|
const noteMock: Note = {
|
||||||
|
id: 'abc',
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
text: '> **エビ**(海老・蝦・魵)は、節足動物門・甲殻亜門・軟甲綱・十脚目(エビ目)のうち、カニ下目(短尾類)とヤドカリ下目(異尾類)以外の全ての種の総称である。すなわち、かつての**長尾類**(長尾亜目 Macrura)にあたる。現在、長尾亜目という分類群は廃止されており、学術的な分類ではなく便宜上の区分である。\n\n出典:https://ja.wikipedia.org/wiki/%E3%82%A8%E3%83%93',
|
||||||
|
cw: null,
|
||||||
|
user: $i as User,
|
||||||
|
userId: $i.id,
|
||||||
|
replyId: '',
|
||||||
|
renoteId: '',
|
||||||
|
files: [],
|
||||||
|
fileIds: [],
|
||||||
|
visibility: 'home',
|
||||||
|
reactions: {},
|
||||||
|
renoteCount: 20,
|
||||||
|
repliesCount: 10,
|
||||||
|
emojis: [],
|
||||||
|
localOnly: true,
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
watch([
|
||||||
|
numberQuoteEnabled,
|
||||||
|
stealEnabled,
|
||||||
|
infoButtonForNoteActionsEnabled,
|
||||||
|
reactableRemoteReactionEnabled,
|
||||||
|
], async () => {
|
||||||
|
await reloadAsk();
|
||||||
|
});
|
||||||
|
|
||||||
|
const headerActions = $computed(() => []);
|
||||||
|
|
||||||
|
const headerTabs = $computed(() => []);
|
||||||
|
|
||||||
|
definePageMetadata({
|
||||||
|
title: 'Ebisskey',
|
||||||
|
icon: 'ti ti-bulb-filled',
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -15,7 +15,12 @@
|
||||||
<div ref="bannerEl" class="banner" :style="style"></div>
|
<div ref="bannerEl" class="banner" :style="style"></div>
|
||||||
<div class="fade"></div>
|
<div class="fade"></div>
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<MkUserName class="name" :user="user" :nowrap="true"/>
|
<div class="name">
|
||||||
|
<MkUserName :user="user" :nowrap="true"/>
|
||||||
|
<button v-if="defaultStore.reactiveState.nicknameEnabled.value" v-tooltip="'ニックネームを編集…'" class="_button nickname-button" @click="editNickname(props.user)">
|
||||||
|
<i class="ti ti-edit"/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<div class="bottom">
|
<div class="bottom">
|
||||||
<span class="username"><MkAcct :user="user" :detail="true"/></span>
|
<span class="username"><MkAcct :user="user" :detail="true"/></span>
|
||||||
<span v-if="user.isAdmin" :title="i18n.ts.isAdmin" style="color: var(--badge);"><i class="ti ti-shield"></i></span>
|
<span v-if="user.isAdmin" :title="i18n.ts.isAdmin" style="color: var(--badge);"><i class="ti ti-shield"></i></span>
|
||||||
|
@ -185,6 +190,7 @@ import { api } from '@/os';
|
||||||
import { isFfVisibility } from '@/scripts/is-ff-visibility';
|
import { isFfVisibility } from '@/scripts/is-ff-visibility';
|
||||||
import { defaultStore } from '@/store';
|
import { defaultStore } from '@/store';
|
||||||
import { miLocalStorage } from '@/local-storage';
|
import { miLocalStorage } from '@/local-storage';
|
||||||
|
import { editNickname } from '@/scripts/edit-nickname';
|
||||||
|
|
||||||
const XPhotos = defineAsyncComponent(() => import('./index.photos.vue'));
|
const XPhotos = defineAsyncComponent(() => import('./index.photos.vue'));
|
||||||
const XActivity = defineAsyncComponent(() => import('./index.activity.vue'));
|
const XActivity = defineAsyncComponent(() => import('./index.activity.vue'));
|
||||||
|
@ -409,12 +415,25 @@ onUnmounted(() => {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
|
||||||
> .name {
|
> .name {
|
||||||
display: block;
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
line-height: 32px;
|
line-height: 32px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 1.8em;
|
font-size: 1.8em;
|
||||||
text-shadow: 0 0 8px #000;
|
text-shadow: 0 0 8px #000;
|
||||||
|
|
||||||
|
> .nickname-button {
|
||||||
|
-webkit-backdrop-filter: var(--blur, blur(8px));
|
||||||
|
backdrop-filter: var(--blur, blur(8px));
|
||||||
|
background: rgba(0, 0, 0, 0.2);
|
||||||
|
color: #ccc;
|
||||||
|
font-size: 0.7em;
|
||||||
|
line-height: 1;
|
||||||
|
width: 1.8em;
|
||||||
|
height: 1.8em;
|
||||||
|
border-radius: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> .bottom {
|
> .bottom {
|
||||||
|
@ -607,7 +626,7 @@ onUnmounted(() => {
|
||||||
font-size: 70%;
|
font-size: 70%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
>div {
|
>div {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
19
packages/frontend/src/scripts/edit-nickname.ts
Normal file
19
packages/frontend/src/scripts/edit-nickname.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import {User} from "misskey-js/built/entities";
|
||||||
|
import {defaultStore} from "@/store";
|
||||||
|
import * as os from '@/os';
|
||||||
|
|
||||||
|
export async function editNickname(user: User) {
|
||||||
|
const { result, canceled } = await os.inputText({
|
||||||
|
title: 'ニックネームを編集',
|
||||||
|
placeholder: user.name || user.username,
|
||||||
|
default: defaultStore.state.nicknameMap[user.id] ?? null,
|
||||||
|
});
|
||||||
|
if (canceled) return
|
||||||
|
const newMap = {...defaultStore.state.nicknameMap};
|
||||||
|
if (result) {
|
||||||
|
newMap[user.id] = result;
|
||||||
|
} else {
|
||||||
|
delete newMap[user.id];
|
||||||
|
}
|
||||||
|
await defaultStore.set('nicknameMap', newMap);
|
||||||
|
}
|
|
@ -376,6 +376,15 @@ export const defaultStore = markRaw(new Storage('base', {
|
||||||
where: 'device',
|
where: 'device',
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
nicknameEnabled: {
|
||||||
|
where: 'account',
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
nicknameMap: {
|
||||||
|
where: 'account',
|
||||||
|
default: {} as Record<string, string>,
|
||||||
|
},
|
||||||
|
// #endregion
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// TODO: 他のタブと永続化されたstateを同期
|
// TODO: 他のタブと永続化されたstateを同期
|
||||||
|
|
Loading…
Reference in a new issue