mirror of
https://github.com/modrinth/code.git
synced 2026-08-30 11:36:05 +00:00
* add account switcher, migrate context menus to overflow menu system, update version filter controls, only pad instance icons * app account switcher, improve some context menus, theme stuff * prepr * handle reauthentication * fix a couple sign in issues, admin page cleanup, fix org status badges, fix official account badge, open in local keybind, publish plus icons * rename generic menus to ButtonMenu (& types) * fix hydration issue w/ dropdowns + middleware error
163 lines
4.2 KiB
Vue
163 lines
4.2 KiB
Vue
<script setup lang="ts">
|
|
import {
|
|
AppearanceSettingsLayout,
|
|
injectAuth,
|
|
injectUserPreferences,
|
|
provideAppearanceSettings,
|
|
useSavable,
|
|
} from '@modrinth/ui'
|
|
import { computed, inject, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
|
|
|
import { type ColorTheme, isDarkTheme, useTheme } from '@/composables/use-theme.ts'
|
|
import { type AppSettings, get, set } from '@/helpers/settings.ts'
|
|
import { getOS } from '@/helpers/utils'
|
|
import { appSettingsModalContextKey } from '@/providers/app-settings-modal'
|
|
|
|
const theme = useTheme()
|
|
const auth = injectAuth()
|
|
const { updatePreferences } = injectUserPreferences()
|
|
const settingsModal = inject(appSettingsModalContextKey, null)
|
|
const os = await getOS()
|
|
const settings = ref(await get())
|
|
|
|
type AppearanceSettingsState = {
|
|
theme: ColorTheme
|
|
syncAcrossDevices: boolean
|
|
advancedRendering: boolean
|
|
nativeDecorations: boolean
|
|
}
|
|
|
|
function getAppearanceSettingsState(settings: AppSettings): AppearanceSettingsState {
|
|
return {
|
|
theme: settings.theme,
|
|
syncAcrossDevices: settings.sync_theme_across_devices,
|
|
advancedRendering: settings.advanced_rendering,
|
|
nativeDecorations: settings.native_decorations,
|
|
}
|
|
}
|
|
|
|
const { saved, current, changes, saving, hasChanges, reset, save } = useSavable(
|
|
() => getAppearanceSettingsState(settings.value),
|
|
async (appearanceChanges) => {
|
|
const value = current.value
|
|
if (
|
|
value.syncAcrossDevices &&
|
|
auth.user.value &&
|
|
(appearanceChanges.theme !== undefined || appearanceChanges.syncAcrossDevices !== undefined)
|
|
) {
|
|
await updatePreferences({
|
|
appearance: value.theme === 'system' ? { auto: true } : { auto: false, theme: value.theme },
|
|
})
|
|
}
|
|
|
|
const nextSettings: AppSettings = {
|
|
...settings.value,
|
|
theme: value.theme,
|
|
sync_theme_across_devices: value.syncAcrossDevices,
|
|
advanced_rendering: value.advancedRendering,
|
|
native_decorations: value.nativeDecorations,
|
|
}
|
|
|
|
await set(nextSettings)
|
|
settings.value = nextSettings
|
|
if (isDarkTheme(value.theme)) {
|
|
theme.preferredDark = value.theme
|
|
}
|
|
theme.preferred = value.theme
|
|
theme.syncAcrossDevices = value.syncAcrossDevices
|
|
theme.advancedRendering = value.advancedRendering
|
|
},
|
|
)
|
|
|
|
const themeOptions = computed(() =>
|
|
theme.options.filter(
|
|
(option) =>
|
|
option !== 'retro' || settings.value.developer_mode || current.value.theme === 'retro',
|
|
),
|
|
)
|
|
|
|
const preferredDarkTheme = computed(() =>
|
|
isDarkTheme(current.value.theme) ? current.value.theme : theme.preferredDark,
|
|
)
|
|
|
|
function setTheme(value: ColorTheme): void {
|
|
current.value.theme = value
|
|
}
|
|
|
|
function setSyncAcrossDevices(enabled: boolean): void {
|
|
current.value.syncAcrossDevices = enabled
|
|
}
|
|
|
|
function setAdvancedRendering(enabled: boolean): void {
|
|
current.value.advancedRendering = enabled
|
|
}
|
|
|
|
function setNativeDecorations(enabled: boolean): void {
|
|
current.value.nativeDecorations = enabled
|
|
}
|
|
|
|
watch(
|
|
[() => current.value.theme, () => saved.value.theme],
|
|
([selectedTheme, savedTheme]) => {
|
|
theme.preview = selectedTheme === savedTheme ? null : selectedTheme
|
|
},
|
|
{ immediate: true },
|
|
)
|
|
|
|
async function saveAppearanceSettings(): Promise<void> {
|
|
try {
|
|
await save()
|
|
} catch {
|
|
return
|
|
}
|
|
}
|
|
|
|
onMounted(() => {
|
|
settingsModal?.registerUnsavedChangesController({
|
|
hasChanges: () => hasChanges.value,
|
|
getOriginal: () => saved.value,
|
|
getModified: () => changes.value,
|
|
isSaving: () => saving.value,
|
|
reset,
|
|
save: saveAppearanceSettings,
|
|
})
|
|
})
|
|
|
|
onBeforeUnmount(() => {
|
|
theme.preview = null
|
|
settingsModal?.registerUnsavedChangesController(null)
|
|
})
|
|
|
|
provideAppearanceSettings({
|
|
deferPersistence: true,
|
|
theme: {
|
|
current: computed(() => current.value.theme),
|
|
options: themeOptions,
|
|
system: computed(() => (theme.native === 'light' ? 'light' : preferredDarkTheme.value)),
|
|
preferredDark: preferredDarkTheme,
|
|
set: setTheme,
|
|
syncAcrossDevices: {
|
|
value: computed(() => current.value.syncAcrossDevices),
|
|
set: setSyncAcrossDevices,
|
|
},
|
|
syncDisabled: computed(() => !auth.user.value),
|
|
},
|
|
advancedRendering: {
|
|
value: computed(() => current.value.advancedRendering),
|
|
set: setAdvancedRendering,
|
|
},
|
|
nativeDecorations:
|
|
os !== 'MacOS'
|
|
? {
|
|
value: computed(() => current.value.nativeDecorations),
|
|
set: setNativeDecorations,
|
|
}
|
|
: undefined,
|
|
updatePreferences,
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<AppearanceSettingsLayout />
|
|
</template>
|