wip
This commit is contained in:
parent
e7171d9ab2
commit
aab1c76981
|
@ -25,9 +25,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, inject, ref } from 'vue';
|
import { computed, inject, ref } from 'vue';
|
||||||
import { getProxiedImageUrl } from '@/to-be-shared/media-proxy.js';
|
|
||||||
import { customEmojisMap } from '@/custom-emojis.js';
|
import { customEmojisMap } from '@/custom-emojis.js';
|
||||||
|
|
||||||
|
const mediaProxy = inject('mediaProxy');
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
name: string;
|
name: string;
|
||||||
normal?: boolean;
|
normal?: boolean;
|
||||||
|
@ -59,7 +60,7 @@ const url = computed(() => {
|
||||||
const proxied =
|
const proxied =
|
||||||
(rawUrl.value.startsWith('/emoji/') || (props.useOriginalSize && isLocal.value))
|
(rawUrl.value.startsWith('/emoji/') || (props.useOriginalSize && isLocal.value))
|
||||||
? rawUrl.value
|
? rawUrl.value
|
||||||
: getProxiedImageUrl(
|
: mediaProxy.getProxiedImageUrl(
|
||||||
rawUrl.value,
|
rawUrl.value,
|
||||||
props.useOriginalSize ? undefined : 'emoji',
|
props.useOriginalSize ? undefined : 'emoji',
|
||||||
false,
|
false,
|
||||||
|
|
|
@ -11,26 +11,19 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed } from 'vue';
|
import { computed, inject } from 'vue';
|
||||||
import { instanceName } from '@/config.js';
|
|
||||||
import { instance as Instance } from '@/instance.js';
|
const mediaProxy = inject('mediaProxy');
|
||||||
import { getProxiedImageUrlNullable } from '@/to-be-shared/media-proxy.js';
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
instance?: {
|
instance: {
|
||||||
faviconUrl?: string | null
|
faviconUrl?: string | null
|
||||||
name?: string | null
|
name?: string | null
|
||||||
themeColor?: string | null
|
themeColor?: string | null
|
||||||
}
|
}
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
// if no instance data is given, this is for the local instance
|
const faviconUrl = computed(() => mediaProxy.getProxiedImageUrlNullable(props.instance.faviconUrl, 'preview'));
|
||||||
const instance = props.instance ?? {
|
|
||||||
name: instanceName,
|
|
||||||
themeColor: (document.querySelector('meta[name="theme-color-orig"]') as HTMLMetaElement).content,
|
|
||||||
};
|
|
||||||
|
|
||||||
const faviconUrl = computed(() => props.instance ? getProxiedImageUrlNullable(props.instance.faviconUrl, 'preview') : getProxiedImageUrlNullable(Instance.iconUrl, 'preview') ?? '/favicon.ico');
|
|
||||||
|
|
||||||
const themeColor = instance.themeColor ?? '#777777';
|
const themeColor = instance.themeColor ?? '#777777';
|
||||||
|
|
||||||
|
|
|
@ -142,7 +142,7 @@ import { userPage } from '@/utils.js';
|
||||||
import { notePage } from '@/utils.js';
|
import { notePage } from '@/utils.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { shouldCollapsed } from '@/to-be-shared/collapsed.js';
|
import { shouldCollapsed } from '@/to-be-shared/collapsed.js';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/server-metadata.js';
|
||||||
import { url } from '@/config.js';
|
import { url } from '@/config.js';
|
||||||
import EmMfm from '@/components/EmMfm.js';
|
import EmMfm from '@/components/EmMfm.js';
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ import XNotFound from '@/pages/not-found.vue';
|
||||||
import EmTimelineContainer from '@/components/EmTimelineContainer.vue';
|
import EmTimelineContainer from '@/components/EmTimelineContainer.vue';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/server-metadata.js';
|
||||||
import { url, instanceName } from '@/config.js';
|
import { url, instanceName } from '@/config.js';
|
||||||
import { scrollToTop } from '@@/js/scroll.js';
|
import { scrollToTop } from '@@/js/scroll.js';
|
||||||
import { isLink } from '@/scripts/is-link.js';
|
import { isLink } from '@/scripts/is-link.js';
|
||||||
|
|
|
@ -45,7 +45,7 @@ import EmNotes from '@/components/EmNotes.vue';
|
||||||
import XNotFound from '@/pages/not-found.vue';
|
import XNotFound from '@/pages/not-found.vue';
|
||||||
import EmTimelineContainer from '@/components/EmTimelineContainer.vue';
|
import EmTimelineContainer from '@/components/EmTimelineContainer.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/server-metadata.js';
|
||||||
import { url, instanceName } from '@/config.js';
|
import { url, instanceName } from '@/config.js';
|
||||||
import { scrollToTop } from '@@/js/scroll.js';
|
import { scrollToTop } from '@@/js/scroll.js';
|
||||||
import { isLink } from '@/scripts/is-link.js';
|
import { isLink } from '@/scripts/is-link.js';
|
||||||
|
|
|
@ -62,7 +62,7 @@ import XNotFound from '@/pages/not-found.vue';
|
||||||
import EmTimelineContainer from '@/components/EmTimelineContainer.vue';
|
import EmTimelineContainer from '@/components/EmTimelineContainer.vue';
|
||||||
import { misskeyApi } from '@/misskey-api.js';
|
import { misskeyApi } from '@/misskey-api.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/server-metadata.js';
|
||||||
import { url, instanceName } from '@/config.js';
|
import { url, instanceName } from '@/config.js';
|
||||||
import { defaultEmbedParams } from '@/embed-page.js';
|
import { defaultEmbedParams } from '@/embed-page.js';
|
||||||
|
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { query } from '@@/js/url.js';
|
|
||||||
import { url } from '@/config.js';
|
|
||||||
import { instance } from '@/instance.js';
|
|
||||||
|
|
||||||
export function getProxiedImageUrl(imageUrl: string, type?: 'preview' | 'emoji' | 'avatar', mustOrigin = false, noFallback = false): string {
|
|
||||||
const localProxy = `${url}/proxy`;
|
|
||||||
|
|
||||||
if (imageUrl.startsWith(instance.mediaProxy + '/') || imageUrl.startsWith('/proxy/') || imageUrl.startsWith(localProxy + '/')) {
|
|
||||||
// もう既にproxyっぽそうだったらurlを取り出す
|
|
||||||
imageUrl = (new URL(imageUrl)).searchParams.get('url') ?? imageUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${mustOrigin ? localProxy : instance.mediaProxy}/${
|
|
||||||
type === 'preview' ? 'preview.webp'
|
|
||||||
: 'image.webp'
|
|
||||||
}?${query({
|
|
||||||
url: imageUrl,
|
|
||||||
...(!noFallback ? { 'fallback': '1' } : {}),
|
|
||||||
...(type ? { [type]: '1' } : {}),
|
|
||||||
...(mustOrigin ? { origin: '1' } : {}),
|
|
||||||
})}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getProxiedImageUrlNullable(imageUrl: string | null | undefined, type?: 'preview'): string | null {
|
|
||||||
if (imageUrl == null) return null;
|
|
||||||
return getProxiedImageUrl(imageUrl, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getStaticImageUrl(baseUrl: string): string {
|
|
||||||
const u = baseUrl.startsWith('http') ? new URL(baseUrl) : new URL(baseUrl, url);
|
|
||||||
|
|
||||||
if (u.href.startsWith(`${url}/emoji/`)) {
|
|
||||||
// もう既にemojiっぽそうだったらsearchParams付けるだけ
|
|
||||||
u.searchParams.set('static', '1');
|
|
||||||
return u.href;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (u.href.startsWith(instance.mediaProxy + '/')) {
|
|
||||||
// もう既にproxyっぽそうだったらsearchParams付けるだけ
|
|
||||||
u.searchParams.set('static', '1');
|
|
||||||
return u.href;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${instance.mediaProxy}/static.webp?${query({
|
|
||||||
url: u.href,
|
|
||||||
static: '1',
|
|
||||||
})}`;
|
|
||||||
}
|
|
|
@ -106,10 +106,6 @@ export const ROLE_POLICIES = [
|
||||||
export const CURRENT_STICKY_TOP = 'CURRENT_STICKY_TOP';
|
export const CURRENT_STICKY_TOP = 'CURRENT_STICKY_TOP';
|
||||||
export const CURRENT_STICKY_BOTTOM = 'CURRENT_STICKY_BOTTOM';
|
export const CURRENT_STICKY_BOTTOM = 'CURRENT_STICKY_BOTTOM';
|
||||||
|
|
||||||
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='],
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { query } from '@@/js/url.js';
|
||||||
|
import * as Misskey from 'misskey-js';
|
||||||
|
|
||||||
|
export class MediaProxy {
|
||||||
|
private serverMetadata: Misskey.entities.MetaDetailed;
|
||||||
|
private url: string;
|
||||||
|
|
||||||
|
constructor(serverMetadata: Misskey.entities.MetaDetailed, url: string) {
|
||||||
|
this.serverMetadata = serverMetadata;
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getProxiedImageUrl(imageUrl: string, type?: 'preview' | 'emoji' | 'avatar', mustOrigin = false, noFallback = false): string {
|
||||||
|
const localProxy = `${this.url}/proxy`;
|
||||||
|
|
||||||
|
if (imageUrl.startsWith(this.serverMetadata.mediaProxy + '/') || imageUrl.startsWith('/proxy/') || imageUrl.startsWith(localProxy + '/')) {
|
||||||
|
// もう既にproxyっぽそうだったらurlを取り出す
|
||||||
|
imageUrl = (new URL(imageUrl)).searchParams.get('url') ?? imageUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${mustOrigin ? localProxy : this.serverMetadata.mediaProxy}/${
|
||||||
|
type === 'preview' ? 'preview.webp'
|
||||||
|
: 'image.webp'
|
||||||
|
}?${query({
|
||||||
|
url: imageUrl,
|
||||||
|
...(!noFallback ? { 'fallback': '1' } : {}),
|
||||||
|
...(type ? { [type]: '1' } : {}),
|
||||||
|
...(mustOrigin ? { origin: '1' } : {}),
|
||||||
|
})}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getProxiedImageUrlNullable(imageUrl: string | null | undefined, type?: 'preview'): string | null {
|
||||||
|
if (imageUrl == null) return null;
|
||||||
|
return this.getProxiedImageUrl(imageUrl, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getStaticImageUrl(baseUrl: string): string {
|
||||||
|
const u = baseUrl.startsWith('http') ? new URL(baseUrl) : new URL(baseUrl, this.url);
|
||||||
|
|
||||||
|
if (u.href.startsWith(`${this.url}/emoji/`)) {
|
||||||
|
// もう既にemojiっぽそうだったらsearchParams付けるだけ
|
||||||
|
u.searchParams.set('static', '1');
|
||||||
|
return u.href;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (u.href.startsWith(this.serverMetadata.mediaProxy + '/')) {
|
||||||
|
// もう既にproxyっぽそうだったらsearchParams付けるだけ
|
||||||
|
u.searchParams.set('static', '1');
|
||||||
|
return u.href;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${this.serverMetadata.mediaProxy}/static.webp?${query({
|
||||||
|
url: u.href,
|
||||||
|
static: '1',
|
||||||
|
})}`;
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,16 +5,17 @@
|
||||||
|
|
||||||
import { computed, watch, version as vueVersion, App } from 'vue';
|
import { computed, watch, version as vueVersion, App } from 'vue';
|
||||||
import { compareVersions } from 'compare-versions';
|
import { compareVersions } from 'compare-versions';
|
||||||
|
import { MediaProxy } from '@@/js/media-proxy.js';
|
||||||
import widgets from '@/widgets/index.js';
|
import widgets from '@/widgets/index.js';
|
||||||
import directives from '@/directives/index.js';
|
import directives from '@/directives/index.js';
|
||||||
import components from '@/components/index.js';
|
import components from '@/components/index.js';
|
||||||
import { version, lang, updateLocale, locale } from '@/config.js';
|
import { version, lang, updateLocale, locale, url } from '@/config.js';
|
||||||
import { applyTheme } from '@/scripts/theme.js';
|
import { applyTheme } from '@/scripts/theme.js';
|
||||||
import { isDeviceDarkmode } from '@/scripts/is-device-darkmode.js';
|
import { isDeviceDarkmode } from '@/scripts/is-device-darkmode.js';
|
||||||
import { updateI18n } from '@/i18n.js';
|
import { updateI18n } from '@/i18n.js';
|
||||||
import { $i, refreshAccount, login } from '@/account.js';
|
import { $i, refreshAccount, login } from '@/account.js';
|
||||||
import { defaultStore, ColdDeviceStorage } from '@/store.js';
|
import { defaultStore, ColdDeviceStorage } from '@/store.js';
|
||||||
import { fetchInstance, instance } from '@/instance.js';
|
import { fetchServerMetadata } from '@/server-metadata.js';
|
||||||
import { deviceKind } from '@/scripts/device-kind.js';
|
import { deviceKind } from '@/scripts/device-kind.js';
|
||||||
import { reloadChannel } from '@/scripts/unison-reload.js';
|
import { reloadChannel } from '@/scripts/unison-reload.js';
|
||||||
import { getUrlWithoutLoginId } from '@/scripts/login-id.js';
|
import { getUrlWithoutLoginId } from '@/scripts/login-id.js';
|
||||||
|
@ -119,11 +120,7 @@ export async function common(createVue: () => App<Element>) {
|
||||||
await defaultStore.ready;
|
await defaultStore.ready;
|
||||||
await deckStore.ready;
|
await deckStore.ready;
|
||||||
|
|
||||||
const fetchInstanceMetaPromise = fetchInstance();
|
const serverMetadata = await fetchServerMetadata();
|
||||||
|
|
||||||
fetchInstanceMetaPromise.then(() => {
|
|
||||||
miLocalStorage.setItem('v', instance.version);
|
|
||||||
});
|
|
||||||
|
|
||||||
//#region loginId
|
//#region loginId
|
||||||
const params = new URLSearchParams(location.search);
|
const params = new URLSearchParams(location.search);
|
||||||
|
@ -178,19 +175,17 @@ export async function common(createVue: () => App<Element>) {
|
||||||
});
|
});
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
fetchInstanceMetaPromise.then(() => {
|
if (defaultStore.state.themeInitial) {
|
||||||
if (defaultStore.state.themeInitial) {
|
if (serverMetadata.defaultLightTheme != null) ColdDeviceStorage.set('lightTheme', JSON.parse(serverMetadata.defaultLightTheme));
|
||||||
if (instance.defaultLightTheme != null) ColdDeviceStorage.set('lightTheme', JSON.parse(instance.defaultLightTheme));
|
if (serverMetadata.defaultDarkTheme != null) ColdDeviceStorage.set('darkTheme', JSON.parse(serverMetadata.defaultDarkTheme));
|
||||||
if (instance.defaultDarkTheme != null) ColdDeviceStorage.set('darkTheme', JSON.parse(instance.defaultDarkTheme));
|
defaultStore.set('themeInitial', false);
|
||||||
defaultStore.set('themeInitial', false);
|
} else {
|
||||||
|
if (defaultStore.state.darkMode) {
|
||||||
|
applyTheme(darkTheme.value);
|
||||||
} else {
|
} else {
|
||||||
if (defaultStore.state.darkMode) {
|
applyTheme(lightTheme.value);
|
||||||
applyTheme(darkTheme.value);
|
|
||||||
} else {
|
|
||||||
applyTheme(lightTheme.value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
watch(defaultStore.reactiveState.useBlurEffectForModal, v => {
|
watch(defaultStore.reactiveState.useBlurEffectForModal, v => {
|
||||||
document.documentElement.style.setProperty('--modalBgFilter', v ? 'blur(4px)' : 'none');
|
document.documentElement.style.setProperty('--modalBgFilter', v ? 'blur(4px)' : 'none');
|
||||||
|
@ -239,6 +234,8 @@ export async function common(createVue: () => App<Element>) {
|
||||||
} catch (err) { /* empty */ }
|
} catch (err) { /* empty */ }
|
||||||
|
|
||||||
const app = createVue();
|
const app = createVue();
|
||||||
|
app.provide('serverMetadata', serverMetadata);
|
||||||
|
app.provide('mediaProxy', new MediaProxy(serverMetadata, url));
|
||||||
|
|
||||||
setupRouter(app, createMainRouter);
|
setupRouter(app, createMainRouter);
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@ import { alert, confirm, popup, post, toast } from '@/os.js';
|
||||||
import { useStream } from '@/stream.js';
|
import { useStream } from '@/stream.js';
|
||||||
import * as sound from '@/scripts/sound.js';
|
import * as sound from '@/scripts/sound.js';
|
||||||
import { $i, signout, updateAccount } from '@/account.js';
|
import { $i, signout, updateAccount } from '@/account.js';
|
||||||
import { instance } from '@/instance.js';
|
|
||||||
import { ColdDeviceStorage, defaultStore } from '@/store.js';
|
import { ColdDeviceStorage, defaultStore } from '@/store.js';
|
||||||
import { reactionPicker } from '@/scripts/reaction-picker.js';
|
import { reactionPicker } from '@/scripts/reaction-picker.js';
|
||||||
import { miLocalStorage } from '@/local-storage.js';
|
import { miLocalStorage } from '@/local-storage.js';
|
||||||
|
@ -23,6 +22,7 @@ import { emojiPicker } from '@/scripts/emoji-picker.js';
|
||||||
import { mainRouter } from '@/router/main.js';
|
import { mainRouter } from '@/router/main.js';
|
||||||
import { type Keymap, makeHotkey } from '@/scripts/hotkey.js';
|
import { type Keymap, makeHotkey } from '@/scripts/hotkey.js';
|
||||||
import { addCustomEmoji, removeCustomEmojis, updateCustomEmojis } from '@/custom-emojis.js';
|
import { addCustomEmoji, removeCustomEmojis, updateCustomEmojis } from '@/custom-emojis.js';
|
||||||
|
import { fetchServerMetadata } from '@/server-metadata.js';
|
||||||
|
|
||||||
export async function mainBoot() {
|
export async function mainBoot() {
|
||||||
const { isClientUpdated } = await common(() => createApp(
|
const { isClientUpdated } = await common(() => createApp(
|
||||||
|
@ -267,8 +267,9 @@ export async function mainBoot() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const serverMetadata = await fetchServerMetadata();
|
||||||
const modifiedVersionMustProminentlyOfferInAgplV3Section13Read = miLocalStorage.getItem('modifiedVersionMustProminentlyOfferInAgplV3Section13Read');
|
const modifiedVersionMustProminentlyOfferInAgplV3Section13Read = miLocalStorage.getItem('modifiedVersionMustProminentlyOfferInAgplV3Section13Read');
|
||||||
if (modifiedVersionMustProminentlyOfferInAgplV3Section13Read !== 'true' && instance.repositoryUrl !== 'https://github.com/misskey-dev/misskey') {
|
if (modifiedVersionMustProminentlyOfferInAgplV3Section13Read !== 'true' && serverMetadata.repositoryUrl !== 'https://github.com/misskey-dev/misskey') {
|
||||||
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkSourceCodeAvailablePopup.vue')), {}, {
|
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkSourceCodeAvailablePopup.vue')), {}, {
|
||||||
closed: () => dispose(),
|
closed: () => dispose(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkPagination :pagination="pagination">
|
<MkPagination :pagination="pagination">
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img :src="infoImageUrl" class="_ghost"/>
|
<img v-if="serverMetadata.infoImageUrl" :src="serverMetadata.infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.notFound }}</div>
|
<div>{{ i18n.ts.notFound }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -19,10 +19,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { inject } from 'vue';
|
||||||
import MkChannelPreview from '@/components/MkChannelPreview.vue';
|
import MkChannelPreview from '@/components/MkChannelPreview.vue';
|
||||||
import MkPagination, { Paging } from '@/components/MkPagination.vue';
|
import MkPagination, { Paging } from '@/components/MkPagination.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
pagination: Paging;
|
pagination: Paging;
|
||||||
|
|
|
@ -31,7 +31,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, shallowRef, ref } from 'vue';
|
import { onMounted, shallowRef, ref, inject } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import Cropper from 'cropperjs';
|
import Cropper from 'cropperjs';
|
||||||
import tinycolor from 'tinycolor2';
|
import tinycolor from 'tinycolor2';
|
||||||
|
@ -41,7 +41,8 @@ import { $i } from '@/account.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
import { apiUrl } from '@/config.js';
|
import { apiUrl } from '@/config.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { getProxiedImageUrl } from '@/scripts/media-proxy.js';
|
|
||||||
|
const mediaProxy = inject('mediaProxy');
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: 'ok', cropped: Misskey.entities.DriveFile): void;
|
(ev: 'ok', cropped: Misskey.entities.DriveFile): void;
|
||||||
|
@ -55,7 +56,7 @@ const props = defineProps<{
|
||||||
uploadFolder?: string | null;
|
uploadFolder?: string | null;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const imgUrl = getProxiedImageUrl(props.file.url, undefined, true);
|
const imgUrl = mediaProxy.getProxiedImageUrl(props.file.url, undefined, true);
|
||||||
const dialogEl = shallowRef<InstanceType<typeof MkModalWindow>>();
|
const dialogEl = shallowRef<InstanceType<typeof MkModalWindow>>();
|
||||||
const imgEl = shallowRef<HTMLImageElement>();
|
const imgEl = shallowRef<HTMLImageElement>();
|
||||||
let cropper: Cropper | null = null;
|
let cropper: Cropper | null = null;
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { action } from '@storybook/addon-actions';
|
||||||
import { StoryObj } from '@storybook/vue3';
|
import { StoryObj } from '@storybook/vue3';
|
||||||
import { onBeforeUnmount } from 'vue';
|
import { onBeforeUnmount } from 'vue';
|
||||||
import MkDonation from './MkDonation.vue';
|
import MkDonation from './MkDonation.vue';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/server-metadata.js';
|
||||||
export const Default = {
|
export const Default = {
|
||||||
render(args) {
|
render(args) {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div :class="$style.text">
|
<div :class="$style.text">
|
||||||
<I18n :src="i18n.ts.pleaseDonate" tag="span">
|
<I18n :src="i18n.ts.pleaseDonate" tag="span">
|
||||||
<template #host>
|
<template #host>
|
||||||
{{ instance.name ?? host }}
|
{{ serverMetadata.name ?? host }}
|
||||||
</template>
|
</template>
|
||||||
</I18n>
|
</I18n>
|
||||||
<div style="margin-top: 0.2em;">
|
<div style="margin-top: 0.2em;">
|
||||||
|
@ -36,13 +36,15 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { inject } from 'vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import MkLink from '@/components/MkLink.vue';
|
import MkLink from '@/components/MkLink.vue';
|
||||||
import { host } from '@/config.js';
|
import { host } from '@/config.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { miLocalStorage } from '@/local-storage.js';
|
import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { instance } from '@/instance.js';
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: 'closed'): void;
|
(ev: 'closed'): void;
|
||||||
|
|
|
@ -4,11 +4,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="instance" :class="$style.root" :style="{ backgroundImage: `url(${ instance.backgroundImageUrl })` }"></div>
|
<div :class="$style.root" :style="{ backgroundImage: `url(${ serverMetadata.backgroundImageUrl })` }"></div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { instance } from '@/instance.js';
|
import { inject } from 'vue';
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" module>
|
<style lang="scss" module>
|
||||||
|
|
|
@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template #header>{{ i18n.ts.forgotPassword }}</template>
|
<template #header>{{ i18n.ts.forgotPassword }}</template>
|
||||||
|
|
||||||
<MkSpacer :marginMin="20" :marginMax="28">
|
<MkSpacer :marginMin="20" :marginMax="28">
|
||||||
<form v-if="instance.enableEmail" @submit.prevent="onSubmit">
|
<form v-if="serverMetadata.enableEmail" @submit.prevent="onSubmit">
|
||||||
<div class="_gaps_m">
|
<div class="_gaps_m">
|
||||||
<MkInput v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" :spellcheck="false" autofocus required>
|
<MkInput v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" :spellcheck="false" autofocus required>
|
||||||
<template #label>{{ i18n.ts.username }}</template>
|
<template #label>{{ i18n.ts.username }}</template>
|
||||||
|
@ -39,15 +39,16 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue';
|
import { inject, ref } from 'vue';
|
||||||
import MkModalWindow from '@/components/MkModalWindow.vue';
|
import MkModalWindow from '@/components/MkModalWindow.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import MkInput from '@/components/MkInput.vue';
|
import MkInput from '@/components/MkInput.vue';
|
||||||
import MkInfo from '@/components/MkInfo.vue';
|
import MkInfo from '@/components/MkInfo.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { instance } from '@/instance.js';
|
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: 'done'): void;
|
(ev: 'done'): void;
|
||||||
(ev: 'closed'): void;
|
(ev: 'closed'): void;
|
||||||
|
|
|
@ -63,7 +63,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="_fullinfo">
|
<div v-else class="_fullinfo">
|
||||||
<img :src="infoImageUrl" class="_ghost"/>
|
<img v-if="serverMetadata.infoImageUrl" :src="serverMetadata.infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.nothing }}</div>
|
<div>{{ i18n.ts.nothing }}</div>
|
||||||
</div>
|
</div>
|
||||||
</MkSpacer>
|
</MkSpacer>
|
||||||
|
@ -72,6 +72,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { reactive, shallowRef } from 'vue';
|
import { reactive, shallowRef } from 'vue';
|
||||||
|
import { inject } from 'vue';
|
||||||
import MkInput from './MkInput.vue';
|
import MkInput from './MkInput.vue';
|
||||||
import MkTextarea from './MkTextarea.vue';
|
import MkTextarea from './MkTextarea.vue';
|
||||||
import MkSwitch from './MkSwitch.vue';
|
import MkSwitch from './MkSwitch.vue';
|
||||||
|
@ -83,7 +84,7 @@ import XFile from './MkFormDialog.file.vue';
|
||||||
import type { Form } from '@/scripts/form.js';
|
import type { Form } from '@/scripts/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 serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
title: string;
|
title: string;
|
||||||
|
|
|
@ -15,11 +15,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue';
|
import { inject, ref } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import MkMiniChart from '@/components/MkMiniChart.vue';
|
import MkMiniChart from '@/components/MkMiniChart.vue';
|
||||||
import { misskeyApiGet } from '@/scripts/misskey-api.js';
|
import { misskeyApiGet } from '@/scripts/misskey-api.js';
|
||||||
import { getProxiedImageUrlNullable } from '@/scripts/media-proxy.js';
|
|
||||||
|
const mediaProxy = inject('mediaProxy');
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
instance: Misskey.entities.FederationInstance;
|
instance: Misskey.entities.FederationInstance;
|
||||||
|
@ -34,7 +35,7 @@ misskeyApiGet('charts/instance', { host: props.instance.host, limit: 16 + 1, spa
|
||||||
});
|
});
|
||||||
|
|
||||||
function getInstanceIcon(instance): string {
|
function getInstanceIcon(instance): string {
|
||||||
return getProxiedImageUrlNullable(instance.iconUrl, 'preview') ?? getProxiedImageUrlNullable(instance.faviconUrl, 'preview') ?? '/client-assets/dummy.png';
|
return mediaProxy.getProxiedImageUrlNullable(instance.iconUrl, 'preview') ?? mediaProxy.getProxiedImageUrlNullable(instance.faviconUrl, 'preview') ?? '/client-assets/dummy.png';
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed } from 'vue';
|
import { computed, inject } from 'vue';
|
||||||
import { instanceName } from '@/config.js';
|
import { instanceName } from '@/config.js';
|
||||||
import { instance as Instance } from '@/instance.js';
|
|
||||||
import { getProxiedImageUrlNullable } from '@/scripts/media-proxy.js';
|
const mediaProxy = inject('mediaProxy');
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
instance?: {
|
instance?: {
|
||||||
|
@ -30,7 +30,7 @@ const instance = props.instance ?? {
|
||||||
themeColor: (document.querySelector('meta[name="theme-color-orig"]') as HTMLMetaElement).content,
|
themeColor: (document.querySelector('meta[name="theme-color-orig"]') as HTMLMetaElement).content,
|
||||||
};
|
};
|
||||||
|
|
||||||
const faviconUrl = computed(() => props.instance ? getProxiedImageUrlNullable(props.instance.faviconUrl, 'preview') : getProxiedImageUrlNullable(Instance.iconUrl, 'preview') ?? '/favicon.ico');
|
const faviconUrl = computed(() => props.instance ? mediaProxy.getProxiedImageUrlNullable(props.instance.faviconUrl, 'preview') : mediaProxy.getProxiedImageUrlNullable(Instance.iconUrl, 'preview') ?? '/favicon.ico');
|
||||||
|
|
||||||
const themeColor = instance.themeColor ?? '#777777';
|
const themeColor = instance.themeColor ?? '#777777';
|
||||||
|
|
||||||
|
|
|
@ -15,13 +15,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineAsyncComponent, ref } from 'vue';
|
import { defineAsyncComponent, inject, ref } from 'vue';
|
||||||
import { url as local } from '@/config.js';
|
import { url as local } from '@/config.js';
|
||||||
import { useTooltip } from '@/scripts/use-tooltip.js';
|
import { useTooltip } from '@/scripts/use-tooltip.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { isEnabledUrlPreview } from '@/instance.js';
|
|
||||||
import { MkABehavior } from '@/components/global/MkA.vue';
|
import { MkABehavior } from '@/components/global/MkA.vue';
|
||||||
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
url: string;
|
url: string;
|
||||||
rel?: null | string;
|
rel?: null | string;
|
||||||
|
@ -35,7 +36,7 @@ const target = self ? null : '_blank';
|
||||||
|
|
||||||
const el = ref<HTMLElement | { $el: HTMLElement }>();
|
const el = ref<HTMLElement | { $el: HTMLElement }>();
|
||||||
|
|
||||||
if (isEnabledUrlPreview.value) {
|
if (serverMetadata.enableUrlPreview) {
|
||||||
useTooltip(el, (showing) => {
|
useTooltip(el, (showing) => {
|
||||||
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkUrlPreviewPopup.vue')), {
|
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkUrlPreviewPopup.vue')), {
|
||||||
showing,
|
showing,
|
||||||
|
|
|
@ -51,9 +51,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { watch, ref, computed } from 'vue';
|
import { watch, ref, computed, inject } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { getStaticImageUrl } from '@/scripts/media-proxy.js';
|
|
||||||
import bytes from '@/filters/bytes.js';
|
import bytes from '@/filters/bytes.js';
|
||||||
import ImgWithBlurhash from '@/components/MkImgWithBlurhash.vue';
|
import ImgWithBlurhash from '@/components/MkImgWithBlurhash.vue';
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
|
@ -61,6 +60,8 @@ import { i18n } from '@/i18n.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { $i, iAmModerator } from '@/account.js';
|
import { $i, iAmModerator } from '@/account.js';
|
||||||
|
|
||||||
|
const mediaProxy = inject('mediaProxy');
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
image: Misskey.entities.DriveFile;
|
image: Misskey.entities.DriveFile;
|
||||||
raw?: boolean;
|
raw?: boolean;
|
||||||
|
@ -79,7 +80,7 @@ const darkMode = ref<boolean>(defaultStore.state.darkMode);
|
||||||
const url = computed(() => (props.raw || defaultStore.state.loadRawImages)
|
const url = computed(() => (props.raw || defaultStore.state.loadRawImages)
|
||||||
? props.image.url
|
? props.image.url
|
||||||
: defaultStore.state.disableShowingAnimatedImages
|
: defaultStore.state.disableShowingAnimatedImages
|
||||||
? getStaticImageUrl(props.image.url)
|
? mediaProxy.getStaticImageUrl(props.image.url)
|
||||||
: props.image.thumbnailUrl,
|
: props.image.thumbnailUrl,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -15,14 +15,15 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { toUnicode } from 'punycode';
|
import { toUnicode } from 'punycode';
|
||||||
import { computed } from 'vue';
|
import { computed, inject } from 'vue';
|
||||||
import tinycolor from 'tinycolor2';
|
import tinycolor from 'tinycolor2';
|
||||||
import { host as localHost } from '@/config.js';
|
import { host as localHost } from '@/config.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
import { getStaticImageUrl } from '@/scripts/media-proxy.js';
|
|
||||||
import { MkABehavior } from '@/components/global/MkA.vue';
|
import { MkABehavior } from '@/components/global/MkA.vue';
|
||||||
|
|
||||||
|
const mediaProxy = inject('mediaProxy');
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
username: string;
|
username: string;
|
||||||
host: string;
|
host: string;
|
||||||
|
@ -42,7 +43,7 @@ bg.setAlpha(0.1);
|
||||||
const bgCss = bg.toRgbString();
|
const bgCss = bg.toRgbString();
|
||||||
|
|
||||||
const avatarUrl = computed(() => defaultStore.state.disableShowingAnimatedImages
|
const avatarUrl = computed(() => defaultStore.state.disableShowingAnimatedImages
|
||||||
? getStaticImageUrl(`/avatar/@${props.username}@${props.host}`)
|
? mediaProxy.getStaticImageUrl(`/avatar/@${props.username}@${props.host}`)
|
||||||
: `/avatar/@${props.username}@${props.host}`,
|
: `/avatar/@${props.username}@${props.host}`,
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -82,7 +82,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkMediaList ref="galleryEl" :mediaList="appearNote.files"/>
|
<MkMediaList ref="galleryEl" :mediaList="appearNote.files"/>
|
||||||
</div>
|
</div>
|
||||||
<MkPoll v-if="appearNote.poll" :noteId="appearNote.id" :poll="appearNote.poll" :class="$style.poll"/>
|
<MkPoll v-if="appearNote.poll" :noteId="appearNote.id" :poll="appearNote.poll" :class="$style.poll"/>
|
||||||
<div v-if="isEnabledUrlPreview">
|
<div v-if="serverMetadata.enableUrlPreview">
|
||||||
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" :class="$style.urlPreview"/>
|
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" :class="$style.urlPreview"/>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="appearNote.renote" :class="$style.quote"><MkNoteSimple :note="appearNote.renote" :class="$style.quoteNote"/></div>
|
<div v-if="appearNote.renote" :class="$style.quote"><MkNoteSimple :note="appearNote.renote" :class="$style.quoteNote"/></div>
|
||||||
|
@ -197,11 +197,12 @@ import MkRippleEffect from '@/components/MkRippleEffect.vue';
|
||||||
import { showMovedDialog } from '@/scripts/show-moved-dialog.js';
|
import { showMovedDialog } from '@/scripts/show-moved-dialog.js';
|
||||||
import { shouldCollapsed } from '@/scripts/collapsed.js';
|
import { shouldCollapsed } from '@/scripts/collapsed.js';
|
||||||
import { host } from '@/config.js';
|
import { host } from '@/config.js';
|
||||||
import { isEnabledUrlPreview } from '@/instance.js';
|
|
||||||
import { type Keymap } from '@/scripts/hotkey.js';
|
import { type Keymap } from '@/scripts/hotkey.js';
|
||||||
import { focusPrev, focusNext } from '@/scripts/focus.js';
|
import { focusPrev, focusNext } from '@/scripts/focus.js';
|
||||||
import { getAppearNote } from '@/scripts/get-appear-note.js';
|
import { getAppearNote } from '@/scripts/get-appear-note.js';
|
||||||
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
note: Misskey.entities.Note;
|
note: Misskey.entities.Note;
|
||||||
pinned?: boolean;
|
pinned?: boolean;
|
||||||
|
@ -523,7 +524,7 @@ function onContextmenu(ev: MouseEvent): void {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
react();
|
react();
|
||||||
} else {
|
} else {
|
||||||
const { menu, cleanup } = getNoteMenu({ note: note.value, translating, translation, isDeleted, currentClip: currentClip?.value });
|
const { menu, cleanup } = getNoteMenu({ serverMetadata }, { note: note.value, translating, translation, isDeleted, currentClip: currentClip?.value });
|
||||||
os.contextMenu(menu, ev).then(focus).finally(cleanup);
|
os.contextMenu(menu, ev).then(focus).finally(cleanup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -533,7 +534,7 @@ function showMenu(): void {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { menu, cleanup } = getNoteMenu({ note: note.value, translating, translation, isDeleted, currentClip: currentClip?.value });
|
const { menu, cleanup } = getNoteMenu({ serverMetadata }, { note: note.value, translating, translation, isDeleted, currentClip: currentClip?.value });
|
||||||
os.popupMenu(menu, menuButton.value).then(focus).finally(cleanup);
|
os.popupMenu(menu, menuButton.value).then(focus).finally(cleanup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkMediaList ref="galleryEl" :mediaList="appearNote.files"/>
|
<MkMediaList ref="galleryEl" :mediaList="appearNote.files"/>
|
||||||
</div>
|
</div>
|
||||||
<MkPoll v-if="appearNote.poll" ref="pollViewer" :noteId="appearNote.id" :poll="appearNote.poll" :class="$style.poll"/>
|
<MkPoll v-if="appearNote.poll" ref="pollViewer" :noteId="appearNote.id" :poll="appearNote.poll" :class="$style.poll"/>
|
||||||
<div v-if="isEnabledUrlPreview">
|
<div v-if="serverMetadata.enableUrlPreview">
|
||||||
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="true" style="margin-top: 6px;"/>
|
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="true" style="margin-top: 6px;"/>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="appearNote.renote" :class="$style.quote"><MkNoteSimple :note="appearNote.renote" :class="$style.quoteNote"/></div>
|
<div v-if="appearNote.renote" :class="$style.quote"><MkNoteSimple :note="appearNote.renote" :class="$style.quoteNote"/></div>
|
||||||
|
@ -234,10 +234,11 @@ import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||||
import MkPagination, { type Paging } from '@/components/MkPagination.vue';
|
import MkPagination, { type Paging } from '@/components/MkPagination.vue';
|
||||||
import MkReactionIcon from '@/components/MkReactionIcon.vue';
|
import MkReactionIcon from '@/components/MkReactionIcon.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import { isEnabledUrlPreview } from '@/instance.js';
|
|
||||||
import { getAppearNote } from '@/scripts/get-appear-note.js';
|
import { getAppearNote } from '@/scripts/get-appear-note.js';
|
||||||
import { type Keymap } from '@/scripts/hotkey.js';
|
import { type Keymap } from '@/scripts/hotkey.js';
|
||||||
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
note: Misskey.entities.Note;
|
note: Misskey.entities.Note;
|
||||||
initialTab: string;
|
initialTab: string;
|
||||||
|
@ -483,13 +484,13 @@ function onContextmenu(ev: MouseEvent): void {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
react();
|
react();
|
||||||
} else {
|
} else {
|
||||||
const { menu, cleanup } = getNoteMenu({ note: note.value, translating, translation, isDeleted });
|
const { menu, cleanup } = getNoteMenu({ serverMetadata }, { note: note.value, translating, translation, isDeleted });
|
||||||
os.contextMenu(menu, ev).then(focus).finally(cleanup);
|
os.contextMenu(menu, ev).then(focus).finally(cleanup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showMenu(): void {
|
function showMenu(): void {
|
||||||
const { menu, cleanup } = getNoteMenu({ note: note.value, translating, translation, isDeleted });
|
const { menu, cleanup } = getNoteMenu({ serverMetadata }, { note: note.value, translating, translation, isDeleted });
|
||||||
os.popupMenu(menu, menuButton.value).then(focus).finally(cleanup);
|
os.popupMenu(menu, menuButton.value).then(focus).finally(cleanup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkPagination ref="pagingComponent" :pagination="pagination" :disableAutoLoad="disableAutoLoad">
|
<MkPagination ref="pagingComponent" :pagination="pagination" :disableAutoLoad="disableAutoLoad">
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img :src="infoImageUrl" class="_ghost"/>
|
<img v-if="serverMetadata.infoImageUrl" :src="serverMetadata.infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.noNotes }}</div>
|
<div>{{ i18n.ts.noNotes }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -33,11 +33,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { shallowRef } from 'vue';
|
import { shallowRef } from 'vue';
|
||||||
|
import { inject } from 'vue';
|
||||||
import MkNote from '@/components/MkNote.vue';
|
import MkNote from '@/components/MkNote.vue';
|
||||||
import MkDateSeparatedList from '@/components/MkDateSeparatedList.vue';
|
import MkDateSeparatedList from '@/components/MkDateSeparatedList.vue';
|
||||||
import MkPagination, { Paging } from '@/components/MkPagination.vue';
|
import MkPagination, { Paging } from '@/components/MkPagination.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
pagination: Paging;
|
pagination: Paging;
|
||||||
|
|
|
@ -148,7 +148,8 @@ import { userPage } from '@/filters/user.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { signinRequired } from '@/account.js';
|
import { signinRequired } from '@/account.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
import { inject } from 'vue';
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const $i = signinRequired();
|
const $i = signinRequired();
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkPagination ref="pagingComponent" :pagination="pagination">
|
<MkPagination ref="pagingComponent" :pagination="pagination">
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img :src="infoImageUrl" class="_ghost"/>
|
<img v-if="serverMetadata.infoImageUrl" :src="serverMetadata.infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.noNotifications }}</div>
|
<div>{{ i18n.ts.noNotifications }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -32,7 +32,8 @@ 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 { notificationTypes } from '@/const.js';
|
import { notificationTypes } from '@/const.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
import { inject } from 'vue';
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
import MkPullToRefresh from '@/components/MkPullToRefresh.vue';
|
import MkPullToRefresh from '@/components/MkPullToRefresh.vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
|
|
|
@ -18,7 +18,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div v-else-if="empty" key="_empty_" class="empty">
|
<div v-else-if="empty" key="_empty_" class="empty">
|
||||||
<slot name="empty">
|
<slot name="empty">
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img :src="infoImageUrl" class="_ghost"/>
|
<img v-if="serverMetadata.infoImageUrl" :src="serverMetadata.infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.nothing }}</div>
|
<div>{{ i18n.ts.nothing }}</div>
|
||||||
</div>
|
</div>
|
||||||
</slot>
|
</slot>
|
||||||
|
@ -90,7 +90,8 @@ function concatMapWithArray(map: MisskeyEntityMap, entities: MisskeyEntity[]): M
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { infoImageUrl } from '@/instance.js';
|
import { inject } from 'vue';
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
|
|
|
@ -120,7 +120,6 @@ import { selectFiles } from '@/scripts/select-file.js';
|
||||||
import { defaultStore, notePostInterruptors, postFormActions } from '@/store.js';
|
import { defaultStore, notePostInterruptors, postFormActions } from '@/store.js';
|
||||||
import MkInfo from '@/components/MkInfo.vue';
|
import MkInfo from '@/components/MkInfo.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
|
||||||
import { signinRequired, notesCount, incNotesCount, getAccounts, openAccountMenu as openAccountMenu_ } from '@/account.js';
|
import { signinRequired, notesCount, incNotesCount, getAccounts, openAccountMenu as openAccountMenu_ } from '@/account.js';
|
||||||
import { uploadFile } from '@/scripts/upload.js';
|
import { uploadFile } from '@/scripts/upload.js';
|
||||||
import { deepClone } from '@/scripts/clone.js';
|
import { deepClone } from '@/scripts/clone.js';
|
||||||
|
@ -130,6 +129,8 @@ import { claimAchievement } from '@/scripts/achievements.js';
|
||||||
import { emojiPicker } from '@/scripts/emoji-picker.js';
|
import { emojiPicker } from '@/scripts/emoji-picker.js';
|
||||||
import { mfmFunctionPicker } from '@/scripts/mfm-function-picker.js';
|
import { mfmFunctionPicker } from '@/scripts/mfm-function-picker.js';
|
||||||
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const $i = signinRequired();
|
const $i = signinRequired();
|
||||||
|
|
||||||
const modal = inject('modal');
|
const modal = inject('modal');
|
||||||
|
@ -249,7 +250,7 @@ const textLength = computed((): number => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const maxTextLength = computed((): number => {
|
const maxTextLength = computed((): number => {
|
||||||
return instance ? instance.maxNoteTextLength : 1000;
|
return serverMetadata.maxNoteTextLength;
|
||||||
});
|
});
|
||||||
|
|
||||||
const canPost = computed((): boolean => {
|
const canPost = computed((): boolean => {
|
||||||
|
|
|
@ -41,14 +41,15 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue';
|
import { inject, ref } from 'vue';
|
||||||
import { $i, getAccounts } from '@/account.js';
|
import { $i, getAccounts } from '@/account.js';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import { instance } from '@/instance.js';
|
|
||||||
import { apiWithDialog, promiseDialog } from '@/os.js';
|
import { apiWithDialog, promiseDialog } from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
primary?: boolean;
|
primary?: boolean;
|
||||||
gradate?: boolean;
|
gradate?: boolean;
|
||||||
|
@ -72,12 +73,12 @@ const pushSubscription = ref<PushSubscription | null>(null);
|
||||||
const pushRegistrationInServer = ref<{ state?: string; key?: string; userId: string; endpoint: string; sendReadMessage: boolean; } | undefined>();
|
const pushRegistrationInServer = ref<{ state?: string; key?: string; userId: string; endpoint: string; sendReadMessage: boolean; } | undefined>();
|
||||||
|
|
||||||
function subscribe() {
|
function subscribe() {
|
||||||
if (!registration.value || !supported.value || !instance.swPublickey) return;
|
if (!registration.value || !supported.value || !serverMetadata.swPublickey) return;
|
||||||
|
|
||||||
// SEE: https://developer.mozilla.org/en-US/docs/Web/API/PushManager/subscribe#Parameters
|
// SEE: https://developer.mozilla.org/en-US/docs/Web/API/PushManager/subscribe#Parameters
|
||||||
return promiseDialog(registration.value.pushManager.subscribe({
|
return promiseDialog(registration.value.pushManager.subscribe({
|
||||||
userVisibleOnly: true,
|
userVisibleOnly: true,
|
||||||
applicationServerKey: urlBase64ToUint8Array(instance.swPublickey),
|
applicationServerKey: urlBase64ToUint8Array(serverMetadata.swPublickey),
|
||||||
})
|
})
|
||||||
.then(async subscription => {
|
.then(async subscription => {
|
||||||
pushSubscription.value = subscription;
|
pushSubscription.value = subscription;
|
||||||
|
@ -156,7 +157,7 @@ if (navigator.serviceWorker == null) {
|
||||||
|
|
||||||
pushSubscription.value = await registration.value.pushManager.getSubscription();
|
pushSubscription.value = await registration.value.pushManager.getSubscription();
|
||||||
|
|
||||||
if (instance.swPublickey && ('PushManager' in window) && $i && $i.token) {
|
if (serverMetadata.swPublickey && ('PushManager' in window) && $i && $i.token) {
|
||||||
supported.value = true;
|
supported.value = true;
|
||||||
|
|
||||||
if (pushSubscription.value) {
|
if (pushSubscription.value) {
|
||||||
|
|
|
@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
<MkSpacer :marginMin="20" :marginMax="32">
|
<MkSpacer :marginMin="20" :marginMax="32">
|
||||||
<form class="_gaps_m" autocomplete="new-password" @submit.prevent="onSubmit">
|
<form class="_gaps_m" autocomplete="new-password" @submit.prevent="onSubmit">
|
||||||
<MkInput v-if="instance.disableRegistration" v-model="invitationCode" type="text" :spellcheck="false" required>
|
<MkInput v-if="serverMetadata.disableRegistration" v-model="invitationCode" type="text" :spellcheck="false" required>
|
||||||
<template #label>{{ i18n.ts.invitationCode }}</template>
|
<template #label>{{ i18n.ts.invitationCode }}</template>
|
||||||
<template #prefix><i class="ti ti-key"></i></template>
|
<template #prefix><i class="ti ti-key"></i></template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
|
@ -29,7 +29,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<span v-else-if="usernameState === 'max-range'" style="color: var(--error)"><i class="ti ti-alert-triangle ti-fw"></i> {{ i18n.ts.tooLong }}</span>
|
<span v-else-if="usernameState === 'max-range'" style="color: var(--error)"><i class="ti ti-alert-triangle ti-fw"></i> {{ i18n.ts.tooLong }}</span>
|
||||||
</template>
|
</template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
<MkInput v-if="instance.emailRequiredForSignup" v-model="email" :debounce="true" type="email" :spellcheck="false" required data-cy-signup-email @update:modelValue="onChangeEmail">
|
<MkInput v-if="serverMetadata.emailRequiredForSignup" v-model="email" :debounce="true" type="email" :spellcheck="false" required data-cy-signup-email @update:modelValue="onChangeEmail">
|
||||||
<template #label>{{ i18n.ts.emailAddress }} <div v-tooltip:dialog="i18n.ts._signup.emailAddressInfo" class="_button _help"><i class="ti ti-help-circle"></i></div></template>
|
<template #label>{{ i18n.ts.emailAddress }} <div v-tooltip:dialog="i18n.ts._signup.emailAddressInfo" class="_button _help"><i class="ti ti-help-circle"></i></div></template>
|
||||||
<template #prefix><i class="ti ti-mail"></i></template>
|
<template #prefix><i class="ti ti-mail"></i></template>
|
||||||
<template #caption>
|
<template #caption>
|
||||||
|
@ -62,10 +62,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<span v-if="passwordRetypeState == 'not-match'" style="color: var(--error)"><i class="ti ti-alert-triangle ti-fw"></i> {{ i18n.ts.passwordNotMatched }}</span>
|
<span v-if="passwordRetypeState == 'not-match'" style="color: var(--error)"><i class="ti ti-alert-triangle ti-fw"></i> {{ i18n.ts.passwordNotMatched }}</span>
|
||||||
</template>
|
</template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
<MkCaptcha v-if="instance.enableHcaptcha" ref="hcaptcha" v-model="hCaptchaResponse" :class="$style.captcha" provider="hcaptcha" :sitekey="instance.hcaptchaSiteKey"/>
|
<MkCaptcha v-if="serverMetadata.enableHcaptcha" ref="hcaptcha" v-model="hCaptchaResponse" :class="$style.captcha" provider="hcaptcha" :sitekey="serverMetadata.hcaptchaSiteKey"/>
|
||||||
<MkCaptcha v-if="instance.enableMcaptcha" ref="mcaptcha" v-model="mCaptchaResponse" :class="$style.captcha" provider="mcaptcha" :sitekey="instance.mcaptchaSiteKey" :instanceUrl="instance.mcaptchaInstanceUrl"/>
|
<MkCaptcha v-if="serverMetadata.enableMcaptcha" ref="mcaptcha" v-model="mCaptchaResponse" :class="$style.captcha" provider="mcaptcha" :sitekey="serverMetadata.mcaptchaSiteKey" :instanceUrl="serverMetadata.mcaptchaInstanceUrl"/>
|
||||||
<MkCaptcha v-if="instance.enableRecaptcha" ref="recaptcha" v-model="reCaptchaResponse" :class="$style.captcha" provider="recaptcha" :sitekey="instance.recaptchaSiteKey"/>
|
<MkCaptcha v-if="serverMetadata.enableRecaptcha" ref="recaptcha" v-model="reCaptchaResponse" :class="$style.captcha" provider="recaptcha" :sitekey="serverMetadata.recaptchaSiteKey"/>
|
||||||
<MkCaptcha v-if="instance.enableTurnstile" ref="turnstile" v-model="turnstileResponse" :class="$style.captcha" provider="turnstile" :sitekey="instance.turnstileSiteKey"/>
|
<MkCaptcha v-if="serverMetadata.enableTurnstile" ref="turnstile" v-model="turnstileResponse" :class="$style.captcha" provider="turnstile" :sitekey="serverMetadata.turnstileSiteKey"/>
|
||||||
<MkButton type="submit" :disabled="shouldDisableSubmitting" large gradate rounded data-cy-signup-submit style="margin: 0 auto;">
|
<MkButton type="submit" :disabled="shouldDisableSubmitting" large gradate rounded data-cy-signup-submit style="margin: 0 auto;">
|
||||||
<template v-if="submitting">
|
<template v-if="submitting">
|
||||||
<MkLoading :em="true" :colored="false"/>
|
<MkLoading :em="true" :colored="false"/>
|
||||||
|
@ -78,7 +78,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed, inject } from 'vue';
|
||||||
import { toUnicode } from 'punycode/';
|
import { toUnicode } from 'punycode/';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import MkButton from './MkButton.vue';
|
import MkButton from './MkButton.vue';
|
||||||
|
@ -88,9 +88,10 @@ import * as config from '@/config.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { login } from '@/account.js';
|
import { login } from '@/account.js';
|
||||||
import { instance } from '@/instance.js';
|
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
autoSet?: boolean;
|
autoSet?: boolean;
|
||||||
}>(), {
|
}>(), {
|
||||||
|
@ -127,11 +128,11 @@ const emailAbortController = ref<null | AbortController>(null);
|
||||||
|
|
||||||
const shouldDisableSubmitting = computed((): boolean => {
|
const shouldDisableSubmitting = computed((): boolean => {
|
||||||
return submitting.value ||
|
return submitting.value ||
|
||||||
instance.enableHcaptcha && !hCaptchaResponse.value ||
|
serverMetadata.enableHcaptcha && !hCaptchaResponse.value ||
|
||||||
instance.enableMcaptcha && !mCaptchaResponse.value ||
|
serverMetadata.enableMcaptcha && !mCaptchaResponse.value ||
|
||||||
instance.enableRecaptcha && !reCaptchaResponse.value ||
|
serverMetadata.enableRecaptcha && !reCaptchaResponse.value ||
|
||||||
instance.enableTurnstile && !turnstileResponse.value ||
|
serverMetadata.enableTurnstile && !turnstileResponse.value ||
|
||||||
instance.emailRequiredForSignup && emailState.value !== 'ok' ||
|
serverMetadata.emailRequiredForSignup && emailState.value !== 'ok' ||
|
||||||
usernameState.value !== 'ok' ||
|
usernameState.value !== 'ok' ||
|
||||||
passwordRetypeState.value !== 'match';
|
passwordRetypeState.value !== 'match';
|
||||||
});
|
});
|
||||||
|
@ -260,7 +261,7 @@ async function onSubmit(): Promise<void> {
|
||||||
'g-recaptcha-response': reCaptchaResponse.value,
|
'g-recaptcha-response': reCaptchaResponse.value,
|
||||||
'turnstile-response': turnstileResponse.value,
|
'turnstile-response': turnstileResponse.value,
|
||||||
});
|
});
|
||||||
if (instance.emailRequiredForSignup) {
|
if (serverMetadata.emailRequiredForSignup) {
|
||||||
os.alert({
|
os.alert({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
title: i18n.ts._signup.almostThere,
|
title: i18n.ts._signup.almostThere,
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { StoryObj } from '@storybook/vue3';
|
||||||
import { onBeforeUnmount } from 'vue';
|
import { onBeforeUnmount } from 'vue';
|
||||||
import MkSignupServerRules from './MkSignupDialog.rules.vue';
|
import MkSignupServerRules from './MkSignupDialog.rules.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/server-metadata.js';
|
||||||
export const Empty = {
|
export const Empty = {
|
||||||
render(args) {
|
render(args) {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
<MkSpacer :marginMin="20" :marginMax="28">
|
<MkSpacer :marginMin="20" :marginMax="28">
|
||||||
<div class="_gaps_m">
|
<div class="_gaps_m">
|
||||||
<div v-if="instance.disableRegistration">
|
<div v-if="serverMetadata.disableRegistration">
|
||||||
<MkInfo warn>{{ i18n.ts.invitationRequiredToRegister }}</MkInfo>
|
<MkInfo warn>{{ i18n.ts.invitationRequiredToRegister }}</MkInfo>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template #suffix><i v-if="agreeServerRules" class="ti ti-check" style="color: var(--success)"></i></template>
|
<template #suffix><i v-if="agreeServerRules" class="ti ti-check" style="color: var(--success)"></i></template>
|
||||||
|
|
||||||
<ol class="_gaps_s" :class="$style.rules">
|
<ol class="_gaps_s" :class="$style.rules">
|
||||||
<li v-for="item in instance.serverRules" :class="$style.rule"><div :class="$style.ruleText" v-html="item"></div></li>
|
<li v-for="item in serverMetadata.serverRules" :class="$style.rule"><div :class="$style.ruleText" v-html="item"></div></li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
<MkSwitch :modelValue="agreeServerRules" style="margin-top: 16px;" @update:modelValue="updateAgreeServerRules">{{ i18n.ts.agree }}</MkSwitch>
|
<MkSwitch :modelValue="agreeServerRules" style="margin-top: 16px;" @update:modelValue="updateAgreeServerRules">{{ i18n.ts.agree }}</MkSwitch>
|
||||||
|
@ -34,8 +34,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template #label>{{ tosPrivacyPolicyLabel }}</template>
|
<template #label>{{ tosPrivacyPolicyLabel }}</template>
|
||||||
<template #suffix><i v-if="agreeTosAndPrivacyPolicy" class="ti ti-check" style="color: var(--success)"></i></template>
|
<template #suffix><i v-if="agreeTosAndPrivacyPolicy" class="ti ti-check" style="color: var(--success)"></i></template>
|
||||||
<div class="_gaps_s">
|
<div class="_gaps_s">
|
||||||
<div v-if="availableTos"><a :href="instance.tosUrl ?? undefined" class="_link" target="_blank">{{ i18n.ts.termsOfService }} <i class="ti ti-external-link"></i></a></div>
|
<div v-if="availableTos"><a :href="serverMetadata.tosUrl ?? undefined" class="_link" target="_blank">{{ i18n.ts.termsOfService }} <i class="ti ti-external-link"></i></a></div>
|
||||||
<div v-if="availablePrivacyPolicy"><a :href="instance.privacyPolicyUrl ?? undefined" class="_link" target="_blank">{{ i18n.ts.privacyPolicy }} <i class="ti ti-external-link"></i></a></div>
|
<div v-if="availablePrivacyPolicy"><a :href="serverMetadata.privacyPolicyUrl ?? undefined" class="_link" target="_blank">{{ i18n.ts.privacyPolicy }} <i class="ti ti-external-link"></i></a></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<MkSwitch :modelValue="agreeTosAndPrivacyPolicy" style="margin-top: 16px;" @update:modelValue="updateAgreeTosAndPrivacyPolicy">{{ i18n.ts.agree }}</MkSwitch>
|
<MkSwitch :modelValue="agreeTosAndPrivacyPolicy" style="margin-top: 16px;" @update:modelValue="updateAgreeTosAndPrivacyPolicy">{{ i18n.ts.agree }}</MkSwitch>
|
||||||
|
@ -62,8 +62,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, ref } from 'vue';
|
import { computed, inject, ref } from 'vue';
|
||||||
import { instance } from '@/instance.js';
|
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import MkFolder from '@/components/MkFolder.vue';
|
import MkFolder from '@/components/MkFolder.vue';
|
||||||
|
@ -71,9 +70,11 @@ import MkSwitch from '@/components/MkSwitch.vue';
|
||||||
import MkInfo from '@/components/MkInfo.vue';
|
import MkInfo from '@/components/MkInfo.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
|
|
||||||
const availableServerRules = instance.serverRules.length > 0;
|
const serverMetadata = inject('serverMetadata');
|
||||||
const availableTos = instance.tosUrl != null && instance.tosUrl !== '';
|
|
||||||
const availablePrivacyPolicy = instance.privacyPolicyUrl != null && instance.privacyPolicyUrl !== '';
|
const availableServerRules = serverMetadata.serverRules.length > 0;
|
||||||
|
const availableTos = serverMetadata.tosUrl != null && serverMetadata.tosUrl !== '';
|
||||||
|
const availablePrivacyPolicy = serverMetadata.privacyPolicyUrl != null && serverMetadata.privacyPolicyUrl !== '';
|
||||||
|
|
||||||
const agreeServerRules = ref(false);
|
const agreeServerRules = ref(false);
|
||||||
const agreeTosAndPrivacyPolicy = ref(false);
|
const agreeTosAndPrivacyPolicy = ref(false);
|
||||||
|
|
|
@ -15,14 +15,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div :class="$style.title">
|
<div :class="$style.title">
|
||||||
<I18n :src="i18n.ts.aboutX" tag="span">
|
<I18n :src="i18n.ts.aboutX" tag="span">
|
||||||
<template #x>
|
<template #x>
|
||||||
{{ instance.name ?? host }}
|
{{ serverMetadata.name ?? host }}
|
||||||
</template>
|
</template>
|
||||||
</I18n>
|
</I18n>
|
||||||
</div>
|
</div>
|
||||||
<div :class="$style.text">
|
<div :class="$style.text">
|
||||||
<I18n :src="i18n.ts._aboutMisskey.thisIsModifiedVersion" tag="span">
|
<I18n :src="i18n.ts._aboutMisskey.thisIsModifiedVersion" tag="span">
|
||||||
<template #name>
|
<template #name>
|
||||||
{{ instance.name ?? host }}
|
{{ serverMetadata.name ?? host }}
|
||||||
</template>
|
</template>
|
||||||
</I18n>
|
</I18n>
|
||||||
<I18n :src="i18n.ts.correspondingSourceIsAvailable" tag="span">
|
<I18n :src="i18n.ts.correspondingSourceIsAvailable" tag="span">
|
||||||
|
@ -40,13 +40,15 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { inject } from 'vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import { host } from '@/config.js';
|
import { host } from '@/config.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
|
||||||
import { miLocalStorage } from '@/local-storage.js';
|
import { miLocalStorage } from '@/local-storage.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: 'closed'): void;
|
(ev: 'closed'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
|
@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, watch, onUnmounted, provide, ref, shallowRef } from 'vue';
|
import { computed, watch, onUnmounted, provide, ref, shallowRef, inject } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import type { BasicTimelineType } from '@/timelines.js';
|
import type { BasicTimelineType } from '@/timelines.js';
|
||||||
import MkNotes from '@/components/MkNotes.vue';
|
import MkNotes from '@/components/MkNotes.vue';
|
||||||
|
@ -25,10 +25,11 @@ import MkPullToRefresh from '@/components/MkPullToRefresh.vue';
|
||||||
import { useStream } from '@/stream.js';
|
import { useStream } from '@/stream.js';
|
||||||
import * as sound from '@/scripts/sound.js';
|
import * as sound from '@/scripts/sound.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import { instance } from '@/instance.js';
|
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
import { Paging } from '@/components/MkPagination.vue';
|
import { Paging } from '@/components/MkPagination.vue';
|
||||||
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
src: BasicTimelineType | 'mentions' | 'directs' | 'list' | 'antenna' | 'channel' | 'role';
|
src: BasicTimelineType | 'mentions' | 'directs' | 'list' | 'antenna' | 'channel' | 'role';
|
||||||
list?: string;
|
list?: string;
|
||||||
|
|
|
@ -133,7 +133,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<a href="https://misskey-hub.net/docs/for-users/" target="_blank" class="_link">{{ i18n.ts.help }}</a>
|
<a href="https://misskey-hub.net/docs/for-users/" target="_blank" class="_link">{{ i18n.ts.help }}</a>
|
||||||
</template>
|
</template>
|
||||||
</I18n>
|
</I18n>
|
||||||
<div>{{ i18n.tsx._initialAccountSetting.haveFun({ name: instance.name ?? host }) }}</div>
|
<div>{{ i18n.tsx._initialAccountSetting.haveFun({ name: serverMetadata.name ?? host }) }}</div>
|
||||||
<div class="_buttonsCenter" style="margin-top: 16px;">
|
<div class="_buttonsCenter" style="margin-top: 16px;">
|
||||||
<MkButton v-if="initialPage !== 4" rounded @click="page--"><i class="ti ti-arrow-left"></i> {{ i18n.ts.goBack }}</MkButton>
|
<MkButton v-if="initialPage !== 4" rounded @click="page--"><i class="ti ti-arrow-left"></i> {{ i18n.ts.goBack }}</MkButton>
|
||||||
<MkButton rounded primary gradate @click="close(false)">{{ i18n.ts.close }}</MkButton>
|
<MkButton rounded primary gradate @click="close(false)">{{ i18n.ts.close }}</MkButton>
|
||||||
|
@ -148,7 +148,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, shallowRef, watch } from 'vue';
|
import { inject, ref, shallowRef, watch } from 'vue';
|
||||||
import MkModalWindow from '@/components/MkModalWindow.vue';
|
import MkModalWindow from '@/components/MkModalWindow.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import XNote from '@/components/MkTutorialDialog.Note.vue';
|
import XNote from '@/components/MkTutorialDialog.Note.vue';
|
||||||
|
@ -157,11 +157,12 @@ import XPostNote from '@/components/MkTutorialDialog.PostNote.vue';
|
||||||
import XSensitive from '@/components/MkTutorialDialog.Sensitive.vue';
|
import XSensitive from '@/components/MkTutorialDialog.Sensitive.vue';
|
||||||
import MkAnimBg from '@/components/MkAnimBg.vue';
|
import MkAnimBg from '@/components/MkAnimBg.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
|
||||||
import { host } from '@/config.js';
|
import { host } from '@/config.js';
|
||||||
import { claimAchievement } from '@/scripts/achievements.js';
|
import { claimAchievement } from '@/scripts/achievements.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
initialPage?: number;
|
initialPage?: number;
|
||||||
}>();
|
}>();
|
||||||
|
|
|
@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="_panel" :class="$style.root">
|
<div class="_panel" :class="$style.root">
|
||||||
<div :class="$style.banner" :style="user.bannerUrl ? `background-image: url(${defaultStore.state.disableShowingAnimatedImages ? getStaticImageUrl(user.bannerUrl) : user.bannerUrl})` : ''"></div>
|
<div :class="$style.banner" :style="user.bannerUrl ? `background-image: url(${defaultStore.state.disableShowingAnimatedImages ? mediaProxy.getStaticImageUrl(user.bannerUrl) : user.bannerUrl})` : ''"></div>
|
||||||
<MkAvatar :class="$style.avatar" :user="user" indicator/>
|
<MkAvatar :class="$style.avatar" :user="user" indicator/>
|
||||||
<div :class="$style.title">
|
<div :class="$style.title">
|
||||||
<MkA :class="$style.name" :to="userPage(user)"><MkUserName :user="user" :nowrap="false"/></MkA>
|
<MkA :class="$style.name" :to="userPage(user)"><MkUserName :user="user" :nowrap="false"/></MkA>
|
||||||
|
@ -35,15 +35,17 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
|
import { inject } from 'vue';
|
||||||
import MkFollowButton from '@/components/MkFollowButton.vue';
|
import MkFollowButton from '@/components/MkFollowButton.vue';
|
||||||
import number from '@/filters/number.js';
|
import number from '@/filters/number.js';
|
||||||
import { userPage } from '@/filters/user.js';
|
import { userPage } from '@/filters/user.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import { isFollowingVisibleForMe, isFollowersVisibleForMe } from '@/scripts/isFfVisibleForMe.js';
|
import { isFollowingVisibleForMe, isFollowersVisibleForMe } from '@/scripts/isFfVisibleForMe.js';
|
||||||
import { getStaticImageUrl } from '@/scripts/media-proxy.js';
|
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
|
|
||||||
|
const mediaProxy = inject('mediaProxy');
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
user: Misskey.entities.UserDetailed;
|
user: Misskey.entities.UserDetailed;
|
||||||
}>();
|
}>();
|
||||||
|
|
|
@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkPagination :pagination="pagination">
|
<MkPagination :pagination="pagination">
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img :src="infoImageUrl" class="_ghost"/>
|
<img v-if="serverMetadata.infoImageUrl" :src="serverMetadata.infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.noUsers }}</div>
|
<div>{{ i18n.ts.noUsers }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -21,10 +21,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { inject } from 'vue';
|
||||||
import MkUserInfo from '@/components/MkUserInfo.vue';
|
import MkUserInfo from '@/components/MkUserInfo.vue';
|
||||||
import MkPagination, { Paging } from '@/components/MkPagination.vue';
|
import MkPagination, { Paging } from '@/components/MkPagination.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
pagination: Paging;
|
pagination: Paging;
|
||||||
|
|
|
@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
>
|
>
|
||||||
<div v-if="showing" :class="$style.root" class="_popup _shadow" :style="{ zIndex, top: top + 'px', left: left + 'px' }" @mouseover="() => { emit('mouseover'); }" @mouseleave="() => { emit('mouseleave'); }">
|
<div v-if="showing" :class="$style.root" class="_popup _shadow" :style="{ zIndex, top: top + 'px', left: left + 'px' }" @mouseover="() => { emit('mouseover'); }" @mouseleave="() => { emit('mouseleave'); }">
|
||||||
<div v-if="user != null">
|
<div v-if="user != null">
|
||||||
<div :class="$style.banner" :style="user.bannerUrl ? `background-image: url(${defaultStore.state.disableShowingAnimatedImages ? getStaticImageUrl(user.bannerUrl) : user.bannerUrl})` : ''">
|
<div :class="$style.banner" :style="user.bannerUrl ? `background-image: url(${defaultStore.state.disableShowingAnimatedImages ? mediaProxy.getStaticImageUrl(user.bannerUrl) : user.bannerUrl})` : ''">
|
||||||
<span v-if="$i && $i.id != user.id && user.isFollowed" :class="$style.followed">{{ i18n.ts.followsYou }}</span>
|
<span v-if="$i && $i.id != user.id && user.isFollowed" :class="$style.followed">{{ i18n.ts.followsYou }}</span>
|
||||||
</div>
|
</div>
|
||||||
<svg viewBox="0 0 128 128" :class="$style.avatarBack">
|
<svg viewBox="0 0 128 128" :class="$style.avatarBack">
|
||||||
|
@ -55,7 +55,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { inject, onMounted, ref } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import MkFollowButton from '@/components/MkFollowButton.vue';
|
import MkFollowButton from '@/components/MkFollowButton.vue';
|
||||||
import { userPage } from '@/filters/user.js';
|
import { userPage } from '@/filters/user.js';
|
||||||
|
@ -67,7 +67,9 @@ import { i18n } from '@/i18n.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import { isFollowingVisibleForMe, isFollowersVisibleForMe } from '@/scripts/isFfVisibleForMe.js';
|
import { isFollowingVisibleForMe, isFollowersVisibleForMe } from '@/scripts/isFfVisibleForMe.js';
|
||||||
import { getStaticImageUrl } from '@/scripts/media-proxy.js';
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
const mediaProxy = inject('mediaProxy');
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
showing: boolean;
|
showing: boolean;
|
||||||
|
@ -88,7 +90,7 @@ const left = ref(0);
|
||||||
|
|
||||||
function showMenu(ev: MouseEvent) {
|
function showMenu(ev: MouseEvent) {
|
||||||
if (user.value == null) return;
|
if (user.value == null) return;
|
||||||
const { menu, cleanup } = getUserMenu(user.value);
|
const { menu, cleanup } = getUserMenu({ serverMetadata }, user.value);
|
||||||
os.popupMenu(menu, ev.currentTarget ?? ev.target).finally(cleanup);
|
os.popupMenu(menu, ev.currentTarget ?? ev.target).finally(cleanup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div class="_gaps" style="text-align: center;">
|
<div class="_gaps" style="text-align: center;">
|
||||||
<i class="ti ti-bell-ringing-2" style="display: block; margin: auto; font-size: 3em; color: var(--accent);"></i>
|
<i class="ti ti-bell-ringing-2" style="display: block; margin: auto; font-size: 3em; color: var(--accent);"></i>
|
||||||
<div style="font-size: 120%;">{{ i18n.ts.pushNotification }}</div>
|
<div style="font-size: 120%;">{{ i18n.ts.pushNotification }}</div>
|
||||||
<div style="padding: 0 16px;">{{ i18n.tsx._initialAccountSetting.pushNotificationDescription({ name: instance.name ?? host }) }}</div>
|
<div style="padding: 0 16px;">{{ i18n.tsx._initialAccountSetting.pushNotificationDescription({ name: serverMetadata.name ?? host }) }}</div>
|
||||||
<MkPushNotificationAllowButton primary showOnlyToRegister style="margin: 0 auto;"/>
|
<MkPushNotificationAllowButton primary showOnlyToRegister style="margin: 0 auto;"/>
|
||||||
<div class="_buttonsCenter" style="margin-top: 16px;">
|
<div class="_buttonsCenter" style="margin-top: 16px;">
|
||||||
<MkButton rounded data-cy-user-setup-back @click="page--"><i class="ti ti-arrow-left"></i> {{ i18n.ts.goBack }}</MkButton>
|
<MkButton rounded data-cy-user-setup-back @click="page--"><i class="ti ti-arrow-left"></i> {{ i18n.ts.goBack }}</MkButton>
|
||||||
|
@ -110,7 +110,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div class="_gaps" style="text-align: center;">
|
<div class="_gaps" style="text-align: center;">
|
||||||
<i class="ti ti-check" style="display: block; margin: auto; font-size: 3em; color: var(--accent);"></i>
|
<i class="ti ti-check" style="display: block; margin: auto; font-size: 3em; color: var(--accent);"></i>
|
||||||
<div style="font-size: 120%;">{{ i18n.ts._initialAccountSetting.initialAccountSettingCompleted }}</div>
|
<div style="font-size: 120%;">{{ i18n.ts._initialAccountSetting.initialAccountSettingCompleted }}</div>
|
||||||
<div>{{ i18n.tsx._initialAccountSetting.youCanContinueTutorial({ name: instance.name ?? host }) }}</div>
|
<div>{{ i18n.tsx._initialAccountSetting.youCanContinueTutorial({ name: serverMetadata.name ?? host }) }}</div>
|
||||||
<div class="_buttonsCenter" style="margin-top: 16px;">
|
<div class="_buttonsCenter" style="margin-top: 16px;">
|
||||||
<MkButton rounded primary gradate data-cy-user-setup-continue @click="launchTutorial()">{{ i18n.ts._initialAccountSetting.startTutorial }} <i class="ti ti-arrow-right"></i></MkButton>
|
<MkButton rounded primary gradate data-cy-user-setup-continue @click="launchTutorial()">{{ i18n.ts._initialAccountSetting.startTutorial }} <i class="ti ti-arrow-right"></i></MkButton>
|
||||||
</div>
|
</div>
|
||||||
|
@ -128,7 +128,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, shallowRef, watch, nextTick, defineAsyncComponent } from 'vue';
|
import { ref, shallowRef, watch, nextTick, defineAsyncComponent, inject } from 'vue';
|
||||||
import MkModalWindow from '@/components/MkModalWindow.vue';
|
import MkModalWindow from '@/components/MkModalWindow.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import XProfile from '@/components/MkUserSetupDialog.Profile.vue';
|
import XProfile from '@/components/MkUserSetupDialog.Profile.vue';
|
||||||
|
@ -136,19 +136,19 @@ import XFollow from '@/components/MkUserSetupDialog.Follow.vue';
|
||||||
import XPrivacy from '@/components/MkUserSetupDialog.Privacy.vue';
|
import XPrivacy from '@/components/MkUserSetupDialog.Privacy.vue';
|
||||||
import MkAnimBg from '@/components/MkAnimBg.vue';
|
import MkAnimBg from '@/components/MkAnimBg.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
|
||||||
import { host } from '@/config.js';
|
import { host } from '@/config.js';
|
||||||
import MkPushNotificationAllowButton from '@/components/MkPushNotificationAllowButton.vue';
|
import MkPushNotificationAllowButton from '@/components/MkPushNotificationAllowButton.vue';
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: 'closed'): void;
|
(ev: 'closed'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
|
const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
|
||||||
|
|
||||||
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
|
|
||||||
const page = ref(defaultStore.state.accountSetupWizard);
|
const page = ref(defaultStore.state.accountSetupWizard);
|
||||||
|
|
||||||
watch(page, () => {
|
watch(page, () => {
|
||||||
|
|
|
@ -6,19 +6,19 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template>
|
<template>
|
||||||
<div v-if="instance" :class="$style.root">
|
<div v-if="instance" :class="$style.root">
|
||||||
<div :class="[$style.main, $style.panel]">
|
<div :class="[$style.main, $style.panel]">
|
||||||
<img :src="instance.iconUrl || '/favicon.ico'" alt="" :class="$style.mainIcon"/>
|
<img :src="serverMetadata.iconUrl || '/favicon.ico'" alt="" :class="$style.mainIcon"/>
|
||||||
<button class="_button _acrylic" :class="$style.mainMenu" @click="showMenu"><i class="ti ti-dots"></i></button>
|
<button class="_button _acrylic" :class="$style.mainMenu" @click="showMenu"><i class="ti ti-dots"></i></button>
|
||||||
<div :class="$style.mainFg">
|
<div :class="$style.mainFg">
|
||||||
<h1 :class="$style.mainTitle">
|
<h1 :class="$style.mainTitle">
|
||||||
<!-- 背景色によってはロゴが見えなくなるのでとりあえず無効に -->
|
<!-- 背景色によってはロゴが見えなくなるのでとりあえず無効に -->
|
||||||
<!-- <img class="logo" v-if="instance.logoImageUrl" :src="instance.logoImageUrl"><span v-else class="text">{{ instanceName }}</span> -->
|
<!-- <img class="logo" v-if="serverMetadata.logoImageUrl" :src="serverMetadata.logoImageUrl"><span v-else class="text">{{ instanceName }}</span> -->
|
||||||
<span>{{ instanceName }}</span>
|
<span>{{ instanceName }}</span>
|
||||||
</h1>
|
</h1>
|
||||||
<div :class="$style.mainAbout">
|
<div :class="$style.mainAbout">
|
||||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||||
<div v-html="instance.description || i18n.ts.headlineMisskey"></div>
|
<div v-html="serverMetadata.description || i18n.ts.headlineMisskey"></div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="instance.disableRegistration" :class="$style.mainWarn">
|
<div v-if="serverMetadata.disableRegistration" :class="$style.mainWarn">
|
||||||
<MkInfo warn>{{ i18n.ts.invitationRequiredToRegister }}</MkInfo>
|
<MkInfo warn>{{ i18n.ts.invitationRequiredToRegister }}</MkInfo>
|
||||||
</div>
|
</div>
|
||||||
<div class="_gaps_s" :class="$style.mainActions">
|
<div class="_gaps_s" :class="$style.mainActions">
|
||||||
|
@ -38,7 +38,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div :class="$style.statsItemCount"><MkNumber :value="stats.originalNotesCount"/></div>
|
<div :class="$style.statsItemCount"><MkNumber :value="stats.originalNotesCount"/></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="instance.policies.ltlAvailable" :class="[$style.tl, $style.panel]">
|
<div v-if="serverMetadata.policies.ltlAvailable" :class="[$style.tl, $style.panel]">
|
||||||
<div :class="$style.tlHeader">{{ i18n.ts.letsLookAtTimeline }}</div>
|
<div :class="$style.tlHeader">{{ i18n.ts.letsLookAtTimeline }}</div>
|
||||||
<div :class="$style.tlBody">
|
<div :class="$style.tlBody">
|
||||||
<MkTimeline src="local"/>
|
<MkTimeline src="local"/>
|
||||||
|
@ -51,7 +51,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue';
|
import { inject, ref } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import XSigninDialog from '@/components/MkSigninDialog.vue';
|
import XSigninDialog from '@/components/MkSigninDialog.vue';
|
||||||
import XSignupDialog from '@/components/MkSignupDialog.vue';
|
import XSignupDialog from '@/components/MkSignupDialog.vue';
|
||||||
|
@ -62,11 +62,11 @@ import { instanceName } from '@/config.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
|
||||||
import MkNumber from '@/components/MkNumber.vue';
|
import MkNumber from '@/components/MkNumber.vue';
|
||||||
import XActiveUsersChart from '@/components/MkVisitorDashboard.ActiveUsersChart.vue';
|
import XActiveUsersChart from '@/components/MkVisitorDashboard.ActiveUsersChart.vue';
|
||||||
import { openInstanceMenu } from '@/ui/_common_/common.js';
|
import { openInstanceMenu } from '@/ui/_common_/common.js';
|
||||||
import type { MenuItem } from '@/types/menu.js';
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const stats = ref<Misskey.entities.StatsResponse | null>(null);
|
const stats = ref<Misskey.entities.StatsResponse | null>(null);
|
||||||
|
|
||||||
|
|
|
@ -42,16 +42,17 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed, inject } from 'vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
|
||||||
import { url as local, host } from '@/config.js';
|
import { url as local, host } from '@/config.js';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
|
|
||||||
type Ad = (typeof instance)['ads'][number];
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
|
type Ad = (typeof serverMetadata)['ads'][number];
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
prefer: string[];
|
prefer: string[];
|
||||||
|
@ -68,7 +69,7 @@ const choseAd = (): Ad | null => {
|
||||||
return props.specify;
|
return props.specify;
|
||||||
}
|
}
|
||||||
|
|
||||||
const allAds = instance.ads.map(ad => defaultStore.state.mutedAds.includes(ad.id) ? {
|
const allAds = serverMetadata.ads.map(ad => defaultStore.state.mutedAds.includes(ad.id) ? {
|
||||||
...ad,
|
...ad,
|
||||||
ratio: 0,
|
ratio: 0,
|
||||||
} : ad);
|
} : ad);
|
||||||
|
|
|
@ -40,16 +40,17 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { watch, ref, computed } from 'vue';
|
import { watch, ref, computed, inject } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { extractAvgColorFromBlurhash } from '@@/js/extract-avg-color-from-blurhash.js';
|
import { extractAvgColorFromBlurhash } from '@@/js/extract-avg-color-from-blurhash.js';
|
||||||
import MkImgWithBlurhash from '../MkImgWithBlurhash.vue';
|
import MkImgWithBlurhash from '../MkImgWithBlurhash.vue';
|
||||||
import MkA from './MkA.vue';
|
import MkA from './MkA.vue';
|
||||||
import { getStaticImageUrl } from '@/scripts/media-proxy.js';
|
|
||||||
import { acct, userPage } from '@/filters/user.js';
|
import { acct, userPage } from '@/filters/user.js';
|
||||||
import MkUserOnlineIndicator from '@/components/MkUserOnlineIndicator.vue';
|
import MkUserOnlineIndicator from '@/components/MkUserOnlineIndicator.vue';
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
|
|
||||||
|
const mediaProxy = inject('mediaProxy');
|
||||||
|
|
||||||
const animation = ref(defaultStore.state.animation);
|
const animation = ref(defaultStore.state.animation);
|
||||||
const squareAvatars = ref(defaultStore.state.squareAvatars);
|
const squareAvatars = ref(defaultStore.state.squareAvatars);
|
||||||
const useBlurEffect = ref(defaultStore.state.useBlurEffect);
|
const useBlurEffect = ref(defaultStore.state.useBlurEffect);
|
||||||
|
@ -83,7 +84,7 @@ const bound = computed(() => props.link
|
||||||
|
|
||||||
const url = computed(() => {
|
const url = computed(() => {
|
||||||
if (props.user.avatarUrl == null) return null;
|
if (props.user.avatarUrl == null) return null;
|
||||||
if (defaultStore.state.disableShowingAnimatedImages || defaultStore.state.dataSaver.avatar) return getStaticImageUrl(props.user.avatarUrl);
|
if (defaultStore.state.disableShowingAnimatedImages || defaultStore.state.dataSaver.avatar) return mediaProxy.getStaticImageUrl(props.user.avatarUrl);
|
||||||
return props.user.avatarUrl;
|
return props.user.avatarUrl;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -93,7 +94,7 @@ function onClick(ev: MouseEvent): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDecorationUrl(decoration: Omit<Misskey.entities.UserDetailed['avatarDecorations'][number], 'id'>) {
|
function getDecorationUrl(decoration: Omit<Misskey.entities.UserDetailed['avatarDecorations'][number], 'id'>) {
|
||||||
if (defaultStore.state.disableShowingAnimatedImages || defaultStore.state.dataSaver.avatar) return getStaticImageUrl(decoration.url);
|
if (defaultStore.state.disableShowingAnimatedImages || defaultStore.state.dataSaver.avatar) return mediaProxy.getStaticImageUrl(decoration.url);
|
||||||
return decoration.url;
|
return decoration.url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, inject, ref } from 'vue';
|
import { computed, inject, ref } from 'vue';
|
||||||
import { getProxiedImageUrl, getStaticImageUrl } from '@/scripts/media-proxy.js';
|
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
import { customEmojisMap } from '@/custom-emojis.js';
|
import { customEmojisMap } from '@/custom-emojis.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
|
@ -36,6 +35,8 @@ import * as sound from '@/scripts/sound.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import MkCustomEmojiDetailedDialog from '@/components/MkCustomEmojiDetailedDialog.vue';
|
import MkCustomEmojiDetailedDialog from '@/components/MkCustomEmojiDetailedDialog.vue';
|
||||||
|
|
||||||
|
const mediaProxy = inject('mediaProxy');
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
name: string;
|
name: string;
|
||||||
normal?: boolean;
|
normal?: boolean;
|
||||||
|
@ -69,14 +70,14 @@ const url = computed(() => {
|
||||||
const proxied =
|
const proxied =
|
||||||
(rawUrl.value.startsWith('/emoji/') || (props.useOriginalSize && isLocal.value))
|
(rawUrl.value.startsWith('/emoji/') || (props.useOriginalSize && isLocal.value))
|
||||||
? rawUrl.value
|
? rawUrl.value
|
||||||
: getProxiedImageUrl(
|
: mediaProxy.getProxiedImageUrl(
|
||||||
rawUrl.value,
|
rawUrl.value,
|
||||||
props.useOriginalSize ? undefined : 'emoji',
|
props.useOriginalSize ? undefined : 'emoji',
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
return defaultStore.reactiveState.disableShowingAnimatedImages.value
|
return defaultStore.reactiveState.disableShowingAnimatedImages.value
|
||||||
? getStaticImageUrl(proxied)
|
? mediaProxy.getStaticImageUrl(proxied)
|
||||||
: proxied;
|
: proxied;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template>
|
<template>
|
||||||
<Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" appear>
|
<Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" appear>
|
||||||
<div :class="$style.root">
|
<div :class="$style.root">
|
||||||
<img :class="$style.img" :src="serverErrorImageUrl" class="_ghost"/>
|
<img v-if="serverMetadata.serverErrorImageUrl" :class="$style.img" :src="serverMetadata.serverErrorImageUrl" class="_ghost"/>
|
||||||
<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>
|
||||||
|
@ -14,10 +14,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { inject } from 'vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
import { serverErrorImageUrl } from '@/instance.js';
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: 'retry'): void;
|
(ev: 'retry'): void;
|
||||||
|
|
|
@ -25,14 +25,15 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineAsyncComponent, ref } from 'vue';
|
import { defineAsyncComponent, inject, ref } from 'vue';
|
||||||
import { toUnicode as decodePunycode } from 'punycode/';
|
import { toUnicode as decodePunycode } from 'punycode/';
|
||||||
import { url as local } from '@/config.js';
|
import { url as local } from '@/config.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { useTooltip } from '@/scripts/use-tooltip.js';
|
import { useTooltip } from '@/scripts/use-tooltip.js';
|
||||||
import { isEnabledUrlPreview } from '@/instance.js';
|
|
||||||
import { MkABehavior } from '@/components/global/MkA.vue';
|
import { MkABehavior } from '@/components/global/MkA.vue';
|
||||||
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
function safeURIDecode(str: string): string {
|
function safeURIDecode(str: string): string {
|
||||||
try {
|
try {
|
||||||
return decodeURIComponent(str);
|
return decodeURIComponent(str);
|
||||||
|
@ -55,7 +56,7 @@ const url = new URL(props.url);
|
||||||
if (!['http:', 'https:'].includes(url.protocol)) throw new Error('invalid url');
|
if (!['http:', 'https:'].includes(url.protocol)) throw new Error('invalid url');
|
||||||
const el = ref();
|
const el = ref();
|
||||||
|
|
||||||
if (props.showUrlPreview && isEnabledUrlPreview.value) {
|
if (props.showUrlPreview && serverMetadata.enableUrlPreview) {
|
||||||
useTooltip(el, (showing) => {
|
useTooltip(el, (showing) => {
|
||||||
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkUrlPreviewPopup.vue')), {
|
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkUrlPreviewPopup.vue')), {
|
||||||
showing,
|
showing,
|
||||||
|
|
|
@ -6,18 +6,19 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template>
|
<template>
|
||||||
<div class="_gaps" :class="$style.textRoot">
|
<div class="_gaps" :class="$style.textRoot">
|
||||||
<Mfm :text="block.text ?? ''" :isNote="false"/>
|
<Mfm :text="block.text ?? ''" :isNote="false"/>
|
||||||
<div v-if="isEnabledUrlPreview" class="_gaps_s">
|
<div v-if="serverMetadata.enableUrlPreview" class="_gaps_s">
|
||||||
<MkUrlPreview v-for="url in urls" :key="url" :url="url"/>
|
<MkUrlPreview v-for="url in urls" :key="url" :url="url"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineAsyncComponent } from 'vue';
|
import { defineAsyncComponent, inject } from 'vue';
|
||||||
import * as mfm from 'mfm-js';
|
import * as mfm from 'mfm-js';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm.js';
|
import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm.js';
|
||||||
import { isEnabledUrlPreview } from '@/instance.js';
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const MkUrlPreview = defineAsyncComponent(() => import('@/components/MkUrlPreview.vue'));
|
const MkUrlPreview = defineAsyncComponent(() => import('@/components/MkUrlPreview.vue'));
|
||||||
|
|
||||||
|
|
|
@ -106,10 +106,6 @@ export const ROLE_POLICIES = [
|
||||||
export const CURRENT_STICKY_TOP = 'CURRENT_STICKY_TOP';
|
export const CURRENT_STICKY_TOP = 'CURRENT_STICKY_TOP';
|
||||||
export const CURRENT_STICKY_BOTTOM = 'CURRENT_STICKY_BOTTOM';
|
export const CURRENT_STICKY_BOTTOM = 'CURRENT_STICKY_BOTTOM';
|
||||||
|
|
||||||
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='],
|
||||||
|
@ -127,7 +123,7 @@ export const MFM_PARAMS: Record<typeof MFM_TAGS[number], string[]> = {
|
||||||
position: ['x=', 'y='],
|
position: ['x=', 'y='],
|
||||||
fg: ['color='],
|
fg: ['color='],
|
||||||
bg: ['color='],
|
bg: ['color='],
|
||||||
border: ['width=', 'style=', 'color=', 'radius=', 'noclip'],
|
border: ['width=', 'style=', 'color=', 'radius=', 'noclip'],
|
||||||
font: ['serif', 'monospace', 'cursive', 'fantasy', 'emoji', 'math'],
|
font: ['serif', 'monospace', 'cursive', 'fantasy', 'emoji', 'math'],
|
||||||
blur: [],
|
blur: [],
|
||||||
rainbow: ['speed=', 'delay='],
|
rainbow: ['speed=', 'delay='],
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export type Keys =
|
export type Keys =
|
||||||
'v' |
|
|
||||||
'lastVersion' |
|
'lastVersion' |
|
||||||
'instance' |
|
'instance' |
|
||||||
'instanceCachedAt' |
|
'instanceCachedAt' |
|
||||||
|
|
|
@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkLoading v-if="!loaded"/>
|
<MkLoading v-if="!loaded"/>
|
||||||
<Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" appear>
|
<Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" appear>
|
||||||
<div v-show="loaded" :class="$style.root">
|
<div v-show="loaded" :class="$style.root">
|
||||||
<img :src="serverErrorImageUrl" class="_ghost" :class="$style.img"/>
|
<img v-if="serverMetadata.serverErrorImageUrl" :src="serverMetadata.serverErrorImageUrl" class="_ghost" :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>
|
||||||
|
@ -25,7 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed, inject } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import MkLink from '@/components/MkLink.vue';
|
import MkLink from '@/components/MkLink.vue';
|
||||||
|
@ -36,7 +36,8 @@ import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { miLocalStorage } from '@/local-storage.js';
|
import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
import { serverErrorImageUrl } from '@/instance.js';
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
error?: Error;
|
error?: Error;
|
||||||
|
|
|
@ -46,21 +46,21 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</FormLink>
|
</FormLink>
|
||||||
</div>
|
</div>
|
||||||
</FormSection>
|
</FormSection>
|
||||||
<FormSection v-if="instance.repositoryUrl !== 'https://github.com/misskey-dev/misskey'">
|
<FormSection v-if="serverMetadata.repositoryUrl !== 'https://github.com/misskey-dev/misskey'">
|
||||||
<div class="_gaps_s">
|
<div class="_gaps_s">
|
||||||
<MkInfo>
|
<MkInfo>
|
||||||
{{ i18n.tsx._aboutMisskey.thisIsModifiedVersion({ name: instance.name }) }}
|
{{ i18n.tsx._aboutMisskey.thisIsModifiedVersion({ name: serverMetadata.name }) }}
|
||||||
</MkInfo>
|
</MkInfo>
|
||||||
<FormLink v-if="instance.repositoryUrl" :to="instance.repositoryUrl" external>
|
<FormLink v-if="serverMetadata.repositoryUrl" :to="serverMetadata.repositoryUrl" external>
|
||||||
<template #icon><i class="ti ti-code"></i></template>
|
<template #icon><i class="ti ti-code"></i></template>
|
||||||
{{ i18n.ts._aboutMisskey.source }}
|
{{ i18n.ts._aboutMisskey.source }}
|
||||||
</FormLink>
|
</FormLink>
|
||||||
<FormLink v-if="instance.providesTarball" :to="`/tarball/misskey-${version}.tar.gz`" external>
|
<FormLink v-if="serverMetadata.providesTarball" :to="`/tarball/misskey-${version}.tar.gz`" external>
|
||||||
<template #icon><i class="ti ti-download"></i></template>
|
<template #icon><i class="ti ti-download"></i></template>
|
||||||
{{ i18n.ts._aboutMisskey.source }}
|
{{ i18n.ts._aboutMisskey.source }}
|
||||||
<template #suffix>Tarball</template>
|
<template #suffix>Tarball</template>
|
||||||
</FormLink>
|
</FormLink>
|
||||||
<MkInfo v-if="!instance.repositoryUrl && !instance.providesTarball" warn>
|
<MkInfo v-if="!serverMetadata.repositoryUrl && !serverMetadata.providesTarball" warn>
|
||||||
{{ i18n.ts.sourceCodeIsNotYetProvided }}
|
{{ i18n.ts.sourceCodeIsNotYetProvided }}
|
||||||
</MkInfo>
|
</MkInfo>
|
||||||
</div>
|
</div>
|
||||||
|
@ -131,7 +131,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { nextTick, onBeforeUnmount, ref, shallowRef, computed } from 'vue';
|
import { nextTick, onBeforeUnmount, ref, shallowRef, computed, inject } from 'vue';
|
||||||
import { version } from '@/config.js';
|
import { version } from '@/config.js';
|
||||||
import FormLink from '@/components/form/link.vue';
|
import FormLink from '@/components/form/link.vue';
|
||||||
import FormSection from '@/components/form/section.vue';
|
import FormSection from '@/components/form/section.vue';
|
||||||
|
@ -139,13 +139,14 @@ import MkButton from '@/components/MkButton.vue';
|
||||||
import MkInfo from '@/components/MkInfo.vue';
|
import MkInfo from '@/components/MkInfo.vue';
|
||||||
import { physics } from '@/scripts/physics.js';
|
import { physics } from '@/scripts/physics.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { claimAchievement, claimedAchievements } from '@/scripts/achievements.js';
|
import { claimAchievement, claimedAchievements } from '@/scripts/achievements.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const patronsWithIcon = [{
|
const patronsWithIcon = [{
|
||||||
name: 'カイヤン',
|
name: 'カイヤン',
|
||||||
icon: 'https://assets.misskey-hub.net/patrons/a2820716883e408cb87773e377ce7c8d.jpg',
|
icon: 'https://assets.misskey-hub.net/patrons/a2820716883e408cb87773e377ce7c8d.jpg',
|
||||||
|
|
|
@ -5,18 +5,18 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="_gaps_m">
|
<div class="_gaps_m">
|
||||||
<div :class="$style.banner" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }">
|
<div :class="$style.banner" :style="{ backgroundImage: `url(${ serverMetadata.bannerUrl })` }">
|
||||||
<div style="overflow: clip;">
|
<div style="overflow: clip;">
|
||||||
<img :src="instance.iconUrl ?? instance.faviconUrl ?? '/favicon.ico'" alt="" :class="$style.bannerIcon"/>
|
<img :src="serverMetadata.iconUrl ?? serverMetadata.faviconUrl ?? '/favicon.ico'" alt="" :class="$style.bannerIcon"/>
|
||||||
<div :class="$style.bannerName">
|
<div :class="$style.bannerName">
|
||||||
<b>{{ instance.name ?? host }}</b>
|
<b>{{ serverMetadata.name ?? host }}</b>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<MkKeyValue>
|
<MkKeyValue>
|
||||||
<template #key>{{ i18n.ts.description }}</template>
|
<template #key>{{ i18n.ts.description }}</template>
|
||||||
<template #value><div v-html="instance.description"></div></template>
|
<template #value><div v-html="serverMetadata.description"></div></template>
|
||||||
</MkKeyValue>
|
</MkKeyValue>
|
||||||
|
|
||||||
<FormSection>
|
<FormSection>
|
||||||
|
@ -25,13 +25,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template #key>Misskey</template>
|
<template #key>Misskey</template>
|
||||||
<template #value>{{ version }}</template>
|
<template #value>{{ version }}</template>
|
||||||
</MkKeyValue>
|
</MkKeyValue>
|
||||||
<div v-html="i18n.tsx.poweredByMisskeyDescription({ name: instance.name ?? host })">
|
<div v-html="i18n.tsx.poweredByMisskeyDescription({ name: serverMetadata.name ?? host })">
|
||||||
</div>
|
</div>
|
||||||
<FormLink to="/about-misskey">
|
<FormLink to="/about-misskey">
|
||||||
<template #icon><i class="ti ti-info-circle"></i></template>
|
<template #icon><i class="ti ti-info-circle"></i></template>
|
||||||
{{ i18n.ts.aboutMisskey }}
|
{{ i18n.ts.aboutMisskey }}
|
||||||
</FormLink>
|
</FormLink>
|
||||||
<FormLink v-if="instance.repositoryUrl || instance.providesTarball" :to="instance.repositoryUrl || `/tarball/misskey-${version}.tar.gz`" external>
|
<FormLink v-if="serverMetadata.repositoryUrl || serverMetadata.providesTarball" :to="serverMetadata.repositoryUrl || `/tarball/misskey-${version}.tar.gz`" external>
|
||||||
<template #icon><i class="ti ti-code"></i></template>
|
<template #icon><i class="ti ti-code"></i></template>
|
||||||
{{ i18n.ts.sourceCode }}
|
{{ i18n.ts.sourceCode }}
|
||||||
</FormLink>
|
</FormLink>
|
||||||
|
@ -44,51 +44,51 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<FormSection>
|
<FormSection>
|
||||||
<div class="_gaps_m">
|
<div class="_gaps_m">
|
||||||
<FormSplit>
|
<FormSplit>
|
||||||
<MkKeyValue :copy="instance.maintainerName">
|
<MkKeyValue :copy="serverMetadata.maintainerName">
|
||||||
<template #key>{{ i18n.ts.administrator }}</template>
|
<template #key>{{ i18n.ts.administrator }}</template>
|
||||||
<template #value>
|
<template #value>
|
||||||
<template v-if="instance.maintainerName">{{ instance.maintainerName }}</template>
|
<template v-if="serverMetadata.maintainerName">{{ serverMetadata.maintainerName }}</template>
|
||||||
<span v-else style="opacity: 0.7;">({{ i18n.ts.none }})</span>
|
<span v-else style="opacity: 0.7;">({{ i18n.ts.none }})</span>
|
||||||
</template>
|
</template>
|
||||||
</MkKeyValue>
|
</MkKeyValue>
|
||||||
<MkKeyValue :copy="instance.maintainerEmail">
|
<MkKeyValue :copy="serverMetadata.maintainerEmail">
|
||||||
<template #key>{{ i18n.ts.contact }}</template>
|
<template #key>{{ i18n.ts.contact }}</template>
|
||||||
<template #value>
|
<template #value>
|
||||||
<template v-if="instance.maintainerEmail">{{ instance.maintainerEmail }}</template>
|
<template v-if="serverMetadata.maintainerEmail">{{ serverMetadata.maintainerEmail }}</template>
|
||||||
<span v-else style="opacity: 0.7;">({{ i18n.ts.none }})</span>
|
<span v-else style="opacity: 0.7;">({{ i18n.ts.none }})</span>
|
||||||
</template>
|
</template>
|
||||||
</MkKeyValue>
|
</MkKeyValue>
|
||||||
<MkKeyValue>
|
<MkKeyValue>
|
||||||
<template #key>{{ i18n.ts.inquiry }}</template>
|
<template #key>{{ i18n.ts.inquiry }}</template>
|
||||||
<template #value>
|
<template #value>
|
||||||
<MkLink v-if="instance.inquiryUrl" :url="instance.inquiryUrl" target="_blank">{{ instance.inquiryUrl }}</MkLink>
|
<MkLink v-if="serverMetadata.inquiryUrl" :url="serverMetadata.inquiryUrl" target="_blank">{{ serverMetadata.inquiryUrl }}</MkLink>
|
||||||
<span v-else style="opacity: 0.7;">({{ i18n.ts.none }})</span>
|
<span v-else style="opacity: 0.7;">({{ i18n.ts.none }})</span>
|
||||||
</template>
|
</template>
|
||||||
</MkKeyValue>
|
</MkKeyValue>
|
||||||
</FormSplit>
|
</FormSplit>
|
||||||
<div class="_gaps_s">
|
<div class="_gaps_s">
|
||||||
<FormLink v-if="instance.impressumUrl" :to="instance.impressumUrl" external>
|
<FormLink v-if="serverMetadata.impressumUrl" :to="serverMetadata.impressumUrl" external>
|
||||||
<template #icon><i class="ti ti-user-shield"></i></template>
|
<template #icon><i class="ti ti-user-shield"></i></template>
|
||||||
<template #default>{{ i18n.ts.impressum }}</template>
|
<template #default>{{ i18n.ts.impressum }}</template>
|
||||||
</FormLink>
|
</FormLink>
|
||||||
<MkFolder v-if="instance.serverRules.length > 0">
|
<MkFolder v-if="serverMetadata.serverRules.length > 0">
|
||||||
<template #icon><i class="ti ti-checkup-list"></i></template>
|
<template #icon><i class="ti ti-checkup-list"></i></template>
|
||||||
<template #label>{{ i18n.ts.serverRules }}</template>
|
<template #label>{{ i18n.ts.serverRules }}</template>
|
||||||
<ol class="_gaps_s" :class="$style.rules">
|
<ol class="_gaps_s" :class="$style.rules">
|
||||||
<li v-for="item in instance.serverRules" :key="item" :class="$style.rule">
|
<li v-for="item in serverMetadata.serverRules" :key="item" :class="$style.rule">
|
||||||
<div :class="$style.ruleText" v-html="item"></div>
|
<div :class="$style.ruleText" v-html="item"></div>
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
<FormLink v-if="instance.tosUrl" :to="instance.tosUrl" external>
|
<FormLink v-if="serverMetadata.tosUrl" :to="serverMetadata.tosUrl" external>
|
||||||
<template #icon><i class="ti ti-license"></i></template>
|
<template #icon><i class="ti ti-license"></i></template>
|
||||||
<template #default>{{ i18n.ts.termsOfService }}</template>
|
<template #default>{{ i18n.ts.termsOfService }}</template>
|
||||||
</FormLink>
|
</FormLink>
|
||||||
<FormLink v-if="instance.privacyPolicyUrl" :to="instance.privacyPolicyUrl" external>
|
<FormLink v-if="serverMetadata.privacyPolicyUrl" :to="serverMetadata.privacyPolicyUrl" external>
|
||||||
<template #icon><i class="ti ti-shield-lock"></i></template>
|
<template #icon><i class="ti ti-shield-lock"></i></template>
|
||||||
<template #default>{{ i18n.ts.privacyPolicy }}</template>
|
<template #default>{{ i18n.ts.privacyPolicy }}</template>
|
||||||
</FormLink>
|
</FormLink>
|
||||||
<FormLink v-if="instance.feedbackUrl" :to="instance.feedbackUrl" external>
|
<FormLink v-if="serverMetadata.feedbackUrl" :to="serverMetadata.feedbackUrl" external>
|
||||||
<template #icon><i class="ti ti-message"></i></template>
|
<template #icon><i class="ti ti-message"></i></template>
|
||||||
<template #default>{{ i18n.ts.feedback }}</template>
|
<template #default>{{ i18n.ts.feedback }}</template>
|
||||||
</FormLink>
|
</FormLink>
|
||||||
|
@ -126,9 +126,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { inject } from 'vue';
|
||||||
import { host, version } from '@/config.js';
|
import { host, version } from '@/config.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
|
||||||
import number from '@/filters/number.js';
|
import number from '@/filters/number.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import FormLink from '@/components/form/link.vue';
|
import FormLink from '@/components/form/link.vue';
|
||||||
|
@ -139,6 +139,8 @@ import MkFolder from '@/components/MkFolder.vue';
|
||||||
import MkKeyValue from '@/components/MkKeyValue.vue';
|
import MkKeyValue from '@/components/MkKeyValue.vue';
|
||||||
import MkLink from '@/components/MkLink.vue';
|
import MkLink from '@/components/MkLink.vue';
|
||||||
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const initStats = () => misskeyApi('stats', {});
|
const initStats = () => misskeyApi('stats', {});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ import FormSuspense from '@/components/form/suspense.vue';
|
||||||
import FormSlot from '@/components/form/slot.vue';
|
import FormSlot from '@/components/form/slot.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { fetchInstance } from '@/instance.js';
|
import { fetchServerMetadata } from '@/server-metadata.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
||||||
const MkCaptcha = defineAsyncComponent(() => import('@/components/MkCaptcha.vue'));
|
const MkCaptcha = defineAsyncComponent(() => import('@/components/MkCaptcha.vue'));
|
||||||
|
@ -142,7 +142,7 @@ function save() {
|
||||||
turnstileSiteKey: turnstileSiteKey.value,
|
turnstileSiteKey: turnstileSiteKey.value,
|
||||||
turnstileSecretKey: turnstileSecretKey.value,
|
turnstileSecretKey: turnstileSecretKey.value,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance(true);
|
fetchServerMetadata(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -112,7 +112,7 @@ import MkTextarea from '@/components/MkTextarea.vue';
|
||||||
import FormSuspense from '@/components/form/suspense.vue';
|
import FormSuspense from '@/components/form/suspense.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { instance, fetchInstance } from '@/instance.js';
|
import { instance, fetchServerMetadata } from '@/server-metadata.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
|
@ -169,7 +169,7 @@ function save() {
|
||||||
feedbackUrl: feedbackUrl.value === '' ? null : feedbackUrl.value,
|
feedbackUrl: feedbackUrl.value === '' ? null : feedbackUrl.value,
|
||||||
manifestJsonOverride: manifestJsonOverride.value === '' ? '{}' : JSON.stringify(JSON5.parse(manifestJsonOverride.value)),
|
manifestJsonOverride: manifestJsonOverride.value === '' ? '{}' : JSON.stringify(JSON5.parse(manifestJsonOverride.value)),
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance(true);
|
fetchServerMetadata(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ import FormSplit from '@/components/form/split.vue';
|
||||||
import FormSection from '@/components/form/section.vue';
|
import FormSection from '@/components/form/section.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { fetchInstance, instance } from '@/instance.js';
|
import { fetchServerMetadata } from '@/server-metadata.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
|
@ -99,10 +99,11 @@ async function init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function testEmail() {
|
async function testEmail() {
|
||||||
|
const serverMetadata = await fetchServerMetadata();
|
||||||
const { canceled, result: destination } = await os.inputText({
|
const { canceled, result: destination } = await os.inputText({
|
||||||
title: i18n.ts.destination,
|
title: i18n.ts.destination,
|
||||||
type: 'email',
|
type: 'email',
|
||||||
default: instance.maintainerEmail ?? '',
|
default: serverMetadata.maintainerEmail ?? '',
|
||||||
placeholder: 'test@example.com',
|
placeholder: 'test@example.com',
|
||||||
minLength: 1,
|
minLength: 1,
|
||||||
});
|
});
|
||||||
|
@ -124,7 +125,7 @@ function save() {
|
||||||
smtpUser: smtpUser.value,
|
smtpUser: smtpUser.value,
|
||||||
smtpPass: smtpPass.value,
|
smtpPass: smtpPass.value,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance(true);
|
fetchServerMetadata(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ import FormSuspense from '@/components/form/suspense.vue';
|
||||||
import FormSection from '@/components/form/section.vue';
|
import FormSection from '@/components/form/section.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { fetchInstance } from '@/instance.js';
|
import { fetchServerMetadata } from '@/server-metadata.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ function save() {
|
||||||
deeplAuthKey: deeplAuthKey.value,
|
deeplAuthKey: deeplAuthKey.value,
|
||||||
deeplIsPro: deeplIsPro.value,
|
deeplIsPro: deeplIsPro.value,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance(true);
|
fetchServerMetadata(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkSpacer :contentMax="700" :marginMin="16">
|
<MkSpacer :contentMax="700" :marginMin="16">
|
||||||
<div class="lxpfedzu _gaps">
|
<div class="lxpfedzu _gaps">
|
||||||
<div class="banner">
|
<div class="banner">
|
||||||
<img :src="instance.iconUrl || '/favicon.ico'" alt="" class="icon"/>
|
<img :src="serverMetadata.iconUrl || '/favicon.ico'" alt="" class="icon"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="_gaps_s">
|
<div class="_gaps_s">
|
||||||
|
@ -31,11 +31,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onActivated, onMounted, onUnmounted, provide, watch, ref, computed } from 'vue';
|
import { onActivated, onMounted, onUnmounted, provide, watch, ref, computed, inject } from 'vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import MkSuperMenu from '@/components/MkSuperMenu.vue';
|
import MkSuperMenu from '@/components/MkSuperMenu.vue';
|
||||||
import MkInfo from '@/components/MkInfo.vue';
|
import MkInfo from '@/components/MkInfo.vue';
|
||||||
import { instance } from '@/instance.js';
|
|
||||||
import { lookup } from '@/scripts/lookup.js';
|
import { lookup } from '@/scripts/lookup.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
|
@ -43,6 +42,8 @@ import { lookupUser, lookupUserByEmail, lookupFile } from '@/scripts/admin-looku
|
||||||
import { PageMetadata, definePageMetadata, provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js';
|
import { PageMetadata, definePageMetadata, provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router/supplier.js';
|
||||||
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const isEmpty = (x: string | null) => x == null || x === '';
|
const isEmpty = (x: string | null) => x == null || x === '';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
@ -61,10 +62,10 @@ const narrow = ref(false);
|
||||||
const view = ref(null);
|
const view = ref(null);
|
||||||
const el = ref<HTMLDivElement | null>(null);
|
const el = ref<HTMLDivElement | null>(null);
|
||||||
const pageProps = ref({});
|
const pageProps = ref({});
|
||||||
const noMaintainerInformation = computed(() => isEmpty(instance.maintainerName) || isEmpty(instance.maintainerEmail));
|
const noMaintainerInformation = computed(() => isEmpty(serverMetadata.maintainerName) || isEmpty(serverMetadata.maintainerEmail));
|
||||||
const noBotProtection = computed(() => !instance.disableRegistration && !instance.enableHcaptcha && !instance.enableRecaptcha && !instance.enableTurnstile && !instance.enableMcaptcha);
|
const noBotProtection = computed(() => !serverMetadata.disableRegistration && !serverMetadata.enableHcaptcha && !serverMetadata.enableRecaptcha && !serverMetadata.enableTurnstile && !serverMetadata.enableMcaptcha);
|
||||||
const noEmailServer = computed(() => !instance.enableEmail);
|
const noEmailServer = computed(() => !serverMetadata.enableEmail);
|
||||||
const noInquiryUrl = computed(() => isEmpty(instance.inquiryUrl));
|
const noInquiryUrl = computed(() => isEmpty(serverMetadata.inquiryUrl));
|
||||||
const thereIsUnresolvedAbuseReport = ref(false);
|
const thereIsUnresolvedAbuseReport = ref(false);
|
||||||
const currentPage = computed(() => router.currentRef.value.child);
|
const currentPage = computed(() => router.currentRef.value.child);
|
||||||
|
|
||||||
|
@ -88,7 +89,7 @@ const menuDef = computed(() => [{
|
||||||
icon: 'ti ti-search',
|
icon: 'ti ti-search',
|
||||||
text: i18n.ts.lookup,
|
text: i18n.ts.lookup,
|
||||||
action: adminLookup,
|
action: adminLookup,
|
||||||
}, ...(instance.disableRegistration ? [{
|
}, ...(serverMetadata.disableRegistration ? [{
|
||||||
type: 'button',
|
type: 'button',
|
||||||
icon: 'ti ti-user-plus',
|
icon: 'ti ti-user-plus',
|
||||||
text: i18n.ts.createInviteCode,
|
text: i18n.ts.createInviteCode,
|
||||||
|
|
|
@ -38,7 +38,7 @@ import MkTextarea from '@/components/MkTextarea.vue';
|
||||||
import FormSuspense from '@/components/form/suspense.vue';
|
import FormSuspense from '@/components/form/suspense.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { fetchInstance } from '@/instance.js';
|
import { fetchServerMetadata } from '@/server-metadata.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ function save() {
|
||||||
mediaSilencedHosts: mediaSilencedHosts.value.split('\n') || [],
|
mediaSilencedHosts: mediaSilencedHosts.value.split('\n') || [],
|
||||||
|
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance(true);
|
fetchServerMetadata(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,7 @@ import MkTextarea from '@/components/MkTextarea.vue';
|
||||||
import FormSuspense from '@/components/form/suspense.vue';
|
import FormSuspense from '@/components/form/suspense.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { fetchInstance } from '@/instance.js';
|
import { fetchServerMetadata } from '@/server-metadata.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
|
@ -119,7 +119,7 @@ function save() {
|
||||||
hiddenTags: hiddenTags.value.split('\n'),
|
hiddenTags: hiddenTags.value.split('\n'),
|
||||||
preservedUsernames: preservedUsernames.value.split('\n'),
|
preservedUsernames: preservedUsernames.value.split('\n'),
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance(true);
|
fetchServerMetadata(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,7 @@ import FormSuspense from '@/components/form/suspense.vue';
|
||||||
import FormSplit from '@/components/form/split.vue';
|
import FormSplit from '@/components/form/split.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { fetchInstance } from '@/instance.js';
|
import { fetchServerMetadata } from '@/server-metadata.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
|
@ -143,7 +143,7 @@ function save() {
|
||||||
objectStorageSetPublicRead: objectStorageSetPublicRead.value,
|
objectStorageSetPublicRead: objectStorageSetPublicRead.value,
|
||||||
objectStorageS3ForcePathStyle: objectStorageS3ForcePathStyle.value,
|
objectStorageS3ForcePathStyle: objectStorageS3ForcePathStyle.value,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance(true);
|
fetchServerMetadata(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ import XHeader from './_header_.vue';
|
||||||
import FormSuspense from '@/components/form/suspense.vue';
|
import FormSuspense from '@/components/form/suspense.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { fetchInstance } from '@/instance.js';
|
import { fetchServerMetadata } from '@/server-metadata.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import MkSwitch from '@/components/MkSwitch.vue';
|
import MkSwitch from '@/components/MkSwitch.vue';
|
||||||
|
@ -73,7 +73,7 @@ function save() {
|
||||||
enableChartsForRemoteUser: enableChartsForRemoteUser.value,
|
enableChartsForRemoteUser: enableChartsForRemoteUser.value,
|
||||||
enableChartsForFederatedInstances: enableChartsForFederatedInstances.value,
|
enableChartsForFederatedInstances: enableChartsForFederatedInstances.value,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance(true);
|
fetchServerMetadata(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ import MkInfo from '@/components/MkInfo.vue';
|
||||||
import FormSuspense from '@/components/form/suspense.vue';
|
import FormSuspense from '@/components/form/suspense.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { fetchInstance } from '@/instance.js';
|
import { fetchServerMetadata } from '@/server-metadata.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ function save() {
|
||||||
os.apiWithDialog('admin/update-meta', {
|
os.apiWithDialog('admin/update-meta', {
|
||||||
proxyAccountId: proxyAccountId.value,
|
proxyAccountId: proxyAccountId.value,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance(true);
|
fetchServerMetadata(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -596,7 +596,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { watch, ref, computed } from 'vue';
|
import { watch, ref, computed, inject } from 'vue';
|
||||||
import { throttle } from 'throttle-debounce';
|
import { throttle } from 'throttle-debounce';
|
||||||
import RolesEditorFormula from './RolesEditorFormula.vue';
|
import RolesEditorFormula from './RolesEditorFormula.vue';
|
||||||
import MkInput from '@/components/MkInput.vue';
|
import MkInput from '@/components/MkInput.vue';
|
||||||
|
@ -609,9 +609,10 @@ import MkRange from '@/components/MkRange.vue';
|
||||||
import FormSlot from '@/components/form/slot.vue';
|
import FormSlot from '@/components/form/slot.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { ROLE_POLICIES } from '@/const.js';
|
import { ROLE_POLICIES } from '@/const.js';
|
||||||
import { instance } from '@/instance.js';
|
|
||||||
import { deepClone } from '@/scripts/clone.js';
|
import { deepClone } from '@/scripts/clone.js';
|
||||||
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: 'update:modelValue', v: any): void;
|
(ev: 'update:modelValue', v: any): void;
|
||||||
}>();
|
}>();
|
||||||
|
@ -629,7 +630,7 @@ for (const ROLE_POLICY of ROLE_POLICIES) {
|
||||||
role.value.policies[ROLE_POLICY] = {
|
role.value.policies[ROLE_POLICY] = {
|
||||||
useDefault: true,
|
useDefault: true,
|
||||||
priority: 0,
|
priority: 0,
|
||||||
value: instance.policies[ROLE_POLICY],
|
value: serverMetadata.policies[ROLE_POLICY],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkPagination :pagination="usersPagination">
|
<MkPagination :pagination="usersPagination">
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img :src="infoImageUrl" class="_ghost"/>
|
<img v-if="serverMetadata.infoImageUrl" :src="serverMetadata.infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.noUsers }}</div>
|
<div>{{ i18n.ts.noUsers }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -74,7 +74,8 @@ 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 { inject } from 'vue';
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router/supplier.js';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
|
@ -251,7 +251,7 @@ import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { instance, fetchInstance } from '@/instance.js';
|
import { instance, fetchServerMetadata } from '@/server-metadata.js';
|
||||||
import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
||||||
import { ROLE_POLICIES } from '@/const.js';
|
import { ROLE_POLICIES } from '@/const.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router/supplier.js';
|
||||||
|
@ -275,7 +275,7 @@ async function updateBaseRole() {
|
||||||
await os.apiWithDialog('admin/roles/update-default-policies', {
|
await os.apiWithDialog('admin/roles/update-default-policies', {
|
||||||
policies,
|
policies,
|
||||||
});
|
});
|
||||||
fetchInstance(true);
|
fetchServerMetadata(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function create() {
|
function create() {
|
||||||
|
|
|
@ -138,7 +138,7 @@ import MkButton from '@/components/MkButton.vue';
|
||||||
import MkTextarea from '@/components/MkTextarea.vue';
|
import MkTextarea from '@/components/MkTextarea.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { fetchInstance } from '@/instance.js';
|
import { fetchServerMetadata } from '@/server-metadata.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
|
|
||||||
|
@ -205,7 +205,7 @@ function save() {
|
||||||
truemailAuthKey: truemailAuthKey.value,
|
truemailAuthKey: truemailAuthKey.value,
|
||||||
bannedEmailDomains: bannedEmailDomains.value.split('\n'),
|
bannedEmailDomains: bannedEmailDomains.value.split('\n'),
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance(true);
|
fetchServerMetadata(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,24 +41,26 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineAsyncComponent, ref, computed } from 'vue';
|
import { defineAsyncComponent, ref, computed, inject } from 'vue';
|
||||||
import XHeader from './_header_.vue';
|
import XHeader from './_header_.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { fetchInstance, instance } from '@/instance.js';
|
import { fetchServerMetadata } from '@/server-metadata.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import MkInput from '@/components/MkInput.vue';
|
import MkInput from '@/components/MkInput.vue';
|
||||||
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const Sortable = defineAsyncComponent(() => import('vuedraggable').then(x => x.default));
|
const Sortable = defineAsyncComponent(() => import('vuedraggable').then(x => x.default));
|
||||||
|
|
||||||
const serverRules = ref<string[]>(instance.serverRules);
|
const serverRules = ref<string[]>(serverMetadata.serverRules);
|
||||||
|
|
||||||
const save = async () => {
|
const save = async () => {
|
||||||
await os.apiWithDialog('admin/update-meta', {
|
await os.apiWithDialog('admin/update-meta', {
|
||||||
serverRules: serverRules.value,
|
serverRules: serverRules.value,
|
||||||
});
|
});
|
||||||
fetchInstance(true);
|
fetchServerMetadata(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const remove = (index: number): void => {
|
const remove = (index: number): void => {
|
||||||
|
|
|
@ -40,7 +40,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template #caption>{{ i18n.ts.repositoryUrlDescription }}</template>
|
<template #caption>{{ i18n.ts.repositoryUrlDescription }}</template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
|
|
||||||
<MkInfo v-if="!instance.providesTarball && !repositoryUrl" warn>
|
<MkInfo v-if="!serverMetadata.providesTarball && !repositoryUrl" warn>
|
||||||
{{ i18n.ts.repositoryUrlOrTarballRequired }}
|
{{ i18n.ts.repositoryUrlOrTarballRequired }}
|
||||||
</MkInfo>
|
</MkInfo>
|
||||||
|
|
||||||
|
@ -205,7 +205,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed, inject } from 'vue';
|
||||||
import XHeader from './_header_.vue';
|
import XHeader from './_header_.vue';
|
||||||
import MkSwitch from '@/components/MkSwitch.vue';
|
import MkSwitch from '@/components/MkSwitch.vue';
|
||||||
import MkInput from '@/components/MkInput.vue';
|
import MkInput from '@/components/MkInput.vue';
|
||||||
|
@ -216,13 +216,15 @@ import FormSplit from '@/components/form/split.vue';
|
||||||
import FormSuspense from '@/components/form/suspense.vue';
|
import FormSuspense from '@/components/form/suspense.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { fetchInstance, instance } from '@/instance.js';
|
import { fetchServerMetadata } from '@/server-metadata.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
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 MkSelect from '@/components/MkSelect.vue';
|
import MkSelect from '@/components/MkSelect.vue';
|
||||||
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const name = ref<string | null>(null);
|
const name = ref<string | null>(null);
|
||||||
const shortName = ref<string | null>(null);
|
const shortName = ref<string | null>(null);
|
||||||
const description = ref<string | null>(null);
|
const description = ref<string | null>(null);
|
||||||
|
@ -310,7 +312,7 @@ async function save() {
|
||||||
urlPreviewSummaryProxyUrl: urlPreviewSummaryProxyUrl.value,
|
urlPreviewSummaryProxyUrl: urlPreviewSummaryProxyUrl.value,
|
||||||
});
|
});
|
||||||
|
|
||||||
fetchInstance(true);
|
fetchServerMetadata(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const headerTabs = computed(() => []);
|
const headerTabs = computed(() => []);
|
||||||
|
|
|
@ -9,16 +9,18 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<MkSpacer :contentMax="500">
|
<MkSpacer :contentMax="500">
|
||||||
<div class="_gaps">
|
<div class="_gaps">
|
||||||
<MkAd v-for="ad in instance.ads" :key="ad.id" :specify="ad"/>
|
<MkAd v-for="ad in serverMetadata.ads" :key="ad.id" :specify="ad"/>
|
||||||
</div>
|
</div>
|
||||||
</MkSpacer>
|
</MkSpacer>
|
||||||
</MkStickyContainer>
|
</MkStickyContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { inject } from 'vue';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
definePageMetadata(() => ({
|
definePageMetadata(() => ({
|
||||||
title: i18n.ts.ads,
|
title: i18n.ts.ads,
|
||||||
|
|
|
@ -8,24 +8,24 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template #header><MkPageHeader/></template>
|
<template #header><MkPageHeader/></template>
|
||||||
<MkSpacer :contentMax="600" :marginMin="20">
|
<MkSpacer :contentMax="600" :marginMin="20">
|
||||||
<div class="_gaps_m">
|
<div class="_gaps_m">
|
||||||
<MkKeyValue :copy="instance.maintainerName">
|
<MkKeyValue :copy="serverMetadata.maintainerName">
|
||||||
<template #key>{{ i18n.ts.administrator }}</template>
|
<template #key>{{ i18n.ts.administrator }}</template>
|
||||||
<template #value>
|
<template #value>
|
||||||
<template v-if="instance.maintainerName">{{ instance.maintainerName }}</template>
|
<template v-if="serverMetadata.maintainerName">{{ serverMetadata.maintainerName }}</template>
|
||||||
<span v-else style="opacity: 0.7;">({{ i18n.ts.none }})</span>
|
<span v-else style="opacity: 0.7;">({{ i18n.ts.none }})</span>
|
||||||
</template>
|
</template>
|
||||||
</MkKeyValue>
|
</MkKeyValue>
|
||||||
<MkKeyValue :copy="instance.maintainerEmail">
|
<MkKeyValue :copy="serverMetadata.maintainerEmail">
|
||||||
<template #key>{{ i18n.ts.contact }}</template>
|
<template #key>{{ i18n.ts.contact }}</template>
|
||||||
<template #value>
|
<template #value>
|
||||||
<template v-if="instance.maintainerEmail">{{ instance.maintainerEmail }}</template>
|
<template v-if="serverMetadata.maintainerEmail">{{ serverMetadata.maintainerEmail }}</template>
|
||||||
<span v-else style="opacity: 0.7;">({{ i18n.ts.none }})</span>
|
<span v-else style="opacity: 0.7;">({{ i18n.ts.none }})</span>
|
||||||
</template>
|
</template>
|
||||||
</MkKeyValue>
|
</MkKeyValue>
|
||||||
<MkKeyValue :copy="instance.inquiryUrl">
|
<MkKeyValue :copy="serverMetadata.inquiryUrl">
|
||||||
<template #key>{{ i18n.ts.inquiry }}</template>
|
<template #key>{{ i18n.ts.inquiry }}</template>
|
||||||
<template #value>
|
<template #value>
|
||||||
<MkLink v-if="instance.inquiryUrl" :url="instance.inquiryUrl" target="_blank">{{ instance.inquiryUrl }}</MkLink>
|
<MkLink v-if="serverMetadata.inquiryUrl" :url="serverMetadata.inquiryUrl" target="_blank">{{ serverMetadata.inquiryUrl }}</MkLink>
|
||||||
<span v-else style="opacity: 0.7;">({{ i18n.ts.none }})</span>
|
<span v-else style="opacity: 0.7;">({{ i18n.ts.none }})</span>
|
||||||
</template>
|
</template>
|
||||||
</MkKeyValue>
|
</MkKeyValue>
|
||||||
|
@ -35,12 +35,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { inject } from 'vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import MkKeyValue from '@/components/MkKeyValue.vue';
|
import MkKeyValue from '@/components/MkKeyValue.vue';
|
||||||
import MkLink from '@/components/MkLink.vue';
|
import MkLink from '@/components/MkLink.vue';
|
||||||
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
definePageMetadata(() => ({
|
definePageMetadata(() => ({
|
||||||
title: i18n.ts.inquiry,
|
title: i18n.ts.inquiry,
|
||||||
icon: 'ti ti-help-circle',
|
icon: 'ti ti-help-circle',
|
||||||
|
|
|
@ -69,7 +69,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="_fullinfo">
|
<div v-else class="_fullinfo">
|
||||||
<img :src="infoImageUrl" class="_ghost"/>
|
<img v-if="serverMetadata.infoImageUrl" :src="serverMetadata.infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.nothing }}</div>
|
<div>{{ i18n.ts.nothing }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -82,7 +82,8 @@ 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 { inject } from 'vue';
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
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 '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
|
@ -99,12 +100,12 @@ const file = ref<Misskey.entities.DriveFile>();
|
||||||
const folderHierarchy = computed(() => {
|
const folderHierarchy = computed(() => {
|
||||||
if (!file.value) return [i18n.ts.drive];
|
if (!file.value) return [i18n.ts.drive];
|
||||||
const folderNames = [i18n.ts.drive];
|
const folderNames = [i18n.ts.drive];
|
||||||
|
|
||||||
function get(folder: Misskey.entities.DriveFolder) {
|
function get(folder: Misskey.entities.DriveFolder) {
|
||||||
if (folder.parent) get(folder.parent);
|
if (folder.parent) get(folder.parent);
|
||||||
folderNames.push(folder.name);
|
folderNames.push(folder.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file.value.folder) get(file.value.folder);
|
if (file.value.folder) get(file.value.folder);
|
||||||
return folderNames;
|
return folderNames;
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkPagination :pagination="pagination">
|
<MkPagination :pagination="pagination">
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img :src="infoImageUrl" class="_ghost"/>
|
<img v-if="serverMetadata.infoImageUrl" :src="serverMetadata.infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.noNotes }}</div>
|
<div>{{ i18n.ts.noNotes }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -31,7 +31,8 @@ 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 { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
import { inject } from 'vue';
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const pagination = {
|
const pagination = {
|
||||||
endpoint: 'i/favorites' as const,
|
endpoint: 'i/favorites' as const,
|
||||||
|
|
|
@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkPagination ref="paginationComponent" :pagination="pagination">
|
<MkPagination ref="paginationComponent" :pagination="pagination">
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img :src="infoImageUrl" class="_ghost"/>
|
<img v-if="serverMetadata.infoImageUrl" :src="serverMetadata.infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.noFollowRequests }}</div>
|
<div>{{ i18n.ts.noFollowRequests }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -44,7 +44,8 @@ import { userPage, acct } from '@/filters/user.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
import { inject } from 'vue';
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const paginationComponent = shallowRef<InstanceType<typeof MkPagination>>();
|
const paginationComponent = shallowRef<InstanceType<typeof MkPagination>>();
|
||||||
|
|
||||||
|
|
|
@ -132,7 +132,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, computed, watch } from 'vue';
|
import { ref, computed, watch, inject } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import MkChart from '@/components/MkChart.vue';
|
import MkChart from '@/components/MkChart.vue';
|
||||||
import MkObjectView from '@/components/MkObjectView.vue';
|
import MkObjectView from '@/components/MkObjectView.vue';
|
||||||
|
@ -152,10 +152,11 @@ import { i18n } from '@/i18n.js';
|
||||||
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||||
import MkPagination from '@/components/MkPagination.vue';
|
import MkPagination from '@/components/MkPagination.vue';
|
||||||
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
|
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
|
||||||
import { getProxiedImageUrlNullable } from '@/scripts/media-proxy.js';
|
|
||||||
import { dateString } from '@/filters/date.js';
|
import { dateString } from '@/filters/date.js';
|
||||||
import MkTextarea from '@/components/MkTextarea.vue';
|
import MkTextarea from '@/components/MkTextarea.vue';
|
||||||
|
|
||||||
|
const mediaProxy = inject('mediaProxy');
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
host: string;
|
host: string;
|
||||||
}>();
|
}>();
|
||||||
|
@ -198,7 +199,7 @@ async function fetch(): Promise<void> {
|
||||||
isBlocked.value = instance.value?.isBlocked ?? false;
|
isBlocked.value = instance.value?.isBlocked ?? false;
|
||||||
isSilenced.value = instance.value?.isSilenced ?? false;
|
isSilenced.value = instance.value?.isSilenced ?? false;
|
||||||
isMediaSilenced.value = instance.value?.isMediaSilenced ?? false;
|
isMediaSilenced.value = instance.value?.isMediaSilenced ?? false;
|
||||||
faviconUrl.value = getProxiedImageUrlNullable(instance.value?.faviconUrl, 'preview') ?? getProxiedImageUrlNullable(instance.value?.iconUrl, 'preview');
|
faviconUrl.value = mediaProxy.getProxiedImageUrlNullable(instance.value?.faviconUrl, 'preview') ?? mediaProxy.getProxiedImageUrlNullable(instance.value?.iconUrl, 'preview');
|
||||||
moderationNote.value = instance.value?.moderationNote ?? '';
|
moderationNote.value = instance.value?.moderationNote ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template #header>
|
<template #header>
|
||||||
<MkPageHeader/>
|
<MkPageHeader/>
|
||||||
</template>
|
</template>
|
||||||
<MKSpacer v-if="!instance.disableRegistration || !($i && ($i.isAdmin || $i.policies.canInvite))" :contentMax="1200">
|
<MKSpacer v-if="!serverMetadata.disableRegistration || !($i && ($i.isAdmin || $i.policies.canInvite))" :contentMax="1200">
|
||||||
<div :class="$style.root">
|
<div :class="$style.root">
|
||||||
<img :class="$style.img" :src="serverErrorImageUrl" class="_ghost"/>
|
<img v-if="serverMetadata.serverErrorImageUrl" :class="$style.img" :src="serverMetadata.serverErrorImageUrl" class="_ghost"/>
|
||||||
<div :class="$style.text">
|
<div :class="$style.text">
|
||||||
<i class="ti ti-alert-triangle"></i>
|
<i class="ti ti-alert-triangle"></i>
|
||||||
{{ i18n.ts.nothing }}
|
{{ i18n.ts.nothing }}
|
||||||
|
@ -36,7 +36,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, ref, shallowRef } from 'vue';
|
import { computed, inject, ref, shallowRef } from 'vue';
|
||||||
import type * as Misskey from 'misskey-js';
|
import type * as Misskey from 'misskey-js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
|
@ -45,13 +45,14 @@ import MkButton from '@/components/MkButton.vue';
|
||||||
import MkPagination, { Paging } from '@/components/MkPagination.vue';
|
import MkPagination, { Paging } from '@/components/MkPagination.vue';
|
||||||
import MkInviteCode from '@/components/MkInviteCode.vue';
|
import MkInviteCode from '@/components/MkInviteCode.vue';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { serverErrorImageUrl, instance } from '@/instance.js';
|
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const pagingComponent = shallowRef<InstanceType<typeof MkPagination>>();
|
const pagingComponent = shallowRef<InstanceType<typeof MkPagination>>();
|
||||||
const currentInviteLimit = ref<null | number>(null);
|
const currentInviteLimit = ref<null | number>(null);
|
||||||
const inviteLimit = (($i != null && $i.policies.inviteLimit) || (($i == null && instance.policies.inviteLimit))) as number;
|
const inviteLimit = (($i != null && $i.policies.inviteLimit) || (($i == null && serverMetadata.policies.inviteLimit))) as number;
|
||||||
const inviteLimitCycle = (($i != null && $i.policies.inviteLimitCycle) || ($i == null && instance.policies.inviteLimitCycle)) as number;
|
const inviteLimitCycle = (($i != null && $i.policies.inviteLimitCycle) || ($i == null && serverMetadata.policies.inviteLimitCycle)) as number;
|
||||||
|
|
||||||
const pagination: Paging = {
|
const pagination: Paging = {
|
||||||
endpoint: 'invite/list' as const,
|
endpoint: 'invite/list' as const,
|
||||||
|
|
|
@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
||||||
<MKSpacer v-if="!(typeof error === 'undefined')" :contentMax="1200">
|
<MKSpacer v-if="!(typeof error === 'undefined')" :contentMax="1200">
|
||||||
<div :class="$style.root">
|
<div :class="$style.root">
|
||||||
<img :class="$style.img" :src="serverErrorImageUrl" class="_ghost"/>
|
<img v-if="serverMetadata.serverErrorImageUrl" :class="$style.img" :src="serverMetadata.serverErrorImageUrl" class="_ghost"/>
|
||||||
<p :class="$style.text">
|
<p :class="$style.text">
|
||||||
<i class="ti ti-alert-triangle"></i>
|
<i class="ti ti-alert-triangle"></i>
|
||||||
{{ i18n.ts.nothing }}
|
{{ i18n.ts.nothing }}
|
||||||
|
@ -34,7 +34,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { watch, computed, ref } from 'vue';
|
import { watch, computed, ref, inject } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
|
@ -43,7 +43,8 @@ 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 { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { serverErrorImageUrl } from '@/instance.js';
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
listId: string;
|
listId: string;
|
||||||
|
|
|
@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div>
|
<div>
|
||||||
<div v-if="antennas.length === 0" class="empty">
|
<div v-if="antennas.length === 0" class="empty">
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img :src="infoImageUrl" class="_ghost"/>
|
<img v-if="serverMetadata.infoImageUrl" :src="serverMetadata.infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.nothing }}</div>
|
<div>{{ i18n.ts.nothing }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -33,7 +33,8 @@ import MkButton from '@/components/MkButton.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { antennasCache } from '@/cache.js';
|
import { antennasCache } from '@/cache.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
import { inject } from 'vue';
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const antennas = computed(() => antennasCache.value.value ?? []);
|
const antennas = computed(() => antennasCache.value.value ?? []);
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div class="_gaps">
|
<div class="_gaps">
|
||||||
<div v-if="items.length === 0" class="empty">
|
<div v-if="items.length === 0" class="empty">
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img :src="infoImageUrl" class="_ghost"/>
|
<img v-if="serverMetadata.infoImageUrl" :src="serverMetadata.infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.nothing }}</div>
|
<div>{{ i18n.ts.nothing }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -36,7 +36,8 @@ import * as os from '@/os.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { userListsCache } from '@/cache.js';
|
import { userListsCache } from '@/cache.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
import { inject } from 'vue';
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
import { signinRequired } from '@/account.js';
|
import { signinRequired } from '@/account.js';
|
||||||
|
|
||||||
const $i = signinRequired();
|
const $i = signinRequired();
|
||||||
|
|
|
@ -6,18 +6,19 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img :src="notFoundImageUrl" class="_ghost"/>
|
<img v-if="serverMetadata.notFoundImageUrl" :src="serverMetadata.notFoundImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.notFoundDescription }}</div>
|
<div>{{ i18n.ts.notFoundDescription }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed } from 'vue';
|
import { computed, inject } from 'vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { pleaseLogin } from '@/scripts/please-login.js';
|
import { pleaseLogin } from '@/scripts/please-login.js';
|
||||||
import { notFoundImageUrl } from '@/instance.js';
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
showLoginPopup?: boolean;
|
showLoginPopup?: boolean;
|
||||||
|
|
|
@ -28,7 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<img
|
<img
|
||||||
v-else-if="instance.backgroundImageUrl || instance.bannerUrl"
|
v-else-if="instance.backgroundImageUrl || instance.bannerUrl"
|
||||||
:class="[$style.pageBannerBg, $style.pageBannerBgFallback1]"
|
:class="[$style.pageBannerBg, $style.pageBannerBgFallback1]"
|
||||||
:src="getStaticImageUrl(instance.backgroundImageUrl ?? instance.bannerUrl!)"
|
:src="mediaProxy.getStaticImageUrl(instance.backgroundImageUrl ?? instance.bannerUrl!)"
|
||||||
/>
|
/>
|
||||||
<div v-else :class="[$style.pageBannerBg, $style.pageBannerBgFallback2]"></div>
|
<div v-else :class="[$style.pageBannerBg, $style.pageBannerBgFallback2]"></div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -98,7 +98,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, watch, ref, defineAsyncComponent } from 'vue';
|
import { computed, watch, ref, defineAsyncComponent, inject } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import XPage from '@/components/page/page.vue';
|
import XPage from '@/components/page/page.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
|
@ -117,12 +117,13 @@ import { pageViewInterruptors, defaultStore } from '@/store.js';
|
||||||
import { deepClone } from '@/scripts/clone.js';
|
import { deepClone } from '@/scripts/clone.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import { isSupportShare } from '@/scripts/navigator.js';
|
import { isSupportShare } from '@/scripts/navigator.js';
|
||||||
import { instance } from '@/instance.js';
|
|
||||||
import { getStaticImageUrl } from '@/scripts/media-proxy.js';
|
|
||||||
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router/supplier.js';
|
||||||
import { MenuItem } from '@/types/menu';
|
import { MenuItem } from '@/types/menu';
|
||||||
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
const mediaProxy = inject('mediaProxy');
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
|
|
@ -20,7 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<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">
|
<div v-else-if="!visible" class="_fullinfo">
|
||||||
<img :src="infoImageUrl" class="_ghost"/>
|
<img v-if="serverMetadata.infoImageUrl" :src="serverMetadata.infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.nothing }}</div>
|
<div>{{ i18n.ts.nothing }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -28,7 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkSpacer v-else-if="tab === 'timeline'" :contentMax="700">
|
<MkSpacer v-else-if="tab === 'timeline'" :contentMax="700">
|
||||||
<MkTimeline v-if="visible" ref="timeline" src="role" :role="props.role"/>
|
<MkTimeline v-if="visible" ref="timeline" src="role" :role="props.role"/>
|
||||||
<div v-else-if="!visible" class="_fullinfo">
|
<div v-else-if="!visible" class="_fullinfo">
|
||||||
<img :src="infoImageUrl" class="_ghost"/>
|
<img v-if="serverMetadata.infoImageUrl" :src="serverMetadata.infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.nothing }}</div>
|
<div>{{ i18n.ts.nothing }}</div>
|
||||||
</div>
|
</div>
|
||||||
</MkSpacer>
|
</MkSpacer>
|
||||||
|
@ -36,7 +36,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, watch, ref } from 'vue';
|
import { computed, watch, ref, inject } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import MkUserList from '@/components/MkUserList.vue';
|
import MkUserList from '@/components/MkUserList.vue';
|
||||||
|
@ -44,7 +44,8 @@ import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import MkTimeline from '@/components/MkTimeline.vue';
|
import MkTimeline from '@/components/MkTimeline.vue';
|
||||||
import { instanceName } from '@/config.js';
|
import { instanceName } from '@/config.js';
|
||||||
import { serverErrorImageUrl, infoImageUrl } from '@/instance.js';
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
role: string;
|
role: string;
|
||||||
|
|
|
@ -51,7 +51,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, ref, toRef, watch } from 'vue';
|
import { computed, inject, ref, toRef, watch } from 'vue';
|
||||||
import type { UserDetailed } from 'misskey-js/entities.js';
|
import type { UserDetailed } from 'misskey-js/entities.js';
|
||||||
import type { Paging } from '@/components/MkPagination.vue';
|
import type { Paging } from '@/components/MkPagination.vue';
|
||||||
import MkNotes from '@/components/MkNotes.vue';
|
import MkNotes from '@/components/MkNotes.vue';
|
||||||
|
@ -66,7 +66,8 @@ import { useRouter } from '@/router/supplier.js';
|
||||||
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||||
import MkRadios from '@/components/MkRadios.vue';
|
import MkRadios from '@/components/MkRadios.vue';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import { instance } from '@/instance.js';
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
query?: string;
|
query?: string;
|
||||||
|
@ -87,7 +88,7 @@ const notePagination = ref<Paging>();
|
||||||
const user = ref<UserDetailed | null>(null);
|
const user = ref<UserDetailed | null>(null);
|
||||||
const hostInput = ref(toRef(props, 'host').value);
|
const hostInput = ref(toRef(props, 'host').value);
|
||||||
|
|
||||||
const noteSearchableScope = instance.noteSearchableScope ?? 'local';
|
const noteSearchableScope = serverMetadata.noteSearchableScope ?? 'local';
|
||||||
|
|
||||||
const hostSelect = ref<'all' | 'local' | 'specified'>('all');
|
const hostSelect = ref<'all' | 'local' | 'specified'>('all');
|
||||||
|
|
||||||
|
@ -121,7 +122,7 @@ if (props.userId != null) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectUser() {
|
function selectUser() {
|
||||||
os.selectUser({ includeSelf: true, localOnly: instance.noteSearchableScope === 'local' }).then(_user => {
|
os.selectUser({ includeSelf: true, localOnly: serverMetadata.noteSearchableScope === 'local' }).then(_user => {
|
||||||
user.value = _user;
|
user.value = _user;
|
||||||
hostInput.value = _user.host ?? '';
|
hostInput.value = _user.host ?? '';
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs">
|
<MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs">
|
||||||
<MkSpacer v-if="tab === 'note'" key="note" :contentMax="800">
|
<MkSpacer v-if="tab === 'note'" key="note" :contentMax="800">
|
||||||
<div v-if="notesSearchAvailable || ignoreNotesSearchAvailable">
|
<div v-if="isNotesSearchAvailable(serverMetadata) || ignoreNotesSearchAvailable">
|
||||||
<XNote v-bind="props"/>
|
<XNote v-bind="props"/>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
|
@ -25,13 +25,15 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, defineAsyncComponent, ref, toRef } from 'vue';
|
import { computed, defineAsyncComponent, inject, ref, toRef } from 'vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { notesSearchAvailable } from '@/scripts/check-permissions.js';
|
import { isNotesSearchAvailable } from '@/scripts/check-permissions.js';
|
||||||
import MkInfo from '@/components/MkInfo.vue';
|
import MkInfo from '@/components/MkInfo.vue';
|
||||||
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
|
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
|
||||||
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
query?: string,
|
query?: string,
|
||||||
userId?: string,
|
userId?: string,
|
||||||
|
|
|
@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<FormPagination ref="list" :pagination="pagination">
|
<FormPagination ref="list" :pagination="pagination">
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img :src="infoImageUrl" class="_ghost"/>
|
<img v-if="serverMetadata.infoImageUrl" :src="serverMetadata.infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.nothing }}</div>
|
<div>{{ i18n.ts.nothing }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -52,7 +52,8 @@ import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.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 { infoImageUrl } from '@/instance.js';
|
import { inject } from 'vue';
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const list = ref<InstanceType<typeof FormPagination>>();
|
const list = ref<InstanceType<typeof FormPagination>>();
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="instance.enableEmail" class="_gaps_m">
|
<div v-if="serverMetadata.enableEmail" class="_gaps_m">
|
||||||
<FormSection first>
|
<FormSection first>
|
||||||
<template #label>{{ i18n.ts.emailAddress }}</template>
|
<template #label>{{ i18n.ts.emailAddress }}</template>
|
||||||
<MkInput v-model="emailAddress" type="email" manualSave>
|
<MkInput v-model="emailAddress" type="email" manualSave>
|
||||||
|
@ -42,13 +42,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
</FormSection>
|
</FormSection>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!instance.enableEmail" class="_gaps_m">
|
<div v-if="!serverMetadata.enableEmail" class="_gaps_m">
|
||||||
<MkInfo>{{ i18n.ts.emailNotSupported }}</MkInfo>
|
<MkInfo>{{ i18n.ts.emailNotSupported }}</MkInfo>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref, watch, computed } from 'vue';
|
import { onMounted, ref, watch, computed, inject } from 'vue';
|
||||||
import FormSection from '@/components/form/section.vue';
|
import FormSection from '@/components/form/section.vue';
|
||||||
import MkInfo from '@/components/MkInfo.vue';
|
import MkInfo from '@/components/MkInfo.vue';
|
||||||
import MkInput from '@/components/MkInput.vue';
|
import MkInput from '@/components/MkInput.vue';
|
||||||
|
@ -58,7 +58,8 @@ import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { signinRequired } from '@/account.js';
|
import { signinRequired } from '@/account.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { instance } from '@/instance.js';
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const $i = signinRequired();
|
const $i = signinRequired();
|
||||||
|
|
||||||
|
|
|
@ -28,17 +28,18 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onActivated, onMounted, onUnmounted, ref, shallowRef, watch } from 'vue';
|
import { computed, inject, onActivated, onMounted, onUnmounted, ref, shallowRef, watch } from 'vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import MkInfo from '@/components/MkInfo.vue';
|
import MkInfo from '@/components/MkInfo.vue';
|
||||||
import MkSuperMenu from '@/components/MkSuperMenu.vue';
|
import MkSuperMenu from '@/components/MkSuperMenu.vue';
|
||||||
import { signout, $i } from '@/account.js';
|
import { signout, $i } from '@/account.js';
|
||||||
import { clearCache } from '@/scripts/clear-cache.js';
|
import { clearCache } from '@/scripts/clear-cache.js';
|
||||||
import { instance } from '@/instance.js';
|
|
||||||
import { PageMetadata, definePageMetadata, provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js';
|
import { PageMetadata, definePageMetadata, provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router/supplier.js';
|
||||||
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const indexInfo = {
|
const indexInfo = {
|
||||||
title: i18n.ts.settings,
|
title: i18n.ts.settings,
|
||||||
icon: 'ti ti-settings',
|
icon: 'ti ti-settings',
|
||||||
|
|
|
@ -33,7 +33,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkPagination :pagination="renoteMutingPagination">
|
<MkPagination :pagination="renoteMutingPagination">
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img :src="infoImageUrl" class="_ghost"/>
|
<img v-if="serverMetadata.infoImageUrl" :src="serverMetadata.infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.noUsers }}</div>
|
<div>{{ i18n.ts.noUsers }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -64,7 +64,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkPagination :pagination="mutingPagination">
|
<MkPagination :pagination="mutingPagination">
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img :src="infoImageUrl" class="_ghost"/>
|
<img v-if="serverMetadata.infoImageUrl" :src="serverMetadata.infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.noUsers }}</div>
|
<div>{{ i18n.ts.noUsers }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -97,7 +97,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkPagination :pagination="blockingPagination">
|
<MkPagination :pagination="blockingPagination">
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img :src="infoImageUrl" class="_ghost"/>
|
<img v-if="serverMetadata.infoImageUrl" :src="serverMetadata.infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.noUsers }}</div>
|
<div>{{ i18n.ts.noUsers }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -136,7 +136,8 @@ import { definePageMetadata } from '@/scripts/page-metadata.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 { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
import { inject } from 'vue';
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
import { signinRequired } from '@/account.js';
|
import { signinRequired } from '@/account.js';
|
||||||
import MkFolder from '@/components/MkFolder.vue';
|
import MkFolder from '@/components/MkFolder.vue';
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, onActivated, ref, watch } from 'vue';
|
import { computed, inject, onActivated, ref, watch } from 'vue';
|
||||||
import JSON5 from 'json5';
|
import JSON5 from 'json5';
|
||||||
import MkSwitch from '@/components/MkSwitch.vue';
|
import MkSwitch from '@/components/MkSwitch.vue';
|
||||||
import MkSelect from '@/components/MkSelect.vue';
|
import MkSelect from '@/components/MkSelect.vue';
|
||||||
|
@ -83,7 +83,6 @@ import { selectFile } from '@/scripts/select-file.js';
|
||||||
import { isDeviceDarkmode } from '@/scripts/is-device-darkmode.js';
|
import { isDeviceDarkmode } from '@/scripts/is-device-darkmode.js';
|
||||||
import { ColdDeviceStorage, defaultStore } from '@/store.js';
|
import { ColdDeviceStorage, defaultStore } from '@/store.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
|
||||||
import { uniqueBy } from '@/scripts/array.js';
|
import { uniqueBy } from '@/scripts/array.js';
|
||||||
import { fetchThemes, getThemes } from '@/theme-store.js';
|
import { fetchThemes, getThemes } from '@/theme-store.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
|
@ -91,6 +90,8 @@ import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { unisonReload } from '@/scripts/unison-reload.js';
|
import { unisonReload } from '@/scripts/unison-reload.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
async function reloadAsk() {
|
async function reloadAsk() {
|
||||||
const { canceled } = await os.confirm({
|
const { canceled } = await os.confirm({
|
||||||
type: 'info',
|
type: 'info',
|
||||||
|
@ -104,10 +105,10 @@ async function reloadAsk() {
|
||||||
const installedThemes = ref(getThemes());
|
const installedThemes = ref(getThemes());
|
||||||
const builtinThemes = getBuiltinThemesRef();
|
const builtinThemes = getBuiltinThemesRef();
|
||||||
|
|
||||||
const instanceDarkTheme = computed(() => instance.defaultDarkTheme ? JSON5.parse(instance.defaultDarkTheme) : null);
|
const instanceDarkTheme = computed(() => serverMetadata.defaultDarkTheme ? JSON5.parse(serverMetadata.defaultDarkTheme) : null);
|
||||||
const installedDarkThemes = computed(() => installedThemes.value.filter(t => t.base === 'dark' || t.kind === 'dark'));
|
const installedDarkThemes = computed(() => installedThemes.value.filter(t => t.base === 'dark' || t.kind === 'dark'));
|
||||||
const builtinDarkThemes = computed(() => builtinThemes.value.filter(t => t.base === 'dark' || t.kind === 'dark'));
|
const builtinDarkThemes = computed(() => builtinThemes.value.filter(t => t.base === 'dark' || t.kind === 'dark'));
|
||||||
const instanceLightTheme = computed(() => instance.defaultLightTheme ? JSON5.parse(instance.defaultLightTheme) : null);
|
const instanceLightTheme = computed(() => serverMetadata.defaultLightTheme ? JSON5.parse(serverMetadata.defaultLightTheme) : null);
|
||||||
const installedLightThemes = computed(() => installedThemes.value.filter(t => t.base === 'light' || t.kind === 'light'));
|
const installedLightThemes = computed(() => installedThemes.value.filter(t => t.base === 'light' || t.kind === 'light'));
|
||||||
const builtinLightThemes = computed(() => builtinThemes.value.filter(t => t.base === 'light' || t.kind === 'light'));
|
const builtinLightThemes = computed(() => builtinThemes.value.filter(t => t.base === 'light' || t.kind === 'light'));
|
||||||
const themes = computed(() => uniqueBy([instanceDarkTheme.value, instanceLightTheme.value, ...builtinThemes.value, ...installedThemes.value].filter(x => x != null), theme => theme.id));
|
const themes = computed(() => uniqueBy([instanceDarkTheme.value, instanceLightTheme.value, ...builtinThemes.value, ...installedThemes.value].filter(x => x != null), theme => theme.id));
|
||||||
|
|
|
@ -34,13 +34,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, watch, provide, shallowRef, ref, onMounted, onActivated } from 'vue';
|
import { computed, watch, provide, shallowRef, ref, onMounted, onActivated, inject } from 'vue';
|
||||||
|
import { scroll } from '@@/js/scroll.js';
|
||||||
import type { Tab } from '@/components/global/MkPageHeader.tabs.vue';
|
import type { Tab } from '@/components/global/MkPageHeader.tabs.vue';
|
||||||
|
import type { BasicTimelineType } from '@/timelines.js';
|
||||||
import MkTimeline from '@/components/MkTimeline.vue';
|
import MkTimeline from '@/components/MkTimeline.vue';
|
||||||
import MkInfo from '@/components/MkInfo.vue';
|
import MkInfo from '@/components/MkInfo.vue';
|
||||||
import MkPostForm from '@/components/MkPostForm.vue';
|
import MkPostForm from '@/components/MkPostForm.vue';
|
||||||
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
|
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
|
||||||
import { scroll } from '@@/js/scroll.js';
|
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
|
@ -53,17 +54,18 @@ import { deepMerge } from '@/scripts/merge.js';
|
||||||
import { MenuItem } from '@/types/menu.js';
|
import { MenuItem } from '@/types/menu.js';
|
||||||
import { miLocalStorage } from '@/local-storage.js';
|
import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { availableBasicTimelines, hasWithReplies, isAvailableBasicTimeline, isBasicTimeline, basicTimelineIconClass } from '@/timelines.js';
|
import { availableBasicTimelines, hasWithReplies, isAvailableBasicTimeline, isBasicTimeline, basicTimelineIconClass } from '@/timelines.js';
|
||||||
import type { BasicTimelineType } from '@/timelines.js';
|
|
||||||
|
|
||||||
provide('shouldOmitHeaderTitle', true);
|
provide('shouldOmitHeaderTitle', true);
|
||||||
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
|
||||||
const tlComponent = shallowRef<InstanceType<typeof MkTimeline>>();
|
const tlComponent = shallowRef<InstanceType<typeof MkTimeline>>();
|
||||||
const rootEl = shallowRef<HTMLElement>();
|
const rootEl = shallowRef<HTMLElement>();
|
||||||
|
|
||||||
type TimelinePageSrc = BasicTimelineType | `list:${string}`;
|
type TimelinePageSrc = BasicTimelineType | `list:${string}`;
|
||||||
|
|
||||||
const queue = ref(0);
|
const queue = ref(0);
|
||||||
const srcWhenNotSignin = ref<'local' | 'global'>(isAvailableBasicTimeline('local') ? 'local' : 'global');
|
const srcWhenNotSignin = ref<'local' | 'global'>(isAvailableBasicTimeline(serverMetadata, 'local') ? 'local' : 'global');
|
||||||
const src = computed<TimelinePageSrc>({
|
const src = computed<TimelinePageSrc>({
|
||||||
get: () => ($i ? defaultStore.reactiveState.tl.value.src : srcWhenNotSignin.value),
|
get: () => ($i ? defaultStore.reactiveState.tl.value.src : srcWhenNotSignin.value),
|
||||||
set: (x) => saveSrc(x),
|
set: (x) => saveSrc(x),
|
||||||
|
@ -240,8 +242,8 @@ function closeTutorial(): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
function switchTlIfNeeded() {
|
function switchTlIfNeeded() {
|
||||||
if (isBasicTimeline(src.value) && !isAvailableBasicTimeline(src.value)) {
|
if (isBasicTimeline(src.value) && !isAvailableBasicTimeline(serverMetadata, src.value)) {
|
||||||
src.value = availableBasicTimelines()[0];
|
src.value = availableBasicTimelines(serverMetadata)[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,7 +299,7 @@ const headerTabs = computed(() => [...(defaultStore.reactiveState.pinnedUserList
|
||||||
title: l.name,
|
title: l.name,
|
||||||
icon: 'ti ti-star',
|
icon: 'ti ti-star',
|
||||||
iconOnly: true,
|
iconOnly: true,
|
||||||
}))), ...availableBasicTimelines().map(tl => ({
|
}))), ...availableBasicTimelines(serverMetadata).map(tl => ({
|
||||||
key: tl,
|
key: tl,
|
||||||
title: i18n.ts._timelines[tl],
|
title: i18n.ts._timelines[tl],
|
||||||
icon: basicTimelineIconClass(tl),
|
icon: basicTimelineIconClass(tl),
|
||||||
|
@ -319,7 +321,7 @@ const headerTabs = computed(() => [...(defaultStore.reactiveState.pinnedUserList
|
||||||
onClick: chooseChannel,
|
onClick: chooseChannel,
|
||||||
}] as Tab[]);
|
}] as Tab[]);
|
||||||
|
|
||||||
const headerTabsWhenNotLogin = computed(() => [...availableBasicTimelines().map(tl => ({
|
const headerTabsWhenNotLogin = computed(() => [...availableBasicTimelines(serverMetadata).map(tl => ({
|
||||||
key: tl,
|
key: tl,
|
||||||
title: i18n.ts._timelines[tl],
|
title: i18n.ts._timelines[tl],
|
||||||
icon: basicTimelineIconClass(tl),
|
icon: basicTimelineIconClass(tl),
|
||||||
|
|
|
@ -151,8 +151,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineAsyncComponent, computed, onMounted, onUnmounted, nextTick, watch, ref } from 'vue';
|
import { defineAsyncComponent, computed, onMounted, onUnmounted, nextTick, watch, ref, inject } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
|
import { getScrollPosition } from '@@/js/scroll.js';
|
||||||
import MkNote from '@/components/MkNote.vue';
|
import MkNote from '@/components/MkNote.vue';
|
||||||
import MkFollowButton from '@/components/MkFollowButton.vue';
|
import MkFollowButton from '@/components/MkFollowButton.vue';
|
||||||
import MkAccountMoved from '@/components/MkAccountMoved.vue';
|
import MkAccountMoved from '@/components/MkAccountMoved.vue';
|
||||||
|
@ -161,7 +162,6 @@ import MkTextarea from '@/components/MkTextarea.vue';
|
||||||
import MkOmit from '@/components/MkOmit.vue';
|
import MkOmit from '@/components/MkOmit.vue';
|
||||||
import MkInfo from '@/components/MkInfo.vue';
|
import MkInfo from '@/components/MkInfo.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import { getScrollPosition } from '@@/js/scroll.js';
|
|
||||||
import { getUserMenu } from '@/scripts/get-user-menu.js';
|
import { getUserMenu } from '@/scripts/get-user-menu.js';
|
||||||
import number from '@/filters/number.js';
|
import number from '@/filters/number.js';
|
||||||
import { userPage } from '@/filters/user.js';
|
import { userPage } from '@/filters/user.js';
|
||||||
|
@ -174,7 +174,9 @@ import { confetti } from '@/scripts/confetti.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { isFollowingVisibleForMe, isFollowersVisibleForMe } from '@/scripts/isFfVisibleForMe.js';
|
import { isFollowingVisibleForMe, isFollowersVisibleForMe } from '@/scripts/isFfVisibleForMe.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router/supplier.js';
|
||||||
import { getStaticImageUrl } from '@/scripts/media-proxy.js';
|
|
||||||
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
const mediaProxy = inject('mediaProxy');
|
||||||
|
|
||||||
function calcAge(birthdate: string): number {
|
function calcAge(birthdate: string): number {
|
||||||
const date = new Date(birthdate);
|
const date = new Date(birthdate);
|
||||||
|
@ -224,7 +226,7 @@ const style = computed(() => {
|
||||||
if (props.user.bannerUrl == null) return {};
|
if (props.user.bannerUrl == null) return {};
|
||||||
if (defaultStore.state.disableShowingAnimatedImages) {
|
if (defaultStore.state.disableShowingAnimatedImages) {
|
||||||
return {
|
return {
|
||||||
backgroundImage: `url(${ getStaticImageUrl(props.user.bannerUrl) })`,
|
backgroundImage: `url(${ mediaProxy.getStaticImageUrl(props.user.bannerUrl) })`,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
|
@ -238,7 +240,7 @@ const age = computed(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
function menu(ev: MouseEvent) {
|
function menu(ev: MouseEvent) {
|
||||||
const { menu, cleanup } = getUserMenu(user.value, router);
|
const { menu, cleanup } = getUserMenu({ serverMetadata }, user.value, router);
|
||||||
os.popupMenu(menu, ev.currentTarget ?? ev.target).finally(cleanup);
|
os.popupMenu(menu, ev.currentTarget ?? ev.target).finally(cleanup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,9 +33,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { inject, onMounted, ref } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { getStaticImageUrl } from '@/scripts/media-proxy.js';
|
|
||||||
import { notePage } from '@/filters/note.js';
|
import { notePage } from '@/filters/note.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import MkContainer from '@/components/MkContainer.vue';
|
import MkContainer from '@/components/MkContainer.vue';
|
||||||
|
@ -43,6 +42,8 @@ import ImgWithBlurhash from '@/components/MkImgWithBlurhash.vue';
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
||||||
|
const mediaProxy = inject('mediaProxy');
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
user: Misskey.entities.UserDetailed;
|
user: Misskey.entities.UserDetailed;
|
||||||
}>();
|
}>();
|
||||||
|
@ -56,7 +57,7 @@ const showingFiles = ref<string[]>([]);
|
||||||
|
|
||||||
function thumbnail(image: Misskey.entities.DriveFile): string {
|
function thumbnail(image: Misskey.entities.DriveFile): string {
|
||||||
return defaultStore.state.disableShowingAnimatedImages
|
return defaultStore.state.disableShowingAnimatedImages
|
||||||
? getStaticImageUrl(image.url)
|
? mediaProxy.getStaticImageUrl(image.url)
|
||||||
: image.thumbnailUrl;
|
: image.thumbnailUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="meta" class="rsqzvsbo">
|
<div class="rsqzvsbo">
|
||||||
<MkFeaturedPhotos class="bg"/>
|
<MkFeaturedPhotos class="bg"/>
|
||||||
<XTimeline class="tl"/>
|
<XTimeline class="tl"/>
|
||||||
<div class="shape1"></div>
|
<div class="shape1"></div>
|
||||||
|
@ -36,7 +36,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue';
|
import { inject, ref } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import XTimeline from './welcome.timeline.vue';
|
import XTimeline from './welcome.timeline.vue';
|
||||||
import MarqueeText from '@/components/MkMarquee.vue';
|
import MarqueeText from '@/components/MkMarquee.vue';
|
||||||
|
@ -44,8 +44,9 @@ import MkFeaturedPhotos from '@/components/MkFeaturedPhotos.vue';
|
||||||
import misskeysvg from '/client-assets/misskey.svg';
|
import misskeysvg from '/client-assets/misskey.svg';
|
||||||
import { misskeyApiGet } from '@/scripts/misskey-api.js';
|
import { misskeyApiGet } from '@/scripts/misskey-api.js';
|
||||||
import MkVisitorDashboard from '@/components/MkVisitorDashboard.vue';
|
import MkVisitorDashboard from '@/components/MkVisitorDashboard.vue';
|
||||||
import { getProxiedImageUrl } from '@/scripts/media-proxy.js';
|
|
||||||
import { instance as meta } from '@/instance.js';
|
const serverMetadata = inject('serverMetadata');
|
||||||
|
const mediaProxy = inject('mediaProxy');
|
||||||
|
|
||||||
const instances = ref<Misskey.entities.FederationInstance[]>();
|
const instances = ref<Misskey.entities.FederationInstance[]>();
|
||||||
|
|
||||||
|
@ -53,7 +54,7 @@ function getInstanceIcon(instance: Misskey.entities.FederationInstance): string
|
||||||
if (!instance.iconUrl) {
|
if (!instance.iconUrl) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
return getProxiedImageUrl(instance.iconUrl, 'preview');
|
return mediaProxy.getProxiedImageUrl(instance.iconUrl, 'preview');
|
||||||
}
|
}
|
||||||
|
|
||||||
misskeyApiGet('federation/instances', {
|
misskeyApiGet('federation/instances', {
|
||||||
|
|
|
@ -17,11 +17,11 @@ import XSetup from './welcome.setup.vue';
|
||||||
import XEntrance from './welcome.entrance.a.vue';
|
import XEntrance from './welcome.entrance.a.vue';
|
||||||
import { instanceName } from '@/config.js';
|
import { instanceName } from '@/config.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { fetchInstance } from '@/instance.js';
|
import { fetchServerMetadata } from '@/server-metadata.js';
|
||||||
|
|
||||||
const instance = ref<Misskey.entities.MetaDetailed | null>(null);
|
const instance = ref<Misskey.entities.MetaDetailed | null>(null);
|
||||||
|
|
||||||
fetchInstance(true).then((res) => {
|
fetchServerMetadata(true).then((res) => {
|
||||||
instance.value = res;
|
instance.value = res;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -3,17 +3,17 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { instance } from '@/instance.js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
|
|
||||||
export const notesSearchAvailable = (
|
export function isNotesSearchAvailable(serverMetadata: Misskey.entities.MetaDetailed): boolean {
|
||||||
// FIXME: instance.policies would be null in Vitest
|
// FIXME: serverMetadata.policies would be null in Vitest
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
($i == null && instance.policies != null && instance.policies.canSearchNotes) ||
|
return ($i == null && serverMetadata.policies != null && serverMetadata.policies.canSearchNotes) ||
|
||||||
($i != null && $i.policies.canSearchNotes) ||
|
($i != null && $i.policies.canSearchNotes) ||
|
||||||
false
|
false;
|
||||||
) as boolean;
|
}
|
||||||
|
|
||||||
export const canSearchNonLocalNotes = (
|
export function canSearchNonLocalNotes(serverMetadata: Misskey.entities.MetaDetailed): boolean {
|
||||||
instance.noteSearchableScope === 'global'
|
return serverMetadata.noteSearchableScope === 'global';
|
||||||
);
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { unisonReload } from '@/scripts/unison-reload.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { miLocalStorage } from '@/local-storage.js';
|
import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { fetchCustomEmojis } from '@/custom-emojis.js';
|
import { fetchCustomEmojis } from '@/custom-emojis.js';
|
||||||
import { fetchInstance } from '@/instance.js';
|
import { fetchServerMetadata } from '@/server-metadata.js';
|
||||||
|
|
||||||
export async function clearCache() {
|
export async function clearCache() {
|
||||||
os.waiting();
|
os.waiting();
|
||||||
|
@ -18,7 +18,7 @@ export async function clearCache() {
|
||||||
miLocalStorage.removeItem('theme');
|
miLocalStorage.removeItem('theme');
|
||||||
miLocalStorage.removeItem('emojis');
|
miLocalStorage.removeItem('emojis');
|
||||||
miLocalStorage.removeItem('lastEmojisFetchedAt');
|
miLocalStorage.removeItem('lastEmojisFetchedAt');
|
||||||
await fetchInstance(true);
|
await fetchServerMetadata(true);
|
||||||
await fetchCustomEmojis(true);
|
await fetchCustomEmojis(true);
|
||||||
unisonReload();
|
unisonReload();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ import * as Misskey from 'misskey-js';
|
||||||
import { claimAchievement } from './achievements.js';
|
import { claimAchievement } from './achievements.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
||||||
|
@ -170,7 +169,7 @@ function getNoteEmbedCodeMenu(note: Misskey.entities.Note, text: string): MenuIt
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getNoteMenu(props: {
|
export function getNoteMenu(ctx: { serverMetadata: Misskey.entities.MetaDetailed }, props: {
|
||||||
note: Misskey.entities.Note;
|
note: Misskey.entities.Note;
|
||||||
translation: Ref<Misskey.entities.NotesTranslateResponse | null>;
|
translation: Ref<Misskey.entities.NotesTranslateResponse | null>;
|
||||||
translating: Ref<boolean>;
|
translating: Ref<boolean>;
|
||||||
|
@ -330,7 +329,7 @@ export function getNoteMenu(props: {
|
||||||
text: i18n.ts.share,
|
text: i18n.ts.share,
|
||||||
action: share,
|
action: share,
|
||||||
}] : []),
|
}] : []),
|
||||||
$i && $i.policies.canUseTranslator && instance.translatorAvailable ? {
|
$i && $i.policies.canUseTranslator && ctx.serverMetadata.translatorAvailable ? {
|
||||||
icon: 'ti ti-language-hiragana',
|
icon: 'ti ti-language-hiragana',
|
||||||
text: i18n.ts.translate,
|
text: i18n.ts.translate,
|
||||||
action: translate,
|
action: translate,
|
||||||
|
@ -375,7 +374,7 @@ export function getNoteMenu(props: {
|
||||||
text: i18n.ts.user,
|
text: i18n.ts.user,
|
||||||
children: async () => {
|
children: async () => {
|
||||||
const user = appearNote.userId === $i?.id ? $i : await misskeyApi('users/show', { userId: appearNote.userId });
|
const user = appearNote.userId === $i?.id ? $i : await misskeyApi('users/show', { userId: appearNote.userId });
|
||||||
const { menu, cleanup } = getUserMenu(user);
|
const { menu, cleanup } = getUserMenu(ctx, user);
|
||||||
cleanups.push(cleanup);
|
cleanups.push(cleanup);
|
||||||
return menu;
|
return menu;
|
||||||
},
|
},
|
||||||
|
@ -458,13 +457,13 @@ export function getNoteMenu(props: {
|
||||||
text: i18n.ts.copyContent,
|
text: i18n.ts.copyContent,
|
||||||
action: copyContent,
|
action: copyContent,
|
||||||
}, getCopyNoteLinkMenu(appearNote, i18n.ts.copyLink),
|
}, getCopyNoteLinkMenu(appearNote, i18n.ts.copyLink),
|
||||||
(appearNote.url || appearNote.uri) ? {
|
(appearNote.url || appearNote.uri) ? {
|
||||||
icon: 'ti ti-external-link',
|
icon: 'ti ti-external-link',
|
||||||
text: i18n.ts.showOnRemote,
|
text: i18n.ts.showOnRemote,
|
||||||
action: () => {
|
action: () => {
|
||||||
window.open(appearNote.url ?? appearNote.uri, '_blank', 'noopener');
|
window.open(appearNote.url ?? appearNote.uri, '_blank', 'noopener');
|
||||||
},
|
},
|
||||||
} : getNoteEmbedCodeMenu(appearNote, i18n.ts.genEmbedCode)]
|
} : getNoteEmbedCodeMenu(appearNote, i18n.ts.genEmbedCode)]
|
||||||
.filter(x => x !== undefined);
|
.filter(x => x !== undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,14 +13,14 @@ import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { defaultStore, userActions } from '@/store.js';
|
import { defaultStore, userActions } from '@/store.js';
|
||||||
import { $i, iAmModerator } from '@/account.js';
|
import { $i, iAmModerator } from '@/account.js';
|
||||||
import { notesSearchAvailable, canSearchNonLocalNotes } from '@/scripts/check-permissions.js';
|
import { isNotesSearchAvailable, canSearchNonLocalNotes } from '@/scripts/check-permissions.js';
|
||||||
import { IRouter } from '@/nirax.js';
|
import { IRouter } from '@/nirax.js';
|
||||||
import { antennasCache, rolesCache, userListsCache } from '@/cache.js';
|
import { antennasCache, rolesCache, userListsCache } from '@/cache.js';
|
||||||
import { mainRouter } from '@/router/main.js';
|
import { mainRouter } from '@/router/main.js';
|
||||||
import { genEmbedCode } from '@/scripts/get-embed-code.js';
|
import { genEmbedCode } from '@/scripts/get-embed-code.js';
|
||||||
import { MenuItem } from '@/types/menu.js';
|
import { MenuItem } from '@/types/menu.js';
|
||||||
|
|
||||||
export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter = mainRouter) {
|
export function getUserMenu(ctx: { serverMetadata: Misskey.entities.MetaDetailed }, user: Misskey.entities.UserDetailed, router: IRouter = mainRouter) {
|
||||||
const meId = $i ? $i.id : null;
|
const meId = $i ? $i.id : null;
|
||||||
|
|
||||||
const cleanups = [] as (() => void)[];
|
const cleanups = [] as (() => void)[];
|
||||||
|
@ -154,7 +154,7 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter
|
||||||
action: () => {
|
action: () => {
|
||||||
copyToClipboard(`@${user.username}@${user.host ?? host}`);
|
copyToClipboard(`@${user.username}@${user.host ?? host}`);
|
||||||
},
|
},
|
||||||
}, ...( notesSearchAvailable && (user.host == null || canSearchNonLocalNotes) ? [{
|
}, ...(isNotesSearchAvailable(ctx.serverMetadata) && (user.host == null || canSearchNonLocalNotes(ctx.serverMetadata)) ? [{
|
||||||
icon: 'ti ti-search',
|
icon: 'ti ti-search',
|
||||||
text: i18n.ts.searchThisUsersNotes,
|
text: i18n.ts.searchThisUsersNotes,
|
||||||
action: () => {
|
action: () => {
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { query } from '@@/js/url.js';
|
|
||||||
import { url } from '@/config.js';
|
|
||||||
import { instance } from '@/instance.js';
|
|
||||||
|
|
||||||
export function getProxiedImageUrl(imageUrl: string, type?: 'preview' | 'emoji' | 'avatar', mustOrigin = false, noFallback = false): string {
|
|
||||||
const localProxy = `${url}/proxy`;
|
|
||||||
|
|
||||||
if (imageUrl.startsWith(instance.mediaProxy + '/') || imageUrl.startsWith('/proxy/') || imageUrl.startsWith(localProxy + '/')) {
|
|
||||||
// もう既にproxyっぽそうだったらurlを取り出す
|
|
||||||
imageUrl = (new URL(imageUrl)).searchParams.get('url') ?? imageUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${mustOrigin ? localProxy : instance.mediaProxy}/${
|
|
||||||
type === 'preview' ? 'preview.webp'
|
|
||||||
: 'image.webp'
|
|
||||||
}?${query({
|
|
||||||
url: imageUrl,
|
|
||||||
...(!noFallback ? { 'fallback': '1' } : {}),
|
|
||||||
...(type ? { [type]: '1' } : {}),
|
|
||||||
...(mustOrigin ? { origin: '1' } : {}),
|
|
||||||
})}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getProxiedImageUrlNullable(imageUrl: string | null | undefined, type?: 'preview'): string | null {
|
|
||||||
if (imageUrl == null) return null;
|
|
||||||
return getProxiedImageUrl(imageUrl, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getStaticImageUrl(baseUrl: string): string {
|
|
||||||
const u = baseUrl.startsWith('http') ? new URL(baseUrl) : new URL(baseUrl, url);
|
|
||||||
|
|
||||||
if (u.href.startsWith(`${url}/emoji/`)) {
|
|
||||||
// もう既にemojiっぽそうだったらsearchParams付けるだけ
|
|
||||||
u.searchParams.set('static', '1');
|
|
||||||
return u.href;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (u.href.startsWith(instance.mediaProxy + '/')) {
|
|
||||||
// もう既にproxyっぽそうだったらsearchParams付けるだけ
|
|
||||||
u.searchParams.set('static', '1');
|
|
||||||
return u.href;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${instance.mediaProxy}/static.webp?${query({
|
|
||||||
url: u.href,
|
|
||||||
static: '1',
|
|
||||||
})}`;
|
|
||||||
}
|
|
|
@ -13,7 +13,7 @@ import { apiUrl } from '@/config.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import { alert } from '@/os.js';
|
import { alert } from '@/os.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
import { fetchServerMetadata } from '@/server-metadata.js';
|
||||||
|
|
||||||
type Uploading = {
|
type Uploading = {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -40,16 +40,16 @@ export function uploadFile(
|
||||||
|
|
||||||
if (folder && typeof folder === 'object') folder = folder.id;
|
if (folder && typeof folder === 'object') folder = folder.id;
|
||||||
|
|
||||||
if (file.size > instance.maxFileSize) {
|
return fetchServerMetadata().then((serverMetadata) => new Promise((resolve, reject) => {
|
||||||
alert({
|
if (file.size > serverMetadata.maxFileSize) {
|
||||||
type: 'error',
|
alert({
|
||||||
title: i18n.ts.failedToUpload,
|
type: 'error',
|
||||||
text: i18n.ts.cannotUploadBecauseExceedsFileSizeLimit,
|
title: i18n.ts.failedToUpload,
|
||||||
});
|
text: i18n.ts.cannotUploadBecauseExceedsFileSizeLimit,
|
||||||
return Promise.reject();
|
});
|
||||||
}
|
return reject();
|
||||||
|
}
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const id = uuid();
|
const id = uuid();
|
||||||
|
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
|
@ -158,5 +158,5 @@ export function uploadFile(
|
||||||
xhr.send(formData);
|
xhr.send(formData);
|
||||||
};
|
};
|
||||||
reader.readAsArrayBuffer(file);
|
reader.readAsArrayBuffer(file);
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue