Merge branch Sharkey:develop into trackeropt

This commit is contained in:
Vavency 2025-06-12 23:34:00 +00:00
commit 1f51d16bf6
207 changed files with 4159 additions and 1597 deletions

View file

@ -118,9 +118,12 @@ import { misskeyApi } from '@/utility/misskey-api';
import AdminUser from '@/pages/admin-user.vue';
import SkUrlPreviewGroup from '@/components/SkUrlPreviewGroup.vue';
const props = defineProps<{
const props = withDefaults(defineProps<{
report: Misskey.entities.AdminAbuseUserReportsResponse[number];
}>();
metaHint?: Misskey.entities.AdminMetaResponse | undefined;
}>(), {
metaHint: undefined,
});
const emit = defineEmits<{
(ev: 'resolved', reportId: string): void;
@ -134,7 +137,6 @@ reporterRouter.init();
*/
const parsedComment = computed(() => mfm.parse(props.report.comment));
const metaHint = ref<Misskey.entities.AdminMetaResponse | undefined>(undefined);
const targetInstanceIcon = computed(() => props.report.targetInstance?.faviconUrl
? getProxiedImageUrlNullable(props.report.targetInstance.faviconUrl, 'preview')
@ -142,12 +144,6 @@ const targetInstanceIcon = computed(() => props.report.targetInstance?.faviconUr
? getProxiedImageUrlNullable(props.report.targetInstance.iconUrl, 'preview')
: null);
if (iAmAdmin) {
misskeyApi('admin/meta')
.then(meta => metaHint.value = meta)
.catch(err => console.error('[MkAbuseReport] Error fetching meta:', err));
}
const moderationNote = ref(props.report.moderationNote ?? '');
watch(moderationNote, async () => {

View file

@ -142,7 +142,7 @@ function reset() {
function remove() {
if (captcha.value.remove && captchaWidgetId.value) {
try {
if (_DEV_) console.log('remove', props.provider, captchaWidgetId.value);
if (_DEV_) console.debug('remove', props.provider, captchaWidgetId.value);
captcha.value.remove(captchaWidgetId.value);
} catch (error: unknown) {
// ignore

View file

@ -52,7 +52,7 @@ async function fetchLanguage(to: string): Promise<void> {
return bundle.id === language || bundle.aliases?.includes(language);
});
if (bundles.length > 0) {
if (_DEV_) console.log(`Loading language: ${language}`);
if (_DEV_) console.debug(`Loading language: ${language}`);
await highlighter.loadLanguage(bundles[0].import);
codeLang.value = language;
} else {

View file

@ -95,7 +95,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<MkPoll v-if="appearNote.poll" :noteId="appearNote.id" :poll="appearNote.poll" :local="!appearNote.user.host" :author="appearNote.user" :emojiUrls="appearNote.emojis" :class="$style.poll" @click.stop/>
<div v-if="isEnabledUrlPreview">
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" :showAsQuote="!appearNote.user.rejectQuotes" :skipNoteIds="selfNoteIds" :class="$style.urlPreview" @click.stop/>
<SkUrlPreviewGroup :sourceUrls="urls" :sourceNote="appearNote" :compact="true" :detail="false" :showAsQuote="!appearNote.user.rejectQuotes" :skipNoteIds="selfNoteIds" :class="$style.urlPreview" @click.stop/>
</div>
<div v-if="appearNote.renote" :class="$style.quote"><MkNoteSimple :note="appearNote.renote" :class="$style.quoteNote"/></div>
<button v-if="isLong && collapsed" :class="$style.collapsed" class="_button" @click.stop @click="collapsed = false">
@ -237,6 +237,7 @@ import SkMutedNote from '@/components/SkMutedNote.vue';
import SkNoteTranslation from '@/components/SkNoteTranslation.vue';
import { getSelfNoteIds } from '@/utility/get-self-note-ids.js';
import { extractPreviewUrls } from '@/utility/extract-preview-urls.js';
import SkUrlPreviewGroup from '@/components/SkUrlPreviewGroup.vue';
const props = withDefaults(defineProps<{
note: Misskey.entities.Note;
@ -304,9 +305,9 @@ const galleryEl = useTemplateRef('galleryEl');
const isMyRenote = $i && ($i.id === note.value.userId);
const showContent = ref(prefer.s.uncollapseCW);
const parsed = computed(() => appearNote.value.text ? mfm.parse(appearNote.value.text) : null);
const urls = computed(() => parsed.value ? extractPreviewUrls(props.note, parsed.value) : null);
const urls = computed(() => parsed.value ? extractPreviewUrls(props.note, parsed.value) : []);
const selfNoteIds = computed(() => getSelfNoteIds(props.note));
const isLong = shouldCollapsed(appearNote.value, urls.value ?? []);
const isLong = shouldCollapsed(appearNote.value, urls.value);
const collapsed = ref(prefer.s.expandLongNote && appearNote.value.cw == null && isLong ? false : appearNote.value.cw == null && isLong);
const isDeleted = ref(false);
const renoted = ref(false);

View file

@ -112,7 +112,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<MkPoll v-if="appearNote.poll" ref="pollViewer" :noteId="appearNote.id" :poll="appearNote.poll" :local="!appearNote.user.host" :class="$style.poll" :author="appearNote.user" :emojiUrls="appearNote.emojis"/>
<div v-if="isEnabledUrlPreview">
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="true" :showAsQuote="!appearNote.user.rejectQuotes" :skipNoteIds="selfNoteIds" style="margin-top: 6px;"/>
<SkUrlPreviewGroup :sourceNodes="nodes" :sourceNote="appearNote" :compact="true" :detail="true" :showAsQuote="!appearNote.user.rejectQuotes" :skipNoteIds="selfNoteIds" style="margin-top: 6px;" @click.stop/>
</div>
<div v-if="appearNote.renote" :class="$style.quote"><MkNoteSimple :note="appearNote.renote" :class="$style.quoteNote" :expandAllCws="props.expandAllCws"/></div>
</div>
@ -286,7 +286,7 @@ import { DI } from '@/di.js';
import SkMutedNote from '@/components/SkMutedNote.vue';
import SkNoteTranslation from '@/components/SkNoteTranslation.vue';
import { getSelfNoteIds } from '@/utility/get-self-note-ids.js';
import { extractPreviewUrls } from '@/utility/extract-preview-urls.js';
import SkUrlPreviewGroup from '@/components/SkUrlPreviewGroup.vue';
const props = withDefaults(defineProps<{
note: Misskey.entities.Note;
@ -339,8 +339,7 @@ const isDeleted = ref(false);
const renoted = ref(false);
const translation = ref<Misskey.entities.NotesTranslateResponse | false | null>(null);
const translating = ref(false);
const parsed = computed(() => appearNote.value.text ? mfm.parse(appearNote.value.text) : null);
const urls = computed(() => parsed.value ? extractPreviewUrls(props.note, parsed.value) : null);
const parsed = computed(() => appearNote.value.text ? mfm.parse(appearNote.value.text) : []);
const selfNoteIds = computed(() => getSelfNoteIds(props.note));
const animated = computed(() => parsed.value ? checkAnimationFromMfm(parsed.value) : null);
const allowAnim = ref(prefer.s.advancedMfm && prefer.s.animatedMfm);

View file

@ -57,7 +57,7 @@ defineExpose({
&.noGap {
background: color-mix(in srgb, var(--MI_THEME-panel) 65%, transparent);
.note {
.note:not(:empty) {
border-bottom: solid 0.5px var(--MI_THEME-divider);
}

View file

@ -106,7 +106,7 @@ windowRouter.addListener('replace', ctx => {
});
windowRouter.addListener('change', ctx => {
if (_DEV_) console.log('windowRouter: change', ctx.fullPath);
if (_DEV_) console.debug('windowRouter: change', ctx.fullPath);
searchMarkerId.value = getSearchMarker(ctx.fullPath);
});

View file

@ -386,7 +386,7 @@ function prepend(item: MisskeyEntity): void {
return;
}
if (_DEV_) console.log(isHead(), isPausingUpdate);
if (_DEV_) console.debug(isHead(), isPausingUpdate);
if (isHead() && !isPausingUpdate) unshiftItems([item]);
else prependQueue(item);

View file

@ -373,7 +373,7 @@ if (props.specified) {
// keep cw when reply
if (prefer.s.keepCw && props.reply && props.reply.cw) {
useCw.value = true;
cw.value = prefer.s.keepCw === 'prepend-re'
cw.value = (prefer.s.keepCw === 'prepend-re' && !props.reply.cw.toLowerCase().startsWith('re:'))
? `RE: ${props.reply.cw}`
: props.reply.cw;
}

View file

@ -307,7 +307,7 @@ async function onSubmit(): Promise<void> {
emit('approvalPending');
} else {
const resJson = (await res.json()) as Misskey.entities.SignupResponse;
if (_DEV_) console.log(resJson);
if (_DEV_) console.debug(resJson);
emit('signup', resJson);

View file

@ -353,7 +353,7 @@ defineExpose({
&.noGap {
background: var(--MI_THEME-panel);
.note {
.note:not(:empty) {
border-bottom: solid 0.5px var(--MI_THEME-divider);
}

View file

@ -97,7 +97,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<MkPoll v-if="appearNote.poll" :noteId="appearNote.id" :poll="appearNote.poll" :local="!appearNote.user.host" :author="appearNote.user" :emojiUrls="appearNote.emojis" :class="$style.poll" @click.stop/>
<div v-if="isEnabledUrlPreview">
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" :showAsQuote="!appearNote.user.rejectQuotes" :skipNoteIds="selfNoteIds" :class="$style.urlPreview" @click.stop/>
<SkUrlPreviewGroup :sourceUrls="urls" :sourceNote="appearNote" :compact="true" :detail="false" :showAsQuote="!appearNote.user.rejectQuotes" :skipNoteIds="selfNoteIds" :class="$style.urlPreview" @click.stop/>
</div>
<div v-if="appearNote.renote" :class="$style.quote"><SkNoteSimple :note="appearNote.renote" :class="$style.quoteNote"/></div>
<button v-if="isLong && collapsed" :class="$style.collapsed" class="_button" @click.stop @click="collapsed = false">
@ -237,6 +237,7 @@ import SkMutedNote from '@/components/SkMutedNote.vue';
import SkNoteTranslation from '@/components/SkNoteTranslation.vue';
import { getSelfNoteIds } from '@/utility/get-self-note-ids.js';
import { extractPreviewUrls } from '@/utility/extract-preview-urls.js';
import SkUrlPreviewGroup from '@/components/SkUrlPreviewGroup.vue';
const props = withDefaults(defineProps<{
note: Misskey.entities.Note;
@ -304,9 +305,9 @@ const galleryEl = useTemplateRef('galleryEl');
const isMyRenote = $i && ($i.id === note.value.userId);
const showContent = ref(prefer.s.uncollapseCW);
const parsed = computed(() => appearNote.value.text ? mfm.parse(appearNote.value.text) : null);
const urls = computed(() => parsed.value ? extractPreviewUrls(props.note, parsed.value) : null);
const urls = computed(() => parsed.value ? extractPreviewUrls(props.note, parsed.value) : []);
const selfNoteIds = computed(() => getSelfNoteIds(props.note));
const isLong = shouldCollapsed(appearNote.value, urls.value ?? []);
const isLong = shouldCollapsed(appearNote.value, urls.value);
const collapsed = ref(prefer.s.expandLongNote && appearNote.value.cw == null && isLong ? false : appearNote.value.cw == null && isLong);
const isDeleted = ref(false);
const renoted = ref(false);

View file

@ -117,7 +117,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<MkPoll v-if="appearNote.poll" ref="pollViewer" :noteId="appearNote.id" :poll="appearNote.poll" :local="!appearNote.user.host" :class="$style.poll" :author="appearNote.user" :emojiUrls="appearNote.emojis"/>
<div v-if="isEnabledUrlPreview">
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="true" :showAsQuote="!appearNote.user.rejectQuotes" :skipNoteIds="selfNoteIds" style="margin-top: 6px;"/>
<SkUrlPreviewGroup :sourceNodes="nodes" :sourceNote="appearNote" :compact="true" :detail="true" :showAsQuote="!appearNote.user.rejectQuotes" :skipNoteIds="selfNoteIds" style="margin-top: 6px;" @click.stop/>
</div>
<div v-if="appearNote.renote" :class="$style.quote"><SkNoteSimple :note="appearNote.renote" :class="$style.quoteNote" :expandAllCws="props.expandAllCws"/></div>
</div>
@ -291,7 +291,7 @@ import { DI } from '@/di.js';
import SkMutedNote from '@/components/SkMutedNote.vue';
import SkNoteTranslation from '@/components/SkNoteTranslation.vue';
import { getSelfNoteIds } from '@/utility/get-self-note-ids.js';
import { extractPreviewUrls } from '@/utility/extract-preview-urls';
import SkUrlPreviewGroup from '@/components/SkUrlPreviewGroup.vue';
const props = withDefaults(defineProps<{
note: Misskey.entities.Note;
@ -345,8 +345,7 @@ const isDeleted = ref(false);
const renoted = ref(false);
const translation = ref<Misskey.entities.NotesTranslateResponse | false | null>(null);
const translating = ref(false);
const parsed = computed(() => appearNote.value.text ? mfm.parse(appearNote.value.text) : null);
const urls = computed(() => parsed.value ? extractPreviewUrls(props.note, parsed.value) : null);
const parsed = computed(() => appearNote.value.text ? mfm.parse(appearNote.value.text) : []);
const selfNoteIds = computed(() => getSelfNoteIds(props.note));
const animated = computed(() => parsed.value ? checkAnimationFromMfm(parsed.value) : null);
const allowAnim = ref(prefer.s.advancedMfm && prefer.s.animatedMfm ? true : false);

View file

@ -33,7 +33,6 @@ if (_DEV_) {
watch(
[() => props.translation, () => props.translating],
([translation, translating]) => console.debug('Translation status changed: ', { translation, translating }),
{ immediate: true },
);
}
</script>

View file

@ -40,14 +40,14 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-show="appearNote.cw == null || showContent">
<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span>
<MkA v-if="appearNote.replyId" :class="$style.noteReplyTarget" :to="`/notes/${appearNote.replyId}`"><i class="ph-arrow-bend-left-up ph-bold ph-lg"></i></MkA>
<Mfm v-if="appearNote.text" :text="appearNote.text" :isBlock="true" :author="appearNote.user" :nyaize="'respect'" :emojiUrls="appearNote.emojis"/>
<Mfm v-if="appearNote.text" :text="appearNote.text" :parsedNodes="parsed" :isBlock="true" :author="appearNote.user" :nyaize="'respect'" :emojiUrls="appearNote.emojis"/>
<a v-if="appearNote.renote != null" :class="$style.rn">RN:</a>
<SkNoteTranslation :note="note" :translation="translation" :translating="translating"></SkNoteTranslation>
<div v-if="appearNote.files && appearNote.files.length > 0">
<MkMediaList :mediaList="appearNote.files"/>
</div>
<MkPoll v-if="appearNote.poll" :noteId="appearNote.id" :poll="appearNote.poll" :local="!appearNote.user.host" :author="appearNote.user" :emojiUrls="appearNote.emojis" :class="$style.poll"/>
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="true" :showAsQuote="!appearNote.user.rejectQuotes" :skipNoteIds="selfNoteIds" style="margin-top: 6px;"/>
<SkUrlPreviewGroup :sourceNodes="parsed" :sourceNote="appearNote" :compact="true" :detail="true" :showAsQuote="!appearNote.user.rejectQuotes" :skipNoteIds="selfNoteIds" style="margin-top: 6px;" @click.stop/>
<div v-if="appearNote.renote" :class="$style.quote"><MkNoteSimple :note="appearNote.renote" :class="$style.quoteNote"/></div>
</div>
<MkA v-if="appearNote.channel && !inChannel" :class="$style.channel" :to="`/channels/${appearNote.channel.id}`"><i class="ph-television ph-bold ph-lg"></i> {{ appearNote.channel.name }}</MkA>
@ -83,7 +83,6 @@ import MkMediaList from '@/components/MkMediaList.vue';
import MkCwButton from '@/components/MkCwButton.vue';
import MkWindow from '@/components/MkWindow.vue';
import MkPoll from '@/components/MkPoll.vue';
import MkUrlPreview from '@/components/MkUrlPreview.vue';
import MkInstanceTicker from '@/components/MkInstanceTicker.vue';
import { userPage } from '@/filters/user.js';
import { i18n } from '@/i18n.js';
@ -93,7 +92,7 @@ import { prefer } from '@/preferences';
import { getPluginHandlers } from '@/plugin.js';
import SkNoteTranslation from '@/components/SkNoteTranslation.vue';
import { getSelfNoteIds } from '@/utility/get-self-note-ids';
import { extractPreviewUrls } from '@/utility/extract-preview-urls.js';
import SkUrlPreviewGroup from '@/components/SkUrlPreviewGroup.vue';
const props = defineProps<{
note: Misskey.entities.Note;
@ -143,12 +142,11 @@ const isRenote = (
const el = shallowRef<HTMLElement>();
const appearNote = computed(() => isRenote ? note.value.renote as Misskey.entities.Note : note.value);
const parsed = computed(() => appearNote.value.text ? mfm.parse(appearNote.value.text) : null);
const parsed = computed(() => appearNote.value.text ? mfm.parse(appearNote.value.text) : []);
const showContent = ref(false);
const translation = ref<Misskey.entities.NotesTranslateResponse | false | null>(null);
const translating = ref(false);
const urls = computed(() => parsed.value ? extractPreviewUrls(props.note, parsed.value) : null);
const selfNoteIds = computed(() => getSelfNoteIds(props.note));
const showTicker = (prefer.s.instanceTicker === 'always') || (prefer.s.instanceTicker === 'remote' && appearNote.value.user.instance);

View file

@ -7,29 +7,20 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="_gaps" :class="$style.textRoot">
<Mfm :text="block.text ?? ''" :isBlock="true" :isNote="false"/>
<div v-if="isEnabledUrlPreview" class="_gaps_s">
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :showAsQuote="!page.user.rejectQuotes"/>
<SkUrlPreviewGroup :sourceText="block.text" :showAsQuote="!page.user.rejectQuotes" @click.stop/>
</div>
</div>
</template>
<script lang="ts" setup>
import { defineAsyncComponent, computed } from 'vue';
import * as mfm from '@transfem-org/sfm-js';
import * as Misskey from 'misskey-js';
import { extractUrlFromMfm } from '@/utility/extract-url-from-mfm.js';
import { isEnabledUrlPreview } from '@/instance.js';
import SkUrlPreviewGroup from '@/components/SkUrlPreviewGroup.vue';
const MkUrlPreview = defineAsyncComponent(() => import('@/components/MkUrlPreview.vue'));
const props = defineProps<{
defineProps<{
block: Misskey.entities.PageBlock,
page: Misskey.entities.Page,
}>();
const urls = computed(() => {
if (!props.block.text) return [];
return extractUrlFromMfm(mfm.parse(props.block.text));
});
</script>
<style lang="scss" module>

View file

@ -274,7 +274,7 @@ export class Nirax<DEF extends RouteDef[]> extends EventEmitter<RouterEvents> {
} else {
redirectPath = current.route.redirect + (current._parsedRoute.queryString ? '?' + current._parsedRoute.queryString : '') + (current._parsedRoute.hash ? '#' + current._parsedRoute.hash : '');
}
if (_DEV_) console.log('Redirecting to: ', redirectPath);
if (_DEV_) console.debug('Redirecting to: ', redirectPath);
if (_redirected && this.redirectCount++ > 10) {
throw new Error('redirect loop detected');
}

View file

@ -97,7 +97,7 @@ export class Pizzax<T extends StateDef> {
if (this.isPureObject(value) && this.isPureObject(def)) {
const merged = deepMerge(value, def);
if (_DEV_) console.log('Merging state. Incoming: ', value, ' Default: ', def, ' Result: ', merged);
if (_DEV_) console.debug('Merging state. Incoming: ', value, ' Default: ', def, ' Result: ', merged);
return merged as X;
}

View file

@ -4,11 +4,11 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<PageWithHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs" :spacer="true" style="--MI_SPACER-w: 600px; --MI_SPACER-min: 16px; --MI_SPACER-max: 32px;">
<div>
<FormSuspense :p="init">
<PageWithHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs" :spacer="true" style="--MI_SPACER-w: 700px; --MI_SPACER-min: 16px; --MI_SPACER-max: 32px;">
<FormSuspense v-if="init" :p="init">
<div v-if="user && info">
<div v-if="tab === 'overview'" class="_gaps">
<div v-if="user" class="aeakzknw">
<div class="aeakzknw">
<MkAvatar class="avatar" :user="user" indicator link preview/>
<div class="body">
<span class="name"><MkUserName class="name" :user="user"/></span>
@ -228,14 +228,46 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<div v-else-if="tab === 'raw'" class="_gaps_m">
<MkObjectView v-if="info && $i.isAdmin" tall :value="info">
</MkObjectView>
<MkFolder :sticky="false" :defaultOpen="true">
<template #icon><i class="ph-user-circle ph-bold ph-lg"></i></template>
<template #label>{{ i18n.ts.user }}</template>
<template #header>
<div :class="$style.rawFolderHeader">
<span>{{ i18n.ts.rawUserDescription }}</span>
<button class="_textButton" @click="copyToClipboard(JSON.stringify(user, null, 4))"><i class="ti ti-copy"></i> {{ i18n.ts.copy }}</button>
</div>
</template>
<MkObjectView tall :value="user">
</MkObjectView>
<MkObjectView tall :value="user"/>
</MkFolder>
<MkFolder :sticky="false">
<template #icon><i class="ti ti-info-circle"></i></template>
<template #label>{{ i18n.ts.details }}</template>
<template #header>
<div :class="$style.rawFolderHeader">
<span>{{ i18n.ts.rawInfoDescription }}</span>
<button class="_textButton" @click="copyToClipboard(JSON.stringify(info, null, 4))"><i class="ti ti-copy"></i> {{ i18n.ts.copy }}</button>
</div>
</template>
<MkObjectView tall :value="info"/>
</MkFolder>
<MkFolder v-if="ap" :sticky="false">
<template #icon><i class="ph-globe ph-bold ph-lg"></i></template>
<template #label>{{ i18n.ts.activityPub }}</template>
<template #header>
<div :class="$style.rawFolderHeader">
<span>{{ i18n.ts.rawApDescription }}</span>
<button class="_textButton" @click="copyToClipboard(JSON.stringify(ap, null, 4))"><i class="ti ti-copy"></i> {{ i18n.ts.copy }}</button>
</div>
</template>
<MkObjectView tall :value="ap"/>
</MkFolder>
</div>
</FormSuspense>
</div>
</div>
</FormSuspense>
</PageWithHeader>
</template>
@ -244,6 +276,7 @@ import { computed, defineAsyncComponent, watch, ref } from 'vue';
import * as Misskey from 'misskey-js';
import { url } from '@@/js/config.js';
import type { Badge } from '@/components/SkBadgeStrip.vue';
import type { ChartSrc } from '@/components/MkChart.vue';
import MkChart from '@/components/MkChart.vue';
import MkObjectView from '@/components/MkObjectView.vue';
import MkTextarea from '@/components/MkTextarea.vue';
@ -276,15 +309,17 @@ const props = withDefaults(defineProps<{
userHint?: Misskey.entities.UserDetailed;
infoHint?: Misskey.entities.AdminShowUserResponse;
ipsHint?: Misskey.entities.AdminGetUserIpsResponse;
apHint?: Misskey.entities.ApGetResponse;
}>(), {
initialTab: 'overview',
userHint: undefined,
infoHint: undefined,
ipsHint: undefined,
apHint: undefined,
});
const tab = ref(props.initialTab);
const chartSrc = ref('per-user-notes');
const chartSrc = ref<ChartSrc>('per-user-notes');
const user = ref<null | Misskey.entities.UserDetailed>();
const init = ref<ReturnType<typeof createFetcher>>();
const info = ref<Misskey.entities.AdminShowUserResponse | null>(null);
@ -409,7 +444,7 @@ const announcementsPagination = {
status: announcementsStatus.value,
})),
};
const expandedRoles = ref([]);
const expandedRoles = ref<string[]>([]);
function createFetcher(withHint = true) {
return () => Promise.all([
@ -424,22 +459,23 @@ function createFetcher(withHint = true) {
userId: props.userId,
})
: null,
iAmAdmin ? misskeyApi('ap/get', {
uri: `${url}/users/${props.userId}`,
}).catch(() => null) : null],
).then(([_user, _info, _ips, _ap]) => {
iAmAdmin
? (withHint && props.apHint) ? props.apHint : misskeyApi('ap/get', {
userId: props.userId,
}).catch(() => null) : null],
).then(async ([_user, _info, _ips, _ap]) => {
user.value = _user;
info.value = _info;
ips.value = _ips;
ap.value = _ap;
moderator.value = info.value.isModerator;
silenced.value = info.value.isSilenced;
approved.value = info.value.approved;
markedAsNSFW.value = info.value.alwaysMarkNsfw;
suspended.value = info.value.isSuspended;
rejectQuotes.value = user.value.rejectQuotes ?? false;
moderationNote.value = info.value.moderationNote;
mandatoryCW.value = user.value.mandatoryCW;
moderator.value = _info.isModerator;
silenced.value = _info.isSilenced;
approved.value = _info.approved;
markedAsNSFW.value = _info.alwaysMarkNsfw;
suspended.value = _info.isSuspended;
rejectQuotes.value = _user.rejectQuotes ?? false;
moderationNote.value = _info.moderationNote;
mandatoryCW.value = _user.mandatoryCW;
});
}
@ -448,9 +484,9 @@ async function refreshUser() {
await createFetcher(false)();
}
async function onMandatoryCWChanged(value: string) {
async function onMandatoryCWChanged(value: string | number) {
await os.promiseDialog(async () => {
await misskeyApi('admin/cw-user', { userId: props.userId, cw: value });
await misskeyApi('admin/cw-user', { userId: props.userId, cw: String(value) });
await refreshUser();
});
}
@ -458,14 +494,14 @@ async function onMandatoryCWChanged(value: string) {
async function onModerationNoteChanged(value: string) {
await os.promiseDialog(async () => {
await misskeyApi('admin/update-user-note', { userId: props.userId, text: value });
refreshUser();
await refreshUser();
});
}
async function updateRemoteUser() {
await os.promiseDialog(async () => {
await misskeyApi('federation/update-remote-user', { userId: props.userId });
refreshUser();
await refreshUser();
});
}
@ -478,7 +514,7 @@ async function resetPassword() {
return;
} else {
const { password } = await misskeyApi('admin/reset-password', {
userId: user.value.id,
userId: props.userId,
});
await os.alert({
type: 'success',
@ -590,15 +626,16 @@ async function deleteAccount() {
text: i18n.ts.deleteThisAccountConfirm,
});
if (confirm.canceled) return;
if (!user.value) return;
const typed = await os.inputText({
text: i18n.tsx.typeToConfirm({ x: user.value?.username }),
text: i18n.tsx.typeToConfirm({ x: user.value.username }),
});
if (typed.canceled) return;
if (typed.result === user.value?.username) {
if (typed.result === user.value.username) {
await os.apiWithDialog('admin/delete-account', {
userId: user.value.id,
userId: props.userId,
});
} else {
await os.alert({
@ -661,7 +698,7 @@ async function unassignRole(role, ev) {
}], ev.currentTarget ?? ev.target);
}
function toggleRoleItem(role) {
function toggleRoleItem(role: Misskey.entities.Role) {
if (expandedRoles.value.includes(role.id)) {
expandedRoles.value = expandedRoles.value.filter(x => x !== role.id);
} else {
@ -670,6 +707,7 @@ function toggleRoleItem(role) {
}
function createAnnouncement() {
if (!user.value) return;
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkUserAnnouncementEditDialog.vue')), {
user: user.value,
}, {
@ -678,6 +716,7 @@ function createAnnouncement() {
}
function editAnnouncement(announcement) {
if (!user.value) return;
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkUserAnnouncementEditDialog.vue')), {
user: user.value,
announcement,
@ -883,4 +922,13 @@ definePage(() => ({
margin: calc(var(--MI-margin) / 2);
}
}
.rawFolderHeader {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: flex-start;
padding: var(--MI-marginHalf);
gap: var(--MI-marginHalf);
}
</style>

View file

@ -49,7 +49,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkPagination v-slot="{items}" ref="reports" :pagination="pagination" :displayLimit="50">
<SkDateSeparatedList v-slot="{ item: report }" :items="items">
<XAbuseReport :report="report" @resolved="resolved"/>
<XAbuseReport :report="report" :metaHint="metaHint" @resolved="resolved"/>
</SkDateSeparatedList>
</MkPagination>
</div>
@ -59,6 +59,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { computed, useTemplateRef, ref } from 'vue';
import * as Misskey from 'misskey-js';
import MkSelect from '@/components/MkSelect.vue';
import MkPagination from '@/components/MkPagination.vue';
import XAbuseReport from '@/components/MkAbuseReport.vue';
@ -68,6 +69,8 @@ import MkButton from '@/components/MkButton.vue';
import MkInfo from '@/components/MkInfo.vue';
import { store } from '@/store.js';
import SkDateSeparatedList from '@/components/SkDateSeparatedList.vue';
import { iAmAdmin } from '@/i';
import { misskeyApi } from '@/utility/misskey-api';
const reports = useTemplateRef('reports');
@ -77,6 +80,14 @@ const targetUserOrigin = ref('combined');
const searchUsername = ref('');
const searchHost = ref('');
const metaHint = ref<Misskey.entities.AdminMetaResponse | undefined>(undefined);
if (iAmAdmin) {
misskeyApi('admin/meta')
.then(meta => metaHint.value = meta)
.catch(err => console.error('[MkAbuseReport] Error fetching meta:', err));
}
const pagination = {
endpoint: 'admin/abuse-user-reports' as const,
limit: 10,

View file

@ -14,6 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
ref="text"
class="_selectable"
:text="message.text"
:parsedNotes="parsed"
:i="$i"
:nyaize="'respect'"
:enableEmojiMenu="true"
@ -21,7 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only
/>
<MkMediaList v-if="message.file" :mediaList="[message.file]" :class="$style.file"/>
</MkFukidashi>
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :showAsQuote="!message.fromUser.rejectQuotes" style="margin: 8px 0;"/>
<SkUrlPreviewGroup :sourceNodes="parsed" :showAsQuote="!message.fromUser.rejectQuotes" style="margin: 8px 0;"/>
<div :class="$style.footer">
<button class="_textButton" style="color: currentColor;" @click="showMenu"><i class="ti ti-dots-circle-horizontal"></i></button>
<MkTime :class="$style.time" :time="message.createdAt"/>
@ -58,8 +59,6 @@ import { url } from '@@/js/config.js';
import { isLink } from '@@/js/is-link.js';
import type { MenuItem } from '@/types/menu.js';
import type { NormalizedChatMessage } from './room.vue';
import { extractUrlFromMfm } from '@/utility/extract-url-from-mfm.js';
import MkUrlPreview from '@/components/MkUrlPreview.vue';
import { ensureSignin } from '@/i.js';
import { misskeyApi } from '@/utility/misskey-api.js';
import { i18n } from '@/i18n.js';
@ -74,6 +73,7 @@ import { prefer } from '@/preferences.js';
import { DI } from '@/di.js';
import { getHTMLElementOrNull } from '@/utility/get-dom-node-or-null.js';
import SkTransitionGroup from '@/components/SkTransitionGroup.vue';
import SkUrlPreviewGroup from '@/components/SkUrlPreviewGroup.vue';
const $i = ensureSignin();
@ -83,7 +83,7 @@ const props = defineProps<{
}>();
const isMe = computed(() => props.message.fromUserId === $i.id);
const urls = computed(() => props.message.text ? extractUrlFromMfm(mfm.parse(props.message.text)) : []);
const parsed = computed(() => props.message.text ? mfm.parse(props.message.text) : []);
provide(DI.mfmEmojiReactCallback, (reaction) => {
if ($i.policies.chatAvailability !== 'available') return;

View file

@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<PageWithHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs" :spacer="true" style="--MI_SPACER-w: 600px; --MI_SPACER-min: 16px; --MI_SPACER-max: 32px;">
<PageWithHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs" :spacer="true" style="--MI_SPACER-w: 700px; --MI_SPACER-min: 16px; --MI_SPACER-max: 32px;">
<div v-if="instance">
<!-- This empty div is preserved to avoid merge conflicts -->
<div>

View file

@ -243,13 +243,13 @@ if (game.value.isStarted && !game.value.isEnded) {
useInterval(() => {
if (game.value.isEnded) return;
const crc32 = engine.value.calcCrc32();
if (_DEV_) console.log('crc32', crc32);
if (_DEV_) console.debug('crc32', crc32);
misskeyApi('reversi/verify', {
gameId: game.value.id,
crc32: crc32.toString(),
}).then((res) => {
if (res.desynced) {
if (_DEV_) console.log('resynced');
if (_DEV_) console.debug('resynced');
restoreGame(res.game!);
}
});

View file

@ -23,24 +23,8 @@ import { i18n } from '@/i18n.js';
import { definePage } from '@/page.js';
import { miLocalStorage } from '@/local-storage.js';
import { prefer } from '@/preferences.js';
import { reloadAsk } from '@/utility/reload-ask';
const customCssModel = prefer.model('customCss');
const localCustomCss = computed<string>({
get() {
return customCssModel.value ?? miLocalStorage.getItem('customCss') ?? '';
},
set(newCustomCss) {
customCssModel.value = newCustomCss;
if (newCustomCss) {
miLocalStorage.setItem('customCss', newCustomCss);
} else {
miLocalStorage.removeItem('customCss');
}
reloadAsk(true);
},
});
const localCustomCss = prefer.model('customCss');
const headerActions = computed(() => []);

View file

@ -1059,68 +1059,13 @@ const clickToOpen = prefer.model('clickToOpen');
const useCustomSearchEngine = computed(() => !Object.keys(searchEngineMap).includes(searchEngine.value));
const defaultCW = ref($i.defaultCW);
const defaultCWPriority = ref($i.defaultCWPriority);
const langModel = prefer.model('lang');
const lang = computed<string>({
get() {
return langModel.value ?? miLocalStorage.getItem('lang') ?? 'en-US';
},
set(newLang) {
langModel.value = newLang;
miLocalStorage.setItem('lang', newLang);
miLocalStorage.removeItem('locale');
miLocalStorage.removeItem('localeVersion');
},
});
const fontSizeModel = prefer.model('fontSize');
const fontSize = computed<'0' | '1' | '2' | '3'>({
get() {
return fontSizeModel.value ?? miLocalStorage.getItem('fontSize') ?? '0';
},
set(newFontSize) {
fontSizeModel.value = newFontSize;
if (newFontSize !== '0') {
miLocalStorage.setItem('fontSize', newFontSize);
} else {
miLocalStorage.removeItem('fontSize');
}
},
});
const useSystemFontModel = prefer.model('useSystemFont');
const useSystemFont = computed<boolean>({
get() {
return useSystemFontModel.value ?? (miLocalStorage.getItem('useSystemFont') != null);
},
set(newUseSystemFont) {
useSystemFontModel.value = newUseSystemFont;
if (newUseSystemFont) {
miLocalStorage.setItem('useSystemFont', 't');
} else {
miLocalStorage.removeItem('useSystemFont');
}
},
});
const cornerRadiusModel = prefer.model('cornerRadius');
const cornerRadius = computed<'misskey' | 'sharkey'>({
get() {
return cornerRadiusModel.value ?? miLocalStorage.getItem('cornerRadius') ?? 'sharkey';
},
set(newCornerRadius) {
cornerRadiusModel.value = newCornerRadius;
if (newCornerRadius === 'sharkey') {
miLocalStorage.removeItem('cornerRadius');
} else {
miLocalStorage.setItem('cornerRadius', newCornerRadius);
}
},
});
const lang = prefer.model('lang');
const fontSize = prefer.model('fontSize');
const useSystemFont = prefer.model('useSystemFont');
const cornerRadius = prefer.model('cornerRadius');
watch([
hemisphere,
lang,
enableInfiniteScroll,
showNoteActionsOnlyHover,
overridedDeviceKind,
@ -1142,9 +1087,6 @@ watch([
useStickyIcons,
keepScreenOn,
contextMenu,
fontSize,
useSystemFont,
cornerRadius,
makeEveryTextElementsSelectable,
noteDesign,
], async () => {

View file

@ -13,15 +13,18 @@ import { deckStore } from '@/ui/deck/deck-store.js';
import { unisonReload } from '@/utility/unison-reload.js';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { miLocalStorage } from '@/local-storage';
// TODO: そのうち消す
export function migrateOldSettings() {
os.waiting(i18n.ts.settingsMigrating);
store.loaded.then(async () => {
misskeyApi('i/registry/get', { scope: ['client'], key: 'themes' }).catch(() => []).then((themes: Theme[]) => {
if (themes.length > 0) {
prefer.commit('themes', themes);
prefer.suppressReload();
await misskeyApi('i/registry/get', { scope: ['client'], key: 'themes' }).catch(() => []).then(themes => {
if (Array.isArray(themes) && themes.length > 0) {
prefer.commit('themes', themes as Theme[]);
}
});
@ -33,7 +36,7 @@ export function migrateOldSettings() {
})));
prefer.commit('deck.profile', deckStore.s.profile);
misskeyApi('i/registry/keys', {
await misskeyApi('i/registry/keys', {
scope: ['client', 'deck', 'profiles'],
}).then(async keys => {
const profiles: DeckProfile[] = [];
@ -41,16 +44,18 @@ export function migrateOldSettings() {
const deck = await misskeyApi('i/registry/get', {
scope: ['client', 'deck', 'profiles'],
key: key,
});
profiles.push({
id: uuid(),
name: key,
columns: deck.columns,
layout: deck.layout,
});
}).catch(() => null);
if (deck) {
profiles.push({
id: uuid(),
name: key,
columns: (deck as DeckProfile).columns,
layout: (deck as DeckProfile).layout,
});
}
}
prefer.commit('deck.profiles', profiles);
});
}).catch(() => null);
prefer.commit('lightTheme', ColdDeviceStorage.get('lightTheme'));
prefer.commit('darkTheme', ColdDeviceStorage.get('darkTheme'));
@ -164,8 +169,17 @@ export function migrateOldSettings() {
prefer.commit('warnMissingAltText', store.s.warnMissingAltText);
//#endregion
window.setTimeout(() => {
unisonReload();
}, 10000);
//#region Hybrid migrations
prefer.commit('fontSize', miLocalStorage.getItem('fontSize') ?? '0');
prefer.commit('useSystemFont', miLocalStorage.getItem('useSystemFont') != null);
prefer.commit('cornerRadius', miLocalStorage.getItem('cornerRadius') ?? 'sharkey');
prefer.commit('lang', miLocalStorage.getItem('lang') ?? 'en-US');
prefer.commit('customCss', miLocalStorage.getItem('customCss') ?? '');
prefer.commit('neverShowDonationInfo', miLocalStorage.getItem('neverShowDonationInfo') != null);
prefer.commit('neverShowLocalOnlyInfo', miLocalStorage.getItem('neverShowLocalOnlyInfo') != null);
//#endregion
prefer.allowReload();
unisonReload();
});
}

View file

@ -130,7 +130,7 @@ function syncBetweenTabs() {
latestSyncedAt = Date.now();
if (_DEV_) console.log('prefer:synced');
if (_DEV_) console.debug('prefer:synced');
}
window.setInterval(syncBetweenTabs, 5000);

View file

@ -10,11 +10,12 @@ import type { SoundType } from '@/utility/sound.js';
import type { Plugin } from '@/plugin.js';
import type { DeviceKind } from '@/utility/device-kind.js';
import type { DeckProfile } from '@/deck.js';
import type { PreferencesDefinition } from './manager.js';
import type { Pref, PreferencesDefinition } from './manager.js';
import type { FollowingFeedState } from '@/types/following-feed.js';
import { DEFAULT_DEVICE_KIND } from '@/utility/device-kind.js';
import { searchEngineMap } from '@/utility/search-engine-map.js';
import { defaultFollowingFeedState } from '@/types/following-feed.js';
import { miLocalStorage } from '@/local-storage';
/** サウンド設定 */
export type SoundStore = {
@ -484,25 +485,77 @@ export const PREF_DEF = {
// Null means "fall back to existing value from localStorage"
// For all of these preferences, "null" means fall back to existing value in localStorage.
fontSize: {
default: null as null | '0' | '1' | '2' | '3',
},
default: '0',
needsReload: true,
onSet: fontSize => {
if (fontSize !== '0') {
miLocalStorage.setItem('fontSize', fontSize);
} else {
miLocalStorage.removeItem('fontSize');
}
},
} as Pref<'0' | '1' | '2' | '3'>,
useSystemFont: {
default: null as null | boolean,
},
default: false,
needsReload: true,
onSet: useSystemFont => {
if (useSystemFont) {
miLocalStorage.setItem('useSystemFont', 't');
} else {
miLocalStorage.removeItem('useSystemFont');
}
},
} as Pref<boolean>,
cornerRadius: {
default: null as null | 'misskey' | 'sharkey',
},
default: 'sharkey',
needsReload: true,
onSet: cornerRadius => {
if (cornerRadius === 'sharkey') {
miLocalStorage.removeItem('cornerRadius');
} else {
miLocalStorage.setItem('cornerRadius', cornerRadius);
}
},
} as Pref<'misskey' | 'sharkey'>,
lang: {
default: null as null | string,
},
default: 'en-US',
needsReload: true,
onSet: lang => {
miLocalStorage.setItem('lang', lang);
miLocalStorage.removeItem('locale');
miLocalStorage.removeItem('localeVersion');
},
} as Pref<string>,
customCss: {
default: null as null | string,
},
default: '',
needsReload: true,
onSet: customCss => {
if (customCss) {
miLocalStorage.setItem('customCss', customCss);
} else {
miLocalStorage.removeItem('customCss');
}
},
} as Pref<string>,
neverShowDonationInfo: {
default: null as null | 'true',
},
default: false,
onSet: neverShowDonationInfo => {
if (neverShowDonationInfo) {
miLocalStorage.setItem('neverShowDonationInfo', 'true');
} else {
miLocalStorage.removeItem('neverShowDonationInfo');
}
},
} as Pref<boolean>,
neverShowLocalOnlyInfo: {
default: null as null | 'true',
},
default: false,
onSet: neverShowLocalOnlyInfo => {
if (neverShowLocalOnlyInfo) {
miLocalStorage.setItem('neverShowLocalOnlyInfo', 'true');
} else {
miLocalStorage.removeItem('neverShowLocalOnlyInfo');
}
},
} as Pref<boolean>,
//#endregion
} satisfies PreferencesDefinition;

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { computed, onUnmounted, ref, watch } from 'vue';
import { computed, nextTick, onUnmounted, ref, watch } from 'vue';
import { v4 as uuid } from 'uuid';
import { host, version } from '@@/js/config.js';
import { PREF_DEF } from './def.js';
@ -14,6 +14,7 @@ import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
import { i18n } from '@/i18n.js';
import * as os from '@/os.js';
import { deepEqual } from '@/utility/deep-equal.js';
import { reloadAsk } from '@/utility/reload-ask';
// NOTE: 明示的な設定値のひとつとして null もあり得るため、設定が存在しないかどうかを判定する目的で null で比較したり ?? を使ってはいけない
@ -84,16 +85,29 @@ export type StorageProvider = {
cloudSet: <K extends keyof PREF>(ctx: { key: K; scope: Scope; value: ValueOf<K>; }) => Promise<void>;
};
export type PreferencesDefinition = Record<string, {
default: any;
export type Pref<T> = {
default: T;
accountDependent?: boolean;
serverDependent?: boolean;
}>;
needsReload?: boolean;
onSet?: (value: T) => void;
};
export type PreferencesDefinition = Record<string, Pref<any> | undefined>;
export class PreferencesManager {
private storageProvider: StorageProvider;
public profile: PreferencesProfile;
public cloudReady: Promise<void>;
private enableReload = true;
public suppressReload() {
this.enableReload = false;
}
public allowReload() {
this.enableReload = true;
}
/**
* static / state (static )
@ -126,11 +140,11 @@ export class PreferencesManager {
}
private isAccountDependentKey<K extends keyof PREF>(key: K): boolean {
return (PREF_DEF as PreferencesDefinition)[key].accountDependent === true;
return (PREF_DEF as PreferencesDefinition)[key]?.accountDependent === true;
}
private isServerDependentKey<K extends keyof PREF>(key: K): boolean {
return (PREF_DEF as PreferencesDefinition)[key].serverDependent === true;
return (PREF_DEF as PreferencesDefinition)[key]?.serverDependent === true;
}
private rewriteRawState<K extends keyof PREF>(key: K, value: ValueOf<K>) {
@ -142,14 +156,28 @@ export class PreferencesManager {
const v = JSON.parse(JSON.stringify(value)); // deep copy 兼 vueのプロキシ解除
if (deepEqual(this.s[key], v)) {
if (_DEV_) console.log('(skip) prefer:commit', key, v);
if (_DEV_) console.debug('(skip) prefer:commit', key, v);
return;
}
if (_DEV_) console.log('prefer:commit', key, v);
if (_DEV_) console.debug('prefer:commit', key, v);
this.rewriteRawState(key, v);
const pref = (PREF_DEF as PreferencesDefinition)[key];
if (pref) {
// Call custom setter
if (pref.onSet) {
pref.onSet(v);
}
// Prompt to reload the frontend
if (pref.needsReload && this.enableReload) {
// noinspection JSIgnoredPromiseFromCall
nextTick(() => reloadAsk({ unison: true }));
}
}
const record = this.getMatchedRecordOf(key);
if (parseScope(record[0]).account == null && this.isAccountDependentKey(key)) {
@ -250,13 +278,13 @@ export class PreferencesManager {
if (!deepEqual(cloudValue, record[1])) {
this.rewriteRawState(key, cloudValue);
record[1] = cloudValue;
if (_DEV_) console.log('cloud fetched', key, cloudValue);
if (_DEV_) console.debug('cloud fetched', key, cloudValue);
}
}
}
this.save();
if (_DEV_) console.log('cloud fetch completed');
if (_DEV_) console.debug('cloud fetch completed');
}
public static newProfile(): PreferencesProfile {

View file

@ -153,7 +153,7 @@ export async function restoreFromCloudBackup() {
scope: ['client', 'preferences', 'backups'],
});
if (_DEV_) console.log(keys);
if (_DEV_) console.debug(keys);
if (keys.length === 0) {
os.alert({
@ -179,7 +179,7 @@ export async function restoreFromCloudBackup() {
key: select.result,
});
if (_DEV_) console.log(profile);
if (_DEV_) console.debug(profile);
miLocalStorage.setItem('preferences', JSON.stringify(profile));
miLocalStorage.setItem('hidePreferencesRestoreSuggestion', 'true');

View file

@ -211,7 +211,9 @@ rt {
max-width: min(var(--MI_SPACER-w, 100%), calc(100% - (var(--MI_SPACER-max, 24px) * 2)));
margin: var(--MI_SPACER-max, 24px) auto;
container-type: inline-size;
}
._spacer > * {
/* 子に継承させない */
--MI_SPACER-w: initial;
--MI_SPACER-min: initial;

View file

@ -8,4 +8,4 @@ import { v4 as uuid } from 'uuid';
// HMR有効時にバグか知らんけど複数回実行されるのでその対策
export const TAB_ID = window.sessionStorage.getItem('TAB_ID') ?? uuid();
window.sessionStorage.setItem('TAB_ID', TAB_ID);
if (_DEV_) console.log('TAB_ID', TAB_ID);
if (_DEV_) console.debug('TAB_ID', TAB_ID);

View file

@ -531,7 +531,7 @@ export function getNoteMenu(props: {
}
const cleanup = () => {
if (_DEV_) console.log('note menu cleanup', cleanups);
if (_DEV_) console.debug('note menu cleanup', cleanups);
for (const cl of cleanups) {
cl();
}

View file

@ -54,7 +54,7 @@ export async function getNoteVersionsMenu(props: { note: Misskey.entities.Note }
});
const cleanup = () => {
if (_DEV_) console.log('note menu cleanup', cleanups);
if (_DEV_) console.debug('note menu cleanup', cleanups);
for (const cl of cleanups) {
cl();
}

View file

@ -443,7 +443,7 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: Router
return {
menu: menuItems,
cleanup: () => {
if (_DEV_) console.log('user menu cleanup', cleanups);
if (_DEV_) console.debug('user menu cleanup', cleanups);
for (const cl of cleanups) {
cl();
}

View file

@ -19,7 +19,7 @@ try {
});
} catch (err) {
console.warn(err);
if (_DEV_) console.log('[Intl] Fallback to en-US');
if (_DEV_) console.debug('[Intl] Fallback to en-US');
// Fallback to en-US
_dateTimeFormat = new Intl.DateTimeFormat('en-US', {
@ -42,7 +42,7 @@ try {
_numberFormat = new Intl.NumberFormat(versatileLang);
} catch (err) {
console.warn(err);
if (_DEV_) console.log('[Intl] Fallback to en-US');
if (_DEV_) console.debug('[Intl] Fallback to en-US');
// Fallback to en-US
_numberFormat = new Intl.NumberFormat('en-US');

View file

@ -134,7 +134,7 @@ export function playMisskeySfx(operationType: OperationType) {
if (!succeed && sound.type === '_driveFile_') {
// ドライブファイルが存在しない場合はデフォルトのサウンドを再生する
const soundName = PREF_DEF[`sound_${operationType}`].default.type as Exclude<SoundType, '_driveFile_'>;
if (_DEV_) console.log(`Failed to play sound: ${sound.fileUrl}, so play default sound: ${soundName}`);
if (_DEV_) console.debug(`Failed to play sound: ${sound.fileUrl}, so play default sound: ${soundName}`);
playMisskeySfxFileInternal({
type: soundName,
volume: sound.volume,