diff options
Diffstat (limited to 'src/components/SettingsModal.vue')
| -rw-r--r-- | src/components/SettingsModal.vue | 278 |
1 files changed, 148 insertions, 130 deletions
diff --git a/src/components/SettingsModal.vue b/src/components/SettingsModal.vue index a54fa58..83b42af 100644 --- a/src/components/SettingsModal.vue +++ b/src/components/SettingsModal.vue @@ -1,164 +1,182 @@ <script lang="ts"> + import {defineComponent, PropType} from 'vue'; -import CloseIcon from './icon/CloseIcon.vue'; import RButton from './RButton.vue'; +import CloseIcon from './icon/CloseIcon.vue'; import {UiOptions} from '../lib'; import {LayoutOptions} from '../layout'; -// Displays configurable options, and sends option-change requests export default defineComponent({ props: { lytOpts: {type: Object as PropType<LayoutOptions>, required: true}, uiOpts: {type: Object as PropType<UiOptions>, required: true}, }, + data(){ + // For making subsets of various options' values available for user selection + let userLayoutTypeVals = [ // Holds pairs of labels with option values + ['Yes', 'sweep'], + ['No', 'rect'] + ]; + let userTileSpacingVals = [ + ['Small', 6], + ['Medium', 10], + ['Large', 20] + ]; + let userTileSizeVals = [ + ['Default', 50, 200], + ['Small', 50, 50], + ['Medium', 100, 100], + ['Large', 200, 200], + ['Flexible', 0, 400], + ]; + // Warn if user-available values don't include the active option value (indicates a developer mistake) + let layoutTypeIdx = userLayoutTypeVals.findIndex(([, optVal]) => optVal == this.lytOpts.layoutType); + if (layoutTypeIdx == -1){ + console.log("WARNING: Initial layoutType option value not included in user setting values"); + } + let tileSpacingIdx = userTileSpacingVals.findIndex(([, optVal]) => optVal == this.lytOpts.tileSpacing); + if (tileSpacingIdx == -1){ + console.log("WARNING: Initial tileSpacing option value not included in user setting values"); + } + let tileSizeValIdx = userTileSizeVals.findIndex( + ([, min, max]) => min == this.lytOpts.minTileSz && max == this.lytOpts.maxTileSz + ); + if (tileSizeValIdx == -1){ + console.log("WARNING: Initial minTileSz/maxTileSz option value not included in user setting values"); + } + // + return { + userLayoutTypeVals, + userLayoutType: userLayoutTypeVals[layoutTypeIdx != -1 ? layoutTypeIdx : 0][0], + userTileSpacingVals, + userTileSpacing: userTileSpacingVals[tileSpacingIdx != -1 ? tileSpacingIdx : 0][0], + userTileSizeVals, + userTileSize: userTileSizeVals[tileSizeValIdx != -1 ? tileSizeValIdx : 0][0], + }; + }, + computed: { + styles(): Record<string,string> { + return { + backgroundColor: this.uiOpts.bgColorAlt, + borderRadius: this.uiOpts.borderRadius + 'px', + boxShadow: this.uiOpts.shadowNormal, + }; + }, + }, methods: { - onCloseClick(evt: Event){ + onClose(evt: Event){ if (evt.target == this.$el || (this.$refs.closeIcon as typeof CloseIcon).$el.contains(evt.target)){ this.$emit('close'); } }, onSettingChg(setting: string){ - if (setting == 'minTileSz'){ - let minInput = this.$refs.minTileSzInput as HTMLInputElement; - let maxInput = this.$refs.maxTileSzInput as HTMLInputElement; - if (Number(minInput.value) > Number(maxInput.value)){ - this.lytOpts.maxTileSz = this.lytOpts.minTileSz; - } - } else if (setting == 'maxTileSz'){ - let minInput = this.$refs.minTileSzInput as HTMLInputElement; - let maxInput = this.$refs.maxTileSzInput as HTMLInputElement; - if (Number(maxInput.value) < Number(minInput.value)){ - this.lytOpts.minTileSz = this.lytOpts.maxTileSz; - } - } this.$emit('setting-chg', setting); }, - onReset(){ - this.$emit('reset'); + }, + watch: { + // Propagate option-subsetting user-settings to options + userLayoutType(newVal, oldVal){ + let [,optVal] = this.userLayoutTypeVals.find(([val,]) => val == newVal)!; + this.lytOpts.layoutType = optVal as LayoutOptions['layoutType']; + }, + userTileSpacing(newVal, oldVal){ + let [,optVal] = this.userTileSpacingVals.find(([val,]) => val == newVal)!; + this.lytOpts.tileSpacing = optVal as LayoutOptions['tileSpacing']; + }, + userTileSize(newVal, oldVal){ + let [,min,max] = this.userTileSizeVals.find(([val,,]) => val == newVal)!; + this.lytOpts.minTileSz = min as LayoutOptions['minTileSz']; + this.lytOpts.maxTileSz = max as LayoutOptions['maxTileSz']; }, }, - components: {CloseIcon, RButton, }, + components: {RButton, CloseIcon, }, emits: ['close', 'setting-chg', 'reset', ], }); </script> <template> -<div class="fixed left-0 top-0 w-full h-full bg-black/40" @click="onCloseClick"> - <div class="absolute left-1/2 -translate-x-1/2 w-4/5 top-1/2 -translate-y-1/2 max-h-[80%] - p-3 bg-stone-50 visible rounded-md shadow shadow-black"> - <close-icon @click.stop="onCloseClick" ref="closeIcon" +<div class="fixed left-0 top-0 w-full h-full bg-black/40" @click="onClose"> + <div class="absolute left-1/2 -translate-x-1/2 top-1/2 -translate-y-1/2 + min-w-[8cm] max-h-[80%] overflow-auto p-3" :style="styles"> + <close-icon @click.stop="onClose" ref="closeIcon" class="block absolute top-2 right-2 w-6 h-6 hover:cursor-pointer" /> <h1 class="text-xl font-bold mb-2">Settings</h1> - <hr class="border-stone-400"/> - <div> - <label>Tile Spacing <input type="range" min="0" max="20" class="mx-2 w-[3cm]" - v-model.number="lytOpts.tileSpacing" @input="onSettingChg('tileSpacing')"/></label> - </div> - <hr class="border-stone-400"/> - <div> - <label> - <span class="inline-block w-[3cm]">Min Tile Size</span> - <input type="range" min="0" max="400" v-model.number="lytOpts.minTileSz" class="w-[3cm]" - @input="onSettingChg('minTileSz')" ref="minTileSzInput"/> - </label> - </div> - <div> - <label> - <span class="inline-block w-[3cm]">Max Tile Size</span> - <input type="range" min="0" max="400" v-model.number="lytOpts.maxTileSz" class="w-[3cm]" - @input="onSettingChg('maxTileSz')" ref="maxTileSzInput"/> - </label> - </div> - <hr class="border-stone-400"/> - <div> - Layout Method - <ul> - <li> - <label> <input type="radio" v-model="lytOpts.layoutType" value="sqr" - @change="onSettingChg('layoutType')"/> Squares </label> - </li> - <li> - <label> <input type="radio" v-model="lytOpts.layoutType" value="rect" - @change="onSettingChg('layoutType')"/> Rectangles </label> - </li> - <li> - <label> <input type="radio" v-model="lytOpts.layoutType" value="sweep" - @change="onSettingChg('layoutType')"/> Sweep to side </label> - </li> - </ul> - </div> - <hr class="border-stone-400"/> - <div> - Sweep to parent - <ul> - <li> - <label> <input type="radio" v-model="lytOpts.sweepToParent" value="none" - @change="onSettingChg('sweepToParent')"/> None </label> - </li> - <li> - <label> <input type="radio" v-model="lytOpts.sweepToParent" value="prefer" - @change="onSettingChg('sweepToParent')"/> Prefer </label> - </li> - <li> - <label> <input type="radio" v-model="lytOpts.sweepToParent" value="fallback" - @change="onSettingChg('sweepToParent')"/> Fallback </label> - </li> - </ul> - </div> - <hr class="border-stone-400"/> - <div> - Sweep Mode - <ul> - <li> - <label> <input type="radio" v-model="lytOpts.sweepMode" value="left" - @change="onSettingChg('sweepMode')"/> To left </label> - </li> - <li> - <label> <input type="radio" v-model="lytOpts.sweepMode" value="top" - @change="onSettingChg('sweepMode')"/> To top </label> - </li> - <li> - <label> <input type="radio" v-model="lytOpts.sweepMode" value="shorter" - @change="onSettingChg('sweepMode')"/> To shorter </label> - </li> - <li> - <label> <input type="radio" v-model="lytOpts.sweepMode" value="auto" - @change="onSettingChg('sweepMode')"/> Auto </label> - </li> - </ul> - </div> - <hr class="border-stone-400"/> - <div> - <label>Animation Duration <input type="range" min="0" max="3000" class="mx-2 w-[3cm]" - v-model.number="uiOpts.transitionDuration" @change="onSettingChg('transitionDuration')"/></label> - </div> - <hr class="border-stone-400"/> - <div> - <label> - <input type="checkbox" v-model="uiOpts.searchJumpMode" @change="onSettingChg('searchJumpMode')"/> - Jump to search result - </label> + <div class="border rounded"> + <h2 class="text-center">Layout</h2> + <div class="grid grid-cols-2 gap-2"> + <div> + Sweep leaves to side + <ul> + <li v-for="[val,] in userLayoutTypeVals"> + <label> <input type="radio" v-model="userLayoutType" :value="val" + @change="onSettingChg('layoutType')"/> {{val}} </label> + </li> + </ul> + </div> + <div> + Sweep into parent + <ul> + <li> <label> <input type="radio" :disabled="lytOpts.layoutType != 'sweep'" + v-model="lytOpts.sweepToParent" value="none" + @change="onSettingChg('sweepToParent')"/> Never </label> </li> + <li> <label> <input type="radio" :disabled="lytOpts.layoutType != 'sweep'" + v-model="lytOpts.sweepToParent" value="prefer" + @change="onSettingChg('sweepToParent')"/> Always </label> </li> + <li> <label> <input type="radio" :disabled="lytOpts.layoutType != 'sweep'" + v-model="lytOpts.sweepToParent" value="fallback" + @change="onSettingChg('sweepToParent')"/> If needed </label> </li> + </ul> + </div> + <div> + Tile Spacing + <ul> + <li v-for="[val,] in userTileSpacingVals"> + <label> <input type="radio" v-model="userTileSpacing" :value="val" + @change="onSettingChg('tileSpacing')"/> {{val}} </label> + </li> + </ul> + </div> + <div> + Tile Size + <ul> + <li v-for="[val,,] in userTileSizeVals"> + <label> <input type="radio" v-model="userTileSize" :value="val" + @change="onSettingChg('minTileSz'), onSettingChg('maxTileSz')"/> {{val}} </label> + </li> + </ul> + </div> + </div> </div> - <hr class="border-stone-400"/> - <div> - Tree - <ul> - <li> - <label> <input type="radio" v-model="uiOpts.useReducedTree" :value="false" - @change="onSettingChg('useReducedTree')"/> Default </label> - </li> - <li> - <label> <input type="radio" v-model="uiOpts.useReducedTree" :value="true" - @change="onSettingChg('useReducedTree')"/> Reduced </label> - </li> - </ul> + <div class="border rounded"> + <h2 class="text-center">Timing</h2> + <div class="grid grid-cols-3"> + <!-- Row 1 --> + <label for="animationTimeInput">Animation Time</label> + <input type="range" min="0" max="3000" class="my-auto" name="animationTimeInput" + v-model.number="uiOpts.transitionDuration" @change="onSettingChg('transitionDuration')"/> + <div class="my-auto">{{uiOpts.transitionDuration}} ms</div> + <!-- Row 2 --> + <label for="autoModeDelayInput">Auo-mode Delay</label> + <input type="range" min="0" max="3000" class="my-auto" name="autoModeDelayInput" + v-model.number="uiOpts.autoActionDelay" @change="onSettingChg('autoActionDelay')"/> + <div class="my-auto">{{uiOpts.autoActionDelay}} ms</div> + </div> </div> - <hr class="border-stone-400"/> - <div class="flex justify-around mt-2"> - <r-button class="bg-stone-800 text-white" @click="onReset"> - Reset - </r-button> + <div class="border rounded"> + <h2 class="text-center">Other</h2> + <div> + <label> <input type="checkbox" v-model="uiOpts.useReducedTree" + @change="onSettingChg('useReducedTree')"/> Use simplified tree </label> + </div> + <div> + <label> <input type="checkbox" v-model="uiOpts.searchJumpMode" + @change="onSettingChg('searchJumpMode')"/> Skip search animation </label> + </div> </div> + <r-button class="mx-auto mt-2" :style="{color: uiOpts.textColor, backgroundColor: uiOpts.bgColor}" + @click="$emit('reset')"> + Reset + </r-button> </div> </div> </template> |
