refactor: app settings layout (#6891)

* refactor: app settings layout

* fix: privacy copy got reverted

* fix: i18n

* fix: modal title

* fix: rev comments
This commit is contained in:
Calum H.
2026-07-28 14:09:41 +00:00
committed by GitHub
parent 3c8bb0923d
commit 5d34e7902a
50 changed files with 1645 additions and 961 deletions
@@ -6,7 +6,7 @@ import {
LanguagesIcon,
ModrinthIcon,
PaintbrushIcon,
SettingsIcon,
Settings2Icon,
ShieldIcon,
ToggleRightIcon,
} from '@modrinth/assets'
@@ -21,19 +21,21 @@ import {
} from '@modrinth/ui'
import { getVersion } from '@tauri-apps/api/app'
import { platform as getOsPlatform, version as getOsVersion } from '@tauri-apps/plugin-os'
import { ref, watch } from 'vue'
import { computed, ref, watch } from 'vue'
import AppearanceSettings from '@/components/ui/settings/AppearanceSettings.vue'
import DefaultInstanceSettings from '@/components/ui/settings/DefaultInstanceSettings.vue'
import FeatureFlagSettings from '@/components/ui/settings/FeatureFlagSettings.vue'
import JavaSettings from '@/components/ui/settings/JavaSettings.vue'
import LanguageSettings from '@/components/ui/settings/LanguageSettings.vue'
import PrivacySettings from '@/components/ui/settings/PrivacySettings.vue'
import ResourceManagementSettings from '@/components/ui/settings/ResourceManagementSettings.vue'
import PrivacySettings from '@/components/ui/settings/account/PrivacySettings.vue'
import AppearanceSettings from '@/components/ui/settings/display/AppearanceSettings.vue'
import BehaviorSettings from '@/components/ui/settings/display/BehaviorSettings.vue'
import FeatureFlagSettings from '@/components/ui/settings/display/FeatureFlagSettings.vue'
import LanguageSettings from '@/components/ui/settings/display/LanguageSettings.vue'
import DefaultInstanceSettings from '@/components/ui/settings/instances/DefaultInstanceSettings.vue'
import JavaSettings from '@/components/ui/settings/instances/JavaSettings.vue'
import ResourceManagementSettings from '@/components/ui/settings/instances/ResourceManagementSettings.vue'
import { get, set } from '@/helpers/settings.ts'
import { injectAppUpdateDownloadProgress } from '@/providers/download-progress.ts'
import { useTheming } from '@/store/state'
// TODO: Apply COMPONENT_STRUCTURE.md here and extract out common setting option components
const themeStore = useTheming()
const { formatMessage } = useVIntl()
@@ -45,64 +47,97 @@ const developerModeEnabled = defineMessage({
defaultMessage: 'Developer mode enabled.',
})
const tabCategories = defineMessages({
display: {
id: 'settings.sidebar.label.display',
defaultMessage: 'Display',
},
account: {
id: 'settings.sidebar.label.account',
defaultMessage: 'Account',
},
instances: {
id: 'app.settings.sidebar.label.instances',
defaultMessage: 'Instances',
},
})
const tabs = [
{
name: defineMessage({
id: 'app.settings.tabs.appearance',
defaultMessage: 'Appearance',
}),
category: tabCategories.display,
icon: PaintbrushIcon,
content: AppearanceSettings,
},
{
name: defineMessage({
id: 'app.settings.tabs.behavior',
defaultMessage: 'Behavior',
}),
category: tabCategories.display,
icon: Settings2Icon,
content: BehaviorSettings,
},
{
name: defineMessage({
id: 'app.settings.tabs.language',
defaultMessage: 'Language',
}),
category: tabCategories.display,
icon: LanguagesIcon,
content: LanguageSettings,
badge: commonMessages.beta,
},
{
name: commonSettingsMessages.featureFlags,
category: tabCategories.display,
icon: ToggleRightIcon,
content: FeatureFlagSettings,
developerOnly: true,
},
{
name: defineMessage({
id: 'app.settings.tabs.privacy',
defaultMessage: 'Privacy',
}),
category: tabCategories.account,
icon: ShieldIcon,
content: PrivacySettings,
},
{
name: defineMessage({
id: 'app.settings.tabs.java-installations',
defaultMessage: 'Java installations',
}),
icon: CoffeeIcon,
content: JavaSettings,
},
{
name: defineMessage({
id: 'app.settings.tabs.default-instance-options',
defaultMessage: 'Default instance options',
}),
category: tabCategories.instances,
icon: GameIcon,
content: DefaultInstanceSettings,
},
{
name: defineMessage({
id: 'app.settings.tabs.java-installations',
defaultMessage: 'Java installations',
}),
category: tabCategories.instances,
icon: CoffeeIcon,
content: JavaSettings,
},
{
name: defineMessage({
id: 'app.settings.tabs.resource-management',
defaultMessage: 'Resource management',
}),
category: tabCategories.instances,
icon: GaugeIcon,
content: ResourceManagementSettings,
},
{
name: commonSettingsMessages.featureFlags,
icon: ToggleRightIcon,
content: FeatureFlagSettings,
developerOnly: true,
},
]
const availableTabs = computed(() => tabs.filter((tab) => !tab.developerOnly || themeStore.devMode))
const modal = ref<InstanceType<typeof TabbedModal> | null>(null)
function show() {
@@ -129,12 +164,15 @@ watch(
function devModeCount() {
devModeCounter.value++
if (devModeCounter.value > 5) {
const selectedTab = modal.value ? availableTabs.value[modal.value.selectedTab] : undefined
themeStore.devMode = !themeStore.devMode
settings.value.developer_mode = !!themeStore.devMode
devModeCounter.value = 0
if (!themeStore.devMode && tabs[modal.value!.selectedTab].developerOnly) {
modal.value!.setTab(0)
if (modal.value) {
const selectedTabIndex = selectedTab ? availableTabs.value.indexOf(selectedTab) : -1
modal.value.setTab(selectedTabIndex >= 0 ? selectedTabIndex : 0)
}
}
}
@@ -144,13 +182,25 @@ const messages = defineMessages({
id: 'app.settings.downloading',
defaultMessage: 'Downloading v{version}',
},
appVersion: {
id: 'app.settings.app-version',
defaultMessage: 'Modrinth App {version}',
},
macos: {
id: 'app.settings.operating-system.macos',
defaultMessage: 'macOS',
},
developerModeButtonLabel: {
id: 'app.settings.developer-mode-button.label',
defaultMessage: 'Toggle developer mode',
},
})
</script>
<template>
<TabbedModal ref="modal" :tabs="tabs.filter((t) => !t.developerOnly || themeStore.devMode)">
<TabbedModal ref="modal" :tabs="availableTabs" :width="'min(928px, calc(95vw - 10rem))'">
<template #title>
<span class="flex items-center gap-2 text-lg font-extrabold text-contrast">
<SettingsIcon /> Settings
<span class="text-2xl font-semibold text-contrast">
{{ formatMessage(commonMessages.settingsLabel) }}
</span>
</template>
<template #footer>
@@ -168,6 +218,7 @@ const messages = defineMessages({
</p>
<div class="flex items-center gap-3">
<button
:aria-label="formatMessage(messages.developerModeButtonLabel)"
class="p-0 m-0 bg-transparent border-none cursor-pointer button-animation"
:class="{
'text-brand': themeStore.devMode,
@@ -175,12 +226,14 @@ const messages = defineMessages({
}"
@click="devModeCount"
>
<ModrinthIcon class="w-6 h-6" />
<ModrinthIcon aria-hidden="true" class="w-6 h-6" />
</button>
<div class="max-w-[200px]">
<p class="m-0">Modrinth App {{ version }}</p>
<p class="m-0">
<span v-if="osPlatform === 'macos'">macOS</span>
{{ formatMessage(messages.appVersion, { version }) }}
</p>
<p class="m-0">
<span v-if="osPlatform === 'macos'">{{ formatMessage(messages.macos) }}</span>
<span v-else class="capitalize">{{ osPlatform }}</span>
{{ osVersion }}
</p>