From 8b5538e0a55a83b1ff190cd5ad689827777e73a7 Mon Sep 17 00:00:00 2001
From: Terry Truong <terry06890@gmail.com>
Date: Wed, 14 Sep 2022 19:17:41 +1000
Subject: Use Pinia to store user settings, palette colors, etc

Move uiOpts and lytOpts to store.ts
Add 'const's to *.ts
---
 src/components/SettingsModal.vue | 192 +++++++++++++++++----------------------
 1 file changed, 83 insertions(+), 109 deletions(-)

(limited to 'src/components/SettingsModal.vue')

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
-- 
cgit v1.2.3

