refactor(frontend): 空/エラー結果表示をコンポーネント化 (#15963)
* wip * wip * wip * wip * wip * Update MkResult.vue * Add storybook story for MkResult (#15964) * Update MkResult.vue --------- Co-authored-by: taichan <40626578+tai-cha@users.noreply.github.com>
This commit is contained in:
parent
d476f7ff50
commit
8959bfa1c0
|
@ -6,7 +6,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img :src="notFoundImageUrl" draggable="false"/>
|
|
||||||
<div>{{ i18n.ts.notFoundDescription }}</div>
|
<div>{{ i18n.ts.notFoundDescription }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -14,11 +13,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { inject, computed } from 'vue';
|
import { inject, computed } from 'vue';
|
||||||
import { DEFAULT_NOT_FOUND_IMAGE_URL } from '@@/js/const.js';
|
|
||||||
import { DI } from '@/di.js';
|
import { DI } from '@/di.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
||||||
const serverMetadata = inject(DI.serverMetadata)!;
|
const serverMetadata = inject(DI.serverMetadata)!;
|
||||||
|
|
||||||
const notFoundImageUrl = computed(() => serverMetadata.notFoundImageUrl ?? DEFAULT_NOT_FOUND_IMAGE_URL);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -286,13 +286,6 @@ rt {
|
||||||
._fullinfo {
|
._fullinfo {
|
||||||
padding: 64px 32px;
|
padding: 64px 32px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
> img {
|
|
||||||
vertical-align: bottom;
|
|
||||||
height: 128px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
border-radius: 16px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
._link {
|
._link {
|
||||||
|
|
|
@ -112,10 +112,6 @@ export const ROLE_POLICIES = [
|
||||||
'chatAvailability',
|
'chatAvailability',
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export const DEFAULT_SERVER_ERROR_IMAGE_URL = 'https://xn--931a.moe/assets/error.jpg';
|
|
||||||
export const DEFAULT_NOT_FOUND_IMAGE_URL = 'https://xn--931a.moe/assets/not-found.jpg';
|
|
||||||
export const DEFAULT_INFO_IMAGE_URL = 'https://xn--931a.moe/assets/info.jpg';
|
|
||||||
|
|
||||||
export const MFM_TAGS = ['tada', 'jelly', 'twitch', 'shake', 'spin', 'jump', 'bounce', 'flip', 'x2', 'x3', 'x4', 'scale', 'position', 'fg', 'bg', 'border', 'font', 'blur', 'rainbow', 'sparkle', 'rotate', 'ruby', 'unixtime'];
|
export const MFM_TAGS = ['tada', 'jelly', 'twitch', 'shake', 'spin', 'jump', 'bounce', 'flip', 'x2', 'x3', 'x4', 'scale', 'position', 'fg', 'bg', 'border', 'font', 'blur', 'rainbow', 'sparkle', 'rotate', 'ruby', 'unixtime'];
|
||||||
export const MFM_PARAMS: Record<typeof MFM_TAGS[number], string[]> = {
|
export const MFM_PARAMS: Record<typeof MFM_TAGS[number], string[]> = {
|
||||||
tada: ['speed=', 'delay='],
|
tada: ['speed=', 'delay='],
|
||||||
|
|
|
@ -5,12 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<MkPagination :pagination="pagination">
|
<MkPagination :pagination="pagination">
|
||||||
<template #empty>
|
<template #empty><MkResult type="empty"/></template>
|
||||||
<div class="_fullinfo">
|
|
||||||
<img :src="infoImageUrl" draggable="false"/>
|
|
||||||
<div>{{ i18n.ts.notFound }}</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #default="{ items }">
|
<template #default="{ items }">
|
||||||
<MkChannelPreview v-for="item in items" :key="item.id" class="_margin" :channel="extractor(item)"/>
|
<MkChannelPreview v-for="item in items" :key="item.id" class="_margin" :channel="extractor(item)"/>
|
||||||
|
@ -23,7 +18,6 @@ import type { Paging } from '@/components/MkPagination.vue';
|
||||||
import MkChannelPreview from '@/components/MkChannelPreview.vue';
|
import MkChannelPreview from '@/components/MkChannelPreview.vue';
|
||||||
import MkPagination from '@/components/MkPagination.vue';
|
import MkPagination from '@/components/MkPagination.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
pagination: Paging;
|
pagination: Paging;
|
||||||
|
|
|
@ -28,9 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
</MkA>
|
</MkA>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!initializing && history.length == 0" class="_fullinfo">
|
<MkResult v-if="!initializing && history.length == 0" type="empty" :text="i18n.ts._chat.noHistory"/>
|
||||||
<div>{{ i18n.ts._chat.noHistory }}</div>
|
|
||||||
</div>
|
|
||||||
<MkLoading v-if="initializing"/>
|
<MkLoading v-if="initializing"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -62,10 +62,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="_fullinfo">
|
<MkResult v-else type="empty"/>
|
||||||
<img :src="infoImageUrl" draggable="false"/>
|
|
||||||
<div>{{ i18n.ts.nothing }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</MkModalWindow>
|
</MkModalWindow>
|
||||||
</template>
|
</template>
|
||||||
|
@ -83,7 +80,6 @@ import XFile from './MkFormDialog.file.vue';
|
||||||
import type { Form } from '@/utility/form.js';
|
import type { Form } from '@/utility/form.js';
|
||||||
import MkModalWindow from '@/components/MkModalWindow.vue';
|
import MkModalWindow from '@/components/MkModalWindow.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
title: string;
|
title: string;
|
||||||
|
|
|
@ -5,12 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<MkPagination ref="pagingComponent" :pagination="pagination" :disableAutoLoad="disableAutoLoad">
|
<MkPagination ref="pagingComponent" :pagination="pagination" :disableAutoLoad="disableAutoLoad">
|
||||||
<template #empty>
|
<template #empty><MkResult type="empty" :text="i18n.ts.noNotes"/></template>
|
||||||
<div class="_fullinfo">
|
|
||||||
<img :src="infoImageUrl" draggable="false"/>
|
|
||||||
<div>{{ i18n.ts.noNotes }}</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #default="{ items: notes }">
|
<template #default="{ items: notes }">
|
||||||
<div :class="[$style.root, { [$style.noGap]: noGap, '_gaps': !noGap, [$style.reverse]: pagination.reversed }]">
|
<div :class="[$style.root, { [$style.noGap]: noGap, '_gaps': !noGap, [$style.reverse]: pagination.reversed }]">
|
||||||
|
@ -34,7 +29,6 @@ import type { Paging } from '@/components/MkPagination.vue';
|
||||||
import MkNote from '@/components/MkNote.vue';
|
import MkNote from '@/components/MkNote.vue';
|
||||||
import MkPagination from '@/components/MkPagination.vue';
|
import MkPagination from '@/components/MkPagination.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
pagination: Paging;
|
pagination: Paging;
|
||||||
|
|
|
@ -11,7 +11,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div v-else-if="notification.type === 'reaction:grouped' && notification.note.reactionAcceptance === 'likeOnly'" :class="[$style.icon, $style.icon_reactionGroupHeart]"><i class="ti ti-heart" style="line-height: 1;"></i></div>
|
<div v-else-if="notification.type === 'reaction:grouped' && notification.note.reactionAcceptance === 'likeOnly'" :class="[$style.icon, $style.icon_reactionGroupHeart]"><i class="ti ti-heart" style="line-height: 1;"></i></div>
|
||||||
<div v-else-if="notification.type === 'reaction:grouped'" :class="[$style.icon, $style.icon_reactionGroup]"><i class="ti ti-plus" style="line-height: 1;"></i></div>
|
<div v-else-if="notification.type === 'reaction:grouped'" :class="[$style.icon, $style.icon_reactionGroup]"><i class="ti ti-plus" style="line-height: 1;"></i></div>
|
||||||
<div v-else-if="notification.type === 'renote:grouped'" :class="[$style.icon, $style.icon_renoteGroup]"><i class="ti ti-repeat" style="line-height: 1;"></i></div>
|
<div v-else-if="notification.type === 'renote:grouped'" :class="[$style.icon, $style.icon_renoteGroup]"><i class="ti ti-repeat" style="line-height: 1;"></i></div>
|
||||||
<img v-else-if="notification.type === 'test'" :class="$style.icon" :src="infoImageUrl"/>
|
|
||||||
<MkAvatar v-else-if="'user' in notification" :class="$style.icon" :user="notification.user" link preview/>
|
<MkAvatar v-else-if="'user' in notification" :class="$style.icon" :user="notification.user" link preview/>
|
||||||
<img v-else-if="'icon' in notification && notification.icon != null" :class="[$style.icon, $style.icon_app]" :src="notification.icon" alt=""/>
|
<img v-else-if="'icon' in notification && notification.icon != null" :class="[$style.icon, $style.icon_app]" :src="notification.icon" alt=""/>
|
||||||
<div
|
<div
|
||||||
|
@ -176,7 +175,6 @@ import { userPage } from '@/filters/user.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
import { ensureSignin } from '@/i.js';
|
import { ensureSignin } from '@/i.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
|
||||||
|
|
||||||
const $i = ensureSignin();
|
const $i = ensureSignin();
|
||||||
|
|
||||||
|
|
|
@ -6,12 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template>
|
<template>
|
||||||
<component :is="prefer.s.enablePullToRefresh ? MkPullToRefresh : 'div'" :refresher="() => reload()">
|
<component :is="prefer.s.enablePullToRefresh ? MkPullToRefresh : 'div'" :refresher="() => reload()">
|
||||||
<MkPagination ref="pagingComponent" :pagination="pagination">
|
<MkPagination ref="pagingComponent" :pagination="pagination">
|
||||||
<template #empty>
|
<template #empty><MkResult type="empty" :text="i18n.ts.noNotifications"/></template>
|
||||||
<div class="_fullinfo">
|
|
||||||
<img :src="infoImageUrl" draggable="false"/>
|
|
||||||
<div>{{ i18n.ts.noNotifications }}</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #default="{ items: notifications }">
|
<template #default="{ items: notifications }">
|
||||||
<component
|
<component
|
||||||
|
@ -42,7 +37,6 @@ import XNotification from '@/components/MkNotification.vue';
|
||||||
import MkNote from '@/components/MkNote.vue';
|
import MkNote from '@/components/MkNote.vue';
|
||||||
import { useStream } from '@/stream.js';
|
import { useStream } from '@/stream.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
|
||||||
import MkPullToRefresh from '@/components/MkPullToRefresh.vue';
|
import MkPullToRefresh from '@/components/MkPullToRefresh.vue';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
|
|
|
@ -16,12 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkError v-else-if="error" @retry="init()"/>
|
<MkError v-else-if="error" @retry="init()"/>
|
||||||
|
|
||||||
<div v-else-if="empty" key="_empty_">
|
<div v-else-if="empty" key="_empty_">
|
||||||
<slot name="empty">
|
<slot name="empty"><MkResult type="empty"/></slot>
|
||||||
<div class="_fullinfo">
|
|
||||||
<img :src="infoImageUrl" draggable="false"/>
|
|
||||||
<div>{{ i18n.ts.nothing }}</div>
|
|
||||||
</div>
|
|
||||||
</slot>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else ref="rootEl" class="_gaps">
|
<div v-else ref="rootEl" class="_gaps">
|
||||||
|
@ -88,7 +83,6 @@ function concatMapWithArray(map: MisskeyEntityMap, entities: MisskeyEntity[]): M
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { infoImageUrl } from '@/instance.js';
|
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
|
|
|
@ -6,12 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template>
|
<template>
|
||||||
<component :is="prefer.s.enablePullToRefresh ? MkPullToRefresh : 'div'" :refresher="() => reloadTimeline()">
|
<component :is="prefer.s.enablePullToRefresh ? MkPullToRefresh : 'div'" :refresher="() => reloadTimeline()">
|
||||||
<MkPagination v-if="paginationQuery" ref="pagingComponent" :pagination="paginationQuery" @queue="emit('queue', $event)">
|
<MkPagination v-if="paginationQuery" ref="pagingComponent" :pagination="paginationQuery" @queue="emit('queue', $event)">
|
||||||
<template #empty>
|
<template #empty><MkResult type="empty" :text="i18n.ts.noNotes"/></template>
|
||||||
<div class="_fullinfo">
|
|
||||||
<img :src="infoImageUrl" draggable="false"/>
|
|
||||||
<div>{{ i18n.ts.noNotes }}</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #default="{ items: notes }">
|
<template #default="{ items: notes }">
|
||||||
<component
|
<component
|
||||||
|
@ -53,7 +48,6 @@ import { prefer } from '@/preferences.js';
|
||||||
import MkNote from '@/components/MkNote.vue';
|
import MkNote from '@/components/MkNote.vue';
|
||||||
import MkPagination from '@/components/MkPagination.vue';
|
import MkPagination from '@/components/MkPagination.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
src: BasicTimelineType | 'mentions' | 'directs' | 'list' | 'antenna' | 'channel' | 'role';
|
src: BasicTimelineType | 'mentions' | 'directs' | 'list' | 'antenna' | 'channel' | 'role';
|
||||||
|
|
|
@ -5,12 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<MkPagination :pagination="pagination">
|
<MkPagination :pagination="pagination">
|
||||||
<template #empty>
|
<template #empty><MkResult type="empty" :text="i18n.ts.noUsers"/></template>
|
||||||
<div class="_fullinfo">
|
|
||||||
<img :src="infoImageUrl" draggable="false"/>
|
|
||||||
<div>{{ i18n.ts.noUsers }}</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #default="{ items }">
|
<template #default="{ items }">
|
||||||
<div :class="$style.root">
|
<div :class="$style.root">
|
||||||
|
@ -25,7 +20,6 @@ import type { Paging } from '@/components/MkPagination.vue';
|
||||||
import MkUserInfo from '@/components/MkUserInfo.vue';
|
import MkUserInfo from '@/components/MkUserInfo.vue';
|
||||||
import MkPagination from '@/components/MkPagination.vue';
|
import MkPagination from '@/components/MkPagination.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
pagination: Paging;
|
pagination: Paging;
|
||||||
|
|
|
@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template>
|
<template>
|
||||||
<Transition :name="prefer.s.animation ? '_transition_zoom' : ''" appear>
|
<Transition :name="prefer.s.animation ? '_transition_zoom' : ''" appear>
|
||||||
<div :class="$style.root">
|
<div :class="$style.root">
|
||||||
<img :class="$style.img" :src="serverErrorImageUrl" draggable="false"/>
|
<img v-if="instance.serverErrorImageUrl" :class="$style.img" :src="instance.serverErrorImageUrl" draggable="false"/>
|
||||||
<p :class="$style.text"><i class="ti ti-alert-triangle"></i> {{ i18n.ts.somethingHappened }}</p>
|
<p :class="$style.text"><i class="ti ti-alert-triangle"></i> {{ i18n.ts.somethingHappened }}</p>
|
||||||
<MkButton :class="$style.button" @click="() => emit('retry')">{{ i18n.ts.retry }}</MkButton>
|
<MkButton :class="$style.button" @click="() => emit('retry')">{{ i18n.ts.retry }}</MkButton>
|
||||||
</div>
|
</div>
|
||||||
|
@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { serverErrorImageUrl } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: 'retry'): void;
|
(ev: 'retry'): void;
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import MkResult from './MkResult.vue';
|
||||||
|
import type { StoryObj } from '@storybook/vue3';
|
||||||
|
export const Default = {
|
||||||
|
render(args) {
|
||||||
|
return {
|
||||||
|
components: {
|
||||||
|
MkResult,
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
return {
|
||||||
|
args,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
props() {
|
||||||
|
return {
|
||||||
|
...this.args,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
template: '<MkResult v-bind="props" />',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
args: {
|
||||||
|
type: 'empty',
|
||||||
|
text: 'Lorem Ipsum',
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
layout: 'centered',
|
||||||
|
},
|
||||||
|
} satisfies StoryObj<typeof MkResult>;
|
||||||
|
export const emptyWithNoText = {
|
||||||
|
...Default,
|
||||||
|
args: {
|
||||||
|
...Default.args,
|
||||||
|
text: undefined,
|
||||||
|
},
|
||||||
|
} satisfies StoryObj<typeof MkResult>;
|
||||||
|
export const notFound = {
|
||||||
|
...Default,
|
||||||
|
args: {
|
||||||
|
...Default.args,
|
||||||
|
type: 'notFound',
|
||||||
|
},
|
||||||
|
} satisfies StoryObj<typeof MkResult>;
|
||||||
|
export const errorType = {
|
||||||
|
...Default,
|
||||||
|
args: {
|
||||||
|
...Default.args,
|
||||||
|
type: 'error',
|
||||||
|
},
|
||||||
|
} satisfies StoryObj<typeof MkResult>;
|
|
@ -0,0 +1,44 @@
|
||||||
|
<!--
|
||||||
|
SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div :class="[$style.root]" class="_gaps">
|
||||||
|
<img v-if="type === 'empty' && instance.infoImageUrl" :src="instance.infoImageUrl" draggable="false" :class="$style.img"/>
|
||||||
|
<i v-else-if="type === 'empty'" class="ti ti-info-circle" :class="$style.icon"></i>
|
||||||
|
<div>{{ props.text ?? (type === 'empty' ? i18n.ts.nothing : type === 'notFound' ? i18n.ts.notFound : null) }}</div>
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import {} from 'vue';
|
||||||
|
import { instance } from '@/instance.js';
|
||||||
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
type: 'empty' | 'notFound' | 'error';
|
||||||
|
text?: string;
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" module>
|
||||||
|
.root {
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
padding: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.img {
|
||||||
|
vertical-align: bottom;
|
||||||
|
height: 128px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
border-radius: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
font-size: 24px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -24,6 +24,7 @@ import MkAd from './global/MkAd.vue';
|
||||||
import MkPageHeader from './global/MkPageHeader.vue';
|
import MkPageHeader from './global/MkPageHeader.vue';
|
||||||
import MkStickyContainer from './global/MkStickyContainer.vue';
|
import MkStickyContainer from './global/MkStickyContainer.vue';
|
||||||
import MkLazy from './global/MkLazy.vue';
|
import MkLazy from './global/MkLazy.vue';
|
||||||
|
import MkResult from './global/MkResult.vue';
|
||||||
import PageWithHeader from './global/PageWithHeader.vue';
|
import PageWithHeader from './global/PageWithHeader.vue';
|
||||||
import PageWithAnimBg from './global/PageWithAnimBg.vue';
|
import PageWithAnimBg from './global/PageWithAnimBg.vue';
|
||||||
import SearchMarker from './global/SearchMarker.vue';
|
import SearchMarker from './global/SearchMarker.vue';
|
||||||
|
@ -61,6 +62,7 @@ export const components = {
|
||||||
MkPageHeader: MkPageHeader,
|
MkPageHeader: MkPageHeader,
|
||||||
MkStickyContainer: MkStickyContainer,
|
MkStickyContainer: MkStickyContainer,
|
||||||
MkLazy: MkLazy,
|
MkLazy: MkLazy,
|
||||||
|
MkResult: MkResult,
|
||||||
PageWithHeader: PageWithHeader,
|
PageWithHeader: PageWithHeader,
|
||||||
PageWithAnimBg: PageWithAnimBg,
|
PageWithAnimBg: PageWithAnimBg,
|
||||||
SearchMarker: SearchMarker,
|
SearchMarker: SearchMarker,
|
||||||
|
@ -92,6 +94,7 @@ declare module '@vue/runtime-core' {
|
||||||
MkPageHeader: typeof MkPageHeader;
|
MkPageHeader: typeof MkPageHeader;
|
||||||
MkStickyContainer: typeof MkStickyContainer;
|
MkStickyContainer: typeof MkStickyContainer;
|
||||||
MkLazy: typeof MkLazy;
|
MkLazy: typeof MkLazy;
|
||||||
|
MkResult: typeof MkResult;
|
||||||
PageWithHeader: typeof PageWithHeader;
|
PageWithHeader: typeof PageWithHeader;
|
||||||
PageWithAnimBg: typeof PageWithAnimBg;
|
PageWithAnimBg: typeof PageWithAnimBg;
|
||||||
SearchMarker: typeof SearchMarker;
|
SearchMarker: typeof SearchMarker;
|
||||||
|
|
|
@ -7,7 +7,6 @@ import { computed, reactive } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
import { miLocalStorage } from '@/local-storage.js';
|
import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { DEFAULT_INFO_IMAGE_URL, DEFAULT_NOT_FOUND_IMAGE_URL, DEFAULT_SERVER_ERROR_IMAGE_URL } from '@@/js/const.js';
|
|
||||||
|
|
||||||
// TODO: 他のタブと永続化されたstateを同期
|
// TODO: 他のタブと永続化されたstateを同期
|
||||||
|
|
||||||
|
@ -30,12 +29,6 @@ if (providedAt > cachedAt) {
|
||||||
|
|
||||||
export const instance: Misskey.entities.MetaDetailed = reactive(cachedMeta ?? {});
|
export const instance: Misskey.entities.MetaDetailed = reactive(cachedMeta ?? {});
|
||||||
|
|
||||||
export const serverErrorImageUrl = computed(() => instance.serverErrorImageUrl ?? DEFAULT_SERVER_ERROR_IMAGE_URL);
|
|
||||||
|
|
||||||
export const infoImageUrl = computed(() => instance.infoImageUrl ?? DEFAULT_INFO_IMAGE_URL);
|
|
||||||
|
|
||||||
export const notFoundImageUrl = computed(() => instance.notFoundImageUrl ?? DEFAULT_NOT_FOUND_IMAGE_URL);
|
|
||||||
|
|
||||||
export const isEnabledUrlPreview = computed(() => instance.enableUrlPreview ?? true);
|
export const isEnabledUrlPreview = computed(() => instance.enableUrlPreview ?? true);
|
||||||
|
|
||||||
export async function fetchInstance(force = false): Promise<Misskey.entities.MetaDetailed> {
|
export async function fetchInstance(force = false): Promise<Misskey.entities.MetaDetailed> {
|
||||||
|
|
|
@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkLoading v-if="!loaded"/>
|
<MkLoading v-if="!loaded"/>
|
||||||
<Transition :name="prefer.s.animation ? '_transition_zoom' : ''" appear>
|
<Transition :name="prefer.s.animation ? '_transition_zoom' : ''" appear>
|
||||||
<div v-show="loaded" :class="$style.root">
|
<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 class="_gaps">
|
||||||
<div><b><i class="ti ti-alert-triangle"></i> {{ i18n.ts.pageLoadError }}</b></div>
|
<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>
|
<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 { definePage } from '@/page.js';
|
||||||
import { miLocalStorage } from '@/local-storage.js';
|
import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { serverErrorImageUrl } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
error?: Error;
|
error?: Error;
|
||||||
|
|
|
@ -24,12 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkButton primary rounded @click="assign"><i class="ti ti-plus"></i> {{ i18n.ts.assign }}</MkButton>
|
<MkButton primary rounded @click="assign"><i class="ti ti-plus"></i> {{ i18n.ts.assign }}</MkButton>
|
||||||
|
|
||||||
<MkPagination :pagination="usersPagination">
|
<MkPagination :pagination="usersPagination">
|
||||||
<template #empty>
|
<template #empty><MkResult type="empty" :text="i18n.ts.noUsers"/></template>
|
||||||
<div class="_fullinfo">
|
|
||||||
<img :src="infoImageUrl" draggable="false"/>
|
|
||||||
<div>{{ i18n.ts.noUsers }}</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #default="{ items }">
|
<template #default="{ items }">
|
||||||
<div class="_gaps_s">
|
<div class="_gaps_s">
|
||||||
|
@ -70,7 +65,6 @@ import MkButton from '@/components/MkButton.vue';
|
||||||
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||||
import MkInfo from '@/components/MkInfo.vue';
|
import MkInfo from '@/components/MkInfo.vue';
|
||||||
import MkPagination from '@/components/MkPagination.vue';
|
import MkPagination from '@/components/MkPagination.vue';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
|
||||||
import { useRouter } from '@/router.js';
|
import { useRouter } from '@/router.js';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
|
@ -27,9 +27,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!fetching && invitations.length == 0" class="_fullinfo">
|
<MkResult v-if="!fetching && invitations.length == 0" type="empty" :text="i18n.ts._chat.noInvitations"/>
|
||||||
<div>{{ i18n.ts._chat.noInvitations }}</div>
|
|
||||||
</div>
|
|
||||||
<MkLoading v-if="fetching"/>
|
<MkLoading v-if="fetching"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -8,9 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div v-if="memberships.length > 0" class="_gaps_s">
|
<div v-if="memberships.length > 0" class="_gaps_s">
|
||||||
<XRoom v-for="membership in memberships" :key="membership.id" :room="membership.room!"/>
|
<XRoom v-for="membership in memberships" :key="membership.id" :room="membership.room!"/>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!fetching && memberships.length == 0" class="_fullinfo">
|
<MkResult v-if="!fetching && memberships.length == 0" type="empty" :text="i18n.ts._chat.noRooms"/>
|
||||||
<div>{{ i18n.ts._chat.noRooms }}</div>
|
|
||||||
</div>
|
|
||||||
<MkLoading v-if="fetching"/>
|
<MkLoading v-if="fetching"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -8,9 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div v-if="rooms.length > 0" class="_gaps_s">
|
<div v-if="rooms.length > 0" class="_gaps_s">
|
||||||
<XRoom v-for="room in rooms" :key="room.id" :room="room"/>
|
<XRoom v-for="room in rooms" :key="room.id" :room="room"/>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!fetching && rooms.length == 0" class="_fullinfo">
|
<MkResult v-if="!fetching && rooms.length == 0" type="empty" :text="i18n.ts._chat.noRooms"/>
|
||||||
<div>{{ i18n.ts._chat.noRooms }}</div>
|
|
||||||
</div>
|
|
||||||
<MkLoading v-if="fetching"/>
|
<MkLoading v-if="fetching"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -24,10 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<XMessage :message="message" :user="message.fromUser" :isSearchResult="true"/>
|
<XMessage :message="message" :user="message.fromUser" :isSearchResult="true"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="_fullinfo">
|
<MkResult v-else type="notFound"/>
|
||||||
<img :src="infoImageUrl" draggable="false"/>
|
|
||||||
<div>{{ i18n.ts.notFound }}</div>
|
|
||||||
</div>
|
|
||||||
</MkFoldableSection>
|
</MkFoldableSection>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -38,7 +35,6 @@ import * as Misskey from 'misskey-js';
|
||||||
import XMessage from './XMessage.vue';
|
import XMessage from './XMessage.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
|
||||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
import MkInput from '@/components/MkInput.vue';
|
import MkInput from '@/components/MkInput.vue';
|
||||||
import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
||||||
|
|
|
@ -68,10 +68,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</MkKeyValue>
|
</MkKeyValue>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="_fullinfo">
|
<MkResult v-else type="empty"/>
|
||||||
<img :src="infoImageUrl" draggable="false"/>
|
|
||||||
<div>{{ i18n.ts.nothing }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -82,7 +79,6 @@ import MkInfo from '@/components/MkInfo.vue';
|
||||||
import MkMediaList from '@/components/MkMediaList.vue';
|
import MkMediaList from '@/components/MkMediaList.vue';
|
||||||
import MkKeyValue from '@/components/MkKeyValue.vue';
|
import MkKeyValue from '@/components/MkKeyValue.vue';
|
||||||
import bytes from '@/filters/bytes.js';
|
import bytes from '@/filters/bytes.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
|
|
|
@ -7,12 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<PageWithHeader>
|
<PageWithHeader>
|
||||||
<div class="_spacer" style="--MI_SPACER-w: 800px;">
|
<div class="_spacer" style="--MI_SPACER-w: 800px;">
|
||||||
<MkPagination :pagination="pagination">
|
<MkPagination :pagination="pagination">
|
||||||
<template #empty>
|
<template #empty><MkResult type="empty" :text="i18n.ts.noNotes"/></template>
|
||||||
<div class="_fullinfo">
|
|
||||||
<img :src="infoImageUrl" draggable="false"/>
|
|
||||||
<div>{{ i18n.ts.noNotes }}</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #default="{ items }">
|
<template #default="{ items }">
|
||||||
<MkDateSeparatedList v-slot="{ item }" :items="items" :direction="'down'" :noGap="false" :ad="false">
|
<MkDateSeparatedList v-slot="{ item }" :items="items" :direction="'down'" :noGap="false" :ad="false">
|
||||||
|
@ -30,7 +25,6 @@ import MkNote from '@/components/MkNote.vue';
|
||||||
import MkDateSeparatedList from '@/components/MkDateSeparatedList.vue';
|
import MkDateSeparatedList from '@/components/MkDateSeparatedList.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
|
||||||
|
|
||||||
const pagination = {
|
const pagination = {
|
||||||
endpoint: 'i/favorites' as const,
|
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">
|
<PageWithHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs" :swipable="true">
|
||||||
<div class="_spacer" style="--MI_SPACER-w: 800px;">
|
<div class="_spacer" style="--MI_SPACER-w: 800px;">
|
||||||
<MkPagination ref="paginationComponent" :pagination="pagination">
|
<MkPagination ref="paginationComponent" :pagination="pagination">
|
||||||
<template #empty>
|
<template #empty><MkResult type="empty" :text="i18n.ts.noFollowRequests"/></template>
|
||||||
<div class="_fullinfo">
|
|
||||||
<img :src="infoImageUrl" draggable="false"/>
|
|
||||||
<div>{{ i18n.ts.noFollowRequests }}</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template #default="{items}">
|
<template #default="{items}">
|
||||||
<div class="mk-follow-requests _gaps">
|
<div class="mk-follow-requests _gaps">
|
||||||
<div v-for="req in items" :key="req.id" class="user _panel">
|
<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 * as os from '@/os.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
|
||||||
import { $i } from '@/i.js';
|
import { $i } from '@/i.js';
|
||||||
|
|
||||||
const paginationComponent = useTemplateRef('paginationComponent');
|
const paginationComponent = useTemplateRef('paginationComponent');
|
||||||
|
|
|
@ -6,13 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template>
|
<template>
|
||||||
<PageWithHeader>
|
<PageWithHeader>
|
||||||
<div v-if="!instance.disableRegistration || !($i && ($i.isAdmin || $i.policies.canInvite))" class="_spacer" style="--MI_SPACER-w: 1200px;">
|
<div v-if="!instance.disableRegistration || !($i && ($i.isAdmin || $i.policies.canInvite))" class="_spacer" style="--MI_SPACER-w: 1200px;">
|
||||||
<div :class="$style.root">
|
<MkResult type="empty"/>
|
||||||
<img :class="$style.img" :src="serverErrorImageUrl" draggable="false"/>
|
|
||||||
<div :class="$style.text">
|
|
||||||
<i class="ti ti-alert-triangle"></i>
|
|
||||||
{{ i18n.ts.nothing }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="_spacer" style="--MI_SPACER-w: 800px;">
|
<div v-else class="_spacer" style="--MI_SPACER-w: 800px;">
|
||||||
<div class="_gaps_m" style="text-align: center;">
|
<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 MkPagination from '@/components/MkPagination.vue';
|
||||||
import MkInviteCode from '@/components/MkInviteCode.vue';
|
import MkInviteCode from '@/components/MkInviteCode.vue';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import { serverErrorImageUrl, instance } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
import { $i } from '@/i.js';
|
import { $i } from '@/i.js';
|
||||||
|
|
||||||
const pagingComponent = useTemplateRef('pagingComponent');
|
const pagingComponent = useTemplateRef('pagingComponent');
|
||||||
|
@ -96,23 +90,3 @@ definePage(() => ({
|
||||||
icon: 'ti ti-user-plus',
|
icon: 'ti ti-user-plus',
|
||||||
}));
|
}));
|
||||||
</script>
|
</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: 16px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -6,13 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template>
|
<template>
|
||||||
<PageWithHeader :actions="headerActions" :tabs="headerTabs">
|
<PageWithHeader :actions="headerActions" :tabs="headerTabs">
|
||||||
<div v-if="error != null" class="_spacer" style="--MI_SPACER-w: 1200px;">
|
<div v-if="error != null" class="_spacer" style="--MI_SPACER-w: 1200px;">
|
||||||
<div :class="$style.root">
|
<MkResult type="error"/>
|
||||||
<img :class="$style.img" :src="serverErrorImageUrl" draggable="false"/>
|
|
||||||
<p :class="$style.text">
|
|
||||||
<i class="ti ti-alert-triangle"></i>
|
|
||||||
{{ i18n.ts.nothing }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="list" class="_spacer" style="--MI_SPACER-w: 700px;">
|
<div v-else-if="list" class="_spacer" style="--MI_SPACER-w: 700px;">
|
||||||
<div v-if="list" class="members _margin">
|
<div v-if="list" class="members _margin">
|
||||||
|
@ -42,7 +36,6 @@ import { i18n } from '@/i18n.js';
|
||||||
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import { serverErrorImageUrl } from '@/instance.js';
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
listId: string;
|
listId: string;
|
||||||
|
|
|
@ -7,12 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<PageWithHeader :actions="headerActions" :tabs="headerTabs">
|
<PageWithHeader :actions="headerActions" :tabs="headerTabs">
|
||||||
<div class="_spacer" style="--MI_SPACER-w: 700px;">
|
<div class="_spacer" style="--MI_SPACER-w: 700px;">
|
||||||
<div>
|
<div>
|
||||||
<div v-if="antennas.length === 0" class="empty">
|
<MkResult v-if="antennas.length === 0" type="empty"/>
|
||||||
<div class="_fullinfo">
|
|
||||||
<img :src="infoImageUrl" draggable="false"/>
|
|
||||||
<div>{{ i18n.ts.nothing }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<MkButton :link="true" to="/my/antennas/create" primary :class="$style.add"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton>
|
<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 { i18n } from '@/i18n.js';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import { antennasCache } from '@/cache.js';
|
import { antennasCache } from '@/cache.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
|
||||||
|
|
||||||
const antennas = computed(() => antennasCache.value.value ?? []);
|
const antennas = computed(() => antennasCache.value.value ?? []);
|
||||||
|
|
||||||
|
|
|
@ -7,12 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<PageWithHeader :actions="headerActions" :tabs="headerTabs">
|
<PageWithHeader :actions="headerActions" :tabs="headerTabs">
|
||||||
<div class="_spacer" style="--MI_SPACER-w: 700px;">
|
<div class="_spacer" style="--MI_SPACER-w: 700px;">
|
||||||
<div class="_gaps">
|
<div class="_gaps">
|
||||||
<div v-if="items.length === 0" class="empty">
|
<MkResult v-if="items.length === 0" type="empty"/>
|
||||||
<div class="_fullinfo">
|
|
||||||
<img :src="infoImageUrl" draggable="false"/>
|
|
||||||
<div>{{ i18n.ts.nothing }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<MkButton primary rounded style="margin: 0 auto;" @click="create"><i class="ti ti-plus"></i> {{ i18n.ts.createList }}</MkButton>
|
<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 { i18n } from '@/i18n.js';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import { userListsCache } from '@/cache.js';
|
import { userListsCache } from '@/cache.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
|
||||||
import { ensureSignin } from '@/i.js';
|
import { ensureSignin } from '@/i.js';
|
||||||
|
|
||||||
const $i = ensureSignin();
|
const $i = ensureSignin();
|
||||||
|
|
|
@ -5,10 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="_fullinfo">
|
<MkResult type="notFound" :text="i18n.ts.notFoundDescription"/>
|
||||||
<img :src="notFoundImageUrl" draggable="false"/>
|
|
||||||
<div>{{ i18n.ts.notFoundDescription }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -17,7 +14,6 @@ import { computed } from 'vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import { pleaseLogin } from '@/utility/please-login.js';
|
import { pleaseLogin } from '@/utility/please-login.js';
|
||||||
import { notFoundImageUrl } from '@/instance.js';
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
showLoginPopup?: boolean;
|
showLoginPopup?: boolean;
|
||||||
|
|
|
@ -6,30 +6,18 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template>
|
<template>
|
||||||
<PageWithHeader v-model:tab="tab" :tabs="headerTabs">
|
<PageWithHeader v-model:tab="tab" :tabs="headerTabs">
|
||||||
<div v-if="error != null" class="_spacer" style="--MI_SPACER-w: 1200px;">
|
<div v-if="error != null" class="_spacer" style="--MI_SPACER-w: 1200px;">
|
||||||
<div :class="$style.root">
|
<MkResult type="error" :text="error"/>
|
||||||
<img :class="$style.img" :src="serverErrorImageUrl" draggable="false"/>
|
|
||||||
<p :class="$style.text">
|
|
||||||
<i class="ti ti-alert-triangle"></i>
|
|
||||||
{{ error }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="tab === 'users'" class="_spacer" style="--MI_SPACER-w: 1200px;">
|
<div v-else-if="tab === 'users'" class="_spacer" style="--MI_SPACER-w: 1200px;">
|
||||||
<div class="_gaps_s">
|
<div class="_gaps_s">
|
||||||
<div v-if="role">{{ role.description }}</div>
|
<div v-if="role">{{ role.description }}</div>
|
||||||
<MkUserList v-if="visible" :pagination="users" :extractor="(item) => item.user"/>
|
<MkUserList v-if="visible" :pagination="users" :extractor="(item) => item.user"/>
|
||||||
<div v-else-if="!visible" class="_fullinfo">
|
<MkResult v-else-if="!visible" type="empty" :text="i18n.ts.nothing"/>
|
||||||
<img :src="infoImageUrl" draggable="false"/>
|
|
||||||
<div>{{ i18n.ts.nothing }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="tab === 'timeline'" class="_spacer" style="--MI_SPACER-w: 700px;">
|
<div v-else-if="tab === 'timeline'" class="_spacer" style="--MI_SPACER-w: 700px;">
|
||||||
<MkTimeline v-if="visible" ref="timeline" src="role" :role="props.roleId"/>
|
<MkTimeline v-if="visible" ref="timeline" src="role" :role="props.roleId"/>
|
||||||
<div v-else-if="!visible" class="_fullinfo">
|
<MkResult v-else-if="!visible" type="empty" :text="i18n.ts.nothing"/>
|
||||||
<img :src="infoImageUrl" draggable="false"/>
|
|
||||||
<div>{{ i18n.ts.nothing }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</PageWithHeader>
|
</PageWithHeader>
|
||||||
</template>
|
</template>
|
||||||
|
@ -37,13 +25,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, watch, ref } from 'vue';
|
import { computed, watch, ref } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { instanceName } from '@@/js/config.js';
|
|
||||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
import MkUserList from '@/components/MkUserList.vue';
|
import MkUserList from '@/components/MkUserList.vue';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import MkTimeline from '@/components/MkTimeline.vue';
|
import MkTimeline from '@/components/MkTimeline.vue';
|
||||||
import { serverErrorImageUrl, infoImageUrl } from '@/instance.js';
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
roleId: string;
|
roleId: string;
|
||||||
|
@ -97,24 +83,3 @@ definePage(() => ({
|
||||||
icon: 'ti ti-badge',
|
icon: 'ti ti-badge',
|
||||||
}));
|
}));
|
||||||
</script>
|
</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: 16px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
|
|
|
@ -6,12 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template>
|
<template>
|
||||||
<div class="_gaps_m">
|
<div class="_gaps_m">
|
||||||
<FormPagination ref="list" :pagination="pagination">
|
<FormPagination ref="list" :pagination="pagination">
|
||||||
<template #empty>
|
<template #empty><MkResult type="empty"/></template>
|
||||||
<div class="_fullinfo">
|
|
||||||
<img :src="infoImageUrl" draggable="false"/>
|
|
||||||
<div>{{ i18n.ts.nothing }}</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template #default="{items}">
|
<template #default="{items}">
|
||||||
<div class="_gaps">
|
<div class="_gaps">
|
||||||
<MkFolder v-for="token in items" :key="token.id" :defaultOpen="true">
|
<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 MkKeyValue from '@/components/MkKeyValue.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import MkFolder from '@/components/MkFolder.vue';
|
import MkFolder from '@/components/MkFolder.vue';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
|
||||||
|
|
||||||
const list = ref<InstanceType<typeof FormPagination>>();
|
const list = ref<InstanceType<typeof FormPagination>>();
|
||||||
|
|
||||||
|
|
|
@ -69,12 +69,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template #label><SearchLabel>{{ i18n.ts.mutedUsers }} ({{ i18n.ts.renote }})</SearchLabel></template>
|
<template #label><SearchLabel>{{ i18n.ts.mutedUsers }} ({{ i18n.ts.renote }})</SearchLabel></template>
|
||||||
|
|
||||||
<MkPagination :pagination="renoteMutingPagination">
|
<MkPagination :pagination="renoteMutingPagination">
|
||||||
<template #empty>
|
<template #empty><MkResult type="empty" :text="i18n.ts.noUsers"/></template>
|
||||||
<div class="_fullinfo">
|
|
||||||
<img :src="infoImageUrl" draggable="false"/>
|
|
||||||
<div>{{ i18n.ts.noUsers }}</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #default="{ items }">
|
<template #default="{ items }">
|
||||||
<div class="_gaps_s">
|
<div class="_gaps_s">
|
||||||
|
@ -105,12 +100,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template #label>{{ i18n.ts.mutedUsers }}</template>
|
<template #label>{{ i18n.ts.mutedUsers }}</template>
|
||||||
|
|
||||||
<MkPagination :pagination="mutingPagination">
|
<MkPagination :pagination="mutingPagination">
|
||||||
<template #empty>
|
<template #empty><MkResult type="empty" :text="i18n.ts.noUsers"/></template>
|
||||||
<div class="_fullinfo">
|
|
||||||
<img :src="infoImageUrl" draggable="false"/>
|
|
||||||
<div>{{ i18n.ts.noUsers }}</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #default="{ items }">
|
<template #default="{ items }">
|
||||||
<div class="_gaps_s">
|
<div class="_gaps_s">
|
||||||
|
@ -143,12 +133,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template #label>{{ i18n.ts.blockedUsers }}</template>
|
<template #label>{{ i18n.ts.blockedUsers }}</template>
|
||||||
|
|
||||||
<MkPagination :pagination="blockingPagination">
|
<MkPagination :pagination="blockingPagination">
|
||||||
<template #empty>
|
<template #empty><MkResult type="empty" :text="i18n.ts.noUsers"/></template>
|
||||||
<div class="_fullinfo">
|
|
||||||
<img :src="infoImageUrl" draggable="false"/>
|
|
||||||
<div>{{ i18n.ts.noUsers }}</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #default="{ items }">
|
<template #default="{ items }">
|
||||||
<div class="_gaps_s">
|
<div class="_gaps_s">
|
||||||
|
@ -186,7 +171,7 @@ import { i18n } from '@/i18n.js';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { instance, infoImageUrl } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
import { ensureSignin } from '@/i.js';
|
import { ensureSignin } from '@/i.js';
|
||||||
import MkInfo from '@/components/MkInfo.vue';
|
import MkInfo from '@/components/MkInfo.vue';
|
||||||
import MkFolder from '@/components/MkFolder.vue';
|
import MkFolder from '@/components/MkFolder.vue';
|
||||||
|
|
|
@ -486,18 +486,6 @@ rt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
._fullinfo {
|
|
||||||
padding: 64px 32px;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
> img {
|
|
||||||
vertical-align: bottom;
|
|
||||||
height: 128px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
border-radius: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
._link {
|
._link {
|
||||||
color: var(--MI_THEME-link);
|
color: var(--MI_THEME-link);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkAvatar v-for="user in users" :key="user.id" :user="user.followee" link preview></MkAvatar>
|
<MkAvatar v-for="user in users" :key="user.id" :user="user.followee" link preview></MkAvatar>
|
||||||
</div>
|
</div>
|
||||||
<div v-else :class="$style.bdayFFallback">
|
<div v-else :class="$style.bdayFFallback">
|
||||||
<img :src="infoImageUrl" draggable="false" :class="$style.bdayFFallbackImage"/>
|
<MkResult type="empty"/>
|
||||||
<div>{{ i18n.ts.nothing }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</MkContainer>
|
</MkContainer>
|
||||||
|
@ -32,7 +31,6 @@ import type { GetFormResultType } from '@/utility/form.js';
|
||||||
import MkContainer from '@/components/MkContainer.vue';
|
import MkContainer from '@/components/MkContainer.vue';
|
||||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
|
||||||
import { $i } from '@/i.js';
|
import { $i } from '@/i.js';
|
||||||
|
|
||||||
const name = i18n.ts._widgets.birthdayFollowings;
|
const name = i18n.ts._widgets.birthdayFollowings;
|
||||||
|
@ -134,12 +132,4 @@ defineExpose<WidgetComponentExpose>({
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bdayFFallbackImage {
|
|
||||||
height: 96px;
|
|
||||||
width: auto;
|
|
||||||
max-width: 90%;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
border-radius: var(--MI-radius);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -11,10 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<div class="ekmkgxbj">
|
<div class="ekmkgxbj">
|
||||||
<MkLoading v-if="fetching"/>
|
<MkLoading v-if="fetching"/>
|
||||||
<div v-else-if="(!items || items.length === 0) && widgetProps.showHeader" class="_fullinfo">
|
<MkResult v-else-if="(!items || items.length === 0) && widgetProps.showHeader" type="empty"/>
|
||||||
<img :src="infoImageUrl" draggable="false"/>
|
|
||||||
<div>{{ i18n.ts.nothing }}</div>
|
|
||||||
</div>
|
|
||||||
<div v-else :class="$style.feed">
|
<div v-else :class="$style.feed">
|
||||||
<a v-for="item in items" :key="item.link" :class="$style.item" :href="item.link" rel="nofollow noopener" target="_blank" :title="item.title">{{ item.title }}</a>
|
<a v-for="item in items" :key="item.link" :class="$style.item" :href="item.link" rel="nofollow noopener" target="_blank" :title="item.title">{{ item.title }}</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -32,7 +29,6 @@ import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps
|
||||||
import type { GetFormResultType } from '@/utility/form.js';
|
import type { GetFormResultType } from '@/utility/form.js';
|
||||||
import MkContainer from '@/components/MkContainer.vue';
|
import MkContainer from '@/components/MkContainer.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
|
||||||
|
|
||||||
const name = 'rss';
|
const name = 'rss';
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue