Merge upstream
This commit is contained in:
commit
5f931855be
147 changed files with 1778 additions and 1044 deletions
|
@ -62,7 +62,7 @@
|
|||
"rollup": "4.29.1",
|
||||
"sanitize-html": "2.14.0",
|
||||
"sass": "1.83.0",
|
||||
"shiki": "1.24.3",
|
||||
"shiki": "1.24.4",
|
||||
"strict-event-emitter-types": "2.0.0",
|
||||
"textarea-caret": "3.1.0",
|
||||
"three": "0.171.0",
|
||||
|
@ -73,7 +73,7 @@
|
|||
"typescript": "5.7.2",
|
||||
"uuid": "11.0.3",
|
||||
"v-code-diff": "1.13.1",
|
||||
"vite": "6.0.5",
|
||||
"vite": "6.0.6",
|
||||
"vue": "3.5.13",
|
||||
"vue-gtag": "2.0.1",
|
||||
"vuedraggable": "next",
|
||||
|
@ -124,7 +124,7 @@
|
|||
"eslint-plugin-import": "2.31.0",
|
||||
"eslint-plugin-vue": "9.32.0",
|
||||
"fast-glob": "3.3.2",
|
||||
"happy-dom": "15.11.7",
|
||||
"happy-dom": "16.0.1",
|
||||
"intersection-observer": "0.12.2",
|
||||
"micromatch": "4.0.8",
|
||||
"msw": "2.7.0",
|
||||
|
@ -139,8 +139,8 @@
|
|||
"vite-plugin-turbosnap": "1.0.3",
|
||||
"vitest": "2.1.8",
|
||||
"vitest-fetch-mock": "0.3.0",
|
||||
"vue-component-type-helpers": "2.1.10",
|
||||
"vue-component-type-helpers": "2.2.0",
|
||||
"vue-eslint-parser": "9.4.3",
|
||||
"vue-tsc": "2.1.10"
|
||||
"vue-tsc": "2.2.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<audio
|
||||
ref="audioEl"
|
||||
preload="metadata"
|
||||
crossorigin="anonymous"
|
||||
controls
|
||||
:class="$style.nativeAudio"
|
||||
@keydown.prevent
|
||||
|
@ -41,6 +42,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<audio
|
||||
ref="audioEl"
|
||||
preload="metadata"
|
||||
crossorigin="anonymous"
|
||||
>
|
||||
<source :src="audio.url">
|
||||
</audio>
|
||||
|
|
|
@ -34,6 +34,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
:title="video.comment ?? undefined"
|
||||
:alt="video.comment"
|
||||
preload="metadata"
|
||||
crossorigin="anonymous"
|
||||
controls
|
||||
@keydown.prevent
|
||||
>
|
||||
|
@ -54,6 +55,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
:title="video.comment ?? undefined"
|
||||
:alt="video.comment"
|
||||
preload="metadata"
|
||||
crossorigin="anonymous"
|
||||
playsinline
|
||||
@keydown.prevent
|
||||
@click.self="togglePlayPause"
|
||||
|
|
|
@ -241,7 +241,7 @@ function loginFailed(err: any): void {
|
|||
os.alert({
|
||||
type: 'error',
|
||||
title: i18n.ts.loginFailed,
|
||||
text: i18n.ts.incorrectPassword,
|
||||
text: i18n.ts.authenticationFailed,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -18,12 +18,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { computed, watch, onUnmounted, provide, shallowRef } from 'vue';
|
||||
import { time as gtagTime } from 'vue-gtag';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import MkNotes from '@/components/MkNotes.vue';
|
||||
import MkPullToRefresh from '@/components/MkPullToRefresh.vue';
|
||||
import { useStream } from '@/stream.js';
|
||||
import * as sound from '@/scripts/sound.js';
|
||||
import { deepMerge } from '@/scripts/merge.js';
|
||||
import { $i, iAmModerator } from '@/account.js';
|
||||
import { instance } from '@/instance.js';
|
||||
import { defaultStore } from '@/store.js';
|
||||
|
@ -76,9 +76,8 @@ async function prepend(data) {
|
|||
let note = data;
|
||||
|
||||
// チェックするプロパティはなんでも良い
|
||||
// idOnlyが有効でid以外が存在しない場合は取得する
|
||||
// minimizeが有効でid以外が存在しない場合は取得する
|
||||
if (!data.visibility) {
|
||||
const initiateTime = Date.now();
|
||||
const res = await window.fetch(`/notes/${data.id}.json`, {
|
||||
method: 'GET',
|
||||
credentials: 'omit',
|
||||
|
@ -86,18 +85,9 @@ async function prepend(data) {
|
|||
'Authorization': 'anonymous',
|
||||
'X-Client-Transaction-Id': generateClientTransactionId('misskey'),
|
||||
},
|
||||
}).then(res => {
|
||||
if (instance.googleAnalyticsId) {
|
||||
gtagTime({
|
||||
name: 'api-get',
|
||||
event_category: `/notes/${data.id}.json`,
|
||||
value: Date.now() - initiateTime,
|
||||
});
|
||||
}
|
||||
return res;
|
||||
});
|
||||
if (!res.ok) return;
|
||||
note = await res.json();
|
||||
note = deepMerge(data, await res.json());
|
||||
}
|
||||
|
||||
tlNotesCount++;
|
||||
|
@ -118,7 +108,7 @@ async function prepend(data) {
|
|||
let connection: Misskey.ChannelConnection | null = null;
|
||||
let connection2: Misskey.ChannelConnection | null = null;
|
||||
let paginationQuery: Paging | null = null;
|
||||
const idOnly = !iAmModerator;
|
||||
const minimize = !iAmModerator;
|
||||
|
||||
const stream = useStream();
|
||||
|
||||
|
@ -127,13 +117,13 @@ function connectChannel() {
|
|||
if (props.antenna == null) return;
|
||||
connection = stream.useChannel('antenna', {
|
||||
antennaId: props.antenna,
|
||||
idOnly: idOnly,
|
||||
minimize: minimize,
|
||||
});
|
||||
} else if (props.src === 'home') {
|
||||
connection = stream.useChannel('homeTimeline', {
|
||||
withRenotes: props.withRenotes,
|
||||
withFiles: props.onlyFiles ? true : undefined,
|
||||
idOnly: idOnly,
|
||||
minimize: minimize,
|
||||
});
|
||||
connection2 = stream.useChannel('main');
|
||||
} else if (props.src === 'local') {
|
||||
|
@ -141,27 +131,27 @@ function connectChannel() {
|
|||
withRenotes: props.withRenotes,
|
||||
withReplies: props.withReplies,
|
||||
withFiles: props.onlyFiles ? true : undefined,
|
||||
idOnly: idOnly,
|
||||
minimize: minimize,
|
||||
});
|
||||
} else if (props.src === 'media') {
|
||||
connection = stream.useChannel('hybridTimeline', {
|
||||
withRenotes: props.withRenotes,
|
||||
withReplies: props.withReplies,
|
||||
withFiles: true,
|
||||
idOnly: idOnly,
|
||||
minimize: minimize,
|
||||
});
|
||||
} else if (props.src === 'social') {
|
||||
connection = stream.useChannel('hybridTimeline', {
|
||||
withRenotes: props.withRenotes,
|
||||
withReplies: props.withReplies,
|
||||
withFiles: props.onlyFiles ? true : undefined,
|
||||
idOnly: idOnly,
|
||||
minimize: minimize,
|
||||
});
|
||||
} else if (props.src === 'global') {
|
||||
connection = stream.useChannel('globalTimeline', {
|
||||
withRenotes: props.withRenotes,
|
||||
withFiles: props.onlyFiles ? true : undefined,
|
||||
idOnly: idOnly,
|
||||
minimize: minimize,
|
||||
});
|
||||
} else if (props.src === 'mentions') {
|
||||
connection = stream.useChannel('main');
|
||||
|
@ -180,19 +170,19 @@ function connectChannel() {
|
|||
withRenotes: props.withRenotes,
|
||||
withFiles: props.onlyFiles ? true : undefined,
|
||||
listId: props.list,
|
||||
idOnly: idOnly,
|
||||
minimize: minimize,
|
||||
});
|
||||
} else if (props.src === 'channel') {
|
||||
if (props.channel == null) return;
|
||||
connection = stream.useChannel('channel', {
|
||||
channelId: props.channel,
|
||||
idOnly: idOnly,
|
||||
minimize: minimize,
|
||||
});
|
||||
} else if (props.src === 'role') {
|
||||
if (props.role == null) return;
|
||||
connection = stream.useChannel('roleTimeline', {
|
||||
roleId: props.role,
|
||||
idOnly: idOnly,
|
||||
minimize: minimize,
|
||||
});
|
||||
}
|
||||
if (props.src !== 'directs' && props.src !== 'mentions') connection?.on('note', prepend);
|
||||
|
|
|
@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<template>
|
||||
<div v-if="instance" :class="$style.root">
|
||||
<div :class="[$style.main, $style.panel]">
|
||||
<img v-if="miLocalStorage.getItem('kawaii')" src="/client-assets/kawaii/about-icon.png" alt="Logo by @sawaratsuki@misskey.io" :class="$style.mainIconAlt"/>
|
||||
<img v-if="kawaiiMode" src="/client-assets/kawaii/about-icon.png" alt="Logo by @sawaratsuki@misskey.io" :class="$style.mainIconAlt"/>
|
||||
<img v-else :src="instance.iconUrl || '/favicon.ico'" alt="" :class="$style.mainIcon"/>
|
||||
<button class="_button" style="background: none;" :class="$style.mainMenu" @click="showMenu"><i class="ti ti-dots"></i></button>
|
||||
<div :class="$style.mainFg">
|
||||
|
@ -89,6 +89,7 @@ import MkNumber from '@/components/MkNumber.vue';
|
|||
import XActiveUsersChart from '@/components/MkVisitorDashboard.ActiveUsersChart.vue';
|
||||
import { openInstanceMenu } from '@/ui/_common_/common.js';
|
||||
|
||||
const kawaiiMode = miLocalStorage.getItem('kawaii') === 'true';
|
||||
const stats = ref<Misskey.entities.StatsResponse | null>(null);
|
||||
|
||||
misskeyApiGet('stats').then((res) => {
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<title>[DEV] Loading...</title>
|
||||
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
|
||||
<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
http-equiv="Content-Security-Policy-Report-Only"
|
||||
content="default-src 'self' https://newassets.hcaptcha.com/ https://challenges.cloudflare.com/ http://localhost:7493/ https://fonts.gstatic.com/ https://www.google-analytics.com/ https://www.googletagmanager.com/;
|
||||
worker-src 'self';
|
||||
script-src 'self' 'unsafe-eval' https://*.hcaptcha.com https://challenges.cloudflare.com https://www.googletagmanager.com https://esm.sh;
|
||||
|
|
|
@ -15,6 +15,8 @@ import { ui, host } from '@/config.js';
|
|||
import { unisonReload } from '@/scripts/unison-reload.js';
|
||||
import { instance } from '@/instance.js';
|
||||
|
||||
const kawaiiMode = miLocalStorage.getItem('kawaii') === 'true';
|
||||
|
||||
export const navbarItemDef = reactive({
|
||||
notifications: {
|
||||
title: i18n.ts.notifications,
|
||||
|
@ -178,10 +180,21 @@ export const navbarItemDef = reactive({
|
|||
show: computed(() => $i != null),
|
||||
to: `/@${$i?.username}`,
|
||||
},
|
||||
kawaii: {
|
||||
title: kawaiiMode ? 'no uwu plz' : 'uwu?',
|
||||
icon: kawaiiMode ? 'ti ti-mood-smile' : 'ti ti-mood-wink',
|
||||
action: (ev) => {
|
||||
if (kawaiiMode) miLocalStorage.removeItem('kawaii');
|
||||
else miLocalStorage.setItem('kawaii', 'true');
|
||||
location.reload();
|
||||
},
|
||||
},
|
||||
support: {
|
||||
title: i18n.tsx.supportThisInstance({ name: instance.name ?? host }),
|
||||
icon: 'ti ti-pig-money',
|
||||
to: 'https://patreon.com/nrmaa',
|
||||
action: (ev) => {
|
||||
window.open('https://patreon.com/nrmaa', '_blank', 'noopener');
|
||||
},
|
||||
},
|
||||
cacheClear: {
|
||||
title: i18n.ts.clearCache,
|
||||
|
|
|
@ -11,9 +11,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<div class="_gaps_m znqjceqz">
|
||||
<div v-panel class="about">
|
||||
<div ref="containerEl" class="container" :class="{ playing: easterEggEngine != null }">
|
||||
<img v-if="miLocalStorage.getItem('kawaii')" src="/client-assets/kawaii/about-icon.png" alt="" class="iconAlt" draggable="false" @load="iconLoaded" @click="gravity"/>
|
||||
<img v-if="kawaiiMode" src="/client-assets/kawaii/about-icon.png" alt="" class="iconAlt" draggable="false" @load="iconLoaded" @click="gravity"/>
|
||||
<img v-else src="/client-assets/about-icon.png" alt="" class="icon" draggable="false" @load="iconLoaded" @click="gravity"/>
|
||||
<Mfm v-if="miLocalStorage.getItem('kawaii')" text="Logo by @sawaratsuki@misskey.io" class="iconCredit"/>
|
||||
<Mfm v-if="kawaiiMode" text="Logo by @sawaratsuki@misskey.io" class="iconCredit"/>
|
||||
<div class="misskey">Misskey</div>
|
||||
<div class="version">v{{ version }}</div>
|
||||
<span v-for="emoji in easterEggEmojis" :key="emoji.id" class="emoji" :data-physics-x="emoji.left" :data-physics-y="emoji.top" :class="{ _physics_circle_: !emoji.emoji.startsWith(':') }">
|
||||
|
@ -145,6 +145,8 @@ import { definePageMetadata } from '@/scripts/page-metadata.js';
|
|||
import { claimAchievement, claimedAchievements } from '@/scripts/achievements.js';
|
||||
import { $i } from '@/account.js';
|
||||
|
||||
const kawaiiMode = miLocalStorage.getItem('kawaii') === 'true';
|
||||
|
||||
const patronsWithIcon = [{
|
||||
name: 'カイヤン',
|
||||
icon: 'https://assets.misskey-hub.net/patrons/a2820716883e408cb87773e377ce7c8d.jpg',
|
||||
|
|
|
@ -11,9 +11,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<div class="_gaps_m">
|
||||
<div :class="$style.banner" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }">
|
||||
<div style="overflow: clip;">
|
||||
<img v-if="miLocalStorage.getItem('kawaii')" src="/client-assets/kawaii/about-icon.png" alt="" :class="$style.bannerIconAlt"/>
|
||||
<img v-else :src="instance.iconUrl ?? '/favicon.ico'" alt="" :class="$style.bannerIcon"/>
|
||||
<Mfm v-if="miLocalStorage.getItem('kawaii')" text="Logo by @sawaratsuki@misskey.io" :class="$style.iconCredit"/>
|
||||
<img v-if="kawaiiMode" src="/client-assets/kawaii/about-icon.png" alt="" :class="$style.bannerIconAlt"/>
|
||||
<img v-else :src="instance.iconUrl ?? instance.faviconUrl ?? '/favicon.ico'" alt="" :class="$style.bannerIcon"/>
|
||||
<Mfm v-if="kawaiiMode" text="Logo by @sawaratsuki@misskey.io" :class="$style.iconCredit"/>
|
||||
<div :class="$style.bannerName">
|
||||
<b>{{ instance.name ?? host }}</b>
|
||||
</div>
|
||||
|
@ -211,6 +211,7 @@ const props = withDefaults(defineProps<{
|
|||
initialTab: 'overview',
|
||||
});
|
||||
|
||||
const kawaiiMode = miLocalStorage.getItem('kawaii') === 'true';
|
||||
const stats = ref<Misskey.entities.StatsResponse | null>(null);
|
||||
const tab = ref(props.initialTab);
|
||||
const staffs = ref<Misskey.entities.User[]>([]);
|
||||
|
|
|
@ -133,6 +133,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</div>
|
||||
<div v-if="expandedRoles.includes(role.id)" :class="$style.roleItemSub">
|
||||
<div>Assigned: <MkTime :time="info.roleAssigns.find(a => a.roleId === role.id).createdAt" mode="detail"/></div>
|
||||
<div v-if="info.roleAssigns.find(a => a.roleId === role.id).memo">Memo: {{ info.roleAssigns.find(a => a.roleId === role.id).memo }}</div>
|
||||
<div v-if="info.roleAssigns.find(a => a.roleId === role.id).expiresAt">Period: {{ new Date(info.roleAssigns.find(a => a.roleId === role.id).expiresAt).toLocaleString() }}</div>
|
||||
<div v-else>Period: {{ i18n.ts.indefinitely }}</div>
|
||||
</div>
|
||||
|
@ -502,8 +503,15 @@ async function assignRole() {
|
|||
: period === 'oneMonth' ? Date.now() + (1000 * 60 * 60 * 24 * 30)
|
||||
: null;
|
||||
|
||||
const { canceled: canceled3, result: memo } = await os.inputText({
|
||||
title: i18n.ts.addMemo,
|
||||
type: 'textarea',
|
||||
placeholder: i18n.ts.memo,
|
||||
});
|
||||
if (canceled3) return;
|
||||
|
||||
await os.apiWithDialog('admin/roles/assign', {
|
||||
roleId, userId: user.value.id, expiresAt,
|
||||
roleId, userId: user.value.id, memo: memo ?? undefined, expiresAt,
|
||||
}).then(refreshUser);
|
||||
}
|
||||
|
||||
|
|
|
@ -91,10 +91,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<template v-else-if="log.type === 'assignRole'">
|
||||
<div>{{ i18n.ts.user }}: {{ log.info.userId }}</div>
|
||||
<div>{{ i18n.ts.role }}: {{ log.info.roleName }} [{{ log.info.roleId }}]</div>
|
||||
<div>{{ i18n.ts.memo }}: {{ log.info.memo }}</div>
|
||||
<div>{{ i18n.ts.expirationDate }}: {{ log.info.expiresAt ?? i18n.ts.indefinitely }}</div>
|
||||
</template>
|
||||
<template v-else-if="log.type === 'unassignRole'">
|
||||
<div>{{ i18n.ts.user }}: {{ log.info.userId }}</div>
|
||||
<div>{{ i18n.ts.role }}: {{ log.info.roleName }} [{{ log.info.roleId }}]</div>
|
||||
<div>{{ i18n.ts.memo }}: {{ log.info.memo }}</div>
|
||||
</template>
|
||||
<template v-else-if="log.type === 'updateCustomEmoji'">
|
||||
<div>{{ i18n.ts.emoji }}: {{ log.info.emojiId }}</div>
|
||||
|
|
|
@ -45,6 +45,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</div>
|
||||
<div v-if="expandedItems.includes(item.id)" :class="$style.userItemSub">
|
||||
<div>Assigned: <MkTime :time="item.createdAt" mode="detail"/></div>
|
||||
<div v-if="item.memo">Memo: {{ item.memo }}</div>
|
||||
<div v-if="item.expiresAt">Period: {{ new Date(item.expiresAt).toLocaleString() }}</div>
|
||||
<div v-else>Period: {{ i18n.ts.indefinitely }}</div>
|
||||
</div>
|
||||
|
@ -142,7 +143,14 @@ async function assign() {
|
|||
: period === 'oneMonth' ? Date.now() + (1000 * 60 * 60 * 24 * 30)
|
||||
: null;
|
||||
|
||||
await os.apiWithDialog('admin/roles/assign', { roleId: role.id, userId: user.id, expiresAt });
|
||||
const { canceled: canceled3, result: memo } = await os.inputText({
|
||||
title: i18n.ts.addMemo,
|
||||
type: 'textarea',
|
||||
placeholder: i18n.ts.memo,
|
||||
});
|
||||
if (canceled3) return;
|
||||
|
||||
await os.apiWithDialog('admin/roles/assign', { roleId: role.id, userId: user.id, memo: memo ?? undefined, expiresAt });
|
||||
//role.users.push(user);
|
||||
}
|
||||
|
||||
|
|
|
@ -303,7 +303,14 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter
|
|||
: period === 'oneMonth' ? Date.now() + (1000 * 60 * 60 * 24 * 30)
|
||||
: null;
|
||||
|
||||
os.apiWithDialog('admin/roles/assign', { roleId: r.id, userId: user.id, expiresAt });
|
||||
const { canceled: canceled3, result: memo } = await os.inputText({
|
||||
title: i18n.ts.addMemo,
|
||||
type: 'textarea',
|
||||
placeholder: i18n.ts.memo,
|
||||
});
|
||||
if (canceled3) return;
|
||||
|
||||
os.apiWithDialog('admin/roles/assign', { roleId: r.id, userId: user.id, memo: memo ?? undefined, expiresAt });
|
||||
},
|
||||
}));
|
||||
},
|
||||
|
|
|
@ -7,7 +7,7 @@ import * as Misskey from 'misskey-js';
|
|||
import { $i } from '@/account.js';
|
||||
|
||||
export function isFollowingVisibleForMe(user: Misskey.entities.UserDetailed): boolean {
|
||||
if ($i && $i.id === user.id) return true;
|
||||
if ($i && ($i.id === user.id || $i.isAdmin || $i.isModerator)) return true;
|
||||
|
||||
if (user.followingVisibility === 'private') return false;
|
||||
if (user.followingVisibility === 'followers' && !user.isFollowing) return false;
|
||||
|
@ -15,7 +15,7 @@ export function isFollowingVisibleForMe(user: Misskey.entities.UserDetailed): bo
|
|||
return true;
|
||||
}
|
||||
export function isFollowersVisibleForMe(user: Misskey.entities.UserDetailed): boolean {
|
||||
if ($i && $i.id === user.id) return true;
|
||||
if ($i && ($i.id === user.id || $i.isAdmin || $i.isModerator)) return true;
|
||||
|
||||
if (user.followersVisibility === 'private') return false;
|
||||
if (user.followersVisibility === 'followers' && !user.isFollowing) return false;
|
||||
|
|
|
@ -22,7 +22,7 @@ export function deepMerge<X extends Record<string | number | symbol, unknown>>(v
|
|||
if (isPureObject(value) && isPureObject(def)) {
|
||||
const result = deepClone(value as Cloneable) as X;
|
||||
for (const [k, v] of Object.entries(def) as [keyof X, X[keyof X]][]) {
|
||||
if (!Object.prototype.hasOwnProperty.call(value, k) || value[k] === undefined) {
|
||||
if (!Object.hasOwn(value, k) || value[k] === undefined) {
|
||||
result[k] = v;
|
||||
} else if (isPureObject(v) && isPureObject(result[k])) {
|
||||
const child = deepClone(result[k] as Cloneable) as DeepPartial<X[keyof X] & Record<string | number | symbol, unknown>>;
|
||||
|
|
|
@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<div :class="$style.top">
|
||||
<div v-if="instance.bannerUrl != null" :class="$style.banner" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div>
|
||||
<button v-tooltip.noDelay.right="instance.name ?? i18n.ts.instance" class="_button" :class="$style.instance" @click="openInstanceMenu">
|
||||
<img v-if="miLocalStorage.getItem('kawaii')" src="/client-assets/kawaii/about-icon.png" alt="" :class="$style.instanceIconAlt"/>
|
||||
<img v-if="kawaiiMode" src="/client-assets/kawaii/about-icon.png" alt="" :class="$style.instanceIconAlt"/>
|
||||
<img v-else :src="instance.iconUrl || instance.faviconUrl || '/favicon.ico'" alt="" :class="$style.instanceIcon"/>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -77,6 +77,7 @@ import { misskeyApi } from '@/scripts/misskey-api.js';
|
|||
|
||||
const iconOnly = ref<boolean>(false);
|
||||
const unresolvedReportAvailable = ref<boolean>(false);
|
||||
const kawaiiMode = miLocalStorage.getItem('kawaii') === 'true';
|
||||
|
||||
const menu = computed(() => defaultStore.state.menu);
|
||||
const otherMenuItemIndicated = computed(() => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue