From a1be39d94ff650ccb77336283da8f3b19edbf4c0 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Sun, 2 Feb 2025 05:31:00 +0000
Subject: [PATCH 01/18] Bump version to 2025.2.0-beta.0

---
 package.json                     | 2 +-
 packages/misskey-js/package.json | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index db3c492b60..05adf49e21 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "misskey",
-	"version": "2025.2.0-alpha.0",
+	"version": "2025.2.0-beta.0",
 	"codename": "nasubi",
 	"repository": {
 		"type": "git",
diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index 667af78ce0..0e1a46ad72 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -1,7 +1,7 @@
 {
 	"type": "module",
 	"name": "misskey-js",
-	"version": "2025.2.0-alpha.0",
+	"version": "2025.2.0-beta.0",
 	"description": "Misskey SDK for JavaScript",
 	"license": "MIT",
 	"main": "./built/index.js",

From 9c70a4e63130f85d191c5bc16d0a4be5cd1dece2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Mon, 3 Feb 2025 22:45:59 +0900
Subject: [PATCH 02/18] =?UTF-8?q?fix(build):=20corepack=E3=81=AE=E3=83=90?=
 =?UTF-8?q?=E3=82=B0=E3=81=AE=E5=9B=9E=E9=81=BF=20(#15387)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix: disallow corepack from fetching latest manager version instead use specified version in package.json

* Update Changelog

* fix?

* apply COREPACK_DEFAULT_TO_LATEST: 0 to every github workflows

* Revert "apply COREPACK_DEFAULT_TO_LATEST: 0 to every github workflows"

This reverts commit 67f0dc31adaa04f891f74f5c44a3d4d13a302a03.

* apply COREPACK_DEFAULT_TO_LATEST: 0 to every github workflows (re)

* fix

* fix?

* revert: removing corepack enable

* test: set COREPACK_DEFAULT_TO_LATEST for federation tests

---------

Co-authored-by: Marie <github@yuugi.dev>
Co-authored-by: anatawa12 <anatawa12@icloud.com>
---
 .github/workflows/api-misskey-js.yml             | 4 ++++
 .github/workflows/get-api-diff.yml               | 4 ++++
 .github/workflows/lint.yml                       | 4 ++++
 .github/workflows/locale.yml                     | 4 ++++
 .github/workflows/on-release-created.yml         | 3 +++
 .github/workflows/storybook.yml                  | 3 +++
 .github/workflows/test-backend.yml               | 4 ++++
 .github/workflows/test-federation.yml            | 3 +++
 .github/workflows/test-frontend.yml              | 4 ++++
 .github/workflows/test-misskey-js.yml            | 4 ++++
 .github/workflows/test-production.yml            | 1 +
 .github/workflows/validate-api-json.yml          | 4 ++++
 CHANGELOG.md                                     | 3 ++-
 Dockerfile                                       | 5 +++++
 packages/backend/test-federation/compose.tpl.yml | 1 +
 packages/backend/test-federation/compose.yml     | 3 +++
 16 files changed, 53 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/api-misskey-js.yml b/.github/workflows/api-misskey-js.yml
index e21738c4f4..6f4219b54b 100644
--- a/.github/workflows/api-misskey-js.yml
+++ b/.github/workflows/api-misskey-js.yml
@@ -9,6 +9,10 @@ on:
     paths:
       - packages/misskey-js/**
       - .github/workflows/api-misskey-js.yml
+
+env:
+  COREPACK_DEFAULT_TO_LATEST: 0
+
 jobs:
   report:
 
diff --git a/.github/workflows/get-api-diff.yml b/.github/workflows/get-api-diff.yml
index 46c726b986..6805e8bc3c 100644
--- a/.github/workflows/get-api-diff.yml
+++ b/.github/workflows/get-api-diff.yml
@@ -9,6 +9,10 @@ on:
     paths:
       - packages/backend/**
       - .github/workflows/get-api-diff.yml
+
+env:
+  COREPACK_DEFAULT_TO_LATEST: 0
+
 jobs:
   get-from-misskey:
     runs-on: ubuntu-latest
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 9785bb5744..2f6938d2e4 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -28,6 +28,10 @@ on:
       - packages/misskey-reversi/**
       - packages/shared/eslint.config.js
       - .github/workflows/lint.yml
+
+env:
+  COREPACK_DEFAULT_TO_LATEST: 0
+
 jobs:
   pnpm_install:
     runs-on: ubuntu-latest
diff --git a/.github/workflows/locale.yml b/.github/workflows/locale.yml
index 2eb4ca3ad9..95d29bf828 100644
--- a/.github/workflows/locale.yml
+++ b/.github/workflows/locale.yml
@@ -9,6 +9,10 @@ on:
     paths:
       - locales/**
       - .github/workflows/locale.yml
+
+env:
+  COREPACK_DEFAULT_TO_LATEST: 0
+
 jobs:
   locale_verify:
     runs-on: ubuntu-latest
diff --git a/.github/workflows/on-release-created.yml b/.github/workflows/on-release-created.yml
index 8ca2ed9efb..fc224a6239 100644
--- a/.github/workflows/on-release-created.yml
+++ b/.github/workflows/on-release-created.yml
@@ -6,6 +6,9 @@ on:
 
   workflow_dispatch:
 
+env:
+  COREPACK_DEFAULT_TO_LATEST: 0
+
 jobs:
   publish-misskey-js:
     name: Publish misskey-js
diff --git a/.github/workflows/storybook.yml b/.github/workflows/storybook.yml
index dfba46a8c8..be294201f0 100644
--- a/.github/workflows/storybook.yml
+++ b/.github/workflows/storybook.yml
@@ -13,6 +13,9 @@ on:
       # This is a waste of chromatic build quota, so we don't run storybook CI on pull requests targets master.
       - master
 
+env:
+  COREPACK_DEFAULT_TO_LATEST: 0
+
 jobs:
   build:
     # chromatic is not likely to be available for fork repositories, so we disable for fork repositories.
diff --git a/.github/workflows/test-backend.yml b/.github/workflows/test-backend.yml
index debfe24819..99a9f99b75 100644
--- a/.github/workflows/test-backend.yml
+++ b/.github/workflows/test-backend.yml
@@ -18,6 +18,10 @@ on:
       - packages/misskey-js/**
       - .github/workflows/test-backend.yml
       - .github/misskey/test.yml
+
+env:
+  COREPACK_DEFAULT_TO_LATEST: 0
+
 jobs:
   unit:
     name: Unit tests (backend)
diff --git a/.github/workflows/test-federation.yml b/.github/workflows/test-federation.yml
index c4546a0590..74cdff80f1 100644
--- a/.github/workflows/test-federation.yml
+++ b/.github/workflows/test-federation.yml
@@ -15,6 +15,9 @@ on:
       - packages/misskey-js/**
       - .github/workflows/test-federation.yml
 
+env:
+  COREPACK_DEFAULT_TO_LATEST: 0
+
 jobs:
   test:
     name: Federation test
diff --git a/.github/workflows/test-frontend.yml b/.github/workflows/test-frontend.yml
index 51e0b0e8b8..6c09896d06 100644
--- a/.github/workflows/test-frontend.yml
+++ b/.github/workflows/test-frontend.yml
@@ -22,6 +22,10 @@ on:
       - packages/backend/**
       - .github/workflows/test-frontend.yml
       - .github/misskey/test.yml
+
+env:
+  COREPACK_DEFAULT_TO_LATEST: 0
+
 jobs:
   vitest:
     name: Unit tests (frontend)
diff --git a/.github/workflows/test-misskey-js.yml b/.github/workflows/test-misskey-js.yml
index c72a2470a4..d88dc18bd8 100644
--- a/.github/workflows/test-misskey-js.yml
+++ b/.github/workflows/test-misskey-js.yml
@@ -14,6 +14,10 @@ on:
     paths:
       - packages/misskey-js/**
       - .github/workflows/test-misskey-js.yml
+
+env:
+  COREPACK_DEFAULT_TO_LATEST: 0
+
 jobs:
   test:
     name: Unit tests (misskey.js)
diff --git a/.github/workflows/test-production.yml b/.github/workflows/test-production.yml
index 4a55f4803c..5269358e38 100644
--- a/.github/workflows/test-production.yml
+++ b/.github/workflows/test-production.yml
@@ -9,6 +9,7 @@ on:
 
 env:
   NODE_ENV: production
+  COREPACK_DEFAULT_TO_LATEST: 0
 
 jobs:
   production:
diff --git a/.github/workflows/validate-api-json.yml b/.github/workflows/validate-api-json.yml
index 0d254898f8..65afcd4cd0 100644
--- a/.github/workflows/validate-api-json.yml
+++ b/.github/workflows/validate-api-json.yml
@@ -12,6 +12,10 @@ on:
     paths:
       - packages/backend/**
       - .github/workflows/validate-api-json.yml
+
+env:
+  COREPACK_DEFAULT_TO_LATEST: 0
+
 jobs:
   validate-api-json:
     runs-on: ubuntu-latest
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 601bf743bc..b2053fad1c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,8 @@
 ## 2025.2.0
 
 ### General
--
+- Fix: Docker のビルドに失敗する問題を修正  
+  (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/883)
 
 ### Client
 - Fix: 一部環境でセンシティブなファイルを含むノートの非表示が効かない問題 
diff --git a/Dockerfile b/Dockerfile
index 13f6909462..3bc2044396 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -6,6 +6,8 @@ ARG NODE_VERSION=22.11.0-bookworm
 
 FROM --platform=$BUILDPLATFORM node:${NODE_VERSION} AS native-builder
 
+ENV COREPACK_DEFAULT_TO_LATEST=0
+
 RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
 	--mount=type=cache,target=/var/lib/apt,sharing=locked \
 	rm -f /etc/apt/apt.conf.d/docker-clean \
@@ -44,6 +46,8 @@ RUN rm -rf .git/
 
 FROM --platform=$TARGETPLATFORM node:${NODE_VERSION} AS target-builder
 
+ENV COREPACK_DEFAULT_TO_LATEST=0
+
 RUN apt-get update \
 	&& apt-get install -yqq --no-install-recommends \
 	build-essential
@@ -68,6 +72,7 @@ FROM --platform=$TARGETPLATFORM node:${NODE_VERSION}-slim AS runner
 
 ARG UID="991"
 ARG GID="991"
+ENV COREPACK_DEFAULT_TO_LATEST=0
 
 RUN apt-get update \
 	&& apt-get install -y --no-install-recommends \
diff --git a/packages/backend/test-federation/compose.tpl.yml b/packages/backend/test-federation/compose.tpl.yml
index 8c38f16919..8b270e58f7 100644
--- a/packages/backend/test-federation/compose.tpl.yml
+++ b/packages/backend/test-federation/compose.tpl.yml
@@ -17,6 +17,7 @@ services:
       - ./.config/docker.env
     environment:
       - NODE_ENV=production
+      - COREPACK_DEFAULT_TO_LATEST=0
     volumes:
       - type: bind
         source: ../../../built
diff --git a/packages/backend/test-federation/compose.yml b/packages/backend/test-federation/compose.yml
index 62d7e977c0..a5a7223982 100644
--- a/packages/backend/test-federation/compose.yml
+++ b/packages/backend/test-federation/compose.yml
@@ -25,6 +25,7 @@ services:
     environment:
       - NODE_ENV=development
       - NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/rootCA.crt
+      - COREPACK_DEFAULT_TO_LATEST=0
     volumes:
       - type: bind
         source: ../package.json
@@ -85,6 +86,8 @@ services:
     depends_on:
       redis.test:
         condition: service_healthy
+    environment:
+      - COREPACK_DEFAULT_TO_LATEST=0
     volumes:
       - type: bind
         source: ../package.json

From 19857632d097f1c9e39291cbbe2e2882439c1853 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Tue, 4 Feb 2025 10:03:51 +0900
Subject: [PATCH 03/18] Update CHANGELOG.md

---
 CHANGELOG.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index b2053fad1c..15eb611fd1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@
 ### Client
 - Fix: 一部環境でセンシティブなファイルを含むノートの非表示が効かない問題 
 - Fix: データセーバー有効時にもユーザーページの「ファイル」タブで画像が読み込まれてしまう問題を修正
+- ローカライゼーションの更新
 
 ### Server
 - Fix: 個別お知らせページのmetaタグ出力の条件が間違っていたのを修正

From 495d72ed2a25d2d4845f451471b7486d604ff744 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Tue, 4 Feb 2025 14:01:32 +0900
Subject: [PATCH 04/18] =?UTF-8?q?fix(frontend):=20MkSparkle=E3=81=8C?=
 =?UTF-8?q?=E5=8B=95=E4=BD=9C=E3=81=97=E3=81=AA=E3=81=84=E5=95=8F=E9=A1=8C?=
 =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3=20(#15390)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix(frontend): MkSparkleが動作しない問題を修正

* Update Changelog

* fix

* add comments
---
 CHANGELOG.md                                  |  1 +
 .../frontend/src/components/MkSparkle.vue     | 53 +++++++++++--------
 2 files changed, 31 insertions(+), 23 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 15eb611fd1..17310ae7d8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@
 ### Client
 - Fix: 一部環境でセンシティブなファイルを含むノートの非表示が効かない問題 
 - Fix: データセーバー有効時にもユーザーページの「ファイル」タブで画像が読み込まれてしまう問題を修正
+- Fix: MFMの `sparkle` エフェクトが正しく表示されない問題を修正
 - ローカライゼーションの更新
 
 ### Server
diff --git a/packages/frontend/src/components/MkSparkle.vue b/packages/frontend/src/components/MkSparkle.vue
index 8491ce2f84..b3fc67c0df 100644
--- a/packages/frontend/src/components/MkSparkle.vue
+++ b/packages/frontend/src/components/MkSparkle.vue
@@ -39,32 +39,18 @@ SPDX-License-Identifier: AGPL-3.0-only
 	-->
 	<!-- MFMで上位レイヤーに表示されるため、リンクをクリックできるようにstyleにpointer-events: none;を付与。 -->
 	<svg v-for="particle in particles" :key="particle.id" :width="width" :height="height" :viewBox="`0 0 ${width} ${height}`" xmlns="http://www.w3.org/2000/svg" style="position: absolute; top: -32px; left: -32px; pointer-events: none;">
+		<!-- SVGのanimateTransformを使用するとChromeで描画できなくなるためCSSアニメーションを使用している (Issue 14155) -->
 		<path
-			style="transform-origin: center; transform-box: fill-box;"
-			:transform="`translate(${particle.x} ${particle.y})`"
+			:style="{
+				'--translateX': particle.x + 'px',
+				'--translateY': particle.y + 'px',
+				'--duration': particle.dur + 'ms',
+				'--size': particle.size,
+			}"
+			:class="$style.particle"
 			:fill="particle.color"
 			d="M29.427,2.011C29.721,0.83 30.782,0 32,0C33.218,0 34.279,0.83 34.573,2.011L39.455,21.646C39.629,22.347 39.991,22.987 40.502,23.498C41.013,24.009 41.653,24.371 42.354,24.545L61.989,29.427C63.17,29.721 64,30.782 64,32C64,33.218 63.17,34.279 61.989,34.573L42.354,39.455C41.653,39.629 41.013,39.991 40.502,40.502C39.991,41.013 39.629,41.653 39.455,42.354L34.573,61.989C34.279,63.17 33.218,64 32,64C30.782,64 29.721,63.17 29.427,61.989L24.545,42.354C24.371,41.653 24.009,41.013 23.498,40.502C22.987,39.991 22.347,39.629 21.646,39.455L2.011,34.573C0.83,34.279 0,33.218 0,32C0,30.782 0.83,29.721 2.011,29.427L21.646,24.545C22.347,24.371 22.987,24.009 23.498,23.498C24.009,22.987 24.371,22.347 24.545,21.646L29.427,2.011Z"
-		>
-			<animateTransform
-				attributeName="transform"
-				attributeType="XML"
-				type="rotate"
-				from="0 0 0"
-				to="360 0 0"
-				:dur="`${particle.dur}ms`"
-				repeatCount="1"
-				additive="sum"
-			/>
-			<animateTransform
-				attributeName="transform"
-				attributeType="XML"
-				type="scale"
-				:values="`0; ${particle.size}; 0`"
-				:dur="`${particle.dur}ms`"
-				repeatCount="1"
-				additive="sum"
-			/>
-		</path>
+		></path>
 	</svg>
 </span>
 </template>
@@ -130,4 +116,25 @@ onUnmounted(() => {
 	position: relative;
 	display: inline-block;
 }
+
+.particle {
+	transform-origin: center;
+	transform-box: fill-box;
+	translate: var(--translateX) var(--translateY);
+	animation: particleAnimation var(--duration) linear infinite;
+}
+
+@keyframes particleAnimation {
+	0% {
+		rotate: 0deg;
+		scale: 0;
+	}
+	50% {
+		scale: var(--size);
+	}
+	100% {
+		rotate: 360deg;
+		scale: 0;
+	}
+}
 </style>

From cb48853334e24055cd94a5756bca052bb38b2094 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Tue, 4 Feb 2025 17:40:44 +0900
Subject: [PATCH 05/18] =?UTF-8?q?fix(frontend):=20=E3=82=B9=E3=83=A9?=
 =?UTF-8?q?=E3=83=83=E3=82=B7=E3=83=A5=E3=82=92=E5=90=AB=E3=82=80=E3=83=9A?=
 =?UTF-8?q?=E3=83=BC=E3=82=B8=E3=82=92=E9=96=B2=E8=A6=A7=E3=81=A7=E3=81=8D?=
 =?UTF-8?q?=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=20(#15394)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix(frontend): スラッシュを含むページを閲覧できるように

* Update Changelog

* fix
---
 CHANGELOG.md                               | 4 ++++
 packages/frontend/src/pages/page.vue       | 6 +-----
 packages/frontend/src/router/definition.ts | 5 +----
 3 files changed, 6 insertions(+), 9 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 17310ae7d8..a7cffbf4cd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,8 @@
 ## 2025.2.0
 
+### Note
+- ページの「ソースを見る」機能は削除されました
+
 ### General
 - Fix: Docker のビルドに失敗する問題を修正  
   (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/883)
@@ -8,6 +11,7 @@
 - Fix: 一部環境でセンシティブなファイルを含むノートの非表示が効かない問題 
 - Fix: データセーバー有効時にもユーザーページの「ファイル」タブで画像が読み込まれてしまう問題を修正
 - Fix: MFMの `sparkle` エフェクトが正しく表示されない問題を修正
+- Fix: ページのURLにスラッシュが含まれている場合にページが正しく表示されない問題を修正
 - ローカライゼーションの更新
 
 ### Server
diff --git a/packages/frontend/src/pages/page.vue b/packages/frontend/src/pages/page.vue
index a1bec52f18..d9ad7babb7 100644
--- a/packages/frontend/src/pages/page.vue
+++ b/packages/frontend/src/pages/page.vue
@@ -266,7 +266,7 @@ function showMenu(ev: MouseEvent) {
 	if ($i && $i.id === page.value.userId) {
 		menuItems.push({
 			icon: 'ti ti-pencil',
-			text: i18n.ts.editThisPage,
+			text: i18n.ts.edit,
 			action: () => router.push(`/pages/edit/${page.value.id}`),
 		});
 
@@ -285,10 +285,6 @@ function showMenu(ev: MouseEvent) {
 		}
 	} else if ($i && $i.id !== page.value.userId) {
 		menuItems.push({
-				icon: 'ti ti-code',
-				text: i18n.ts._pages.viewSource,
-				action: () => router.push(`/@${props.username}/pages/${props.pageName}/view-source`),
-		}, {
 			icon: 'ti ti-exclamation-circle',
 			text: i18n.ts.reportAbuse,
 			action: reportAbuse,
diff --git a/packages/frontend/src/router/definition.ts b/packages/frontend/src/router/definition.ts
index 732b209a36..217954a7bb 100644
--- a/packages/frontend/src/router/definition.ts
+++ b/packages/frontend/src/router/definition.ts
@@ -17,10 +17,7 @@ export const page = (loader: AsyncComponentLoader) => defineAsyncComponent({
 });
 
 const routes: RouteDef[] = [{
-	path: '/@:initUser/pages/:initPageName/view-source',
-	component: page(() => import('@/pages/page-editor/page-editor.vue')),
-}, {
-	path: '/@:username/pages/:pageName',
+	path: '/@:username/pages/:pageName(*)',
 	component: page(() => import('@/pages/page.vue')),
 }, {
 	path: '/@:acct/following',

From 5840c7a945507f3c1e6f69c269b814ff564e9ceb Mon Sep 17 00:00:00 2001
From: lqvp <183242690+lqvp@users.noreply.github.com>
Date: Tue, 4 Feb 2025 18:16:41 +0900
Subject: [PATCH 06/18] =?UTF-8?q?fix(frontend):=20=E3=83=91=E3=82=B9?=
 =?UTF-8?q?=E3=82=AD=E3=83=BC=E3=81=A7=E3=83=91=E3=82=B9=E3=83=AF=E3=83=BC?=
 =?UTF-8?q?=E3=83=89=E3=83=AC=E3=82=B9=E3=83=AD=E3=82=B0=E3=82=A4=E3=83=B3?=
 =?UTF-8?q?=E3=81=8C=E5=87=BA=E6=9D=A5=E3=81=AA=E3=81=84=E5=95=8F=E9=A1=8C?=
 =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3=20(#15370)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 packages/frontend/src/components/MkSignin.vue | 1 +
 1 file changed, 1 insertion(+)

diff --git a/packages/frontend/src/components/MkSignin.vue b/packages/frontend/src/components/MkSignin.vue
index 776ee20e36..5a27cd6de7 100644
--- a/packages/frontend/src/components/MkSignin.vue
+++ b/packages/frontend/src/components/MkSignin.vue
@@ -140,6 +140,7 @@ function onPasskeyDone(credential: AuthenticationPublicKeyCredential): void {
 				return;
 			}
 			emit('login', res.signinResponse);
+			onLoginSucceeded(res.signinResponse);
 		}).catch(onSigninApiError);
 	} else if (userInfo.value != null) {
 		tryLogin({

From 0c634c9675e4bd77bd5d36d0a8a8a58525981767 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Tue, 4 Feb 2025 20:33:31 +0900
Subject: [PATCH 07/18] Update CHANGELOG.md

---
 CHANGELOG.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index a7cffbf4cd..b3909a374a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,7 @@
   (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/883)
 
 ### Client
+- Fix: パスキーでパスワードレスログインが出来ない問題を修正
 - Fix: 一部環境でセンシティブなファイルを含むノートの非表示が効かない問題 
 - Fix: データセーバー有効時にもユーザーページの「ファイル」タブで画像が読み込まれてしまう問題を修正
 - Fix: MFMの `sparkle` エフェクトが正しく表示されない問題を修正

From 82d410933946218353175eb7cf103211a07f030d Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Wed, 5 Feb 2025 09:30:41 +0900
Subject: [PATCH 08/18] New translations ja-jp.yml (English) (#15389)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: おさむのひと <46447427+samunohito@users.noreply.github.com>
---
 locales/en-US.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/locales/en-US.yml b/locales/en-US.yml
index fb34dfc829..360cfd72c5 100644
--- a/locales/en-US.yml
+++ b/locales/en-US.yml
@@ -2775,6 +2775,7 @@ _customEmojisManager:
       confirmUpdateEmojisDescription: "Update {count} Emoji(s). Are you sure to continue?"
       confirmDeleteEmojisDescription: "Delete checked {count} Emoji(s). Are you sure to continue?"
       confirmResetDescription: ""
+      confirmMovePageDesciption: "Changes have been made to the Emojis on this page.\nIf you leave the page without saving, all changes made on this page will be discarded."
       dialogSelectRoleTitle: "Search by roll set in Emojis"
     _register:
       uploadSettingTitle: "Upload settings"

From 904da7bad6bfaa5fd4502b4cc40b2d6ba376c269 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Wed, 5 Feb 2025 09:55:39 +0900
Subject: [PATCH 09/18] Update CHANGELOG.md

---
 CHANGELOG.md | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index b3909a374a..32b9f91a38 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,8 +1,5 @@
 ## 2025.2.0
 
-### Note
-- ページの「ソースを見る」機能は削除されました
-
 ### General
 - Fix: Docker のビルドに失敗する問題を修正  
   (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/883)
@@ -14,6 +11,7 @@
 - Fix: MFMの `sparkle` エフェクトが正しく表示されない問題を修正
 - Fix: ページのURLにスラッシュが含まれている場合にページが正しく表示されない問題を修正
 - ローカライゼーションの更新
+- Playが実装されたため、ページ機能の「ソースを見る」は削除されました
 
 ### Server
 - Fix: 個別お知らせページのmetaタグ出力の条件が間違っていたのを修正

From fbc6d0de54031de840c39be3a2c7c63fe522c439 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Wed, 5 Feb 2025 10:39:46 +0900
Subject: [PATCH 10/18] =?UTF-8?q?enhance:=20=E3=83=9A=E3=83=BC=E3=82=B8slu?=
 =?UTF-8?q?g=E3=81=AB=E4=BD=BF=E7=94=A8=E5=8F=AF=E8=83=BD=E3=81=AA?=
 =?UTF-8?q?=E6=96=87=E5=AD=97=E3=82=92=E9=99=90=E5=AE=9A=20(#15395)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* wip

* paramの正規表現で弾くように

* apiWithDialogを使用するように

* Update CHANGELOG.md

---------

Co-authored-by: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com>
---
 CHANGELOG.md                                  |   2 +-
 locales/index.d.ts                            |  14 +--
 locales/ja-JP.yml                             |   5 +-
 packages/backend/src/models/Page.ts           |   2 +
 .../src/server/api/endpoints/pages/create.ts  |   4 +-
 .../src/server/api/endpoints/pages/update.ts  |   5 +-
 .../src/pages/page-editor/page-editor.vue     | 113 ++++++++----------
 7 files changed, 60 insertions(+), 85 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 32b9f91a38..7f48d1c532 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,9 +14,9 @@
 - Playが実装されたため、ページ機能の「ソースを見る」は削除されました
 
 ### Server
+- Enhance: ページのURLに使用可能な文字を限定するように
 - Fix: 個別お知らせページのmetaタグ出力の条件が間違っていたのを修正
 
-
 ## 2025.1.0
 
 ### Note
diff --git a/locales/index.d.ts b/locales/index.d.ts
index a0540fd228..4e26d5406b 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -4195,7 +4195,7 @@ export interface Locale extends ILocale {
      */
     "invalidParamError": string;
     /**
-     * リクエストパラメータに問題があります。通常これはバグですが、入力した文字数が多すぎる等の可能性もあります。
+     * リクエストパラメータに問題があります。通常これはバグですが、入力した文字数が多すぎる・許可されていない文字を入力している等の可能性もあります。
      */
     "invalidParamErrorDescription": string;
     /**
@@ -9180,18 +9180,6 @@ export interface Locale extends ILocale {
          * ソースを表示中
          */
         "readPage": string;
-        /**
-         * ページを作成しました
-         */
-        "created": string;
-        /**
-         * ページを更新しました
-         */
-        "updated": string;
-        /**
-         * ページを削除しました
-         */
-        "deleted": string;
         /**
          * ページ設定
          */
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index a578704434..13d8aec9b8 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1044,7 +1044,7 @@ youCannotCreateAnymore: "これ以上作成することはできません。"
 cannotPerformTemporary: "一時的に利用できません"
 cannotPerformTemporaryDescription: "操作回数が制限を超過するため一時的に利用できません。しばらく時間を置いてから再度お試しください。"
 invalidParamError: "パラメータエラー"
-invalidParamErrorDescription: "リクエストパラメータに問題があります。通常これはバグですが、入力した文字数が多すぎる等の可能性もあります。"
+invalidParamErrorDescription: "リクエストパラメータに問題があります。通常これはバグですが、入力した文字数が多すぎる・許可されていない文字を入力している等の可能性もあります。"
 permissionDeniedError: "操作が拒否されました"
 permissionDeniedErrorDescription: "このアカウントにはこの操作を行うための権限がありません。"
 preset: "プリセット"
@@ -2422,9 +2422,6 @@ _pages:
   newPage: "ページの作成"
   editPage: "ページの編集"
   readPage: "ソースを表示中"
-  created: "ページを作成しました"
-  updated: "ページを更新しました"
-  deleted: "ページを削除しました"
   pageSetting: "ページ設定"
   nameAlreadyExists: "指定されたページURLは既に存在しています"
   invalidNameTitle: "不正なページURLです"
diff --git a/packages/backend/src/models/Page.ts b/packages/backend/src/models/Page.ts
index 1695bf570e..0b59e7a92c 100644
--- a/packages/backend/src/models/Page.ts
+++ b/packages/backend/src/models/Page.ts
@@ -118,3 +118,5 @@ export class MiPage {
 		}
 	}
 }
+
+export const pageNameSchema = { type: 'string', pattern: /^[^\s:\/?#\[\]@!$&'()*+,;=\\%\x00-\x20]{1,256}$/.source } as const;
diff --git a/packages/backend/src/server/api/endpoints/pages/create.ts b/packages/backend/src/server/api/endpoints/pages/create.ts
index fa03b0b457..6de5fe3d44 100644
--- a/packages/backend/src/server/api/endpoints/pages/create.ts
+++ b/packages/backend/src/server/api/endpoints/pages/create.ts
@@ -7,7 +7,7 @@ import ms from 'ms';
 import { Inject, Injectable } from '@nestjs/common';
 import type { DriveFilesRepository, PagesRepository } from '@/models/_.js';
 import { IdService } from '@/core/IdService.js';
-import { MiPage } from '@/models/Page.js';
+import { MiPage, pageNameSchema } from '@/models/Page.js';
 import { Endpoint } from '@/server/api/endpoint-base.js';
 import { PageEntityService } from '@/core/entities/PageEntityService.js';
 import { DI } from '@/di-symbols.js';
@@ -51,7 +51,7 @@ export const paramDef = {
 	type: 'object',
 	properties: {
 		title: { type: 'string' },
-		name: { type: 'string', minLength: 1 },
+		name: { ...pageNameSchema, minLength: 1 },
 		summary: { type: 'string', nullable: true },
 		content: { type: 'array', items: {
 			type: 'object', additionalProperties: true,
diff --git a/packages/backend/src/server/api/endpoints/pages/update.ts b/packages/backend/src/server/api/endpoints/pages/update.ts
index e52d9c32df..a6aeb6002e 100644
--- a/packages/backend/src/server/api/endpoints/pages/update.ts
+++ b/packages/backend/src/server/api/endpoints/pages/update.ts
@@ -10,6 +10,7 @@ import type { PagesRepository, DriveFilesRepository } from '@/models/_.js';
 import { Endpoint } from '@/server/api/endpoint-base.js';
 import { DI } from '@/di-symbols.js';
 import { ApiError } from '../../error.js';
+import { pageNameSchema } from '@/models/Page.js';
 
 export const meta = {
 	tags: ['pages'],
@@ -31,13 +32,11 @@ export const meta = {
 			code: 'NO_SUCH_PAGE',
 			id: '21149b9e-3616-4778-9592-c4ce89f5a864',
 		},
-
 		accessDenied: {
 			message: 'Access denied.',
 			code: 'ACCESS_DENIED',
 			id: '3c15cd52-3b4b-4274-967d-6456fc4f792b',
 		},
-
 		noSuchFile: {
 			message: 'No such file.',
 			code: 'NO_SUCH_FILE',
@@ -56,7 +55,7 @@ export const paramDef = {
 	properties: {
 		pageId: { type: 'string', format: 'misskey:id' },
 		title: { type: 'string' },
-		name: { type: 'string', minLength: 1 },
+		name: { ...pageNameSchema, minLength: 1 },
 		summary: { type: 'string', nullable: true },
 		content: { type: 'array', items: {
 			type: 'object', additionalProperties: true,
diff --git a/packages/frontend/src/pages/page-editor/page-editor.vue b/packages/frontend/src/pages/page-editor/page-editor.vue
index ddb808390c..c08cfebab3 100644
--- a/packages/frontend/src/pages/page-editor/page-editor.vue
+++ b/packages/frontend/src/pages/page-editor/page-editor.vue
@@ -96,7 +96,7 @@ const summary = ref<string | null>(null);
 const name = ref(Date.now().toString());
 const eyeCatchingImage = ref<Misskey.entities.DriveFile | null>(null);
 const eyeCatchingImageId = ref<string | null>(null);
-const font = ref('sans-serif');
+const font = ref<'sans-serif' | 'serif'>('sans-serif');
 const content = ref<Misskey.entities.Page['content']>([]);
 const alignCenter = ref(false);
 const hideTitleWhenPinned = ref(false);
@@ -113,7 +113,7 @@ watch(eyeCatchingImageId, async () => {
 	}
 });
 
-function getSaveOptions() {
+function getSaveOptions(): Misskey.entities.PagesCreateRequest {
 	return {
 		title: title.value.trim(),
 		name: name.value.trim(),
@@ -128,80 +128,69 @@ function getSaveOptions() {
 	};
 }
 
-function save() {
+async function save() {
 	const options = getSaveOptions();
 
-	const onError = err => {
-		if (err.id === '3d81ceae-475f-4600-b2a8-2bc116157532') {
-			if (err.info.param === 'name') {
-				os.alert({
-					type: 'error',
-					title: i18n.ts._pages.invalidNameTitle,
-					text: i18n.ts._pages.invalidNameText,
-				});
-			}
-		} else if (err.code === 'NAME_ALREADY_EXISTS') {
-			os.alert({
-				type: 'error',
-				text: i18n.ts._pages.nameAlreadyExists,
-			});
-		}
-	};
-
 	if (pageId.value) {
-		options.pageId = pageId.value;
-		misskeyApi('pages/update', options)
-			.then(page => {
-				currentName.value = name.value.trim();
-				os.alert({
-					type: 'success',
-					text: i18n.ts._pages.updated,
-				});
-			}).catch(onError);
+		const updateOptions: Misskey.entities.PagesUpdateRequest = {
+			pageId: pageId.value,
+			...options,
+		};
+
+		await os.apiWithDialog('pages/update', updateOptions, undefined, {
+			'2298a392-d4a1-44c5-9ebb-ac1aeaa5a9ab': {
+				title: i18n.ts.somethingHappened,
+				text: i18n.ts._pages.nameAlreadyExists,
+			},
+		});
+
+		currentName.value = name.value.trim();
 	} else {
-		misskeyApi('pages/create', options)
-			.then(created => {
-				pageId.value = created.id;
-				currentName.value = name.value.trim();
-				os.alert({
-					type: 'success',
-					text: i18n.ts._pages.created,
-				});
-				mainRouter.push(`/pages/edit/${pageId.value}`);
-			}).catch(onError);
+		const created = await os.apiWithDialog('pages/create', options, undefined, {
+			'4650348e-301c-499a-83c9-6aa988c66bc1': {
+				title: i18n.ts.somethingHappened,
+				text: i18n.ts._pages.nameAlreadyExists,
+			},
+		});
+
+		pageId.value = created.id;
+		currentName.value = name.value.trim();
+		mainRouter.replace(`/pages/edit/${pageId.value}`);
 	}
 }
 
-function del() {
-	os.confirm({
+async function del() {
+	if (!pageId.value) return;
+
+	const { canceled } = await os.confirm({
 		type: 'warning',
 		text: i18n.tsx.removeAreYouSure({ x: title.value.trim() }),
-	}).then(({ canceled }) => {
-		if (canceled) return;
-		misskeyApi('pages/delete', {
-			pageId: pageId.value,
-		}).then(() => {
-			os.alert({
-				type: 'success',
-				text: i18n.ts._pages.deleted,
-			});
-			mainRouter.push('/pages');
-		});
 	});
+
+	if (canceled) return;
+
+	await os.apiWithDialog('pages/delete', {
+		pageId: pageId.value,
+	});
+
+	mainRouter.replace('/pages');
 }
 
-function duplicate() {
+async function duplicate() {
 	title.value = title.value + ' - copy';
 	name.value = name.value + '-copy';
-	misskeyApi('pages/create', getSaveOptions()).then(created => {
-		pageId.value = created.id;
-		currentName.value = name.value.trim();
-		os.alert({
-			type: 'success',
-			text: i18n.ts._pages.created,
-		});
-		mainRouter.push(`/pages/edit/${pageId.value}`);
+
+	const created = await os.apiWithDialog('pages/create', getSaveOptions(), undefined, {
+		'4650348e-301c-499a-83c9-6aa988c66bc1': {
+			title: i18n.ts.somethingHappened,
+			text: i18n.ts._pages.nameAlreadyExists,
+		},
 	});
+
+	pageId.value = created.id;
+	currentName.value = name.value.trim();
+
+	mainRouter.push(`/pages/edit/${pageId.value}`);
 }
 
 async function add() {
@@ -216,7 +205,7 @@ async function add() {
 	content.value.push({ id, type });
 }
 
-function setEyeCatchingImage(img) {
+function setEyeCatchingImage(img: Event) {
 	selectFile(img.currentTarget ?? img.target, null).then(file => {
 		eyeCatchingImageId.value = file.id;
 	});

From 23fc79bf069f6ead5dc617b35792bd968d02a1f0 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Wed, 5 Feb 2025 13:23:36 +0900
Subject: [PATCH 11/18] New Crowdin updates (#15400)

* New translations ja-jp.yml (Russian)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Portuguese)

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

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Japanese, Kansai)

* New translations ja-jp.yml (French)

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Arabic)

* New translations ja-jp.yml (Czech)

* New translations ja-jp.yml (German)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Polish)

* New translations ja-jp.yml (Slovak)

* New translations ja-jp.yml (Ukrainian)

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

* New translations ja-jp.yml (Vietnamese)

* New translations ja-jp.yml (Indonesian)

* New translations ja-jp.yml (Bengali)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Uzbek)
---
 locales/ar-SA.yml | 3 ---
 locales/bn-BD.yml | 3 ---
 locales/ca-ES.yml | 3 ---
 locales/cs-CZ.yml | 3 ---
 locales/de-DE.yml | 3 ---
 locales/en-US.yml | 3 ---
 locales/es-ES.yml | 3 ---
 locales/fr-FR.yml | 3 ---
 locales/id-ID.yml | 3 ---
 locales/it-IT.yml | 3 ---
 locales/ja-KS.yml | 3 ---
 locales/ko-KR.yml | 3 ---
 locales/pl-PL.yml | 3 ---
 locales/pt-PT.yml | 3 ---
 locales/ru-RU.yml | 3 ---
 locales/sk-SK.yml | 3 ---
 locales/th-TH.yml | 3 ---
 locales/uk-UA.yml | 3 ---
 locales/uz-UZ.yml | 3 ---
 locales/vi-VN.yml | 3 ---
 locales/zh-CN.yml | 3 ---
 locales/zh-TW.yml | 3 ---
 22 files changed, 66 deletions(-)

diff --git a/locales/ar-SA.yml b/locales/ar-SA.yml
index 1f885c66a2..91c90ce75a 100644
--- a/locales/ar-SA.yml
+++ b/locales/ar-SA.yml
@@ -1460,9 +1460,6 @@ _pages:
   newPage: "أنشئ صفحة جديدة"
   editPage: "عدّل الصفحة"
   readPage: "نُشّط عرض المصدر"
-  created: "نجح إنشاء الصفحة"
-  updated: "نجح تعديل الصفحة"
-  deleted: "نجح حذف الصفحة"
   pageSetting: "إعدادات الصفحة"
   nameAlreadyExists: "رابط الصفحة موجود مسبقًا"
   invalidNameTitle: "رابط الصفحة ليس صالحًا"
diff --git a/locales/bn-BD.yml b/locales/bn-BD.yml
index 9c8566c5b7..709874ac20 100644
--- a/locales/bn-BD.yml
+++ b/locales/bn-BD.yml
@@ -1237,9 +1237,6 @@ _pages:
   newPage: "নতুন পৃষ্ঠা বানান"
   editPage: "পৃষ্ঠাটি সম্পাদনা করুন"
   readPage: "উৎস দেখছেন"
-  created: "পৃষ্ঠা তৈরি করা হয়েছে"
-  updated: "পৃষ্ঠা সম্পাদনা করা হয়েছে"
-  deleted: "পৃষ্ঠা মুছে ফেলা হয়েছে"
   pageSetting: "পৃষ্ঠার সেটিংস"
   nameAlreadyExists: "পৃষ্ঠার URLটি ইতিমধ্যেই ব্যাবহার করা হয়েছে"
   invalidNameTitle: "পৃষ্ঠার URL অবৈধ"
diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml
index 9954b2a747..7b029c6f41 100644
--- a/locales/ca-ES.yml
+++ b/locales/ca-ES.yml
@@ -2365,9 +2365,6 @@ _pages:
   newPage: "pa"
   editPage: "Editar la pàgina"
   readPage: "Veure el codi font d'aquesta pàgina"
-  created: "La pàgina ha sigut creada correctament"
-  updated: "La pàgina s'ha editat correctament"
-  deleted: "La pàgina s'ha esborrat sense problemes"
   pageSetting: "Configuració de la pàgina"
   nameAlreadyExists: "L'adreça URL de la pàgina ja existeix"
   invalidNameTitle: "L'adreça URL de la pàgina no és vàlida"
diff --git a/locales/cs-CZ.yml b/locales/cs-CZ.yml
index 20bea96b7f..afa3047c1d 100644
--- a/locales/cs-CZ.yml
+++ b/locales/cs-CZ.yml
@@ -1883,9 +1883,6 @@ _pages:
   newPage: "Vytvořit novou stránku"
   editPage: "Upravit stránku"
   readPage: "Prohlížení zdroje této stránky"
-  created: "Stránka byla úspěšně vytvořena"
-  updated: "Stránka byla úspěšně aktualizována"
-  deleted: "Stránka byla úspěšně smazána"
   pageSetting: "Nastavení stránky"
   nameAlreadyExists: "Zadaná adresa URL stránky již existuje"
   invalidNameTitle: "Zadaná adresa URL stránky je neplatná"
diff --git a/locales/de-DE.yml b/locales/de-DE.yml
index e99a32a364..11fe6d3ff5 100644
--- a/locales/de-DE.yml
+++ b/locales/de-DE.yml
@@ -2277,9 +2277,6 @@ _pages:
   newPage: "Seite erstellen"
   editPage: "Seite bearbeiten"
   readPage: "Quelltextansicht"
-  created: "Seite erfolgreich erstellt"
-  updated: "Seite erfolgreich aktualisiert"
-  deleted: "Seite erfolgreich gelöscht"
   pageSetting: "Seiteneinstellungen"
   nameAlreadyExists: "Die angegebene Seiten-URL existiert bereits"
   invalidNameTitle: "Die angegebene Seiten-URL ist ungültig"
diff --git a/locales/en-US.yml b/locales/en-US.yml
index 360cfd72c5..6ff7e5fb7c 100644
--- a/locales/en-US.yml
+++ b/locales/en-US.yml
@@ -2365,9 +2365,6 @@ _pages:
   newPage: "Create a new Page"
   editPage: "Edit this Page"
   readPage: "Viewing this Page's source"
-  created: "Page successfully created"
-  updated: "Page successfully edited"
-  deleted: "Page successfully deleted"
   pageSetting: "Page settings"
   nameAlreadyExists: "The specified Page URL already exists"
   invalidNameTitle: "The specified Page URL is invalid"
diff --git a/locales/es-ES.yml b/locales/es-ES.yml
index 28cfba1c20..0b1411d84b 100644
--- a/locales/es-ES.yml
+++ b/locales/es-ES.yml
@@ -2294,9 +2294,6 @@ _pages:
   newPage: "Crear página"
   editPage: "Editar página"
   readPage: "Viendo la fuente"
-  created: "La página fue creada"
-  updated: "La página fue actualizada"
-  deleted: "La página borrada"
   pageSetting: "Configurar página"
   nameAlreadyExists: "La URL de la página especificada ya existe"
   invalidNameTitle: "URL inválida"
diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml
index 473774114e..ccfd462a76 100644
--- a/locales/fr-FR.yml
+++ b/locales/fr-FR.yml
@@ -2118,9 +2118,6 @@ _pages:
   newPage: "Créer une page"
   editPage: "Modifier une page"
   readPage: "Affichage de la source en cours"
-  created: "La page a été créée !"
-  updated: "La page a été mise à jour !"
-  deleted: "La page a été supprimée"
   pageSetting: "Paramètres de la Page"
   nameAlreadyExists: "L'URL de page spécifiée existe déjà"
   invalidNameTitle: "L'URL de page spécifiée n’est pas valide"
diff --git a/locales/id-ID.yml b/locales/id-ID.yml
index 9a28cee275..7be56b1494 100644
--- a/locales/id-ID.yml
+++ b/locales/id-ID.yml
@@ -2285,9 +2285,6 @@ _pages:
   newPage: "Buat halaman baru"
   editPage: "Sunting halaman"
   readPage: "Lihat sumber kode aktif"
-  created: "Halaman berhasil dibuat"
-  updated: "Halaman berhasil diperbaharui!"
-  deleted: "Halaman telah dihapus"
   pageSetting: "Pengaturan Halaman"
   nameAlreadyExists: "URL Halaman yang ditentukan sudah ada"
   invalidNameTitle: "URL Halaman yang ditentukan tidak valid"
diff --git a/locales/it-IT.yml b/locales/it-IT.yml
index d2942c389c..c233e3ab87 100644
--- a/locales/it-IT.yml
+++ b/locales/it-IT.yml
@@ -2365,9 +2365,6 @@ _pages:
   newPage: "Crea pagina"
   editPage: "Modifica pagina"
   readPage: "Visualizzando fonte "
-  created: "Pagina creata!"
-  updated: "Pagina aggiornata con successo!"
-  deleted: "Pagina eliminata"
   pageSetting: "Impostazioni pagina"
   nameAlreadyExists: "Esiste già una pagina con lo stesso URL."
   invalidNameTitle: "L'URL di pagina definito non è valido"
diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml
index 2dd2220791..66560f524b 100644
--- a/locales/ja-KS.yml
+++ b/locales/ja-KS.yml
@@ -2357,9 +2357,6 @@ _pages:
   newPage: "ページを作る"
   editPage: "ページの編集"
   readPage: "ソースを表示中"
-  created: "ページを作成したで"
-  updated: "ページを更新したで"
-  deleted: "ページを削除したで"
   pageSetting: "ページ設定"
   nameAlreadyExists: "指定されたページURLはもうあるみたいや"
   invalidNameTitle: "正しくないページURLみたいやで"
diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml
index 45d7f26075..36b818c117 100644
--- a/locales/ko-KR.yml
+++ b/locales/ko-KR.yml
@@ -2365,9 +2365,6 @@ _pages:
   newPage: "페이지 만들기"
   editPage: "페이지 수정"
   readPage: "소스 표시 중"
-  created: "페이지를 만들었습니다"
-  updated: "페이지를 수정했습니다"
-  deleted: "페이지가 삭제되었습니다"
   pageSetting: "페이지 설정"
   nameAlreadyExists: "지정한 페이지 URL이 이미 존재합니다"
   invalidNameTitle: "유효하지 않은 페이지 URL입니다"
diff --git a/locales/pl-PL.yml b/locales/pl-PL.yml
index 98465ea82b..9bd585de86 100644
--- a/locales/pl-PL.yml
+++ b/locales/pl-PL.yml
@@ -1459,9 +1459,6 @@ _pages:
   newPage: "Utwórz stronę"
   editPage: "Edytuj tę stronę"
   readPage: "Aktywowano widok źródła"
-  created: "Pomyślnie utworzono stronę!"
-  updated: "Pomyślnie zaktualizowano stronę!"
-  deleted: "Strona została usunięta"
   pageSetting: "Ustawienia strony"
   nameAlreadyExists: "Określony adres URL strony już istnieje"
   invalidNameTitle: "Podany adres URL strony jest nieprawidłowy"
diff --git a/locales/pt-PT.yml b/locales/pt-PT.yml
index aae63805c3..d691022d75 100644
--- a/locales/pt-PT.yml
+++ b/locales/pt-PT.yml
@@ -2357,9 +2357,6 @@ _pages:
   newPage: "Criar uma Página"
   editPage: "Editar essa Página"
   readPage: "Ver a fonte dessa Página"
-  created: "Página criada com sucesso"
-  updated: "Página atualizada com sucesso"
-  deleted: "Página excluída com sucesso"
   pageSetting: "Configurações da página"
   nameAlreadyExists: "O URL de Página especificado já existe"
   invalidNameTitle: "O URL de Página especificado é inválido"
diff --git a/locales/ru-RU.yml b/locales/ru-RU.yml
index bc1b12895c..7ed41a9c47 100644
--- a/locales/ru-RU.yml
+++ b/locales/ru-RU.yml
@@ -1976,9 +1976,6 @@ _pages:
   newPage: "Создать страницу"
   editPage: "Править страницу"
   readPage: "Читать страницу"
-  created: "Страница успешно создана."
-  updated: "Страница успешно обновлена."
-  deleted: "Страница успешно удалена."
   pageSetting: "Настройки страницы"
   nameAlreadyExists: "Указанный адрес страницы уже существует."
   invalidNameTitle: "Указанный адрес страницы недопустим."
diff --git a/locales/sk-SK.yml b/locales/sk-SK.yml
index 715ff4c847..521d172671 100644
--- a/locales/sk-SK.yml
+++ b/locales/sk-SK.yml
@@ -1332,9 +1332,6 @@ _pages:
   newPage: "Vytvoriť novú stránku"
   editPage: "Upraviť túto stránku"
   readPage: "Zobrazenie zdroja aktívne"
-  created: "Stránka úspešne vytvorená"
-  updated: "Stránka úspešne upravená"
-  deleted: "Stránka úspešne odstránená"
   pageSetting: "Nastavenia stránky"
   nameAlreadyExists: "Zadaná URL stránku už existuje"
   invalidNameTitle: "Zadaná URL stránku je nesprávna"
diff --git a/locales/th-TH.yml b/locales/th-TH.yml
index 8e68d6cf49..ec83ba888c 100644
--- a/locales/th-TH.yml
+++ b/locales/th-TH.yml
@@ -2331,9 +2331,6 @@ _pages:
   newPage: "สร้างหน้าเพจใหม่"
   editPage: "แก้ไขหน้าเพจ"
   readPage: "กำลังดูแหล่งที่มาของเพจนี้"
-  created: "สร้างหน้าเพจสำเร็จเรียบร้อยแล้ว"
-  updated: "แก้ไขหน้าเพจสำเร็จเรียบร้อยแล้ว"
-  deleted: "ลบหน้าเพจสำเร็จเรียบร้อยแล้ว"
   pageSetting: "การตั้งค่าหน้าเพจ"
   nameAlreadyExists: "URL ของหน้าที่ระบุนั้นมีอยู่แล้ว"
   invalidNameTitle: "URL ของหน้าที่ระบุนั้นไม่ถูกต้อง"
diff --git a/locales/uk-UA.yml b/locales/uk-UA.yml
index 6e3e0bb9da..a83ad80683 100644
--- a/locales/uk-UA.yml
+++ b/locales/uk-UA.yml
@@ -1513,9 +1513,6 @@ _pages:
   newPage: "Створити сторінку"
   editPage: "Редагувати сторінку"
   readPage: "Перегляд вихідного коду"
-  created: "Сторінка успішно створена."
-  updated: "Сторінка успішно оновлена."
-  deleted: "Сторінку видалено"
   pageSetting: "Налаштування сторінки"
   nameAlreadyExists: "Вказана адреса сторінки вже існує."
   invalidNameTitle: "Вказана адреса сторінки неприпустима."
diff --git a/locales/uz-UZ.yml b/locales/uz-UZ.yml
index 2116d2b86f..6015492b92 100644
--- a/locales/uz-UZ.yml
+++ b/locales/uz-UZ.yml
@@ -1004,9 +1004,6 @@ _play:
 _pages:
   newPage: "Yangi Sahifa yaratish"
   editPage: "Ushbu Sahifani tahrirlash"
-  created: "Sahifa muvaffaqiyatli yaratildi"
-  updated: "Sahifa muvaffaqiyatli tahrirlandi"
-  deleted: "Sahifa muvaffaqiyatli o'chirildi"
   pageSetting: "Sahifa sozlamalari"
   nameAlreadyExists: "Ko'rsatilgan Sahifa URL'i allaqachon mavjud"
   invalidNameTitle: "Ko'rsatilgan Sahifa URL'i yaroqsiz"
diff --git a/locales/vi-VN.yml b/locales/vi-VN.yml
index cded29fdba..e6a9418126 100644
--- a/locales/vi-VN.yml
+++ b/locales/vi-VN.yml
@@ -1802,9 +1802,6 @@ _pages:
   newPage: "Tạo Trang mới"
   editPage: "Sửa Trang này"
   readPage: "Xem mã nguồn Trang này"
-  created: "Trang đã được tạo thành công"
-  updated: "Trang đã được cập nhật thành công"
-  deleted: "Trang đã được xóa thành công"
   pageSetting: "Cài đặt trang"
   nameAlreadyExists: "URL Trang đã tồn tại"
   invalidNameTitle: "URL Trang không hợp lệ"
diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml
index 1a14f0bf76..f4df425af4 100644
--- a/locales/zh-CN.yml
+++ b/locales/zh-CN.yml
@@ -2365,9 +2365,6 @@ _pages:
   newPage: "创建页面"
   editPage: "编辑页面"
   readPage: "查看页面"
-  created: "页面已创建"
-  updated: "页面已更新"
-  deleted: "该页面已被删除"
   pageSetting: "页面设置"
   nameAlreadyExists: "该页面 URL 已存在"
   invalidNameTitle: "无效的页面 URL"
diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml
index 159ede1356..466e3cc1d8 100644
--- a/locales/zh-TW.yml
+++ b/locales/zh-TW.yml
@@ -2365,9 +2365,6 @@ _pages:
   newPage: "建立頁面"
   editPage: "編輯頁面"
   readPage: "正在檢視原始碼"
-  created: "頁面已建立"
-  updated: "頁面已更新"
-  deleted: "頁面已被刪除"
   pageSetting: "頁面設定"
   nameAlreadyExists: "該頁面 URL 已存在"
   invalidNameTitle: "無效的頁面 URL"

From 2f4e2a7cca47638d15eb0d11109111565af988cb Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Wed, 5 Feb 2025 04:24:51 +0000
Subject: [PATCH 12/18] Bump version to 2025.2.0-beta.1

---
 package.json                     | 2 +-
 packages/misskey-js/package.json | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index 05adf49e21..972191a88f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "misskey",
-	"version": "2025.2.0-beta.0",
+	"version": "2025.2.0-beta.1",
 	"codename": "nasubi",
 	"repository": {
 		"type": "git",
diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index 0e1a46ad72..b9dd5b6817 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -1,7 +1,7 @@
 {
 	"type": "module",
 	"name": "misskey-js",
-	"version": "2025.2.0-beta.0",
+	"version": "2025.2.0-beta.1",
 	"description": "Misskey SDK for JavaScript",
 	"license": "MIT",
 	"main": "./built/index.js",

From fd880660a3120a0ff3c44740df98cd46c9113237 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Wed, 5 Feb 2025 17:02:10 +0900
Subject: [PATCH 13/18] =?UTF-8?q?fix(frontend):=20=E3=83=87=E3=83=83?=
 =?UTF-8?q?=E3=82=AD=E3=81=AE=E3=83=97=E3=83=AD=E3=83=95=E3=82=A1=E3=82=A4?=
 =?UTF-8?q?=E3=83=AB=E3=81=8C=E6=96=B0=E8=A6=8F=E4=BD=9C=E6=88=90=E3=81=A7?=
 =?UTF-8?q?=E3=81=8D=E3=81=AA=E3=81=84=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE?=
 =?UTF-8?q?=E6=AD=A3=20(#15406)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix(frontend): デッキのプロファイルが保存できない問題を修正

* Update Changelog

* Update CHANGELOG.md
---
 CHANGELOG.md                                |  1 +
 packages/frontend/src/ui/deck.vue           | 26 ++++++++++++++++-----
 packages/frontend/src/ui/deck/deck-store.ts | 10 +++++---
 3 files changed, 28 insertions(+), 9 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7f48d1c532..c5a25c5e84 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@
 - Fix: データセーバー有効時にもユーザーページの「ファイル」タブで画像が読み込まれてしまう問題を修正
 - Fix: MFMの `sparkle` エフェクトが正しく表示されない問題を修正
 - Fix: ページのURLにスラッシュが含まれている場合にページが正しく表示されない問題を修正
+- Fix: デッキのプロファイルが新規作成できない問題を修正
 - ローカライゼーションの更新
 - Playが実装されたため、ページ機能の「ソースを見る」は削除されました
 
diff --git a/packages/frontend/src/ui/deck.vue b/packages/frontend/src/ui/deck.vue
index a1a76a7e7d..71a18fbc66 100644
--- a/packages/frontend/src/ui/deck.vue
+++ b/packages/frontend/src/ui/deck.vue
@@ -95,7 +95,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 import { computed, defineAsyncComponent, ref, watch, shallowRef } from 'vue';
 import { v4 as uuid } from 'uuid';
 import XCommon from './_common_/common.vue';
-import { deckStore, columnTypes, addColumn as addColumnToStore, loadDeck, getProfiles, deleteProfile as deleteProfile_ } from './deck/deck-store.js';
+import { deckStore, columnTypes, addColumn as addColumnToStore, forceSaveDeck, loadDeck, getProfiles, deleteProfile as deleteProfile_ } from './deck/deck-store.js';
 import type { ColumnType } from './deck/deck-store.js';
 import type { MenuItem } from '@/types/menu.js';
 import XSidebar from '@/ui/_common_/navbar.vue';
@@ -233,10 +233,15 @@ function changeProfile(ev: MouseEvent) {
 					title: i18n.ts._deck.profile,
 					minLength: 1,
 				});
+
 				if (canceled || name == null) return;
 
-				deckStore.set('profile', name);
-				unisonReload();
+				os.promiseDialog((async () => {
+					await deckStore.set('profile', name);
+					await forceSaveDeck();
+				})(), () => {
+					unisonReload();
+				});
 			},
 		});
 	}).then(() => {
@@ -251,9 +256,18 @@ async function deleteProfile() {
 	});
 	if (canceled) return;
 
-	deleteProfile_(deckStore.state.profile);
-	deckStore.set('profile', 'default');
-	unisonReload();
+	os.promiseDialog((async () => {
+		if (deckStore.state.profile === 'default') {
+			await deckStore.set('columns', []);
+			await deckStore.set('layout', []);
+			await forceSaveDeck();
+		} else {
+			await deleteProfile_(deckStore.state.profile);
+		}
+		await deckStore.set('profile', 'default');
+	})(), () => {
+		unisonReload();
+	});
 }
 </script>
 
diff --git a/packages/frontend/src/ui/deck/deck-store.ts b/packages/frontend/src/ui/deck/deck-store.ts
index 3186982349..231bf19aa8 100644
--- a/packages/frontend/src/ui/deck/deck-store.ts
+++ b/packages/frontend/src/ui/deck/deck-store.ts
@@ -112,9 +112,8 @@ export const loadDeck = async () => {
 	deckStore.set('layout', deck.layout);
 };
 
-// TODO: deckがloadされていない状態でsaveすると意図せず上書きが発生するので対策する
-export const saveDeck = throttle(1000, () => {
-	misskeyApi('i/registry/set', {
+export async function forceSaveDeck() {
+	await misskeyApi('i/registry/set', {
 		scope: ['client', 'deck', 'profiles'],
 		key: deckStore.state.profile,
 		value: {
@@ -122,6 +121,11 @@ export const saveDeck = throttle(1000, () => {
 			layout: deckStore.reactiveState.layout.value,
 		},
 	});
+}
+
+// TODO: deckがloadされていない状態でsaveすると意図せず上書きが発生するので対策する
+export const saveDeck = throttle(1000, () => {
+	forceSaveDeck();
 });
 
 export async function getProfiles(): Promise<string[]> {

From 0f0e88e4c7bcfb30a3800e5e942c6414659e1eaa Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Wed, 5 Feb 2025 17:14:40 +0900
Subject: [PATCH 14/18] Update CHANGELOG.md

---
 CHANGELOG.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index c5a25c5e84..5acfb71727 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,7 @@
 - Fix: MFMの `sparkle` エフェクトが正しく表示されない問題を修正
 - Fix: ページのURLにスラッシュが含まれている場合にページが正しく表示されない問題を修正
 - Fix: デッキのプロファイルが新規作成できない問題を修正
+- Fix: セキュリティに関する修正
 - ローカライゼーションの更新
 - Playが実装されたため、ページ機能の「ソースを見る」は削除されました
 

From b7c3630da991bd0ab75f86c6b95092b161cc8085 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Wed, 5 Feb 2025 08:58:41 +0000
Subject: [PATCH 15/18] Release: 2025.2.0

---
 package.json                     | 2 +-
 packages/misskey-js/package.json | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index 972191a88f..52c139342f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "misskey",
-	"version": "2025.2.0-beta.1",
+	"version": "2025.2.0",
 	"codename": "nasubi",
 	"repository": {
 		"type": "git",
diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index b9dd5b6817..601c261a05 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -1,7 +1,7 @@
 {
 	"type": "module",
 	"name": "misskey-js",
-	"version": "2025.2.0-beta.1",
+	"version": "2025.2.0",
 	"description": "Misskey SDK for JavaScript",
 	"license": "MIT",
 	"main": "./built/index.js",

From c634ae37e5e1cd221c9bc9d83f277e1758ef0b43 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Wed, 5 Feb 2025 08:58:47 +0000
Subject: [PATCH 16/18] [skip ci] Update CHANGELOG.md (prepend template)

---
 CHANGELOG.md | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5acfb71727..6d17921700 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,15 @@
+## Unreleased
+
+### General
+-
+
+### Client
+-
+
+### Server
+-
+
+
 ## 2025.2.0
 
 ### General

From c548ec9906947c72743e611254a6557e8e8d057c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Wed, 5 Feb 2025 19:01:44 +0900
Subject: [PATCH 17/18] =?UTF-8?q?refactor(frontend):=20verbatimModuleSynta?=
 =?UTF-8?q?x=E3=82=92=E6=9C=89=E5=8A=B9=E5=8C=96=20(#15323)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* wip

* wip

* wip

* wip

* revert unnecessary changes

* wip

* refactor(frontend): enforce verbatimModuleSyntax

* fix

* refactor(frontend-shared): enforce verbatimModuleSyntax

* wip

* refactor(frontend-embed): enforce verbatimModuleSyntax

* enforce consistent-type-imports

* fix lint config

* attemt to fix ci

* fix lint

* fix

* fix

* fix
---
 packages/frontend-embed/eslint.config.js      |  1 +
 .../frontend-embed/src/components/EmMfm.ts    |  3 +-
 .../frontend-embed/src/components/EmNotes.vue |  3 +-
 packages/frontend-embed/tsconfig.json         |  1 +
 packages/frontend-shared/eslint.config.js     |  1 +
 packages/frontend-shared/tsconfig.json        |  1 +
 packages/frontend/.storybook/charts.ts        |  3 +-
 packages/frontend/eslint.config.js            |  1 +
 ...lup-plugin-unwind-css-module-class-name.ts |  2 +-
 packages/frontend/src/boot/common.ts          |  3 +-
 packages/frontend/src/boot/main-boot.ts       |  5 +-
 .../MkAbuseReportWindow.stories.impl.ts       |  2 +-
 .../components/MkAccountMoved.stories.impl.ts |  2 +-
 .../components/MkAchievements.stories.impl.ts |  2 +-
 .../components/MkAnalogClock.stories.impl.ts  |  2 +-
 .../MkAnnouncementDialog.stories.impl.ts      |  2 +-
 .../MkAntennaEditor.stories.impl.ts           |  2 +-
 .../MkAntennaEditorDialog.stories.impl.ts     |  2 +-
 packages/frontend/src/components/MkAsUi.vue   |  5 +-
 .../components/MkAutocomplete.stories.impl.ts |  2 +-
 .../src/components/MkAutocomplete.vue         |  3 +-
 .../src/components/MkAvatars.stories.impl.ts  |  2 +-
 .../src/components/MkButton.stories.impl.ts   |  2 +-
 .../MkChannelFollowButton.stories.impl.ts     |  2 +-
 .../components/MkChannelList.stories.impl.ts  |  2 +-
 .../frontend/src/components/MkChannelList.vue |  3 +-
 .../MkChannelPreview.stories.impl.ts          |  2 +-
 .../src/components/MkChart.stories.impl.ts    |  2 +-
 .../frontend/src/components/MkChartLegend.vue |  3 +-
 .../components/MkClickerGame.stories.impl.ts  |  2 +-
 .../components/MkClipPreview.stories.impl.ts  |  2 +-
 .../src/components/MkCode.stories.impl.ts     |  2 +-
 .../components/MkCodeEditor.stories.impl.ts   |  2 +-
 .../components/MkCodeInline.stories.impl.ts   |  2 +-
 .../components/MkColorInput.stories.impl.ts   |  2 +-
 .../components/MkContextMenu.stories.impl.ts  |  2 +-
 .../MkCropperDialog.stories.impl.ts           |  2 +-
 ...kCustomEmojiDetailedDialog.stories.impl.ts |  2 +-
 .../src/components/MkCwButton.stories.impl.ts |  2 +-
 .../src/components/MkDateSeparatedList.vue    |  5 +-
 .../src/components/MkDialog.stories.impl.ts   |  2 +-
 .../components/MkDigitalClock.stories.impl.ts |  2 +-
 .../src/components/MkDonation.stories.impl.ts |  2 +-
 .../components/MkDrive.file.stories.impl.ts   |  2 +-
 .../components/MkDrive.folder.stories.impl.ts |  2 +-
 .../src/components/MkDrive.stories.impl.ts    |  2 +-
 .../MkDriveFileThumbnail.stories.impl.ts      |  2 +-
 .../src/components/MkEmojiPicker.section.vue  |  6 +-
 .../components/MkEmojiPicker.stories.impl.ts  |  2 +-
 .../frontend/src/components/MkEmojiPicker.vue |  6 +-
 .../MkExtensionInstaller.stories.impl.ts      |  2 +-
 .../components/MkFlashPreview.stories.impl.ts |  2 +-
 .../MkGalleryPostPreview.stories.impl.ts      |  2 +-
 packages/frontend/src/components/MkInput.vue  |  6 +-
 .../MkInstanceCardMini.stories.impl.ts        |  2 +-
 .../src/components/MkInstanceStats.vue        |  3 +-
 .../src/components/MkInstanceTicker.vue       |  3 +-
 .../components/MkInviteCode.stories.impl.ts   |  2 +-
 packages/frontend/src/components/MkLink.vue   |  2 +-
 .../frontend/src/components/MkMediaAudio.vue  |  2 +-
 .../frontend/src/components/MkMediaRange.vue  |  5 +-
 .../frontend/src/components/MkMediaVideo.vue  |  2 +-
 .../frontend/src/components/MkMention.vue     |  2 +-
 packages/frontend/src/components/MkMenu.vue   |  4 +-
 packages/frontend/src/components/MkModal.vue  |  2 +-
 packages/frontend/src/components/MkNote.vue   |  8 ++-
 .../src/components/MkNoteDetailed.vue         |  8 ++-
 .../src/components/MkNoteMediaGrid.vue        | 70 +++++++++----------
 packages/frontend/src/components/MkNotes.vue  |  3 +-
 .../components/MkNotificationSelectWindow.vue |  3 +-
 .../src/components/MkNotifications.vue        |  2 +-
 .../frontend/src/components/MkPageWindow.vue  |  3 +-
 .../frontend/src/components/MkPagination.vue  |  5 +-
 .../frontend/src/components/MkPostForm.vue    |  6 +-
 packages/frontend/src/components/MkRadios.vue |  3 +-
 .../MkRoleSelectDialog.stories.impl.ts        |  2 +-
 packages/frontend/src/components/MkSelect.vue |  3 +-
 packages/frontend/src/components/MkSignin.vue |  3 +-
 .../src/components/MkSignupDialog.form.vue    |  3 +-
 .../MkSignupDialog.rules.stories.impl.ts      |  2 +-
 .../src/components/MkSortOrderEditor.vue      |  4 +-
 .../frontend/src/components/MkSuperMenu.vue   |  2 +-
 .../src/components/MkSwitch.button.vue        |  3 +-
 packages/frontend/src/components/MkSwitch.vue |  3 +-
 .../src/components/MkSystemWebhookEditor.vue  |  2 +-
 .../src/components/MkTagItem.stories.impl.ts  |  2 +-
 .../frontend/src/components/MkTextarea.vue    |  3 +-
 .../frontend/src/components/MkTimeline.vue    |  2 +-
 .../frontend/src/components/MkUserList.vue    |  3 +-
 .../MkUserSetupDialog.Follow.stories.impl.ts  |  2 +-
 .../components/MkUserSetupDialog.Follow.vue   |  3 +-
 .../MkUserSetupDialog.Privacy.stories.impl.ts |  2 +-
 .../MkUserSetupDialog.Profile.stories.impl.ts |  2 +-
 .../MkUserSetupDialog.User.stories.impl.ts    |  2 +-
 .../MkUserSetupDialog.stories.impl.ts         |  2 +-
 .../src/components/global/MkA.stories.impl.ts |  2 +-
 .../components/global/MkAcct.stories.impl.ts  |  2 +-
 .../components/global/MkAd.stories.impl.ts    |  2 +-
 .../global/MkAvatar.stories.impl.ts           |  2 +-
 .../global/MkCondensedLine.stories.impl.ts    |  2 +-
 .../global/MkCustomEmoji.stories.impl.ts      |  2 +-
 .../global/MkEllipsis.stories.impl.ts         |  2 +-
 .../components/global/MkEmoji.stories.impl.ts |  2 +-
 .../components/global/MkError.stories.impl.ts |  2 +-
 .../components/global/MkError.stories.meta.ts |  2 +-
 .../global/MkLoading.stories.impl.ts          |  2 +-
 .../components/global/MkMfm.stories.impl.ts   |  4 +-
 .../frontend/src/components/global/MkMfm.ts   |  6 +-
 .../global/MkPageHeader.stories.impl.ts       |  2 +-
 .../src/components/global/MkPageHeader.vue    |  3 +-
 .../components/global/MkStickyContainer.vue   |  3 +-
 .../components/global/MkTime.stories.impl.ts  |  2 +-
 .../components/global/MkUrl.stories.impl.ts   |  2 +-
 .../frontend/src/components/global/MkUrl.vue  |  2 +-
 .../global/MkUserName.stories.impl.ts         |  2 +-
 .../src/components/global/RouterView.vue      |  2 +-
 .../src/components/grid/MkDataCell.vue        |  7 +-
 .../src/components/grid/MkDataRow.vue         |  7 +-
 .../components/grid/MkGrid.stories.impl.ts    |  8 +--
 .../frontend/src/components/grid/MkGrid.vue   | 17 +++--
 .../src/components/grid/MkHeaderCell.vue      |  5 +-
 .../src/components/grid/MkHeaderRow.vue       |  7 +-
 .../src/components/grid/MkNumberCell.vue      |  3 +-
 .../src/components/grid/cell-validators.ts    |  6 +-
 packages/frontend/src/components/grid/cell.ts | 12 ++--
 .../frontend/src/components/grid/column.ts    | 12 ++--
 .../src/components/grid/grid-event.ts         | 10 +--
 .../src/components/grid/grid-utils.ts         | 14 ++--
 packages/frontend/src/components/grid/grid.ts |  6 +-
 packages/frontend/src/components/grid/row.ts  | 10 +--
 packages/frontend/src/components/index.ts     |  2 +-
 packages/frontend/src/debug.ts                |  3 +-
 .../frontend/src/directives/adaptive-bg.ts    |  2 +-
 .../src/directives/adaptive-border.ts         |  2 +-
 packages/frontend/src/directives/anim.ts      |  2 +-
 packages/frontend/src/directives/appear.ts    |  2 +-
 .../frontend/src/directives/click-anime.ts    |  2 +-
 .../frontend/src/directives/follow-append.ts  |  2 +-
 packages/frontend/src/directives/get-size.ts  |  2 +-
 packages/frontend/src/directives/hotkey.ts    |  2 +-
 packages/frontend/src/directives/index.ts     |  2 +-
 packages/frontend/src/directives/panel.ts     |  2 +-
 packages/frontend/src/directives/tooltip.ts   |  3 +-
 .../frontend/src/directives/user-preview.ts   |  3 +-
 packages/frontend/src/nirax.ts                |  3 +-
 packages/frontend/src/os.ts                   |  3 +-
 .../frontend/src/pages/about.federation.vue   |  3 +-
 .../notification-recipient.editor.vue         |  3 +-
 .../src/pages/admin/bot-protection.vue        |  2 +-
 .../custom-emojis-manager.local.list.vue      |  7 +-
 .../custom-emojis-manager.local.register.vue  | 12 ++--
 .../admin/custom-emojis-manager.remote.vue    | 15 ++--
 .../custom-emojis-manager2.stories.impl.ts    |  2 +-
 packages/frontend/src/pages/admin/index.vue   |  3 +-
 packages/frontend/src/pages/admin/invites.vue |  3 +-
 .../overview.ap-requests.stories.impl.ts      |  2 +-
 .../src/pages/admin/overview.federation.vue   |  3 +-
 packages/frontend/src/pages/admin/queue.vue   |  3 +-
 packages/frontend/src/pages/api-console.vue   |  2 +-
 packages/frontend/src/pages/channel.vue       |  2 +-
 .../frontend/src/pages/drive.file.notes.vue   |  2 +-
 .../src/pages/drop-and-fusion.game.vue        |  3 +-
 packages/frontend/src/pages/flash/flash.vue   |  9 ++-
 .../frontend/src/pages/follow-requests.vue    |  3 +-
 .../frontend/src/pages/install-extensions.vue |  6 +-
 packages/frontend/src/pages/instance-info.vue |  6 +-
 packages/frontend/src/pages/invite.vue        |  5 +-
 packages/frontend/src/pages/scratchpad.vue    |  8 ++-
 .../frontend/src/pages/search.stories.impl.ts |  2 +-
 .../frontend/src/pages/settings/accounts.vue  |  4 +-
 .../src/pages/settings/drive-cleaner.vue      |  3 +-
 .../src/pages/settings/emoji-picker.vue       |  3 +-
 .../frontend/src/pages/settings/index.vue     |  6 +-
 .../src/pages/settings/notifications.vue      |  3 +-
 .../frontend/src/pages/settings/sounds.vue    |  3 +-
 .../src/pages/settings/theme.manage.vue       |  3 +-
 packages/frontend/src/pages/theme-editor.vue  |  3 +-
 .../src/pages/user/activity.following.vue     |  3 +-
 .../src/pages/user/activity.notes.vue         |  3 +-
 .../frontend/src/pages/user/activity.pv.vue   |  3 +-
 .../src/pages/user/home.stories.impl.ts       |  2 +-
 packages/frontend/src/pizzax.ts               |  3 +-
 packages/frontend/src/plugin.ts               |  3 +-
 packages/frontend/src/router/definition.ts    |  3 +-
 packages/frontend/src/router/main.ts          |  2 +-
 packages/frontend/src/router/supplier.ts      |  3 +-
 .../frontend/src/scripts/aiscript/common.ts   |  3 +-
 packages/frontend/src/scripts/aiscript/ui.ts  |  3 +-
 packages/frontend/src/scripts/autocomplete.ts |  3 +-
 packages/frontend/src/scripts/chart-legend.ts |  2 +-
 packages/frontend/src/scripts/chart-vline.ts  |  2 +-
 .../src/scripts/check-reaction-permissions.ts |  2 +-
 packages/frontend/src/scripts/emoji-picker.ts |  3 +-
 .../frontend/src/scripts/get-note-menu.ts     |  3 +-
 .../frontend/src/scripts/get-user-menu.ts     |  2 +-
 .../frontend/src/scripts/install-theme.ts     |  3 +-
 .../src/scripts/mfm-function-picker.ts        |  3 +-
 .../frontend/src/scripts/page-metadata.ts     |  3 +-
 .../frontend/src/scripts/reaction-picker.ts   |  3 +-
 packages/frontend/src/scripts/theme-editor.ts |  3 +-
 packages/frontend/src/scripts/use-form.ts     |  3 +-
 .../frontend/src/scripts/use-leave-guard.ts   |  2 +-
 .../frontend/src/scripts/use-note-capture.ts  |  3 +-
 packages/frontend/src/scripts/use-tooltip.ts  |  3 +-
 packages/frontend/src/store.ts                |  3 +-
 packages/frontend/src/theme-store.ts          |  3 +-
 packages/frontend/src/types/menu.ts           |  2 +-
 packages/frontend/src/ui/classic.vue          |  3 +-
 .../frontend/src/ui/deck/antenna-column.vue   |  5 +-
 .../frontend/src/ui/deck/channel-column.vue   |  5 +-
 packages/frontend/src/ui/deck/column.vue      |  3 +-
 packages/frontend/src/ui/deck/deck-store.ts   |  2 +-
 .../frontend/src/ui/deck/direct-column.vue    |  2 +-
 packages/frontend/src/ui/deck/list-column.vue |  5 +-
 packages/frontend/src/ui/deck/main-column.vue |  6 +-
 .../frontend/src/ui/deck/mentions-column.vue  |  2 +-
 .../src/ui/deck/notifications-column.vue      |  3 +-
 .../src/ui/deck/role-timeline-column.vue      |  5 +-
 packages/frontend/src/ui/deck/tl-column.vue   |  5 +-
 .../src/ui/deck/tl-note-notification.ts       |  7 +-
 .../frontend/src/ui/deck/widgets-column.vue   |  3 +-
 packages/frontend/src/ui/minimum.vue          |  3 +-
 packages/frontend/src/ui/universal.vue        |  6 +-
 packages/frontend/src/ui/visitor.vue          |  3 +-
 packages/frontend/src/ui/zen.vue              |  3 +-
 .../frontend/src/widgets/WidgetActivity.vue   |  5 +-
 .../frontend/src/widgets/WidgetAichan.vue     |  5 +-
 .../frontend/src/widgets/WidgetAiscript.vue   |  5 +-
 .../src/widgets/WidgetAiscriptApp.vue         | 11 +--
 .../src/widgets/WidgetBirthdayFollowings.vue  |  5 +-
 .../frontend/src/widgets/WidgetButton.vue     |  5 +-
 .../frontend/src/widgets/WidgetCalendar.vue   |  5 +-
 .../frontend/src/widgets/WidgetClicker.vue    |  5 +-
 packages/frontend/src/widgets/WidgetClock.vue |  5 +-
 .../src/widgets/WidgetDigitalClock.vue        |  5 +-
 .../frontend/src/widgets/WidgetFederation.vue |  5 +-
 .../src/widgets/WidgetInstanceCloud.vue       |  5 +-
 .../src/widgets/WidgetInstanceInfo.vue        |  5 +-
 .../frontend/src/widgets/WidgetJobQueue.vue   |  5 +-
 packages/frontend/src/widgets/WidgetMemo.vue  |  5 +-
 .../src/widgets/WidgetNotifications.vue       |  5 +-
 .../src/widgets/WidgetOnlineUsers.vue         |  5 +-
 .../frontend/src/widgets/WidgetPhotos.vue     |  5 +-
 .../frontend/src/widgets/WidgetPostForm.vue   |  5 +-
 .../frontend/src/widgets/WidgetProfile.vue    |  5 +-
 packages/frontend/src/widgets/WidgetRss.vue   |  5 +-
 .../frontend/src/widgets/WidgetRssTicker.vue  |  5 +-
 .../frontend/src/widgets/WidgetSlideshow.vue  |  5 +-
 .../frontend/src/widgets/WidgetTimeline.vue   |  5 +-
 .../frontend/src/widgets/WidgetTrends.vue     |  5 +-
 .../frontend/src/widgets/WidgetUnixClock.vue  |  5 +-
 .../frontend/src/widgets/WidgetUserList.vue   |  5 +-
 packages/frontend/src/widgets/index.ts        |  3 +-
 .../src/widgets/server-metric/index.vue       |  5 +-
 packages/frontend/src/widgets/widget.ts       |  2 +-
 packages/frontend/test/home.test.ts           |  2 +-
 packages/frontend/test/i18n.test.ts           |  2 +-
 packages/frontend/test/note.test.ts           |  2 +-
 packages/frontend/tsconfig.json               |  1 +
 259 files changed, 568 insertions(+), 409 deletions(-)

diff --git a/packages/frontend-embed/eslint.config.js b/packages/frontend-embed/eslint.config.js
index dd8f03dac5..7805256fd4 100644
--- a/packages/frontend-embed/eslint.config.js
+++ b/packages/frontend-embed/eslint.config.js
@@ -47,6 +47,7 @@ export default [
 			'@typescript-eslint/no-empty-interface': ['error', {
 				allowSingleExtends: true,
 			}],
+			'import/consistent-type-specifier-style': ['error', 'prefer-top-level'],
 			// window の禁止理由: グローバルスコープと衝突し、予期せぬ結果を招くため
 			// e の禁止理由: error や event など、複数のキーワードの頭文字であり分かりにくいため
 			'id-denylist': ['error', 'window', 'e'],
diff --git a/packages/frontend-embed/src/components/EmMfm.ts b/packages/frontend-embed/src/components/EmMfm.ts
index e84fd6f679..1f9ce9d4f4 100644
--- a/packages/frontend-embed/src/components/EmMfm.ts
+++ b/packages/frontend-embed/src/components/EmMfm.ts
@@ -3,7 +3,8 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { VNode, h, SetupContext, provide } from 'vue';
+import { h, provide } from 'vue';
+import type { VNode, SetupContext } from 'vue';
 import * as mfm from 'mfm-js';
 import * as Misskey from 'misskey-js';
 import { host } from '@@/js/config.js';
diff --git a/packages/frontend-embed/src/components/EmNotes.vue b/packages/frontend-embed/src/components/EmNotes.vue
index 4e0ae005df..962a982fb7 100644
--- a/packages/frontend-embed/src/components/EmNotes.vue
+++ b/packages/frontend-embed/src/components/EmNotes.vue
@@ -22,7 +22,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { useTemplateRef } from 'vue';
 import EmNote from '@/components/EmNote.vue';
-import EmPagination, { Paging } from '@/components/EmPagination.vue';
+import EmPagination from '@/components/EmPagination.vue';
+import type { Paging } from '@/components/EmPagination.vue';
 import { i18n } from '@/i18n.js';
 import * as Misskey from 'misskey-js';
 
diff --git a/packages/frontend-embed/tsconfig.json b/packages/frontend-embed/tsconfig.json
index 60164a7e3d..63e637c844 100644
--- a/packages/frontend-embed/tsconfig.json
+++ b/packages/frontend-embed/tsconfig.json
@@ -21,6 +21,7 @@
 		"allowSyntheticDefaultImports": true,
 		"isolatedModules": true,
 		"useDefineForClassFields": true,
+		"verbatimModuleSyntax": true,
 		"baseUrl": ".",
 		"paths": {
 			"@/*": ["./src/*"],
diff --git a/packages/frontend-shared/eslint.config.js b/packages/frontend-shared/eslint.config.js
index cd4641a270..a3ab438336 100644
--- a/packages/frontend-shared/eslint.config.js
+++ b/packages/frontend-shared/eslint.config.js
@@ -52,6 +52,7 @@ export default [
 			'@typescript-eslint/no-empty-interface': ['error', {
 				allowSingleExtends: true,
 			}],
+			'import/consistent-type-specifier-style': ['error', 'prefer-top-level'],
 			// window の禁止理由: グローバルスコープと衝突し、予期せぬ結果を招くため
 			// e の禁止理由: error や event など、複数のキーワードの頭文字であり分かりにくいため
 			'id-denylist': ['error', 'window', 'e'],
diff --git a/packages/frontend-shared/tsconfig.json b/packages/frontend-shared/tsconfig.json
index 09a8ff76aa..12f00eb503 100644
--- a/packages/frontend-shared/tsconfig.json
+++ b/packages/frontend-shared/tsconfig.json
@@ -16,6 +16,7 @@
 		"experimentalDecorators": true,
 		"noImplicitReturns": true,
 		"esModuleInterop": true,
+		"verbatimModuleSyntax": true,
 		"baseUrl": ".",
 		"paths": {
 			"@/*": ["./*"],
diff --git a/packages/frontend/.storybook/charts.ts b/packages/frontend/.storybook/charts.ts
index 5015012a82..31bb9e51c5 100644
--- a/packages/frontend/.storybook/charts.ts
+++ b/packages/frontend/.storybook/charts.ts
@@ -3,7 +3,8 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { DefaultBodyType, HttpResponse, HttpResponseResolver, JsonBodyType, PathParams, http } from 'msw';
+import { HttpResponse, http } from 'msw';
+import type { DefaultBodyType, HttpResponseResolver, JsonBodyType, PathParams } from 'msw';
 import seedrandom from 'seedrandom';
 import { action } from '@storybook/addon-actions';
 
diff --git a/packages/frontend/eslint.config.js b/packages/frontend/eslint.config.js
index dd8f03dac5..7805256fd4 100644
--- a/packages/frontend/eslint.config.js
+++ b/packages/frontend/eslint.config.js
@@ -47,6 +47,7 @@ export default [
 			'@typescript-eslint/no-empty-interface': ['error', {
 				allowSingleExtends: true,
 			}],
+			'import/consistent-type-specifier-style': ['error', 'prefer-top-level'],
 			// window の禁止理由: グローバルスコープと衝突し、予期せぬ結果を招くため
 			// e の禁止理由: error や event など、複数のキーワードの頭文字であり分かりにくいため
 			'id-denylist': ['error', 'window', 'e'],
diff --git a/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.ts b/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.ts
index 0ed2e14d2a..7ecb1e9179 100644
--- a/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.ts
+++ b/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.ts
@@ -4,8 +4,8 @@
  */
 
 import { generate } from 'astring';
-import * as estree from 'estree';
 import { walk } from '../node_modules/estree-walker/src/index.js';
+import type * as estree from 'estree';
 import type * as estreeWalker from 'estree-walker';
 import type { Plugin } from 'vite';
 
diff --git a/packages/frontend/src/boot/common.ts b/packages/frontend/src/boot/common.ts
index ae6b1aee26..1d8e40a12d 100644
--- a/packages/frontend/src/boot/common.ts
+++ b/packages/frontend/src/boot/common.ts
@@ -3,7 +3,8 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { computed, watch, version as vueVersion, App } from 'vue';
+import { computed, watch, version as vueVersion } from 'vue';
+import type { App } from 'vue';
 import { compareVersions } from 'compare-versions';
 import { version, lang, updateLocale, locale } from '@@/js/config.js';
 import widgets from '@/widgets/index.js';
diff --git a/packages/frontend/src/boot/main-boot.ts b/packages/frontend/src/boot/main-boot.ts
index 874e97f3a4..3a43c6794b 100644
--- a/packages/frontend/src/boot/main-boot.ts
+++ b/packages/frontend/src/boot/main-boot.ts
@@ -6,7 +6,7 @@
 import { createApp, defineAsyncComponent, markRaw } from 'vue';
 import { ui } from '@@/js/config.js';
 import { common } from './common.js';
-import type * as Misskey from 'misskey-js';
+import * as Misskey from 'misskey-js';
 import type { Component } from 'vue';
 import { i18n } from '@/i18n.js';
 import { alert, confirm, popup, post, toast } from '@/os.js';
@@ -22,7 +22,8 @@ import { initializeSw } from '@/scripts/initialize-sw.js';
 import { deckStore } from '@/ui/deck/deck-store.js';
 import { emojiPicker } from '@/scripts/emoji-picker.js';
 import { mainRouter } from '@/router/main.js';
-import { type Keymap, makeHotkey } from '@/scripts/hotkey.js';
+import { makeHotkey } from '@/scripts/hotkey.js';
+import type { Keymap } from '@/scripts/hotkey.js';
 import { addCustomEmoji, removeCustomEmojis, updateCustomEmojis } from '@/custom-emojis.js';
 
 export async function mainBoot() {
diff --git a/packages/frontend/src/components/MkAbuseReportWindow.stories.impl.ts b/packages/frontend/src/components/MkAbuseReportWindow.stories.impl.ts
index 9df957f3ec..b62096bbe9 100644
--- a/packages/frontend/src/components/MkAbuseReportWindow.stories.impl.ts
+++ b/packages/frontend/src/components/MkAbuseReportWindow.stories.impl.ts
@@ -5,7 +5,7 @@
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 import { action } from '@storybook/addon-actions';
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { HttpResponse, http } from 'msw';
 import { userDetailed } from '../../.storybook/fakes.js';
 import { commonHandlers } from '../../.storybook/mocks.js';
diff --git a/packages/frontend/src/components/MkAccountMoved.stories.impl.ts b/packages/frontend/src/components/MkAccountMoved.stories.impl.ts
index cad26de6e2..b907b5b25a 100644
--- a/packages/frontend/src/components/MkAccountMoved.stories.impl.ts
+++ b/packages/frontend/src/components/MkAccountMoved.stories.impl.ts
@@ -5,7 +5,7 @@
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 import { action } from '@storybook/addon-actions';
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { HttpResponse, http } from 'msw';
 import { commonHandlers } from '../../.storybook/mocks.js';
 import { userDetailed } from '../../.storybook/fakes.js';
diff --git a/packages/frontend/src/components/MkAchievements.stories.impl.ts b/packages/frontend/src/components/MkAchievements.stories.impl.ts
index 7614da51da..bbd3f69d7c 100644
--- a/packages/frontend/src/components/MkAchievements.stories.impl.ts
+++ b/packages/frontend/src/components/MkAchievements.stories.impl.ts
@@ -4,7 +4,7 @@
  */
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { HttpResponse, http } from 'msw';
 import { userDetailed } from '../../.storybook/fakes.js';
 import { commonHandlers } from '../../.storybook/mocks.js';
diff --git a/packages/frontend/src/components/MkAnalogClock.stories.impl.ts b/packages/frontend/src/components/MkAnalogClock.stories.impl.ts
index 270ca40825..a01d91ad20 100644
--- a/packages/frontend/src/components/MkAnalogClock.stories.impl.ts
+++ b/packages/frontend/src/components/MkAnalogClock.stories.impl.ts
@@ -4,7 +4,7 @@
  */
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import isChromatic from 'chromatic/isChromatic';
 import MkAnalogClock from './MkAnalogClock.vue';
 export const Default = {
diff --git a/packages/frontend/src/components/MkAnnouncementDialog.stories.impl.ts b/packages/frontend/src/components/MkAnnouncementDialog.stories.impl.ts
index bf3ddb935b..627cb0c4ff 100644
--- a/packages/frontend/src/components/MkAnnouncementDialog.stories.impl.ts
+++ b/packages/frontend/src/components/MkAnnouncementDialog.stories.impl.ts
@@ -5,7 +5,7 @@
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 import { action } from '@storybook/addon-actions';
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { HttpResponse, http } from 'msw';
 import { commonHandlers } from '../../.storybook/mocks.js';
 import MkAnnouncementDialog from './MkAnnouncementDialog.vue';
diff --git a/packages/frontend/src/components/MkAntennaEditor.stories.impl.ts b/packages/frontend/src/components/MkAntennaEditor.stories.impl.ts
index 1749e07a4e..4d921a4c48 100644
--- a/packages/frontend/src/components/MkAntennaEditor.stories.impl.ts
+++ b/packages/frontend/src/components/MkAntennaEditor.stories.impl.ts
@@ -5,7 +5,7 @@
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 import { action } from '@storybook/addon-actions';
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { HttpResponse, http } from 'msw';
 import { commonHandlers } from '../../.storybook/mocks.js';
 import MkAntennaEditor from './MkAntennaEditor.vue';
diff --git a/packages/frontend/src/components/MkAntennaEditorDialog.stories.impl.ts b/packages/frontend/src/components/MkAntennaEditorDialog.stories.impl.ts
index 1c6ca83b47..5878b52fb9 100644
--- a/packages/frontend/src/components/MkAntennaEditorDialog.stories.impl.ts
+++ b/packages/frontend/src/components/MkAntennaEditorDialog.stories.impl.ts
@@ -5,7 +5,7 @@
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 import { action } from '@storybook/addon-actions';
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { HttpResponse, http } from 'msw';
 import { commonHandlers } from '../../.storybook/mocks.js';
 import MkAntennaEditorDialog from './MkAntennaEditorDialog.vue';
diff --git a/packages/frontend/src/components/MkAsUi.vue b/packages/frontend/src/components/MkAsUi.vue
index 365b767bd6..5c4d887e0c 100644
--- a/packages/frontend/src/components/MkAsUi.vue
+++ b/packages/frontend/src/components/MkAsUi.vue
@@ -63,14 +63,15 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
-import { Ref, ref, computed } from 'vue';
+import { ref, computed } from 'vue';
+import type { Ref } from 'vue';
 import * as os from '@/os.js';
 import MkButton from '@/components/MkButton.vue';
 import MkInput from '@/components/MkInput.vue';
 import MkSwitch from '@/components/MkSwitch.vue';
 import MkTextarea from '@/components/MkTextarea.vue';
 import MkSelect from '@/components/MkSelect.vue';
-import { AsUiComponent, AsUiRoot, AsUiPostFormButton } from '@/scripts/aiscript/ui.js';
+import type { AsUiComponent, AsUiRoot, AsUiPostFormButton } from '@/scripts/aiscript/ui.js';
 import MkFolder from '@/components/MkFolder.vue';
 import MkPostForm from '@/components/MkPostForm.vue';
 
diff --git a/packages/frontend/src/components/MkAutocomplete.stories.impl.ts b/packages/frontend/src/components/MkAutocomplete.stories.impl.ts
index ec24b8c240..af5dd4784d 100644
--- a/packages/frontend/src/components/MkAutocomplete.stories.impl.ts
+++ b/packages/frontend/src/components/MkAutocomplete.stories.impl.ts
@@ -6,7 +6,7 @@
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 import { action } from '@storybook/addon-actions';
 import { expect, userEvent, waitFor, within } from '@storybook/test';
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { HttpResponse, http } from 'msw';
 import { userDetailed } from '../../.storybook/fakes.js';
 import { commonHandlers } from '../../.storybook/mocks.js';
diff --git a/packages/frontend/src/components/MkAutocomplete.vue b/packages/frontend/src/components/MkAutocomplete.vue
index 0ea4566d4e..e7372da6f8 100644
--- a/packages/frontend/src/components/MkAutocomplete.vue
+++ b/packages/frontend/src/components/MkAutocomplete.vue
@@ -57,7 +57,8 @@ import { i18n } from '@/i18n.js';
 import { miLocalStorage } from '@/local-storage.js';
 import { customEmojis } from '@/custom-emojis.js';
 import { MFM_TAGS, MFM_PARAMS } from '@@/js/const.js';
-import { searchEmoji, EmojiDef } from '@/scripts/search-emoji.js';
+import { searchEmoji } from '@/scripts/search-emoji.js';
+import type { EmojiDef } from '@/scripts/search-emoji.js';
 
 const lib = emojilist.filter(x => x.category !== 'flags');
 
diff --git a/packages/frontend/src/components/MkAvatars.stories.impl.ts b/packages/frontend/src/components/MkAvatars.stories.impl.ts
index d2a4a9f03b..6e20294438 100644
--- a/packages/frontend/src/components/MkAvatars.stories.impl.ts
+++ b/packages/frontend/src/components/MkAvatars.stories.impl.ts
@@ -4,7 +4,7 @@
  */
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { HttpResponse, http } from 'msw';
 import { userDetailed } from '../../.storybook/fakes.js';
 import { commonHandlers } from '../../.storybook/mocks.js';
diff --git a/packages/frontend/src/components/MkButton.stories.impl.ts b/packages/frontend/src/components/MkButton.stories.impl.ts
index e8802e4f8f..0a569b3beb 100644
--- a/packages/frontend/src/components/MkButton.stories.impl.ts
+++ b/packages/frontend/src/components/MkButton.stories.impl.ts
@@ -6,7 +6,7 @@
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 /* eslint-disable import/no-default-export */
 import { action } from '@storybook/addon-actions';
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import MkButton from './MkButton.vue';
 export const Default = {
 	render(args) {
diff --git a/packages/frontend/src/components/MkChannelFollowButton.stories.impl.ts b/packages/frontend/src/components/MkChannelFollowButton.stories.impl.ts
index b9770670dc..a42e80c27a 100644
--- a/packages/frontend/src/components/MkChannelFollowButton.stories.impl.ts
+++ b/packages/frontend/src/components/MkChannelFollowButton.stories.impl.ts
@@ -5,7 +5,7 @@
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 /* eslint-disable import/no-default-export */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { HttpResponse, http } from 'msw';
 import { action } from '@storybook/addon-actions';
 import { expect, userEvent, within } from '@storybook/test';
diff --git a/packages/frontend/src/components/MkChannelList.stories.impl.ts b/packages/frontend/src/components/MkChannelList.stories.impl.ts
index f69b20c049..47ca864dc0 100644
--- a/packages/frontend/src/components/MkChannelList.stories.impl.ts
+++ b/packages/frontend/src/components/MkChannelList.stories.impl.ts
@@ -5,7 +5,7 @@
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 /* eslint-disable import/no-default-export */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { HttpResponse, http } from 'msw';
 import { action } from '@storybook/addon-actions';
 import { channel } from '../../.storybook/fakes.js';
diff --git a/packages/frontend/src/components/MkChannelList.vue b/packages/frontend/src/components/MkChannelList.vue
index 2850ecca16..23705f6ff8 100644
--- a/packages/frontend/src/components/MkChannelList.vue
+++ b/packages/frontend/src/components/MkChannelList.vue
@@ -20,7 +20,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import MkChannelPreview from '@/components/MkChannelPreview.vue';
-import MkPagination, { Paging } from '@/components/MkPagination.vue';
+import MkPagination from '@/components/MkPagination.vue';
+import type { Paging } from '@/components/MkPagination.vue';
 import { i18n } from '@/i18n.js';
 import { infoImageUrl } from '@/instance.js';
 
diff --git a/packages/frontend/src/components/MkChannelPreview.stories.impl.ts b/packages/frontend/src/components/MkChannelPreview.stories.impl.ts
index de0193c78f..dbee069771 100644
--- a/packages/frontend/src/components/MkChannelPreview.stories.impl.ts
+++ b/packages/frontend/src/components/MkChannelPreview.stories.impl.ts
@@ -5,7 +5,7 @@
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 /* eslint-disable import/no-default-export */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { channel } from '../../.storybook/fakes.js';
 import MkChannelPreview from './MkChannelPreview.vue';
 export const Default = {
diff --git a/packages/frontend/src/components/MkChart.stories.impl.ts b/packages/frontend/src/components/MkChart.stories.impl.ts
index 1bcb9c30d8..3caf01d34e 100644
--- a/packages/frontend/src/components/MkChart.stories.impl.ts
+++ b/packages/frontend/src/components/MkChart.stories.impl.ts
@@ -5,7 +5,7 @@
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 /* eslint-disable import/no-default-export */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { http } from 'msw';
 import { commonHandlers } from '../../.storybook/mocks.js';
 import { getChartResolver } from '../../.storybook/charts.js';
diff --git a/packages/frontend/src/components/MkChartLegend.vue b/packages/frontend/src/components/MkChartLegend.vue
index 574cde9da4..06607bc04c 100644
--- a/packages/frontend/src/components/MkChartLegend.vue
+++ b/packages/frontend/src/components/MkChartLegend.vue
@@ -14,7 +14,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import { shallowRef } from 'vue';
-import { Chart, LegendItem } from 'chart.js';
+import { Chart } from 'chart.js';
+import type { LegendItem } from 'chart.js';
 
 const chart = shallowRef<Chart>();
 const type = shallowRef<string>();
diff --git a/packages/frontend/src/components/MkClickerGame.stories.impl.ts b/packages/frontend/src/components/MkClickerGame.stories.impl.ts
index 36313f965d..eb7e61f294 100644
--- a/packages/frontend/src/components/MkClickerGame.stories.impl.ts
+++ b/packages/frontend/src/components/MkClickerGame.stories.impl.ts
@@ -5,7 +5,7 @@
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 /* eslint-disable import/no-default-export */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { HttpResponse, http } from 'msw';
 import { action } from '@storybook/addon-actions';
 import { expect, userEvent, within } from '@storybook/test';
diff --git a/packages/frontend/src/components/MkClipPreview.stories.impl.ts b/packages/frontend/src/components/MkClipPreview.stories.impl.ts
index 62503fb98a..496dc09eed 100644
--- a/packages/frontend/src/components/MkClipPreview.stories.impl.ts
+++ b/packages/frontend/src/components/MkClipPreview.stories.impl.ts
@@ -5,7 +5,7 @@
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 /* eslint-disable import/no-default-export */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { clip } from '../../.storybook/fakes.js';
 import MkClipPreview from './MkClipPreview.vue';
 export const Default = {
diff --git a/packages/frontend/src/components/MkCode.stories.impl.ts b/packages/frontend/src/components/MkCode.stories.impl.ts
index b7e53e8e35..fae9d459fb 100644
--- a/packages/frontend/src/components/MkCode.stories.impl.ts
+++ b/packages/frontend/src/components/MkCode.stories.impl.ts
@@ -5,7 +5,7 @@
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 /* eslint-disable import/no-default-export */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import MkCode from './MkCode.vue';
 const code = `for (let i, 100) {
 	<: if (i % 15 == 0) "FizzBuzz"
diff --git a/packages/frontend/src/components/MkCodeEditor.stories.impl.ts b/packages/frontend/src/components/MkCodeEditor.stories.impl.ts
index 5c410c4886..c76b6fd08e 100644
--- a/packages/frontend/src/components/MkCodeEditor.stories.impl.ts
+++ b/packages/frontend/src/components/MkCodeEditor.stories.impl.ts
@@ -5,7 +5,7 @@
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 /* eslint-disable import/no-default-export */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { action } from '@storybook/addon-actions';
 import MkCodeEditor from './MkCodeEditor.vue';
 const code = `for (let i, 100) {
diff --git a/packages/frontend/src/components/MkCodeInline.stories.impl.ts b/packages/frontend/src/components/MkCodeInline.stories.impl.ts
index 51d4d106ff..c17be177cb 100644
--- a/packages/frontend/src/components/MkCodeInline.stories.impl.ts
+++ b/packages/frontend/src/components/MkCodeInline.stories.impl.ts
@@ -5,7 +5,7 @@
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 /* eslint-disable import/no-default-export */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import MkCodeInline from './MkCodeInline.vue';
 export const Default = {
 	render(args) {
diff --git a/packages/frontend/src/components/MkColorInput.stories.impl.ts b/packages/frontend/src/components/MkColorInput.stories.impl.ts
index 61383e2cae..3df92ca858 100644
--- a/packages/frontend/src/components/MkColorInput.stories.impl.ts
+++ b/packages/frontend/src/components/MkColorInput.stories.impl.ts
@@ -5,7 +5,7 @@
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 /* eslint-disable import/no-default-export */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { action } from '@storybook/addon-actions';
 import MkColorInput from './MkColorInput.vue';
 export const Default = {
diff --git a/packages/frontend/src/components/MkContextMenu.stories.impl.ts b/packages/frontend/src/components/MkContextMenu.stories.impl.ts
index 1ff0f51bd4..7a5e36131b 100644
--- a/packages/frontend/src/components/MkContextMenu.stories.impl.ts
+++ b/packages/frontend/src/components/MkContextMenu.stories.impl.ts
@@ -5,7 +5,7 @@
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 /* eslint-disable import/no-default-export */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { userEvent, within } from '@storybook/test';
 import MkContextMenu from './MkContextMenu.vue';
 import * as os from '@/os.js';
diff --git a/packages/frontend/src/components/MkCropperDialog.stories.impl.ts b/packages/frontend/src/components/MkCropperDialog.stories.impl.ts
index ce13093975..27ce60415b 100644
--- a/packages/frontend/src/components/MkCropperDialog.stories.impl.ts
+++ b/packages/frontend/src/components/MkCropperDialog.stories.impl.ts
@@ -5,7 +5,7 @@
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 /* eslint-disable import/no-default-export */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { HttpResponse, http } from 'msw';
 import { action } from '@storybook/addon-actions';
 import { file } from '../../.storybook/fakes.js';
diff --git a/packages/frontend/src/components/MkCustomEmojiDetailedDialog.stories.impl.ts b/packages/frontend/src/components/MkCustomEmojiDetailedDialog.stories.impl.ts
index 8a05e06311..3da27dcedb 100644
--- a/packages/frontend/src/components/MkCustomEmojiDetailedDialog.stories.impl.ts
+++ b/packages/frontend/src/components/MkCustomEmojiDetailedDialog.stories.impl.ts
@@ -5,7 +5,7 @@
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 /* eslint-disable import/no-default-export */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { emojiDetailed } from '../../.storybook/fakes.js';
 import MkCustomEmojiDetailedDialog from './MkCustomEmojiDetailedDialog.vue';
 export const Default = {
diff --git a/packages/frontend/src/components/MkCwButton.stories.impl.ts b/packages/frontend/src/components/MkCwButton.stories.impl.ts
index 5d6ea56da9..bbe5f4eddb 100644
--- a/packages/frontend/src/components/MkCwButton.stories.impl.ts
+++ b/packages/frontend/src/components/MkCwButton.stories.impl.ts
@@ -5,7 +5,7 @@
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 /* eslint-disable import/no-default-export */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { action } from '@storybook/addon-actions';
 import { expect, userEvent, within } from '@storybook/test';
 import { file } from '../../.storybook/fakes.js';
diff --git a/packages/frontend/src/components/MkDateSeparatedList.vue b/packages/frontend/src/components/MkDateSeparatedList.vue
index 9c75f91cb2..0d5a16126b 100644
--- a/packages/frontend/src/components/MkDateSeparatedList.vue
+++ b/packages/frontend/src/components/MkDateSeparatedList.vue
@@ -4,14 +4,15 @@ SPDX-License-Identifier: AGPL-3.0-only
 -->
 
 <script lang="ts">
-import { defineComponent, h, PropType, TransitionGroup, useCssModule } from 'vue';
+import { defineComponent, h, TransitionGroup, useCssModule } from 'vue';
+import type { PropType } from 'vue';
 import MkAd from '@/components/global/MkAd.vue';
 import { isDebuggerEnabled, stackTraceInstances } from '@/debug.js';
 import { i18n } from '@/i18n.js';
 import * as os from '@/os.js';
 import { instance } from '@/instance.js';
 import { defaultStore } from '@/store.js';
-import { MisskeyEntity } from '@/types/date-separated-list.js';
+import type { MisskeyEntity } from '@/types/date-separated-list.js';
 
 export default defineComponent({
 	props: {
diff --git a/packages/frontend/src/components/MkDialog.stories.impl.ts b/packages/frontend/src/components/MkDialog.stories.impl.ts
index 2d8d3661f2..57c7916049 100644
--- a/packages/frontend/src/components/MkDialog.stories.impl.ts
+++ b/packages/frontend/src/components/MkDialog.stories.impl.ts
@@ -5,7 +5,7 @@
 
 import { action } from '@storybook/addon-actions';
 import { expect, userEvent, waitFor, within } from '@storybook/test';
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { i18n } from '@/i18n.js';
 import MkDialog from './MkDialog.vue';
 const Base = {
diff --git a/packages/frontend/src/components/MkDigitalClock.stories.impl.ts b/packages/frontend/src/components/MkDigitalClock.stories.impl.ts
index e3391bcf7e..af58f5c375 100644
--- a/packages/frontend/src/components/MkDigitalClock.stories.impl.ts
+++ b/packages/frontend/src/components/MkDigitalClock.stories.impl.ts
@@ -4,7 +4,7 @@
  */
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import isChromatic from 'chromatic/isChromatic';
 import MkDigitalClock from './MkDigitalClock.vue';
 export const Default = {
diff --git a/packages/frontend/src/components/MkDonation.stories.impl.ts b/packages/frontend/src/components/MkDonation.stories.impl.ts
index 27d6b7df6c..71d0c20c63 100644
--- a/packages/frontend/src/components/MkDonation.stories.impl.ts
+++ b/packages/frontend/src/components/MkDonation.stories.impl.ts
@@ -4,7 +4,7 @@
  */
 
 import { action } from '@storybook/addon-actions';
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { onBeforeUnmount } from 'vue';
 import MkDonation from './MkDonation.vue';
 import { instance } from '@/instance.js';
diff --git a/packages/frontend/src/components/MkDrive.file.stories.impl.ts b/packages/frontend/src/components/MkDrive.file.stories.impl.ts
index 5f6e6a0667..933383775c 100644
--- a/packages/frontend/src/components/MkDrive.file.stories.impl.ts
+++ b/packages/frontend/src/components/MkDrive.file.stories.impl.ts
@@ -4,7 +4,7 @@
  */
 
 import { action } from '@storybook/addon-actions';
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import MkDrive_file from './MkDrive.file.vue';
 import { file } from '../../.storybook/fakes.js';
 export const Default = {
diff --git a/packages/frontend/src/components/MkDrive.folder.stories.impl.ts b/packages/frontend/src/components/MkDrive.folder.stories.impl.ts
index 5f8ef48520..e6c7c2f645 100644
--- a/packages/frontend/src/components/MkDrive.folder.stories.impl.ts
+++ b/packages/frontend/src/components/MkDrive.folder.stories.impl.ts
@@ -4,7 +4,7 @@
  */
 
 import { action } from '@storybook/addon-actions';
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { http, HttpResponse } from 'msw';
 import * as Misskey from 'misskey-js';
 import MkDrive_folder from './MkDrive.folder.vue';
diff --git a/packages/frontend/src/components/MkDrive.stories.impl.ts b/packages/frontend/src/components/MkDrive.stories.impl.ts
index fe20e61415..4394eebfda 100644
--- a/packages/frontend/src/components/MkDrive.stories.impl.ts
+++ b/packages/frontend/src/components/MkDrive.stories.impl.ts
@@ -4,7 +4,7 @@
  */
 
 import { action } from '@storybook/addon-actions';
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { http, HttpResponse } from 'msw';
 import * as Misskey from 'misskey-js';
 import MkDrive from './MkDrive.vue';
diff --git a/packages/frontend/src/components/MkDriveFileThumbnail.stories.impl.ts b/packages/frontend/src/components/MkDriveFileThumbnail.stories.impl.ts
index 3fa24d7edb..d259444e94 100644
--- a/packages/frontend/src/components/MkDriveFileThumbnail.stories.impl.ts
+++ b/packages/frontend/src/components/MkDriveFileThumbnail.stories.impl.ts
@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import MkDriveFileThumbnail from './MkDriveFileThumbnail.vue';
 import { file } from '../../.storybook/fakes.js';
 export const Default = {
diff --git a/packages/frontend/src/components/MkEmojiPicker.section.vue b/packages/frontend/src/components/MkEmojiPicker.section.vue
index b418ed3ae6..ef515e471f 100644
--- a/packages/frontend/src/components/MkEmojiPicker.section.vue
+++ b/packages/frontend/src/components/MkEmojiPicker.section.vue
@@ -61,8 +61,10 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
-import { ref, computed, Ref } from 'vue';
-import { CustomEmojiFolderTree, getEmojiName } from '@@/js/emojilist.js';
+import { ref, computed } from 'vue';
+import type { Ref } from 'vue';
+import { getEmojiName } from '@@/js/emojilist.js';
+import type { CustomEmojiFolderTree } from '@@/js/emojilist.js';
 import { i18n } from '@/i18n.js';
 import { customEmojis } from '@/custom-emojis.js';
 import MkEmojiPickerSection from '@/components/MkEmojiPicker.section.vue';
diff --git a/packages/frontend/src/components/MkEmojiPicker.stories.impl.ts b/packages/frontend/src/components/MkEmojiPicker.stories.impl.ts
index d38d8de808..bf4158a2c8 100644
--- a/packages/frontend/src/components/MkEmojiPicker.stories.impl.ts
+++ b/packages/frontend/src/components/MkEmojiPicker.stories.impl.ts
@@ -5,7 +5,7 @@
 
 import { action } from '@storybook/addon-actions';
 import { expect, userEvent, waitFor, within } from '@storybook/test';
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { i18n } from '@/i18n.js';
 import MkEmojiPicker from './MkEmojiPicker.vue';
 export const Default = {
diff --git a/packages/frontend/src/components/MkEmojiPicker.vue b/packages/frontend/src/components/MkEmojiPicker.vue
index 8187d991e7..7ee0d6a6ac 100644
--- a/packages/frontend/src/components/MkEmojiPicker.vue
+++ b/packages/frontend/src/components/MkEmojiPicker.vue
@@ -120,12 +120,14 @@ import * as Misskey from 'misskey-js';
 import {
 	emojilist,
 	emojiCharByCategory,
-	UnicodeEmojiDef,
 	unicodeEmojiCategories as categories,
 	getEmojiName,
-	CustomEmojiFolderTree,
 	getUnicodeEmoji,
 } from '@@/js/emojilist.js';
+import type {
+	UnicodeEmojiDef,
+	CustomEmojiFolderTree,
+} from '@@/js/emojilist.js';
 import XSection from '@/components/MkEmojiPicker.section.vue';
 import MkRippleEffect from '@/components/MkRippleEffect.vue';
 import * as os from '@/os.js';
diff --git a/packages/frontend/src/components/MkExtensionInstaller.stories.impl.ts b/packages/frontend/src/components/MkExtensionInstaller.stories.impl.ts
index 6763f7c546..f531762710 100644
--- a/packages/frontend/src/components/MkExtensionInstaller.stories.impl.ts
+++ b/packages/frontend/src/components/MkExtensionInstaller.stories.impl.ts
@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import MkExtensionInstaller from './MkExtensionInstaller.vue';
 import lightTheme from '@@/themes/_light.json5';
 
diff --git a/packages/frontend/src/components/MkFlashPreview.stories.impl.ts b/packages/frontend/src/components/MkFlashPreview.stories.impl.ts
index fa5288b73d..4a751062c9 100644
--- a/packages/frontend/src/components/MkFlashPreview.stories.impl.ts
+++ b/packages/frontend/src/components/MkFlashPreview.stories.impl.ts
@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import MkFlashPreview from './MkFlashPreview.vue';
 import { flash } from './../../.storybook/fakes.js';
 export const Public = {
diff --git a/packages/frontend/src/components/MkGalleryPostPreview.stories.impl.ts b/packages/frontend/src/components/MkGalleryPostPreview.stories.impl.ts
index a433ad680b..616e04aabb 100644
--- a/packages/frontend/src/components/MkGalleryPostPreview.stories.impl.ts
+++ b/packages/frontend/src/components/MkGalleryPostPreview.stories.impl.ts
@@ -5,7 +5,7 @@
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 import { expect, userEvent, waitFor, within } from '@storybook/test';
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { galleryPost } from '../../.storybook/fakes.js';
 import MkGalleryPostPreview from './MkGalleryPostPreview.vue';
 export const Default = {
diff --git a/packages/frontend/src/components/MkInput.vue b/packages/frontend/src/components/MkInput.vue
index 08817fd6a8..739061bce1 100644
--- a/packages/frontend/src/components/MkInput.vue
+++ b/packages/frontend/src/components/MkInput.vue
@@ -44,12 +44,14 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
-import { onMounted, onUnmounted, nextTick, ref, shallowRef, watch, computed, toRefs, InputHTMLAttributes } from 'vue';
+import { onMounted, onUnmounted, nextTick, ref, shallowRef, watch, computed, toRefs } from 'vue';
+import type { InputHTMLAttributes } from 'vue';
 import { debounce } from 'throttle-debounce';
 import MkButton from '@/components/MkButton.vue';
 import { useInterval } from '@@/js/use-interval.js';
 import { i18n } from '@/i18n.js';
-import { Autocomplete, SuggestionType } from '@/scripts/autocomplete.js';
+import { Autocomplete } from '@/scripts/autocomplete.js';
+import type { SuggestionType } from '@/scripts/autocomplete.js';
 
 const props = defineProps<{
 	modelValue: string | number | null;
diff --git a/packages/frontend/src/components/MkInstanceCardMini.stories.impl.ts b/packages/frontend/src/components/MkInstanceCardMini.stories.impl.ts
index 9e8de9d878..b9d203ee80 100644
--- a/packages/frontend/src/components/MkInstanceCardMini.stories.impl.ts
+++ b/packages/frontend/src/components/MkInstanceCardMini.stories.impl.ts
@@ -4,7 +4,7 @@
  */
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { HttpResponse, http } from 'msw';
 import { federationInstance } from '../../.storybook/fakes.js';
 import { commonHandlers } from '../../.storybook/mocks.js';
diff --git a/packages/frontend/src/components/MkInstanceStats.vue b/packages/frontend/src/components/MkInstanceStats.vue
index d8066857fe..c2860ed89b 100644
--- a/packages/frontend/src/components/MkInstanceStats.vue
+++ b/packages/frontend/src/components/MkInstanceStats.vue
@@ -94,7 +94,8 @@ import * as os from '@/os.js';
 import { misskeyApiGet } from '@/scripts/misskey-api.js';
 import { instance } from '@/instance.js';
 import { i18n } from '@/i18n.js';
-import MkHeatmap, { type HeatmapSource } from '@/components/MkHeatmap.vue';
+import MkHeatmap from '@/components/MkHeatmap.vue';
+import type { HeatmapSource } from '@/components/MkHeatmap.vue';
 import MkFoldableSection from '@/components/MkFoldableSection.vue';
 import MkRetentionHeatmap from '@/components/MkRetentionHeatmap.vue';
 import MkRetentionLineChart from '@/components/MkRetentionLineChart.vue';
diff --git a/packages/frontend/src/components/MkInstanceTicker.vue b/packages/frontend/src/components/MkInstanceTicker.vue
index 70c33a692d..1da3f14ad4 100644
--- a/packages/frontend/src/components/MkInstanceTicker.vue
+++ b/packages/frontend/src/components/MkInstanceTicker.vue
@@ -11,7 +11,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
-import { computed, type CSSProperties } from 'vue';
+import { computed } from 'vue';
+import type { CSSProperties } from 'vue';
 import { instanceName as localInstanceName } from '@@/js/config.js';
 import { instance as localInstance } from '@/instance.js';
 import { getProxiedImageUrlNullable } from '@/scripts/media-proxy.js';
diff --git a/packages/frontend/src/components/MkInviteCode.stories.impl.ts b/packages/frontend/src/components/MkInviteCode.stories.impl.ts
index 456d215288..ccdebf0a4d 100644
--- a/packages/frontend/src/components/MkInviteCode.stories.impl.ts
+++ b/packages/frontend/src/components/MkInviteCode.stories.impl.ts
@@ -4,7 +4,7 @@
  */
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { HttpResponse, http } from 'msw';
 import { userDetailed, inviteCode } from '../../.storybook/fakes.js';
 import { commonHandlers } from '../../.storybook/mocks.js';
diff --git a/packages/frontend/src/components/MkLink.vue b/packages/frontend/src/components/MkLink.vue
index bda2161eb8..a276bf68b4 100644
--- a/packages/frontend/src/components/MkLink.vue
+++ b/packages/frontend/src/components/MkLink.vue
@@ -20,7 +20,7 @@ import { url as local } from '@@/js/config.js';
 import { useTooltip } from '@/scripts/use-tooltip.js';
 import * as os from '@/os.js';
 import { isEnabledUrlPreview } from '@/instance.js';
-import { MkABehavior } from '@/components/global/MkA.vue';
+import type { MkABehavior } from '@/components/global/MkA.vue';
 
 const props = withDefaults(defineProps<{
 	url: string;
diff --git a/packages/frontend/src/components/MkMediaAudio.vue b/packages/frontend/src/components/MkMediaAudio.vue
index 8b713b2734..e409b7fd57 100644
--- a/packages/frontend/src/components/MkMediaAudio.vue
+++ b/packages/frontend/src/components/MkMediaAudio.vue
@@ -94,7 +94,7 @@ import type { MenuItem } from '@/types/menu.js';
 import { defaultStore } from '@/store.js';
 import { i18n } from '@/i18n.js';
 import * as os from '@/os.js';
-import { type Keymap } from '@/scripts/hotkey.js';
+import type { Keymap } from '@/scripts/hotkey.js';
 import bytes from '@/filters/bytes.js';
 import { hms } from '@/filters/hms.js';
 import MkMediaRange from '@/components/MkMediaRange.vue';
diff --git a/packages/frontend/src/components/MkMediaRange.vue b/packages/frontend/src/components/MkMediaRange.vue
index df7505b0c3..9689dc5cfa 100644
--- a/packages/frontend/src/components/MkMediaRange.vue
+++ b/packages/frontend/src/components/MkMediaRange.vue
@@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script setup lang="ts">
-import { computed, ModelRef } from 'vue';
+import { computed } from 'vue';
 
 withDefaults(defineProps<{
 	buffer?: number;
@@ -28,8 +28,7 @@ const emit = defineEmits<{
 	(ev: 'dragEnded', value: number): void;
 }>();
 
-// eslint-disable-next-line no-undef
-const model = defineModel({ required: true }) as ModelRef<string | number>;
+const model = defineModel<string | number>({ required: true });
 const modelValue = computed({
 	get: () => typeof model.value === 'number' ? model.value : parseFloat(model.value),
 	set: v => { model.value = v; },
diff --git a/packages/frontend/src/components/MkMediaVideo.vue b/packages/frontend/src/components/MkMediaVideo.vue
index 65e4a1eb12..caa93e3f2b 100644
--- a/packages/frontend/src/components/MkMediaVideo.vue
+++ b/packages/frontend/src/components/MkMediaVideo.vue
@@ -112,7 +112,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 import { ref, shallowRef, computed, watch, onDeactivated, onActivated, onMounted } from 'vue';
 import * as Misskey from 'misskey-js';
 import type { MenuItem } from '@/types/menu.js';
-import { type Keymap } from '@/scripts/hotkey.js';
+import type { Keymap } from '@/scripts/hotkey.js';
 import bytes from '@/filters/bytes.js';
 import { hms } from '@/filters/hms.js';
 import { defaultStore } from '@/store.js';
diff --git a/packages/frontend/src/components/MkMention.vue b/packages/frontend/src/components/MkMention.vue
index 5ceeeee255..8616081423 100644
--- a/packages/frontend/src/components/MkMention.vue
+++ b/packages/frontend/src/components/MkMention.vue
@@ -20,7 +20,7 @@ import { host as localHost } from '@@/js/config.js';
 import { $i } from '@/account.js';
 import { defaultStore } from '@/store.js';
 import { getStaticImageUrl } from '@/scripts/media-proxy.js';
-import { MkABehavior } from '@/components/global/MkA.vue';
+import type { MkABehavior } from '@/components/global/MkA.vue';
 
 const props = defineProps<{
 	username: string;
diff --git a/packages/frontend/src/components/MkMenu.vue b/packages/frontend/src/components/MkMenu.vue
index 13a65e411f..d484c1b338 100644
--- a/packages/frontend/src/components/MkMenu.vue
+++ b/packages/frontend/src/components/MkMenu.vue
@@ -178,11 +178,11 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts">
 import { computed, defineAsyncComponent, inject, nextTick, onBeforeUnmount, onMounted, ref, shallowRef, unref, watch } from 'vue';
 import MkSwitchButton from '@/components/MkSwitch.button.vue';
-import { MenuItem, InnerMenuItem, MenuPending, MenuAction, MenuSwitch, MenuRadio, MenuRadioOption, MenuParent } from '@/types/menu.js';
+import type { MenuItem, InnerMenuItem, MenuPending, MenuAction, MenuSwitch, MenuRadio, MenuRadioOption, MenuParent } from '@/types/menu.js';
 import * as os from '@/os.js';
 import { i18n } from '@/i18n.js';
 import { isTouchUsing } from '@/scripts/touch.js';
-import { type Keymap } from '@/scripts/hotkey.js';
+import type { Keymap } from '@/scripts/hotkey.js';
 import { isFocusable } from '@/scripts/focus.js';
 import { getNodeOrNull } from '@/scripts/get-dom-node-or-null.js';
 
diff --git a/packages/frontend/src/components/MkModal.vue b/packages/frontend/src/components/MkModal.vue
index a446dad0ab..19588003fa 100644
--- a/packages/frontend/src/components/MkModal.vue
+++ b/packages/frontend/src/components/MkModal.vue
@@ -47,7 +47,7 @@ import * as os from '@/os.js';
 import { isTouchUsing } from '@/scripts/touch.js';
 import { defaultStore } from '@/store.js';
 import { deviceKind } from '@/scripts/device-kind.js';
-import { type Keymap } from '@/scripts/hotkey.js';
+import type { Keymap } from '@/scripts/hotkey.js';
 import { focusTrap } from '@/scripts/focus-trap.js';
 import { focusParent } from '@/scripts/focus.js';
 
diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue
index a23ff9b48e..919734f763 100644
--- a/packages/frontend/src/components/MkNote.vue
+++ b/packages/frontend/src/components/MkNote.vue
@@ -177,7 +177,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
-import { computed, inject, onMounted, ref, shallowRef, Ref, watch, provide } from 'vue';
+import { computed, inject, onMounted, ref, shallowRef, watch, provide } from 'vue';
+import type { Ref } from 'vue';
 import * as mfm from 'mfm-js';
 import * as Misskey from 'misskey-js';
 import { isLink } from '@@/js/is-link.js';
@@ -195,7 +196,8 @@ import MkPoll from '@/components/MkPoll.vue';
 import MkUsersTooltip from '@/components/MkUsersTooltip.vue';
 import MkUrlPreview from '@/components/MkUrlPreview.vue';
 import MkInstanceTicker from '@/components/MkInstanceTicker.vue';
-import { pleaseLogin, type OpenOnRemoteOptions } from '@/scripts/please-login.js';
+import { pleaseLogin } from '@/scripts/please-login.js';
+import type { OpenOnRemoteOptions } from '@/scripts/please-login.js';
 import { checkWordMute } from '@/scripts/check-word-mute.js';
 import { notePage } from '@/filters/note.js';
 import { userPage } from '@/filters/user.js';
@@ -217,7 +219,7 @@ import { getNoteSummary } from '@/scripts/get-note-summary.js';
 import MkRippleEffect from '@/components/MkRippleEffect.vue';
 import { showMovedDialog } from '@/scripts/show-moved-dialog.js';
 import { isEnabledUrlPreview } from '@/instance.js';
-import { type Keymap } from '@/scripts/hotkey.js';
+import type { Keymap } from '@/scripts/hotkey.js';
 import { focusPrev, focusNext } from '@/scripts/focus.js';
 import { getAppearNote } from '@/scripts/get-appear-note.js';
 
diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue
index 9d3374d433..fa1358da3d 100644
--- a/packages/frontend/src/components/MkNoteDetailed.vue
+++ b/packages/frontend/src/components/MkNoteDetailed.vue
@@ -225,7 +225,8 @@ import MkPoll from '@/components/MkPoll.vue';
 import MkUsersTooltip from '@/components/MkUsersTooltip.vue';
 import MkUrlPreview from '@/components/MkUrlPreview.vue';
 import MkInstanceTicker from '@/components/MkInstanceTicker.vue';
-import { pleaseLogin, type OpenOnRemoteOptions } from '@/scripts/please-login.js';
+import { pleaseLogin } from '@/scripts/please-login.js';
+import type { OpenOnRemoteOptions } from '@/scripts/please-login.js';
 import { checkWordMute } from '@/scripts/check-word-mute.js';
 import { userPage } from '@/filters/user.js';
 import { notePage } from '@/filters/note.js';
@@ -246,12 +247,13 @@ import { claimAchievement } from '@/scripts/achievements.js';
 import MkRippleEffect from '@/components/MkRippleEffect.vue';
 import { showMovedDialog } from '@/scripts/show-moved-dialog.js';
 import MkUserCardMini from '@/components/MkUserCardMini.vue';
-import MkPagination, { type Paging } from '@/components/MkPagination.vue';
+import MkPagination from '@/components/MkPagination.vue';
+import type { Paging } from '@/components/MkPagination.vue';
 import MkReactionIcon from '@/components/MkReactionIcon.vue';
 import MkButton from '@/components/MkButton.vue';
 import { isEnabledUrlPreview } from '@/instance.js';
 import { getAppearNote } from '@/scripts/get-appear-note.js';
-import { type Keymap } from '@/scripts/hotkey.js';
+import type { Keymap } from '@/scripts/hotkey.js';
 
 const props = withDefaults(defineProps<{
 	note: Misskey.entities.Note;
diff --git a/packages/frontend/src/components/MkNoteMediaGrid.vue b/packages/frontend/src/components/MkNoteMediaGrid.vue
index bf105c3c27..e51ea5a2de 100644
--- a/packages/frontend/src/components/MkNoteMediaGrid.vue
+++ b/packages/frontend/src/components/MkNoteMediaGrid.vue
@@ -4,43 +4,43 @@ SPDX-License-Identifier: AGPL-3.0-only
 -->
 
 <template>
-	<template v-for="file in note.files">
-		<div
-			v-if="(((
-					(defaultStore.state.nsfw === 'force' || file.isSensitive) &&
-					defaultStore.state.nsfw !== 'ignore'
-				) || (defaultStore.state.dataSaver.media && file.type.startsWith('image/'))) &&
-				!showingFiles.has(file.id)
-			)"
-			:class="[$style.filePreview, { [$style.square]: square }]"
-			@click="showingFiles.add(file.id)"
-		>
-			<MkDriveFileThumbnail
-				:file="file"
-				fit="cover"
-				:highlightWhenSensitive="defaultStore.state.highlightSensitiveMedia"
-				:forceBlurhash="true"
-				:large="true"
-				:class="$style.file"
-			/>
-			<div :class="$style.sensitive">
-				<div>
-					<div v-if="file.isSensitive"><i class="ti ti-eye-exclamation"></i> {{ i18n.ts.sensitive }}{{ defaultStore.state.dataSaver.media && file.size ? ` (${bytes(file.size)})` : '' }}</div>
-					<div v-else><i class="ti ti-photo"></i> {{ defaultStore.state.dataSaver.media && file.size ? bytes(file.size) : i18n.ts.image }}</div>
-					<div>{{ i18n.ts.clickToShow }}</div>
-				</div>
+<template v-for="file in note.files">
+	<div
+		v-if="(((
+				(defaultStore.state.nsfw === 'force' || file.isSensitive) &&
+				defaultStore.state.nsfw !== 'ignore'
+			) || (defaultStore.state.dataSaver.media && file.type.startsWith('image/'))) &&
+			!showingFiles.has(file.id)
+		)"
+		:class="[$style.filePreview, { [$style.square]: square }]"
+		@click="showingFiles.add(file.id)"
+	>
+		<MkDriveFileThumbnail
+			:file="file"
+			fit="cover"
+			:highlightWhenSensitive="defaultStore.state.highlightSensitiveMedia"
+			:forceBlurhash="true"
+			:large="true"
+			:class="$style.file"
+		/>
+		<div :class="$style.sensitive">
+			<div>
+				<div v-if="file.isSensitive"><i class="ti ti-eye-exclamation"></i> {{ i18n.ts.sensitive }}{{ defaultStore.state.dataSaver.media && file.size ? ` (${bytes(file.size)})` : '' }}</div>
+				<div v-else><i class="ti ti-photo"></i> {{ defaultStore.state.dataSaver.media && file.size ? bytes(file.size) : i18n.ts.image }}</div>
+				<div>{{ i18n.ts.clickToShow }}</div>
 			</div>
 		</div>
-		<MkA v-else :class="[$style.filePreview, { [$style.square]: square }]" :to="notePage(note)">
-			<MkDriveFileThumbnail
-				:file="file"
-				fit="cover"
-				:highlightWhenSensitive="defaultStore.state.highlightSensitiveMedia"
-				:large="true"
-				:class="$style.file"
-			/>
-		</MkA>
-	</template>
+	</div>
+	<MkA v-else :class="[$style.filePreview, { [$style.square]: square }]" :to="notePage(note)">
+		<MkDriveFileThumbnail
+			:file="file"
+			fit="cover"
+			:highlightWhenSensitive="defaultStore.state.highlightSensitiveMedia"
+			:large="true"
+			:class="$style.file"
+		/>
+	</MkA>
+</template>
 </template>
 
 <script lang="ts" setup>
diff --git a/packages/frontend/src/components/MkNotes.vue b/packages/frontend/src/components/MkNotes.vue
index 1c17c6b691..344b7c4dd2 100644
--- a/packages/frontend/src/components/MkNotes.vue
+++ b/packages/frontend/src/components/MkNotes.vue
@@ -35,7 +35,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 import { shallowRef } from 'vue';
 import MkNote from '@/components/MkNote.vue';
 import MkDateSeparatedList from '@/components/MkDateSeparatedList.vue';
-import MkPagination, { Paging } from '@/components/MkPagination.vue';
+import MkPagination from '@/components/MkPagination.vue';
+import type { Paging } from '@/components/MkPagination.vue';
 import { i18n } from '@/i18n.js';
 import { infoImageUrl } from '@/instance.js';
 
diff --git a/packages/frontend/src/components/MkNotificationSelectWindow.vue b/packages/frontend/src/components/MkNotificationSelectWindow.vue
index d07827d11a..90a3e48187 100644
--- a/packages/frontend/src/components/MkNotificationSelectWindow.vue
+++ b/packages/frontend/src/components/MkNotificationSelectWindow.vue
@@ -30,7 +30,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
-import { ref, Ref, shallowRef } from 'vue';
+import { ref, shallowRef } from 'vue';
+import type { Ref } from 'vue';
 import MkSwitch from './MkSwitch.vue';
 import MkInfo from './MkInfo.vue';
 import MkButton from './MkButton.vue';
diff --git a/packages/frontend/src/components/MkNotifications.vue b/packages/frontend/src/components/MkNotifications.vue
index 5a6ada474a..470837ace5 100644
--- a/packages/frontend/src/components/MkNotifications.vue
+++ b/packages/frontend/src/components/MkNotifications.vue
@@ -31,7 +31,7 @@ import MkDateSeparatedList from '@/components/MkDateSeparatedList.vue';
 import MkNote from '@/components/MkNote.vue';
 import { useStream } from '@/stream.js';
 import { i18n } from '@/i18n.js';
-import { notificationTypes } from '@@/js/const.js';
+import type { notificationTypes } from '@@/js/const.js';
 import { infoImageUrl } from '@/instance.js';
 import { defaultStore } from '@/store.js';
 import MkPullToRefresh from '@/components/MkPullToRefresh.vue';
diff --git a/packages/frontend/src/components/MkPageWindow.vue b/packages/frontend/src/components/MkPageWindow.vue
index 9547423227..1420b9c26f 100644
--- a/packages/frontend/src/components/MkPageWindow.vue
+++ b/packages/frontend/src/components/MkPageWindow.vue
@@ -38,7 +38,8 @@ import { popout as _popout } from '@/scripts/popout.js';
 import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
 import { useScrollPositionManager } from '@/nirax.js';
 import { i18n } from '@/i18n.js';
-import { PageMetadata, provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js';
+import { provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js';
+import type { PageMetadata } from '@/scripts/page-metadata.js';
 import { openingWindowsCount } from '@/os.js';
 import { claimAchievement } from '@/scripts/achievements.js';
 import { useRouterFactory } from '@/router/supplier.js';
diff --git a/packages/frontend/src/components/MkPagination.vue b/packages/frontend/src/components/MkPagination.vue
index ea299c319e..d9135ab517 100644
--- a/packages/frontend/src/components/MkPagination.vue
+++ b/packages/frontend/src/components/MkPagination.vue
@@ -43,14 +43,15 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts">
-import { computed, ComputedRef, isRef, nextTick, onActivated, onBeforeMount, onBeforeUnmount, onDeactivated, ref, shallowRef, watch } from 'vue';
+import { computed, isRef, nextTick, onActivated, onBeforeMount, onBeforeUnmount, onDeactivated, ref, shallowRef, watch } from 'vue';
+import type { ComputedRef } from 'vue';
 import * as Misskey from 'misskey-js';
 import { useDocumentVisibility } from '@@/js/use-document-visibility.js';
 import { onScrollTop, isTopVisible, getBodyScrollHeight, getScrollContainer, onScrollBottom, scrollToBottom, scroll, isBottomVisible } from '@@/js/scroll.js';
 import * as os from '@/os.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
 import { defaultStore } from '@/store.js';
-import { MisskeyEntity } from '@/types/date-separated-list.js';
+import type { MisskeyEntity } from '@/types/date-separated-list.js';
 import { i18n } from '@/i18n.js';
 
 const SECOND_FETCH_LIMIT = 30;
diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue
index 5d0716ef37..500f97b2ed 100644
--- a/packages/frontend/src/components/MkPostForm.vue
+++ b/packages/frontend/src/components/MkPostForm.vue
@@ -100,7 +100,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
-import { inject, watch, nextTick, onMounted, defineAsyncComponent, provide, shallowRef, ref, computed, type ShallowRef } from 'vue';
+import { inject, watch, nextTick, onMounted, defineAsyncComponent, provide, shallowRef, ref, computed } from 'vue';
+import type { ShallowRef } from 'vue';
 import * as mfm from 'mfm-js';
 import * as Misskey from 'misskey-js';
 import insertTextAtCursor from 'insert-text-at-cursor';
@@ -110,7 +111,8 @@ import type { PostFormProps } from '@/types/post-form.js';
 import MkNoteSimple from '@/components/MkNoteSimple.vue';
 import MkNotePreview from '@/components/MkNotePreview.vue';
 import XPostFormAttaches from '@/components/MkPostFormAttaches.vue';
-import MkPollEditor, { type PollEditorModelValue } from '@/components/MkPollEditor.vue';
+import MkPollEditor from '@/components/MkPollEditor.vue';
+import type { PollEditorModelValue } from '@/components/MkPollEditor.vue';
 import { erase, unique } from '@/scripts/array.js';
 import { extractMentions } from '@/scripts/extract-mentions.js';
 import { formatTimeString } from '@/scripts/format-time-string.js';
diff --git a/packages/frontend/src/components/MkRadios.vue b/packages/frontend/src/components/MkRadios.vue
index af81eb814d..559399d1d4 100644
--- a/packages/frontend/src/components/MkRadios.vue
+++ b/packages/frontend/src/components/MkRadios.vue
@@ -4,7 +4,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 -->
 
 <script lang="ts">
-import { VNode, defineComponent, h, ref, watch } from 'vue';
+import { defineComponent, h, ref, watch } from 'vue';
+import type { VNode } from 'vue';
 import MkRadio from './MkRadio.vue';
 
 export default defineComponent({
diff --git a/packages/frontend/src/components/MkRoleSelectDialog.stories.impl.ts b/packages/frontend/src/components/MkRoleSelectDialog.stories.impl.ts
index 411d62edf9..b090f0a0fa 100644
--- a/packages/frontend/src/components/MkRoleSelectDialog.stories.impl.ts
+++ b/packages/frontend/src/components/MkRoleSelectDialog.stories.impl.ts
@@ -4,7 +4,7 @@
  */
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { http, HttpResponse } from 'msw';
 import { role } from '../../.storybook/fakes.js';
 import { commonHandlers } from '../../.storybook/mocks.js';
diff --git a/packages/frontend/src/components/MkSelect.vue b/packages/frontend/src/components/MkSelect.vue
index eeadd49936..83a79d0c9f 100644
--- a/packages/frontend/src/components/MkSelect.vue
+++ b/packages/frontend/src/components/MkSelect.vue
@@ -40,7 +40,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
-import { onMounted, nextTick, ref, watch, computed, toRefs, VNode, useSlots, VNodeChild } from 'vue';
+import { onMounted, nextTick, ref, watch, computed, toRefs, useSlots } from 'vue';
+import type { VNode, VNodeChild } from 'vue';
 import { useInterval } from '@@/js/use-interval.js';
 import type { MenuItem } from '@/types/menu.js';
 import * as os from '@/os.js';
diff --git a/packages/frontend/src/components/MkSignin.vue b/packages/frontend/src/components/MkSignin.vue
index 5a27cd6de7..2fb97e8e46 100644
--- a/packages/frontend/src/components/MkSignin.vue
+++ b/packages/frontend/src/components/MkSignin.vue
@@ -77,7 +77,8 @@ import { i18n } from '@/i18n.js';
 import * as os from '@/os.js';
 
 import XInput from '@/components/MkSignin.input.vue';
-import XPassword, { type PwResponse } from '@/components/MkSignin.password.vue';
+import XPassword from '@/components/MkSignin.password.vue';
+import type { PwResponse } from '@/components/MkSignin.password.vue';
 import XTotp from '@/components/MkSignin.totp.vue';
 import XPasskey from '@/components/MkSignin.passkey.vue';
 
diff --git a/packages/frontend/src/components/MkSignupDialog.form.vue b/packages/frontend/src/components/MkSignupDialog.form.vue
index 3a7d896bff..4227e1317a 100644
--- a/packages/frontend/src/components/MkSignupDialog.form.vue
+++ b/packages/frontend/src/components/MkSignupDialog.form.vue
@@ -85,7 +85,8 @@ import * as Misskey from 'misskey-js';
 import * as config from '@@/js/config.js';
 import MkButton from './MkButton.vue';
 import MkInput from './MkInput.vue';
-import MkCaptcha, { type Captcha } from '@/components/MkCaptcha.vue';
+import MkCaptcha from '@/components/MkCaptcha.vue';
+import type { Captcha } from '@/components/MkCaptcha.vue';
 import * as os from '@/os.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
 import { login } from '@/account.js';
diff --git a/packages/frontend/src/components/MkSignupDialog.rules.stories.impl.ts b/packages/frontend/src/components/MkSignupDialog.rules.stories.impl.ts
index 9df3ec0c30..8d99bc44b7 100644
--- a/packages/frontend/src/components/MkSignupDialog.rules.stories.impl.ts
+++ b/packages/frontend/src/components/MkSignupDialog.rules.stories.impl.ts
@@ -5,7 +5,7 @@
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 import { expect, userEvent, waitFor, within } from '@storybook/test';
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { onBeforeUnmount } from 'vue';
 import MkSignupServerRules from './MkSignupDialog.rules.vue';
 import { i18n } from '@/i18n.js';
diff --git a/packages/frontend/src/components/MkSortOrderEditor.vue b/packages/frontend/src/components/MkSortOrderEditor.vue
index 9decacc5f5..27ffc724ae 100644
--- a/packages/frontend/src/components/MkSortOrderEditor.vue
+++ b/packages/frontend/src/components/MkSortOrderEditor.vue
@@ -27,9 +27,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 import { toRefs } from 'vue';
 import MkTagItem from '@/components/MkTagItem.vue';
 import MkButton from '@/components/MkButton.vue';
-import { MenuItem } from '@/types/menu.js';
+import type { MenuItem } from '@/types/menu.js';
 import * as os from '@/os.js';
-import { SortOrder } from '@/components/MkSortOrderEditor.define.js';
+import type { SortOrder } from '@/components/MkSortOrderEditor.define.js';
 
 const emit = defineEmits<{
 	(ev: 'update', sortOrders: SortOrder<T>[]): void;
diff --git a/packages/frontend/src/components/MkSuperMenu.vue b/packages/frontend/src/components/MkSuperMenu.vue
index fa0e40d8f9..397aa68ed6 100644
--- a/packages/frontend/src/components/MkSuperMenu.vue
+++ b/packages/frontend/src/components/MkSuperMenu.vue
@@ -45,7 +45,7 @@ export type SuperMenuDef = {
 		text: string;
 		danger?: boolean;
 		active?: boolean;
-		action: (ev: MouseEvent) => void;
+		action: (ev: MouseEvent) => void | Promise<void>;
 	} | {
 		type?: 'link';
 		to: string;
diff --git a/packages/frontend/src/components/MkSwitch.button.vue b/packages/frontend/src/components/MkSwitch.button.vue
index fd8ed0992e..263b883567 100644
--- a/packages/frontend/src/components/MkSwitch.button.vue
+++ b/packages/frontend/src/components/MkSwitch.button.vue
@@ -19,7 +19,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
-import { toRefs, Ref } from 'vue';
+import { toRefs } from 'vue';
+import type { Ref } from 'vue';
 import { i18n } from '@/i18n.js';
 
 const props = withDefaults(defineProps<{
diff --git a/packages/frontend/src/components/MkSwitch.vue b/packages/frontend/src/components/MkSwitch.vue
index 5e6029ee40..797e577fa4 100644
--- a/packages/frontend/src/components/MkSwitch.vue
+++ b/packages/frontend/src/components/MkSwitch.vue
@@ -27,7 +27,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
-import { toRefs, Ref } from 'vue';
+import { toRefs } from 'vue';
+import type { Ref } from 'vue';
 import XButton from '@/components/MkSwitch.button.vue';
 
 const props = defineProps<{
diff --git a/packages/frontend/src/components/MkSystemWebhookEditor.vue b/packages/frontend/src/components/MkSystemWebhookEditor.vue
index 485d003f93..6a03c8acaa 100644
--- a/packages/frontend/src/components/MkSystemWebhookEditor.vue
+++ b/packages/frontend/src/components/MkSystemWebhookEditor.vue
@@ -96,7 +96,7 @@ import { computed, onMounted, ref, shallowRef, toRefs } from 'vue';
 import * as Misskey from 'misskey-js';
 import MkInput from '@/components/MkInput.vue';
 import MkSwitch from '@/components/MkSwitch.vue';
-import {
+import type {
 	MkSystemWebhookEditorProps,
 	MkSystemWebhookResult,
 	SystemWebhookEventType,
diff --git a/packages/frontend/src/components/MkTagItem.stories.impl.ts b/packages/frontend/src/components/MkTagItem.stories.impl.ts
index 3f243ff651..ac932c8342 100644
--- a/packages/frontend/src/components/MkTagItem.stories.impl.ts
+++ b/packages/frontend/src/components/MkTagItem.stories.impl.ts
@@ -6,7 +6,7 @@
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 /* eslint-disable import/no-default-export */
 import { action } from '@storybook/addon-actions';
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import MkTagItem from './MkTagItem.vue';
 
 export const Default = {
diff --git a/packages/frontend/src/components/MkTextarea.vue b/packages/frontend/src/components/MkTextarea.vue
index d1a6e1ebbf..3e8588018c 100644
--- a/packages/frontend/src/components/MkTextarea.vue
+++ b/packages/frontend/src/components/MkTextarea.vue
@@ -40,7 +40,8 @@ import { onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs, shallow
 import { debounce } from 'throttle-debounce';
 import MkButton from '@/components/MkButton.vue';
 import { i18n } from '@/i18n.js';
-import { Autocomplete, SuggestionType } from '@/scripts/autocomplete.js';
+import { Autocomplete } from '@/scripts/autocomplete.js';
+import type { SuggestionType } from '@/scripts/autocomplete.js';
 
 const props = defineProps<{
 	modelValue: string | null;
diff --git a/packages/frontend/src/components/MkTimeline.vue b/packages/frontend/src/components/MkTimeline.vue
index fb8eb4ae37..d88ff60a51 100644
--- a/packages/frontend/src/components/MkTimeline.vue
+++ b/packages/frontend/src/components/MkTimeline.vue
@@ -27,7 +27,7 @@ import * as sound from '@/scripts/sound.js';
 import { $i } from '@/account.js';
 import { instance } from '@/instance.js';
 import { defaultStore } from '@/store.js';
-import { Paging } from '@/components/MkPagination.vue';
+import type { Paging } from '@/components/MkPagination.vue';
 
 const props = withDefaults(defineProps<{
 	src: BasicTimelineType | 'mentions' | 'directs' | 'list' | 'antenna' | 'channel' | 'role';
diff --git a/packages/frontend/src/components/MkUserList.vue b/packages/frontend/src/components/MkUserList.vue
index 8b4afd7994..d1881ec3fc 100644
--- a/packages/frontend/src/components/MkUserList.vue
+++ b/packages/frontend/src/components/MkUserList.vue
@@ -22,7 +22,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import MkUserInfo from '@/components/MkUserInfo.vue';
-import MkPagination, { Paging } from '@/components/MkPagination.vue';
+import MkPagination from '@/components/MkPagination.vue';
+import type { Paging } from '@/components/MkPagination.vue';
 import { i18n } from '@/i18n.js';
 import { infoImageUrl } from '@/instance.js';
 
diff --git a/packages/frontend/src/components/MkUserSetupDialog.Follow.stories.impl.ts b/packages/frontend/src/components/MkUserSetupDialog.Follow.stories.impl.ts
index 638bfb4372..52467893a0 100644
--- a/packages/frontend/src/components/MkUserSetupDialog.Follow.stories.impl.ts
+++ b/packages/frontend/src/components/MkUserSetupDialog.Follow.stories.impl.ts
@@ -4,7 +4,7 @@
  */
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { HttpResponse, http } from 'msw';
 import { commonHandlers } from '../../.storybook/mocks.js';
 import { userDetailed } from '../../.storybook/fakes.js';
diff --git a/packages/frontend/src/components/MkUserSetupDialog.Follow.vue b/packages/frontend/src/components/MkUserSetupDialog.Follow.vue
index 5153c06139..67a06c70db 100644
--- a/packages/frontend/src/components/MkUserSetupDialog.Follow.vue
+++ b/packages/frontend/src/components/MkUserSetupDialog.Follow.vue
@@ -38,7 +38,8 @@ import * as Misskey from 'misskey-js';
 import { i18n } from '@/i18n.js';
 import MkFolder from '@/components/MkFolder.vue';
 import XUser from '@/components/MkUserSetupDialog.User.vue';
-import MkPagination, { type Paging } from '@/components/MkPagination.vue';
+import MkPagination from '@/components/MkPagination.vue';
+import type { Paging } from '@/components/MkPagination.vue';
 
 const pinnedUsers: Paging = {
 	endpoint: 'pinned-users',
diff --git a/packages/frontend/src/components/MkUserSetupDialog.Privacy.stories.impl.ts b/packages/frontend/src/components/MkUserSetupDialog.Privacy.stories.impl.ts
index 2a7947c6f8..0ada259d3f 100644
--- a/packages/frontend/src/components/MkUserSetupDialog.Privacy.stories.impl.ts
+++ b/packages/frontend/src/components/MkUserSetupDialog.Privacy.stories.impl.ts
@@ -4,7 +4,7 @@
  */
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import MkUserSetupDialog_Privacy from './MkUserSetupDialog.Privacy.vue';
 export const Default = {
 	render(args) {
diff --git a/packages/frontend/src/components/MkUserSetupDialog.Profile.stories.impl.ts b/packages/frontend/src/components/MkUserSetupDialog.Profile.stories.impl.ts
index c6088a5ae3..cefd48cb01 100644
--- a/packages/frontend/src/components/MkUserSetupDialog.Profile.stories.impl.ts
+++ b/packages/frontend/src/components/MkUserSetupDialog.Profile.stories.impl.ts
@@ -4,7 +4,7 @@
  */
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import MkUserSetupDialog_Profile from './MkUserSetupDialog.Profile.vue';
 export const Default = {
 	render(args) {
diff --git a/packages/frontend/src/components/MkUserSetupDialog.User.stories.impl.ts b/packages/frontend/src/components/MkUserSetupDialog.User.stories.impl.ts
index f0206e0cb4..b424632bdc 100644
--- a/packages/frontend/src/components/MkUserSetupDialog.User.stories.impl.ts
+++ b/packages/frontend/src/components/MkUserSetupDialog.User.stories.impl.ts
@@ -4,7 +4,7 @@
  */
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { userDetailed } from '../../.storybook/fakes.js';
 import MkUserSetupDialog_User from './MkUserSetupDialog.User.vue';
 export const Default = {
diff --git a/packages/frontend/src/components/MkUserSetupDialog.stories.impl.ts b/packages/frontend/src/components/MkUserSetupDialog.stories.impl.ts
index 3f5ae734bd..751391c2d8 100644
--- a/packages/frontend/src/components/MkUserSetupDialog.stories.impl.ts
+++ b/packages/frontend/src/components/MkUserSetupDialog.stories.impl.ts
@@ -4,7 +4,7 @@
  */
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { HttpResponse, http } from 'msw';
 import { commonHandlers } from '../../.storybook/mocks.js';
 import { userDetailed } from '../../.storybook/fakes.js';
diff --git a/packages/frontend/src/components/global/MkA.stories.impl.ts b/packages/frontend/src/components/global/MkA.stories.impl.ts
index 02e5a7f98c..1ccf105dbb 100644
--- a/packages/frontend/src/components/global/MkA.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkA.stories.impl.ts
@@ -5,7 +5,7 @@
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 import { expect, userEvent, within } from '@storybook/test';
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import MkA from './MkA.vue';
 import { tick } from '@/scripts/test-utils.js';
 export const Default = {
diff --git a/packages/frontend/src/components/global/MkAcct.stories.impl.ts b/packages/frontend/src/components/global/MkAcct.stories.impl.ts
index 04960ec60c..02fc835709 100644
--- a/packages/frontend/src/components/global/MkAcct.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkAcct.stories.impl.ts
@@ -4,7 +4,7 @@
  */
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { userDetailed } from '../../../.storybook/fakes.js';
 import MkAcct from './MkAcct.vue';
 export const Default = {
diff --git a/packages/frontend/src/components/global/MkAd.stories.impl.ts b/packages/frontend/src/components/global/MkAd.stories.impl.ts
index 8c0b7ef52f..c5a928b5cf 100644
--- a/packages/frontend/src/components/global/MkAd.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkAd.stories.impl.ts
@@ -5,7 +5,7 @@
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 import { expect, userEvent, waitFor, within } from '@storybook/test';
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import MkAd from './MkAd.vue';
 import { i18n } from '@/i18n.js';
 
diff --git a/packages/frontend/src/components/global/MkAvatar.stories.impl.ts b/packages/frontend/src/components/global/MkAvatar.stories.impl.ts
index 9d2de9f0be..84221842e9 100644
--- a/packages/frontend/src/components/global/MkAvatar.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkAvatar.stories.impl.ts
@@ -4,7 +4,7 @@
  */
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { userDetailed } from '../../../.storybook/fakes.js';
 import MkAvatar from './MkAvatar.vue';
 const common = {
diff --git a/packages/frontend/src/components/global/MkCondensedLine.stories.impl.ts b/packages/frontend/src/components/global/MkCondensedLine.stories.impl.ts
index e15dcba760..15ae489ff8 100644
--- a/packages/frontend/src/components/global/MkCondensedLine.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkCondensedLine.stories.impl.ts
@@ -4,7 +4,7 @@
  */
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import MkCondensedLine from './MkCondensedLine.vue';
 export const Default = {
 	render(args) {
diff --git a/packages/frontend/src/components/global/MkCustomEmoji.stories.impl.ts b/packages/frontend/src/components/global/MkCustomEmoji.stories.impl.ts
index 9e6177045d..eded13b686 100644
--- a/packages/frontend/src/components/global/MkCustomEmoji.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkCustomEmoji.stories.impl.ts
@@ -4,7 +4,7 @@
  */
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import MkCustomEmoji from './MkCustomEmoji.vue';
 export const Default = {
 	render(args) {
diff --git a/packages/frontend/src/components/global/MkEllipsis.stories.impl.ts b/packages/frontend/src/components/global/MkEllipsis.stories.impl.ts
index 6a8fcf4fe3..dafdcbd13f 100644
--- a/packages/frontend/src/components/global/MkEllipsis.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkEllipsis.stories.impl.ts
@@ -4,7 +4,7 @@
  */
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import isChromatic from 'chromatic/isChromatic';
 import MkEllipsis from './MkEllipsis.vue';
 export const Default = {
diff --git a/packages/frontend/src/components/global/MkEmoji.stories.impl.ts b/packages/frontend/src/components/global/MkEmoji.stories.impl.ts
index 309c015757..1a394ca6bb 100644
--- a/packages/frontend/src/components/global/MkEmoji.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkEmoji.stories.impl.ts
@@ -4,7 +4,7 @@
  */
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import MkEmoji from './MkEmoji.vue';
 export const Default = {
 	render(args) {
diff --git a/packages/frontend/src/components/global/MkError.stories.impl.ts b/packages/frontend/src/components/global/MkError.stories.impl.ts
index daef04cd87..e150493a18 100644
--- a/packages/frontend/src/components/global/MkError.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkError.stories.impl.ts
@@ -6,7 +6,7 @@
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 import { action } from '@storybook/addon-actions';
 import { expect, waitFor } from '@storybook/test';
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import MkError from './MkError.vue';
 export const Default = {
 	render(args) {
diff --git a/packages/frontend/src/components/global/MkError.stories.meta.ts b/packages/frontend/src/components/global/MkError.stories.meta.ts
index cd7fada189..940b445e90 100644
--- a/packages/frontend/src/components/global/MkError.stories.meta.ts
+++ b/packages/frontend/src/components/global/MkError.stories.meta.ts
@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { Meta } from '@storybook/vue3';
+import type { Meta } from '@storybook/vue3';
 import MkError from './MkError.vue';
 
 export const argTypes = {
diff --git a/packages/frontend/src/components/global/MkLoading.stories.impl.ts b/packages/frontend/src/components/global/MkLoading.stories.impl.ts
index c781ad0479..8313f73e4b 100644
--- a/packages/frontend/src/components/global/MkLoading.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkLoading.stories.impl.ts
@@ -4,7 +4,7 @@
  */
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import isChromatic from 'chromatic/isChromatic';
 import MkLoading from './MkLoading.vue';
 export const Default = {
diff --git a/packages/frontend/src/components/global/MkMfm.stories.impl.ts b/packages/frontend/src/components/global/MkMfm.stories.impl.ts
index 1daf7a29cb..98da531ed4 100644
--- a/packages/frontend/src/components/global/MkMfm.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkMfm.stories.impl.ts
@@ -2,8 +2,8 @@
  * SPDX-FileCopyrightText: syuilo and misskey-project
  * SPDX-License-Identifier: AGPL-3.0-only
  */
- 
-import { StoryObj } from '@storybook/vue3';
+
+import type { StoryObj } from '@storybook/vue3';
 import { expect, within } from '@storybook/test';
 import MkMfm from './MkMfm.js';
 export const Default = {
diff --git a/packages/frontend/src/components/global/MkMfm.ts b/packages/frontend/src/components/global/MkMfm.ts
index 0d138d1f1c..48d7e34d76 100644
--- a/packages/frontend/src/components/global/MkMfm.ts
+++ b/packages/frontend/src/components/global/MkMfm.ts
@@ -3,7 +3,8 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { VNode, h, SetupContext, provide } from 'vue';
+import { h, provide } from 'vue';
+import type { VNode, SetupContext } from 'vue';
 import * as mfm from 'mfm-js';
 import * as Misskey from 'misskey-js';
 import { host } from '@@/js/config.js';
@@ -17,7 +18,8 @@ import MkCode from '@/components/MkCode.vue';
 import MkCodeInline from '@/components/MkCodeInline.vue';
 import MkGoogle from '@/components/MkGoogle.vue';
 import MkSparkle from '@/components/MkSparkle.vue';
-import MkA, { MkABehavior } from '@/components/global/MkA.vue';
+import MkA from '@/components/global/MkA.vue';
+import type { MkABehavior } from '@/components/global/MkA.vue';
 import { defaultStore } from '@/store.js';
 
 function safeParseFloat(str: unknown): number | null {
diff --git a/packages/frontend/src/components/global/MkPageHeader.stories.impl.ts b/packages/frontend/src/components/global/MkPageHeader.stories.impl.ts
index 1d079edd2c..c9af5f4ea4 100644
--- a/packages/frontend/src/components/global/MkPageHeader.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkPageHeader.stories.impl.ts
@@ -5,7 +5,7 @@
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 import { waitFor } from '@storybook/test';
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import MkPageHeader from './MkPageHeader.vue';
 export const Empty = {
 	render(args) {
diff --git a/packages/frontend/src/components/global/MkPageHeader.vue b/packages/frontend/src/components/global/MkPageHeader.vue
index a2e70a5cad..1070c0c83b 100644
--- a/packages/frontend/src/components/global/MkPageHeader.vue
+++ b/packages/frontend/src/components/global/MkPageHeader.vue
@@ -43,7 +43,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { onMounted, onUnmounted, ref, inject, shallowRef, computed } from 'vue';
 import tinycolor from 'tinycolor2';
-import XTabs, { Tab } from './MkPageHeader.tabs.vue';
+import XTabs from './MkPageHeader.tabs.vue';
+import type { Tab } from './MkPageHeader.tabs.vue';
 import { scrollToTop } from '@@/js/scroll.js';
 import { globalEvents } from '@/events.js';
 import { injectReactiveMetadata } from '@/scripts/page-metadata.js';
diff --git a/packages/frontend/src/components/global/MkStickyContainer.vue b/packages/frontend/src/components/global/MkStickyContainer.vue
index 1aebf487bb..7ee3952083 100644
--- a/packages/frontend/src/components/global/MkStickyContainer.vue
+++ b/packages/frontend/src/components/global/MkStickyContainer.vue
@@ -22,7 +22,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
-import { onMounted, onUnmounted, provide, inject, Ref, ref, watch, useTemplateRef } from 'vue';
+import { onMounted, onUnmounted, provide, inject, ref, watch, useTemplateRef } from 'vue';
+import type { Ref } from 'vue';
 
 import { CURRENT_STICKY_BOTTOM, CURRENT_STICKY_TOP } from '@@/js/const.js';
 
diff --git a/packages/frontend/src/components/global/MkTime.stories.impl.ts b/packages/frontend/src/components/global/MkTime.stories.impl.ts
index ccf7f200b5..5e62c3fbab 100644
--- a/packages/frontend/src/components/global/MkTime.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkTime.stories.impl.ts
@@ -5,7 +5,7 @@
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 import { expect } from '@storybook/test';
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import MkTime from './MkTime.vue';
 import { i18n } from '@/i18n.js';
 import { dateTimeFormat } from '@@/js/intl-const.js';
diff --git a/packages/frontend/src/components/global/MkUrl.stories.impl.ts b/packages/frontend/src/components/global/MkUrl.stories.impl.ts
index 34a4adfe49..ea02fdfdd0 100644
--- a/packages/frontend/src/components/global/MkUrl.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkUrl.stories.impl.ts
@@ -5,7 +5,7 @@
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 import { expect, userEvent, waitFor, within } from '@storybook/test';
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { HttpResponse, http } from 'msw';
 import { commonHandlers } from '../../../.storybook/mocks.js';
 import MkUrl from './MkUrl.vue';
diff --git a/packages/frontend/src/components/global/MkUrl.vue b/packages/frontend/src/components/global/MkUrl.vue
index 4ab530b136..3d2036e376 100644
--- a/packages/frontend/src/components/global/MkUrl.vue
+++ b/packages/frontend/src/components/global/MkUrl.vue
@@ -31,7 +31,7 @@ import { url as local } from '@@/js/config.js';
 import * as os from '@/os.js';
 import { useTooltip } from '@/scripts/use-tooltip.js';
 import { isEnabledUrlPreview } from '@/instance.js';
-import { MkABehavior } from '@/components/global/MkA.vue';
+import type { MkABehavior } from '@/components/global/MkA.vue';
 
 function safeURIDecode(str: string): string {
 	try {
diff --git a/packages/frontend/src/components/global/MkUserName.stories.impl.ts b/packages/frontend/src/components/global/MkUserName.stories.impl.ts
index e39061c291..b46c91c903 100644
--- a/packages/frontend/src/components/global/MkUserName.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkUserName.stories.impl.ts
@@ -5,7 +5,7 @@
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 import { expect } from '@storybook/test';
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { userDetailed } from '../../../.storybook/fakes.js';
 import MkUserName from './MkUserName.vue';
 export const Default = {
diff --git a/packages/frontend/src/components/global/RouterView.vue b/packages/frontend/src/components/global/RouterView.vue
index 38bdfc52d4..3ab3d10a40 100644
--- a/packages/frontend/src/components/global/RouterView.vue
+++ b/packages/frontend/src/components/global/RouterView.vue
@@ -20,7 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import { inject, onBeforeUnmount, provide, ref, shallowRef, computed, nextTick } from 'vue';
-import { IRouter, Resolved, RouteDef } from '@/nirax.js';
+import type { IRouter, Resolved, RouteDef } from '@/nirax.js';
 import { defaultStore } from '@/store.js';
 import { globalEvents } from '@/events.js';
 import MkLoadingPage from '@/pages/_loading_.vue';
diff --git a/packages/frontend/src/components/grid/MkDataCell.vue b/packages/frontend/src/components/grid/MkDataCell.vue
index e473b7c1af..c2dc05efe6 100644
--- a/packages/frontend/src/components/grid/MkDataCell.vue
+++ b/packages/frontend/src/components/grid/MkDataCell.vue
@@ -89,12 +89,13 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script setup lang="ts">
 import { computed, defineAsyncComponent, nextTick, onMounted, onUnmounted, ref, shallowRef, toRefs, watch } from 'vue';
-import { GridEventEmitter, Size } from '@/components/grid/grid.js';
+import { GridEventEmitter } from '@/components/grid/grid.js';
 import { useTooltip } from '@/scripts/use-tooltip.js';
 import * as os from '@/os.js';
-import { CellValue, GridCell } from '@/components/grid/cell.js';
 import { equalCellAddress, getCellAddress } from '@/components/grid/grid-utils.js';
-import { GridRowSetting } from '@/components/grid/row.js';
+import type { Size } from '@/components/grid/grid.js';
+import type { CellValue, GridCell } from '@/components/grid/cell.js';
+import type { GridRowSetting } from '@/components/grid/row.js';
 
 const emit = defineEmits<{
 	(ev: 'operation:beginEdit', sender: GridCell): void;
diff --git a/packages/frontend/src/components/grid/MkDataRow.vue b/packages/frontend/src/components/grid/MkDataRow.vue
index 280a14bc4a..a35f93b435 100644
--- a/packages/frontend/src/components/grid/MkDataRow.vue
+++ b/packages/frontend/src/components/grid/MkDataRow.vue
@@ -37,11 +37,12 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script setup lang="ts">
-import { GridEventEmitter, Size } from '@/components/grid/grid.js';
+import { GridEventEmitter } from '@/components/grid/grid.js';
 import MkDataCell from '@/components/grid/MkDataCell.vue';
 import MkNumberCell from '@/components/grid/MkNumberCell.vue';
-import { CellValue, GridCell } from '@/components/grid/cell.js';
-import { GridRow, GridRowSetting } from '@/components/grid/row.js';
+import type { Size } from '@/components/grid/grid.js';
+import type { CellValue, GridCell } from '@/components/grid/cell.js';
+import type { GridRow, GridRowSetting } from '@/components/grid/row.js';
 
 const emit = defineEmits<{
 	(ev: 'operation:beginEdit', sender: GridCell): void;
diff --git a/packages/frontend/src/components/grid/MkGrid.stories.impl.ts b/packages/frontend/src/components/grid/MkGrid.stories.impl.ts
index 5801012f15..f85bf146e8 100644
--- a/packages/frontend/src/components/grid/MkGrid.stories.impl.ts
+++ b/packages/frontend/src/components/grid/MkGrid.stories.impl.ts
@@ -5,14 +5,14 @@
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
 import { action } from '@storybook/addon-actions';
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { ref } from 'vue';
 import { commonHandlers } from '../../../.storybook/mocks.js';
 import { boolean, choose, country, date, firstName, integer, lastName, text } from '../../../.storybook/fake-utils.js';
 import MkGrid from './MkGrid.vue';
-import { GridContext, GridEvent } from '@/components/grid/grid-event.js';
-import { DataSource, GridSetting } from '@/components/grid/grid.js';
-import { GridColumnSetting } from '@/components/grid/column.js';
+import type { GridContext, GridEvent } from '@/components/grid/grid-event.js';
+import type { DataSource, GridSetting } from '@/components/grid/grid.js';
+import type { GridColumnSetting } from '@/components/grid/column.js';
 
 function d(p: {
 	check?: boolean,
diff --git a/packages/frontend/src/components/grid/MkGrid.vue b/packages/frontend/src/components/grid/MkGrid.vue
index 4dbd4ebcae..84f1f754b2 100644
--- a/packages/frontend/src/components/grid/MkGrid.vue
+++ b/packages/frontend/src/components/grid/MkGrid.vue
@@ -50,11 +50,11 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script setup lang="ts">
 import { computed, onMounted, ref, toRefs, watch } from 'vue';
-import { DataSource, GridEventEmitter, GridSetting, GridState, Size } from '@/components/grid/grid.js';
+import { GridEventEmitter } from '@/components/grid/grid.js';
 import MkDataRow from '@/components/grid/MkDataRow.vue';
 import MkHeaderRow from '@/components/grid/MkHeaderRow.vue';
 import { cellValidation } from '@/components/grid/cell-validators.js';
-import { CELL_ADDRESS_NONE, CellAddress, CellValue, createCell, GridCell, resetCell } from '@/components/grid/cell.js';
+import { CELL_ADDRESS_NONE, createCell, resetCell } from '@/components/grid/cell.js';
 import {
 	copyGridDataToClipboard,
 	equalCellAddress,
@@ -63,13 +63,18 @@ import {
 	pasteToGridFromClipboard,
 	removeDataFromGrid,
 } from '@/components/grid/grid-utils.js';
-import { MenuItem } from '@/types/menu.js';
 import * as os from '@/os.js';
-import { GridContext, GridEvent } from '@/components/grid/grid-event.js';
-import { createColumn, GridColumn } from '@/components/grid/column.js';
-import { createRow, defaultGridRowSetting, GridRow, GridRowSetting, resetRow } from '@/components/grid/row.js';
+import { createColumn } from '@/components/grid/column.js';
+import { createRow, defaultGridRowSetting, resetRow } from '@/components/grid/row.js';
 import { handleKeyEvent } from '@/scripts/key-event.js';
 
+import type { DataSource, GridSetting, GridState, Size } from '@/components/grid/grid.js';
+import type { CellAddress, CellValue, GridCell } from '@/components/grid/cell.js';
+import type { GridContext, GridEvent } from '@/components/grid/grid-event.js';
+import type { GridColumn } from '@/components/grid/column.js';
+import type { GridRow, GridRowSetting } from '@/components/grid/row.js';
+import type { MenuItem } from '@/types/menu.js';
+
 type RowHolder = {
 	row: GridRow,
 	cells: GridCell[],
diff --git a/packages/frontend/src/components/grid/MkHeaderCell.vue b/packages/frontend/src/components/grid/MkHeaderCell.vue
index aecfe7eaa3..69a68b6f2c 100644
--- a/packages/frontend/src/components/grid/MkHeaderCell.vue
+++ b/packages/frontend/src/components/grid/MkHeaderCell.vue
@@ -32,8 +32,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script setup lang="ts">
 import { computed, nextTick, onMounted, onUnmounted, ref, toRefs, watch } from 'vue';
-import { GridEventEmitter, Size } from '@/components/grid/grid.js';
-import { GridColumn } from '@/components/grid/column.js';
+import { GridEventEmitter } from '@/components/grid/grid.js';
+import type { Size } from '@/components/grid/grid.js';
+import type { GridColumn } from '@/components/grid/column.js';
 
 const emit = defineEmits<{
 	(ev: 'operation:beginWidthChange', sender: GridColumn): void;
diff --git a/packages/frontend/src/components/grid/MkHeaderRow.vue b/packages/frontend/src/components/grid/MkHeaderRow.vue
index 8affa08fd5..225f623b84 100644
--- a/packages/frontend/src/components/grid/MkHeaderRow.vue
+++ b/packages/frontend/src/components/grid/MkHeaderRow.vue
@@ -29,11 +29,12 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script setup lang="ts">
-import { GridEventEmitter, Size } from '@/components/grid/grid.js';
+import { GridEventEmitter } from '@/components/grid/grid.js';
 import MkHeaderCell from '@/components/grid/MkHeaderCell.vue';
 import MkNumberCell from '@/components/grid/MkNumberCell.vue';
-import { GridColumn } from '@/components/grid/column.js';
-import { GridRowSetting } from '@/components/grid/row.js';
+import type { Size } from '@/components/grid/grid.js';
+import type { GridColumn } from '@/components/grid/column.js';
+import type { GridRowSetting } from '@/components/grid/row.js';
 
 const emit = defineEmits<{
 	(ev: 'operation:beginWidthChange', sender: GridColumn): void;
diff --git a/packages/frontend/src/components/grid/MkNumberCell.vue b/packages/frontend/src/components/grid/MkNumberCell.vue
index 674bba96bc..d3b5956ddd 100644
--- a/packages/frontend/src/components/grid/MkNumberCell.vue
+++ b/packages/frontend/src/components/grid/MkNumberCell.vue
@@ -19,8 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script setup lang="ts">
-
-import { GridRow } from '@/components/grid/row.js';
+import type { GridRow } from '@/components/grid/row.js';
 
 defineProps<{
 	content: string,
diff --git a/packages/frontend/src/components/grid/cell-validators.ts b/packages/frontend/src/components/grid/cell-validators.ts
index 949cab2ec6..56d7f0f13d 100644
--- a/packages/frontend/src/components/grid/cell-validators.ts
+++ b/packages/frontend/src/components/grid/cell-validators.ts
@@ -3,9 +3,9 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { CellValue, GridCell } from '@/components/grid/cell.js';
-import { GridColumn } from '@/components/grid/column.js';
-import { GridRow } from '@/components/grid/row.js';
+import type { CellValue, GridCell } from '@/components/grid/cell.js';
+import type { GridColumn } from '@/components/grid/column.js';
+import type { GridRow } from '@/components/grid/row.js';
 import { i18n } from '@/i18n.js';
 
 export type ValidatorParams = {
diff --git a/packages/frontend/src/components/grid/cell.ts b/packages/frontend/src/components/grid/cell.ts
index 71b7a3e3f1..2569c6d50d 100644
--- a/packages/frontend/src/components/grid/cell.ts
+++ b/packages/frontend/src/components/grid/cell.ts
@@ -3,12 +3,12 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { ValidateViolation } from '@/components/grid/cell-validators.js';
-import { Size } from '@/components/grid/grid.js';
-import { GridColumn } from '@/components/grid/column.js';
-import { GridRow } from '@/components/grid/row.js';
-import { MenuItem } from '@/types/menu.js';
-import { GridContext } from '@/components/grid/grid-event.js';
+import type { ValidateViolation } from '@/components/grid/cell-validators.js';
+import type { Size } from '@/components/grid/grid.js';
+import type { GridColumn } from '@/components/grid/column.js';
+import type { GridRow } from '@/components/grid/row.js';
+import type { MenuItem } from '@/types/menu.js';
+import type { GridContext } from '@/components/grid/grid-event.js';
 
 export type CellValue = string | boolean | number | undefined | null | Array<unknown> | NonNullable<unknown>;
 
diff --git a/packages/frontend/src/components/grid/column.ts b/packages/frontend/src/components/grid/column.ts
index 2f505756fe..6780c8a3a7 100644
--- a/packages/frontend/src/components/grid/column.ts
+++ b/packages/frontend/src/components/grid/column.ts
@@ -3,13 +3,13 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { GridCellValidator } from '@/components/grid/cell-validators.js';
-import { Size, SizeStyle } from '@/components/grid/grid.js';
 import { calcCellWidth } from '@/components/grid/grid-utils.js';
-import { CellValue, GridCell } from '@/components/grid/cell.js';
-import { GridRow } from '@/components/grid/row.js';
-import { MenuItem } from '@/types/menu.js';
-import { GridContext } from '@/components/grid/grid-event.js';
+import type { GridCellValidator } from '@/components/grid/cell-validators.js';
+import type { Size, SizeStyle } from '@/components/grid/grid.js';
+import type { CellValue, GridCell } from '@/components/grid/cell.js';
+import type { GridRow } from '@/components/grid/row.js';
+import type { MenuItem } from '@/types/menu.js';
+import type { GridContext } from '@/components/grid/grid-event.js';
 
 export type ColumnType = 'text' | 'number' | 'date' | 'boolean' | 'image' | 'hidden';
 
diff --git a/packages/frontend/src/components/grid/grid-event.ts b/packages/frontend/src/components/grid/grid-event.ts
index 074b72b956..e2f1e44055 100644
--- a/packages/frontend/src/components/grid/grid-event.ts
+++ b/packages/frontend/src/components/grid/grid-event.ts
@@ -3,11 +3,11 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { CellAddress, CellValue, GridCell } from '@/components/grid/cell.js';
-import { GridState } from '@/components/grid/grid.js';
-import { ValidateViolation } from '@/components/grid/cell-validators.js';
-import { GridColumn } from '@/components/grid/column.js';
-import { GridRow } from '@/components/grid/row.js';
+import type { CellAddress, CellValue, GridCell } from '@/components/grid/cell.js';
+import type { GridState } from '@/components/grid/grid.js';
+import type { ValidateViolation } from '@/components/grid/cell-validators.js';
+import type { GridColumn } from '@/components/grid/column.js';
+import type { GridRow } from '@/components/grid/row.js';
 
 export type GridContext = {
 	selectedCell?: GridCell;
diff --git a/packages/frontend/src/components/grid/grid-utils.ts b/packages/frontend/src/components/grid/grid-utils.ts
index a45bc88926..4f48af194c 100644
--- a/packages/frontend/src/components/grid/grid-utils.ts
+++ b/packages/frontend/src/components/grid/grid-utils.ts
@@ -3,13 +3,15 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { isRef, Ref } from 'vue';
-import { DataSource, SizeStyle } from '@/components/grid/grid.js';
-import { CELL_ADDRESS_NONE, CellAddress, CellValue, GridCell } from '@/components/grid/cell.js';
-import { GridRow } from '@/components/grid/row.js';
-import { GridContext } from '@/components/grid/grid-event.js';
+import { isRef } from 'vue';
+import type { Ref } from 'vue';
+import type { DataSource, SizeStyle } from '@/components/grid/grid.js';
+import { CELL_ADDRESS_NONE } from '@/components/grid/cell.js';
+import type { CellAddress, CellValue, GridCell } from '@/components/grid/cell.js';
+import type { GridRow } from '@/components/grid/row.js';
+import type { GridContext } from '@/components/grid/grid-event.js';
 import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
-import { GridColumn, GridColumnSetting } from '@/components/grid/column.js';
+import type { GridColumn, GridColumnSetting } from '@/components/grid/column.js';
 
 export function isCellElement(elem: HTMLElement): boolean {
 	return elem.hasAttribute('data-grid-cell');
diff --git a/packages/frontend/src/components/grid/grid.ts b/packages/frontend/src/components/grid/grid.ts
index b82e12b304..03947b7ee3 100644
--- a/packages/frontend/src/components/grid/grid.ts
+++ b/packages/frontend/src/components/grid/grid.ts
@@ -4,9 +4,9 @@
  */
 
 import { EventEmitter } from 'eventemitter3';
-import { CellValue, GridCellSetting } from '@/components/grid/cell.js';
-import { GridColumnSetting } from '@/components/grid/column.js';
-import { GridRowSetting } from '@/components/grid/row.js';
+import type { CellValue, GridCellSetting } from '@/components/grid/cell.js';
+import type { GridColumnSetting } from '@/components/grid/column.js';
+import type { GridRowSetting } from '@/components/grid/row.js';
 
 export type GridSetting = {
 	root?: {
diff --git a/packages/frontend/src/components/grid/row.ts b/packages/frontend/src/components/grid/row.ts
index e0a317c9d3..f34770312a 100644
--- a/packages/frontend/src/components/grid/row.ts
+++ b/packages/frontend/src/components/grid/row.ts
@@ -3,11 +3,11 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { AdditionalStyle } from '@/components/grid/grid.js';
-import { GridCell } from '@/components/grid/cell.js';
-import { GridColumn } from '@/components/grid/column.js';
-import { MenuItem } from '@/types/menu.js';
-import { GridContext } from '@/components/grid/grid-event.js';
+import type { AdditionalStyle } from '@/components/grid/grid.js';
+import type { GridCell } from '@/components/grid/cell.js';
+import type { GridColumn } from '@/components/grid/column.js';
+import type { MenuItem } from '@/types/menu.js';
+import type { GridContext } from '@/components/grid/grid-event.js';
 
 export const defaultGridRowSetting: Required<GridRowSetting> = {
 	showNumber: true,
diff --git a/packages/frontend/src/components/index.ts b/packages/frontend/src/components/index.ts
index b36625ed1b..0252bf0252 100644
--- a/packages/frontend/src/components/index.ts
+++ b/packages/frontend/src/components/index.ts
@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { App } from 'vue';
+import type { App } from 'vue';
 
 import Mfm from './global/MkMfm.js';
 import MkA from './global/MkA.vue';
diff --git a/packages/frontend/src/debug.ts b/packages/frontend/src/debug.ts
index 8bb8012ae3..3a8f6289d1 100644
--- a/packages/frontend/src/debug.ts
+++ b/packages/frontend/src/debug.ts
@@ -3,7 +3,8 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { type ComponentInternalInstance, getCurrentInstance } from 'vue';
+import { getCurrentInstance } from 'vue';
+import type { ComponentInternalInstance } from 'vue';
 
 export function isDebuggerEnabled(id: number): boolean {
 	try {
diff --git a/packages/frontend/src/directives/adaptive-bg.ts b/packages/frontend/src/directives/adaptive-bg.ts
index f88996019f..98e3d91b29 100644
--- a/packages/frontend/src/directives/adaptive-bg.ts
+++ b/packages/frontend/src/directives/adaptive-bg.ts
@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { Directive } from 'vue';
+import type { Directive } from 'vue';
 import { getBgColor } from '@/scripts/get-bg-color.js';
 
 export default {
diff --git a/packages/frontend/src/directives/adaptive-border.ts b/packages/frontend/src/directives/adaptive-border.ts
index 1305f312bd..4037076cae 100644
--- a/packages/frontend/src/directives/adaptive-border.ts
+++ b/packages/frontend/src/directives/adaptive-border.ts
@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { Directive } from 'vue';
+import type { Directive } from 'vue';
 import { getBgColor } from '@/scripts/get-bg-color.js';
 
 export default {
diff --git a/packages/frontend/src/directives/anim.ts b/packages/frontend/src/directives/anim.ts
index d5b6ae4287..ad0cb5ed81 100644
--- a/packages/frontend/src/directives/anim.ts
+++ b/packages/frontend/src/directives/anim.ts
@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { Directive } from 'vue';
+import type { Directive } from 'vue';
 
 export default {
 	beforeMount(src, binding, vn) {
diff --git a/packages/frontend/src/directives/appear.ts b/packages/frontend/src/directives/appear.ts
index 706d4a9ee4..802477e00b 100644
--- a/packages/frontend/src/directives/appear.ts
+++ b/packages/frontend/src/directives/appear.ts
@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { Directive } from 'vue';
+import type { Directive } from 'vue';
 
 export default {
 	mounted(src, binding, vn) {
diff --git a/packages/frontend/src/directives/click-anime.ts b/packages/frontend/src/directives/click-anime.ts
index 5bb48bbcdd..60242837f2 100644
--- a/packages/frontend/src/directives/click-anime.ts
+++ b/packages/frontend/src/directives/click-anime.ts
@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { Directive } from 'vue';
+import type { Directive } from 'vue';
 import { defaultStore } from '@/store.js';
 
 export default {
diff --git a/packages/frontend/src/directives/follow-append.ts b/packages/frontend/src/directives/follow-append.ts
index 615dd99fa8..f3eaac10e3 100644
--- a/packages/frontend/src/directives/follow-append.ts
+++ b/packages/frontend/src/directives/follow-append.ts
@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { Directive } from 'vue';
+import type { Directive } from 'vue';
 import { getScrollContainer, getScrollPosition } from '@@/js/scroll.js';
 
 export default {
diff --git a/packages/frontend/src/directives/get-size.ts b/packages/frontend/src/directives/get-size.ts
index 2655c76c48..488f201a0d 100644
--- a/packages/frontend/src/directives/get-size.ts
+++ b/packages/frontend/src/directives/get-size.ts
@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { Directive } from 'vue';
+import type { Directive } from 'vue';
 
 const mountings = new Map<Element, {
 	resize: ResizeObserver;
diff --git a/packages/frontend/src/directives/hotkey.ts b/packages/frontend/src/directives/hotkey.ts
index 0e5c7ede24..ec00652381 100644
--- a/packages/frontend/src/directives/hotkey.ts
+++ b/packages/frontend/src/directives/hotkey.ts
@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { Directive } from 'vue';
+import type { Directive } from 'vue';
 import { makeHotkey } from '@/scripts/hotkey.js';
 
 export default {
diff --git a/packages/frontend/src/directives/index.ts b/packages/frontend/src/directives/index.ts
index bda7738ccd..9555045afe 100644
--- a/packages/frontend/src/directives/index.ts
+++ b/packages/frontend/src/directives/index.ts
@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { App } from 'vue';
+import type { App } from 'vue';
 
 import userPreview from './user-preview.js';
 import getSize from './get-size.js';
diff --git a/packages/frontend/src/directives/panel.ts b/packages/frontend/src/directives/panel.ts
index aa26b94d0b..19fd374861 100644
--- a/packages/frontend/src/directives/panel.ts
+++ b/packages/frontend/src/directives/panel.ts
@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { Directive } from 'vue';
+import type { Directive } from 'vue';
 import { getBgColor } from '@/scripts/get-bg-color.js';
 
 export default {
diff --git a/packages/frontend/src/directives/tooltip.ts b/packages/frontend/src/directives/tooltip.ts
index 251ce5675f..6bfe6ac31d 100644
--- a/packages/frontend/src/directives/tooltip.ts
+++ b/packages/frontend/src/directives/tooltip.ts
@@ -6,7 +6,8 @@
 // TODO: useTooltip関数使うようにしたい
 // ただディレクティブ内でonUnmountedなどのcomposition api使えるのか不明
 
-import { defineAsyncComponent, Directive, ref } from 'vue';
+import { defineAsyncComponent, ref } from 'vue';
+import type { Directive } from 'vue';
 import { isTouchUsing } from '@/scripts/touch.js';
 import { popup, alert } from '@/os.js';
 
diff --git a/packages/frontend/src/directives/user-preview.ts b/packages/frontend/src/directives/user-preview.ts
index 278d842d09..43a93a0865 100644
--- a/packages/frontend/src/directives/user-preview.ts
+++ b/packages/frontend/src/directives/user-preview.ts
@@ -3,7 +3,8 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { defineAsyncComponent, Directive, ref } from 'vue';
+import { defineAsyncComponent, ref } from 'vue';
+import type { Directive } from 'vue';
 import { popup } from '@/os.js';
 
 export class UserPreview {
diff --git a/packages/frontend/src/nirax.ts b/packages/frontend/src/nirax.ts
index 965bd6f0bc..ec4ac9d91a 100644
--- a/packages/frontend/src/nirax.ts
+++ b/packages/frontend/src/nirax.ts
@@ -5,7 +5,8 @@
 
 // NIRAX --- A lightweight router
 
-import { Component, onMounted, shallowRef, ShallowRef } from 'vue';
+import { onMounted, shallowRef } from 'vue';
+import type { Component, ShallowRef } from 'vue';
 import { EventEmitter } from 'eventemitter3';
 
 function safeURIDecode(str: string): string {
diff --git a/packages/frontend/src/os.ts b/packages/frontend/src/os.ts
index 18c7464d2e..69cc62ad6e 100644
--- a/packages/frontend/src/os.ts
+++ b/packages/frontend/src/os.ts
@@ -5,7 +5,8 @@
 
 // TODO: なんでもかんでもos.tsに突っ込むのやめたいのでよしなに分割する
 
-import { Component, markRaw, Ref, ref, defineAsyncComponent, nextTick } from 'vue';
+import { markRaw, ref, defineAsyncComponent, nextTick } from 'vue';
+import type { Component, Ref } from 'vue';
 import { EventEmitter } from 'eventemitter3';
 import * as Misskey from 'misskey-js';
 import type { ComponentProps as CP } from 'vue-component-type-helpers';
diff --git a/packages/frontend/src/pages/about.federation.vue b/packages/frontend/src/pages/about.federation.vue
index 0a7cb8a50b..97743995bf 100644
--- a/packages/frontend/src/pages/about.federation.vue
+++ b/packages/frontend/src/pages/about.federation.vue
@@ -54,7 +54,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 import { computed, ref } from 'vue';
 import MkInput from '@/components/MkInput.vue';
 import MkSelect from '@/components/MkSelect.vue';
-import MkPagination, { Paging } from '@/components/MkPagination.vue';
+import MkPagination from '@/components/MkPagination.vue';
+import type { Paging } from '@/components/MkPagination.vue';
 import MkInstanceCardMini from '@/components/MkInstanceCardMini.vue';
 import FormSplit from '@/components/form/split.vue';
 import { i18n } from '@/i18n.js';
diff --git a/packages/frontend/src/pages/admin/abuse-report/notification-recipient.editor.vue b/packages/frontend/src/pages/admin/abuse-report/notification-recipient.editor.vue
index eef24afd32..5f683c7a1d 100644
--- a/packages/frontend/src/pages/admin/abuse-report/notification-recipient.editor.vue
+++ b/packages/frontend/src/pages/admin/abuse-report/notification-recipient.editor.vue
@@ -79,7 +79,8 @@ import { i18n } from '@/i18n.js';
 import MkInput from '@/components/MkInput.vue';
 import { misskeyApi } from '@/scripts/misskey-api.js';
 import MkSelect from '@/components/MkSelect.vue';
-import { MkSystemWebhookResult, showSystemWebhookEditorDialog } from '@/components/MkSystemWebhookEditor.impl.js';
+import { showSystemWebhookEditorDialog } from '@/components/MkSystemWebhookEditor.impl.js';
+import type { MkSystemWebhookResult } from '@/components/MkSystemWebhookEditor.impl.js';
 import MkSwitch from '@/components/MkSwitch.vue';
 import MkDivider from '@/components/MkDivider.vue';
 import * as os from '@/os.js';
diff --git a/packages/frontend/src/pages/admin/bot-protection.vue b/packages/frontend/src/pages/admin/bot-protection.vue
index 498cf13943..2d314c822d 100644
--- a/packages/frontend/src/pages/admin/bot-protection.vue
+++ b/packages/frontend/src/pages/admin/bot-protection.vue
@@ -167,7 +167,7 @@ import { useForm } from '@/scripts/use-form.js';
 import MkFormFooter from '@/components/MkFormFooter.vue';
 import MkFolder from '@/components/MkFolder.vue';
 import MkInfo from '@/components/MkInfo.vue';
-import { ApiWithDialogCustomErrors } from '@/os.js';
+import type { ApiWithDialogCustomErrors } from '@/os.js';
 
 const MkCaptcha = defineAsyncComponent(() => import('@/components/MkCaptcha.vue'));
 
diff --git a/packages/frontend/src/pages/admin/custom-emojis-manager.local.list.vue b/packages/frontend/src/pages/admin/custom-emojis-manager.local.list.vue
index c4ea3b93e3..b69457e05e 100644
--- a/packages/frontend/src/pages/admin/custom-emojis-manager.local.list.vue
+++ b/packages/frontend/src/pages/admin/custom-emojis-manager.local.list.vue
@@ -76,21 +76,22 @@ import {
 	emptyStrToEmptyArray,
 	emptyStrToNull,
 	emptyStrToUndefined,
-	RequestLogItem,
 	roleIdsParser,
 } from '@/pages/admin/custom-emojis-manager.impl.js';
 import MkGrid from '@/components/grid/MkGrid.vue';
 import { i18n } from '@/i18n.js';
 import MkButton from '@/components/MkButton.vue';
 import { validators } from '@/components/grid/cell-validators.js';
-import { GridCellValidationEvent, GridCellValueChangeEvent, GridEvent } from '@/components/grid/grid-event.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
 import MkPagingButtons from '@/components/MkPagingButtons.vue';
-import { GridSetting } from '@/components/grid/grid.js';
 import { selectFile } from '@/scripts/select-file.js';
 import { copyGridDataToClipboard, removeDataFromGrid } from '@/components/grid/grid-utils.js';
 import { useLoading } from "@/components/hook/useLoading.js";
 
+import type { RequestLogItem } from '@/pages/admin/custom-emojis-manager.impl.js';
+import type { GridCellValidationEvent, GridCellValueChangeEvent, GridEvent } from '@/components/grid/grid-event.js';
+import type { GridSetting } from '@/components/grid/grid.js';
+
 type GridItem = {
 	checked: boolean;
 	id: string;
diff --git a/packages/frontend/src/pages/admin/custom-emojis-manager.local.register.vue b/packages/frontend/src/pages/admin/custom-emojis-manager.local.register.vue
index cc8b625cd5..da85d38a40 100644
--- a/packages/frontend/src/pages/admin/custom-emojis-manager.local.register.vue
+++ b/packages/frontend/src/pages/admin/custom-emojis-manager.local.register.vue
@@ -82,7 +82,6 @@ import { misskeyApi } from '@/scripts/misskey-api.js';
 import {
 	emptyStrToEmptyArray,
 	emptyStrToNull,
-	RequestLogItem,
 	roleIdsParser,
 } from '@/pages/admin/custom-emojis-manager.impl.js';
 import MkGrid from '@/components/grid/MkGrid.vue';
@@ -96,12 +95,15 @@ import * as os from '@/os.js';
 import { validators } from '@/components/grid/cell-validators.js';
 import { chooseFileFromDrive, chooseFileFromPc } from '@/scripts/select-file.js';
 import { uploadFile } from '@/scripts/upload.js';
-import { GridCellValidationEvent, GridCellValueChangeEvent, GridEvent } from '@/components/grid/grid-event.js';
-import { DroppedFile, extractDroppedItems, flattenDroppedFiles } from '@/scripts/file-drop.js';
+import { extractDroppedItems, flattenDroppedFiles } from '@/scripts/file-drop.js';
 import XRegisterLogs from '@/pages/admin/custom-emojis-manager.logs.vue';
-import { GridSetting } from '@/components/grid/grid.js';
 import { copyGridDataToClipboard } from '@/components/grid/grid-utils.js';
-import { GridRow } from '@/components/grid/row.js';
+
+import type { RequestLogItem } from '@/pages/admin/custom-emojis-manager.impl.js';
+import type { GridCellValidationEvent, GridCellValueChangeEvent, GridEvent } from '@/components/grid/grid-event.js';
+import type { DroppedFile } from '@/scripts/file-drop.js';
+import type { GridSetting } from '@/components/grid/grid.js';
+import type { GridRow } from '@/components/grid/row.js';
 
 const MAXIMUM_EMOJI_REGISTER_COUNT = 100;
 
diff --git a/packages/frontend/src/pages/admin/custom-emojis-manager.remote.vue b/packages/frontend/src/pages/admin/custom-emojis-manager.remote.vue
index eecf8d7390..21ffe558ca 100644
--- a/packages/frontend/src/pages/admin/custom-emojis-manager.remote.vue
+++ b/packages/frontend/src/pages/admin/custom-emojis-manager.remote.vue
@@ -148,23 +148,20 @@ import { i18n } from '@/i18n.js';
 import MkButton from '@/components/MkButton.vue';
 import MkInput from '@/components/MkInput.vue';
 import MkGrid from '@/components/grid/MkGrid.vue';
-import {
-	emptyStrToUndefined,
-	GridSortOrderKey,
-	gridSortOrderKeys,
-	RequestLogItem,
-} from '@/pages/admin/custom-emojis-manager.impl.js';
-import { GridCellValueChangeEvent, GridEvent } from '@/components/grid/grid-event.js';
+import { emptyStrToUndefined, gridSortOrderKeys } from '@/pages/admin/custom-emojis-manager.impl.js';
 import MkFolder from '@/components/MkFolder.vue';
 import XRegisterLogs from '@/pages/admin/custom-emojis-manager.logs.vue';
 import * as os from '@/os.js';
-import { GridSetting } from '@/components/grid/grid.js';
 import { deviceKind } from '@/scripts/device-kind.js';
 import MkPagingButtons from '@/components/MkPagingButtons.vue';
 import MkSortOrderEditor from '@/components/MkSortOrderEditor.vue';
-import { SortOrder } from '@/components/MkSortOrderEditor.define.js';
 import { useLoading } from '@/components/hook/useLoading.js';
 
+import type { GridSortOrderKey, RequestLogItem } from '@/pages/admin/custom-emojis-manager.impl.js';
+import type { GridCellValueChangeEvent, GridEvent } from '@/components/grid/grid-event.js';
+import type { GridSetting } from '@/components/grid/grid.js';
+import type { SortOrder } from '@/components/MkSortOrderEditor.define.js';
+
 type GridItem = {
 	checked: boolean;
 	id: string;
diff --git a/packages/frontend/src/pages/admin/custom-emojis-manager2.stories.impl.ts b/packages/frontend/src/pages/admin/custom-emojis-manager2.stories.impl.ts
index f62304277a..3384a71f0f 100644
--- a/packages/frontend/src/pages/admin/custom-emojis-manager2.stories.impl.ts
+++ b/packages/frontend/src/pages/admin/custom-emojis-manager2.stories.impl.ts
@@ -4,7 +4,7 @@
  */
 
 import { delay, http, HttpResponse } from 'msw';
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { entities } from 'misskey-js';
 import { commonHandlers } from '../../../.storybook/mocks.js';
 import { emoji } from '../../../.storybook/fakes.js';
diff --git a/packages/frontend/src/pages/admin/index.vue b/packages/frontend/src/pages/admin/index.vue
index ea5fa457f2..672ee8da18 100644
--- a/packages/frontend/src/pages/admin/index.vue
+++ b/packages/frontend/src/pages/admin/index.vue
@@ -41,7 +41,8 @@ import { lookup } from '@/scripts/lookup.js';
 import * as os from '@/os.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
 import { lookupUser, lookupUserByEmail, lookupFile } from '@/scripts/admin-lookup.js';
-import { PageMetadata, definePageMetadata, provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js';
+import { definePageMetadata, provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js';
+import type { PageMetadata } from '@/scripts/page-metadata.js';
 import { useRouter } from '@/router/supplier.js';
 
 const isEmpty = (x: string | null) => x == null || x === '';
diff --git a/packages/frontend/src/pages/admin/invites.vue b/packages/frontend/src/pages/admin/invites.vue
index 9cb430b0fe..5189e12899 100644
--- a/packages/frontend/src/pages/admin/invites.vue
+++ b/packages/frontend/src/pages/admin/invites.vue
@@ -65,7 +65,8 @@ import MkFolder from '@/components/MkFolder.vue';
 import MkSelect from '@/components/MkSelect.vue';
 import MkInput from '@/components/MkInput.vue';
 import MkSwitch from '@/components/MkSwitch.vue';
-import MkPagination, { Paging } from '@/components/MkPagination.vue';
+import MkPagination from '@/components/MkPagination.vue';
+import type { Paging } from '@/components/MkPagination.vue';
 import MkInviteCode from '@/components/MkInviteCode.vue';
 import { definePageMetadata } from '@/scripts/page-metadata.js';
 
diff --git a/packages/frontend/src/pages/admin/overview.ap-requests.stories.impl.ts b/packages/frontend/src/pages/admin/overview.ap-requests.stories.impl.ts
index 584cd3e4d9..88747ef4ed 100644
--- a/packages/frontend/src/pages/admin/overview.ap-requests.stories.impl.ts
+++ b/packages/frontend/src/pages/admin/overview.ap-requests.stories.impl.ts
@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { http, HttpResponse } from 'msw';
 import { action } from '@storybook/addon-actions';
 import { commonHandlers } from '../../../.storybook/mocks.js';
diff --git a/packages/frontend/src/pages/admin/overview.federation.vue b/packages/frontend/src/pages/admin/overview.federation.vue
index 0896859f3c..7d80f8c2e3 100644
--- a/packages/frontend/src/pages/admin/overview.federation.vue
+++ b/packages/frontend/src/pages/admin/overview.federation.vue
@@ -47,7 +47,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import { onMounted, ref } from 'vue';
-import XPie, { type InstanceForPie } from './overview.pie.vue';
+import XPie from './overview.pie.vue';
+import type { InstanceForPie } from './overview.pie.vue';
 import * as os from '@/os.js';
 import { misskeyApiGet } from '@/scripts/misskey-api.js';
 import number from '@/filters/number.js';
diff --git a/packages/frontend/src/pages/admin/queue.vue b/packages/frontend/src/pages/admin/queue.vue
index 512039242e..1a26c00ddb 100644
--- a/packages/frontend/src/pages/admin/queue.vue
+++ b/packages/frontend/src/pages/admin/queue.vue
@@ -16,7 +16,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
-import { ref, computed, type Ref } from 'vue';
+import { ref, computed } from 'vue';
+import type { Ref } from 'vue';
 import XQueue from './queue.chart.vue';
 import XHeader from './_header_.vue';
 import * as os from '@/os.js';
diff --git a/packages/frontend/src/pages/api-console.vue b/packages/frontend/src/pages/api-console.vue
index 30f12a8fb3..9bddb0a9d2 100644
--- a/packages/frontend/src/pages/api-console.vue
+++ b/packages/frontend/src/pages/api-console.vue
@@ -36,7 +36,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { ref, computed } from 'vue';
 import JSON5 from 'json5';
-import { Endpoints } from 'misskey-js';
+import type { Endpoints } from 'misskey-js';
 import MkButton from '@/components/MkButton.vue';
 import MkInput from '@/components/MkInput.vue';
 import MkTextarea from '@/components/MkTextarea.vue';
diff --git a/packages/frontend/src/pages/channel.vue b/packages/frontend/src/pages/channel.vue
index 655e69461f..4a91165d50 100644
--- a/packages/frontend/src/pages/channel.vue
+++ b/packages/frontend/src/pages/channel.vue
@@ -94,7 +94,7 @@ import MkNote from '@/components/MkNote.vue';
 import MkInfo from '@/components/MkInfo.vue';
 import MkFoldableSection from '@/components/MkFoldableSection.vue';
 import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
-import { PageHeaderItem } from '@/types/page-header.js';
+import type { PageHeaderItem } from '@/types/page-header.js';
 import { isSupportShare } from '@/scripts/navigator.js';
 import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
 import { notesSearchAvailable } from '@/scripts/check-permissions.js';
diff --git a/packages/frontend/src/pages/drive.file.notes.vue b/packages/frontend/src/pages/drive.file.notes.vue
index ca63d43747..d7519896cc 100644
--- a/packages/frontend/src/pages/drive.file.notes.vue
+++ b/packages/frontend/src/pages/drive.file.notes.vue
@@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { ref, computed } from 'vue';
 import { i18n } from '@/i18n.js';
-import { Paging } from '@/components/MkPagination.vue';
+import type { Paging } from '@/components/MkPagination.vue';
 import MkInfo from '@/components/MkInfo.vue';
 import MkNotes from '@/components/MkNotes.vue';
 
diff --git a/packages/frontend/src/pages/drop-and-fusion.game.vue b/packages/frontend/src/pages/drop-and-fusion.game.vue
index fb4d599c28..10099e6291 100644
--- a/packages/frontend/src/pages/drop-and-fusion.game.vue
+++ b/packages/frontend/src/pages/drop-and-fusion.game.vue
@@ -194,7 +194,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 import { computed, onDeactivated, onMounted, onUnmounted, ref, shallowRef, watch } from 'vue';
 import * as Matter from 'matter-js';
 import * as Misskey from 'misskey-js';
-import { DropAndFusionGame, Mono } from 'misskey-bubble-game';
+import { DropAndFusionGame } from 'misskey-bubble-game';
+import type { Mono } from 'misskey-bubble-game';
 import { definePageMetadata } from '@/scripts/page-metadata.js';
 import MkRippleEffect from '@/components/MkRippleEffect.vue';
 import * as os from '@/os.js';
diff --git a/packages/frontend/src/pages/flash/flash.vue b/packages/frontend/src/pages/flash/flash.vue
index 3b982a405e..980e8a21b5 100644
--- a/packages/frontend/src/pages/flash/flash.vue
+++ b/packages/frontend/src/pages/flash/flash.vue
@@ -62,7 +62,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
-import { computed, onDeactivated, onUnmounted, Ref, ref, watch, shallowRef, defineAsyncComponent } from 'vue';
+import { computed, onDeactivated, onUnmounted, ref, watch, shallowRef, defineAsyncComponent } from 'vue';
 import * as Misskey from 'misskey-js';
 import { Interpreter, Parser, values } from '@syuilo/aiscript';
 import MkButton from '@/components/MkButton.vue';
@@ -72,7 +72,7 @@ import { url } from '@@/js/config.js';
 import { i18n } from '@/i18n.js';
 import { definePageMetadata } from '@/scripts/page-metadata.js';
 import MkAsUi from '@/components/MkAsUi.vue';
-import { AsUiComponent, AsUiRoot, registerAsUiLib } from '@/scripts/aiscript/ui.js';
+import { registerAsUiLib } from '@/scripts/aiscript/ui.js';
 import { aiScriptReadline, createAiScriptEnv } from '@/scripts/aiscript/api.js';
 import MkFolder from '@/components/MkFolder.vue';
 import MkCode from '@/components/MkCode.vue';
@@ -80,9 +80,12 @@ import { defaultStore } from '@/store.js';
 import { $i } from '@/account.js';
 import { isSupportShare } from '@/scripts/navigator.js';
 import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
-import type { MenuItem } from '@/types/menu.js';
 import { pleaseLogin } from '@/scripts/please-login.js';
 
+import type { Ref } from 'vue';
+import type { AsUiComponent, AsUiRoot } from '@/scripts/aiscript/ui.js';
+import type { MenuItem } from '@/types/menu.js';
+
 const props = defineProps<{
 	id: string;
 }>();
diff --git a/packages/frontend/src/pages/follow-requests.vue b/packages/frontend/src/pages/follow-requests.vue
index 5d819e7993..863ae018ba 100644
--- a/packages/frontend/src/pages/follow-requests.vue
+++ b/packages/frontend/src/pages/follow-requests.vue
@@ -46,7 +46,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import * as Misskey from 'misskey-js';
 import { shallowRef, computed, ref } from 'vue';
-import MkPagination, { type Paging } from '@/components/MkPagination.vue';
+import MkPagination from '@/components/MkPagination.vue';
+import type { Paging } from '@/components/MkPagination.vue';
 import MkButton from '@/components/MkButton.vue';
 import { userPage, acct } from '@/filters/user.js';
 import * as os from '@/os.js';
diff --git a/packages/frontend/src/pages/install-extensions.vue b/packages/frontend/src/pages/install-extensions.vue
index 6d68ed83b4..58f8b865bb 100644
--- a/packages/frontend/src/pages/install-extensions.vue
+++ b/packages/frontend/src/pages/install-extensions.vue
@@ -46,14 +46,16 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { ref, computed, onActivated, onDeactivated, nextTick } from 'vue';
 import MkLoading from '@/components/global/MkLoading.vue';
-import MkExtensionInstaller, { type Extension } from '@/components/MkExtensionInstaller.vue';
+import MkExtensionInstaller from '@/components/MkExtensionInstaller.vue';
+import type { Extension } from '@/components/MkExtensionInstaller.vue';
 import MkButton from '@/components/MkButton.vue';
 import MkKeyValue from '@/components/MkKeyValue.vue';
 import MkUrl from '@/components/global/MkUrl.vue';
 import FormSection from '@/components/form/section.vue';
 import * as os from '@/os.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
-import { AiScriptPluginMeta, parsePluginMeta, installPlugin } from '@/scripts/install-plugin.js';
+import { parsePluginMeta, installPlugin } from '@/scripts/install-plugin.js';
+import type { AiScriptPluginMeta } from '@/scripts/install-plugin.js';
 import { parseThemeCode, installTheme } from '@/scripts/install-theme.js';
 import { unisonReload } from '@/scripts/unison-reload.js';
 import { i18n } from '@/i18n.js';
diff --git a/packages/frontend/src/pages/instance-info.vue b/packages/frontend/src/pages/instance-info.vue
index 6cec3f9d45..35d1c7dcd1 100644
--- a/packages/frontend/src/pages/instance-info.vue
+++ b/packages/frontend/src/pages/instance-info.vue
@@ -135,7 +135,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { ref, computed, watch } from 'vue';
 import * as Misskey from 'misskey-js';
-import MkChart, { type ChartSrc } from '@/components/MkChart.vue';
+import MkChart from '@/components/MkChart.vue';
+import type { ChartSrc } from '@/components/MkChart.vue';
 import MkObjectView from '@/components/MkObjectView.vue';
 import FormLink from '@/components/form/link.vue';
 import MkLink from '@/components/MkLink.vue';
@@ -151,7 +152,8 @@ import { iAmModerator, iAmAdmin } from '@/account.js';
 import { definePageMetadata } from '@/scripts/page-metadata.js';
 import { i18n } from '@/i18n.js';
 import MkUserCardMini from '@/components/MkUserCardMini.vue';
-import MkPagination, { type Paging } from '@/components/MkPagination.vue';
+import MkPagination from '@/components/MkPagination.vue';
+import type { Paging } from '@/components/MkPagination.vue';
 import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
 import { getProxiedImageUrlNullable } from '@/scripts/media-proxy.js';
 import { dateString } from '@/filters/date.js';
diff --git a/packages/frontend/src/pages/invite.vue b/packages/frontend/src/pages/invite.vue
index 3f6ae27b89..49c0d931c5 100644
--- a/packages/frontend/src/pages/invite.vue
+++ b/packages/frontend/src/pages/invite.vue
@@ -35,12 +35,13 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import { computed, ref, shallowRef } from 'vue';
-import type * as Misskey from 'misskey-js';
+import * as Misskey from 'misskey-js';
 import { i18n } from '@/i18n.js';
 import * as os from '@/os.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
 import MkButton from '@/components/MkButton.vue';
-import MkPagination, { Paging } from '@/components/MkPagination.vue';
+import MkPagination from '@/components/MkPagination.vue';
+import type { Paging } from '@/components/MkPagination.vue';
 import MkInviteCode from '@/components/MkInviteCode.vue';
 import { definePageMetadata } from '@/scripts/page-metadata.js';
 import { serverErrorImageUrl, instance } from '@/instance.js';
diff --git a/packages/frontend/src/pages/scratchpad.vue b/packages/frontend/src/pages/scratchpad.vue
index 88171f7d70..22c06bfc85 100644
--- a/packages/frontend/src/pages/scratchpad.vue
+++ b/packages/frontend/src/pages/scratchpad.vue
@@ -57,7 +57,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
-import { onDeactivated, onUnmounted, Ref, ref, watch, computed } from 'vue';
+import { onDeactivated, onUnmounted, ref, watch, computed } from 'vue';
+import type { Ref } from 'vue';
 import { Interpreter, Parser, utils } from '@syuilo/aiscript';
 import MkContainer from '@/components/MkContainer.vue';
 import MkButton from '@/components/MkButton.vue';
@@ -68,11 +69,14 @@ import * as os from '@/os.js';
 import { $i } from '@/account.js';
 import { i18n } from '@/i18n.js';
 import { definePageMetadata } from '@/scripts/page-metadata.js';
-import { AsUiComponent, AsUiRoot, registerAsUiLib } from '@/scripts/aiscript/ui.js';
+import { registerAsUiLib } from '@/scripts/aiscript/ui.js';
+import type { AsUiComponent } from '@/scripts/aiscript/ui.js';
 import MkAsUi from '@/components/MkAsUi.vue';
 import { miLocalStorage } from '@/local-storage.js';
 import { claimAchievement } from '@/scripts/achievements.js';
 
+import type { AsUiRoot } from '@/scripts/aiscript/ui.js';
+
 const parser = new Parser();
 let aiscript: Interpreter;
 const code = ref('');
diff --git a/packages/frontend/src/pages/search.stories.impl.ts b/packages/frontend/src/pages/search.stories.impl.ts
index 0110a7ab8e..27271615c2 100644
--- a/packages/frontend/src/pages/search.stories.impl.ts
+++ b/packages/frontend/src/pages/search.stories.impl.ts
@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { HttpResponse, http } from 'msw';
 import search_ from './search.vue';
 import { userDetailed } from '@/../.storybook/fakes.js';
diff --git a/packages/frontend/src/pages/settings/accounts.vue b/packages/frontend/src/pages/settings/accounts.vue
index c2588736b3..4a7301f405 100644
--- a/packages/frontend/src/pages/settings/accounts.vue
+++ b/packages/frontend/src/pages/settings/accounts.vue
@@ -29,7 +29,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import { ref, computed } from 'vue';
-import type * as Misskey from 'misskey-js';
+import * as Misskey from 'misskey-js';
 import FormSuspense from '@/components/form/suspense.vue';
 import MkButton from '@/components/MkButton.vue';
 import * as os from '@/os.js';
@@ -38,7 +38,7 @@ import { getAccounts, removeAccount as _removeAccount, login, $i, getAccountWith
 import { i18n } from '@/i18n.js';
 import { definePageMetadata } from '@/scripts/page-metadata.js';
 import MkUserCardMini from '@/components/MkUserCardMini.vue';
-import { MenuItem } from '@/types/menu';
+import type { MenuItem } from '@/types/menu.js';
 
 const storedAccounts = ref<{ id: string, token: string }[] | null>(null);
 const accounts = ref(new Map<string, Misskey.entities.UserDetailed | null>());
diff --git a/packages/frontend/src/pages/settings/drive-cleaner.vue b/packages/frontend/src/pages/settings/drive-cleaner.vue
index 6a13984dd7..c5657fce68 100644
--- a/packages/frontend/src/pages/settings/drive-cleaner.vue
+++ b/packages/frontend/src/pages/settings/drive-cleaner.vue
@@ -48,7 +48,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script setup lang="ts">
-import { computed, ref, watch, type StyleValue } from 'vue';
+import { computed, ref, watch } from 'vue';
+import type { StyleValue } from 'vue';
 import tinycolor from 'tinycolor2';
 import * as os from '@/os.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
diff --git a/packages/frontend/src/pages/settings/emoji-picker.vue b/packages/frontend/src/pages/settings/emoji-picker.vue
index fd3581d114..b16c943676 100644
--- a/packages/frontend/src/pages/settings/emoji-picker.vue
+++ b/packages/frontend/src/pages/settings/emoji-picker.vue
@@ -126,7 +126,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
-import { computed, ref, Ref, watch } from 'vue';
+import { computed, ref, watch } from 'vue';
+import type { Ref } from 'vue';
 import Sortable from 'vuedraggable';
 import MkRadios from '@/components/MkRadios.vue';
 import MkButton from '@/components/MkButton.vue';
diff --git a/packages/frontend/src/pages/settings/index.vue b/packages/frontend/src/pages/settings/index.vue
index b5a6d719d1..bc6d6d0261 100644
--- a/packages/frontend/src/pages/settings/index.vue
+++ b/packages/frontend/src/pages/settings/index.vue
@@ -35,9 +35,11 @@ import MkSuperMenu from '@/components/MkSuperMenu.vue';
 import { signout, $i } from '@/account.js';
 import { clearCache } from '@/scripts/clear-cache.js';
 import { instance } from '@/instance.js';
-import { PageMetadata, definePageMetadata, provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js';
+import { definePageMetadata, provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js';
 import * as os from '@/os.js';
 import { useRouter } from '@/router/supplier.js';
+import type { PageMetadata } from '@/scripts/page-metadata.js';
+import type { SuperMenuDef } from '@/components/MkSuperMenu.vue';
 
 const indexInfo = {
 	title: i18n.ts.settings,
@@ -60,7 +62,7 @@ const ro = new ResizeObserver((entries, observer) => {
 	narrow.value = entries[0].borderBoxSize[0].inlineSize < NARROW_THRESHOLD;
 });
 
-const menuDef = computed(() => [{
+const menuDef = computed<SuperMenuDef[]>(() => [{
 	title: i18n.ts.basicSettings,
 	items: [{
 		icon: 'ti ti-user',
diff --git a/packages/frontend/src/pages/settings/notifications.vue b/packages/frontend/src/pages/settings/notifications.vue
index 8ffe0d6a7a..12af8d93d7 100644
--- a/packages/frontend/src/pages/settings/notifications.vue
+++ b/packages/frontend/src/pages/settings/notifications.vue
@@ -63,7 +63,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import { shallowRef, computed } from 'vue';
-import XNotificationConfig, { type NotificationConfig } from './notifications.notification-config.vue';
+import XNotificationConfig from './notifications.notification-config.vue';
+import type { NotificationConfig } from './notifications.notification-config.vue';
 import FormLink from '@/components/form/link.vue';
 import FormSection from '@/components/form/section.vue';
 import MkFolder from '@/components/MkFolder.vue';
diff --git a/packages/frontend/src/pages/settings/sounds.vue b/packages/frontend/src/pages/settings/sounds.vue
index 9fcf564e55..bf461f173b 100644
--- a/packages/frontend/src/pages/settings/sounds.vue
+++ b/packages/frontend/src/pages/settings/sounds.vue
@@ -38,7 +38,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
-import { Ref, computed, ref } from 'vue';
+import { computed, ref } from 'vue';
+import type { Ref } from 'vue';
 import XSound from './sounds.sound.vue';
 import type { SoundType, OperationType } from '@/scripts/sound.js';
 import type { SoundStore } from '@/store.js';
diff --git a/packages/frontend/src/pages/settings/theme.manage.vue b/packages/frontend/src/pages/settings/theme.manage.vue
index 579ca6b20b..f63f15fc13 100644
--- a/packages/frontend/src/pages/settings/theme.manage.vue
+++ b/packages/frontend/src/pages/settings/theme.manage.vue
@@ -37,7 +37,8 @@ import MkTextarea from '@/components/MkTextarea.vue';
 import MkSelect from '@/components/MkSelect.vue';
 import MkInput from '@/components/MkInput.vue';
 import MkButton from '@/components/MkButton.vue';
-import { Theme, getBuiltinThemesRef } from '@/scripts/theme.js';
+import { getBuiltinThemesRef } from '@/scripts/theme.js';
+import type { Theme } from '@/scripts/theme.js';
 import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
 import * as os from '@/os.js';
 import { getThemes, removeTheme } from '@/theme-store.js';
diff --git a/packages/frontend/src/pages/theme-editor.vue b/packages/frontend/src/pages/theme-editor.vue
index 7025cde879..76567cc403 100644
--- a/packages/frontend/src/pages/theme-editor.vue
+++ b/packages/frontend/src/pages/theme-editor.vue
@@ -87,7 +87,8 @@ import MkTextarea from '@/components/MkTextarea.vue';
 import MkFolder from '@/components/MkFolder.vue';
 
 import { $i } from '@/account.js';
-import { Theme, applyTheme } from '@/scripts/theme.js';
+import { applyTheme } from '@/scripts/theme.js';
+import type { Theme } from '@/scripts/theme.js';
 import { host } from '@@/js/config.js';
 import * as os from '@/os.js';
 import { ColdDeviceStorage, defaultStore } from '@/store.js';
diff --git a/packages/frontend/src/pages/user/activity.following.vue b/packages/frontend/src/pages/user/activity.following.vue
index aa2c791c76..7b74ea67ca 100644
--- a/packages/frontend/src/pages/user/activity.following.vue
+++ b/packages/frontend/src/pages/user/activity.following.vue
@@ -15,7 +15,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import { onMounted, shallowRef, ref } from 'vue';
-import { Chart, ChartDataset } from 'chart.js';
+import { Chart } from 'chart.js';
+import type { ChartDataset } from 'chart.js';
 import * as Misskey from 'misskey-js';
 import gradient from 'chartjs-plugin-gradient';
 import { misskeyApi } from '@/scripts/misskey-api.js';
diff --git a/packages/frontend/src/pages/user/activity.notes.vue b/packages/frontend/src/pages/user/activity.notes.vue
index 64514716d6..8c7484ae08 100644
--- a/packages/frontend/src/pages/user/activity.notes.vue
+++ b/packages/frontend/src/pages/user/activity.notes.vue
@@ -15,7 +15,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import { onMounted, shallowRef, ref } from 'vue';
-import { Chart, ChartDataset } from 'chart.js';
+import { Chart } from 'chart.js';
+import type { ChartDataset } from 'chart.js';
 import * as Misskey from 'misskey-js';
 import gradient from 'chartjs-plugin-gradient';
 import { misskeyApi } from '@/scripts/misskey-api.js';
diff --git a/packages/frontend/src/pages/user/activity.pv.vue b/packages/frontend/src/pages/user/activity.pv.vue
index ce24807f93..a073626cbb 100644
--- a/packages/frontend/src/pages/user/activity.pv.vue
+++ b/packages/frontend/src/pages/user/activity.pv.vue
@@ -15,7 +15,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import { onMounted, shallowRef, ref } from 'vue';
-import { Chart, ChartDataset } from 'chart.js';
+import { Chart } from 'chart.js';
+import type { ChartDataset } from 'chart.js';
 import * as Misskey from 'misskey-js';
 import gradient from 'chartjs-plugin-gradient';
 import { misskeyApi } from '@/scripts/misskey-api.js';
diff --git a/packages/frontend/src/pages/user/home.stories.impl.ts b/packages/frontend/src/pages/user/home.stories.impl.ts
index c623ef9ee4..66d3579041 100644
--- a/packages/frontend/src/pages/user/home.stories.impl.ts
+++ b/packages/frontend/src/pages/user/home.stories.impl.ts
@@ -4,7 +4,7 @@
  */
 
 /* eslint-disable @typescript-eslint/explicit-function-return-type */
-import { StoryObj } from '@storybook/vue3';
+import type { StoryObj } from '@storybook/vue3';
 import { HttpResponse, http } from 'msw';
 import { userDetailed } from '../../../.storybook/fakes.js';
 import { commonHandlers } from '../../../.storybook/mocks.js';
diff --git a/packages/frontend/src/pizzax.ts b/packages/frontend/src/pizzax.ts
index 7740fe0d39..e94210363a 100644
--- a/packages/frontend/src/pizzax.ts
+++ b/packages/frontend/src/pizzax.ts
@@ -5,7 +5,8 @@
 
 // PIZZAX --- A lightweight store
 
-import { onUnmounted, Ref, ref, watch } from 'vue';
+import { onUnmounted, ref, watch } from 'vue';
+import type { Ref } from 'vue';
 import { BroadcastChannel } from 'broadcast-channel';
 import { $i } from '@/account.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
diff --git a/packages/frontend/src/plugin.ts b/packages/frontend/src/plugin.ts
index 81233a5a5e..e319a8c398 100644
--- a/packages/frontend/src/plugin.ts
+++ b/packages/frontend/src/plugin.ts
@@ -7,7 +7,8 @@ import { ref } from 'vue';
 import { Interpreter, Parser, utils, values } from '@syuilo/aiscript';
 import { aiScriptReadline, createAiScriptEnv } from '@/scripts/aiscript/api.js';
 import { inputText } from '@/os.js';
-import { Plugin, noteActions, notePostInterruptors, noteViewInterruptors, postFormActions, userActions, pageViewInterruptors } from '@/store.js';
+import { noteActions, notePostInterruptors, noteViewInterruptors, postFormActions, userActions, pageViewInterruptors } from '@/store.js';
+import type { Plugin } from '@/store.js';
 
 const parser = new Parser();
 const pluginContexts = new Map<string, Interpreter>();
diff --git a/packages/frontend/src/router/definition.ts b/packages/frontend/src/router/definition.ts
index 217954a7bb..d2a4484c45 100644
--- a/packages/frontend/src/router/definition.ts
+++ b/packages/frontend/src/router/definition.ts
@@ -3,7 +3,8 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { AsyncComponentLoader, defineAsyncComponent } from 'vue';
+import { defineAsyncComponent } from 'vue';
+import type { AsyncComponentLoader } from 'vue';
 import type { IRouter, RouteDef } from '@/nirax.js';
 import { Router } from '@/nirax.js';
 import { $i, iAmModerator } from '@/account.js';
diff --git a/packages/frontend/src/router/main.ts b/packages/frontend/src/router/main.ts
index 3c25e80d12..4379b6a316 100644
--- a/packages/frontend/src/router/main.ts
+++ b/packages/frontend/src/router/main.ts
@@ -4,7 +4,7 @@
  */
 
 import { EventEmitter } from 'eventemitter3';
-import { IRouter, Resolved, RouteDef, RouterEvent, RouterFlag } from '@/nirax.js';
+import type { IRouter, Resolved, RouteDef, RouterEvent, RouterFlag } from '@/nirax.js';
 
 import type { App, ShallowRef } from 'vue';
 
diff --git a/packages/frontend/src/router/supplier.ts b/packages/frontend/src/router/supplier.ts
index 7da236f4e7..87f8829854 100644
--- a/packages/frontend/src/router/supplier.ts
+++ b/packages/frontend/src/router/supplier.ts
@@ -4,7 +4,8 @@
  */
 
 import { inject } from 'vue';
-import { IRouter, Router } from '@/nirax.js';
+import { Router } from '@/nirax.js';
+import type { IRouter } from '@/nirax.js';
 import { mainRouter } from '@/router/main.js';
 
 /**
diff --git a/packages/frontend/src/scripts/aiscript/common.ts b/packages/frontend/src/scripts/aiscript/common.ts
index de6fa1d633..ba5dfb8368 100644
--- a/packages/frontend/src/scripts/aiscript/common.ts
+++ b/packages/frontend/src/scripts/aiscript/common.ts
@@ -3,7 +3,8 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { errors, utils, type values } from '@syuilo/aiscript';
+import { errors, utils } from '@syuilo/aiscript';
+import type { values } from '@syuilo/aiscript';
 
 export function assertStringAndIsIn<A extends readonly string[]>(value: values.Value | undefined, expects: A): asserts value is values.VStr & { value: A[number] } {
 	utils.assertString(value);
diff --git a/packages/frontend/src/scripts/aiscript/ui.ts b/packages/frontend/src/scripts/aiscript/ui.ts
index ca92b27ff5..46e193f7c1 100644
--- a/packages/frontend/src/scripts/aiscript/ui.ts
+++ b/packages/frontend/src/scripts/aiscript/ui.ts
@@ -5,7 +5,8 @@
 
 import { utils, values } from '@syuilo/aiscript';
 import { v4 as uuid } from 'uuid';
-import { ref, Ref } from 'vue';
+import { ref } from 'vue';
+import type { Ref } from 'vue';
 import * as Misskey from 'misskey-js';
 import { assertStringAndIsIn } from './common.js';
 
diff --git a/packages/frontend/src/scripts/autocomplete.ts b/packages/frontend/src/scripts/autocomplete.ts
index 7766c44c04..55015c90fd 100644
--- a/packages/frontend/src/scripts/autocomplete.ts
+++ b/packages/frontend/src/scripts/autocomplete.ts
@@ -3,7 +3,8 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { nextTick, Ref, ref, defineAsyncComponent } from 'vue';
+import { nextTick, ref, defineAsyncComponent } from 'vue';
+import type { Ref } from 'vue';
 import getCaretCoordinates from 'textarea-caret';
 import { toASCII } from 'punycode.js';
 import { popup } from '@/os.js';
diff --git a/packages/frontend/src/scripts/chart-legend.ts b/packages/frontend/src/scripts/chart-legend.ts
index 2d534f60c1..e701d18dd2 100644
--- a/packages/frontend/src/scripts/chart-legend.ts
+++ b/packages/frontend/src/scripts/chart-legend.ts
@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { Plugin } from 'chart.js';
+import type { Plugin } from 'chart.js';
 import MkChartLegend from '@/components/MkChartLegend.vue';
 
 export const chartLegend = (legend: InstanceType<typeof MkChartLegend>) => ({
diff --git a/packages/frontend/src/scripts/chart-vline.ts b/packages/frontend/src/scripts/chart-vline.ts
index 24e41245e7..465ca591c6 100644
--- a/packages/frontend/src/scripts/chart-vline.ts
+++ b/packages/frontend/src/scripts/chart-vline.ts
@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { Plugin } from 'chart.js';
+import type { Plugin } from 'chart.js';
 
 export const chartVLine = (vLineColor: string) => ({
 	id: 'vLine',
diff --git a/packages/frontend/src/scripts/check-reaction-permissions.ts b/packages/frontend/src/scripts/check-reaction-permissions.ts
index c3c3f419a9..281ea2520e 100644
--- a/packages/frontend/src/scripts/check-reaction-permissions.ts
+++ b/packages/frontend/src/scripts/check-reaction-permissions.ts
@@ -4,7 +4,7 @@
  */
 
 import * as Misskey from 'misskey-js';
-import { UnicodeEmojiDef } from '@@/js/emojilist.js';
+import type { UnicodeEmojiDef } from '@@/js/emojilist.js';
 
 export function checkReactionPermissions(me: Misskey.entities.MeDetailed, note: Misskey.entities.Note, emoji: Misskey.entities.EmojiSimple | UnicodeEmojiDef | string): boolean {
 	if (typeof emoji === 'string') return true; // UnicodeEmojiDefにも無い絵文字であれば文字列で来る。Unicode絵文字であることには変わりないので常にリアクション可能とする;
diff --git a/packages/frontend/src/scripts/emoji-picker.ts b/packages/frontend/src/scripts/emoji-picker.ts
index 14b5cbf35e..e704b5fd6f 100644
--- a/packages/frontend/src/scripts/emoji-picker.ts
+++ b/packages/frontend/src/scripts/emoji-picker.ts
@@ -3,7 +3,8 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { defineAsyncComponent, Ref, ref } from 'vue';
+import { defineAsyncComponent, ref } from 'vue';
+import type { Ref } from 'vue';
 import { popup } from '@/os.js';
 import { defaultStore } from '@/store.js';
 
diff --git a/packages/frontend/src/scripts/get-note-menu.ts b/packages/frontend/src/scripts/get-note-menu.ts
index bc504077b0..23fe811525 100644
--- a/packages/frontend/src/scripts/get-note-menu.ts
+++ b/packages/frontend/src/scripts/get-note-menu.ts
@@ -3,7 +3,8 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { defineAsyncComponent, Ref, ShallowRef } from 'vue';
+import { defineAsyncComponent } from 'vue';
+import type { Ref, ShallowRef } from 'vue';
 import * as Misskey from 'misskey-js';
 import { url } from '@@/js/config.js';
 import { claimAchievement } from './achievements.js';
diff --git a/packages/frontend/src/scripts/get-user-menu.ts b/packages/frontend/src/scripts/get-user-menu.ts
index 94a1d4c855..8f7c3ba3be 100644
--- a/packages/frontend/src/scripts/get-user-menu.ts
+++ b/packages/frontend/src/scripts/get-user-menu.ts
@@ -14,7 +14,7 @@ import { misskeyApi } from '@/scripts/misskey-api.js';
 import { defaultStore, userActions } from '@/store.js';
 import { $i, iAmModerator } from '@/account.js';
 import { notesSearchAvailable, canSearchNonLocalNotes } from '@/scripts/check-permissions.js';
-import { IRouter } from '@/nirax.js';
+import type { IRouter } from '@/nirax.js';
 import { antennasCache, rolesCache, userListsCache } from '@/cache.js';
 import { mainRouter } from '@/router/main.js';
 import { genEmbedCode } from '@/scripts/get-embed-code.js';
diff --git a/packages/frontend/src/scripts/install-theme.ts b/packages/frontend/src/scripts/install-theme.ts
index 866f1225bf..cc32adcc6a 100644
--- a/packages/frontend/src/scripts/install-theme.ts
+++ b/packages/frontend/src/scripts/install-theme.ts
@@ -5,7 +5,8 @@
 
 import JSON5 from 'json5';
 import { addTheme, getThemes } from '@/theme-store.js';
-import { Theme, applyTheme, validateTheme } from '@/scripts/theme.js';
+import { applyTheme, validateTheme } from '@/scripts/theme.js';
+import type { Theme } from '@/scripts/theme.js';
 
 export function parseThemeCode(code: string): Theme {
 	let theme;
diff --git a/packages/frontend/src/scripts/mfm-function-picker.ts b/packages/frontend/src/scripts/mfm-function-picker.ts
index bf59fe98a0..a2f777f623 100644
--- a/packages/frontend/src/scripts/mfm-function-picker.ts
+++ b/packages/frontend/src/scripts/mfm-function-picker.ts
@@ -3,7 +3,8 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { Ref, nextTick } from 'vue';
+import { nextTick } from 'vue';
+import type { Ref } from 'vue';
 import * as os from '@/os.js';
 import { i18n } from '@/i18n.js';
 import { MFM_TAGS } from '@@/js/const.js';
diff --git a/packages/frontend/src/scripts/page-metadata.ts b/packages/frontend/src/scripts/page-metadata.ts
index 0e3b093ecf..671751147c 100644
--- a/packages/frontend/src/scripts/page-metadata.ts
+++ b/packages/frontend/src/scripts/page-metadata.ts
@@ -4,7 +4,8 @@
  */
 
 import * as Misskey from 'misskey-js';
-import { MaybeRefOrGetter, Ref, inject, isRef, onActivated, onBeforeUnmount, provide, ref, toValue, watch } from 'vue';
+import { inject, isRef, onActivated, onBeforeUnmount, provide, ref, toValue, watch } from 'vue';
+import type { MaybeRefOrGetter, Ref } from 'vue';
 
 export type PageMetadata = {
 	title: string;
diff --git a/packages/frontend/src/scripts/reaction-picker.ts b/packages/frontend/src/scripts/reaction-picker.ts
index 7aec05c0cf..c142b3ed2a 100644
--- a/packages/frontend/src/scripts/reaction-picker.ts
+++ b/packages/frontend/src/scripts/reaction-picker.ts
@@ -4,7 +4,8 @@
  */
 
 import * as Misskey from 'misskey-js';
-import { defineAsyncComponent, Ref, ref } from 'vue';
+import { defineAsyncComponent, ref } from 'vue';
+import type { Ref } from 'vue';
 import { popup } from '@/os.js';
 import { defaultStore } from '@/store.js';
 
diff --git a/packages/frontend/src/scripts/theme-editor.ts b/packages/frontend/src/scripts/theme-editor.ts
index 0092af1640..0206e378bf 100644
--- a/packages/frontend/src/scripts/theme-editor.ts
+++ b/packages/frontend/src/scripts/theme-editor.ts
@@ -5,7 +5,8 @@
 
 import { v4 as uuid } from 'uuid';
 
-import { themeProps, Theme } from './theme.js';
+import { themeProps } from './theme.js';
+import type { Theme } from './theme.js';
 
 export type Default = null;
 export type Color = string;
diff --git a/packages/frontend/src/scripts/use-form.ts b/packages/frontend/src/scripts/use-form.ts
index 0d505fe466..26cca839c3 100644
--- a/packages/frontend/src/scripts/use-form.ts
+++ b/packages/frontend/src/scripts/use-form.ts
@@ -3,7 +3,8 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { computed, Reactive, reactive, watch } from 'vue';
+import { computed, reactive, watch } from 'vue';
+import type { Reactive } from 'vue';
 
 function copy<T>(v: T): T {
 	return JSON.parse(JSON.stringify(v));
diff --git a/packages/frontend/src/scripts/use-leave-guard.ts b/packages/frontend/src/scripts/use-leave-guard.ts
index 5f7e56e8a9..395c12a756 100644
--- a/packages/frontend/src/scripts/use-leave-guard.ts
+++ b/packages/frontend/src/scripts/use-leave-guard.ts
@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { Ref } from 'vue';
+import type { Ref } from 'vue';
 
 export function useLeaveGuard(enabled: Ref<boolean>) {
 	/* TODO
diff --git a/packages/frontend/src/scripts/use-note-capture.ts b/packages/frontend/src/scripts/use-note-capture.ts
index 542d8ab52b..0bc10e90e4 100644
--- a/packages/frontend/src/scripts/use-note-capture.ts
+++ b/packages/frontend/src/scripts/use-note-capture.ts
@@ -3,7 +3,8 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { onUnmounted, Ref, ShallowRef } from 'vue';
+import { onUnmounted } from 'vue';
+import type { Ref, ShallowRef } from 'vue';
 import * as Misskey from 'misskey-js';
 import { useStream } from '@/stream.js';
 import { $i } from '@/account.js';
diff --git a/packages/frontend/src/scripts/use-tooltip.ts b/packages/frontend/src/scripts/use-tooltip.ts
index a26d08cce7..d9ddfc8b5d 100644
--- a/packages/frontend/src/scripts/use-tooltip.ts
+++ b/packages/frontend/src/scripts/use-tooltip.ts
@@ -3,7 +3,8 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { Ref, ref, watch, onUnmounted } from 'vue';
+import { ref, watch, onUnmounted } from 'vue';
+import type { Ref } from 'vue';
 
 export function useTooltip(
 	elRef: Ref<HTMLElement | { $el: HTMLElement } | null | undefined>,
diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts
index dbe90dba86..e9650bcf1f 100644
--- a/packages/frontend/src/store.ts
+++ b/packages/frontend/src/store.ts
@@ -10,7 +10,8 @@ import lightTheme from '@@/themes/l-light.json5';
 import darkTheme from '@@/themes/d-green-lime.json5';
 import type { SoundType } from '@/scripts/sound.js';
 import type { Ast } from '@syuilo/aiscript';
-import { DEFAULT_DEVICE_KIND, type DeviceKind } from '@/scripts/device-kind.js';
+import { DEFAULT_DEVICE_KIND } from '@/scripts/device-kind.js';
+import type { DeviceKind } from '@/scripts/device-kind.js';
 import { miLocalStorage } from '@/local-storage.js';
 import { Storage } from '@/pizzax.js';
 
diff --git a/packages/frontend/src/theme-store.ts b/packages/frontend/src/theme-store.ts
index c41cc17652..fb010ae426 100644
--- a/packages/frontend/src/theme-store.ts
+++ b/packages/frontend/src/theme-store.ts
@@ -3,7 +3,8 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { Theme, getBuiltinThemes } from '@/scripts/theme.js';
+import { getBuiltinThemes } from '@/scripts/theme.js';
+import type { Theme } from '@/scripts/theme.js';
 import { miLocalStorage } from '@/local-storage.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
 import { $i } from '@/account.js';
diff --git a/packages/frontend/src/types/menu.ts b/packages/frontend/src/types/menu.ts
index 138eb7dd62..046799536f 100644
--- a/packages/frontend/src/types/menu.ts
+++ b/packages/frontend/src/types/menu.ts
@@ -4,7 +4,7 @@
  */
 
 import * as Misskey from 'misskey-js';
-import { ComputedRef, Ref } from 'vue';
+import type { ComputedRef, Ref } from 'vue';
 
 interface MenuRadioOptionsDef extends Record<string, any> { }
 
diff --git a/packages/frontend/src/ui/classic.vue b/packages/frontend/src/ui/classic.vue
index 5ea9bf7068..da5059bb59 100644
--- a/packages/frontend/src/ui/classic.vue
+++ b/packages/frontend/src/ui/classic.vue
@@ -52,7 +52,8 @@ import XCommon from './_common_/common.vue';
 import { instanceName } from '@@/js/config.js';
 import { StickySidebar } from '@/scripts/sticky-sidebar.js';
 import * as os from '@/os.js';
-import { PageMetadata, provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js';
+import { provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js';
+import type { PageMetadata } from '@/scripts/page-metadata.js';
 import { defaultStore } from '@/store.js';
 import { i18n } from '@/i18n.js';
 import { miLocalStorage } from '@/local-storage.js';
diff --git a/packages/frontend/src/ui/deck/antenna-column.vue b/packages/frontend/src/ui/deck/antenna-column.vue
index a41639e71c..07ae17b982 100644
--- a/packages/frontend/src/ui/deck/antenna-column.vue
+++ b/packages/frontend/src/ui/deck/antenna-column.vue
@@ -17,14 +17,15 @@ SPDX-License-Identifier: AGPL-3.0-only
 import { onMounted, ref, shallowRef, watch, defineAsyncComponent } from 'vue';
 import type { entities as MisskeyEntities } from 'misskey-js';
 import XColumn from './column.vue';
-import { updateColumn, Column } from './deck-store.js';
+import { updateColumn } from './deck-store.js';
+import type { Column } from './deck-store.js';
 import MkTimeline from '@/components/MkTimeline.vue';
 import * as os from '@/os.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
 import { i18n } from '@/i18n.js';
 import type { MenuItem } from '@/types/menu.js';
 import { antennasCache } from '@/cache.js';
-import { SoundStore } from '@/store.js';
+import type { SoundStore } from '@/store.js';
 import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js';
 import * as sound from '@/scripts/sound.js';
 
diff --git a/packages/frontend/src/ui/deck/channel-column.vue b/packages/frontend/src/ui/deck/channel-column.vue
index 5479b53d90..d656eec60a 100644
--- a/packages/frontend/src/ui/deck/channel-column.vue
+++ b/packages/frontend/src/ui/deck/channel-column.vue
@@ -22,7 +22,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 import { ref, shallowRef, watch } from 'vue';
 import * as Misskey from 'misskey-js';
 import XColumn from './column.vue';
-import { updateColumn, Column } from './deck-store.js';
+import { updateColumn } from './deck-store.js';
+import type { Column } from './deck-store.js';
 import MkTimeline from '@/components/MkTimeline.vue';
 import MkButton from '@/components/MkButton.vue';
 import * as os from '@/os.js';
@@ -30,7 +31,7 @@ import { favoritedChannelsCache } from '@/cache.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
 import { i18n } from '@/i18n.js';
 import type { MenuItem } from '@/types/menu.js';
-import { SoundStore } from '@/store.js';
+import type { SoundStore } from '@/store.js';
 import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js';
 import * as sound from '@/scripts/sound.js';
 
diff --git a/packages/frontend/src/ui/deck/column.vue b/packages/frontend/src/ui/deck/column.vue
index da0bf24a56..34d7b2d4b5 100644
--- a/packages/frontend/src/ui/deck/column.vue
+++ b/packages/frontend/src/ui/deck/column.vue
@@ -43,9 +43,10 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import { onBeforeUnmount, onMounted, provide, watch, shallowRef, ref, computed } from 'vue';
-import { updateColumn, swapLeftColumn, swapRightColumn, swapUpColumn, swapDownColumn, stackLeftColumn, popRightColumn, removeColumn, swapColumn, Column } from './deck-store.js';
+import { updateColumn, swapLeftColumn, swapRightColumn, swapUpColumn, swapDownColumn, stackLeftColumn, popRightColumn, removeColumn, swapColumn } from './deck-store.js';
 import * as os from '@/os.js';
 import { i18n } from '@/i18n.js';
+import type { Column } from './deck-store.js';
 import type { MenuItem } from '@/types/menu.js';
 
 provide('shouldHeaderThin', true);
diff --git a/packages/frontend/src/ui/deck/deck-store.ts b/packages/frontend/src/ui/deck/deck-store.ts
index 231bf19aa8..002d409f78 100644
--- a/packages/frontend/src/ui/deck/deck-store.ts
+++ b/packages/frontend/src/ui/deck/deck-store.ts
@@ -10,7 +10,7 @@ import type { BasicTimelineType } from '@/timelines.js';
 import { Storage } from '@/pizzax.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
 import { deepClone } from '@/scripts/clone.js';
-import { SoundStore } from '@/store.js';
+import type { SoundStore } from '@/store.js';
 
 type ColumnWidget = {
 	name: string;
diff --git a/packages/frontend/src/ui/deck/direct-column.vue b/packages/frontend/src/ui/deck/direct-column.vue
index d12a18f760..4337397c2a 100644
--- a/packages/frontend/src/ui/deck/direct-column.vue
+++ b/packages/frontend/src/ui/deck/direct-column.vue
@@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { ref } from 'vue';
 import XColumn from './column.vue';
-import { Column } from './deck-store.js';
+import type { Column } from './deck-store.js';
 import MkNotes from '@/components/MkNotes.vue';
 
 defineProps<{
diff --git a/packages/frontend/src/ui/deck/list-column.vue b/packages/frontend/src/ui/deck/list-column.vue
index 8bb8fe7225..a22a8743b4 100644
--- a/packages/frontend/src/ui/deck/list-column.vue
+++ b/packages/frontend/src/ui/deck/list-column.vue
@@ -17,13 +17,14 @@ SPDX-License-Identifier: AGPL-3.0-only
 import { watch, shallowRef, ref } from 'vue';
 import type { entities as MisskeyEntities } from 'misskey-js';
 import XColumn from './column.vue';
-import { updateColumn, Column } from './deck-store.js';
+import { updateColumn } from './deck-store.js';
+import type { Column } from './deck-store.js';
 import MkTimeline from '@/components/MkTimeline.vue';
 import * as os from '@/os.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
 import { i18n } from '@/i18n.js';
 import type { MenuItem } from '@/types/menu.js';
-import { SoundStore } from '@/store.js';
+import type { SoundStore } from '@/store.js';
 import { userListsCache } from '@/cache.js';
 import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js';
 import * as sound from '@/scripts/sound.js';
diff --git a/packages/frontend/src/ui/deck/main-column.vue b/packages/frontend/src/ui/deck/main-column.vue
index f8c712c371..45c39a5cad 100644
--- a/packages/frontend/src/ui/deck/main-column.vue
+++ b/packages/frontend/src/ui/deck/main-column.vue
@@ -21,10 +21,12 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { provide, shallowRef, ref } from 'vue';
 import XColumn from './column.vue';
-import { deckStore, Column } from '@/ui/deck/deck-store.js';
+import { deckStore } from '@/ui/deck/deck-store.js';
+import type { Column } from '@/ui/deck/deck-store.js';
 import * as os from '@/os.js';
 import { i18n } from '@/i18n.js';
-import { PageMetadata, provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js';
+import { provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js';
+import type { PageMetadata } from '@/scripts/page-metadata.js';
 import { useScrollPositionManager } from '@/nirax.js';
 import { getScrollContainer } from '@@/js/scroll.js';
 import { isLink } from '@@/js/is-link.js';
diff --git a/packages/frontend/src/ui/deck/mentions-column.vue b/packages/frontend/src/ui/deck/mentions-column.vue
index 7b25a55ec3..fde02eaf5b 100644
--- a/packages/frontend/src/ui/deck/mentions-column.vue
+++ b/packages/frontend/src/ui/deck/mentions-column.vue
@@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { ref } from 'vue';
 import XColumn from './column.vue';
-import { Column } from './deck-store.js';
+import type { Column } from './deck-store.js';
 import MkNotes from '@/components/MkNotes.vue';
 
 defineProps<{
diff --git a/packages/frontend/src/ui/deck/notifications-column.vue b/packages/frontend/src/ui/deck/notifications-column.vue
index 19ccfc1f7c..fdf80ea987 100644
--- a/packages/frontend/src/ui/deck/notifications-column.vue
+++ b/packages/frontend/src/ui/deck/notifications-column.vue
@@ -14,7 +14,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { defineAsyncComponent, shallowRef } from 'vue';
 import XColumn from './column.vue';
-import { updateColumn, Column } from './deck-store.js';
+import { updateColumn } from './deck-store.js';
+import type { Column } from './deck-store.js';
 import XNotifications from '@/components/MkNotifications.vue';
 import * as os from '@/os.js';
 import { i18n } from '@/i18n.js';
diff --git a/packages/frontend/src/ui/deck/role-timeline-column.vue b/packages/frontend/src/ui/deck/role-timeline-column.vue
index beb4237978..8fb0729bf2 100644
--- a/packages/frontend/src/ui/deck/role-timeline-column.vue
+++ b/packages/frontend/src/ui/deck/role-timeline-column.vue
@@ -16,13 +16,14 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { onMounted, ref, shallowRef, watch } from 'vue';
 import XColumn from './column.vue';
-import { updateColumn, Column } from './deck-store.js';
+import { updateColumn } from './deck-store.js';
+import type { Column } from './deck-store.js';
 import MkTimeline from '@/components/MkTimeline.vue';
 import * as os from '@/os.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
 import { i18n } from '@/i18n.js';
 import type { MenuItem } from '@/types/menu.js';
-import { SoundStore } from '@/store.js';
+import type { SoundStore } from '@/store.js';
 import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js';
 import * as sound from '@/scripts/sound.js';
 
diff --git a/packages/frontend/src/ui/deck/tl-column.vue b/packages/frontend/src/ui/deck/tl-column.vue
index 74c4fb504b..99f6482457 100644
--- a/packages/frontend/src/ui/deck/tl-column.vue
+++ b/packages/frontend/src/ui/deck/tl-column.vue
@@ -34,14 +34,15 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { onMounted, watch, ref, shallowRef, computed } from 'vue';
 import XColumn from './column.vue';
-import { removeColumn, updateColumn, Column } from './deck-store.js';
+import { removeColumn, updateColumn } from './deck-store.js';
+import type { Column } from './deck-store.js';
 import type { MenuItem } from '@/types/menu.js';
 import MkTimeline from '@/components/MkTimeline.vue';
 import * as os from '@/os.js';
 import { i18n } from '@/i18n.js';
 import { hasWithReplies, isAvailableBasicTimeline, basicTimelineIconClass } from '@/timelines.js';
 import { instance } from '@/instance.js';
-import { SoundStore } from '@/store.js';
+import type { SoundStore } from '@/store.js';
 import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js';
 import * as sound from '@/scripts/sound.js';
 
diff --git a/packages/frontend/src/ui/deck/tl-note-notification.ts b/packages/frontend/src/ui/deck/tl-note-notification.ts
index 275ea56ba0..03d4b3a580 100644
--- a/packages/frontend/src/ui/deck/tl-note-notification.ts
+++ b/packages/frontend/src/ui/deck/tl-note-notification.ts
@@ -4,9 +4,10 @@
  */
 
 import * as Misskey from 'misskey-js';
-import { Ref } from 'vue';
-import { SoundStore } from '@/store.js';
-import { getSoundDuration, playMisskeySfxFile, soundsTypes, SoundType } from '@/scripts/sound.js';
+import type { Ref } from 'vue';
+import type { SoundStore } from '@/store.js';
+import type { SoundType } from '@/scripts/sound.js';
+import { getSoundDuration, playMisskeySfxFile, soundsTypes } from '@/scripts/sound.js';
 import { i18n } from '@/i18n.js';
 import * as os from '@/os.js';
 
diff --git a/packages/frontend/src/ui/deck/widgets-column.vue b/packages/frontend/src/ui/deck/widgets-column.vue
index a0e62c8264..a4d72b9255 100644
--- a/packages/frontend/src/ui/deck/widgets-column.vue
+++ b/packages/frontend/src/ui/deck/widgets-column.vue
@@ -17,7 +17,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { ref } from 'vue';
 import XColumn from './column.vue';
-import { addColumnWidget, Column, removeColumnWidget, setColumnWidgets, updateColumnWidget } from './deck-store.js';
+import { addColumnWidget, removeColumnWidget, setColumnWidgets, updateColumnWidget } from './deck-store.js';
+import type { Column } from './deck-store.js';
 import XWidgets from '@/components/MkWidgets.vue';
 import { i18n } from '@/i18n.js';
 
diff --git a/packages/frontend/src/ui/minimum.vue b/packages/frontend/src/ui/minimum.vue
index 9e41c48c5b..5cbcd69b2c 100644
--- a/packages/frontend/src/ui/minimum.vue
+++ b/packages/frontend/src/ui/minimum.vue
@@ -16,7 +16,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { computed, provide, ref } from 'vue';
 import XCommon from './_common_/common.vue';
-import { PageMetadata, provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js';
+import { provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js';
+import type { PageMetadata } from '@/scripts/page-metadata.js';
 import { instanceName } from '@@/js/config.js';
 import { mainRouter } from '@/router/main.js';
 
diff --git a/packages/frontend/src/ui/universal.vue b/packages/frontend/src/ui/universal.vue
index 94998b7be6..9fff5efe51 100644
--- a/packages/frontend/src/ui/universal.vue
+++ b/packages/frontend/src/ui/universal.vue
@@ -95,7 +95,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
-import { defineAsyncComponent, provide, onMounted, computed, ref, watch, shallowRef, Ref } from 'vue';
+import { defineAsyncComponent, provide, onMounted, computed, ref, watch, shallowRef } from 'vue';
+import type { Ref } from 'vue';
 import { instanceName } from '@@/js/config.js';
 import { CURRENT_STICKY_BOTTOM } from '@@/js/const.js';
 import { isLink } from '@@/js/is-link.js';
@@ -107,7 +108,8 @@ import { defaultStore } from '@/store.js';
 import { navbarItemDef } from '@/navbar.js';
 import { i18n } from '@/i18n.js';
 import { $i } from '@/account.js';
-import { PageMetadata, provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js';
+import { provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js';
+import type { PageMetadata } from '@/scripts/page-metadata.js';
 import { deviceKind } from '@/scripts/device-kind.js';
 import { miLocalStorage } from '@/local-storage.js';
 import { useScrollPositionManager } from '@/nirax.js';
diff --git a/packages/frontend/src/ui/visitor.vue b/packages/frontend/src/ui/visitor.vue
index 7d8677e3be..8bcb260677 100644
--- a/packages/frontend/src/ui/visitor.vue
+++ b/packages/frontend/src/ui/visitor.vue
@@ -77,7 +77,8 @@ import { instance } from '@/instance.js';
 import XSigninDialog from '@/components/MkSigninDialog.vue';
 import XSignupDialog from '@/components/MkSignupDialog.vue';
 import { ColdDeviceStorage, defaultStore } from '@/store.js';
-import { PageMetadata, provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js';
+import { provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js';
+import type { PageMetadata } from '@/scripts/page-metadata.js';
 import { i18n } from '@/i18n.js';
 import MkVisitorDashboard from '@/components/MkVisitorDashboard.vue';
 import { mainRouter } from '@/router/main.js';
diff --git a/packages/frontend/src/ui/zen.vue b/packages/frontend/src/ui/zen.vue
index 1f73b5fcaf..2e31d056c1 100644
--- a/packages/frontend/src/ui/zen.vue
+++ b/packages/frontend/src/ui/zen.vue
@@ -24,7 +24,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { computed, provide, ref } from 'vue';
 import XCommon from './_common_/common.vue';
-import { PageMetadata, provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js';
+import { provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js';
+import type { PageMetadata } from '@/scripts/page-metadata.js';
 import { instanceName, ui } from '@@/js/config.js';
 import { i18n } from '@/i18n.js';
 import { mainRouter } from '@/router/main.js';
diff --git a/packages/frontend/src/widgets/WidgetActivity.vue b/packages/frontend/src/widgets/WidgetActivity.vue
index 0aaf18ddd1..cf1110da2b 100644
--- a/packages/frontend/src/widgets/WidgetActivity.vue
+++ b/packages/frontend/src/widgets/WidgetActivity.vue
@@ -21,10 +21,11 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import { ref } from 'vue';
-import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { useWidgetPropsManager } from './widget.js';
+import type { WidgetComponentProps, WidgetComponentEmits, WidgetComponentExpose } from './widget.js';
 import XCalendar from './WidgetActivity.calendar.vue';
 import XChart from './WidgetActivity.chart.vue';
-import { GetFormResultType } from '@/scripts/form.js';
+import type { GetFormResultType } from '@/scripts/form.js';
 import { misskeyApiGet } from '@/scripts/misskey-api.js';
 import MkContainer from '@/components/MkContainer.vue';
 import { $i } from '@/account.js';
diff --git a/packages/frontend/src/widgets/WidgetAichan.vue b/packages/frontend/src/widgets/WidgetAichan.vue
index 00001005de..9b04c463ba 100644
--- a/packages/frontend/src/widgets/WidgetAichan.vue
+++ b/packages/frontend/src/widgets/WidgetAichan.vue
@@ -11,8 +11,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import { onMounted, onUnmounted, shallowRef } from 'vue';
-import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
-import { GetFormResultType } from '@/scripts/form.js';
+import { useWidgetPropsManager } from './widget.js';
+import type { WidgetComponentProps, WidgetComponentEmits, WidgetComponentExpose } from './widget.js';
+import type { GetFormResultType } from '@/scripts/form.js';
 
 const name = 'ai';
 
diff --git a/packages/frontend/src/widgets/WidgetAiscript.vue b/packages/frontend/src/widgets/WidgetAiscript.vue
index cf7e9c5a3e..80573d2dc4 100644
--- a/packages/frontend/src/widgets/WidgetAiscript.vue
+++ b/packages/frontend/src/widgets/WidgetAiscript.vue
@@ -21,8 +21,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { ref } from 'vue';
 import { Interpreter, Parser, utils } from '@syuilo/aiscript';
-import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
-import { GetFormResultType } from '@/scripts/form.js';
+import { useWidgetPropsManager } from './widget.js';
+import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import type { GetFormResultType } from '@/scripts/form.js';
 import * as os from '@/os.js';
 import MkContainer from '@/components/MkContainer.vue';
 import { aiScriptReadline, createAiScriptEnv } from '@/scripts/aiscript/api.js';
diff --git a/packages/frontend/src/widgets/WidgetAiscriptApp.vue b/packages/frontend/src/widgets/WidgetAiscriptApp.vue
index fa79e4aeb7..f0f81a4a89 100644
--- a/packages/frontend/src/widgets/WidgetAiscriptApp.vue
+++ b/packages/frontend/src/widgets/WidgetAiscriptApp.vue
@@ -13,16 +13,19 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
-import { onMounted, Ref, ref, watch } from 'vue';
+import { onMounted, ref, watch } from 'vue';
+import type { Ref } from 'vue';
 import { Interpreter, Parser } from '@syuilo/aiscript';
-import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
-import { GetFormResultType } from '@/scripts/form.js';
+import { useWidgetPropsManager } from './widget.js';
+import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import type { GetFormResultType } from '@/scripts/form.js';
 import * as os from '@/os.js';
 import { aiScriptReadline, createAiScriptEnv } from '@/scripts/aiscript/api.js';
 import { $i } from '@/account.js';
 import MkAsUi from '@/components/MkAsUi.vue';
 import MkContainer from '@/components/MkContainer.vue';
-import { AsUiComponent, AsUiRoot, registerAsUiLib } from '@/scripts/aiscript/ui.js';
+import { registerAsUiLib } from '@/scripts/aiscript/ui.js';
+import type { AsUiComponent, AsUiRoot } from '@/scripts/aiscript/ui.js';
 
 const name = 'aiscriptApp';
 
diff --git a/packages/frontend/src/widgets/WidgetBirthdayFollowings.vue b/packages/frontend/src/widgets/WidgetBirthdayFollowings.vue
index c2bda85ac7..98e186f836 100644
--- a/packages/frontend/src/widgets/WidgetBirthdayFollowings.vue
+++ b/packages/frontend/src/widgets/WidgetBirthdayFollowings.vue
@@ -26,8 +26,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 import { ref } from 'vue';
 import * as Misskey from 'misskey-js';
 import { useInterval } from '@@/js/use-interval.js';
-import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
-import { GetFormResultType } from '@/scripts/form.js';
+import { useWidgetPropsManager } from './widget.js';
+import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import type { GetFormResultType } from '@/scripts/form.js';
 import MkContainer from '@/components/MkContainer.vue';
 import { misskeyApi } from '@/scripts/misskey-api.js';
 import { i18n } from '@/i18n.js';
diff --git a/packages/frontend/src/widgets/WidgetButton.vue b/packages/frontend/src/widgets/WidgetButton.vue
index 6080e120ec..3e455bee3b 100644
--- a/packages/frontend/src/widgets/WidgetButton.vue
+++ b/packages/frontend/src/widgets/WidgetButton.vue
@@ -13,8 +13,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import { Interpreter, Parser } from '@syuilo/aiscript';
-import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
-import { GetFormResultType } from '@/scripts/form.js';
+import { useWidgetPropsManager } from './widget.js';
+import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import type { GetFormResultType } from '@/scripts/form.js';
 import * as os from '@/os.js';
 import { aiScriptReadline, createAiScriptEnv } from '@/scripts/aiscript/api.js';
 import { $i } from '@/account.js';
diff --git a/packages/frontend/src/widgets/WidgetCalendar.vue b/packages/frontend/src/widgets/WidgetCalendar.vue
index 2443e40789..1f8d715b8e 100644
--- a/packages/frontend/src/widgets/WidgetCalendar.vue
+++ b/packages/frontend/src/widgets/WidgetCalendar.vue
@@ -39,8 +39,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import { ref } from 'vue';
-import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
-import { GetFormResultType } from '@/scripts/form.js';
+import { useWidgetPropsManager } from './widget.js';
+import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import type { GetFormResultType } from '@/scripts/form.js';
 import { i18n } from '@/i18n.js';
 import { useInterval } from '@@/js/use-interval.js';
 
diff --git a/packages/frontend/src/widgets/WidgetClicker.vue b/packages/frontend/src/widgets/WidgetClicker.vue
index 5c978fdf72..2b3663d35b 100644
--- a/packages/frontend/src/widgets/WidgetClicker.vue
+++ b/packages/frontend/src/widgets/WidgetClicker.vue
@@ -12,8 +12,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
-import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
-import { GetFormResultType } from '@/scripts/form.js';
+import { useWidgetPropsManager } from './widget.js';
+import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import type { GetFormResultType } from '@/scripts/form.js';
 import MkContainer from '@/components/MkContainer.vue';
 import MkClickerGame from '@/components/MkClickerGame.vue';
 
diff --git a/packages/frontend/src/widgets/WidgetClock.vue b/packages/frontend/src/widgets/WidgetClock.vue
index b3128ef27e..2d3f57a92f 100644
--- a/packages/frontend/src/widgets/WidgetClock.vue
+++ b/packages/frontend/src/widgets/WidgetClock.vue
@@ -30,8 +30,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import { computed } from 'vue';
-import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
-import { GetFormResultType } from '@/scripts/form.js';
+import { useWidgetPropsManager } from './widget.js';
+import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import type { GetFormResultType } from '@/scripts/form.js';
 import MkContainer from '@/components/MkContainer.vue';
 import MkAnalogClock from '@/components/MkAnalogClock.vue';
 import MkDigitalClock from '@/components/MkDigitalClock.vue';
diff --git a/packages/frontend/src/widgets/WidgetDigitalClock.vue b/packages/frontend/src/widgets/WidgetDigitalClock.vue
index fa9a98d571..6e0c9e6dfc 100644
--- a/packages/frontend/src/widgets/WidgetDigitalClock.vue
+++ b/packages/frontend/src/widgets/WidgetDigitalClock.vue
@@ -15,8 +15,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import { computed } from 'vue';
-import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
-import { GetFormResultType } from '@/scripts/form.js';
+import { useWidgetPropsManager } from './widget.js';
+import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import type { GetFormResultType } from '@/scripts/form.js';
 import { timezones } from '@/scripts/timezones.js';
 import MkDigitalClock from '@/components/MkDigitalClock.vue';
 
diff --git a/packages/frontend/src/widgets/WidgetFederation.vue b/packages/frontend/src/widgets/WidgetFederation.vue
index 4a10a612e2..89716575a9 100644
--- a/packages/frontend/src/widgets/WidgetFederation.vue
+++ b/packages/frontend/src/widgets/WidgetFederation.vue
@@ -27,8 +27,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { ref } from 'vue';
 import * as Misskey from 'misskey-js';
-import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
-import { GetFormResultType } from '@/scripts/form.js';
+import { useWidgetPropsManager } from './widget.js';
+import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import type { GetFormResultType } from '@/scripts/form.js';
 import MkContainer from '@/components/MkContainer.vue';
 import MkMiniChart from '@/components/MkMiniChart.vue';
 import { misskeyApi, misskeyApiGet } from '@/scripts/misskey-api.js';
diff --git a/packages/frontend/src/widgets/WidgetInstanceCloud.vue b/packages/frontend/src/widgets/WidgetInstanceCloud.vue
index d090372b9a..aee9066731 100644
--- a/packages/frontend/src/widgets/WidgetInstanceCloud.vue
+++ b/packages/frontend/src/widgets/WidgetInstanceCloud.vue
@@ -20,8 +20,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { shallowRef } from 'vue';
 import * as Misskey from 'misskey-js';
-import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
-import { GetFormResultType } from '@/scripts/form.js';
+import { useWidgetPropsManager } from './widget.js';
+import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import type { GetFormResultType } from '@/scripts/form.js';
 import MkContainer from '@/components/MkContainer.vue';
 import MkTagCloud from '@/components/MkTagCloud.vue';
 import * as os from '@/os.js';
diff --git a/packages/frontend/src/widgets/WidgetInstanceInfo.vue b/packages/frontend/src/widgets/WidgetInstanceInfo.vue
index ec12aa265c..69832332b1 100644
--- a/packages/frontend/src/widgets/WidgetInstanceInfo.vue
+++ b/packages/frontend/src/widgets/WidgetInstanceInfo.vue
@@ -20,8 +20,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
-import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
-import { GetFormResultType } from '@/scripts/form.js';
+import { useWidgetPropsManager } from './widget.js';
+import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import type { GetFormResultType } from '@/scripts/form.js';
 import { host } from '@@/js/config.js';
 import { instance } from '@/instance.js';
 
diff --git a/packages/frontend/src/widgets/WidgetJobQueue.vue b/packages/frontend/src/widgets/WidgetJobQueue.vue
index 0ee6b863dc..84ba05b5d3 100644
--- a/packages/frontend/src/widgets/WidgetJobQueue.vue
+++ b/packages/frontend/src/widgets/WidgetJobQueue.vue
@@ -52,8 +52,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import { onUnmounted, reactive, ref } from 'vue';
-import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
-import { GetFormResultType } from '@/scripts/form.js';
+import { useWidgetPropsManager } from './widget.js';
+import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import type { GetFormResultType } from '@/scripts/form.js';
 import { useStream } from '@/stream.js';
 import kmg from '@/filters/kmg.js';
 import * as sound from '@/scripts/sound.js';
diff --git a/packages/frontend/src/widgets/WidgetMemo.vue b/packages/frontend/src/widgets/WidgetMemo.vue
index 7b179ce703..65ab7a7075 100644
--- a/packages/frontend/src/widgets/WidgetMemo.vue
+++ b/packages/frontend/src/widgets/WidgetMemo.vue
@@ -17,8 +17,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import { ref, watch } from 'vue';
-import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
-import { GetFormResultType } from '@/scripts/form.js';
+import { useWidgetPropsManager } from './widget.js';
+import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import type { GetFormResultType } from '@/scripts/form.js';
 import MkContainer from '@/components/MkContainer.vue';
 import { defaultStore } from '@/store.js';
 import { i18n } from '@/i18n.js';
diff --git a/packages/frontend/src/widgets/WidgetNotifications.vue b/packages/frontend/src/widgets/WidgetNotifications.vue
index 773c078b49..8aaed2624d 100644
--- a/packages/frontend/src/widgets/WidgetNotifications.vue
+++ b/packages/frontend/src/widgets/WidgetNotifications.vue
@@ -17,8 +17,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import { defineAsyncComponent } from 'vue';
-import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
-import { GetFormResultType } from '@/scripts/form.js';
+import { useWidgetPropsManager } from './widget.js';
+import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import type { GetFormResultType } from '@/scripts/form.js';
 import MkContainer from '@/components/MkContainer.vue';
 import XNotifications from '@/components/MkNotifications.vue';
 import * as os from '@/os.js';
diff --git a/packages/frontend/src/widgets/WidgetOnlineUsers.vue b/packages/frontend/src/widgets/WidgetOnlineUsers.vue
index d8c4e259c8..4a3cdb9ba3 100644
--- a/packages/frontend/src/widgets/WidgetOnlineUsers.vue
+++ b/packages/frontend/src/widgets/WidgetOnlineUsers.vue
@@ -15,8 +15,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import { ref } from 'vue';
-import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
-import { GetFormResultType } from '@/scripts/form.js';
+import { useWidgetPropsManager } from './widget.js';
+import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import type { GetFormResultType } from '@/scripts/form.js';
 import { misskeyApi, misskeyApiGet } from '@/scripts/misskey-api.js';
 import { useInterval } from '@@/js/use-interval.js';
 import { i18n } from '@/i18n.js';
diff --git a/packages/frontend/src/widgets/WidgetPhotos.vue b/packages/frontend/src/widgets/WidgetPhotos.vue
index 40e2d8fbc7..6d13ba09cc 100644
--- a/packages/frontend/src/widgets/WidgetPhotos.vue
+++ b/packages/frontend/src/widgets/WidgetPhotos.vue
@@ -24,8 +24,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { onUnmounted, ref } from 'vue';
 import * as Misskey from 'misskey-js';
-import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
-import { GetFormResultType } from '@/scripts/form.js';
+import { useWidgetPropsManager } from './widget.js';
+import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import type { GetFormResultType } from '@/scripts/form.js';
 import { useStream } from '@/stream.js';
 import { getStaticImageUrl } from '@/scripts/media-proxy.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
diff --git a/packages/frontend/src/widgets/WidgetPostForm.vue b/packages/frontend/src/widgets/WidgetPostForm.vue
index 7f344505d8..b0a62d1be2 100644
--- a/packages/frontend/src/widgets/WidgetPostForm.vue
+++ b/packages/frontend/src/widgets/WidgetPostForm.vue
@@ -9,8 +9,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import { } from 'vue';
-import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
-import { GetFormResultType } from '@/scripts/form.js';
+import { useWidgetPropsManager } from './widget.js';
+import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import type { GetFormResultType } from '@/scripts/form.js';
 import MkPostForm from '@/components/MkPostForm.vue';
 
 const name = 'postForm';
diff --git a/packages/frontend/src/widgets/WidgetProfile.vue b/packages/frontend/src/widgets/WidgetProfile.vue
index ae39098305..9f006945ab 100644
--- a/packages/frontend/src/widgets/WidgetProfile.vue
+++ b/packages/frontend/src/widgets/WidgetProfile.vue
@@ -22,8 +22,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
-import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
-import { GetFormResultType } from '@/scripts/form.js';
+import { useWidgetPropsManager } from './widget.js';
+import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import type { GetFormResultType } from '@/scripts/form.js';
 import { $i } from '@/account.js';
 import { userPage } from '@/filters/user.js';
 
diff --git a/packages/frontend/src/widgets/WidgetRss.vue b/packages/frontend/src/widgets/WidgetRss.vue
index 3e43687709..0d7ce55be3 100644
--- a/packages/frontend/src/widgets/WidgetRss.vue
+++ b/packages/frontend/src/widgets/WidgetRss.vue
@@ -25,8 +25,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { ref, watch, computed } from 'vue';
 import * as Misskey from 'misskey-js';
-import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
-import { GetFormResultType } from '@/scripts/form.js';
+import { useWidgetPropsManager } from './widget.js';
+import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import type { GetFormResultType } from '@/scripts/form.js';
 import MkContainer from '@/components/MkContainer.vue';
 import { url as base } from '@@/js/config.js';
 import { i18n } from '@/i18n.js';
diff --git a/packages/frontend/src/widgets/WidgetRssTicker.vue b/packages/frontend/src/widgets/WidgetRssTicker.vue
index 4f594b720f..5ecc1ab022 100644
--- a/packages/frontend/src/widgets/WidgetRssTicker.vue
+++ b/packages/frontend/src/widgets/WidgetRssTicker.vue
@@ -29,9 +29,10 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { ref, watch, computed } from 'vue';
 import * as Misskey from 'misskey-js';
-import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { useWidgetPropsManager } from './widget.js';
+import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
 import MarqueeText from '@/components/MkMarquee.vue';
-import { GetFormResultType } from '@/scripts/form.js';
+import type { GetFormResultType } from '@/scripts/form.js';
 import MkContainer from '@/components/MkContainer.vue';
 import { shuffle } from '@/scripts/shuffle.js';
 import { url as base } from '@@/js/config.js';
diff --git a/packages/frontend/src/widgets/WidgetSlideshow.vue b/packages/frontend/src/widgets/WidgetSlideshow.vue
index 3fea1d7053..67d35d71db 100644
--- a/packages/frontend/src/widgets/WidgetSlideshow.vue
+++ b/packages/frontend/src/widgets/WidgetSlideshow.vue
@@ -19,8 +19,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { onMounted, ref, shallowRef } from 'vue';
 import * as Misskey from 'misskey-js';
-import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
-import { GetFormResultType } from '@/scripts/form.js';
+import { useWidgetPropsManager } from './widget.js';
+import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import type { GetFormResultType } from '@/scripts/form.js';
 import * as os from '@/os.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
 import { useInterval } from '@@/js/use-interval.js';
diff --git a/packages/frontend/src/widgets/WidgetTimeline.vue b/packages/frontend/src/widgets/WidgetTimeline.vue
index a4685fd1fc..02db9454a8 100644
--- a/packages/frontend/src/widgets/WidgetTimeline.vue
+++ b/packages/frontend/src/widgets/WidgetTimeline.vue
@@ -32,8 +32,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import { ref } from 'vue';
-import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
-import { GetFormResultType } from '@/scripts/form.js';
+import { useWidgetPropsManager } from './widget.js';
+import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import type { GetFormResultType } from '@/scripts/form.js';
 import * as os from '@/os.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
 import MkContainer from '@/components/MkContainer.vue';
diff --git a/packages/frontend/src/widgets/WidgetTrends.vue b/packages/frontend/src/widgets/WidgetTrends.vue
index 47a4efc106..3354912c07 100644
--- a/packages/frontend/src/widgets/WidgetTrends.vue
+++ b/packages/frontend/src/widgets/WidgetTrends.vue
@@ -26,8 +26,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { ref } from 'vue';
 import * as Misskey from 'misskey-js';
-import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
-import { GetFormResultType } from '@/scripts/form.js';
+import { useWidgetPropsManager } from './widget.js';
+import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import type { GetFormResultType } from '@/scripts/form.js';
 import MkContainer from '@/components/MkContainer.vue';
 import MkMiniChart from '@/components/MkMiniChart.vue';
 import { misskeyApiGet } from '@/scripts/misskey-api.js';
diff --git a/packages/frontend/src/widgets/WidgetUnixClock.vue b/packages/frontend/src/widgets/WidgetUnixClock.vue
index 832cd575cc..f85d27d6aa 100644
--- a/packages/frontend/src/widgets/WidgetUnixClock.vue
+++ b/packages/frontend/src/widgets/WidgetUnixClock.vue
@@ -17,8 +17,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <script lang="ts" setup>
 import { onUnmounted, ref, watch } from 'vue';
-import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
-import { GetFormResultType } from '@/scripts/form.js';
+import { useWidgetPropsManager } from './widget.js';
+import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import type { GetFormResultType } from '@/scripts/form.js';
 
 const name = 'unixClock';
 
diff --git a/packages/frontend/src/widgets/WidgetUserList.vue b/packages/frontend/src/widgets/WidgetUserList.vue
index 72391d622e..805e14c669 100644
--- a/packages/frontend/src/widgets/WidgetUserList.vue
+++ b/packages/frontend/src/widgets/WidgetUserList.vue
@@ -26,8 +26,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { ref } from 'vue';
 import * as Misskey from 'misskey-js';
-import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
-import { GetFormResultType } from '@/scripts/form.js';
+import { useWidgetPropsManager } from './widget.js';
+import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import type { GetFormResultType } from '@/scripts/form.js';
 import MkContainer from '@/components/MkContainer.vue';
 import * as os from '@/os.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
diff --git a/packages/frontend/src/widgets/index.ts b/packages/frontend/src/widgets/index.ts
index c5be25e7df..ea17d484c5 100644
--- a/packages/frontend/src/widgets/index.ts
+++ b/packages/frontend/src/widgets/index.ts
@@ -3,7 +3,8 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { App, defineAsyncComponent } from 'vue';
+import { defineAsyncComponent } from 'vue';
+import type { App } from 'vue';
 
 export default function(app: App) {
 	app.component('WidgetProfile', defineAsyncComponent(() => import('./WidgetProfile.vue')));
diff --git a/packages/frontend/src/widgets/server-metric/index.vue b/packages/frontend/src/widgets/server-metric/index.vue
index 86d84b4f33..3264c8dc04 100644
--- a/packages/frontend/src/widgets/server-metric/index.vue
+++ b/packages/frontend/src/widgets/server-metric/index.vue
@@ -22,14 +22,15 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { onUnmounted, ref } from 'vue';
 import * as Misskey from 'misskey-js';
-import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from '../widget.js';
+import { useWidgetPropsManager } from '../widget.js';
+import type { WidgetComponentProps, WidgetComponentEmits, WidgetComponentExpose } from '../widget.js';
 import XCpuMemory from './cpu-mem.vue';
 import XNet from './net.vue';
 import XCpu from './cpu.vue';
 import XMemory from './mem.vue';
 import XDisk from './disk.vue';
 import MkContainer from '@/components/MkContainer.vue';
-import { GetFormResultType } from '@/scripts/form.js';
+import type { GetFormResultType } from '@/scripts/form.js';
 import { misskeyApiGet } from '@/scripts/misskey-api.js';
 import { useStream } from '@/stream.js';
 import { i18n } from '@/i18n.js';
diff --git a/packages/frontend/src/widgets/widget.ts b/packages/frontend/src/widgets/widget.ts
index bfe8067adf..98e1e44cd8 100644
--- a/packages/frontend/src/widgets/widget.ts
+++ b/packages/frontend/src/widgets/widget.ts
@@ -5,7 +5,7 @@
 
 import { reactive, watch } from 'vue';
 import { throttle } from 'throttle-debounce';
-import { Form, GetFormResultType } from '@/scripts/form.js';
+import type { Form, GetFormResultType } from '@/scripts/form.js';
 import * as os from '@/os.js';
 import { deepClone } from '@/scripts/clone.js';
 
diff --git a/packages/frontend/test/home.test.ts b/packages/frontend/test/home.test.ts
index b3a4e8ff3a..b70edc6ac1 100644
--- a/packages/frontend/test/home.test.ts
+++ b/packages/frontend/test/home.test.ts
@@ -6,7 +6,7 @@
 import { afterEach, assert, describe, test } from 'vitest';
 import { cleanup, render, type RenderResult } from '@testing-library/vue';
 import './init';
-import type * as Misskey from 'misskey-js';
+import * as Misskey from 'misskey-js';
 import { directives } from '@/directives/index.js';
 import { components } from '@/components/index.js';
 import XHome from '@/pages/user/home.vue';
diff --git a/packages/frontend/test/i18n.test.ts b/packages/frontend/test/i18n.test.ts
index 9d6cf855f3..a51dfc6c4e 100644
--- a/packages/frontend/test/i18n.test.ts
+++ b/packages/frontend/test/i18n.test.ts
@@ -5,7 +5,7 @@
 
 import { describe, expect, it } from 'vitest';
 import { I18n } from '../../frontend-shared/js/i18n.js'; // @@で参照できなかったので
-import { ParameterizedString } from '../../../locales/index.js';
+import type { ParameterizedString } from '../../../locales/index.js';
 
 // TODO: このテストはfrontend-sharedに移動する
 
diff --git a/packages/frontend/test/note.test.ts b/packages/frontend/test/note.test.ts
index 7ce5f23e22..fda2d9ad7b 100644
--- a/packages/frontend/test/note.test.ts
+++ b/packages/frontend/test/note.test.ts
@@ -6,7 +6,7 @@
 import { describe, test, assert, afterEach } from 'vitest';
 import { render, cleanup, type RenderResult } from '@testing-library/vue';
 import './init';
-import type * as Misskey from 'misskey-js';
+import * as Misskey from 'misskey-js';
 import { components } from '@/components/index.js';
 import { directives } from '@/directives/index.js';
 import MkMediaImage from '@/components/MkMediaImage.vue';
diff --git a/packages/frontend/tsconfig.json b/packages/frontend/tsconfig.json
index 68b6651a56..ee200d6890 100644
--- a/packages/frontend/tsconfig.json
+++ b/packages/frontend/tsconfig.json
@@ -21,6 +21,7 @@
 		"allowSyntheticDefaultImports": true,
 		"isolatedModules": true,
 		"useDefineForClassFields": true,
+		"verbatimModuleSyntax": true,
 		"baseUrl": ".",
 		"paths": {
 			"@/*": ["./src/*"],

From cfb61289a99a2f6c4e0d8214a11046a93db1180d Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Wed, 5 Feb 2025 20:17:48 +0900
Subject: [PATCH 18/18] refactor(frontend): remove X theme properties (#15376)

* refactor(frontend): remove X theme properties

* Update MkAutocomplete.vue

* Update WidgetCalendar.vue
---
 packages/frontend-shared/themes/_dark.json5               | 8 --------
 packages/frontend-shared/themes/_light.json5              | 8 --------
 packages/frontend-shared/themes/d-astro.json5             | 8 --------
 packages/frontend-shared/themes/d-u0.json5                | 8 --------
 packages/frontend-shared/themes/l-u0.json5                | 8 --------
 packages/frontend-shared/themes/l-vivid.json5             | 8 --------
 packages/frontend/src/components/MkAutocomplete.vue       | 6 +++---
 .../src/components/MkCustomEmojiDetailedDialog.vue        | 4 ++--
 packages/frontend/src/components/MkEmojiPicker.vue        | 6 +++---
 packages/frontend/src/components/MkPostForm.vue           | 6 +++---
 packages/frontend/src/components/MkUserSelectDialog.vue   | 4 ++--
 packages/frontend/src/pages/admin/server-rules.vue        | 2 +-
 .../src/pages/page-editor/page-editor.container.vue       | 4 ++--
 packages/frontend/src/widgets/WidgetCalendar.vue          | 2 +-
 14 files changed, 17 insertions(+), 65 deletions(-)

diff --git a/packages/frontend-shared/themes/_dark.json5 b/packages/frontend-shared/themes/_dark.json5
index 5271785e62..f2d8a7aed8 100644
--- a/packages/frontend-shared/themes/_dark.json5
+++ b/packages/frontend-shared/themes/_dark.json5
@@ -79,14 +79,6 @@
 		codeBoolean: '#c59eff',
 		deckBg: '#000',
 		htmlThemeColor: '@bg',
-		X3: 'rgba(255, 255, 255, 0.05)',
-		X4: 'rgba(255, 255, 255, 0.1)',
-		X5: 'rgba(255, 255, 255, 0.05)',
-		X6: 'rgba(255, 255, 255, 0.15)',
-		X7: 'rgba(255, 255, 255, 0.05)',
-		X11: 'rgba(0, 0, 0, 0.3)',
-		X12: 'rgba(255, 255, 255, 0.1)',
-		X13: 'rgba(255, 255, 255, 0.15)',
 	},
 
 	codeHighlighter: {
diff --git a/packages/frontend-shared/themes/_light.json5 b/packages/frontend-shared/themes/_light.json5
index be331ce58f..22893bf4b3 100644
--- a/packages/frontend-shared/themes/_light.json5
+++ b/packages/frontend-shared/themes/_light.json5
@@ -79,14 +79,6 @@
 		codeBoolean: '#62b70c',
 		deckBg: ':darken<3<@bg',
 		htmlThemeColor: '@bg',
-		X3: 'rgba(0, 0, 0, 0.05)',
-		X4: 'rgba(0, 0, 0, 0.1)',
-		X5: 'rgba(0, 0, 0, 0.05)',
-		X6: 'rgba(0, 0, 0, 0.25)',
-		X7: 'rgba(0, 0, 0, 0.05)',
-		X11: 'rgba(0, 0, 0, 0.1)',
-		X12: 'rgba(0, 0, 0, 0.1)',
-		X13: 'rgba(0, 0, 0, 0.15)',
 	},
 
 	codeHighlighter: {
diff --git a/packages/frontend-shared/themes/d-astro.json5 b/packages/frontend-shared/themes/d-astro.json5
index 4422526a33..e8864df336 100644
--- a/packages/frontend-shared/themes/d-astro.json5
+++ b/packages/frontend-shared/themes/d-astro.json5
@@ -54,13 +54,5 @@
 		wallpaperOverlay: 'rgba(0, 0, 0, 0.5)',
 		panelHeaderDivider: 'rgba(0, 0, 0, 0)',
 		scrollbarHandleHover: 'rgba(255, 255, 255, 0.4)',
-		X3: 'rgba(255, 255, 255, 0.05)',
-		X4: 'rgba(255, 255, 255, 0.1)',
-		X5: 'rgba(255, 255, 255, 0.05)',
-		X6: 'rgba(255, 255, 255, 0.15)',
-		X7: 'rgba(255, 255, 255, 0.05)',
-		X11: 'rgba(0, 0, 0, 0.3)',
-		X12: 'rgba(255, 255, 255, 0.1)',
-		X13: 'rgba(255, 255, 255, 0.15)',
 	},
 }
diff --git a/packages/frontend-shared/themes/d-u0.json5 b/packages/frontend-shared/themes/d-u0.json5
index fb707c74c3..0223b1fb5c 100644
--- a/packages/frontend-shared/themes/d-u0.json5
+++ b/packages/frontend-shared/themes/d-u0.json5
@@ -3,17 +3,9 @@
 	base: 'dark',
 	name: 'Mi U0 Dark',
 	props: {
-		X3: 'rgba(255, 255, 255, 0.05)',
-		X4: 'rgba(255, 255, 255, 0.1)',
-		X5: 'rgba(255, 255, 255, 0.05)',
-		X6: 'rgba(255, 255, 255, 0.15)',
-		X7: 'rgba(255, 255, 255, 0.05)',
 		bg: '#172426',
 		fg: '#dadada',
 		X10: ':alpha<0.4<@accent',
-		X11: 'rgba(0, 0, 0, 0.3)',
-		X12: 'rgba(255, 255, 255, 0.1)',
-		X13: 'rgba(255, 255, 255, 0.15)',
 		X14: ':alpha<0.5<@navBg',
 		X15: ':alpha<0<@panel',
 		X16: ':alpha<0.7<@panel',
diff --git a/packages/frontend-shared/themes/l-u0.json5 b/packages/frontend-shared/themes/l-u0.json5
index 7062e7fe5b..f6023af819 100644
--- a/packages/frontend-shared/themes/l-u0.json5
+++ b/packages/frontend-shared/themes/l-u0.json5
@@ -3,17 +3,9 @@
 	base: 'light',
 	name: 'Mi U0 Light',
 	props: {
-		X3: 'rgba(255, 255, 255, 0.05)',
-		X4: 'rgba(255, 255, 255, 0.1)',
-		X5: 'rgba(255, 255, 255, 0.05)',
-		X6: 'rgba(255, 255, 255, 0.15)',
-		X7: 'rgba(255, 255, 255, 0.05)',
 		bg: '#e7e7eb',
 		fg: '#5f5f5f',
 		X10: ':alpha<0.4<@accent',
-		X11: 'rgba(0, 0, 0, 0.3)',
-		X12: 'rgba(255, 255, 255, 0.1)',
-		X13: 'rgba(255, 255, 255, 0.15)',
 		X14: ':alpha<0.5<@navBg',
 		X15: ':alpha<0<@panel',
 		X16: ':alpha<0.7<@panel',
diff --git a/packages/frontend-shared/themes/l-vivid.json5 b/packages/frontend-shared/themes/l-vivid.json5
index 39768d4ac6..058c9c32e5 100644
--- a/packages/frontend-shared/themes/l-vivid.json5
+++ b/packages/frontend-shared/themes/l-vivid.json5
@@ -57,13 +57,5 @@
 		fgTransparentWeak: ':alpha<0.75<@fg',
 		panelHeaderDivider: '@divider',
 		scrollbarHandleHover: 'rgba(0, 0, 0, 0.4)',
-		X3: 'rgba(0, 0, 0, 0.05)',
-		X4: 'rgba(0, 0, 0, 0.1)',
-		X5: 'rgba(0, 0, 0, 0.05)',
-		X6: 'rgba(0, 0, 0, 0.25)',
-		X7: 'rgba(0, 0, 0, 0.05)',
-		X11: 'rgba(0, 0, 0, 0.1)',
-		X12: 'rgba(0, 0, 0, 0.1)',
-		X13: 'rgba(0, 0, 0, 0.15)',
 	},
 }
diff --git a/packages/frontend/src/components/MkAutocomplete.vue b/packages/frontend/src/components/MkAutocomplete.vue
index e7372da6f8..685dcb86e4 100644
--- a/packages/frontend/src/components/MkAutocomplete.vue
+++ b/packages/frontend/src/components/MkAutocomplete.vue
@@ -47,8 +47,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 import { markRaw, ref, shallowRef, computed, onUpdated, onMounted, onBeforeUnmount, nextTick, watch } from 'vue';
 import sanitizeHtml from 'sanitize-html';
 import { emojilist, getEmojiName } from '@@/js/emojilist.js';
-import contains from '@/scripts/contains.js';
 import { char2twemojiFilePath, char2fluentEmojiFilePath } from '@@/js/emoji-base.js';
+import { MFM_TAGS, MFM_PARAMS } from '@@/js/const.js';
+import contains from '@/scripts/contains.js';
 import { acct } from '@/filters/user.js';
 import * as os from '@/os.js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
@@ -56,7 +57,6 @@ import { defaultStore } from '@/store.js';
 import { i18n } from '@/i18n.js';
 import { miLocalStorage } from '@/local-storage.js';
 import { customEmojis } from '@/custom-emojis.js';
-import { MFM_TAGS, MFM_PARAMS } from '@@/js/const.js';
 import { searchEmoji } from '@/scripts/search-emoji.js';
 import type { EmojiDef } from '@/scripts/search-emoji.js';
 
@@ -408,7 +408,7 @@ onBeforeUnmount(() => {
 	text-overflow: ellipsis;
 
 	&:hover {
-		background: var(--MI_THEME-X3);
+		background: light-dark(rgba(0, 0, 0, 0.05), rgba(255, 255, 255, 0.05));
 	}
 
 	&[data-selected='true'] {
diff --git a/packages/frontend/src/components/MkCustomEmojiDetailedDialog.vue b/packages/frontend/src/components/MkCustomEmojiDetailedDialog.vue
index e6ab17417d..86d6269c69 100644
--- a/packages/frontend/src/components/MkCustomEmojiDetailedDialog.vue
+++ b/packages/frontend/src/components/MkCustomEmojiDetailedDialog.vue
@@ -85,7 +85,7 @@ function cancel() {
 .emojiImgWrapper {
   max-width: 100%;
   height: 40cqh;
-  background-image: repeating-linear-gradient(45deg, transparent, transparent 8px, var(--MI_THEME-X5) 8px, var(--MI_THEME-X5) 14px);
+  background-image: repeating-linear-gradient(45deg, transparent, transparent 8px, light-dark(rgba(0, 0, 0, 0.05), rgba(255, 255, 255, 0.05)) 8px, light-dark(rgba(0, 0, 0, 0.05), rgba(255, 255, 255, 0.05)) 14px);
   border-radius: var(--MI-radius);
   margin: auto;
   overflow-y: hidden;
@@ -101,7 +101,7 @@ function cancel() {
   display: inline-block;
   word-break: break-all;
   padding: 3px 10px;
-  background-color: var(--MI_THEME-X5);
+  background-color: light-dark(rgba(0, 0, 0, 0.05), rgba(255, 255, 255, 0.05));
   border: solid 1px var(--MI_THEME-divider);
   border-radius: var(--MI-radius);
 }
diff --git a/packages/frontend/src/components/MkEmojiPicker.vue b/packages/frontend/src/components/MkEmojiPicker.vue
index 7ee0d6a6ac..5da161dae8 100644
--- a/packages/frontend/src/components/MkEmojiPicker.vue
+++ b/packages/frontend/src/components/MkEmojiPicker.vue
@@ -582,7 +582,7 @@ defineExpose({
 
 						&:disabled {
 							cursor: not-allowed;
-							background: linear-gradient(-45deg, transparent 0% 48%, var(--MI_THEME-X6) 48% 52%, transparent 52% 100%);
+							background: linear-gradient(-45deg, transparent 0% 48%, light-dark(rgba(0, 0, 0, 0.25), rgba(255, 255, 255, 0.15)) 48% 52%, transparent 52% 100%);
 							opacity: 1;
 
 							> .emoji {
@@ -617,7 +617,7 @@ defineExpose({
 
 						&:disabled {
 							cursor: not-allowed;
-							background: linear-gradient(-45deg, transparent 0% 48%, var(--MI_THEME-X6) 48% 52%, transparent 52% 100%);
+							background: linear-gradient(-45deg, transparent 0% 48%, light-dark(rgba(0, 0, 0, 0.25), rgba(255, 255, 255, 0.15)) 48% 52%, transparent 52% 100%);
 							opacity: 1;
 
 							> .emoji {
@@ -738,7 +738,7 @@ defineExpose({
 
 					&:disabled {
 						cursor: not-allowed;
-						background: linear-gradient(-45deg, transparent 0% 48%, var(--MI_THEME-X6) 48% 52%, transparent 52% 100%);
+						background: linear-gradient(-45deg, transparent 0% 48%, light-dark(rgba(0, 0, 0, 0.25), rgba(255, 255, 255, 0.15)) 48% 52%, transparent 52% 100%);
 						opacity: 1;
 
 						> .emoji {
diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue
index 500f97b2ed..4f2792ed40 100644
--- a/packages/frontend/src/components/MkPostForm.vue
+++ b/packages/frontend/src/components/MkPostForm.vue
@@ -1166,7 +1166,7 @@ defineExpose({
 	border-radius: 6px;
 
 	&:hover {
-		background: var(--MI_THEME-X5);
+		background: light-dark(rgba(0, 0, 0, 0.05), rgba(255, 255, 255, 0.05));
 	}
 
 	&:disabled {
@@ -1238,7 +1238,7 @@ html[data-color-scheme=light] .preview {
 	margin-right: 14px;
 	padding: 8px 0 8px 8px;
 	border-radius: 8px;
-	background: var(--MI_THEME-X4);
+	background: light-dark(rgba(0, 0, 0, 0.1), rgba(255, 255, 255, 0.1));
 }
 
 .hasNotSpecifiedMentions {
@@ -1349,7 +1349,7 @@ html[data-color-scheme=light] .preview {
 	border-radius: 6px;
 
 	&:hover {
-		background: var(--MI_THEME-X5);
+		background: light-dark(rgba(0, 0, 0, 0.05), rgba(255, 255, 255, 0.05));
 	}
 
 	&.footerButtonActive {
diff --git a/packages/frontend/src/components/MkUserSelectDialog.vue b/packages/frontend/src/components/MkUserSelectDialog.vue
index 63af652cbc..1e93d9dbea 100644
--- a/packages/frontend/src/components/MkUserSelectDialog.vue
+++ b/packages/frontend/src/components/MkUserSelectDialog.vue
@@ -63,6 +63,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { onMounted, ref, computed, shallowRef } from 'vue';
 import * as Misskey from 'misskey-js';
+import { host as currentHost, hostname } from '@@/js/config.js';
 import MkInput from '@/components/MkInput.vue';
 import FormSplit from '@/components/form/split.vue';
 import MkModalWindow from '@/components/MkModalWindow.vue';
@@ -71,7 +72,6 @@ import { defaultStore } from '@/store.js';
 import { i18n } from '@/i18n.js';
 import { $i } from '@/account.js';
 import { instance } from '@/instance.js';
-import { host as currentHost, hostname } from '@@/js/config.js';
 
 const emit = defineEmits<{
 	(ev: 'ok', selected: Misskey.entities.UserDetailed): void;
@@ -198,7 +198,7 @@ onMounted(() => {
 	font-size: 14px;
 
 	&:hover {
-		background: var(--MI_THEME-X7);
+		background: light-dark(rgba(0, 0, 0, 0.05), rgba(255, 255, 255, 0.05));
 	}
 
 	&.selected {
diff --git a/packages/frontend/src/pages/admin/server-rules.vue b/packages/frontend/src/pages/admin/server-rules.vue
index 552958af6f..cd50f92143 100644
--- a/packages/frontend/src/pages/admin/server-rules.vue
+++ b/packages/frontend/src/pages/admin/server-rules.vue
@@ -122,7 +122,7 @@ definePageMetadata(() => ({
 	border-radius: 6px;
 
 	&:hover {
-		background: var(--MI_THEME-X5);
+		background: light-dark(rgba(0, 0, 0, 0.05), rgba(255, 255, 255, 0.05));
 	}
 }
 
diff --git a/packages/frontend/src/pages/page-editor/page-editor.container.vue b/packages/frontend/src/pages/page-editor/page-editor.container.vue
index a96c2c2a77..936a7462dd 100644
--- a/packages/frontend/src/pages/page-editor/page-editor.container.vue
+++ b/packages/frontend/src/pages/page-editor/page-editor.container.vue
@@ -61,11 +61,11 @@ function remove() {
 	position: relative;
 	overflow: hidden;
 	background: var(--MI_THEME-panel);
-	border: solid 2px var(--MI_THEME-X12);
+	border: solid 2px light-dark(rgba(0, 0, 0, 0.1), rgba(255, 255, 255, 0.1));
 	border-radius: 8px;
 
 	&:hover {
-		border: solid 2px var(--MI_THEME-X13);
+		border: solid 2px light-dark(rgba(0, 0, 0, 0.15), rgba(255, 255, 255, 0.15));
 	}
 
 	&.warn {
diff --git a/packages/frontend/src/widgets/WidgetCalendar.vue b/packages/frontend/src/widgets/WidgetCalendar.vue
index 1f8d715b8e..94169d5e40 100644
--- a/packages/frontend/src/widgets/WidgetCalendar.vue
+++ b/packages/frontend/src/widgets/WidgetCalendar.vue
@@ -208,7 +208,7 @@ defineExpose<WidgetComponentExpose>({
 .meter {
 	width: 100%;
 	overflow: hidden;
-	background: var(--MI_THEME-X11);
+	background: light-dark(rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.3));
 	border-radius: 8px;
 }