diff --git a/CHANGELOG.md b/CHANGELOG.md index e0b47ff5e8..7e3215dc6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Feat: 設定の管理が強化されました - 自動でバックアップされるように - Enhance: プラグインの管理が強化されました +- Enhance: テーマ設定画面のデザインを改善 - Fix: テーマ切り替え時に一部の色が変わらない問題を修正 ### Server diff --git a/locales/index.d.ts b/locales/index.d.ts index 0cdd428c82..1f06e25f1e 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -7746,6 +7746,10 @@ export interface Locale extends ILocale { * 標準のテーマ */ "builtinThemes": string; + /** + * サーバーのテーマ + */ + "instanceTheme": string; /** * そのテーマは既にインストールされています */ diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 1e41c43864..9b3a051f0b 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -2031,6 +2031,7 @@ _theme: installed: "{name}をインストールしました" installedThemes: "インストールされたテーマ" builtinThemes: "標準のテーマ" + instanceTheme: "サーバーのテーマ" alreadyInstalled: "そのテーマは既にインストールされています" invalid: "テーマの形式が間違っています" make: "テーマを作る" diff --git a/packages/frontend/src/components/MkThemePreview.vue b/packages/frontend/src/components/MkThemePreview.vue new file mode 100644 index 0000000000..5b180b3680 --- /dev/null +++ b/packages/frontend/src/components/MkThemePreview.vue @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/frontend/src/pages/settings/theme.vue b/packages/frontend/src/pages/settings/theme.vue index 71dba777b7..0e4f791f2c 100644 --- a/packages/frontend/src/pages/settings/theme.vue +++ b/packages/frontend/src/pages/settings/theme.vue @@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only - + @@ -36,23 +36,149 @@ SPDX-License-Identifier: AGPL-3.0-only - - + + - + + {{ i18n.ts.themeForLightMode }} - - + {{ lightThemeName }} + + + + {{ i18n.ts._theme.instanceTheme }} + + + + + + {{ instanceLightTheme.name }} + + + + + + + {{ i18n.ts._theme.installedThemes }} + + + + + + {{ theme.name }} + + + + + + + {{ i18n.ts._theme.builtinThemes }} + + + + + + {{ theme.name }} + + + + + + - - + + - + + {{ i18n.ts.themeForDarkMode }} - - + {{ darkThemeName }} + + + + {{ i18n.ts._theme.instanceTheme }} + + + + + + {{ instanceDarkTheme.name }} + + + + + + + {{ i18n.ts._theme.installedThemes }} + + + + + + {{ theme.name }} + + + + + + + {{ i18n.ts._theme.builtinThemes }} + + + + + + {{ theme.name }} + + + + + + - + @@ -77,12 +203,13 @@ import { computed, onActivated, ref, watch } from 'vue'; import JSON5 from 'json5'; import defaultLightTheme from '@@/themes/l-light.json5'; import defaultDarkTheme from '@@/themes/d-green-lime.json5'; -import type { MkSelectItem } from '@/components/MkSelect.vue'; +import type { Theme } from '@/theme.js'; import MkSwitch from '@/components/MkSwitch.vue'; -import MkSelect from '@/components/MkSelect.vue'; import FormSection from '@/components/form/section.vue'; import FormLink from '@/components/form/link.vue'; import MkButton from '@/components/MkButton.vue'; +import MkFolder from '@/components/MkFolder.vue'; +import MkThemePreview from '@/components/MkThemePreview.vue'; import { getBuiltinThemesRef } from '@/theme.js'; import { selectFile } from '@/utility/select-file.js'; import { isDeviceDarkmode } from '@/utility/is-device-darkmode.js'; @@ -99,79 +226,16 @@ import { prefer } from '@/preferences.js'; const installedThemes = ref(getThemes()); const builtinThemes = getBuiltinThemesRef(); -const instanceDarkTheme = computed(() => instance.defaultDarkTheme ? JSON5.parse(instance.defaultDarkTheme) : null); +const instanceDarkTheme = computed(() => instance.defaultDarkTheme ? JSON5.parse(instance.defaultDarkTheme) : null); const installedDarkThemes = computed(() => installedThemes.value.filter(t => t.base === 'dark' || t.kind === 'dark')); const builtinDarkThemes = computed(() => builtinThemes.value.filter(t => t.base === 'dark' || t.kind === 'dark')); -const instanceLightTheme = computed(() => instance.defaultLightTheme ? JSON5.parse(instance.defaultLightTheme) : null); +const instanceLightTheme = computed(() => instance.defaultLightTheme ? JSON5.parse(instance.defaultLightTheme) : null); const installedLightThemes = computed(() => installedThemes.value.filter(t => t.base === 'light' || t.kind === 'light')); const builtinLightThemes = computed(() => builtinThemes.value.filter(t => t.base === 'light' || t.kind === 'light')); const themes = computed(() => uniqueBy([instanceDarkTheme.value, instanceLightTheme.value, ...builtinThemes.value, ...installedThemes.value].filter(x => x != null), theme => theme.id)); -const lightThemeSelectorItems = computed(() => { - const items = [] as MkSelectItem[]; - if (instanceLightTheme.value) { - items.push({ - type: 'option', - value: instanceLightTheme.value.id, - label: instanceLightTheme.value.name, - }); - } - if (installedLightThemes.value.length > 0) { - items.push({ - type: 'group', - label: i18n.ts._theme.installedThemes, - items: installedLightThemes.value.map(x => ({ - type: 'option', - value: x.id, - label: x.name, - })), - }); - } - items.push({ - type: 'group', - label: i18n.ts._theme.builtinThemes, - items: builtinLightThemes.value.map(x => ({ - type: 'option', - value: x.id, - label: x.name, - })), - }); - return items; -}); - -const darkThemeSelectorItems = computed(() => { - const items = [] as MkSelectItem[]; - if (instanceDarkTheme.value) { - items.push({ - type: 'option', - value: instanceDarkTheme.value.id, - label: instanceDarkTheme.value.name, - }); - } - if (installedDarkThemes.value.length > 0) { - items.push({ - type: 'group', - label: i18n.ts._theme.installedThemes, - items: installedDarkThemes.value.map(x => ({ - type: 'option', - value: x.id, - label: x.name, - })), - }); - } - items.push({ - type: 'group', - label: i18n.ts._theme.builtinThemes, - items: builtinDarkThemes.value.map(x => ({ - type: 'option', - value: x.id, - label: x.name, - })), - }); - return items; -}); - const darkTheme = prefer.r.darkTheme; +const darkThemeName = computed(() => darkTheme.value?.name ?? defaultDarkTheme.name); const darkThemeId = computed({ get() { return darkTheme.value ? darkTheme.value.id : defaultDarkTheme.id; @@ -184,6 +248,7 @@ const darkThemeId = computed({ }, }); const lightTheme = prefer.r.lightTheme; +const lightThemeName = computed(() => lightTheme.value?.name ?? defaultLightTheme.name); const lightThemeId = computed({ get() { return lightTheme.value ? lightTheme.value.id : defaultLightTheme.id; @@ -236,6 +301,57 @@ definePage(() => ({ })); + + diff --git a/packages/frontend/src/theme.ts b/packages/frontend/src/theme.ts index ed2f1d3164..970d143b97 100644 --- a/packages/frontend/src/theme.ts +++ b/packages/frontend/src/theme.ts @@ -114,7 +114,7 @@ export function applyTheme(theme: Theme, persist = true) { globalEvents.emit('themeChanging'); } -function compile(theme: Theme): Record { +export function compile(theme: Theme): Record { function getColor(val: string): tinycolor.Instance { if (val[0] === '@') { // ref (prop) return getColor(theme.props[val.substring(1)]); diff --git a/packages/frontend/src/utility/autogen/settings-search-index.ts b/packages/frontend/src/utility/autogen/settings-search-index.ts index 66476672e3..db4459bf06 100644 --- a/packages/frontend/src/utility/autogen/settings-search-index.ts +++ b/packages/frontend/src/utility/autogen/settings-search-index.ts @@ -33,12 +33,12 @@ export const searchIndexes: SearchIndexItem[] = [ keywords: ['light', 'theme'], }, { - id: 'eLOwK5Ia2', + id: 'CsSVILKpX', label: i18n.ts.themeForDarkMode, keywords: ['dark', 'theme'], }, { - id: 'ujvMfyzUr', + id: '8wcoRp76b', label: i18n.ts.setWallpaper, keywords: ['wallpaper'], },