Compare commits

...

18 Commits

Author SHA1 Message Date
syuilo dd6f56edca Update drive.vue 2025-06-01 10:46:44 +09:00
syuilo 8d3a315645 Update MkUploaderDialog.vue 2025-06-01 10:46:21 +09:00
syuilo 4a115c34ee Merge branch 'develop' into watermark 2025-06-01 10:45:30 +09:00
syuilo f4167ae7f1 enhance(frontend): 非同期的なコンポーネントの読み込み時のハンドリングを強化 2025-06-01 10:44:45 +09:00
syuilo 63db879bcc fix(frontend): remove unused text 2025-06-01 10:22:32 +09:00
syuilo 70c71859f3 wip 2025-06-01 10:21:21 +09:00
syuilo 8e9c9e9906 use WEBGL_lose_context 2025-06-01 09:53:13 +09:00
syuilo 66e93dcdd9 Merge branch 'develop' into watermark 2025-06-01 09:50:11 +09:00
syuilo bd17b465c3
New Crowdin updates (#16129)
* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Korean)
2025-06-01 09:34:08 +09:00
syuilo 6b1fbf6819 Update about-misskey.vue 2025-06-01 09:24:49 +09:00
github-actions[bot] 021c332097 Bump version to 2025.6.0-alpha.0 2025-06-01 00:22:01 +00:00
syuilo 3691b69488 Merge branch 'develop' into watermark 2025-06-01 08:11:31 +09:00
syuilo 5bdbff19ae fix(frontend): リアクションの一部の絵文字が重複して表示されることがある問題を修正
Fix #16130
2025-06-01 08:10:49 +09:00
syuilo 070a4516fc 🎨 2025-06-01 07:57:22 +09:00
syuilo c5d33661b2 chore(frontend): improve type def 2025-06-01 07:57:18 +09:00
github-actions[bot] 777ca15083 [skip ci] Update CHANGELOG.md (prepend template) 2025-05-31 12:37:08 +00:00
github-actions[bot] 21344f7695 Release: 2025.5.1 2025-05-31 12:37:02 +00:00
syuilo 4254f52ced
New Crowdin updates (#16126)
* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (English)
2025-05-31 18:06:59 +09:00
49 changed files with 179 additions and 92 deletions

View File

@ -1,3 +1,16 @@
## 2025.6.0
### General
-
### Client
- Enhance: 非同期的なコンポーネントの読み込み時のハンドリングを強化
- Fix: リアクションの一部の絵文字が重複して表示されることがある問題を修正
### Server
-
## 2025.5.1 ## 2025.5.1
### Note ### Note

View File

@ -1330,6 +1330,7 @@ restore: "Restaurar "
syncBetweenDevices: "Sincronització entre dispositius" syncBetweenDevices: "Sincronització entre dispositius"
preferenceSyncConflictTitle: "Els valors de la configuració ja existeixen al dispositiu" preferenceSyncConflictTitle: "Els valors de la configuració ja existeixen al dispositiu"
preferenceSyncConflictText: "Un element de la configuració amb sincronització activada desa els seus valors al servidor, però s'ha trobat un valor a la configuració desat al servidor per aquest element de la configuració. Quin valor us sobreescriure?" preferenceSyncConflictText: "Un element de la configuració amb sincronització activada desa els seus valors al servidor, però s'ha trobat un valor a la configuració desat al servidor per aquest element de la configuració. Quin valor us sobreescriure?"
preferenceSyncConflictChoiceMerge: "Integració "
preferenceSyncConflictChoiceServer: "Valors de configuració del servidor" preferenceSyncConflictChoiceServer: "Valors de configuració del servidor"
preferenceSyncConflictChoiceDevice: "Punts d'ajustos del dispositiu " preferenceSyncConflictChoiceDevice: "Punts d'ajustos del dispositiu "
preferenceSyncConflictChoiceCancel: "Cancel·lar l'activació de la sincronització " preferenceSyncConflictChoiceCancel: "Cancel·lar l'activació de la sincronització "

View File

@ -1330,6 +1330,7 @@ restore: "Restore"
syncBetweenDevices: "Sync between devices" syncBetweenDevices: "Sync between devices"
preferenceSyncConflictTitle: "The configured value exists on the server." preferenceSyncConflictTitle: "The configured value exists on the server."
preferenceSyncConflictText: "The sync enabled settings will save their values to the server. However, there are existing values on the server. Which set of values would you like to overwrite?" preferenceSyncConflictText: "The sync enabled settings will save their values to the server. However, there are existing values on the server. Which set of values would you like to overwrite?"
preferenceSyncConflictChoiceMerge: "Merge"
preferenceSyncConflictChoiceServer: "Configured value on server" preferenceSyncConflictChoiceServer: "Configured value on server"
preferenceSyncConflictChoiceDevice: "Configured value on device" preferenceSyncConflictChoiceDevice: "Configured value on device"
preferenceSyncConflictChoiceCancel: "Cancel enabling sync" preferenceSyncConflictChoiceCancel: "Cancel enabling sync"

View File

@ -3001,3 +3001,12 @@ _search:
pleaseEnterServerHost: "서버의 호스트를 입력해 주세요." pleaseEnterServerHost: "서버의 호스트를 입력해 주세요."
pleaseSelectUser: "유저를 선택해주세요" pleaseSelectUser: "유저를 선택해주세요"
serverHostPlaceholder: "예: misskey.example.com" serverHostPlaceholder: "예: misskey.example.com"
_clientPerformanceIssueTip:
makeSureDisabledCustomCss: "커스텀 CSS를 무효로 해주십시오."
makeSureDisabledCustomCss_description: "스타일을 덮어쓰기하면 성능에 영향을 미칠 수 있습니다. 커스텀 CSS나 스타일을 덮어쓰기하는 확장 기능이 유효로 돼있는지 확인해주십시오."
makeSureDisabledAddons: "확장 기능을 무효로 해주십시오."
makeSureDisabledAddons_description: "일부 확장 기능은 클라이언트의 동작에 간섭해 성능에 영향을 미칠 수 있습니다. 브라우저의 확장 기능을 무효로 해 개선할지 확인해주십시오."
_clip:
tip: "클립은 노트를 정리할 수 있는 기능입니다."
_userLists:
tip: "임의의 유저가 포함된 리스트를 작성할 수 있습니다. 작성한 리스트는 타임라인으로 표시가 가능합니다."

View File

@ -1330,6 +1330,7 @@ restore: "恢复"
syncBetweenDevices: "设备间同步" syncBetweenDevices: "设备间同步"
preferenceSyncConflictTitle: "服务器上已存在设定值" preferenceSyncConflictTitle: "服务器上已存在设定值"
preferenceSyncConflictText: "服务器上已有此设置的设定值。要覆盖哪个设定值?" preferenceSyncConflictText: "服务器上已有此设置的设定值。要覆盖哪个设定值?"
preferenceSyncConflictChoiceMerge: "合并"
preferenceSyncConflictChoiceServer: "服务器上的设定值" preferenceSyncConflictChoiceServer: "服务器上的设定值"
preferenceSyncConflictChoiceDevice: "设备上的设定值" preferenceSyncConflictChoiceDevice: "设备上的设定值"
preferenceSyncConflictChoiceCancel: "取消同步" preferenceSyncConflictChoiceCancel: "取消同步"

View File

@ -327,6 +327,7 @@ dark: "深色"
lightThemes: "淺色佈景主題" lightThemes: "淺色佈景主題"
darkThemes: "深色佈景主題" darkThemes: "深色佈景主題"
syncDeviceDarkMode: "與裝置的深色模式同步" syncDeviceDarkMode: "與裝置的深色模式同步"
switchDarkModeManuallyWhenSyncEnabledConfirm: "「{x}」已開啟。要關閉同步並手動切換模式嗎?\n"
drive: "雲端硬碟" drive: "雲端硬碟"
fileName: "檔案名稱" fileName: "檔案名稱"
selectFile: "選擇檔案" selectFile: "選擇檔案"
@ -1329,6 +1330,7 @@ restore: "還原"
syncBetweenDevices: "裝置之間的同步化" syncBetweenDevices: "裝置之間的同步化"
preferenceSyncConflictTitle: "伺服器上存在設定值" preferenceSyncConflictTitle: "伺服器上存在設定值"
preferenceSyncConflictText: "已啟用同步的設定項目會將設定值儲存至伺服器,並已找到該設定項目在伺服器上儲存的設定值。請選擇要使用哪個設定值進行覆寫。" preferenceSyncConflictText: "已啟用同步的設定項目會將設定值儲存至伺服器,並已找到該設定項目在伺服器上儲存的設定值。請選擇要使用哪個設定值進行覆寫。"
preferenceSyncConflictChoiceMerge: "合併至"
preferenceSyncConflictChoiceServer: "伺服器設定值" preferenceSyncConflictChoiceServer: "伺服器設定值"
preferenceSyncConflictChoiceDevice: "裝置的設定值" preferenceSyncConflictChoiceDevice: "裝置的設定值"
preferenceSyncConflictChoiceCancel: "取消啟用同步" preferenceSyncConflictChoiceCancel: "取消啟用同步"

View File

@ -1,6 +1,6 @@
{ {
"name": "misskey", "name": "misskey",
"version": "2025.5.1-beta.6", "version": "2025.6.0-alpha.0",
"codename": "nasubi", "codename": "nasubi",
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -282,8 +282,8 @@ function onContextmenu(ev: MouseEvent) {
menu = [{ menu = [{
text: i18n.ts.openInWindow, text: i18n.ts.openInWindow,
icon: 'ti ti-app-window', icon: 'ti ti-app-window',
action: () => { action: async () => {
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkDriveWindow.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkDriveWindow.vue').then(x => x.default), {
initialFolder: props.folder, initialFolder: props.folder,
}, { }, {
closed: () => dispose(), closed: () => dispose(),

View File

@ -113,7 +113,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-if="filesPaginator.items.value.length == 0 && foldersPaginator.items.value.length == 0 && !fetching" :class="$style.empty"> <div v-if="filesPaginator.items.value.length == 0 && foldersPaginator.items.value.length == 0 && !fetching" :class="$style.empty">
<div v-if="draghover">{{ i18n.ts['empty-draghover'] }}</div> <div v-if="draghover">{{ i18n.ts['empty-draghover'] }}</div>
<div v-if="!draghover && folder == null"><strong>{{ i18n.ts.emptyDrive }}</strong><br/>{{ i18n.ts['empty-drive-description'] }}</div> <div v-if="!draghover && folder == null"><strong>{{ i18n.ts.emptyDrive }}</strong></div>
<div v-if="!draghover && folder != null">{{ i18n.ts.emptyFolder }}</div> <div v-if="!draghover && folder != null">{{ i18n.ts.emptyFolder }}</div>
</div> </div>
</div> </div>

View File

@ -126,7 +126,7 @@ async function rename(file) {
async function describe(file: Misskey.entities.DriveFile) { async function describe(file: Misskey.entities.DriveFile) {
if (mock) return; if (mock) return;
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkFileCaptionEditWindow.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkFileCaptionEditWindow.vue').then(x => x.default), {
default: file.comment !== null ? file.comment : '', default: file.comment !== null ? file.comment : '',
file: file, file: file,
}, { }, {
@ -168,9 +168,11 @@ function showFileMenu(file: Misskey.entities.DriveFile, ev: MouseEvent | Keyboar
menuItems.push({ menuItems.push({
text: i18n.ts.preview, text: i18n.ts.preview,
icon: 'ti ti-photo-search', icon: 'ti ti-photo-search',
action: () => { action: async () => {
os.popup(defineAsyncComponent(() => import('@/components/MkImgPreviewDialog.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkImgPreviewDialog.vue').then(x => x.default), {
file: file, file: file,
}, {
closed: () => dispose(),
}); });
}, },
}); });

View File

@ -297,7 +297,7 @@ function showMenu(ev: MouseEvent, item: typeof items.value[0]) {
icon: 'ti ti-sparkles', icon: 'ti ti-sparkles',
text: i18n.ts._imageEffector.title, text: i18n.ts._imageEffector.title,
action: async () => { action: async () => {
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkImageEffectorDialog.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkImageEffectorDialog.vue').then(x => x.default), {
image: item.file, image: item.file,
}, { }, {
ok: (file) => { ok: (file) => {
@ -349,7 +349,7 @@ function showMenu(ev: MouseEvent, item: typeof items.value[0]) {
icon: 'ti ti-plus', icon: 'ti ti-plus',
text: i18n.ts.add, text: i18n.ts.add,
action: async () => { action: async () => {
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkWatermarkEditorDialog.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkWatermarkEditorDialog.vue').then(x => x.default), {
image: item.file, image: item.file,
}, { }, {
ok: (preset) => { ok: (preset) => {

View File

@ -174,8 +174,8 @@ function setupComplete() {
function launchTutorial() { function launchTutorial() {
setupComplete(); setupComplete();
nextTick(() => { nextTick(async () => {
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkTutorialDialog.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkTutorialDialog.vue').then(x => x.default), {
initialPage: 1, initialPage: 1,
}, { }, {
closed: () => dispose(), closed: () => dispose(),

View File

@ -185,7 +185,7 @@ async function edit(name: string) {
const emoji = await misskeyApi('emoji', { const emoji = await misskeyApi('emoji', {
name: name, name: name,
}); });
const { dispose } = os.popup(defineAsyncComponent(() => import('@/pages/emoji-edit-dialog.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('@/pages/emoji-edit-dialog.vue').then(x => x.default), {
emoji: emoji, emoji: emoji,
}, { }, {
closed: () => dispose(), closed: () => dispose(),

View File

@ -194,9 +194,9 @@ export function useNoteCapture(props: {
parentNote: Misskey.entities.Note | null; parentNote: Misskey.entities.Note | null;
mock?: boolean; mock?: boolean;
}): { }): {
$note: Reactive<ReactiveNoteData>; $note: Reactive<ReactiveNoteData>;
subscribe: () => void; subscribe: () => void;
} { } {
const { note, parentNote, mock } = props; const { note, parentNote, mock } = props;
const $note = reactive<ReactiveNoteData>({ const $note = reactive<ReactiveNoteData>({
@ -225,8 +225,8 @@ export function useNoteCapture(props: {
let latestPollVotedKey: string | null = null; let latestPollVotedKey: string | null = null;
function onReacted(ctx: { userId: Misskey.entities.User['id']; reaction: string; emoji?: { name: string; url: string; }; }): void { function onReacted(ctx: { userId: Misskey.entities.User['id']; reaction: string; emoji?: { name: string; url: string; }; }): void {
const normalizedName = ctx.reaction.replace(/^:(\w+):$/, ':$1@.:'); let normalizedName = ctx.reaction.replace(/^:(\w+):$/, ':$1@.:');
normalizedName = normalizedName.match('\u200d') ? normalizedName : normalizedName.replace(/\ufe0f/g, '');
if (reactionUserMap.has(ctx.userId) && reactionUserMap.get(ctx.userId) === normalizedName) return; if (reactionUserMap.has(ctx.userId) && reactionUserMap.get(ctx.userId) === normalizedName) return;
reactionUserMap.set(ctx.userId, normalizedName); reactionUserMap.set(ctx.userId, normalizedName);
@ -245,7 +245,8 @@ export function useNoteCapture(props: {
} }
function onUnreacted(ctx: { userId: Misskey.entities.User['id']; reaction: string; emoji?: { name: string; url: string; }; }): void { function onUnreacted(ctx: { userId: Misskey.entities.User['id']; reaction: string; emoji?: { name: string; url: string; }; }): void {
const normalizedName = ctx.reaction.replace(/^:(\w+):$/, ':$1@.:'); let normalizedName = ctx.reaction.replace(/^:(\w+):$/, ':$1@.:');
normalizedName = normalizedName.match('\u200d') ? normalizedName : normalizedName.replace(/\ufe0f/g, '');
// 確実に一度リアクションされて取り消されている場合のみ処理をとめるAPIで初回読み込み→Streamでアップデート等の場合、reactionUserMapに情報がないため // 確実に一度リアクションされて取り消されている場合のみ処理をとめるAPIで初回読み込み→Streamでアップデート等の場合、reactionUserMapに情報がないため
if (reactionUserMap.has(ctx.userId) && reactionUserMap.get(ctx.userId) === noReaction) return; if (reactionUserMap.has(ctx.userId) && reactionUserMap.get(ctx.userId) === noReaction) return;

View File

@ -206,6 +206,52 @@ export function popup<T extends Component>(
}; };
} }
export async function popupAsyncWithDialog<T extends Component>(
componentFetching: Promise<T>,
props: ComponentProps<T>,
events: Partial<ComponentEmit<T>> = {},
): Promise<{ dispose: () => void }> {
const closeWaiting = waiting();
let component: T;
try {
component = await componentFetching;
} catch (err) {
closeWaiting();
alert({
type: 'error',
title: i18n.ts.somethingHappened,
text: 'CODE: ASYNC_COMP_LOAD_FAIL',
});
throw err;
}
closeWaiting();
markRaw(component);
const id = ++popupIdCount;
const dispose = () => {
// このsetTimeoutが無いと挙動がおかしくなる(autocompleteが閉じなくなる)。Vueのバグ
window.setTimeout(() => {
popups.value = popups.value.filter(p => p.id !== id);
}, 0);
};
const state = {
component,
props,
events,
id,
};
popups.value.push(state);
return {
dispose,
};
}
export function pageWindow(path: string) { export function pageWindow(path: string) {
const { dispose } = popup(MkPageWindow, { const { dispose } = popup(MkPageWindow, {
initialPath: path, initialPath: path,
@ -787,9 +833,9 @@ export function launchUploader(
multiple?: boolean; multiple?: boolean;
}, },
): Promise<Misskey.entities.DriveFile[]> { ): Promise<Misskey.entities.DriveFile[]> {
return new Promise((res, rej) => { return new Promise(async (res, rej) => {
if (files.length === 0) return rej(); if (files.length === 0) return rej();
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkUploaderDialog.vue')), { const { dispose } = await popupAsyncWithDialog(import('@/components/MkUploaderDialog.vue').then(x => x.default), {
files: markRaw(files), files: markRaw(files),
folderId: options?.folderId, folderId: options?.folderId,
multiple: options?.multiple, multiple: options?.multiple,

View File

@ -391,6 +391,7 @@ const patrons = [
'asata', 'asata',
'ruru', 'ruru',
'みりめい', 'みりめい',
'東雲 琥珀',
]; ];
const thereIsTreasure = ref($i && !claimedAchievements.includes('foundTreasure')); const thereIsTreasure = ref($i && !claimedAchievements.includes('foundTreasure'));

View File

@ -477,16 +477,16 @@ function toggleRoleItem(role) {
} }
} }
function createAnnouncement() { async function createAnnouncement() {
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkUserAnnouncementEditDialog.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkUserAnnouncementEditDialog.vue').then(x => x.default), {
user: user.value, user: user.value,
}, { }, {
closed: () => dispose(), closed: () => dispose(),
}); });
} }
function editAnnouncement(announcement) { async function editAnnouncement(announcement) {
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkUserAnnouncementEditDialog.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkUserAnnouncementEditDialog.vue').then(x => x.default), {
user: user.value, user: user.value,
announcement, announcement,
}, { }, {

View File

@ -525,10 +525,10 @@ const headerPageMetadata = computed(() => ({
const headerActions = computed(() => [{ const headerActions = computed(() => [{
icon: 'ti ti-search', icon: 'ti ti-search',
text: i18n.ts.search, text: i18n.ts.search,
handler: () => { handler: async () => {
if (searchWindowOpening) return; if (searchWindowOpening) return;
searchWindowOpening = true; searchWindowOpening = true;
const { dispose } = os.popup(defineAsyncComponent(() => import('./custom-emojis-manager.local.list.search.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('./custom-emojis-manager.local.list.search.vue').then(x => x.default), {
query: searchQuery.value, query: searchQuery.value,
}, { }, {
queryUpdated: (query: EmojiSearchQuery) => { queryUpdated: (query: EmojiSearchQuery) => {
@ -584,8 +584,8 @@ const headerActions = computed(() => [{
}, { }, {
icon: 'ti ti-notes', icon: 'ti ti-notes',
text: i18n.ts._customEmojisManager._gridCommon.registrationLogs, text: i18n.ts._customEmojisManager._gridCommon.registrationLogs,
handler: () => { handler: async () => {
const { dispose } = os.popup(defineAsyncComponent(() => import('./custom-emojis-manager.local.list.logs.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('./custom-emojis-manager.local.list.logs.vue').then(x => x.default), {
logs: requestLogs.value, logs: requestLogs.value,
}, { }, {
closed: () => { closed: () => {

View File

@ -46,7 +46,7 @@ function load() {
load(); load();
async function add(ev: MouseEvent) { async function add(ev: MouseEvent) {
const { dispose } = os.popup(defineAsyncComponent(() => import('./avatar-decoration-edit-dialog.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('./avatar-decoration-edit-dialog.vue').then(x => x.default), {
}, { }, {
done: result => { done: result => {
if (result.created) { if (result.created) {
@ -57,8 +57,8 @@ async function add(ev: MouseEvent) {
}); });
} }
function edit(avatarDecoration) { async function edit(avatarDecoration) {
const { dispose } = os.popup(defineAsyncComponent(() => import('./avatar-decoration-edit-dialog.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('./avatar-decoration-edit-dialog.vue').then(x => x.default), {
avatarDecoration: avatarDecoration, avatarDecoration: avatarDecoration,
}, { }, {
done: result => { done: result => {

View File

@ -181,9 +181,9 @@ function showMenu(ev: MouseEvent, contextmenu = false) {
menu.push({ menu.push({
text: i18n.ts.reportAbuse, text: i18n.ts.reportAbuse,
icon: 'ti ti-exclamation-circle', icon: 'ti ti-exclamation-circle',
action: () => { action: async () => {
const localUrl = `${url}/chat/messages/${props.message.id}`; const localUrl = `${url}/chat/messages/${props.message.id}`;
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkAbuseReportWindow.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkAbuseReportWindow.vue').then(x => x.default), {
user: props.message.fromUser!, user: props.message.fromUser!,
initialComment: `${localUrl}\n-----\n`, initialComment: `${localUrl}\n-----\n`,
}, { }, {

View File

@ -128,7 +128,7 @@ const toggleSelect = (emoji) => {
}; };
const add = async (ev: MouseEvent) => { const add = async (ev: MouseEvent) => {
const { dispose } = os.popup(defineAsyncComponent(() => import('./emoji-edit-dialog.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('./emoji-edit-dialog.vue').then(x => x.default), {
}, { }, {
done: result => { done: result => {
if (result.created) { if (result.created) {
@ -139,8 +139,8 @@ const add = async (ev: MouseEvent) => {
}); });
}; };
const edit = (emoji) => { const edit = async (emoji) => {
const { dispose } = os.popup(defineAsyncComponent(() => import('./emoji-edit-dialog.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('./emoji-edit-dialog.vue').then(x => x.default), {
emoji: emoji, emoji: emoji,
}, { }, {
done: result => { done: result => {

View File

@ -174,10 +174,10 @@ function rename() {
}); });
} }
function describe() { async function describe() {
if (!file.value) return; if (!file.value) return;
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkFileCaptionEditWindow.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkFileCaptionEditWindow.vue').then(x => x.default), {
default: file.value.comment ?? '', default: file.value.comment ?? '',
file: file.value, file: file.value,
}, { }, {

View File

@ -67,7 +67,7 @@ function menu(ev) {
} }
const edit = async (emoji) => { const edit = async (emoji) => {
const { dispose } = os.popup(defineAsyncComponent(() => import('@/pages/emoji-edit-dialog.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('@/pages/emoji-edit-dialog.vue').then(x => x.default), {
emoji: emoji, emoji: emoji,
}, { }, {
closed: () => dispose(), closed: () => dispose(),

View File

@ -238,12 +238,12 @@ async function run() {
} }
} }
function reportAbuse() { async function reportAbuse() {
if (!flash.value) return; if (!flash.value) return;
const pageUrl = `${url}/play/${flash.value.id}`; const pageUrl = `${url}/play/${flash.value.id}`;
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkAbuseReportWindow.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkAbuseReportWindow.vue').then(x => x.default), {
user: flash.value.user, user: flash.value.user,
initialComment: `Play: ${pageUrl}\n-----\n`, initialComment: `Play: ${pageUrl}\n-----\n`,
}, { }, {

View File

@ -153,12 +153,12 @@ function edit() {
router.push(`/gallery/${post.value.id}/edit`); router.push(`/gallery/${post.value.id}/edit`);
} }
function reportAbuse() { async function reportAbuse() {
if (!post.value) return; if (!post.value) return;
const pageUrl = `${url}/gallery/${post.value.id}`; const pageUrl = `${url}/gallery/${post.value.id}`;
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkAbuseReportWindow.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkAbuseReportWindow.vue').then(x => x.default), {
user: post.value.user, user: post.value.user,
initialComment: `Post: ${pageUrl}\n-----\n`, initialComment: `Post: ${pageUrl}\n-----\n`,
}, { }, {

View File

@ -245,12 +245,12 @@ function pin(pin) {
}); });
} }
function reportAbuse() { async function reportAbuse() {
if (!page.value) return; if (!page.value) return;
const pageUrl = `${url}/@${props.username}/pages/${props.pageName}`; const pageUrl = `${url}/@${props.username}/pages/${props.pageName}`;
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkAbuseReportWindow.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkAbuseReportWindow.vue').then(x => x.default), {
user: page.value.user, user: page.value.user,
initialComment: `Page: ${pageUrl}\n-----\n`, initialComment: `Page: ${pageUrl}\n-----\n`,
}, { }, {

View File

@ -41,9 +41,9 @@ async function save() {
mainRouter.push('/'); mainRouter.push('/');
} }
onMounted(() => { onMounted(async () => {
if (props.token == null) { if (props.token == null) {
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkForgotPassword.vue')), {}, { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkForgotPassword.vue').then(x => x.default), {}, {
closed: () => dispose(), closed: () => dispose(),
}); });
mainRouter.push('/'); mainRouter.push('/');

View File

@ -117,7 +117,7 @@ async function registerTOTP(): Promise<void> {
token: auth.result.token, token: auth.result.token,
}); });
const { dispose } = os.popup(defineAsyncComponent(() => import('./2fa.qrdialog.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('./2fa.qrdialog.vue').then(x => x.default), {
twoFactorData, twoFactorData,
}, { }, {
closed: () => dispose(), closed: () => dispose(),

View File

@ -68,8 +68,8 @@ misskeyApi('get-avatar-decorations').then(_avatarDecorations => {
loading.value = false; loading.value = false;
}); });
function openDecoration(avatarDecoration, index?: number) { async function openDecoration(avatarDecoration, index?: number) {
const { dispose } = os.popup(defineAsyncComponent(() => import('./avatar-decoration.dialog.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('./avatar-decoration.dialog.vue').then(x => x.default), {
decoration: avatarDecoration, decoration: avatarDecoration,
usingIndex: index, usingIndex: index,
}, { }, {

View File

@ -81,8 +81,8 @@ const pagination = {
noPaging: true, noPaging: true,
}; };
function generateToken() { async function generateToken() {
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkTokenGenerateWindow.vue')), {}, { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkTokenGenerateWindow.vue').then(x => x.default), {}, {
done: async result => { done: async result => {
const { name, permissions } = result; const { name, permissions } = result;
const { token } = await misskeyApi('miauth/gen-token', { const { token } = await misskeyApi('miauth/gen-token', {

View File

@ -239,8 +239,8 @@ function chooseUploadFolder() {
}); });
} }
function addWatermarkPreset() { async function addWatermarkPreset() {
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkWatermarkEditorDialog.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkWatermarkEditorDialog.vue').then(x => x.default), {
}, { }, {
ok: (preset: WatermarkPreset) => { ok: (preset: WatermarkPreset) => {
prefer.commit('watermarkPresets', [...prefer.s.watermarkPresets, preset]); prefer.commit('watermarkPresets', [...prefer.s.watermarkPresets, preset]);

View File

@ -604,7 +604,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkInfo> <MkInfo>
<div class="_gaps_s"> <div class="_gaps_s">
<div>{{ i18n.ts._clientPerformanceIssueTip.title }}</div> <div>{{ i18n.ts._clientPerformanceIssueTip.title }}:</div>
<div> <div>
<div><b>{{ i18n.ts._clientPerformanceIssueTip.makeSureDisabledAdBlocker }}</b></div> <div><b>{{ i18n.ts._clientPerformanceIssueTip.makeSureDisabledAdBlocker }}</b></div>
<div>{{ i18n.ts._clientPerformanceIssueTip.makeSureDisabledAdBlocker_description }}</div> <div>{{ i18n.ts._clientPerformanceIssueTip.makeSureDisabledAdBlocker_description }}</div>

View File

@ -95,8 +95,8 @@ export async function authorizePlugin(plugin: Plugin) {
if (plugin.permissions == null || plugin.permissions.length === 0) return; if (plugin.permissions == null || plugin.permissions.length === 0) return;
if (Object.hasOwn(store.s.pluginTokens, plugin.installId)) return; if (Object.hasOwn(store.s.pluginTokens, plugin.installId)) return;
const token = await new Promise<string>((res, rej) => { const token = await new Promise<string>(async (res, rej) => {
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkTokenGenerateWindow.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkTokenGenerateWindow.vue').then(x => x.default), {
title: i18n.ts.tokenRequested, title: i18n.ts.tokenRequested,
information: i18n.ts.pluginTokenRequestedDescription, information: i18n.ts.pluginTokenRequestedDescription,
initialName: plugin.name, initialName: plugin.name,

View File

@ -6,12 +6,12 @@
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import { hemisphere } from '@@/js/intl-const.js'; import { hemisphere } from '@@/js/intl-const.js';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import { definePreferences } from './manager.js';
import type { Theme } from '@/theme.js'; import type { Theme } from '@/theme.js';
import type { SoundType } from '@/utility/sound.js'; import type { SoundType } from '@/utility/sound.js';
import type { Plugin } from '@/plugin.js'; import type { Plugin } from '@/plugin.js';
import type { DeviceKind } from '@/utility/device-kind.js'; import type { DeviceKind } from '@/utility/device-kind.js';
import type { DeckProfile } from '@/deck.js'; import type { DeckProfile } from '@/deck.js';
import type { PreferencesDefinition } from './manager.js';
import type { WatermarkPreset } from '@/utility/watermark.js'; import type { WatermarkPreset } from '@/utility/watermark.js';
import { DEFAULT_DEVICE_KIND } from '@/utility/device-kind.js'; import { DEFAULT_DEVICE_KIND } from '@/utility/device-kind.js';
import { deepEqual } from '@/utility/deep-equal.js'; import { deepEqual } from '@/utility/deep-equal.js';
@ -34,7 +34,7 @@ export type SoundStore = {
// NOTE: デフォルト値は他の設定の状態に依存してはならない(依存していた場合、ユーザーがその設定項目単体で「初期値にリセット」した場合不具合の原因になる) // NOTE: デフォルト値は他の設定の状態に依存してはならない(依存していた場合、ユーザーがその設定項目単体で「初期値にリセット」した場合不具合の原因になる)
export const PREF_DEF = { export const PREF_DEF = definePreferences({
accounts: { accounts: {
default: [] as [host: string, user: { default: [] as [host: string, user: {
id: string; id: string;
@ -89,7 +89,7 @@ export const PREF_DEF = {
emojis: string[]; emojis: string[];
}[], }[],
mergeStrategy: (a, b) => { mergeStrategy: (a, b) => {
const mergedItems = [] as (typeof a)[]; const mergedItems = [] as typeof a;
for (const x of a.concat(b)) { for (const x of a.concat(b)) {
const sameIdItem = mergedItems.find(y => y.id === x.id); const sameIdItem = mergedItems.find(y => y.id === x.id);
if (sameIdItem != null) { if (sameIdItem != null) {
@ -120,7 +120,7 @@ export const PREF_DEF = {
themes: { themes: {
default: [] as Theme[], default: [] as Theme[],
mergeStrategy: (a, b) => { mergeStrategy: (a, b) => {
const mergedItems = [] as (typeof a)[]; const mergedItems = [] as typeof a;
for (const x of a.concat(b)) { for (const x of a.concat(b)) {
const sameIdItem = mergedItems.find(y => y.id === x.id); const sameIdItem = mergedItems.find(y => y.id === x.id);
if (sameIdItem != null) { if (sameIdItem != null) {
@ -398,7 +398,7 @@ export const PREF_DEF = {
accountDependent: true, accountDependent: true,
default: [] as WatermarkPreset[], default: [] as WatermarkPreset[],
mergeStrategy: (a, b) => { mergeStrategy: (a, b) => {
const mergedItems = [] as (typeof a)[]; const mergedItems = [] as typeof a;
for (const x of a.concat(b)) { for (const x of a.concat(b)) {
const sameIdItem = mergedItems.find(y => y.id === x.id); const sameIdItem = mergedItems.find(y => y.id === x.id);
if (sameIdItem != null) { if (sameIdItem != null) {
@ -492,4 +492,4 @@ export const PREF_DEF = {
'experimental.enableFolderPageView': { 'experimental.enableFolderPageView': {
default: false, default: false,
}, },
} satisfies PreferencesDefinition; });

View File

@ -96,6 +96,14 @@ type PreferencesDefinitionRecord<Default, T = Default extends (...args: any) =>
export type PreferencesDefinition = Record<string, PreferencesDefinitionRecord<any>>; export type PreferencesDefinition = Record<string, PreferencesDefinitionRecord<any>>;
export function definePreferences<T extends Record<string, unknown>>(x: {
[K in keyof T]: PreferencesDefinitionRecord<T[K]>
}): {
[K in keyof T]: PreferencesDefinitionRecord<T[K]>
} {
return x;
}
export function getInitialPrefValue<K extends keyof PREF>(k: K): ValueOf<K> { export function getInitialPrefValue<K extends keyof PREF>(k: K): ValueOf<K> {
if (typeof PREF_DEF[k].default === 'function') { // factory if (typeof PREF_DEF[k].default === 'function') { // factory
return PREF_DEF[k].default(); return PREF_DEF[k].default();

View File

@ -4,10 +4,10 @@
*/ */
import { defineAsyncComponent } from 'vue'; import { defineAsyncComponent } from 'vue';
import { host } from '@@/js/config.js';
import type { MenuItem } from '@/types/menu.js'; import type { MenuItem } from '@/types/menu.js';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { instance } from '@/instance.js'; import { instance } from '@/instance.js';
import { host } from '@@/js/config.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { $i } from '@/i.js'; import { $i } from '@/i.js';
@ -146,8 +146,8 @@ export function openInstanceMenu(ev: MouseEvent) {
menuItems.push({ menuItems.push({
text: i18n.ts._initialTutorial.launchTutorial, text: i18n.ts._initialTutorial.launchTutorial,
icon: 'ti ti-presentation', icon: 'ti ti-presentation',
action: () => { action: async () => {
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkTutorialDialog.vue')), {}, { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkTutorialDialog.vue').then(x => x.default), {}, {
closed: () => dispose(), closed: () => dispose(),
}); });
}, },

View File

@ -71,8 +71,8 @@ const otherNavItemIndicated = computed<boolean>(() => {
return false; return false;
}); });
function more(ev: MouseEvent) { async function more(ev: MouseEvent) {
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkLaunchPad.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkLaunchPad.vue').then(x => x.default), {
anchorElement: ev.currentTarget ?? ev.target, anchorElement: ev.currentTarget ?? ev.target,
anchor: { x: 'center', y: 'bottom' }, anchor: { x: 'center', y: 'bottom' },
}, { }, {

View File

@ -176,10 +176,10 @@ function openAccountMenu(ev: MouseEvent) {
}, ev); }, ev);
} }
function more(ev: MouseEvent) { async function more(ev: MouseEvent) {
const target = getHTMLElementOrNull(ev.currentTarget ?? ev.target); const target = getHTMLElementOrNull(ev.currentTarget ?? ev.target);
if (!target) return; if (!target) return;
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkLaunchPad.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkLaunchPad.vue').then(x => x.default), {
anchorElement: target, anchorElement: target,
}, { }, {
closed: () => dispose(), closed: () => dispose(),

View File

@ -72,7 +72,7 @@ async function setAntenna() {
if (canceled || antenna == null) return; if (canceled || antenna == null) return;
if (antenna === '_CREATE_') { if (antenna === '_CREATE_') {
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkAntennaEditorDialog.vue')), {}, { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkAntennaEditorDialog.vue').then(x => x.default), {}, {
created: (newAntenna: MisskeyEntities.Antenna) => { created: (newAntenna: MisskeyEntities.Antenna) => {
antennasCache.delete(); antennasCache.delete();
updateColumn(props.column.id, { updateColumn(props.column.id, {

View File

@ -27,8 +27,8 @@ const props = defineProps<{
const notificationsComponent = useTemplateRef('notificationsComponent'); const notificationsComponent = useTemplateRef('notificationsComponent');
function func() { async function func() {
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkNotificationSelectWindow.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkNotificationSelectWindow.vue').then(x => x.default), {
excludeTypes: props.column.excludeTypes, excludeTypes: props.column.excludeTypes,
}, { }, {
done: async (res) => { done: async (res) => {

View File

@ -172,8 +172,8 @@ export function chooseFileFromPcAndUpload(
export function chooseDriveFile(options: { export function chooseDriveFile(options: {
multiple?: boolean; multiple?: boolean;
} = {}): Promise<Misskey.entities.DriveFile[]> { } = {}): Promise<Misskey.entities.DriveFile[]> {
return new Promise(resolve => { return new Promise(async resolve => {
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkDriveFileSelectDialog.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkDriveFileSelectDialog.vue').then(x => x.default), {
multiple: options.multiple ?? false, multiple: options.multiple ?? false,
}, { }, {
done: files => { done: files => {
@ -286,8 +286,8 @@ export async function createCroppedImageDriveFileFromImageDriveFile(imageDriveFi
} }
export async function selectDriveFolder(initialFolder: Misskey.entities.DriveFolder['id'] | null): Promise<Misskey.entities.DriveFolder[]> { export async function selectDriveFolder(initialFolder: Misskey.entities.DriveFolder['id'] | null): Promise<Misskey.entities.DriveFolder[]> {
return new Promise(resolve => { return new Promise(async resolve => {
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkDriveFolderSelectDialog.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkDriveFolderSelectDialog.vue').then(x => x.default), {
initialFolder, initialFolder,
}, { }, {
done: folders => { done: folders => {

View File

@ -28,8 +28,8 @@ function rename(file: Misskey.entities.DriveFile) {
}); });
} }
function describe(file: Misskey.entities.DriveFile) { async function describe(file: Misskey.entities.DriveFile) {
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkFileCaptionEditWindow.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkFileCaptionEditWindow.vue').then(x => x.default), {
default: file.comment ?? '', default: file.comment ?? '',
file: file, file: file,
}, { }, {

View File

@ -64,7 +64,7 @@ export function getEmbedCode(path: string, params?: EmbedParams): string {
* *
* getEmbedCode 使 * getEmbedCode 使
*/ */
export function genEmbedCode(entity: EmbeddableEntity, id: string, params?: EmbedParams) { export async function genEmbedCode(entity: EmbeddableEntity, id: string, params?: EmbedParams) {
const _params = { ...params }; const _params = { ...params };
if (embedRouteWithScrollbar.includes(entity) && _params.maxHeight == null) { if (embedRouteWithScrollbar.includes(entity) && _params.maxHeight == null) {
@ -75,7 +75,7 @@ export function genEmbedCode(entity: EmbeddableEntity, id: string, params?: Embe
if (window.innerWidth < MOBILE_THRESHOLD) { if (window.innerWidth < MOBILE_THRESHOLD) {
copyToClipboard(getEmbedCode(`/embed/${entity}/${id}`, _params)); copyToClipboard(getEmbedCode(`/embed/${entity}/${id}`, _params));
} else { } else {
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkEmbedCodeGenDialog.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkEmbedCodeGenDialog.vue').then(x => x.default), {
entity, entity,
id, id,
params: _params, params: _params,

View File

@ -135,12 +135,12 @@ export function getAbuseNoteMenu(note: Misskey.entities.Note, text: string): Men
return { return {
icon: 'ti ti-exclamation-circle', icon: 'ti ti-exclamation-circle',
text, text,
action: (): void => { action: async (): Promise<void> => {
const localUrl = `${url}/notes/${note.id}`; const localUrl = `${url}/notes/${note.id}`;
let noteInfo = ''; let noteInfo = '';
if (note.url ?? note.uri != null) noteInfo = `Note: ${note.url ?? note.uri}\n`; if (note.url ?? note.uri != null) noteInfo = `Note: ${note.url ?? note.uri}\n`;
noteInfo += `Local Note: ${localUrl}\n`; noteInfo += `Local Note: ${localUrl}\n`;
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkAbuseReportWindow.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkAbuseReportWindow.vue').then(x => x.default), {
user: note.user, user: note.user,
initialComment: `${noteInfo}-----\n`, initialComment: `${noteInfo}-----\n`,
}, { }, {

View File

@ -94,8 +94,8 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: Router
}); });
} }
function reportAbuse() { async function reportAbuse() {
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkAbuseReportWindow.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkAbuseReportWindow.vue').then(x => x.default), {
user: user, user: user,
}, { }, {
closed: () => dispose(), closed: () => dispose(),

View File

@ -387,6 +387,9 @@ export class ImageEffector {
this.gl.deleteProgram(this.renderTextureProgram); this.gl.deleteProgram(this.renderTextureProgram);
this.gl.deleteProgram(this.renderInvertedTextureProgram); this.gl.deleteProgram(this.renderInvertedTextureProgram);
this.gl.deleteTexture(this.originalImageTexture); this.gl.deleteTexture(this.originalImageTexture);
const loseContextExt = this.gl.getExtension('WEBGL_lose_context');
if (loseContextExt) loseContextExt.loseContext();
} }
} }

View File

@ -3,11 +3,10 @@
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
import { defineAsyncComponent } from 'vue';
import { $i } from '@/i.js'; import { $i } from '@/i.js';
import { instance } from '@/instance.js'; import { instance } from '@/instance.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { popup } from '@/os.js'; import { popupAsyncWithDialog } from '@/os.js';
export type OpenOnRemoteOptions = { export type OpenOnRemoteOptions = {
/** /**
@ -45,7 +44,7 @@ export type OpenOnRemoteOptions = {
params: Record<string, string>; params: Record<string, string>;
}; };
export function pleaseLogin(opts: { export async function pleaseLogin(opts: {
path?: string; path?: string;
message?: string; message?: string;
openOnRemote?: OpenOnRemoteOptions; openOnRemote?: OpenOnRemoteOptions;
@ -59,7 +58,7 @@ export function pleaseLogin(opts: {
_openOnRemote = opts.openOnRemote; _openOnRemote = opts.openOnRemote;
} }
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkSigninDialog.vue')), { const { dispose } = await popupAsyncWithDialog(import('@/components/MkSigninDialog.vue').then(x => x.default), {
autoSet: true, autoSet: true,
message: opts.message ?? (_openOnRemote ? i18n.ts.signinOrContinueOnRemote : i18n.ts.signinRequired), message: opts.message ?? (_openOnRemote ? i18n.ts.signinOrContinueOnRemote : i18n.ts.signinRequired),
openOnRemote: _openOnRemote, openOnRemote: _openOnRemote,

View File

@ -54,8 +54,8 @@ const { widgetProps, configure, save } = useWidgetPropsManager(name,
emit, emit,
); );
const configureNotification = () => { const configureNotification = async () => {
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkNotificationSelectWindow.vue')), { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkNotificationSelectWindow.vue').then(x => x.default), {
excludeTypes: widgetProps.excludeTypes, excludeTypes: widgetProps.excludeTypes,
}, { }, {
done: async (res) => { done: async (res) => {

View File

@ -1,7 +1,7 @@
{ {
"type": "module", "type": "module",
"name": "misskey-js", "name": "misskey-js",
"version": "2025.5.1-beta.6", "version": "2025.6.0-alpha.0",
"description": "Misskey SDK for JavaScript", "description": "Misskey SDK for JavaScript",
"license": "MIT", "license": "MIT",
"main": "./built/index.js", "main": "./built/index.js",