feat: instance default theme
This commit is contained in:
		
							parent
							
								
									bc9157a03b
								
							
						
					
					
						commit
						ba4ef23d6b
					
				
					 10 changed files with 93 additions and 5 deletions
				
			
		|  | @ -16,11 +16,12 @@ You should also include the user name that made the change. | ||||||
| このバージョンからNode v16.14.0以降が必要です | このバージョンからNode v16.14.0以降が必要です | ||||||
| 
 | 
 | ||||||
| ### Changes | ### Changes | ||||||
| - ノートの最大文字数を設定できる機能が廃止され、デフォルトで一律3000文字になりました | - ノートの最大文字数を設定できる機能が廃止され、デフォルトで一律3000文字になりました @syuilo | ||||||
| 
 | 
 | ||||||
| ### Improvements | ### Improvements | ||||||
| - プロフィールの追加情報を最大16まで保存できるように | - インスタンスデフォルトテーマを設定できるように @syuilo | ||||||
| - 連合チャートにPub&Subを追加 | - プロフィールの追加情報を最大16まで保存できるように @syuilo | ||||||
|  | - 連合チャートにPub&Subを追加 @syuilo | ||||||
| 
 | 
 | ||||||
| ### Bugfixes | ### Bugfixes | ||||||
| - Client: リアクションピッカーの高さが低くなったまま戻らないことがあるのを修正 @syuilo | - Client: リアクションピッカーの高さが低くなったまま戻らないことがあるのを修正 @syuilo | ||||||
|  |  | ||||||
|  | @ -831,6 +831,9 @@ themeColor: "テーマカラー" | ||||||
| size: "サイズ" | size: "サイズ" | ||||||
| numberOfColumn: "列の数" | numberOfColumn: "列の数" | ||||||
| searchByGoogle: "ググる" | searchByGoogle: "ググる" | ||||||
|  | instanceDefaultLightTheme: "インスタンスデフォルトのライトテーマ" | ||||||
|  | instanceDefaultDarkTheme: "インスタンスデフォルトのダークテーマ" | ||||||
|  | instanceDefaultThemeDescription: "オブジェクト形式のテーマコードを記入します。" | ||||||
| 
 | 
 | ||||||
