diff --git a/CHANGELOG.md b/CHANGELOG.md
index f8e961073c..56efd7477c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,12 @@
- 日本語における公開範囲名称の「ダイレクト」が「指名」に改称されました
### Client
+- Feat: セーフモード
+ - プラグイン・テーマ・カスタムCSSの使用でクライアントの起動に問題が発生した際に、これらを無効にして起動できます
+ - 以下の方法でセーフモードを起動できます
+ - `g` キーを連打する
+ - URLに`?safemode=true`を付ける
+ - PWAのショートカットで Safemode を選択して起動する
- Fix: 一部の設定検索結果が存在しないパスになる問題を修正
(Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/1171)
- Fix: テーマエディタが動作しない問題を修正
diff --git a/locales/index.d.ts b/locales/index.d.ts
index d2e2b729e8..f77925b410 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -5501,6 +5501,22 @@ export interface Locale extends ILocale {
* 日
*/
"inDays": string;
+ /**
+ * セーフモードが有効です
+ */
+ "safeModeEnabled": string;
+ /**
+ * セーフモードが有効なため、プラグインはすべて無効化されています。
+ */
+ "pluginsAreDisabledBecauseSafeMode": string;
+ /**
+ * セーフモードが有効なため、カスタムCSSは適用されていません。
+ */
+ "customCssIsDisabledBecauseSafeMode": string;
+ /**
+ * セーフモードが有効な間はデフォルトのテーマが使用されます。セーフモードをオフにすると元に戻ります。
+ */
+ "themeIsDefaultBecauseSafeMode": string;
"_order": {
/**
* 新しい順
@@ -11839,6 +11855,10 @@ export interface Locale extends ILocale {
* 修復ツールを起動
*/
"otherOption3": string;
+ /**
+ * Misskeyをセーフモードで起動
+ */
+ "otherOption4": string;
};
"_search": {
/**
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 377231ee19..4d79b31b1b 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1370,6 +1370,10 @@ defaultImageCompressionLevel: "デフォルトの画像圧縮度"
defaultImageCompressionLevel_description: "低くすると画質を保てますが、ファイルサイズは増加します。
高くするとファイルサイズを減らせますが、画質は低下します。"
inMinutes: "分"
inDays: "日"
+safeModeEnabled: "セーフモードが有効です"
+pluginsAreDisabledBecauseSafeMode: "セーフモードが有効なため、プラグインはすべて無効化されています。"
+customCssIsDisabledBecauseSafeMode: "セーフモードが有効なため、カスタムCSSは適用されていません。"
+themeIsDefaultBecauseSafeMode: "セーフモードが有効な間はデフォルトのテーマが使用されます。セーフモードをオフにすると元に戻ります。"
_order:
newest: "新しい順"
@@ -3164,6 +3168,7 @@ _bootErrors:
otherOption1: "クライアント設定とキャッシュを削除"
otherOption2: "簡易クライアントを起動"
otherOption3: "修復ツールを起動"
+ otherOption4: "Misskeyをセーフモードで起動"
_search:
searchScopeAll: "全て"
diff --git a/packages/backend/src/server/web/ClientServerService.ts b/packages/backend/src/server/web/ClientServerService.ts
index 4d122b0fcf..768cfde701 100644
--- a/packages/backend/src/server/web/ClientServerService.ts
+++ b/packages/backend/src/server/web/ClientServerService.ts
@@ -188,6 +188,10 @@ export class ClientServerService {
'url': 'url',
},
},
+ 'shortcuts': [{
+ 'name': 'Safemode',
+ 'url': '/?safemode=true',
+ }],
};
manifest = {
diff --git a/packages/backend/src/server/web/boot.js b/packages/backend/src/server/web/boot.js
index 24794cbf2a..1a30e9ed2b 100644
--- a/packages/backend/src/server/web/boot.js
+++ b/packages/backend/src/server/web/boot.js
@@ -94,23 +94,37 @@
}
//#endregion
- //#region Theme
- const theme = localStorage.getItem('theme');
- if (theme) {
- for (const [k, v] of Object.entries(JSON.parse(theme))) {
- document.documentElement.style.setProperty(`--MI_THEME-${k}`, v.toString());
+ let isSafeMode = (localStorage.getItem('isSafeMode') === 'true');
- // HTMLの theme-color 適用
- if (k === 'htmlThemeColor') {
- for (const tag of document.head.children) {
- if (tag.tagName === 'META' && tag.getAttribute('name') === 'theme-color') {
- tag.setAttribute('content', v);
- break;
+ if (!isSafeMode) {
+ const urlParams = new URLSearchParams(window.location.search);
+
+ if (urlParams.has('safemode') && urlParams.get('safemode') === 'true') {
+ localStorage.setItem('isSafeMode', 'true');
+ isSafeMode = true;
+ }
+ }
+
+ //#region Theme
+ if (!isSafeMode) {
+ const theme = localStorage.getItem('theme');
+ if (theme) {
+ for (const [k, v] of Object.entries(JSON.parse(theme))) {
+ document.documentElement.style.setProperty(`--MI_THEME-${k}`, v.toString());
+
+ // HTMLの theme-color 適用
+ if (k === 'htmlThemeColor') {
+ for (const tag of document.head.children) {
+ if (tag.tagName === 'META' && tag.getAttribute('name') === 'theme-color') {
+ tag.setAttribute('content', v);
+ break;
+ }
}
}
}
}
}
+
const colorScheme = localStorage.getItem('colorScheme');
if (colorScheme) {
document.documentElement.style.setProperty('color-scheme', colorScheme);
@@ -127,11 +141,13 @@
document.documentElement.classList.add('useSystemFont');
}
- const customCss = localStorage.getItem('customCss');
- if (customCss && customCss.length > 0) {
- const style = document.createElement('style');
- style.innerHTML = customCss;
- document.head.appendChild(style);
+ if (!isSafeMode) {
+ const customCss = localStorage.getItem('customCss');
+ if (customCss && customCss.length > 0) {
+ const style = document.createElement('style');
+ style.innerHTML = customCss;
+ document.head.appendChild(style);
+ }
}
async function addStyle(styleText) {
@@ -159,9 +175,13 @@
otherOption1: 'Clear preferences and cache',
otherOption2: 'Start the simple client',
otherOption3: 'Start the repair tool',
+ otherOption4: 'Start Misskey in safe mode',
}, locale?._bootErrors || {});
const reload = locale?.reload || 'Reload';
+ const safeModeUrl = new URL(window.location.href);
+ safeModeUrl.searchParams.set('safemode', 'true');
+
let errorsElement = document.getElementById('errors');
if (!errorsElement) {
@@ -182,6 +202,12 @@
${messages.solution4}