Bootstrap collapse; drop Alpine; fix expand anim
Alessandro committed
Oct 19, 2025 at 17:22 UTC
3b7c5a12f2c8e9392c27e1c8bb68e8b2c5d0e60a
5 files changed
+51
-34
webui/components/sidebar/bottom/preferences/preferences-panel.html
+4
-12
@@ -7,15 +7,15 @@
7
<body>
8
<div x-data>
9
<template x-if="$store.preferences">
10
- <div class="pref-section" x-data="{ prefOpen: true }">
10
+ <div class="pref-section">
11
<span>
12
- <h3 class="pref-header" @click="prefOpen = !prefOpen">
12
+ <h3 class="pref-header" data-bs-toggle="collapse" data-bs-target="#pref-list">
13
Preferences
14
- <svg class="arrow-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16" :class="{'rotated': !prefOpen}">
14
+ <svg class="arrow-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16">
15
<path d="M8 4l8 8-8 8" />
16
</svg>
17
</h3>
18
- <ul class="config-list" id="pref-list" x-show="prefOpen" x-collapse x-transition>
18
+ <ul class="config-list collapse show" id="pref-list">
19
<li x-data x-init="$watch('$store.preferences.autoScroll', v => $store.preferences.applyAutoScroll(v))">
20
<span>Autoscroll</span>
21
<label class="switch">
@@ -81,14 +81,6 @@
81
cursor: pointer;
82
user-select: none;
83
}
84
- .pref-section .arrow-icon {
85
- margin-left: 0.5rem;
86
- transition: transform .15s ease;
87
- transform: rotate(90deg);
88
- }
89
- .pref-section .arrow-icon.rotated {
90
- transform: rotate(0deg);
91
- }
84
.pref-section .config-list {
85
list-style: none;
86
padding: 0.05rem 0;
webui/components/sidebar/left-sidebar.html
+10
-15
@@ -118,11 +118,17 @@
118
display: contents;
119
}
120
121
- /* Ensure the collapse wrapper participates in flex sizing */
122
- #tasks-section div[x-show][x-collapse] {
123
- display: contents;
121
+ /* Bootstrap collapse elements need proper display for animation to work */
122
+ #tasks-section .collapse {
123
+ display: flex;
124
+ flex-direction: column;
125
+ flex: 1;
126
+ min-height: 0;
127
+ }
128
+ /* During the collapsing transition, allow height animation to control size */
129
+ #tasks-section .collapsing {
130
+ flex: 0 0 auto !important;
131
}
125
-
132
/* Common section header styling (Chats, Tasks) - matching Preferences style */
133
.section-header {
134
display: flex;
@@ -141,17 +147,6 @@
147
cursor: pointer;
148
}
149
144
- /* Arrow icon for collapsible sections */
145
- .section-header .arrow-icon {
146
- margin-left: 0.5rem;
147
- transition: transform 0.15s ease;
148
- transform: rotate(90deg);
149
- }
150
-
151
- .section-header .arrow-icon.rotated {
152
- transform: rotate(0deg);
153
- }
154
-
150
@media (max-width: 768px) {
151
#left-panel {
152
position: fixed;
webui/components/sidebar/tasks/tasks-list.html
+15
-6
@@ -5,16 +5,17 @@
5
</script>
6
</head>
7
<body>
8
- <div x-data="{ tasksOpen: true }" class="tasks-list-root">
8
+ <div class="tasks-list-root">
9
<template x-if="$store.tasks">
10
<div x-data class="tasks-list-inner">
11
- <h3 class="section-header section-header-collapsible" @click="tasksOpen = !tasksOpen">
11
+ <h3 class="section-header section-header-collapsible" data-bs-toggle="collapse" data-bs-target="#tasks-collapse">
12
Tasks
13
- <svg class="arrow-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16" :class="{'rotated': !tasksOpen}">
13
+ <svg class="arrow-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16">
14
<path d="M8 4l8 8-8 8" />
15
</svg>
16
</h3>
17
- <div class="tasks-list-body" x-show="tasksOpen" x-collapse x-transition>
17
+ <div class="collapse show" id="tasks-collapse">
18
+ <div class="tasks-list-body">
19
<div class="tasks-list-container" x-data>
20
<ul class="config-list tasks-config-list" x-show="$store.tasks.tasks.length > 0">
21
<template x-for="task in $store.tasks.tasks" :key="task.id">
@@ -54,6 +55,7 @@
55
<p><i>No tasks to list.</i></p>
56
</div>
57
</div>
58
+ </div>
59
</div>
60
</div>
61
</template>
@@ -64,10 +66,17 @@
66
<style>
67
/* Root wrappers provide flex context when embedded */
68
.tasks-list-root,
67
- .tasks-list-inner,
68
- .tasks-list-body {
69
+ .tasks-list-inner {
70
display: contents;
71
}
72
+
73
+ /* tasks-list-body is the flex container inside the collapse wrapper */
74
+ .tasks-list-body {
75
+ display: flex;
76
+ flex-direction: column;
77
+ flex: 1 1 auto;
78
+ min-height: 0;
79
+ }
80
.tasks-list-container .section-header {
81
position: sticky;
82
top: 0;
webui/index.css
+19
@@ -1641,3 +1641,22 @@ nav ul li a img {
1641
.spin {
1642
animation: spin 1s linear infinite;
1643
}
1644
+
1645
+/* Bootstrap Collapse */
1646
+.collapse:not(.show) {
1647
+ display: none !important;
1648
+}
1649
+.collapsing {
1650
+ height: 0;
1651
+ overflow: hidden;
1652
+ transition: height .35s ease;
1653
+}
1654
+
1655
+/* Arrow rotation based on Bootstrap's .collapsed class */
1656
+[data-bs-toggle="collapse"] .arrow-icon {
1657
+ transform: rotate(90deg);
1658
+ transition: transform .15s ease;
1659
+}
1660
+[data-bs-toggle="collapse"].collapsed .arrow-icon {
1661
+ transform: rotate(0deg);
1662
+}
webui/index.html
+3
-1
@@ -102,8 +102,10 @@
102
103
<script type="module" src="index.js"></script>
104
105
+ <!-- Bootstrap JS (only for logic, importing bundled CSS => UI conflicts) -->
106
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
107
+
108
<!-- Then load Alpine.js -->
106
- <script defer src="vendor/alpine/alpine.collapse.min.js"></script>
109
<!-- <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.3/dist/cdn.min.js"></script> -->
110
<script type="module" src="js/initFw.js"></script>
111