| _emailUnavailable: | _emailUnavailable: | ||||||
|   used: "既に使用されています" |   used: "既に使用されています" | ||||||
|  |  | ||||||
|  | @ -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"`); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -344,6 +344,20 @@ export class Meta { | ||||||
| 	}) | 	}) | ||||||
| 	public feedbackUrl: string | null; | 	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', { | 	@Column('boolean', { | ||||||
| 		default: false, | 		default: false, | ||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
|  | @ -36,6 +36,8 @@ export const paramDef = { | ||||||
| 		logoImageUrl: { type: 'string', nullable: true }, | 		logoImageUrl: { type: 'string', nullable: true }, | ||||||
| 		name: { type: 'string', nullable: true }, | 		name: { type: 'string', nullable: true }, | ||||||
| 		description: { type: 'string', nullable: true }, | 		description: { type: 'string', nullable: true }, | ||||||
|  | 		defaultLightTheme: { type: 'string', nullable: true }, | ||||||
|  | 		defaultDarkTheme: { type: 'string', nullable: true }, | ||||||
| 		localDriveCapacityMb: { type: 'integer' }, | 		localDriveCapacityMb: { type: 'integer' }, | ||||||
| 		remoteDriveCapacityMb: { type: 'integer' }, | 		remoteDriveCapacityMb: { type: 'integer' }, | ||||||
| 		cacheRemoteFiles: { type: 'boolean' }, | 		cacheRemoteFiles: { type: 'boolean' }, | ||||||
|  | @ -162,6 +164,14 @@ export default define(meta, paramDef, async (ps, me) => { | ||||||
| 		set.description = ps.description; | 		set.description = ps.description; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (ps.defaultLightTheme !== undefined) { | ||||||
|  | 		set.defaultLightTheme = ps.defaultLightTheme; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (ps.defaultDarkTheme !== undefined) { | ||||||
|  | 		set.defaultDarkTheme = ps.defaultDarkTheme; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	if (ps.localDriveCapacityMb !== undefined) { | 	if (ps.localDriveCapacityMb !== undefined) { | ||||||
| 		set.localDriveCapacityMb = ps.localDriveCapacityMb; | 		set.localDriveCapacityMb = ps.localDriveCapacityMb; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -69,6 +69,14 @@ export const meta = { | ||||||
| 				optional: false, nullable: false, | 				optional: false, nullable: false, | ||||||
| 				default: false, | 				default: false, | ||||||
| 			}, | 			}, | ||||||
|  | 			defaultDarkTheme: { | ||||||
|  | 				type: 'string', | ||||||
|  | 				optional: false, nullable: true, | ||||||
|  | 			}, | ||||||
|  | 			defaultLightTheme: { | ||||||
|  | 				type: 'string', | ||||||
|  | 				optional: false, nullable: true, | ||||||
|  | 			}, | ||||||
| 			disableRegistration: { | 			disableRegistration: { | ||||||
| 				type: 'boolean', | 				type: 'boolean', | ||||||
| 				optional: false, nullable: false, | 				optional: false, nullable: false, | ||||||
|  | @ -504,6 +512,8 @@ export default define(meta, paramDef, async (ps, me) => { | ||||||
| 		logoImageUrl: instance.logoImageUrl, | 		logoImageUrl: instance.logoImageUrl, | ||||||
| 		maxNoteTextLength: MAX_NOTE_TEXT_LENGTH, // 後方互換性のため
 | 		maxNoteTextLength: MAX_NOTE_TEXT_LENGTH, // 後方互換性のため
 | ||||||
| 		emojis: await Emojis.packMany(emojis), | 		emojis: await Emojis.packMany(emojis), | ||||||
|  | 		defaultLightTheme: instance.defaultLightTheme, | ||||||
|  | 		defaultDarkTheme: instance.defaultDarkTheme, | ||||||
| 		ads: ads.map(ad => ({ | 		ads: ads.map(ad => ({ | ||||||
| 			id: ad.id, | 			id: ad.id, | ||||||
| 			url: ad.url, | 			url: ad.url, | ||||||
|  |  | ||||||
|  | @ -15,6 +15,7 @@ if (localStorage.getItem('accounts') != null) { | ||||||
| 
 | 
 | ||||||
| import { computed, createApp, watch, markRaw, version as vueVersion } from 'vue'; | import { computed, createApp, watch, markRaw, version as vueVersion } from 'vue'; | ||||||
| import compareVersions from 'compare-versions'; | import compareVersions from 'compare-versions'; | ||||||
|  | import * as JSON5 from 'json5'; | ||||||
| 
 | 
 | ||||||
| import widgets from '@/widgets'; | import widgets from '@/widgets'; | ||||||
| import directives from '@/directives'; | import directives from '@/directives'; | ||||||
|  | @ -159,7 +160,9 @@ if ($i && $i.token) { | ||||||
| } | } | ||||||
| //#endregion
 | //#endregion
 | ||||||
| 
 | 
 | ||||||
| fetchInstance().then(() => { | const fetchInstanceMetaPromise = fetchInstance(); | ||||||
|  | 
 | ||||||
|  | fetchInstanceMetaPromise.then(() => { | ||||||
| 	localStorage.setItem('v', instance.version); | 	localStorage.setItem('v', instance.version); | ||||||
| 
 | 
 | ||||||
| 	// Init service worker
 | 	// Init service worker
 | ||||||
|  | @ -267,6 +270,14 @@ window.matchMedia('(prefers-color-scheme: dark)').addListener(mql => { | ||||||
| }); | }); | ||||||
| //#endregion
 | //#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
 | // shortcut
 | ||||||
| document.addEventListener('keydown', makeHotkey({ | document.addEventListener('keydown', makeHotkey({ | ||||||
| 	'd': () => { | 	'd': () => { | ||||||
|  |  | ||||||
|  | @ -31,6 +31,16 @@ | ||||||
| 				<template #caption>#RRGGBB</template> | 				<template #caption>#RRGGBB</template> | ||||||
| 			</FormInput> | 			</FormInput> | ||||||
| 
 | 
 | ||||||
|  | 			<FormTextarea v-model="defaultLightTheme" class="_formBlock"> | ||||||
|  | 				<template #label>{{ $ts.instanceDefaultLightTheme }}</template> | ||||||
|  | 				<template #caption>{{ $ts.instanceDefaultThemeDescription }}</template> | ||||||
|  | 			</FormTextarea> | ||||||
|  | 
 | ||||||
|  | 			<FormTextarea v-model="defaultDarkTheme" class="_formBlock"> | ||||||
|  | 				<template #label>{{ $ts.instanceDefaultDarkTheme }}</template> | ||||||
|  | 				<template #caption>{{ $ts.instanceDefaultThemeDescription }}</template> | ||||||
|  | 			</FormTextarea> | ||||||
|  | 
 | ||||||
| 			<FormInput v-model="tosUrl" class="_formBlock"> | 			<FormInput v-model="tosUrl" class="_formBlock"> | ||||||
| 				<template #prefix><i class="fas fa-link"></i></template> | 				<template #prefix><i class="fas fa-link"></i></template> | ||||||
| 				<template #label>{{ $ts.tosUrl }}</template> | 				<template #label>{{ $ts.tosUrl }}</template> | ||||||
|  | @ -176,6 +186,8 @@ export default defineComponent({ | ||||||
| 			bannerUrl: null, | 			bannerUrl: null, | ||||||
| 			backgroundImageUrl: null, | 			backgroundImageUrl: null, | ||||||
| 			themeColor: null, | 			themeColor: null, | ||||||
|  | 			defaultLightTheme: null, | ||||||
|  | 			defaultDarkTheme: null, | ||||||
| 			enableLocalTimeline: false, | 			enableLocalTimeline: false, | ||||||
| 			enableGlobalTimeline: false, | 			enableGlobalTimeline: false, | ||||||
| 			pinnedUsers: '', | 			pinnedUsers: '', | ||||||
|  | @ -202,6 +214,8 @@ export default defineComponent({ | ||||||
| 			this.bannerUrl = meta.bannerUrl; | 			this.bannerUrl = meta.bannerUrl; | ||||||
| 			this.backgroundImageUrl = meta.backgroundImageUrl; | 			this.backgroundImageUrl = meta.backgroundImageUrl; | ||||||
| 			this.themeColor = meta.themeColor; | 			this.themeColor = meta.themeColor; | ||||||
|  | 			this.defaultLightTheme = meta.defaultLightTheme; | ||||||
|  | 			this.defaultDarkTheme = meta.defaultDarkTheme; | ||||||
| 			this.maintainerName = meta.maintainerName; | 			this.maintainerName = meta.maintainerName; | ||||||
| 			this.maintainerEmail = meta.maintainerEmail; | 			this.maintainerEmail = meta.maintainerEmail; | ||||||
| 			this.enableLocalTimeline = !meta.disableLocalTimeline; | 			this.enableLocalTimeline = !meta.disableLocalTimeline; | ||||||
|  | @ -228,6 +242,8 @@ export default defineComponent({ | ||||||
| 				bannerUrl: this.bannerUrl, | 				bannerUrl: this.bannerUrl, | ||||||
| 				backgroundImageUrl: this.backgroundImageUrl, | 				backgroundImageUrl: this.backgroundImageUrl, | ||||||
| 				themeColor: this.themeColor === '' ? null : this.themeColor, | 				themeColor: this.themeColor === '' ? null : this.themeColor, | ||||||
|  | 				defaultLightTheme: this.defaultLightTheme === '' ? null : this.defaultLightTheme, | ||||||
|  | 				defaultDarkTheme: this.defaultDarkTheme === '' ? null : this.defaultDarkTheme, | ||||||
| 				maintainerName: this.maintainerName, | 				maintainerName: this.maintainerName, | ||||||
| 				maintainerEmail: this.maintainerEmail, | 				maintainerEmail: this.maintainerEmail, | ||||||
| 				disableLocalTimeline: !this.enableLocalTimeline, | 				disableLocalTimeline: !this.enableLocalTimeline, | ||||||
|  |  | ||||||
|  | @ -87,6 +87,7 @@ | ||||||
| 
 | 
 | ||||||
| <script lang="ts"> | <script lang="ts"> | ||||||
| import { computed, defineComponent, onActivated, onMounted, ref, watch } from 'vue'; | import { computed, defineComponent, onActivated, onMounted, ref, watch } from 'vue'; | ||||||
|  | import * as JSON5 from 'json5'; | ||||||
| import FormSwitch from '@/components/form/switch.vue'; | import FormSwitch from '@/components/form/switch.vue'; | ||||||
| import FormSelect from '@/components/form/select.vue'; | import FormSelect from '@/components/form/select.vue'; | ||||||
| import FormGroup from '@/components/form/group.vue'; | import FormGroup from '@/components/form/group.vue'; | ||||||
|  | @ -99,6 +100,8 @@ import { isDeviceDarkmode } from '@/scripts/is-device-darkmode'; | ||||||
| import { ColdDeviceStorage } from '@/store'; | import { ColdDeviceStorage } from '@/store'; | ||||||
| import { i18n } from '@/i18n'; | import { i18n } from '@/i18n'; | ||||||
| import { defaultStore } from '@/store'; | import { defaultStore } from '@/store'; | ||||||
|  | import { instance } from '@/instance'; | ||||||
|  | import { concat } from '@/scripts/array'; | ||||||
| import { fetchThemes, getThemes } from '@/theme-store'; | import { fetchThemes, getThemes } from '@/theme-store'; | ||||||
| import * as symbols from '@/symbols'; | import * as symbols from '@/symbols'; | ||||||
| 
 | 
 | ||||||
|  | @ -122,7 +125,10 @@ export default defineComponent({ | ||||||
| 		}; | 		}; | ||||||
| 
 | 
 | ||||||
| 		const installedThemes = ref(getThemes()); | 		const installedThemes = ref(getThemes()); | ||||||
| 		const themes = computed(() => builtinThemes.concat(installedThemes.value)); | 		const instanceThemes = []; | ||||||
|  | 		if (instance.defaultLightTheme != null) instanceThemes.push(JSON5.parse(instance.defaultLightTheme)); | ||||||
|  | 		if (instance.defaultDarkTheme != null) instanceThemes.push(JSON5.parse(instance.defaultDarkTheme)); | ||||||
|  | 		const themes = computed(() => instanceThemes.concat(builtinThemes.concat(installedThemes.value))); | ||||||
| 		const darkThemes = computed(() => themes.value.filter(t => t.base === 'dark' || t.kind === 'dark')); | 		const darkThemes = computed(() => themes.value.filter(t => t.base === 'dark' || t.kind === 'dark')); | ||||||
| 		const lightThemes = computed(() => themes.value.filter(t => t.base === 'light' || t.kind === 'light')); | 		const lightThemes = computed(() => themes.value.filter(t => t.base === 'light' || t.kind === 'light')); | ||||||
| 		const darkTheme = ColdDeviceStorage.ref('darkTheme'); | 		const darkTheme = ColdDeviceStorage.ref('darkTheme'); | ||||||
|  |  | ||||||
|  | @ -230,6 +230,10 @@ export const defaultStore = markRaw(new Storage('base', { | ||||||
| 		where: 'device', | 		where: 'device', | ||||||
| 		default: '' | 		default: '' | ||||||
| 	}, | 	}, | ||||||
|  | 	themeInitial: { | ||||||
|  | 		where: 'device', | ||||||
|  | 		default: true, | ||||||
|  | 	}, | ||||||
| 	aiChanMode: { | 	aiChanMode: { | ||||||
| 		where: 'device', | 		where: 'device', | ||||||
| 		default: false | 		default: false | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue