From 3fa7ccf0c1b2f9d4826ac7a6b38c47e0930b84f3 Mon Sep 17 00:00:00 2001
From: thepaperpilot <thepaperpilot@gmail.com>
Date: Sun, 27 Mar 2022 13:47:36 -0500
Subject: [PATCH] Added collapsibles

---
 src/components/layout/Collapsible.vue | 51 +++++++++++++++++++++++++++
 src/util/vue.tsx                      | 18 +++++++++-
 2 files changed, 68 insertions(+), 1 deletion(-)
 create mode 100644 src/components/layout/Collapsible.vue

diff --git a/src/components/layout/Collapsible.vue b/src/components/layout/Collapsible.vue
new file mode 100644
index 0000000..a9554cc
--- /dev/null
+++ b/src/components/layout/Collapsible.vue
@@ -0,0 +1,51 @@
+<template>
+    <Col style="width: 100%">
+        <button @click="collapsed.value = !collapsed.value" class="feature collapsible-toggle">
+            <component :is="displayComponent" />
+        </button>
+        <component v-if="!collapsed.value" :is="contentComponent" />
+    </Col>
+</template>
+
+<script setup lang="ts">
+import { CoercableComponent } from "features/feature";
+import { coerceComponent } from "util/vue";
+import { computed, Ref } from "vue";
+import Col from "./Column.vue";
+
+const props = defineProps<{
+    collapsed: Ref<boolean>;
+    display: CoercableComponent;
+    content: CoercableComponent;
+}>();
+
+const displayComponent = computed(() => coerceComponent(props.display));
+const contentComponent = computed(() => coerceComponent(props.content));
+</script>
+
+<style scoped>
+.collapsible-toggle {
+    width: calc(100% - 10px);
+    background: var(--raised-background);
+    padding: var(--feature-margin);
+    color: var(--foreground);
+    cursor: pointer;
+}
+
+:deep(.col) {
+    margin-top: 0;
+    margin-bottom: 0;
+    width: 100%;
+}
+
+.mergeAdjacent .collapsible-toggle {
+    border: 0;
+    border-top-left-radius: 0 !important;
+    border-top-right-radius: 0 !important;
+}
+
+:deep(.mergeAdjacent .feature:not(.dontMerge):first-child) {
+    border-top-left-radius: 0 !important;
+    border-top-right-radius: 0 !important;
+}
+</style>
diff --git a/src/util/vue.tsx b/src/util/vue.tsx
index f11e63f..7606e55 100644
--- a/src/util/vue.tsx
+++ b/src/util/vue.tsx
@@ -5,7 +5,8 @@ import {
     Component as ComponentKey,
     GatherProps,
     GenericComponent,
-    JSXFunction
+    JSXFunction,
+    Visibility
 } from "features/feature";
 import {
     Component,
@@ -121,6 +122,21 @@ export function setupHoldToClick(
     return { start, stop, handleHolding };
 }
 
+export function getFirstFeature<T extends { visibility: ProcessedComputable<Visibility> }>(
+    features: T[],
+    filter: (feature: T) => boolean
+): { firstFeature: Ref<T | undefined>; hiddenFeatures: Ref<T[]> } {
+    const filteredFeatures = computed(() =>
+        features.filter(
+            feature => unref(feature.visibility) === Visibility.Visible && filter(feature)
+        )
+    );
+    return {
+        firstFeature: computed(() => filteredFeatures.value[0]),
+        hiddenFeatures: computed(() => filteredFeatures.value.slice(1))
+    };
+}
+
 export function computeComponent(
     component: Ref<ProcessedComputable<CoercableComponent>>,
     defaultWrapper = "div"