From f93a728091e52ae5144a51fb6203fde8cdf02558 Mon Sep 17 00:00:00 2001
From: Terry Truong <terry06890@gmail.com>
Date: Wed, 4 Jan 2023 23:55:10 +1100
Subject: Add event info modal

Add InfoModal.vue, SCollapsible.vue, and icons.
Update Timeline.vue, App.vue, lib.ts, and store.ts to display modal.
For testing, send/use dummy EventInfo from server (still waiting on image downloads).
---
 src/components/SCollapsible.vue | 61 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)
 create mode 100644 src/components/SCollapsible.vue

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

diff --git a/src/components/SCollapsible.vue b/src/components/SCollapsible.vue
new file mode 100644
index 0000000..39b4283
--- /dev/null
+++ b/src/components/SCollapsible.vue
@@ -0,0 +1,61 @@
+<template>
+<div :style="styles">
+	<div class="hover:cursor-pointer" @click="onClick">
+		<slot name="summary" :open="open">(Summary)</slot>
+	</div>
+	<transition @enter="onEnter" @after-enter="onAfterEnter" @leave="onLeave" @before-leave="onBeforeLeave">
+		<div v-show="open" :style="contentStyles" class="max-h-0" ref="content">
+			<slot name="content">(Content)</slot>
+		</div>
+	</transition>
+</div>
+</template>
+
+<script setup lang="ts">
+import {ref, computed, watch} from 'vue';
+
+// Props + events
+const props = defineProps({
+	modelValue: {type: Boolean, default: false}, // For using v-model on the component
+});
+const emit = defineEmits(['update:modelValue', 'open']);
+
+// For open status
+const open = ref(false);
+watch(() => props.modelValue, (newVal) => {open.value = newVal})
+function onClick(){
+	open.value = !open.value;
+	emit('update:modelValue', open.value);
+	if (open.value){
+		emit('open');
+	}
+}
+
+// Styles
+const styles = computed(() => ({
+	overflow: open.value ? 'visible' : 'hidden',
+}));
+const contentStyles = computed(() => ({
+	overflow: 'hidden',
+	opacity: open.value ? '1' : '0',
+	transitionProperty: 'max-height, opacity',
+	transitionDuration: '300ms',
+	transitionTimingFunction: 'ease-in-out',
+}));
+
+// Open/close transitions
+function onEnter(el: HTMLDivElement){
+	el.style.maxHeight = el.scrollHeight + 'px';
+}
+function onAfterEnter(el: HTMLDivElement){
+	el.style.maxHeight = 'none';
+		// Allows the content to grow after the transition ends, as the scrollHeight sometimes is too short
+}
+function onBeforeLeave(el: HTMLDivElement){
+	el.style.maxHeight = el.scrollHeight + 'px';
+	el.offsetWidth; // Triggers reflow
+}
+function onLeave(el: HTMLDivElement){
+	el.style.maxHeight = '0';
+}
+</script>
-- 
cgit v1.2.3

