diff --git a/CHANGELOG.md b/CHANGELOG.md
index 38dce92cb2..4571d09b6b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,11 +16,12 @@ You should also include the user name that made the change.
このバージョンからNode v16.14.0以降が必要です
### Changes
-- ノートの最大文字数を設定できる機能が廃止され、デフォルトで一律3000文字になりました
+- ノートの最大文字数を設定できる機能が廃止され、デフォルトで一律3000文字になりました @syuilo
### Improvements
-- プロフィールの追加情報を最大16まで保存できるように
-- 連合チャートにPub&Subを追加
+- インスタンスデフォルトテーマを設定できるように @syuilo
+- プロフィールの追加情報を最大16まで保存できるように @syuilo
+- 連合チャートにPub&Subを追加 @syuilo
### Bugfixes
- Client: リアクションピッカーの高さが低くなったまま戻らないことがあるのを修正 @syuilo
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index af88f382ef..90dc14815e 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -831,6 +831,9 @@ themeColor: "テーマカラー"
size: "サイズ"
numberOfColumn: "列の数"
searchByGoogle: "ググる"
+instanceDefaultLightTheme: "インスタンスデフォルトのライトテーマ"
+instanceDefaultDarkTheme: "インスタンスデフォルトのダークテーマ"
+instanceDefaultThemeDescription: "オブジェクト形式のテーマコードを記入します。"
_emailUnavailable:
used: "既に使用されています"
diff --git a/packages/backend/migration/1646143552768-instance-default-theme.js b/packages/backend/migration/1646143552768-instance-default-theme.js
new file mode 100644
index 0000000000..029354fd92
--- /dev/null
+++ b/packages/backend/migration/1646143552768-instance-default-theme.js
@@ -0,0 +1,13 @@
+export class instanceDefaultTheme1646143552768 {
+ name = 'instanceDefaultTheme1646143552768'
+
+ async up(queryRunner) {
+ await queryRunner.query(`ALTER TABLE "meta" ADD "defaultLightTheme" character varying(8192)`);
+ await queryRunner.query(`ALTER TABLE "meta" ADD "defaultDarkTheme" character varying(8192)`);
+ }
+
+ async down(queryRunner) {
+ await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "defaultDarkTheme"`);
+ await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "defaultLightTheme"`);
+ }
+}
diff --git a/packages/backend/src/models/entities/meta.ts b/packages/backend/src/models/entities/meta.ts
index 0b1e9c85c3..4d58b5f04f 100644
--- a/packages/backend/src/models/entities/meta.ts
+++ b/packages/backend/src/models/entities/meta.ts
@@ -344,6 +344,20 @@ export class Meta {
})
public feedbackUrl: string | null;
+ @Column('varchar', {
+ length: 8192,
+ default: null,
+ nullable: true,
+ })
+ public defaultLightTheme: string | null;
+
+ @Column('varchar', {
+ length: 8192,
+ default: null,
+ nullable: true,
+ })
+ public defaultDarkTheme: string | null;
+
@Column('boolean', {
default: false,
})
diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts
index 6dc6abb00a..66b634c877 100644
--- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts
+++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts
@@ -36,6 +36,8 @@ export const paramDef = {
logoImageUrl: { type: 'string', nullable: true },
name: { type: 'string', nullable: true },
description: { type: 'string', nullable: true },
+ defaultLightTheme: { type: 'string', nullable: true },
+ defaultDarkTheme: { type: 'string', nullable: true },
localDriveCapacityMb: { type: 'integer' },
remoteDriveCapacityMb: { type: 'integer' },
cacheRemoteFiles: { type: 'boolean' },
@@ -162,6 +164,14 @@ export default define(meta, paramDef, async (ps, me) => {
set.description = ps.description;
}
+ if (ps.defaultLightTheme !== undefined) {
+ set.defaultLightTheme = ps.defaultLightTheme;
+ }
+
+ if (ps.defaultDarkTheme !== undefined) {
+ set.defaultDarkTheme = ps.defaultDarkTheme;
+ }
+
if (ps.localDriveCapacityMb !== undefined) {
set.localDriveCapacityMb = ps.localDriveCapacityMb;
}
diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts
index 312b075794..6231c35ab9 100644
--- a/packages/backend/src/server/api/endpoints/meta.ts
+++ b/packages/backend/src/server/api/endpoints/meta.ts
@@ -69,6 +69,14 @@ export const meta = {
optional: false, nullable: false,
default: false,
},
+ defaultDarkTheme: {
+ type: 'string',
+ optional: false, nullable: true,
+ },
+ defaultLightTheme: {
+ type: 'string',
+ optional: false, nullable: true,
+ },
disableRegistration: {
type: 'boolean',
optional: false, nullable: false,
@@ -504,6 +512,8 @@ export default define(meta, paramDef, async (ps, me) => {
logoImageUrl: instance.logoImageUrl,
maxNoteTextLength: MAX_NOTE_TEXT_LENGTH, // 後方互換性のため
emojis: await Emojis.packMany(emojis),
+ defaultLightTheme: instance.defaultLightTheme,
+ defaultDarkTheme: instance.defaultDarkTheme,
ads: ads.map(ad => ({
id: ad.id,
url: ad.url,
diff --git a/packages/client/src/init.ts b/packages/client/src/init.ts
index 113324d494..ab3299d22b 100644
--- a/packages/client/src/init.ts
+++ b/packages/client/src/init.ts
@@ -15,6 +15,7 @@ if (localStorage.getItem('accounts') != null) {
import { computed, createApp, watch, markRaw, version as vueVersion } from 'vue';
import compareVersions from 'compare-versions';
+import * as JSON5 from 'json5';
import widgets from '@/widgets';
import directives from '@/directives';
@@ -159,7 +160,9 @@ if ($i && $i.token) {
}
//#endregion
-fetchInstance().then(() => {
+const fetchInstanceMetaPromise = fetchInstance();
+
+fetchInstanceMetaPromise.then(() => {
localStorage.setItem('v', instance.version);
// Init service worker
@@ -267,6 +270,14 @@ window.matchMedia('(prefers-color-scheme: dark)').addListener(mql => {
});
//#endregion
+fetchInstanceMetaPromise.then(() => {
+ if (defaultStore.state.themeInitial) {
+ if (instance.defaultLightTheme != null) ColdDeviceStorage.set('lightTheme', JSON5.parse(instance.defaultLightTheme));
+ if (instance.defaultDarkTheme != null) ColdDeviceStorage.set('darkTheme', JSON5.parse(instance.defaultDarkTheme));
+ defaultStore.set('themeInitial', false);
+ }
+});
+
// shortcut
document.addEventListener('keydown', makeHotkey({
'd': () => {
diff --git a/packages/client/src/pages/admin/settings.vue b/packages/client/src/pages/admin/settings.vue
index 5cf4d6c882..c5d7821329 100644
--- a/packages/client/src/pages/admin/settings.vue
+++ b/packages/client/src/pages/admin/settings.vue
@@ -31,6 +31,16 @@
#RRGGBB
+
+ {{ $ts.instanceDefaultLightTheme }}
+ {{ $ts.instanceDefaultThemeDescription }}
+
+
+
+ {{ $ts.instanceDefaultDarkTheme }}
+ {{ $ts.instanceDefaultThemeDescription }}
+
+
{{ $ts.tosUrl }}
@@ -176,6 +186,8 @@ export default defineComponent({
bannerUrl: null,
backgroundImageUrl: null,
themeColor: null,
+ defaultLightTheme: null,
+ defaultDarkTheme: null,
enableLocalTimeline: false,
enableGlobalTimeline: false,
pinnedUsers: '',
@@ -202,6 +214,8 @@ export default defineComponent({
this.bannerUrl = meta.bannerUrl;
this.backgroundImageUrl = meta.backgroundImageUrl;
this.themeColor = meta.themeColor;
+ this.defaultLightTheme = meta.defaultLightTheme;
+ this.defaultDarkTheme = meta.defaultDarkTheme;
this.maintainerName = meta.maintainerName;
this.maintainerEmail = meta.maintainerEmail;
this.enableLocalTimeline = !meta.disableLocalTimeline;
@@ -228,6 +242,8 @@ export default defineComponent({
bannerUrl: this.bannerUrl,
backgroundImageUrl: this.backgroundImageUrl,
themeColor: this.themeColor === '' ? null : this.themeColor,
+ defaultLightTheme: this.defaultLightTheme === '' ? null : this.defaultLightTheme,
+ defaultDarkTheme: this.defaultDarkTheme === '' ? null : this.defaultDarkTheme,
maintainerName: this.maintainerName,
maintainerEmail: this.maintainerEmail,
disableLocalTimeline: !this.enableLocalTimeline,
diff --git a/packages/client/src/pages/settings/theme.vue b/packages/client/src/pages/settings/theme.vue
index 72b7e69174..92a6fee7a4 100644
--- a/packages/client/src/pages/settings/theme.vue
+++ b/packages/client/src/pages/settings/theme.vue
@@ -87,6 +87,7 @@