refactor(client): Refine routing (#8846)
This commit is contained in:
@ -127,30 +127,32 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineExpose, onMounted, ref } from 'vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import FormSection from '@/components/form/section.vue';
|
||||
import MkKeyValue from '@/components/key-value.vue';
|
||||
import * as os from '@/os';
|
||||
import number from '@/filters/number';
|
||||
import bytes from '@/filters/bytes';
|
||||
import * as symbols from '@/symbols';
|
||||
import { $i } from '@/account';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
const stats = ref<any>({});
|
||||
|
||||
onMounted(() => {
|
||||
os.api('users/stats', {
|
||||
userId: $i!.id
|
||||
userId: $i!.id,
|
||||
}).then(response => {
|
||||
stats.value = response;
|
||||
});
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: i18n.ts.accountInfo,
|
||||
icon: 'fas fa-info-circle'
|
||||
}
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.accountInfo,
|
||||
icon: 'fas fa-info-circle',
|
||||
});
|
||||
</script>
|
||||
|
@ -21,13 +21,13 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineAsyncComponent, defineExpose, ref } from 'vue';
|
||||
import { defineAsyncComponent, ref } from 'vue';
|
||||
import FormSuspense from '@/components/form/suspense.vue';
|
||||
import FormButton from '@/components/ui/button.vue';
|
||||
import * as os from '@/os';
|
||||
import * as symbols from '@/symbols';
|
||||
import { getAccounts, addAccount as addAccounts, login, $i } from '@/account';
|
||||
import { getAccounts, addAccount as addAccounts, removeAccount as _removeAccount, login, $i } from '@/account';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
const storedAccounts = ref<any>(null);
|
||||
const accounts = ref<any>(null);
|
||||
@ -39,7 +39,7 @@ const init = async () => {
|
||||
console.log(storedAccounts.value);
|
||||
|
||||
return os.api('users/show', {
|
||||
userIds: storedAccounts.value.map(x => x.id)
|
||||
userIds: storedAccounts.value.map(x => x.id),
|
||||
});
|
||||
}).then(response => {
|
||||
accounts.value = response;
|
||||
@ -70,6 +70,10 @@ function addAccount(ev) {
|
||||
}], ev.currentTarget ?? ev.target);
|
||||
}
|
||||
|
||||
function removeAccount(account) {
|
||||
_removeAccount(account.id);
|
||||
}
|
||||
|
||||
function addExistingAccount() {
|
||||
os.popup(defineAsyncComponent(() => import('@/components/signin-dialog.vue')), {}, {
|
||||
done: res => {
|
||||
@ -98,12 +102,14 @@ function switchAccountWithToken(token: string) {
|
||||
login(token);
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: i18n.ts.accounts,
|
||||
icon: 'fas fa-users',
|
||||
bg: 'var(--bg)',
|
||||
}
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.accounts,
|
||||
icon: 'fas fa-users',
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -7,12 +7,12 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineAsyncComponent, defineExpose, ref } from 'vue';
|
||||
import { defineAsyncComponent, ref } from 'vue';
|
||||
import FormLink from '@/components/form/link.vue';
|
||||
import FormButton from '@/components/ui/button.vue';
|
||||
import * as os from '@/os';
|
||||
import * as symbols from '@/symbols';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
const isDesktop = ref(window.innerWidth >= 1100);
|
||||
|
||||
@ -29,17 +29,19 @@ function generateToken() {
|
||||
os.alert({
|
||||
type: 'success',
|
||||
title: i18n.ts.token,
|
||||
text: token
|
||||
text: token,
|
||||
});
|
||||
},
|
||||
}, 'closed');
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: 'API',
|
||||
icon: 'fas fa-key',
|
||||
bg: 'var(--bg)',
|
||||
}
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: 'API',
|
||||
icon: 'fas fa-key',
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
@ -7,7 +7,7 @@
|
||||
<div>{{ i18n.ts.nothing }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot="{items}">
|
||||
<template #default="{items}">
|
||||
<div v-for="token in items" :key="token.id" class="_panel bfomjevm">
|
||||
<img v-if="token.iconUrl" class="icon" :src="token.iconUrl" alt=""/>
|
||||
<div class="body">
|
||||
@ -38,11 +38,11 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineExpose, ref } from 'vue';
|
||||
import { ref } from 'vue';
|
||||
import FormPagination from '@/components/ui/pagination.vue';
|
||||
import * as os from '@/os';
|
||||
import * as symbols from '@/symbols';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
const list = ref<any>(null);
|
||||
|
||||
@ -50,8 +50,8 @@ const pagination = {
|
||||
endpoint: 'i/apps' as const,
|
||||
limit: 100,
|
||||
params: {
|
||||
sort: '+lastUsedAt'
|
||||
}
|
||||
sort: '+lastUsedAt',
|
||||
},
|
||||
};
|
||||
|
||||
function revoke(token) {
|
||||
@ -60,12 +60,14 @@ function revoke(token) {
|
||||
});
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: i18n.ts.installedApps,
|
||||
icon: 'fas fa-plug',
|
||||
bg: 'var(--bg)',
|
||||
}
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.installedApps,
|
||||
icon: 'fas fa-plug',
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -9,13 +9,13 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineExpose, ref, watch } from 'vue';
|
||||
import { ref, watch } from 'vue';
|
||||
import FormTextarea from '@/components/form/textarea.vue';
|
||||
import FormInfo from '@/components/ui/info.vue';
|
||||
import * as os from '@/os';
|
||||
import { unisonReload } from '@/scripts/unison-reload';
|
||||
import * as symbols from '@/symbols';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
const localCustomCss = ref(localStorage.getItem('customCss') ?? '');
|
||||
|
||||
@ -35,11 +35,13 @@ watch(localCustomCss, async () => {
|
||||
await apply();
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: i18n.ts.customCss,
|
||||
icon: 'fas fa-code',
|
||||
bg: 'var(--bg)',
|
||||
}
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.customCss,
|
||||
icon: 'fas fa-code',
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
@ -30,7 +30,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, defineExpose, watch } from 'vue';
|
||||
import { computed, watch } from 'vue';
|
||||
import FormSwitch from '@/components/form/switch.vue';
|
||||
import FormLink from '@/components/form/link.vue';
|
||||
import FormRadios from '@/components/form/radios.vue';
|
||||
@ -39,8 +39,8 @@ import FormGroup from '@/components/form/group.vue';
|
||||
import { deckStore } from '@/ui/deck/deck-store';
|
||||
import * as os from '@/os';
|
||||
import { unisonReload } from '@/scripts/unison-reload';
|
||||
import * as symbols from '@/symbols';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
const navWindow = computed(deckStore.makeGetterSetter('navWindow'));
|
||||
const alwaysShowMainColumn = computed(deckStore.makeGetterSetter('alwaysShowMainColumn'));
|
||||
@ -62,7 +62,7 @@ watch(navWindow, async () => {
|
||||
async function setProfile() {
|
||||
const { canceled, result: name } = await os.inputText({
|
||||
title: i18n.ts._deck.profile,
|
||||
allowEmpty: false
|
||||
allowEmpty: false,
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
@ -70,11 +70,13 @@ async function setProfile() {
|
||||
unisonReload();
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: i18n.ts.deck,
|
||||
icon: 'fas fa-columns',
|
||||
bg: 'var(--bg)',
|
||||
}
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.deck,
|
||||
icon: 'fas fa-columns',
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
@ -8,13 +8,12 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineExpose } from 'vue';
|
||||
import FormInfo from '@/components/ui/info.vue';
|
||||
import FormButton from '@/components/ui/button.vue';
|
||||
import * as os from '@/os';
|
||||
import { signout } from '@/account';
|
||||
import * as symbols from '@/symbols';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
async function deleteAccount() {
|
||||
{
|
||||
@ -27,12 +26,12 @@ async function deleteAccount() {
|
||||
|
||||
const { canceled, result: password } = await os.inputText({
|
||||
title: i18n.ts.password,
|
||||
type: 'password'
|
||||
type: 'password',
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
await os.apiWithDialog('i/delete-account', {
|
||||
password: password
|
||||
password: password,
|
||||
});
|
||||
|
||||
await os.alert({
|
||||
@ -42,11 +41,13 @@ async function deleteAccount() {
|
||||
await signout();
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: i18n.ts._accountDelete.accountDelete,
|
||||
icon: 'fas fa-exclamation-triangle',
|
||||
bg: 'var(--bg)',
|
||||
}
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts._accountDelete.accountDelete,
|
||||
icon: 'fas fa-exclamation-triangle',
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
@ -34,7 +34,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, defineExpose, ref } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import tinycolor from 'tinycolor2';
|
||||
import FormLink from '@/components/form/link.vue';
|
||||
import FormSwitch from '@/components/form/switch.vue';
|
||||
@ -43,10 +43,10 @@ import MkKeyValue from '@/components/key-value.vue';
|
||||
import FormSplit from '@/components/form/split.vue';
|
||||
import * as os from '@/os';
|
||||
import bytes from '@/filters/bytes';
|
||||
import * as symbols from '@/symbols';
|
||||
import { defaultStore } from '@/store';
|
||||
import MkChart from '@/components/chart.vue';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
const fetching = ref(true);
|
||||
const usage = ref<any>(null);
|
||||
@ -59,8 +59,8 @@ const meterStyle = computed(() => {
|
||||
background: tinycolor({
|
||||
h: 180 - (usage.value / capacity.value * 180),
|
||||
s: 0.7,
|
||||
l: 0.5
|
||||
})
|
||||
l: 0.5,
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
@ -74,7 +74,7 @@ os.api('drive').then(info => {
|
||||
|
||||
if (defaultStore.state.uploadFolder) {
|
||||
os.api('drive/folders/show', {
|
||||
folderId: defaultStore.state.uploadFolder
|
||||
folderId: defaultStore.state.uploadFolder,
|
||||
}).then(response => {
|
||||
uploadFolder.value = response;
|
||||
});
|
||||
@ -86,7 +86,7 @@ function chooseUploadFolder() {
|
||||
os.success();
|
||||
if (defaultStore.state.uploadFolder) {
|
||||
uploadFolder.value = await os.api('drive/folders/show', {
|
||||
folderId: defaultStore.state.uploadFolder
|
||||
folderId: defaultStore.state.uploadFolder,
|
||||
});
|
||||
} else {
|
||||
uploadFolder.value = null;
|
||||
@ -94,12 +94,14 @@ function chooseUploadFolder() {
|
||||
});
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: i18n.ts.drive,
|
||||
icon: 'fas fa-cloud',
|
||||
bg: 'var(--bg)',
|
||||
}
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.drive,
|
||||
icon: 'fas fa-cloud',
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -40,27 +40,27 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineExpose, onMounted, ref, watch } from 'vue';
|
||||
import { onMounted, ref, watch } from 'vue';
|
||||
import FormSection from '@/components/form/section.vue';
|
||||
import FormInput from '@/components/form/input.vue';
|
||||
import FormSwitch from '@/components/form/switch.vue';
|
||||
import * as os from '@/os';
|
||||
import * as symbols from '@/symbols';
|
||||
import { $i } from '@/account';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
const emailAddress = ref($i!.email);
|
||||
|
||||
const onChangeReceiveAnnouncementEmail = (v) => {
|
||||
os.api('i/update', {
|
||||
receiveAnnouncementEmail: v
|
||||
receiveAnnouncementEmail: v,
|
||||
});
|
||||
};
|
||||
|
||||
const saveEmailAddress = () => {
|
||||
os.inputText({
|
||||
title: i18n.ts.password,
|
||||
type: 'password'
|
||||
type: 'password',
|
||||
}).then(({ canceled, result: password }) => {
|
||||
if (canceled) return;
|
||||
os.apiWithDialog('i/update-email', {
|
||||
@ -86,7 +86,7 @@ const saveNotificationSettings = () => {
|
||||
...[emailNotification_follow.value ? 'follow' : null],
|
||||
...[emailNotification_receiveFollowRequest.value ? 'receiveFollowRequest' : null],
|
||||
...[emailNotification_groupInvited.value ? 'groupInvited' : null],
|
||||
].filter(x => x != null)
|
||||
].filter(x => x != null),
|
||||
});
|
||||
};
|
||||
|
||||
@ -100,11 +100,13 @@ onMounted(() => {
|
||||
});
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: i18n.ts.email,
|
||||
icon: 'fas fa-envelope',
|
||||
bg: 'var(--bg)',
|
||||
}
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.email,
|
||||
icon: 'fas fa-envelope',
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
@ -48,7 +48,8 @@
|
||||
<FormSwitch v-model="disableShowingAnimatedImages" class="_formBlock">{{ i18n.ts.disableShowingAnimatedImages }}</FormSwitch>
|
||||
<FormSwitch v-model="squareAvatars" class="_formBlock">{{ i18n.ts.squareAvatars }}</FormSwitch>
|
||||
<FormSwitch v-model="useSystemFont" class="_formBlock">{{ i18n.ts.useSystemFont }}</FormSwitch>
|
||||
<FormSwitch v-model="useOsNativeEmojis" class="_formBlock">{{ i18n.ts.useOsNativeEmojis }}
|
||||
<FormSwitch v-model="useOsNativeEmojis" class="_formBlock">
|
||||
{{ i18n.ts.useOsNativeEmojis }}
|
||||
<div><Mfm :key="useOsNativeEmojis" text="🍮🍦🍭🍩🍰🍫🍬🥞🍪"/></div>
|
||||
</FormSwitch>
|
||||
<FormSwitch v-model="disableDrawer" class="_formBlock">{{ i18n.ts.disableDrawer }}</FormSwitch>
|
||||
@ -92,7 +93,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, defineExpose, ref, watch } from 'vue';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import FormSwitch from '@/components/form/switch.vue';
|
||||
import FormSelect from '@/components/form/select.vue';
|
||||
import FormRadios from '@/components/form/radios.vue';
|
||||
@ -104,8 +105,8 @@ import { langs } from '@/config';
|
||||
import { defaultStore } from '@/store';
|
||||
import * as os from '@/os';
|
||||
import { unisonReload } from '@/scripts/unison-reload';
|
||||
import * as symbols from '@/symbols';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
const lang = ref(localStorage.getItem('lang'));
|
||||
const fontSize = ref(localStorage.getItem('fontSize'));
|
||||
@ -173,16 +174,18 @@ watch([
|
||||
aiChanMode,
|
||||
showGapBetweenNotesInTimeline,
|
||||
instanceTicker,
|
||||
overridedDeviceKind
|
||||
overridedDeviceKind,
|
||||
], async () => {
|
||||
await reloadAsk();
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: i18n.ts.general,
|
||||
icon: 'fas fa-cogs',
|
||||
bg: 'var(--bg)'
|
||||
}
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.general,
|
||||
icon: 'fas fa-cogs',
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
@ -38,15 +38,15 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineExpose, ref } from 'vue';
|
||||
import { ref } from 'vue';
|
||||
import MkButton from '@/components/ui/button.vue';
|
||||
import FormSection from '@/components/form/section.vue';
|
||||
import FormGroup from '@/components/form/group.vue';
|
||||
import FormSwitch from '@/components/form/switch.vue';
|
||||
import * as os from '@/os';
|
||||
import { selectFile } from '@/scripts/select-file';
|
||||
import * as symbols from '@/symbols';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
const excludeMutingUsers = ref(false);
|
||||
const excludeInactiveUsers = ref(false);
|
||||
@ -116,12 +116,14 @@ const importBlocking = async (ev) => {
|
||||
os.api('i/import-blocking', { fileId: file.id }).then(onImportSuccess).catch(onError);
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: i18n.ts.importAndExport,
|
||||
icon: 'fas fa-boxes',
|
||||
bg: 'var(--bg)',
|
||||
}
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.importAndExport,
|
||||
icon: 'fas fa-boxes',
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -1,46 +1,42 @@
|
||||
<template>
|
||||
<MkSpacer :content-max="900" :margin-min="20" :margin-max="32">
|
||||
<div ref="el" class="vvcocwet" :class="{ wide: !narrow }">
|
||||
<div class="header">
|
||||
<div class="title">
|
||||
<MkA v-if="narrow" to="/settings">{{ $ts.settings }}</MkA>
|
||||
<template v-else>{{ $ts.settings }}</template>
|
||||
</div>
|
||||
<div v-if="childInfo" class="subtitle">{{ childInfo.title }}</div>
|
||||
</div>
|
||||
<div class="body">
|
||||
<div v-if="!narrow || initialPage == null" class="nav">
|
||||
<div class="baaadecd">
|
||||
<MkInfo v-if="emailNotConfigured" warn class="info">{{ $ts.emailNotConfiguredWarning }} <MkA to="/settings/email" class="_link">{{ $ts.configure }}</MkA></MkInfo>
|
||||
<MkSuperMenu :def="menuDef" :grid="initialPage == null"></MkSuperMenu>
|
||||
<MkStickyContainer>
|
||||
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
||||
<MkSpacer :content-max="900" :margin-min="20" :margin-max="32">
|
||||
<div ref="el" class="vvcocwet" :class="{ wide: !narrow }">
|
||||
<div class="body">
|
||||
<div v-if="!narrow || initialPage == null" class="nav">
|
||||
<div class="baaadecd">
|
||||
<MkInfo v-if="emailNotConfigured" warn class="info">{{ $ts.emailNotConfiguredWarning }} <MkA to="/settings/email" class="_link">{{ $ts.configure }}</MkA></MkInfo>
|
||||
<MkSuperMenu :def="menuDef" :grid="initialPage == null"></MkSuperMenu>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!(narrow && initialPage == null)" class="main">
|
||||
<div class="bkzroven">
|
||||
<component :is="component" :ref="el => pageChanged(el)" :key="initialPage" v-bind="pageProps"/>
|
||||
<div v-if="!(narrow && initialPage == null)" class="main">
|
||||
<div class="bkzroven">
|
||||
<component :is="component" :key="initialPage" v-bind="pageProps"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</MkSpacer>
|
||||
</MkSpacer>
|
||||
</mkstickycontainer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, defineAsyncComponent, nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
|
||||
import { computed, defineAsyncComponent, inject, nextTick, onMounted, onUnmounted, provide, ref, watch } from 'vue';
|
||||
import { i18n } from '@/i18n';
|
||||
import MkInfo from '@/components/ui/info.vue';
|
||||
import MkSuperMenu from '@/components/ui/super-menu.vue';
|
||||
import { scroll } from '@/scripts/scroll';
|
||||
import { signout } from '@/account';
|
||||
import { signout , $i } from '@/account';
|
||||
import { unisonReload } from '@/scripts/unison-reload';
|
||||
import * as symbols from '@/symbols';
|
||||
import { instance } from '@/instance';
|
||||
import { $i } from '@/account';
|
||||
import { MisskeyNavigator } from '@/scripts/navigate';
|
||||
import { useRouter } from '@/router';
|
||||
import { definePageMetadata, provideMetadataReceiver, setPageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
const props = defineProps<{
|
||||
initialPage?: string
|
||||
}>();
|
||||
const props = withDefaults(defineProps<{
|
||||
initialPage?: string;
|
||||
}>(), {
|
||||
});
|
||||
|
||||
const indexInfo = {
|
||||
title: i18n.ts.settings,
|
||||
@ -52,7 +48,7 @@ const INFO = ref(indexInfo);
|
||||
const el = ref<HTMLElement | null>(null);
|
||||
const childInfo = ref(null);
|
||||
|
||||
const nav = new MisskeyNavigator();
|
||||
const router = useRouter();
|
||||
|
||||
const narrow = ref(false);
|
||||
const NARROW_THRESHOLD = 600;
|
||||
@ -189,7 +185,7 @@ const menuDef = computed(() => [{
|
||||
signout();
|
||||
},
|
||||
danger: true,
|
||||
},],
|
||||
}],
|
||||
}]);
|
||||
|
||||
const pageProps = ref({});
|
||||
@ -242,7 +238,7 @@ watch(component, () => {
|
||||
|
||||
watch(() => props.initialPage, () => {
|
||||
if (props.initialPage == null && !narrow.value) {
|
||||
nav.push('/settings/profile');
|
||||
router.push('/settings/profile');
|
||||
} else {
|
||||
if (props.initialPage == null) {
|
||||
INFO.value = indexInfo;
|
||||
@ -252,7 +248,7 @@ watch(() => props.initialPage, () => {
|
||||
|
||||
watch(narrow, () => {
|
||||
if (props.initialPage == null && !narrow.value) {
|
||||
nav.push('/settings/profile');
|
||||
router.push('/settings/profile');
|
||||
}
|
||||
});
|
||||
|
||||
@ -261,7 +257,7 @@ onMounted(() => {
|
||||
|
||||
narrow.value = el.value.offsetWidth < NARROW_THRESHOLD;
|
||||
if (props.initialPage == null && !narrow.value) {
|
||||
nav.push('/settings/profile');
|
||||
router.push('/settings/profile');
|
||||
}
|
||||
});
|
||||
|
||||
@ -271,38 +267,23 @@ onUnmounted(() => {
|
||||
|
||||
const emailNotConfigured = computed(() => instance.enableEmail && ($i.email == null || !$i.emailVerified));
|
||||
|
||||
const pageChanged = (page) => {
|
||||
if (page == null) {
|
||||
provideMetadataReceiver((info) => {
|
||||
if (info == null) {
|
||||
childInfo.value = null;
|
||||
} else {
|
||||
childInfo.value = page[symbols.PAGE_INFO];
|
||||
childInfo.value = info;
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: INFO,
|
||||
});
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata(INFO);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.vvcocwet {
|
||||
> .header {
|
||||
display: flex;
|
||||
margin-bottom: 24px;
|
||||
font-size: 1.3em;
|
||||
font-weight: bold;
|
||||
|
||||
> .title {
|
||||
display: block;
|
||||
width: 34%;
|
||||
}
|
||||
|
||||
> .subtitle {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
> .body {
|
||||
> .nav {
|
||||
.baaadecd {
|
||||
|
@ -10,14 +10,14 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineExpose, ref, watch } from 'vue';
|
||||
import { ref, watch } from 'vue';
|
||||
import FormTextarea from '@/components/form/textarea.vue';
|
||||
import MkInfo from '@/components/ui/info.vue';
|
||||
import MkButton from '@/components/ui/button.vue';
|
||||
import * as os from '@/os';
|
||||
import * as symbols from '@/symbols';
|
||||
import { $i } from '@/account';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
const instanceMutes = ref($i!.mutedInstances.join('\n'));
|
||||
const changed = ref(false);
|
||||
@ -42,10 +42,12 @@ watch(instanceMutes, () => {
|
||||
changed.value = true;
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: i18n.ts.instanceMute,
|
||||
icon: 'fas fa-volume-mute'
|
||||
}
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.instanceMute,
|
||||
icon: 'fas fa-volume-mute',
|
||||
});
|
||||
</script>
|
||||
|
@ -24,14 +24,14 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, defineExpose, onMounted, ref, watch } from 'vue';
|
||||
import { computed, onMounted, ref, watch } from 'vue';
|
||||
import { apiUrl } from '@/config';
|
||||
import FormSection from '@/components/form/section.vue';
|
||||
import MkButton from '@/components/ui/button.vue';
|
||||
import * as symbols from '@/symbols';
|
||||
import { $i } from '@/account';
|
||||
import { instance } from '@/instance';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
const twitterForm = ref<Window | null>(null);
|
||||
const discordForm = ref<Window | null>(null);
|
||||
@ -42,7 +42,7 @@ const integrations = computed(() => $i!.integrations);
|
||||
function openWindow(service: string, type: string) {
|
||||
return window.open(`${apiUrl}/${type}/${service}`,
|
||||
`${service}_${type}_window`,
|
||||
'height=570, width=520'
|
||||
'height=570, width=520',
|
||||
);
|
||||
}
|
||||
|
||||
@ -72,7 +72,7 @@ function disconnectGithub() {
|
||||
|
||||
onMounted(() => {
|
||||
document.cookie = `igi=${$i!.token}; path=/;` +
|
||||
` max-age=31536000;` +
|
||||
' max-age=31536000;' +
|
||||
(document.location.protocol.startsWith('https') ? ' secure' : '');
|
||||
|
||||
watch(integrations, () => {
|
||||
@ -88,11 +88,13 @@ onMounted(() => {
|
||||
});
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: i18n.ts.integration,
|
||||
icon: 'fas fa-share-alt',
|
||||
bg: 'var(--bg)',
|
||||
}
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.integration,
|
||||
icon: 'fas fa-share-alt',
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
@ -18,16 +18,16 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, defineExpose, ref, watch } from 'vue';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import FormTextarea from '@/components/form/textarea.vue';
|
||||
import FormRadios from '@/components/form/radios.vue';
|
||||
import FormButton from '@/components/ui/button.vue';
|
||||
import * as os from '@/os';
|
||||
import { menuDef } from '@/menu';
|
||||
import { defaultStore } from '@/store';
|
||||
import * as symbols from '@/symbols';
|
||||
import { unisonReload } from '@/scripts/unison-reload';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
const items = ref(defaultStore.state.menu.join('\n'));
|
||||
|
||||
@ -37,7 +37,7 @@ const menuDisplay = computed(defaultStore.makeGetterSetter('menuDisplay'));
|
||||
async function reloadAsk() {
|
||||
const { canceled } = await os.confirm({
|
||||
type: 'info',
|
||||
text: i18n.ts.reloadToApplySetting
|
||||
text: i18n.ts.reloadToApplySetting,
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
@ -49,10 +49,10 @@ async function addItem() {
|
||||
const { canceled, result: item } = await os.select({
|
||||
title: i18n.ts.addItem,
|
||||
items: [...menu.map(k => ({
|
||||
value: k, text: i18n.ts[menuDef[k].title]
|
||||
value: k, text: i18n.ts[menuDef[k].title],
|
||||
})), {
|
||||
value: '-', text: i18n.ts.divider
|
||||
}]
|
||||
value: '-', text: i18n.ts.divider,
|
||||
}],
|
||||
});
|
||||
if (canceled) return;
|
||||
items.value = [...split.value, item].join('\n');
|
||||
@ -76,11 +76,13 @@ watch(menuDisplay, async () => {
|
||||
await reloadAsk();
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: i18n.ts.menu,
|
||||
icon: 'fas fa-list-ul',
|
||||
bg: 'var(--bg)',
|
||||
}
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.menu,
|
||||
icon: 'fas fa-list-ul',
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
@ -7,7 +7,7 @@
|
||||
<div v-if="tab === 'mute'">
|
||||
<MkPagination :pagination="mutingPagination" class="muting">
|
||||
<template #empty><FormInfo>{{ $ts.noUsers }}</FormInfo></template>
|
||||
<template v-slot="{items}">
|
||||
<template #default="{items}">
|
||||
<FormLink v-for="mute in items" :key="mute.id" :to="userPage(mute.mutee)">
|
||||
<MkAcct :user="mute.mutee"/>
|
||||
</FormLink>
|
||||
@ -17,7 +17,7 @@
|
||||
<div v-if="tab === 'block'">
|
||||
<MkPagination :pagination="blockingPagination" class="blocking">
|
||||
<template #empty><FormInfo>{{ $ts.noUsers }}</FormInfo></template>
|
||||
<template v-slot="{items}">
|
||||
<template #default="{items}">
|
||||
<FormLink v-for="block in items" :key="block.id" :to="userPage(block.blockee)">
|
||||
<MkAcct :user="block.blockee"/>
|
||||
</FormLink>
|
||||
@ -35,8 +35,8 @@ import FormInfo from '@/components/ui/info.vue';
|
||||
import FormLink from '@/components/form/link.vue';
|
||||
import { userPage } from '@/filters/user';
|
||||
import * as os from '@/os';
|
||||
import * as symbols from '@/symbols';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
let tab = $ref('mute');
|
||||
|
||||
@ -50,11 +50,13 @@ const blockingPagination = {
|
||||
limit: 10,
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: i18n.ts.muteAndBlock,
|
||||
icon: 'fas fa-ban',
|
||||
bg: 'var(--bg)',
|
||||
},
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.muteAndBlock,
|
||||
icon: 'fas fa-ban',
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
@ -10,15 +10,15 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineAsyncComponent, defineExpose } from 'vue';
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
import { notificationTypes } from 'misskey-js';
|
||||
import FormButton from '@/components/ui/button.vue';
|
||||
import FormLink from '@/components/form/link.vue';
|
||||
import FormSection from '@/components/form/section.vue';
|
||||
import { notificationTypes } from 'misskey-js';
|
||||
import * as os from '@/os';
|
||||
import * as symbols from '@/symbols';
|
||||
import { $i } from '@/account';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
async function readAllUnreadNotes() {
|
||||
await os.api('i/read-all-unread-notes');
|
||||
@ -45,15 +45,17 @@ function configure() {
|
||||
}).then(i => {
|
||||
$i!.mutingNotificationTypes = i.mutingNotificationTypes;
|
||||
});
|
||||
}
|
||||
},
|
||||
}, 'closed');
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: i18n.ts.notifications,
|
||||
icon: 'fas fa-bell',
|
||||
bg: 'var(--bg)',
|
||||
}
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.notifications,
|
||||
icon: 'fas fa-bell',
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
@ -15,30 +15,32 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, defineExpose } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
import FormSwitch from '@/components/form/switch.vue';
|
||||
import FormLink from '@/components/form/link.vue';
|
||||
import * as os from '@/os';
|
||||
import { defaultStore } from '@/store';
|
||||
import * as symbols from '@/symbols';
|
||||
import { $i } from '@/account';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
const reportError = computed(defaultStore.makeGetterSetter('reportError'));
|
||||
|
||||
function onChangeInjectFeaturedNote(v) {
|
||||
os.api('i/update', {
|
||||
injectFeaturedNote: v
|
||||
injectFeaturedNote: v,
|
||||
}).then((i) => {
|
||||
$i!.injectFeaturedNote = i.injectFeaturedNote;
|
||||
});
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: i18n.ts.other,
|
||||
icon: 'fas fa-ellipsis-h',
|
||||
bg: 'var(--bg)',
|
||||
}
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.other,
|
||||
icon: 'fas fa-ellipsis-h',
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
@ -13,7 +13,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineExpose, defineAsyncComponent, nextTick, ref } from 'vue';
|
||||
import { defineAsyncComponent, nextTick, ref } from 'vue';
|
||||
import { AiScript, parse } from '@syuilo/aiscript';
|
||||
import { serialize } from '@syuilo/aiscript/built/serializer';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
@ -24,7 +24,7 @@ import * as os from '@/os';
|
||||
import { ColdDeviceStorage } from '@/store';
|
||||
import { unisonReload } from '@/scripts/unison-reload';
|
||||
import { i18n } from '@/i18n';
|
||||
import * as symbols from '@/symbols';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
const code = ref(null);
|
||||
|
||||
@ -35,7 +35,7 @@ function installPlugin({ id, meta, ast, token }) {
|
||||
active: true,
|
||||
configData: {},
|
||||
token: token,
|
||||
ast: ast
|
||||
ast: ast,
|
||||
}));
|
||||
}
|
||||
|
||||
@ -46,7 +46,7 @@ async function install() {
|
||||
} catch (err) {
|
||||
os.alert({
|
||||
type: 'error',
|
||||
text: 'Syntax error :('
|
||||
text: 'Syntax error :(',
|
||||
});
|
||||
return;
|
||||
}
|
||||
@ -55,7 +55,7 @@ async function install() {
|
||||
if (meta == null) {
|
||||
os.alert({
|
||||
type: 'error',
|
||||
text: 'No metadata found :('
|
||||
text: 'No metadata found :(',
|
||||
});
|
||||
return;
|
||||
}
|
||||
@ -64,7 +64,7 @@ async function install() {
|
||||
if (metadata == null) {
|
||||
os.alert({
|
||||
type: 'error',
|
||||
text: 'No metadata found :('
|
||||
text: 'No metadata found :(',
|
||||
});
|
||||
return;
|
||||
}
|
||||
@ -73,7 +73,7 @@ async function install() {
|
||||
if (name == null || version == null || author == null) {
|
||||
os.alert({
|
||||
type: 'error',
|
||||
text: 'Required property not found :('
|
||||
text: 'Required property not found :(',
|
||||
});
|
||||
return;
|
||||
}
|
||||
@ -83,7 +83,7 @@ async function install() {
|
||||
title: i18n.ts.tokenRequested,
|
||||
information: i18n.ts.pluginTokenRequestedDescription,
|
||||
initialName: name,
|
||||
initialPermissions: permissions
|
||||
initialPermissions: permissions,
|
||||
}, {
|
||||
done: async result => {
|
||||
const { name, permissions } = result;
|
||||
@ -93,17 +93,17 @@ async function install() {
|
||||
permission: permissions,
|
||||
});
|
||||
res(token);
|
||||
}
|
||||
},
|
||||
}, 'closed');
|
||||
});
|
||||
|
||||
installPlugin({
|
||||
id: uuid(),
|
||||
meta: {
|
||||
name, version, author, description, permissions, config
|
||||
name, version, author, description, permissions, config,
|
||||
},
|
||||
token,
|
||||
ast: serialize(ast)
|
||||
ast: serialize(ast),
|
||||
});
|
||||
|
||||
os.success();
|
||||
@ -113,11 +113,13 @@ async function install() {
|
||||
});
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: i18n.ts._plugin.install,
|
||||
icon: 'fas fa-download',
|
||||
bg: 'var(--bg)',
|
||||
}
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts._plugin.install,
|
||||
icon: 'fas fa-download',
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
@ -7,7 +7,7 @@
|
||||
<div v-for="plugin in plugins" :key="plugin.id" class="_formBlock _panel" style="padding: 20px;">
|
||||
<span style="display: flex;"><b>{{ plugin.name }}</b><span style="margin-left: auto;">v{{ plugin.version }}</span></span>
|
||||
|
||||
<FormSwitch class="_formBlock" :modelValue="plugin.active" @update:modelValue="changeActive(plugin, $event)">{{ i18n.ts.makeActive }}</FormSwitch>
|
||||
<FormSwitch class="_formBlock" :model-value="plugin.active" @update:modelValue="changeActive(plugin, $event)">{{ i18n.ts.makeActive }}</FormSwitch>
|
||||
|
||||
<MkKeyValue class="_formBlock">
|
||||
<template #key>{{ i18n.ts.author }}</template>
|
||||
@ -32,7 +32,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineExpose, nextTick, ref } from 'vue';
|
||||
import { nextTick, ref } from 'vue';
|
||||
import FormLink from '@/components/form/link.vue';
|
||||
import FormSwitch from '@/components/form/switch.vue';
|
||||
import FormSection from '@/components/form/section.vue';
|
||||
@ -40,9 +40,9 @@ import MkButton from '@/components/ui/button.vue';
|
||||
import MkKeyValue from '@/components/key-value.vue';
|
||||
import * as os from '@/os';
|
||||
import { ColdDeviceStorage } from '@/store';
|
||||
import * as symbols from '@/symbols';
|
||||
import { unisonReload } from '@/scripts/unison-reload';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
const plugins = ref(ColdDeviceStorage.get('plugins'));
|
||||
|
||||
@ -83,12 +83,14 @@ function changeActive(plugin, active) {
|
||||
});
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: i18n.ts.plugins,
|
||||
icon: 'fas fa-plug',
|
||||
bg: 'var(--bg)',
|
||||
}
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.plugins,
|
||||
icon: 'fas fa-plug',
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -55,9 +55,9 @@ import FormSection from '@/components/form/section.vue';
|
||||
import FormGroup from '@/components/form/group.vue';
|
||||
import * as os from '@/os';
|
||||
import { defaultStore } from '@/store';
|
||||
import * as symbols from '@/symbols';
|
||||
import { i18n } from '@/i18n';
|
||||
import { $i } from '@/account';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
let isLocked = $ref($i.isLocked);
|
||||
let autoAcceptFollowed = $ref($i.autoAcceptFollowed);
|
||||
@ -84,11 +84,13 @@ function save() {
|
||||
});
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: i18n.ts.privacy,
|
||||
icon: 'fas fa-lock-open',
|
||||
bg: 'var(--bg)',
|
||||
},
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.privacy,
|
||||
icon: 'fas fa-lock-open',
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
@ -74,10 +74,10 @@ import FormSlot from '@/components/form/slot.vue';
|
||||
import { host } from '@/config';
|
||||
import { selectFile } from '@/scripts/select-file';
|
||||
import * as os from '@/os';
|
||||
import * as symbols from '@/symbols';
|
||||
import { i18n } from '@/i18n';
|
||||
import { $i } from '@/account';
|
||||
import { langmap } from '@/scripts/langmap';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
const profile = reactive({
|
||||
name: $i.name,
|
||||
@ -176,12 +176,14 @@ function changeBanner(ev) {
|
||||
});
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: i18n.ts.profile,
|
||||
icon: 'fas fa-user',
|
||||
bg: 'var(--bg)',
|
||||
},
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.profile,
|
||||
icon: 'fas fa-user',
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -64,8 +64,8 @@ import FormSection from '@/components/form/section.vue';
|
||||
import FormSwitch from '@/components/form/switch.vue';
|
||||
import * as os from '@/os';
|
||||
import { defaultStore } from '@/store';
|
||||
import * as symbols from '@/symbols';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
let reactions = $ref(JSON.parse(JSON.stringify(defaultStore.state.reactions)));
|
||||
|
||||
@ -83,7 +83,7 @@ function remove(reaction, ev: MouseEvent) {
|
||||
text: i18n.ts.remove,
|
||||
action: () => {
|
||||
reactions = reactions.filter(x => x !== reaction);
|
||||
}
|
||||
},
|
||||
}], ev.currentTarget ?? ev.target);
|
||||
}
|
||||
|
||||
@ -106,7 +106,7 @@ async function setDefault() {
|
||||
|
||||
function chooseEmoji(ev: MouseEvent) {
|
||||
os.pickEmoji(ev.currentTarget ?? ev.target, {
|
||||
showPinned: false
|
||||
showPinned: false,
|
||||
}).then(emoji => {
|
||||
if (!reactions.includes(emoji)) {
|
||||
reactions.push(emoji);
|
||||
@ -120,16 +120,18 @@ watch($$(reactions), () => {
|
||||
deep: true,
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: i18n.ts.reaction,
|
||||
icon: 'fas fa-laugh',
|
||||
action: {
|
||||
icon: 'fas fa-eye',
|
||||
handler: preview,
|
||||
},
|
||||
bg: 'var(--bg)',
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.reaction,
|
||||
icon: 'fas fa-laugh',
|
||||
action: {
|
||||
icon: 'fas fa-eye',
|
||||
handler: preview,
|
||||
},
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
<FormSection>
|
||||
<template #label>{{ i18n.ts.signinHistory }}</template>
|
||||
<MkPagination :pagination="pagination">
|
||||
<template v-slot="{items}">
|
||||
<template #default="{items}">
|
||||
<div>
|
||||
<div v-for="item in items" :key="item.id" v-panel class="timnmucd">
|
||||
<header>
|
||||
@ -38,15 +38,14 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineExpose } from 'vue';
|
||||
import X2fa from './2fa.vue';
|
||||
import FormSection from '@/components/form/section.vue';
|
||||
import FormSlot from '@/components/form/slot.vue';
|
||||
import FormButton from '@/components/ui/button.vue';
|
||||
import MkPagination from '@/components/ui/pagination.vue';
|
||||
import X2fa from './2fa.vue';
|
||||
import * as os from '@/os';
|
||||
import * as symbols from '@/symbols';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
const pagination = {
|
||||
endpoint: 'i/signin-history' as const,
|
||||
@ -56,54 +55,56 @@ const pagination = {
|
||||
async function change() {
|
||||
const { canceled: canceled1, result: currentPassword } = await os.inputText({
|
||||
title: i18n.ts.currentPassword,
|
||||
type: 'password'
|
||||
type: 'password',
|
||||
});
|
||||
if (canceled1) return;
|
||||
|
||||
const { canceled: canceled2, result: newPassword } = await os.inputText({
|
||||
title: i18n.ts.newPassword,
|
||||
type: 'password'
|
||||
type: 'password',
|
||||
});
|
||||
if (canceled2) return;
|
||||
|
||||
const { canceled: canceled3, result: newPassword2 } = await os.inputText({
|
||||
title: i18n.ts.newPasswordRetype,
|
||||
type: 'password'
|
||||
type: 'password',
|
||||
});
|
||||
if (canceled3) return;
|
||||
|
||||
if (newPassword !== newPassword2) {
|
||||
os.alert({
|
||||
type: 'error',
|
||||
text: i18n.ts.retypedNotMatch
|
||||
text: i18n.ts.retypedNotMatch,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
os.apiWithDialog('i/change-password', {
|
||||
currentPassword,
|
||||
newPassword
|
||||
newPassword,
|
||||
});
|
||||
}
|
||||
|
||||
function regenerateToken() {
|
||||
os.inputText({
|
||||
title: i18n.ts.password,
|
||||
type: 'password'
|
||||
type: 'password',
|
||||
}).then(({ canceled, result: password }) => {
|
||||
if (canceled) return;
|
||||
os.api('i/regenerate_token', {
|
||||
password: password
|
||||
password: password,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: i18n.ts.security,
|
||||
icon: 'fas fa-lock',
|
||||
bg: 'var(--bg)',
|
||||
}
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.security,
|
||||
icon: 'fas fa-lock',
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, defineExpose, ref } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import FormRange from '@/components/form/range.vue';
|
||||
import FormButton from '@/components/ui/button.vue';
|
||||
import FormLink from '@/components/form/link.vue';
|
||||
@ -26,8 +26,8 @@ import FormSection from '@/components/form/section.vue';
|
||||
import * as os from '@/os';
|
||||
import { ColdDeviceStorage } from '@/store';
|
||||
import { playFile } from '@/scripts/sound';
|
||||
import * as symbols from '@/symbols';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
const masterVolume = computed({
|
||||
get: () => {
|
||||
@ -35,19 +35,19 @@ const masterVolume = computed({
|
||||
},
|
||||
set: (value) => {
|
||||
ColdDeviceStorage.set('sound_masterVolume', value);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const volumeIcon = computed(() => masterVolume.value === 0 ? 'fas fa-volume-mute' : 'fas fa-volume-up');
|
||||
|
||||
const sounds = ref({
|
||||
note: ColdDeviceStorage.get('sound_note'),
|
||||
noteMy: ColdDeviceStorage.get('sound_noteMy'),
|
||||
notification: ColdDeviceStorage.get('sound_notification'),
|
||||
chat: ColdDeviceStorage.get('sound_chat'),
|
||||
chatBg: ColdDeviceStorage.get('sound_chatBg'),
|
||||
antenna: ColdDeviceStorage.get('sound_antenna'),
|
||||
channel: ColdDeviceStorage.get('sound_channel'),
|
||||
note: ColdDeviceStorage.get('sound_note'),
|
||||
noteMy: ColdDeviceStorage.get('sound_noteMy'),
|
||||
notification: ColdDeviceStorage.get('sound_notification'),
|
||||
chat: ColdDeviceStorage.get('sound_chat'),
|
||||
chatBg: ColdDeviceStorage.get('sound_chatBg'),
|
||||
antenna: ColdDeviceStorage.get('sound_antenna'),
|
||||
channel: ColdDeviceStorage.get('sound_channel'),
|
||||
});
|
||||
|
||||
const soundsTypes = [
|
||||
@ -95,15 +95,15 @@ async function edit(type) {
|
||||
step: 0.05,
|
||||
textConverter: (v) => `${Math.floor(v * 100)}%`,
|
||||
label: i18n.ts.volume,
|
||||
default: sounds.value[type].volume
|
||||
default: sounds.value[type].volume,
|
||||
},
|
||||
listen: {
|
||||
type: 'button',
|
||||
content: i18n.ts.listen,
|
||||
action: (_, values) => {
|
||||
playFile(values.type, values.volume);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
@ -124,11 +124,13 @@ function reset() {
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: i18n.ts.sounds,
|
||||
icon: 'fas fa-music',
|
||||
bg: 'var(--bg)',
|
||||
}
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.sounds,
|
||||
icon: 'fas fa-music',
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
@ -19,8 +19,8 @@ import FormButton from '@/components/ui/button.vue';
|
||||
import { applyTheme, validateTheme } from '@/scripts/theme';
|
||||
import * as os from '@/os';
|
||||
import { addTheme, getThemes } from '@/theme-store';
|
||||
import * as symbols from '@/symbols';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
let installThemeCode = $ref(null);
|
||||
|
||||
@ -32,21 +32,21 @@ function parseThemeCode(code: string) {
|
||||
} catch (err) {
|
||||
os.alert({
|
||||
type: 'error',
|
||||
text: i18n.ts._theme.invalid
|
||||
text: i18n.ts._theme.invalid,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if (!validateTheme(theme)) {
|
||||
os.alert({
|
||||
type: 'error',
|
||||
text: i18n.ts._theme.invalid
|
||||
text: i18n.ts._theme.invalid,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if (getThemes().some(t => t.id === theme.id)) {
|
||||
os.alert({
|
||||
type: 'info',
|
||||
text: i18n.ts._theme.alreadyInstalled
|
||||
text: i18n.ts._theme.alreadyInstalled,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
@ -65,15 +65,17 @@ async function install(code: string): Promise<void> {
|
||||
await addTheme(theme);
|
||||
os.alert({
|
||||
type: 'success',
|
||||
text: i18n.t('_theme.installed', { name: theme.name })
|
||||
text: i18n.t('_theme.installed', { name: theme.name }),
|
||||
});
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: i18n.ts._theme.install,
|
||||
icon: 'fas fa-download',
|
||||
bg: 'var(--bg)',
|
||||
},
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts._theme.install,
|
||||
icon: 'fas fa-download',
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
@ -26,7 +26,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, defineExpose, ref } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import JSON5 from 'json5';
|
||||
import FormTextarea from '@/components/form/textarea.vue';
|
||||
import FormSelect from '@/components/form/select.vue';
|
||||
@ -36,8 +36,8 @@ import { Theme, getBuiltinThemesRef } from '@/scripts/theme';
|
||||
import copyToClipboard from '@/scripts/copy-to-clipboard';
|
||||
import * as os from '@/os';
|
||||
import { getThemes, removeTheme } from '@/theme-store';
|
||||
import * as symbols from '@/symbols';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
const installedThemes = ref(getThemes());
|
||||
const builtinThemes = getBuiltinThemesRef();
|
||||
@ -67,11 +67,13 @@ function uninstall() {
|
||||
os.success();
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: i18n.ts._theme.manage,
|
||||
icon: 'fas fa-folder-open',
|
||||
bg: 'var(--bg)',
|
||||
}
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts._theme.manage,
|
||||
icon: 'fas fa-folder-open',
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
@ -96,13 +96,12 @@ import FormButton from '@/components/ui/button.vue';
|
||||
import { getBuiltinThemesRef } from '@/scripts/theme';
|
||||
import { selectFile } from '@/scripts/select-file';
|
||||
import { isDeviceDarkmode } from '@/scripts/is-device-darkmode';
|
||||
import { ColdDeviceStorage } from '@/store';
|
||||
import { ColdDeviceStorage , defaultStore } from '@/store';
|
||||
import { i18n } from '@/i18n';
|
||||
import { defaultStore } from '@/store';
|
||||
import { instance } from '@/instance';
|
||||
import { uniqueBy } from '@/scripts/array';
|
||||
import { fetchThemes, getThemes } from '@/theme-store';
|
||||
import * as symbols from '@/symbols';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
const installedThemes = ref(getThemes());
|
||||
const builtinThemes = getBuiltinThemesRef();
|
||||
@ -121,7 +120,7 @@ const darkThemeId = computed({
|
||||
},
|
||||
set(id) {
|
||||
ColdDeviceStorage.set('darkTheme', themes.value.find(x => x.id === id));
|
||||
}
|
||||
},
|
||||
});
|
||||
const lightTheme = ColdDeviceStorage.ref('lightTheme');
|
||||
const lightThemeId = computed({
|
||||
@ -130,7 +129,7 @@ const lightThemeId = computed({
|
||||
},
|
||||
set(id) {
|
||||
ColdDeviceStorage.set('lightTheme', themes.value.find(x => x.id === id));
|
||||
}
|
||||
},
|
||||
});
|
||||
const darkMode = computed(defaultStore.makeGetterSetter('darkMode'));
|
||||
const syncDeviceDarkMode = computed(ColdDeviceStorage.makeGetterSetter('syncDeviceDarkMode'));
|
||||
@ -168,12 +167,14 @@ function setWallpaper(event) {
|
||||
});
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: i18n.ts.theme,
|
||||
icon: 'fas fa-palette',
|
||||
bg: 'var(--bg)',
|
||||
}
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.theme,
|
||||
icon: 'fas fa-palette',
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -40,19 +40,11 @@ import FormSection from '@/components/form/section.vue';
|
||||
import FormSwitch from '@/components/form/switch.vue';
|
||||
import FormButton from '@/components/ui/button.vue';
|
||||
import * as os from '@/os';
|
||||
import * as symbols from '@/symbols';
|
||||
import { i18n } from '@/i18n';
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: 'Edit webhook',
|
||||
icon: 'fas fa-bolt',
|
||||
bg: 'var(--bg)',
|
||||
},
|
||||
});
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
const webhook = await os.api('i/webhooks/show', {
|
||||
webhookId: new URLSearchParams(window.location.search).get('id')
|
||||
webhookId: new URLSearchParams(window.location.search).get('id'),
|
||||
});
|
||||
|
||||
let name = $ref(webhook.name);
|
||||
@ -86,4 +78,14 @@ async function save(): Promise<void> {
|
||||
active,
|
||||
});
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: 'Edit webhook',
|
||||
icon: 'fas fa-bolt',
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
@ -38,8 +38,8 @@ import FormSection from '@/components/form/section.vue';
|
||||
import FormSwitch from '@/components/form/switch.vue';
|
||||
import FormButton from '@/components/ui/button.vue';
|
||||
import * as os from '@/os';
|
||||
import * as symbols from '@/symbols';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
let name = $ref('');
|
||||
let url = $ref('');
|
||||
@ -71,11 +71,13 @@ async function create(): Promise<void> {
|
||||
});
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: 'Create new webhook',
|
||||
icon: 'fas fa-bolt',
|
||||
bg: 'var(--bg)',
|
||||
},
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: 'Create new webhook',
|
||||
icon: 'fas fa-bolt',
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
<FormSection>
|
||||
<MkPagination :pagination="pagination">
|
||||
<template v-slot="{items}">
|
||||
<template #default="{items}">
|
||||
<FormLink v-for="webhook in items" :key="webhook.id" :to="`/settings/webhook/edit?id=${webhook.id}`" class="_formBlock">
|
||||
<template #icon>
|
||||
<i v-if="webhook.active === false" class="fas fa-circle-pause"></i>
|
||||
@ -34,19 +34,21 @@ import FormSection from '@/components/form/section.vue';
|
||||
import FormLink from '@/components/form/link.vue';
|
||||
import { userPage } from '@/filters/user';
|
||||
import * as os from '@/os';
|
||||
import * as symbols from '@/symbols';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
const pagination = {
|
||||
endpoint: 'i/webhooks/list' as const,
|
||||
limit: 10,
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: 'Webhook',
|
||||
icon: 'fas fa-bolt',
|
||||
bg: 'var(--bg)',
|
||||
},
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: 'Webhook',
|
||||
icon: 'fas fa-bolt',
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
@ -29,7 +29,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineExpose, ref, watch } from 'vue';
|
||||
import { ref, watch } from 'vue';
|
||||
import FormTextarea from '@/components/form/textarea.vue';
|
||||
import MkKeyValue from '@/components/key-value.vue';
|
||||
import MkButton from '@/components/ui/button.vue';
|
||||
@ -37,10 +37,10 @@ import MkInfo from '@/components/ui/info.vue';
|
||||
import MkTab from '@/components/tab.vue';
|
||||
import * as os from '@/os';
|
||||
import number from '@/filters/number';
|
||||
import * as symbols from '@/symbols';
|
||||
import { defaultStore } from '@/store';
|
||||
import { $i } from '@/account';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
const render = (mutedWords) => mutedWords.map(x => {
|
||||
if (Array.isArray(x)) {
|
||||
@ -87,7 +87,7 @@ async function save() {
|
||||
os.alert({
|
||||
type: 'error',
|
||||
title: i18n.ts.regexpError,
|
||||
text: i18n.t('regexpErrorDescription', { tab, line: i + 1 }) + "\n" + err.toString()
|
||||
text: i18n.t('regexpErrorDescription', { tab, line: i + 1 }) + '\n' + err.toString(),
|
||||
});
|
||||
// re-throw error so these invalid settings are not saved
|
||||
throw err;
|
||||
@ -117,11 +117,13 @@ async function save() {
|
||||
changed.value = false;
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: i18n.ts.wordMute,
|
||||
icon: 'fas fa-comment-slash',
|
||||
bg: 'var(--bg)',
|
||||
}
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.wordMute,
|
||||
icon: 'fas fa-comment-slash',
|
||||
bg: 'var(--bg)',
|
||||
});
|
||||
</script>
|
||||
|
Reference in New Issue
Block a user