aboutsummaryrefslogtreecommitdiff
path: root/src/components/SettingsModal.vue
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/SettingsModal.vue')
-rw-r--r--src/components/SettingsModal.vue127
1 files changed, 127 insertions, 0 deletions
diff --git a/src/components/SettingsModal.vue b/src/components/SettingsModal.vue
new file mode 100644
index 0000000..1ccea2a
--- /dev/null
+++ b/src/components/SettingsModal.vue
@@ -0,0 +1,127 @@
+<template>
+<div class="fixed left-0 top-0 w-full h-full bg-black/40" @click="onClose" ref="rootRef">
+ <div class="absolute left-1/2 -translate-x-1/2 top-1/2 -translate-y-1/2
+ min-w-[8cm] max-w-[80%] max-h-[80%] overflow-auto" :style="styles">
+ <close-icon @click.stop="onClose" ref="closeRef"
+ class="absolute top-1 right-1 md:top-2 md:right-2 w-8 h-8 hover:cursor-pointer" />
+ <h1 class="text-xl md:text-2xl font-bold text-center py-2" :class="borderBClasses">Settings</h1>
+ <div class="pb-2" :class="borderBClasses">
+ <h2 class="font-bold md:text-xl text-center pt-1 md:pt-2 md:pb-1">Categories</h2>
+ <ul class="px-2 grid grid-cols-3">
+ <!-- Row 1 -->
+ <li> <label> <input type="checkbox" v-model="store.ctgs.event"
+ @change="onSettingChg('ctgs.event')"/> Event </label> </li>
+ <li> <label> <input type="checkbox" v-model="store.ctgs.person"
+ @change="onSettingChg('ctgs.person')"/> Person </label> </li>
+ <li> <label> <input type="checkbox" v-model="store.ctgs.work"
+ @change="onSettingChg('ctgs.work')"/> Work </label> </li>
+ <!-- Row 2 -->
+ <li> <label> <input type="checkbox" v-model="store.ctgs.place"
+ @change="onSettingChg('ctgs.place')"/> Place </label> </li>
+ <li> <label> <input type="checkbox" v-model="store.ctgs.organism"
+ @change="onSettingChg('ctgs.organism')"/> Organism </label> </li>
+ <li> <label> <input type="checkbox" v-model="store.ctgs.discovery"
+ @change="onSettingChg('ctgs.discovery')"/> Discovery </label> </li>
+ </ul>
+ </div>
+ <div class="pb-2" :class="borderBClasses">
+ <h2 class="font-bold md:text-xl text-center pt-1 md:pt-2 md:pb-1">Display</h2>
+ <div class="px-2">
+ <label> <input type="checkbox" v-model="store.showEventCounts"
+ @change="onSettingChg('showEventCounts')"/> Show event count indicators </label>
+ </div>
+ <div class="px-2">
+ <label> <input type="checkbox" v-model="store.showMinorTicks"
+ @change="onSettingChg('showMinorTicks')"/> Show minor tick labels </label>
+ </div>
+ </div>
+ <div v-if="store.touchDevice == false" class="pb-2" :class="borderBClasses">
+ <h2 class="font-bold md:text-xl text-center pt-1 md:pt-2 md:pb-1">Input</h2>
+ <div class="px-2">
+ <label> <input type="checkbox" v-model="store.disableShortcuts"
+ @change="onSettingChg('disableShortcuts')"/> Disable keyboard shortcuts </label>
+ </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="scrollRatio" @click="onResetOne('scrollRatio')" :class="rLabelClasses">
+ Scroll ratio
+ </label>
+ <input type="range" min="0.1" max="0.8" step="0.1" v-model.number="store.scrollRatio"
+ @change="onSettingChg('scrollRatio')" name="scrollRatio"/>
+ <div class="my-auto text-right">{{store.scrollRatio}}</div>
+ <!-- Row 2 -->
+ <label for="zoomRatio" @click="onResetOne('zoomRatio')" :class="rLabelClasses">
+ Zoom ratio
+ </label>
+ <input type="range" min="1.2" max="5" step="0.2" v-model.number="store.zoomRatio"
+ @change="onSettingChg('zoomRatio')" name="zoomRatio"/>
+ <div class="my-auto text-right">{{store.zoomRatio}}</div>
+ </div>
+ </div>
+ <s-button class="mx-auto my-2" :style="{color: store.color.text, backgroundColor: store.color.bg}"
+ @click="onReset">
+ Reset
+ </s-button>
+ <transition name="fade">
+ <div v-if="saved" class="absolute right-1 bottom-1" ref="saveIndRef"> Saved </div>
+ </transition>
+ </div>
+</div>
+</template>
+
+<script setup lang="ts">
+import {ref, computed} from 'vue';
+import SButton from './SButton.vue';
+import CloseIcon from './icon/CloseIcon.vue';
+import {useStore} from '../store';
+
+// Refs
+const rootRef = ref(null as HTMLDivElement | null);
+const closeRef = ref(null as typeof CloseIcon | null);
+const saveIndRef = ref(null as HTMLDivElement | null);
+
+// Global store
+const store = useStore();
+
+// Events
+const emit = defineEmits(['close']);
+
+// Settings change handling
+const saved = ref(false); // Set to true after a setting is saved
+function onSettingChg(option: string){
+ store.save(option);
+ // Make 'Saved' indicator appear/animate
+ if (!saved.value){
+ saved.value = true;
+ } else {
+ let el = saveIndRef.value!;
+ el.classList.remove('animate-flash-yellow');
+ el.offsetWidth; // Triggers reflow
+ el.classList.add('animate-flash-yellow');
+ }
+}
+function onResetOne(option: string){
+ store.resetOne(option);
+ onSettingChg(option);
+}
+function onReset(){
+ store.reset();
+ store.clear();
+ saved.value = false;
+}
+
+// Close handling
+function onClose(evt: Event){
+ if (evt.target == rootRef.value || closeRef.value!.$el.contains(evt.target)){
+ emit('close');
+ }
+}
+
+// Styles and classes
+const styles = computed(() => ({
+ backgroundColor: store.color.bgAlt,
+ borderRadius: store.borderRadius + 'px',
+}));
+const borderBClasses = 'border-b border-stone-400';
+const rLabelClasses = "w-fit hover:cursor-pointer hover:text-yellow-600"; // For reset-upon-click labels
+</script>