Skip to content

Commit 59f04a1

Browse files
committed
feat(#5099): implement collapsible sidebar functionality and improve layout
1 parent 63127fd commit 59f04a1

5 files changed

Lines changed: 53 additions & 43 deletions

File tree

spring-boot-admin-server-ui/src/main/frontend/components/sba-button.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
22
<component
33
:is="as"
4-
class="btn relative items-center"
4+
class="btn items-center"
55
v-bind="componentAttrs"
66
@click="handleClick"
77
>

spring-boot-admin-server-ui/src/main/frontend/components/sba-sticky-subnav.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
22
<div
33
id="subnavigation"
4-
class="sticky shadow-sm top-14 w-full bg-white py-1 px-2 md:px-6 backdrop-filter backdrop-blur bg-opacity-40 z-20 drop-shadow-lg"
4+
class="sticky shadow-sm top-0 w-full bg-white py-1 px-2 md:px-6 backdrop-filter backdrop-blur bg-opacity-40 z-20 drop-shadow-lg"
55
>
66
<slot />
77
</div>

spring-boot-admin-server-ui/src/main/frontend/directives/sticks-below.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const mounted = (el, binding) => {
2222
const targetElement = document.querySelector(binding.value);
2323
if (targetElement) {
2424
const clientRect = targetElement.getBoundingClientRect();
25-
const top = clientRect.height + clientRect.top;
25+
const top = clientRect.height;
2626

2727
el.style.top = `${top}px`;
2828
el.style.position = 'sticky';

spring-boot-admin-server-ui/src/main/frontend/views/instances/shell/InstanceShell.vue

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,31 +15,55 @@
1515
-->
1616

1717
<template>
18-
<div class="h-full">
18+
<div class="flex h-full">
1919
<sba-wave />
20-
<div class="h-full">
20+
<div
21+
class="flex-shrink-0 flex flex-col transition-all duration-300 ease-in-out bg-white border-r relative overflow-hidden pb-14"
22+
:class="{
23+
'w-8': !sidebarOpen,
24+
'w-64 overflow-y-auto': sidebarOpen,
25+
}"
26+
>
27+
<button
28+
aria-label="Toggle sidebar"
29+
class="bg-sba-50 mx-[0.25rem] mt-[0.25rem] p-1 text-xs"
30+
:class="{
31+
'text-center': !sidebarOpen,
32+
'text-right': sidebarOpen,
33+
}"
34+
@click="toggleSidebar"
35+
>
36+
<font-awesome-icon
37+
:icon="faAngleDoubleLeft"
38+
class="transition-all"
39+
:class="{
40+
'rotate-0': sidebarOpen,
41+
'rotate-180': !sidebarOpen,
42+
}"
43+
/>
44+
</button>
2145
<Sidebar
2246
v-if="instance"
47+
v-show="sidebarOpen"
2348
:key="instanceId"
2449
:application="application"
2550
:instance="instance"
2651
:views="sidebarViews"
2752
/>
28-
<main
29-
class="min-h-full h-full relative z-0 ml-10 md:ml-60 transition-all"
30-
>
31-
<router-view
32-
v-if="instance"
33-
:application="application"
34-
:instance="instance"
35-
/>
36-
</main>
3753
</div>
54+
<main class="flex-1 overflow-y-auto relative">
55+
<router-view
56+
v-if="instance"
57+
:application="application"
58+
:instance="instance"
59+
/>
60+
</main>
3861
</div>
3962
</template>
4063

