Skip to content

Commit e7ea330

Browse files
committed
Refactor CycleBlock and CollapsibleComparisonFileSelect components
- Refactor CollapsibleComparisonFileSelect to use Vue's Transition component for cleaner animation handling - Improve code readability and structure in both CycleBlock and CollapsibleComparisonFileSelect components
1 parent b7123df commit e7ea330

File tree

2 files changed

+198
-111
lines changed

2 files changed

+198
-111
lines changed

webapp/src/components/CollapsibleComparisonFileSelect.vue

Lines changed: 68 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -9,33 +9,41 @@
99
/>
1010
<span class="comparison-title" @click="toggleExpanded">{{ title }}</span>
1111
</div>
12-
<div
13-
ref="contentContainer"
14-
class="comparison-content-container"
15-
:style="{ 'max-height': maxHeight }"
12+
<Transition
13+
name="expand"
14+
@before-enter="beforeEnter"
15+
@enter="enter"
16+
@after-enter="afterEnter"
17+
@before-leave="beforeLeave"
18+
@leave="leave"
1619
>
17-
<div class="form-row align-items-center mb-2">
18-
<FileMultiSelectDropdown
19-
v-model="internalFileModel"
20-
:item_id="item_id"
21-
:block_id="block_id"
22-
:extensions="extensions"
23-
:update-block-on-change="false"
24-
:exclude-file-ids="excludeFileIds"
25-
/>
20+
<div v-if="isExpanded" ref="contentContainer" class="comparison-content-container">
21+
<div class="form-row align-items-center mb-2">
22+
<FileMultiSelectDropdown
23+
v-model="internalFileModel"
24+
:item_id="item_id"
25+
:block_id="block_id"
26+
:extensions="extensions"
27+
:update-block-on-change="false"
28+
:exclude-file-ids="excludeFileIds"
29+
/>
30+
</div>
31+
<div class="form-row mt-2 mb-3">
32+
<button class="btn btn-primary btn-sm" @click="applySelection">
33+
{{ applyButtonText }}
34+
</button>
35+
</div>
2636
</div>
27-
<div class="form-row mt-2 mb-3">
28-
<button class="btn btn-primary btn-sm" @click="applySelection">
29-
{{ applyButtonText }}
30-
</button>
31-
</div>
32-
</div>
37+
</Transition>
3338
</div>
3439
</template>
3540

3641
<script>
3742
import FileMultiSelectDropdown from "@/components/FileMultiSelectDropdown";
3843
44+
// Padding added to content height for smooth collapse animation
45+
const CONTENT_PADDING_HEIGHT = 18;
46+
3947
export default {
4048
components: {
4149
FileMultiSelectDropdown,
@@ -78,8 +86,6 @@ export default {
7886
data() {
7987
return {
8088
internalFileModel: [],
81-
maxHeight: "0px",
82-
paddingHeight: 18,
8389
isExpanded: false,
8490
};
8591
},
@@ -94,42 +100,42 @@ export default {
94100
95101
// Set initial expanded state
96102
this.isExpanded = this.initiallyExpanded;
97-
98-
// Initialize collapse state
99-
var contentContainer = this.$refs.contentContainer;
100-
if (contentContainer) {
101-
if (this.isExpanded) {
102-
this.maxHeight = "none";
103-
contentContainer.style.overflow = "visible";
104-
} else {
105-
this.maxHeight = "0px";
106-
}
107-
108-
contentContainer.addEventListener("transitionend", () => {
109-
if (this.isExpanded) {
110-
this.maxHeight = "none";
111-
}
112-
});
113-
}
114103
},
115104
methods: {
116105
toggleExpanded() {
117-
var content = this.$refs.contentContainer;
118-
if (!this.isExpanded) {
119-
this.maxHeight = content.scrollHeight + 2 * this.paddingHeight + "px";
120-
this.isExpanded = true;
121-
content.style.overflow = "visible";
122-
} else {
123-
content.style.overflow = "hidden";
124-
requestAnimationFrame(() => {
125-
this.maxHeight = content.scrollHeight + "px";
126-
requestAnimationFrame(() => {
127-
this.maxHeight = "0px";
128-
this.isExpanded = false;
129-
});
130-
});
131-
}
106+
this.isExpanded = !this.isExpanded;
132107
},
108+
109+
// Transition hooks for dynamic height animation
110+
beforeEnter(el) {
111+
el.style.height = "0";
112+
el.style.overflow = "hidden";
113+
},
114+
115+
enter(el) {
116+
// Get actual content height including padding
117+
const height = el.scrollHeight + 2 * CONTENT_PADDING_HEIGHT;
118+
el.style.height = height + "px";
119+
},
120+
121+
afterEnter(el) {
122+
// Allow content to grow/shrink naturally after animation
123+
el.style.height = "auto";
124+
el.style.overflow = "visible";
125+
},
126+
127+
beforeLeave(el) {
128+
// Set current height before collapsing
129+
el.style.height = el.scrollHeight + "px";
130+
el.style.overflow = "hidden";
131+
},
132+
133+
leave(el) {
134+
// Force reflow to ensure the height is set before animating
135+
el.offsetHeight;
136+
el.style.height = "0";
137+
},
138+
133139
applySelection() {
134140
this.$emit("update:modelValue", this.internalFileModel.slice());
135141
this.$emit("apply", this.internalFileModel.slice());
@@ -170,9 +176,15 @@ export default {
170176
transform: rotate(90deg);
171177
}
172178
173-
.comparison-content-container {
179+
/* Transition styles for expand/collapse */
180+
.expand-enter-active,
181+
.expand-leave-active {
182+
transition: height 0.4s ease-in-out;
174183
overflow: hidden;
175-
max-height: none;
176-
transition: max-height 0.4s ease-in-out;
184+
}
185+
186+
.expand-enter-from,
187+
.expand-leave-to {
188+
height: 0;
177189
}
178190
</style>

0 commit comments

Comments
 (0)