diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 9e500f6130..a92d838388 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -761,6 +761,9 @@ middle: "中"
low: "低"
emailNotConfiguredWarning: "メールアドレスの設定がされていません。"
ratio: "比率"
+customCss: "カスタムCSS"
+customCssWarn: "この設定は必ず知識のある方が行ってください。不適切な設定を行うとクライアントが正常に使用できなくなる恐れがあります。"
+global: "グローバル"
_ad:
back: "戻る"
diff --git a/src/client/pages/settings/custom-css.vue b/src/client/pages/settings/custom-css.vue
new file mode 100644
index 0000000000..0781eeebd7
--- /dev/null
+++ b/src/client/pages/settings/custom-css.vue
@@ -0,0 +1,72 @@
+
+
+ {{ $ts.customCssWarn }}
+
+
+ {{ $ts.local }}
+
+
+
+
+
diff --git a/src/client/pages/settings/general.vue b/src/client/pages/settings/general.vue
index fdbae0b8a1..9dbc103145 100644
--- a/src/client/pages/settings/general.vue
+++ b/src/client/pages/settings/general.vue
@@ -78,6 +78,8 @@
{{ $ts.deck }}
+
+ {{ $ts.customCss }}
diff --git a/src/client/pages/settings/index.vue b/src/client/pages/settings/index.vue
index 3fd10fc44f..8a0171a6e8 100644
--- a/src/client/pages/settings/index.vue
+++ b/src/client/pages/settings/index.vue
@@ -123,6 +123,7 @@ export default defineComponent({
case 'theme/manage': return defineAsyncComponent(() => import('./theme.manage.vue'));
case 'sidebar': return defineAsyncComponent(() => import('./sidebar.vue'));
case 'sounds': return defineAsyncComponent(() => import('./sounds.vue'));
+ case 'custom-css': return defineAsyncComponent(() => import('./custom-css.vue'));
case 'deck': return defineAsyncComponent(() => import('./deck.vue'));
case 'plugin': return defineAsyncComponent(() => import('./plugin.vue'));
case 'plugin/install': return defineAsyncComponent(() => import('./plugin.install.vue'));
diff --git a/src/server/web/boot.js b/src/server/web/boot.js
index 1c94e6e4f4..e2fd137f95 100644
--- a/src/server/web/boot.js
+++ b/src/server/web/boot.js
@@ -107,6 +107,13 @@
document.documentElement.style.backgroundImage = `url(${wallpaper})`;
}
+ const customCss = localStorage.getItem('customCss');
+ if (customCss && customCss.length > 0) {
+ const style = document.createElement('style');
+ style.innerHTML = customCss;
+ head.appendChild(style);
+ }
+
// eslint-disable-next-line no-inner-declarations
function renderError(code, details) {
document.documentElement.innerHTML = `