4164
<script lang="ts" setup>
42-
import { computed } from 'vue';
65+
import { faAngleDoubleLeft } from '@fortawesome/free-solid-svg-icons';
66+
import { computed, ref } from 'vue';
4367
import { useRoute } from 'vue-router';
4468
4569
import { useViewRegistry } from '@/composables/ViewRegistry';
@@ -51,6 +75,11 @@ const { applications } = useApplicationStore();
5175
const { views } = useViewRegistry();
5276
const route = useRoute();
5377
78+
const SIDEBAR_STORAGE_KEY = 'de.codecentric.spring-boot-admin.sidebar';
79+
const sidebarOpen = ref(
80+
localStorage.getItem(SIDEBAR_STORAGE_KEY) === 'true' || true,
81+
);
82+
5483
const instanceId = computed(() => {
5584
return route.params.instanceId;
5685
});
@@ -71,4 +100,9 @@ const application = computed(() => {
71100
const instance = computed(() => {
72101
return findInstance(applications.value, instanceId.value);
73102
});
103+
104+
const toggleSidebar = () => {
105+
sidebarOpen.value = !sidebarOpen.value;
106+
localStorage.setItem(SIDEBAR_STORAGE_KEY, String(sidebarOpen.value));
107+
};
74108
</script>

spring-boot-admin-server-ui/src/main/frontend/views/instances/shell/sidebar.vue

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,9 @@
1616

1717
<template>
1818
<aside
19-
:class="{ 'w-60': sidebarOpen }"
20-
class="h-full flex flex-col bg-white border-r backdrop-filter backdrop-blur-lg bg-opacity-80 z-40 w-10 md:w-60 transition-all left-0 pb-14 fixed"
19+
class="flex flex-col bg-white backdrop-filter backdrop-blur-lg bg-opacity-80 transition-all"
2120
>
22-
<ul class="relative px-1 py-1 overflow-y-auto">
21+
<ul class="relative px-1 py-1">
2322
<!-- Instance info block -->
2423
<li class="relative mb-1 hidden md:block">
2524
<router-link
@@ -37,13 +36,6 @@
3736
</router-link>
3837
</li>
3938

40-
<!-- sm: button toggle navigation -->
41-
<li class="block md:hidden mb-1">
42-
<a class="navbar-link navbar-link__group" @click.stop="toggleSidebar">
43-
<font-awesome-icon :icon="['fas', 'bars']" />
44-
</a>
45-
</li>
46-
4739
<!-- The actual nav -->
4840
<li
4941
v-for="group in groups"
@@ -91,7 +83,6 @@
9183
<!-- Le subnav -->
9284
<ul
9385
v-if="hasMultipleViews(group) && isActiveGroup(group)"
94-
:class="{ 'hidden md:block': !sidebarOpen }"
9586
class="relative block"
9687
>
9788
<li
@@ -119,10 +110,7 @@
119110
</Divider>
120111

121112
<li>
122-
<ul
123-
:class="{ 'hidden md:block': !sidebarOpen }"
124-
class="relative block"
125-
>
113+
<ul class="relative block">
126114
<li
127115
v-for="view in customLinksFromMetadata"
128116
:key="view.name"
@@ -165,7 +153,7 @@
165153
import { faArrowUpRightFromSquare } from '@fortawesome/free-solid-svg-icons';
166154
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
167155
import { Divider } from 'primevue';
168-
import { computed, h, ref, toRaw, watch } from 'vue';
156+
import { computed, h, toRaw } from 'vue';
169157
import { useI18n } from 'vue-i18n';
170158
import { useRoute } from 'vue-router';
171159
@@ -182,7 +170,6 @@ const props = defineProps<{
182170
183171
const { t } = useI18n();
184172
const route = useRoute();
185-
const sidebarOpen = ref(false);
186173
187174
const customLinksFromMetadata = computed(() => {
188175
const newVar = props.instance.metadataParsed?.sidebar?.links || [];
@@ -229,17 +216,6 @@ const groups = computed(() => {
229216
return Array.from(groups.values());
230217
});
231218
232-
watch(
233-
() => route.fullPath,
234-
() => {
235-
sidebarOpen.value = false;
236-
},
237-
);
238-
239-
function toggleSidebar() {
240-
sidebarOpen.value = !sidebarOpen.value;
241-
}
242-
243219
function getGroupTitle(groupId: string) {
244220
const key = 'sidebar.' + groupId + '.title';
245221
const translated = t(key);

0 commit comments

Comments
 (0)