ui(admin-panel): responsive dashboard and mobile drawer layout
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -126,9 +126,19 @@ async function onLogout() {
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
.nav-left {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
}
|
||||
.nav-right {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.page-title {
|
||||
font-size: 16px;
|
||||
color: #1c2d56;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.breadcrumb {
|
||||
font-size: 13px;
|
||||
@@ -139,6 +149,29 @@ async function onLogout() {
|
||||
gap: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@media (max-width: 991px) {
|
||||
.the-navbar {
|
||||
height: 56px;
|
||||
line-height: 56px;
|
||||
padding: 0 8px 0 16px;
|
||||
}
|
||||
.nav-left {
|
||||
gap: 4px;
|
||||
}
|
||||
.breadcrumb {
|
||||
display: none;
|
||||
}
|
||||
.page-title {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
@media (max-width: 575px) {
|
||||
.user-name {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--
|
||||
|
||||
@@ -12,10 +12,25 @@
|
||||
sidebar/navbar that used to scroll away with it.
|
||||
-->
|
||||
<a-layout class="layout--main" :class="{ 'no-scroll': isAppPage }">
|
||||
<VerticalNavMenu :collapsed="collapsed" />
|
||||
<VerticalNavMenu v-if="!layout.isSmallScreen" :collapsed="collapsed" />
|
||||
|
||||
<a-drawer
|
||||
v-else
|
||||
:open="layout.mobileNavOpen"
|
||||
placement="right"
|
||||
:width="260"
|
||||
:closable="false"
|
||||
root-class-name="mobile-nav-drawer"
|
||||
@close="layout.setMobileNavOpen(false)"
|
||||
>
|
||||
<VerticalNavMenu />
|
||||
</a-drawer>
|
||||
|
||||
<a-layout>
|
||||
<TheNavbar :collapsed="collapsed" @toggle-sidebar="layout.setSidebarCollapsed(!collapsed)" />
|
||||
<TheNavbar
|
||||
:collapsed="layout.isSmallScreen ? !layout.mobileNavOpen : collapsed"
|
||||
@toggle-sidebar="onToggleSidebar"
|
||||
/>
|
||||
|
||||
<a-layout-content id="content-area">
|
||||
<div class="content-wrapper">
|
||||
@@ -41,6 +56,11 @@ const layout = useLayoutStore();
|
||||
// collapsed/expanded across reloads instead of resetting every time.
|
||||
const collapsed = computed(() => layout.sidebarCollapsed);
|
||||
|
||||
function onToggleSidebar() {
|
||||
if (layout.isSmallScreen) layout.setMobileNavOpen(!layout.mobileNavOpen);
|
||||
else layout.setSidebarCollapsed(!collapsed.value);
|
||||
}
|
||||
|
||||
// legacy meta.no_scroll -> the 'no-scroll' body class
|
||||
const isAppPage = computed(() => Boolean(route.meta?.no_scroll));
|
||||
|
||||
@@ -58,13 +78,23 @@ watch(
|
||||
() => route.path,
|
||||
() => {
|
||||
overriddenTitle.value = undefined;
|
||||
layout.setMobileNavOpen(false);
|
||||
},
|
||||
);
|
||||
|
||||
watch(
|
||||
() => layout.isSmallScreen,
|
||||
(small) => {
|
||||
if (!small) layout.setMobileNavOpen(false);
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.layout--main {
|
||||
height: 100vh;
|
||||
/* --vh is set from window.innerHeight in App.vue, so mobile browser chrome
|
||||
(address bar) is excluded from the height */
|
||||
height: calc(var(--vh, 1vh) * 100);
|
||||
overflow: hidden; /* the sidebar and navbar are pinned; only #content-area scrolls */
|
||||
}
|
||||
.layout--main > :deep(.ant-layout) {
|
||||
@@ -78,8 +108,14 @@ watch(
|
||||
gap underneath on short lists. This is also the ONLY element that
|
||||
scrolls — the navbar above it and the sidebar beside it stay fixed. */
|
||||
display: flex;
|
||||
height: calc(100vh - 61px); /* 61px matches TheNavbar's fixed height */
|
||||
height: calc(var(--vh, 1vh) * 100 - 61px); /* 61px matches TheNavbar's fixed height */
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
@media (max-width: 991px) {
|
||||
#content-area {
|
||||
height: calc(var(--vh, 1vh) * 100 - 56px); /* TheNavbar is 56px below 992 */
|
||||
}
|
||||
}
|
||||
.content-wrapper,
|
||||
.content-area__content {
|
||||
@@ -87,5 +123,17 @@ watch(
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
min-width: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- Unscoped: <a-drawer> teleports to <body>; contained by root-class-name. -->
|
||||
<style>
|
||||
.mobile-nav-drawer .ant-drawer-body {
|
||||
padding: 0;
|
||||
}
|
||||
.mobile-nav-drawer .vertical-nav-menu {
|
||||
height: 100%;
|
||||
border-left: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user