diff options
Diffstat (limited to 'src/components/SettingsModal.vue')
| -rw-r--r-- | src/components/SettingsModal.vue | 192 |
1 files changed, 83 insertions, 109 deletions
diff --git a/src/components/SettingsModal.vue b/src/components/SettingsModal.vue index df8444f..a55dc41 100644 --- a/src/components/SettingsModal.vue +++ b/src/components/SettingsModal.vue @@ -9,19 +9,19 @@ <h2 class="font-bold md:text-xl text-center pt-1 md:pt-2 md:pb-1">Timing</h2> <div class="grid grid-cols-[130px_minmax(0,1fr)_65px] gap-1 px-2 md:px-3"> <!-- Row 1 --> - <label for="animTimeInput" @click="onReset('UI', 'transitionDuration')" :class="rLabelClasses"> + <label for="animTimeInput" @click="onResetOne('transitionDuration')" :class="rLabelClasses"> Animation Time </label> - <input type="range" min="0" max="1000" v-model.number="uiOpts.transitionDuration" - @change="onSettingChg('UI', 'transitionDuration')" class="my-auto" name="animTimeInput"/> - <div class="my-auto text-right">{{uiOpts.transitionDuration}} ms</div> + <input type="range" min="0" max="1000" v-model.number="store.transitionDuration" + @change="onSettingChg('transitionDuration')" class="my-auto" name="animTimeInput"/> + <div class="my-auto text-right">{{store.transitionDuration}} ms</div> <!-- Row 2 --> - <label for="autoDelayInput" @click="onReset('UI', 'autoActionDelay')" :class="rLabelClasses"> + <label for="autoDelayInput" @click="onResetOne('autoActionDelay')" :class="rLabelClasses"> Auto-mode Delay </label> - <input type="range" min="100" max="1000" v-model.number="uiOpts.autoActionDelay" - @change="onSettingChg('UI', 'autoActionDelay')" class="my-auto" name="autoDelayInput"/> - <div class="my-auto text-right">{{uiOpts.autoActionDelay}} ms</div> + <input type="range" min="300" max="2000" v-model.number="store.autoActionDelay" + @change="onSettingChg('autoActionDelay')" class="my-auto" name="autoDelayInput"/> + <div class="my-auto text-right">{{store.autoActionDelay}} ms</div> </div> </div> <div class="pb-2" :class="borderBClasses"> @@ -31,49 +31,49 @@ <div>Sweep leaves left</div> <ul> <li> <label> <input type="radio" v-model="sweepLeaves" :value="true" - @change="onSettingChg('LYT', 'layoutType')"/> Yes </label> </li> + @change="onSettingChg('lytOpts.layoutType')"/> Yes </label> </li> <li> <label> <input type="radio" v-model="sweepLeaves" :value="false" - @change="onSettingChg('LYT', 'layoutType')"/> No </label> </li> + @change="onSettingChg('lytOpts.layoutType')"/> No </label> </li> </ul> </div> <div> <div>Sweep into parent</div> <ul> - <li> <label> <input type="radio" :disabled="!sweepLeaves" v-model="lytOpts.sweepToParent" - value="none" @change="onSettingChg('LYT', 'sweepToParent')"/> Never </label> </li> - <li> <label> <input type="radio" :disabled="!sweepLeaves" v-model="lytOpts.sweepToParent" - value="prefer" @change="onSettingChg('LYT', 'sweepToParent')"/> Always </label> </li> - <li> <label> <input type="radio" :disabled="!sweepLeaves" v-model="lytOpts.sweepToParent" - value="fallback" @change="onSettingChg('LYT', 'sweepToParent')"/> If needed </label> </li> + <li> <label> <input type="radio" :disabled="!sweepLeaves" v-model="store.lytOpts.sweepToParent" + value="none" @change="onSettingChg('lytOpts.sweepToParent')"/> Never </label> </li> + <li> <label> <input type="radio" :disabled="!sweepLeaves" v-model="store.lytOpts.sweepToParent" + value="prefer" @change="onSettingChg('lytOpts.sweepToParent')"/> Always </label> </li> + <li> <label> <input type="radio" :disabled="!sweepLeaves" v-model="store.lytOpts.sweepToParent" + value="fallback" @change="onSettingChg('lytOpts.sweepToParent')"/> If needed </label> </li> </ul> </div> </div> <div class="grid grid-cols-[100px_minmax(0,1fr)_65px] gap-1 w-fit mx-auto px-2 md:px-3"> <!-- Row 1 --> - <label for="minTileSizeInput" @click="onReset('LYT', 'minTileSz')" :class="rLabelClasses"> + <label for="minTileSizeInput" @click="onResetOne('lytOpts.minTileSz')" :class="rLabelClasses"> Min Tile Size </label> <input type="range" - min="15" :max="uiOpts.breakpoint == 'sm' ? 150 : 200" v-model.number="lytOpts.minTileSz" - @input="onSettingChgThrottled('LYT', 'minTileSz')" @change="onSettingChg('LYT', 'minTileSz')" + min="15" :max="store.breakpoint == 'sm' ? 150 : 200" v-model.number="store.lytOpts.minTileSz" + @input="onSettingChgThrottled('lytOpts.minTileSz')" @change="onSettingChg('lytOpts.minTileSz')" name="minTileSizeInput" ref="minTileSzRef"/> - <div class="my-auto text-right">{{lytOpts.minTileSz}} px</div> + <div class="my-auto text-right">{{store.lytOpts.minTileSz}} px</div> <!-- Row 2 --> - <label for="maxTileSizeInput" @click="onReset('LYT', 'maxTileSz')" :class="rLabelClasses"> + <label for="maxTileSizeInput" @click="onResetOne('lytOpts.maxTileSz')" :class="rLabelClasses"> Max Tile Size </label> - <input type="range" min="15" max="400" v-model.number="lytOpts.maxTileSz" - @input="onSettingChgThrottled('LYT', 'maxTileSz')" @change="onSettingChg('LYT', 'maxTileSz')" + <input type="range" min="15" max="400" v-model.number="store.lytOpts.maxTileSz" + @input="onSettingChgThrottled('lytOpts.maxTileSz')" @change="onSettingChg('lytOpts.maxTileSz')" name="maxTileSizeInput" ref="maxTileSzRef"/> - <div class="my-auto text-right">{{lytOpts.maxTileSz}} px</div> + <div class="my-auto text-right">{{store.lytOpts.maxTileSz}} px</div> <!-- Row 3 --> - <label for="tileSpacingInput" @click="onReset('LYT', 'tileSpacing')" :class="rLabelClasses"> + <label for="tileSpacingInput" @click="onResetOne('lytOpts.tileSpacing')" :class="rLabelClasses"> Tile Spacing </label> - <input type="range" min="0" max="20" v-model.number="lytOpts.tileSpacing" - @input="onSettingChgThrottled('LYT', 'tileSpacing')" @change="onSettingChg('LYT', 'tileSpacing')" + <input type="range" min="0" max="20" v-model.number="store.lytOpts.tileSpacing" + @input="onSettingChgThrottled('lytOpts.tileSpacing')" @change="onSettingChg('lytOpts.tileSpacing')" name="tileSpacingInput"/> - <div class="my-auto text-right">{{lytOpts.tileSpacing}} px</div> + <div class="my-auto text-right">{{store.lytOpts.tileSpacing}} px</div> </div> </div> <div class="pb-2 px-2 md:px-3" :class="borderBClasses"> @@ -81,29 +81,29 @@ <div> Tree to use <ul class="flex justify-evenly"> - <li> <label> <input type="radio" v-model="uiOpts.tree" value="trimmed" - @change="onSettingChg('UI', 'tree')"/> Complex </label> </li> - <li> <label> <input type="radio" v-model="uiOpts.tree" value="images" - @change="onSettingChg('UI', 'tree')"/> Visual </label> </li> - <li> <label> <input type="radio" v-model="uiOpts.tree" value="picked" - @change="onSettingChg('UI', 'tree')"/> Minimal </label> </li> + <li> <label> <input type="radio" v-model="store.tree" value="trimmed" + @change="onSettingChg('tree')"/> Complex </label> </li> + <li> <label> <input type="radio" v-model="store.tree" value="images" + @change="onSettingChg('tree')"/> Visual </label> </li> + <li> <label> <input type="radio" v-model="store.tree" value="picked" + @change="onSettingChg('tree')"/> Minimal </label> </li> </ul> </div> <div> - <label> <input type="checkbox" v-model="uiOpts.searchJumpMode" - @change="onSettingChg('UI', 'searchJumpMode')"/> Skip search animation </label> + <label> <input type="checkbox" v-model="store.searchJumpMode" + @change="onSettingChg('searchJumpMode')"/> Skip search animation </label> </div> <div> - <label> <input type="checkbox" v-model="uiOpts.autoHide" - @change="onSettingChg('UI', 'autoHide')"/> Auto-hide ancestors </label> + <label> <input type="checkbox" v-model="store.autoHide" + @change="onSettingChg('autoHide')"/> Auto-hide ancestors </label> </div> - <div v-if="uiOpts.touchDevice == false"> - <label> <input type="checkbox" v-model="uiOpts.disableShortcuts" - @change="onSettingChg('UI', 'disableShortcuts')"/> Disable keyboard shortcuts </label> + <div v-if="store.touchDevice == false"> + <label> <input type="checkbox" v-model="store.disableShortcuts" + @change="onSettingChg('disableShortcuts')"/> Disable keyboard shortcuts </label> </div> </div> - <s-button class="mx-auto my-2" :style="{color: uiOpts.textColor, backgroundColor: uiOpts.bgColor}" - @click="onResetAll"> + <s-button class="mx-auto my-2" :style="{color: store.color.text, backgroundColor: store.color.bg}" + @click="onReset"> Reset </s-button> <transition name="fade"> @@ -114,11 +114,10 @@ </template> <script setup lang="ts"> -import {ref, computed, watch, PropType} from 'vue'; +import {ref, computed, watch} from 'vue'; import SButton from './SButton.vue'; import CloseIcon from './icon/CloseIcon.vue'; -import {UiOptions, OptionType, getDefaultLytOpts, getDefaultUiOpts} from '../lib'; -import {LayoutOptions} from '../layout'; +import {useStore, StoreState} from '../store'; // Refs const rootRef = ref(null as HTMLDivElement | null); @@ -127,37 +126,36 @@ const minTileSzRef = ref(null as HTMLInputElement | null); const maxTileSzRef = ref(null as HTMLInputElement | null); const saveIndRef = ref(null as HTMLDivElement | null); -// Props + events -const props = defineProps({ - lytOpts: {type: Object as PropType<LayoutOptions>, required: true}, - uiOpts: {type: Object as PropType<UiOptions>, required: true}, -}); -const emit = defineEmits(['close', 'setting-chg', 'reset', ]); +// Global store +const store = useStore(); -// For settings -const sweepLeaves = ref(props.lytOpts.layoutType == 'sweep'); - // For making only two of 'layoutType's values available for user selection) -watch(sweepLeaves, (newVal) => {props.lytOpts.layoutType = newVal ? 'sweep' : 'rect'}) +// Events +const emit = defineEmits(['close', 'setting-chg', 'reset']); + +// For making only two of 'layoutType's values available for user selection) +const sweepLeaves = ref(store.lytOpts.layoutType == 'sweep'); +watch(sweepLeaves, (newVal) => {store.lytOpts.layoutType = newVal ? 'sweep' : 'rect'}) // Settings change handling const saved = ref(false); // Set to true after a setting is saved -const settingChgTimeout = ref(0); // Used to throttle some setting-change handling -function onSettingChg(optionType: OptionType, option: string){ +let settingChgTimeout = 0; // Used to throttle some setting-change handling +function onSettingChg(option: string){ // Maintain min/max-tile-size consistency - if (optionType == 'LYT' && (option == 'minTileSz' || option == 'maxTileSz')){ + if (option == 'lytOpts.minTileSz' || option == 'lytOpts.maxTileSz'){ let minInput = minTileSzRef.value!; let maxInput = maxTileSzRef.value!; - if (option == 'minTileSz' && Number(minInput.value) > Number(maxInput.value)){ - props.lytOpts.maxTileSz = props.lytOpts.minTileSz; - emit('setting-chg', 'LYT', 'maxTileSz'); - } else if (option == 'maxTileSz' && Number(maxInput.value) < Number(minInput.value)){ - props.lytOpts.minTileSz = props.lytOpts.maxTileSz; - emit('setting-chg', 'LYT', 'minTileSz'); + if (Number(minInput.value) > Number(maxInput.value)){ + if (option == 'lytOpts.minTileSz'){ + store.lytOpts.maxTileSz = store.lytOpts.minTileSz; + emit('setting-chg', 'lytOpts.maxTileSz'); + } else { + store.lytOpts.minTileSz = store.lytOpts.maxTileSz; + emit('setting-chg', 'lytOpts.minTileSz'); + } } } - // Notify parent component - emit('setting-chg', optionType, option, - {relayout: optionType == 'LYT', reinit: optionType == 'UI' && option == 'tree'}); + // Notify parent (might need to relayout) + emit('setting-chg', option); // Possibly make saved-indicator appear/animate if (!saved.value){ saved.value = true; @@ -168,48 +166,24 @@ function onSettingChg(optionType: OptionType, option: string){ el.classList.add('animate-flash-green'); } } -function onSettingChgThrottled(optionType: OptionType, option: string){ - if (settingChgTimeout.value == 0){ - settingChgTimeout.value = setTimeout(() => { - settingChgTimeout.value = 0; - onSettingChg(optionType, option); - }, props.uiOpts.animationDelay); +function onSettingChgThrottled(option: string){ + if (settingChgTimeout == 0){ + settingChgTimeout = setTimeout(() => { + settingChgTimeout = 0; + onSettingChg(option); + }, store.animationDelay); } } -function onReset(optionType: OptionType, option: string){ - // Restore the setting's default - let defaultLytOpts = getDefaultLytOpts(); - let defaultUiOpts = getDefaultUiOpts(defaultLytOpts); - if (optionType == 'LYT'){ - let lytOpt = option as keyof LayoutOptions; - if (props.lytOpts[lytOpt] == defaultLytOpts[lytOpt]){ - return; - } - (props.lytOpts[lytOpt] as any) = defaultLytOpts[lytOpt]; - if (option == 'layoutType'){ - sweepLeaves.value = props.lytOpts.layoutType == 'sweep'; - } - } else { - let uiOpt = option as keyof UiOptions; - if (props.uiOpts[uiOpt] == defaultUiOpts[uiOpt]){ - return; - } - (props.uiOpts[uiOpt] as any) = defaultUiOpts[uiOpt]; +function onResetOne(option: string){ + store.resetOne(option); + if (option == 'lytOpts.layoutType'){ + sweepLeaves.value = (store.lytOpts.layoutType == 'sweep'); } - // Notify parent component - onSettingChg(optionType, option); + onSettingChg(option); } -function onResetAll(){ - // Restore default options - let defaultLytOpts = getDefaultLytOpts(); - let defaultUiOpts = getDefaultUiOpts(defaultLytOpts); - let needReinit = props.uiOpts.tree != defaultUiOpts.tree; - Object.assign(props.lytOpts, defaultLytOpts); - Object.assign(props.uiOpts, defaultUiOpts); - // Notify parent component - emit('reset', needReinit); - // Clear saved-indicator - saved.value = false; +function onReset(){ + emit('reset'); // Notify parent (might need to relayout) + saved.value = false; // Clear saved-indicator } // Close handling @@ -221,9 +195,9 @@ function onClose(evt: Event){ // Styles and classes const styles = computed(() => ({ - backgroundColor: props.uiOpts.bgColorAlt, - borderRadius: props.uiOpts.borderRadius + 'px', - boxShadow: props.uiOpts.shadowNormal, + backgroundColor: store.color.bgAlt, + borderRadius: store.borderRadius + 'px', + boxShadow: store.shadowNormal, })); const borderBClasses = 'border-b border-stone-400'; const rLabelClasses = "w-fit hover:cursor-pointer hover:text-lime-600"; // For reset-upon-click labels |
