diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 9e500f613..a92d83838 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 000000000..0781eeebd
--- /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 fdbae0b8a..9dbc10314 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 3fd10fc44..8a0171a6e 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 1c94e6e4f..e2fd137f9 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 = `