Have features register settings fields dynamically

This commit is contained in:
thepaperpilot 2022-02-27 16:41:39 -06:00
parent a81040d6a2
commit 5beecba267
5 changed files with 53 additions and 17 deletions

View file

@ -7,9 +7,9 @@
</template>
<template v-slot:body>
<Select title="Theme" :options="themes" v-model="theme" />
<Select title="Show Milestones" :options="msDisplayOptions" v-model="msDisplay" />
<component :is="settingFieldsComponent" />
<Toggle title="Show TPS" v-model="showTPS" />
<Toggle title="Hide Maxed Challenges" v-model="hideChallenges" />
<hr />
<Toggle title="Unthrottled" v-model="unthrottled" />
<Toggle :title="offlineProdTitle" v-model="offlineProd" />
<Toggle :title="autosaveTitle" v-model="autosave" />
@ -21,15 +21,15 @@
<script setup lang="tsx">
import Modal from "@/components/Modal.vue";
import rawThemes from "@/data/themes";
import { MilestoneDisplay } from "@/features/milestones/milestone";
import player from "@/game/player";
import settings from "@/game/settings";
import settings, { settingFields } from "@/game/settings";
import { camelToTitle } from "@/util/common";
import { computed, ref, toRefs } from "vue";
import Toggle from "./fields/Toggle.vue";
import Select from "./fields/Select.vue";
import Tooltip from "./Tooltip.vue";
import { jsx } from "@/features/feature";
import { coerceComponent, render } from "@/util/vue";
const isOpen = ref(false);
@ -44,13 +44,11 @@ const themes = Object.keys(rawThemes).map(theme => ({
value: theme
}));
// TODO allow features to register options
const msDisplayOptions = Object.values(MilestoneDisplay).map(option => ({
label: camelToTitle(option),
value: option
}));
const settingFieldsComponent = computed(() => {
return coerceComponent(jsx(() => <>{settingFields.map(render)}</>));
});
const { showTPS, hideChallenges, theme, msDisplay, unthrottled } = toRefs(settings);
const { showTPS, theme, unthrottled } = toRefs(settings);
const { autosave, offlineProd } = toRefs(player);
const isPaused = computed({
get() {

View file

@ -1,9 +1,11 @@
import Toggle from "@/components/fields/Toggle.vue";
import ChallengeComponent from "@/features/challenges/Challenge.vue";
import {
CoercableComponent,
Component,
GatherProps,
getUniqueID,
jsx,
Replace,
setDefault,
StyleValue,
@ -12,8 +14,8 @@ import {
import { GenericReset } from "@/features/reset";
import { Resource } from "@/features/resources/resource";
import { globalBus } from "@/game/events";
import { PersistentRef, persistent } from "@/game/persistence";
import settings from "@/game/settings";
import { persistent, PersistentRef } from "@/game/persistence";
import settings, { registerSettingField } from "@/game/settings";
import Decimal, { DecimalSource } from "@/util/bignum";
import {
Computable,
@ -258,3 +260,13 @@ declare module "@/game/settings" {
globalBus.on("loadSettings", settings => {
setDefault(settings, "hideChallenges", false);
});
registerSettingField(
jsx(() => (
<Toggle
title="Hide Maxed Challenges"
onUpdate:modelValue={value => (settings.hideChallenges = value)}
modelValue={settings.hideChallenges}
/>
))
);

View file

@ -1,18 +1,22 @@
import MilestoneComponent from "@/features/milestones/Milestone.vue";
import Select from "@/components/fields/Select.vue";
import {
CoercableComponent,
Component,
findFeatures,
GatherProps,
getUniqueID,
jsx,
Replace,
setDefault,
StyleValue,
Visibility
} from "@/features/feature";
import MilestoneComponent from "@/features/milestones/Milestone.vue";
import { globalBus } from "@/game/events";
import "@/game/notifications";
import settings from "@/game/settings";
import { makePersistent, Persistent, PersistentState } from "@/game/persistence";
import settings, { registerSettingField } from "@/game/settings";
import { camelToTitle } from "@/util/common";
import {
Computable,
GetComputableType,
@ -25,7 +29,6 @@ import { coerceComponent, isCoercableComponent } from "@/util/vue";
import { Unsubscribe } from "nanoevents";
import { computed, Ref, unref } from "vue";
import { useToast } from "vue-toastification";
import { Persistent, makePersistent, PersistentState } from "@/game/persistence";
export const MilestoneType = Symbol("Milestone");
@ -186,3 +189,19 @@ declare module "@/game/settings" {
globalBus.on("loadSettings", settings => {
setDefault(settings, "msDisplay", MilestoneDisplay.All);
});
const msDisplayOptions = Object.values(MilestoneDisplay).map(option => ({
label: camelToTitle(option),
value: option
}));
registerSettingField(
jsx(() => (
<Select
title="Show Milestones"
options={msDisplayOptions}
onUpdate:modelValue={value => (settings.msDisplay = value as MilestoneDisplay)}
modelValue={settings.msDisplay}
/>
))
);

View file

@ -1,5 +1,6 @@
import modInfo from "@/data/modInfo.json";
import { Themes } from "@/data/themes";
import { CoercableComponent } from "@/features/feature";
import { globalBus } from "@/game/events";
import { hardReset } from "@/util/save";
import { reactive, watch } from "vue";
@ -53,3 +54,9 @@ export const hardResetSettings = (window.hardResetSettings = () => {
Object.assign(state, settings);
hardReset();
});
export const settingFields: CoercableComponent[] = reactive([]);
export function registerSettingField(component: CoercableComponent) {
settingFields.push(component);
}

View file

@ -62,11 +62,11 @@ export function render(object: VueFeature | CoercableComponent): JSX.Element | D
}
export function renderRow(...objects: (VueFeature | CoercableComponent)[]): JSX.Element {
return <Row>{objects.map(obj => render(obj))}</Row>;
return <Row>{objects.map(render)}</Row>;
}
export function renderCol(...objects: (VueFeature | CoercableComponent)[]): JSX.Element {
return <Col>{objects.map(obj => render(obj))}</Col>;
return <Col>{objects.map(render)}</Col>;
}
export function isCoercableComponent(component: unknown): component is CoercableComponent {