From 75f447d23d53c484d8c6e607e47ea425743690aa Mon Sep 17 00:00:00 2001 From: Yisroel Baum Date: Sat, 15 Aug 2026 22:00:33 +0300 Subject: [PATCH] add foldable set hierarchy --- .../website/src/components/ElementTree.vue | 88 ++++++++++++++++++- frontend/website/src/views/SetLayoutView.vue | 22 ++++- 2 files changed, 105 insertions(+), 5 deletions(-) diff --git a/frontend/website/src/components/ElementTree.vue b/frontend/website/src/components/ElementTree.vue index 54d7e39..e0ca8a4 100644 --- a/frontend/website/src/components/ElementTree.vue +++ b/frontend/website/src/components/ElementTree.vue @@ -1,10 +1,23 @@ @@ -69,6 +109,23 @@ defineProps<{ box-shadow: 0 0.55rem 1.5rem rgb(40 62 52 / 6%); } +.element-node__card--toggle { + width: 100%; + color: inherit; + text-align: left; + cursor: pointer; +} + +.element-node__card--toggle:hover { + border-color: rgb(40 92 78 / 34%); + background: #fffdf7; +} + +.element-node__card--toggle:focus-visible { + outline: 3px solid rgb(86 127 112 / 34%); + outline-offset: 0.2rem; +} + .element-node__name { min-width: 0; color: #183029; @@ -78,6 +135,13 @@ defineProps<{ overflow-wrap: anywhere; } +.element-node__metadata { + display: flex; + flex: 0 0 auto; + align-items: center; + gap: 0.8rem; +} + .element-node__kind { flex: 0 0 auto; padding: 0.35rem 0.55rem; @@ -90,6 +154,18 @@ defineProps<{ text-transform: none; } +.element-node__chevron { + width: 0.55rem; + height: 0.55rem; + border-right: 2px solid #5e7067; + border-bottom: 2px solid #5e7067; + transform: rotate(-45deg); +} + +.element-node__chevron--expanded { + transform: rotate(45deg); +} + @media (max-width: 37.5rem) { .element-tree { margin-left: 0.45rem; @@ -106,6 +182,10 @@ defineProps<{ padding: 0.75rem 0.7rem; } + .element-node__metadata { + gap: 0.6rem; + } + .element-node__kind { padding-inline: 0.42rem; font-size: 0.56rem; diff --git a/frontend/website/src/views/SetLayoutView.vue b/frontend/website/src/views/SetLayoutView.vue index 6edf2b9..9b86551 100644 --- a/frontend/website/src/views/SetLayoutView.vue +++ b/frontend/website/src/views/SetLayoutView.vue @@ -11,6 +11,7 @@ const route = useRoute() const setLayoutStore = useSetLayoutStore() const { layout, loading, error, notFound } = storeToRefs(setLayoutStore) const currentSetId = ref(null) +const expandedElementIds = ref(new Set()) const EMPTY_MESSAGE = 'This set does not have any elements yet.' watch( @@ -19,6 +20,7 @@ watch( const rawSetId = Array.isArray(setIdParameter) ? setIdParameter[0] : setIdParameter const setId = Number(rawSetId) currentSetId.value = setId + expandedElementIds.value = new Set() await setLayoutStore.fetchSetLayout(setId) }, { immediate: true }, @@ -29,8 +31,21 @@ async function retry(): Promise { return } + expandedElementIds.value = new Set() await setLayoutStore.fetchSetLayout(currentSetId.value) } + +function toggleElement(elementId: number): void { + const nextExpandedElementIds = new Set(expandedElementIds.value) + + if (nextExpandedElementIds.has(elementId)) { + nextExpandedElementIds.delete(elementId) + } else { + nextExpandedElementIds.add(elementId) + } + + expandedElementIds.value = nextExpandedElementIds +}