merge: misskey 2025.5.0 (!1028)
View MR for information: https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/1028 Approved-by: Hazelnoot <acomputerdog@gmail.com> Approved-by: Marie <github@yuugi.dev>
This commit is contained in:
commit
13d045d813
152 changed files with 1690 additions and 842 deletions
|
|
@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<MkLoading v-if="!loaded"/>
|
||||
<Transition :name="prefer.s.animation ? '_transition_zoom' : ''" appear>
|
||||
<div v-show="loaded" :class="$style.root">
|
||||
<img :src="serverErrorImageUrl" draggable="false" :class="$style.img"/>
|
||||
<img v-if="instance.serverErrorImageUrl" :src="instance.serverErrorImageUrl" draggable="false" :class="$style.img"/>
|
||||
<div class="_gaps">
|
||||
<div><b><i class="ti ti-alert-triangle"></i> {{ i18n.ts.pageLoadError }}</b></div>
|
||||
<div v-if="meta && (version === meta.version)">{{ i18n.ts.pageLoadErrorDescription }}</div>
|
||||
|
|
@ -36,7 +36,7 @@ import { i18n } from '@/i18n.js';
|
|||
import { definePage } from '@/page.js';
|
||||
import { miLocalStorage } from '@/local-storage.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
import { serverErrorImageUrl } from '@/instance.js';
|
||||
import { instance } from '@/instance.js';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
error?: Error;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<MkTl :events="timeline" :displayLimit="50" style="margin-top: var(--MI-margin);">
|
||||
<template #left="{ event }">
|
||||
<div>
|
||||
<MkAvatar :user="event.user" style="width: 24px; height: 24px;"/>
|
||||
<MkAvatar :user="event.user" style="width: 26px; height: 26px;"/>
|
||||
</div>
|
||||
</template>
|
||||
<template #right="{ event, timestamp, delta }">
|
||||
|
|
|
|||
|
|
@ -25,12 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<MkButton primary rounded @click="assign"><i class="ti ti-plus"></i> {{ i18n.ts.assign }}</MkButton>
|
||||
|
||||
<MkPagination :pagination="usersPagination" :displayLimit="50">
|
||||
<template #empty>
|
||||
<div class="_fullinfo">
|
||||
<img :src="infoImageUrl" draggable="false"/>
|
||||
<div>{{ i18n.ts.noUsers }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #empty><MkResult type="empty" :text="i18n.ts.noUsers"/></template>
|
||||
|
||||
<template #default="{ items }">
|
||||
<div class="_gaps_s">
|
||||
|
|
@ -71,7 +66,6 @@ import MkButton from '@/components/MkButton.vue';
|
|||
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||
import MkInfo from '@/components/MkInfo.vue';
|
||||
import MkPagination from '@/components/MkPagination.vue';
|
||||
import { infoImageUrl } from '@/instance.js';
|
||||
import { useRouter } from '@/router.js';
|
||||
|
||||
const router = useRouter();
|
||||
|
|
|
|||
|
|
@ -262,6 +262,31 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<template #label>{{ i18n.ts.federationAllowedHosts }}<span v-if="federationForm.modifiedStates.federationHosts" class="_modified">{{ i18n.ts.modified }}</span></template>
|
||||
<template #caption>{{ i18n.ts.federationAllowedHostsDescription }}</template>
|
||||
</MkTextarea>
|
||||
|
||||
<MkFolder>
|
||||
<template #icon><i class="ti ti-list"></i></template>
|
||||
<template #label><SearchLabel>{{ i18n.ts._serverSettings.deliverSuspendedSoftware }}</SearchLabel></template>
|
||||
<template #footer>
|
||||
<div class="_buttons">
|
||||
<MkButton @click="federationForm.state.deliverSuspendedSoftware.push({software: '', versionRange: ''})"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div :class="$style.metadataRoot" class="_gaps_s">
|
||||
<MkInfo>{{ i18n.ts._serverSettings.deliverSuspendedSoftwareDescription }}</MkInfo>
|
||||
<div v-for="(element, index) in federationForm.state.deliverSuspendedSoftware" :key="index" v-panel :class="$style.fieldDragItem">
|
||||
<button class="_button" :class="$style.dragItemRemove" @click="federationForm.state.deliverSuspendedSoftware.splice(index, 1)"><i class="ti ti-x"></i></button>
|
||||
<div :class="$style.dragItemForm">
|
||||
<FormSplit :minWidth="200">
|
||||
<MkInput v-model="element.software" small :placeholder="i18n.ts.softwareName">
|
||||
</MkInput>
|
||||
<MkInput v-model="element.versionRange" small :placeholder="i18n.ts.version">
|
||||
</MkInput>
|
||||
</FormSplit>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</MkFolder>
|
||||
</div>
|
||||
</MkFolder>
|
||||
|
||||
|
|
@ -420,10 +445,12 @@ const urlPreviewForm = useForm({
|
|||
const federationForm = useForm({
|
||||
federation: meta.federation,
|
||||
federationHosts: meta.federationHosts.join('\n'),
|
||||
deliverSuspendedSoftware: meta.deliverSuspendedSoftware,
|
||||
}, async (state) => {
|
||||
await os.apiWithDialog('admin/update-meta', {
|
||||
federation: state.federation,
|
||||
federationHosts: state.federationHosts.split('\n'),
|
||||
deliverSuspendedSoftware: state.deliverSuspendedSoftware,
|
||||
});
|
||||
fetchInstance(true);
|
||||
});
|
||||
|
|
@ -470,4 +497,53 @@ definePage(() => ({
|
|||
font-size: 0.85em;
|
||||
color: color(from var(--MI_THEME-fg) srgb r g b / 0.75);
|
||||
}
|
||||
|
||||
.metadataRoot {
|
||||
container-type: inline-size;
|
||||
}
|
||||
|
||||
.fieldDragItem {
|
||||
display: flex;
|
||||
padding: 10px;
|
||||
align-items: flex-end;
|
||||
border-radius: 6px;
|
||||
|
||||
/* (drag button) 32px + (drag button margin) 8px + (input width) 200px * 2 + (input gap) 12px = 452px */
|
||||
@container (max-width: 452px) {
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.dragItemHandle {
|
||||
cursor: grab;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin: 0 8px 0 0;
|
||||
opacity: 0.5;
|
||||
flex-shrink: 0;
|
||||
|
||||
&:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
}
|
||||
|
||||
.dragItemRemove {
|
||||
@extend .dragItemHandle;
|
||||
|
||||
color: #ff2a2a;
|
||||
opacity: 1;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover, &:focus {
|
||||
opacity: .7;
|
||||
}
|
||||
|
||||
&:active {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.dragItemForm {
|
||||
flex-grow: 1;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -27,9 +27,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</div>
|
||||
</MkFolder>
|
||||
</div>
|
||||
<div v-if="!fetching && invitations.length == 0" class="_fullinfo">
|
||||
<div>{{ i18n.ts._chat.noInvitations }}</div>
|
||||
</div>
|
||||
<MkResult v-if="!fetching && invitations.length == 0" type="empty" :text="i18n.ts._chat.noInvitations"/>
|
||||
<MkLoading v-if="fetching"/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -8,9 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<div v-if="memberships.length > 0" class="_gaps_s">
|
||||
<XRoom v-for="membership in memberships" :key="membership.id" :room="membership.room!"/>
|
||||
</div>
|
||||
<div v-if="!fetching && memberships.length == 0" class="_fullinfo">
|
||||
<div>{{ i18n.ts._chat.noRooms }}</div>
|
||||
</div>
|
||||
<MkResult v-if="!fetching && memberships.length == 0" type="empty" :text="i18n.ts._chat.noRooms"/>
|
||||
<MkLoading v-if="fetching"/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -8,9 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<div v-if="rooms.length > 0" class="_gaps_s">
|
||||
<XRoom v-for="room in rooms" :key="room.id" :room="room"/>
|
||||
</div>
|
||||
<div v-if="!fetching && rooms.length == 0" class="_fullinfo">
|
||||
<div>{{ i18n.ts._chat.noRooms }}</div>
|
||||
</div>
|
||||
<MkResult v-if="!fetching && rooms.length == 0" type="empty" :text="i18n.ts._chat.noRooms"/>
|
||||
<MkLoading v-if="fetching"/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -24,10 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<XMessage :message="message" :user="message.fromUser" :isSearchResult="true"/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="_fullinfo">
|
||||
<img :src="infoImageUrl" draggable="false"/>
|
||||
<div>{{ i18n.ts.notFound }}</div>
|
||||
</div>
|
||||
<MkResult v-else type="notFound"/>
|
||||
</MkFoldableSection>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -38,7 +35,6 @@ import * as Misskey from 'misskey-js';
|
|||
import XMessage from './XMessage.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { infoImageUrl } from '@/instance.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
||||
|
|
|
|||
66
packages/frontend/src/pages/debug.vue
Normal file
66
packages/frontend/src/pages/debug.vue
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
<!--
|
||||
SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<template>
|
||||
<PageWithHeader>
|
||||
<div class="_spacer" style="--MI_SPACER-w: 600px;">
|
||||
<div class="_gaps_m">
|
||||
<MkResult v-if="resultType === 'empty'" type="empty"/>
|
||||
<MkResult v-if="resultType === 'notFound'" type="notFound"/>
|
||||
<MkResult v-if="resultType === 'error'" type="error"/>
|
||||
<MkSelect
|
||||
v-model="resultType" :items="[
|
||||
{ label: 'empty', value: 'empty' },
|
||||
{ label: 'notFound', value: 'notFound' },
|
||||
{ label: 'error', value: 'error' },
|
||||
]"
|
||||
></MkSelect>
|
||||
|
||||
<MkSystemIcon v-if="iconType === 'info'" type="info" style="width: 60px;"/>
|
||||
<MkSystemIcon v-if="iconType === 'question'" type="question" style="width: 60px;"/>
|
||||
<MkSystemIcon v-if="iconType === 'success'" type="success" style="width: 60px;"/>
|
||||
<MkSystemIcon v-if="iconType === 'warn'" type="warn" style="width: 60px;"/>
|
||||
<MkSystemIcon v-if="iconType === 'error'" type="error" style="width: 60px;"/>
|
||||
<MkSelect
|
||||
v-model="iconType" :items="[
|
||||
{ label: 'info', value: 'info' },
|
||||
{ label: 'question', value: 'question' },
|
||||
{ label: 'success', value: 'success' },
|
||||
{ label: 'warn', value: 'warn' },
|
||||
{ label: 'error', value: 'error' },
|
||||
]"
|
||||
></MkSelect>
|
||||
|
||||
<div class="_buttons">
|
||||
<MkButton @click="os.alert({ type: 'error', title: 'Error', text: 'error' })">Error</MkButton>
|
||||
<MkButton @click="os.alert({ type: 'warning', title: 'Warning', text: 'warning' })">Warning</MkButton>
|
||||
<MkButton @click="os.alert({ type: 'info', title: 'Info', text: 'info' })">Info</MkButton>
|
||||
<MkButton @click="os.alert({ type: 'success', title: 'Success', text: 'success' })">Success</MkButton>
|
||||
<MkButton @click="os.alert({ type: 'question', title: 'Question', text: 'question' })">Question</MkButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PageWithHeader>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { instance } from '@/instance.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import MkKeyValue from '@/components/MkKeyValue.vue';
|
||||
import MkLink from '@/components/MkLink.vue';
|
||||
import MkSelect from '@/components/MkSelect.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import * as os from '@/os.js';
|
||||
|
||||
const resultType = ref('empty');
|
||||
const iconType = ref('info');
|
||||
|
||||
definePage(() => ({
|
||||
title: 'DEBUG ROOM',
|
||||
icon: 'ti ti-help-circle',
|
||||
}));
|
||||
</script>
|
||||
|
|
@ -68,10 +68,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</MkKeyValue>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="_fullinfo">
|
||||
<img :src="infoImageUrl" draggable="false"/>
|
||||
<div>{{ i18n.ts.nothing }}</div>
|
||||
</div>
|
||||
<MkResult v-else type="empty"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -82,7 +79,6 @@ import MkInfo from '@/components/MkInfo.vue';
|
|||
import MkMediaList from '@/components/MkMediaList.vue';
|
||||
import MkKeyValue from '@/components/MkKeyValue.vue';
|
||||
import bytes from '@/filters/bytes.js';
|
||||
import { infoImageUrl } from '@/instance.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
|
|
|
|||
|
|
@ -7,12 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<PageWithHeader>
|
||||
<div class="_spacer" style="--MI_SPACER-w: 800px;">
|
||||
<MkPagination :pagination="pagination">
|
||||
<template #empty>
|
||||
<div class="_fullinfo">
|
||||
<img :src="infoImageUrl" draggable="false"/>
|
||||
<div>{{ i18n.ts.noNotes }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #empty><MkResult type="empty" :text="i18n.ts.noNotes"/></template>
|
||||
|
||||
<template #default="{ items }">
|
||||
<!-- TODO replace with SkDateSeparatedList when merged -->
|
||||
|
|
@ -31,7 +26,6 @@ import DynamicNote from '@/components/DynamicNote.vue';
|
|||
import MkDateSeparatedList from '@/components/MkDateSeparatedList.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { infoImageUrl } from '@/instance.js';
|
||||
|
||||
const pagination = {
|
||||
endpoint: 'i/favorites' as const,
|
||||
|
|
|
|||
|
|
@ -7,12 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<PageWithHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs" :swipable="true">
|
||||
<div class="_spacer" style="--MI_SPACER-w: 800px;">
|
||||
<MkPagination ref="paginationComponent" :pagination="pagination">
|
||||
<template #empty>
|
||||
<div class="_fullinfo">
|
||||
<img :src="infoImageUrl" draggable="false"/>
|
||||
<div>{{ i18n.ts.noFollowRequests }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #empty><MkResult type="empty" :text="i18n.ts.noFollowRequests"/></template>
|
||||
<template #default="{items}">
|
||||
<div class="mk-follow-requests _gaps">
|
||||
<div v-for="req in items" :key="req.id" class="user _panel">
|
||||
|
|
@ -48,7 +43,6 @@ import { userPage, acct } from '@/filters/user.js';
|
|||
import * as os from '@/os.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { infoImageUrl } from '@/instance.js';
|
||||
import { $i } from '@/i.js';
|
||||
|
||||
const paginationComponent = useTemplateRef('paginationComponent');
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<div class="_gaps">
|
||||
<MkInfo v-if="isBaseSilenced" warn>{{ i18n.ts.silencedByBase }}</MkInfo>
|
||||
<MkSwitch v-model="isSilenced" :disabled="!meta || !instance || isBaseSilenced" @update:modelValue="toggleSilenced">{{ i18n.ts.silenceThisInstance }}</MkSwitch>
|
||||
<MkSwitch v-model="isSuspended" :disabled="!instance" @update:modelValue="toggleSuspended">{{ i18n.ts._delivery.stop }}</MkSwitch>
|
||||
<MkSwitch v-model="isSuspended" :disabled="!instance || suspensionState == 'softwareSuspended'" @update:modelValue="toggleSuspended">{{ i18n.ts._delivery.stop }}</MkSwitch>
|
||||
<MkInfo v-if="isBaseBlocked" warn>{{ i18n.ts.blockedByBase }}</MkInfo>
|
||||
<MkSwitch v-model="isBlocked" :disabled="!meta || !instance || isBaseBlocked" @update:modelValue="toggleBlock">{{ i18n.ts.blockThisInstance }}</MkSwitch>
|
||||
<MkSwitch v-model="rejectQuotes" :disabled="!instance" @update:modelValue="toggleRejectQuotes">{{ i18n.ts.rejectQuotesInstance }}</MkSwitch>
|
||||
|
|
@ -249,7 +249,7 @@ const tab = ref('overview');
|
|||
const chartSrc = ref<ChartSrc>('instance-requests');
|
||||
const meta = ref<Misskey.entities.AdminMetaResponse | null>(null);
|
||||
const instance = ref<Misskey.entities.FederationInstance | null>(null);
|
||||
const suspensionState = ref<'none' | 'manuallySuspended' | 'goneSuspended' | 'autoSuspendedForNotResponding'>('none');
|
||||
const suspensionState = ref<'none' | 'manuallySuspended' | 'goneSuspended' | 'autoSuspendedForNotResponding' | 'softwareSuspended'>('none');
|
||||
const isSuspended = ref(false);
|
||||
const isBlocked = ref(false);
|
||||
const isSilenced = ref(false);
|
||||
|
|
@ -436,6 +436,7 @@ async function toggleMediaSilenced(): Promise<void> {
|
|||
|
||||
async function toggleSuspended(): Promise<void> {
|
||||
if (!iAmModerator) return;
|
||||
if (suspensionState.value === 'softwareSuspended') return;
|
||||
await os.promiseDialog(async () => {
|
||||
if (!instance.value) throw new Error('No instance?');
|
||||
suspensionState.value = isSuspended.value ? 'manuallySuspended' : 'none';
|
||||
|
|
|
|||
|
|
@ -6,13 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<template>
|
||||
<PageWithHeader>
|
||||
<div v-if="!instance.disableRegistration || !($i && ($i.isAdmin || $i.policies.canInvite))" class="_spacer" style="--MI_SPACER-w: 1200px;">
|
||||
<div :class="$style.root">
|
||||
<img :class="$style.img" :src="serverErrorImageUrl" draggable="false"/>
|
||||
<div :class="$style.text">
|
||||
<i class="ti ti-alert-triangle"></i>
|
||||
{{ i18n.ts.nothing }}
|
||||
</div>
|
||||
</div>
|
||||
<MkResult type="empty"/>
|
||||
</div>
|
||||
<div v-else class="_spacer" style="--MI_SPACER-w: 800px;">
|
||||
<div class="_gaps_m" style="text-align: center;">
|
||||
|
|
@ -43,7 +37,7 @@ import MkButton from '@/components/MkButton.vue';
|
|||
import MkPagination from '@/components/MkPagination.vue';
|
||||
import MkInviteCode from '@/components/MkInviteCode.vue';
|
||||
import { definePage } from '@/page.js';
|
||||
import { serverErrorImageUrl, instance } from '@/instance.js';
|
||||
import { instance } from '@/instance.js';
|
||||
import { $i } from '@/i.js';
|
||||
|
||||
const pagingComponent = useTemplateRef('pagingComponent');
|
||||
|
|
@ -96,23 +90,3 @@ definePage(() => ({
|
|||
icon: 'ti ti-user-plus',
|
||||
}));
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
.root {
|
||||
padding: 32px;
|
||||
text-align: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.text {
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
|
||||
.img {
|
||||
vertical-align: bottom;
|
||||
width: 128px;
|
||||
height: 128px;
|
||||
margin-bottom: 16px;
|
||||
border-radius: var(--MI-radius-md);
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -6,13 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<template>
|
||||
<PageWithHeader :actions="headerActions" :tabs="headerTabs">
|
||||
<div v-if="error != null" class="_spacer" style="--MI_SPACER-w: 1200px;">
|
||||
<div :class="$style.root">
|
||||
<img :class="$style.img" :src="serverErrorImageUrl" draggable="false"/>
|
||||
<p :class="$style.text">
|
||||
<i class="ti ti-alert-triangle"></i>
|
||||
{{ i18n.ts.nothing }}
|
||||
</p>
|
||||
</div>
|
||||
<MkResult type="error"/>
|
||||
</div>
|
||||
<div v-else-if="list" class="_spacer" style="--MI_SPACER-w: 700px;">
|
||||
<div v-if="list" class="members _margin">
|
||||
|
|
@ -42,7 +36,6 @@ import { i18n } from '@/i18n.js';
|
|||
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import { definePage } from '@/page.js';
|
||||
import { serverErrorImageUrl } from '@/instance.js';
|
||||
|
||||
const props = defineProps<{
|
||||
listId: string;
|
||||
|
|
|
|||
|
|
@ -7,12 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<PageWithHeader :actions="headerActions" :tabs="headerTabs">
|
||||
<div class="_spacer" style="--MI_SPACER-w: 700px;">
|
||||
<div>
|
||||
<div v-if="antennas.length === 0" class="empty">
|
||||
<div class="_fullinfo">
|
||||
<img :src="infoImageUrl" draggable="false"/>
|
||||
<div>{{ i18n.ts.nothing }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<MkResult v-if="antennas.length === 0" type="empty"/>
|
||||
|
||||
<MkButton :link="true" to="/my/antennas/create" primary :class="$style.add"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton>
|
||||
|
||||
|
|
@ -32,7 +27,6 @@ import MkButton from '@/components/MkButton.vue';
|
|||
import { i18n } from '@/i18n.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { antennasCache } from '@/cache.js';
|
||||
import { infoImageUrl } from '@/instance.js';
|
||||
|
||||
const antennas = computed(() => antennasCache.value.value ?? []);
|
||||
|
||||
|
|
|
|||
|
|
@ -7,12 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<PageWithHeader :actions="headerActions" :tabs="headerTabs">
|
||||
<div class="_spacer" style="--MI_SPACER-w: 700px;">
|
||||
<div class="_gaps">
|
||||
<div v-if="items.length === 0" class="empty">
|
||||
<div class="_fullinfo">
|
||||
<img :src="infoImageUrl" draggable="false"/>
|
||||
<div>{{ i18n.ts.nothing }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<MkResult v-if="items.length === 0" type="empty"/>
|
||||
|
||||
<MkButton primary rounded style="margin: 0 auto;" @click="create"><i class="ti ti-plus"></i> {{ i18n.ts.createList }}</MkButton>
|
||||
|
||||
|
|
@ -35,7 +30,6 @@ import * as os from '@/os.js';
|
|||
import { i18n } from '@/i18n.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { userListsCache } from '@/cache.js';
|
||||
import { infoImageUrl } from '@/instance.js';
|
||||
import { ensureSignin } from '@/i.js';
|
||||
|
||||
const $i = ensureSignin();
|
||||
|
|
|
|||
|
|
@ -4,11 +4,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
-->
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="_fullinfo">
|
||||
<img :src="notFoundImageUrl" draggable="false"/>
|
||||
<div>{{ i18n.ts.notFoundDescription }}</div>
|
||||
</div>
|
||||
<div style="align-content: center; height: 100cqh;">
|
||||
<MkResult type="notFound" :text="i18n.ts.notFoundDescription"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -17,7 +14,6 @@ import { computed } from 'vue';
|
|||
import { i18n } from '@/i18n.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { pleaseLogin } from '@/utility/please-login.js';
|
||||
import { notFoundImageUrl } from '@/instance.js';
|
||||
|
||||
const props = defineProps<{
|
||||
showLoginPopup?: boolean;
|
||||
|
|
|
|||
|
|
@ -6,30 +6,18 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<template>
|
||||
<PageWithHeader v-model:tab="tab" :displayBackButton="true" :tabs="headerTabs">
|
||||
<div v-if="error != null" class="_spacer" style="--MI_SPACER-w: 1200px;">
|
||||
<div :class="$style.root">
|
||||
<img :class="$style.img" :src="serverErrorImageUrl" draggable="false"/>
|
||||
<p :class="$style.text">
|
||||
<i class="ti ti-alert-triangle"></i>
|
||||
{{ error }}
|
||||
</p>
|
||||
</div>
|
||||
<MkResult type="error" :text="error"/>
|
||||
</div>
|
||||
<div v-else-if="tab === 'users'" class="_spacer" style="--MI_SPACER-w: 1200px;">
|
||||
<div class="_gaps_s">
|
||||
<div v-if="role">{{ role.description }}</div>
|
||||
<MkUserList v-if="visible" :pagination="users" :extractor="(item) => item.user"/>
|
||||
<div v-else-if="!visible" class="_fullinfo">
|
||||
<img :src="infoImageUrl" draggable="false"/>
|
||||
<div>{{ i18n.ts.nothing }}</div>
|
||||
</div>
|
||||
<MkResult v-else-if="!visible" type="empty" :text="i18n.ts.nothing"/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="tab === 'timeline'" class="_spacer" style="--MI_SPACER-w: 700px;">
|
||||
<MkTimeline v-if="visible" ref="timeline" src="role" :role="props.roleId"/>
|
||||
<div v-else-if="!visible" class="_fullinfo">
|
||||
<img :src="infoImageUrl" draggable="false"/>
|
||||
<div>{{ i18n.ts.nothing }}</div>
|
||||
</div>
|
||||
<MkResult v-else-if="!visible" type="empty" :text="i18n.ts.nothing"/>
|
||||
</div>
|
||||
</PageWithHeader>
|
||||
</template>
|
||||
|
|
@ -37,13 +25,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<script lang="ts" setup>
|
||||
import { computed, watch, ref } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { instanceName } from '@@/js/config.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import MkUserList from '@/components/MkUserList.vue';
|
||||
import { definePage } from '@/page.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import MkTimeline from '@/components/MkTimeline.vue';
|
||||
import { serverErrorImageUrl, infoImageUrl } from '@/instance.js';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
roleId: string;
|
||||
|
|
@ -97,23 +83,3 @@ definePage(() => ({
|
|||
icon: 'ti ti-badge',
|
||||
}));
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
.root {
|
||||
padding: 32px;
|
||||
text-align: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.text {
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
|
||||
.img {
|
||||
vertical-align: bottom;
|
||||
width: 128px;
|
||||
height: 128px;
|
||||
margin-bottom: 16px;
|
||||
border-radius: var(--MI-radius-md);
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -6,12 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<template>
|
||||
<div class="_gaps_m">
|
||||
<FormPagination ref="list" :pagination="pagination">
|
||||
<template #empty>
|
||||
<div class="_fullinfo">
|
||||
<img :src="infoImageUrl" draggable="false"/>
|
||||
<div>{{ i18n.ts.nothing }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #empty><MkResult type="empty"/></template>
|
||||
<template #default="{items}">
|
||||
<div class="_gaps">
|
||||
<MkFolder v-for="token in items" :key="token.id" :defaultOpen="true">
|
||||
|
|
@ -63,7 +58,6 @@ import { definePage } from '@/page.js';
|
|||
import MkKeyValue from '@/components/MkKeyValue.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkFolder from '@/components/MkFolder.vue';
|
||||
import { infoImageUrl } from '@/instance.js';
|
||||
|
||||
const list = ref<InstanceType<typeof FormPagination>>();
|
||||
|
||||
|
|
|
|||
|
|
@ -78,12 +78,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<template #label><SearchLabel>{{ i18n.ts.mutedUsers }} ({{ i18n.ts.renote }})</SearchLabel></template>
|
||||
|
||||
<MkPagination :pagination="renoteMutingPagination">
|
||||
<template #empty>
|
||||
<div class="_fullinfo">
|
||||
<img :src="infoImageUrl" draggable="false"/>
|
||||
<div>{{ i18n.ts.noUsers }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #empty><MkResult type="empty" :text="i18n.ts.noUsers"/></template>
|
||||
|
||||
<template #default="{ items }">
|
||||
<div class="_gaps_s">
|
||||
|
|
@ -115,12 +110,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<template #label>{{ i18n.ts.mutedUsers }}</template>
|
||||
|
||||
<MkPagination :pagination="mutingPagination">
|
||||
<template #empty>
|
||||
<div class="_fullinfo">
|
||||
<img :src="infoImageUrl" draggable="false"/>
|
||||
<div>{{ i18n.ts.noUsers }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #empty><MkResult type="empty" :text="i18n.ts.noUsers"/></template>
|
||||
|
||||
<template #default="{ items }">
|
||||
<div class="_gaps_s">
|
||||
|
|
@ -154,12 +144,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<template #label>{{ i18n.ts.blockedUsers }}</template>
|
||||
|
||||
<MkPagination :pagination="blockingPagination">
|
||||
<template #empty>
|
||||
<div class="_fullinfo">
|
||||
<img :src="infoImageUrl" draggable="false"/>
|
||||
<div>{{ i18n.ts.noUsers }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #empty><MkResult type="empty" :text="i18n.ts.noUsers"/></template>
|
||||
|
||||
<template #default="{ items }">
|
||||
<div class="_gaps_s">
|
||||
|
|
@ -197,7 +182,7 @@ import { i18n } from '@/i18n.js';
|
|||
import { definePage } from '@/page.js';
|
||||
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||
import * as os from '@/os.js';
|
||||
import { instance, infoImageUrl } from '@/instance.js';
|
||||
import { instance } from '@/instance.js';
|
||||
import { ensureSignin } from '@/i.js';
|
||||
import MkInfo from '@/components/MkInfo.vue';
|
||||
import MkFolder from '@/components/MkFolder.vue';
|
||||
|
|
|
|||
|
|
@ -628,6 +628,15 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</MkPreferenceContainer>
|
||||
</SearchMarker>
|
||||
|
||||
<SearchMarker :keywords="['swipe', 'pull', 'refresh']">
|
||||
<MkPreferenceContainer k="enablePullToRefresh">
|
||||
<MkSwitch v-model="enablePullToRefresh">
|
||||
<template #label><SearchLabel>{{ i18n.ts._settings.enablePullToRefresh }}</SearchLabel></template>
|
||||
<template #caption><SearchKeyword>{{ i18n.ts._settings.enablePullToRefresh_description }}</SearchKeyword></template>
|
||||
</MkSwitch>
|
||||
</MkPreferenceContainer>
|
||||
</SearchMarker>
|
||||
|
||||
<SearchMarker :keywords="['keep', 'screen', 'display', 'on']">
|
||||
<MkPreferenceContainer k="keepScreenOn">
|
||||
<MkSwitch v-model="keepScreenOn">
|
||||
|
|
@ -1032,6 +1041,7 @@ const animatedMfm = prefer.model('animatedMfm');
|
|||
const disableShowingAnimatedImages = prefer.model('disableShowingAnimatedImages');
|
||||
const keepScreenOn = prefer.model('keepScreenOn');
|
||||
const enableHorizontalSwipe = prefer.model('enableHorizontalSwipe');
|
||||
const enablePullToRefresh = prefer.model('enablePullToRefresh');
|
||||
const useNativeUiForVideoAudioPlayer = prefer.model('useNativeUiForVideoAudioPlayer');
|
||||
const contextMenu = prefer.model('contextMenu');
|
||||
const menuStyle = prefer.model('menuStyle');
|
||||
|
|
@ -1088,6 +1098,8 @@ watch([
|
|||
keepScreenOn,
|
||||
contextMenu,
|
||||
makeEveryTextElementsSelectable,
|
||||
enableHorizontalSwipe,
|
||||
enablePullToRefresh,
|
||||
noteDesign,
|
||||
], async () => {
|
||||
await reloadAsk({ reason: i18n.ts.reloadToApplySetting, unison: true });
|
||||
|
|
|
|||
47
packages/frontend/src/pages/settings/profiles.vue
Normal file
47
packages/frontend/src/pages/settings/profiles.vue
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
<!--
|
||||
SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<template>
|
||||
<SearchMarker path="/settings/profiles" :label="i18n.ts._preferencesProfile.manageProfiles" :keywords="['profile', 'settings', 'preferences', 'manage']" icon="ti ti-settings-cog">
|
||||
<div class="_gaps">
|
||||
<MkFolder v-for="backup in backups">
|
||||
<template #label>{{ backup.name }}</template>
|
||||
<MkButton danger @click="del(backup)">{{ i18n.ts.delete }}</MkButton>
|
||||
</MkFolder>
|
||||
</div>
|
||||
</SearchMarker>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import type { MenuItem } from '@/types/menu.js';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkFolder from '@/components/MkFolder.vue';
|
||||
import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
import { deleteCloudBackup, listCloudBackups } from '@/preferences/utility.js';
|
||||
|
||||
const backups = await listCloudBackups();
|
||||
|
||||
function del(backup) {
|
||||
deleteCloudBackup(backup.name);
|
||||
}
|
||||
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePage(() => ({
|
||||
title: i18n.ts._preferencesProfile.manageProfiles,
|
||||
icon: 'ti ti-settings-cog',
|
||||
}));
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
</style>
|
||||
|
|
@ -173,8 +173,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<MkLazy>
|
||||
<div v-if="noteview === 'pinned'" class="_gaps">
|
||||
<div v-if="user.pinnedNotes.length < 1" class="_fullinfo">
|
||||
<img :src="infoImageUrl" draggable="false" aria-hidden="true" :alt="i18n.ts.noNotes"/>
|
||||
<div>{{ i18n.ts.noNotes }}</div>
|
||||
<MkResult type="empty" :text="i18n.ts.noNotes"/>
|
||||
</div>
|
||||
<div v-else class="_panel">
|
||||
<DynamicNote v-for="note of user.pinnedNotes" :key="note.id" class="note" :class="$style.pinnedNote" :note="note" :pinned="true"/>
|
||||
|
|
@ -220,7 +219,6 @@ import { misskeyApi } from '@/utility/misskey-api.js';
|
|||
import { isFollowingVisibleForMe, isFollowersVisibleForMe } from '@/utility/isFfVisibleForMe.js';
|
||||
import { useRouter } from '@/router.js';
|
||||
import { getStaticImageUrl } from '@/utility/media-proxy.js';
|
||||
import { infoImageUrl } from '@/instance.js';
|
||||
import MkSparkle from '@/components/MkSparkle.vue';
|
||||
import { prefer } from '@/preferences.js';
|
||||
import DynamicNote from '@/components/DynamicNote.vue';
|
||||
|
|
|
|||
|
|
@ -16,8 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
<div v-if="tab === 'pinned'" class="_gaps">
|
||||
<div v-if="user.pinnedNotes.length < 1" class="_fullinfo">
|
||||
<img :src="infoImageUrl" draggable="false" aria-hidden="true" :alt="i18n.ts.noNotes"/>
|
||||
<div>{{ i18n.ts.noNotes }}</div>
|
||||
<MkResult type="empty" :text="i18n.ts.noNotes"/>
|
||||
</div>
|
||||
<div v-else class="_panel">
|
||||
<DynamicNote v-for="note of user.pinnedNotes" :key="note.id" class="note" :class="$style.pinnedNote" :note="note" :pinned="true"/>
|
||||
|
|
@ -33,7 +32,6 @@ import * as Misskey from 'misskey-js';
|
|||
import MkNotes from '@/components/MkNotes.vue';
|
||||
import MkTab from '@/components/MkTab.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { infoImageUrl } from '@/instance.js';
|
||||
import DynamicNote from '@/components/DynamicNote.vue';
|
||||
|
||||
const props = defineProps<{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue