fix resize issue when nav menu collapsed

This commit is contained in:
pa
2026-01-07 19:27:08 +09:00
committed by Natsumi
parent 7e4de15ef2
commit 738d22461e
2 changed files with 62 additions and 18 deletions

View File

@@ -1,4 +1,4 @@
import { computed, nextTick, onMounted, ref, watch } from 'vue';
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
import { storeToRefs } from 'pinia';
import { useAppearanceSettingsStore } from '../stores';
@@ -15,15 +15,18 @@ export function useAuthenticatedLayoutResizable() {
const { asideWidth, isNavCollapsed, isSideBarTabShow, navWidth } =
storeToRefs(appearanceStore);
const panelGroupRef = ref(null);
const navPanelRef = ref(null);
const navExpandedSize = ref(null);
const fallbackWidth =
typeof window !== 'undefined' && window.innerWidth
? window.innerWidth
: 1200;
const panelGroupRef = ref(null);
const navPanelRef = ref(null);
const navExpandedSize = ref(null);
const groupWidth = ref(fallbackWidth);
let resizeObserver = null;
let windowResizeHandler = null;
const getGroupWidth = () => {
const element = panelGroupRef.value?.$el ?? panelGroupRef.value;
const width = element?.getBoundingClientRect?.().width;
@@ -42,7 +45,9 @@ export function useAuthenticatedLayoutResizable() {
layout.length >= 3 &&
layout[layout.length - 1] <= 1;
const navCollapsedSize = computed(() => pxToPercent(navCollapsedPx));
const navCollapsedSize = computed(() =>
pxToPercent(navCollapsedPx, groupWidth.value)
);
const navExpandedPx = computed(() => navWidth.value || navDefaultPx);
const navDefaultSize = computed(() =>
@@ -75,15 +80,15 @@ export function useAuthenticatedLayoutResizable() {
return;
}
const groupWidth = getGroupWidth();
if (!Number.isFinite(groupWidth) || groupWidth <= 0) {
const width = getGroupWidth();
if (!Number.isFinite(width) || width <= 0) {
return;
}
const navSize = sizes[0];
if (!isNavCollapsed.value && Number.isFinite(navSize) && navSize > 0) {
navExpandedSize.value = navSize;
setNavWidth(Math.round(percentToPx(navSize, groupWidth)));
setNavWidth(Math.round(percentToPx(navSize, width)));
}
if (!isSideBarTabShow.value || sizes.length < 3) {
@@ -100,12 +105,19 @@ export function useAuthenticatedLayoutResizable() {
return;
}
setAsideWidth(Math.round(percentToPx(asideSize, groupWidth)));
setAsideWidth(Math.round(percentToPx(asideSize, width)));
};
const resizeNavPanel = (targetSize) =>
navPanelRef.value?.resize?.(targetSize);
const updateGroupWidth = () => {
groupWidth.value = getGroupWidth();
if (isNavCollapsed.value) {
resizeNavPanel(navCollapsedSize.value);
}
};
watch(isNavCollapsed, async (collapsed) => {
await nextTick();
if (collapsed) {
@@ -119,6 +131,7 @@ export function useAuthenticatedLayoutResizable() {
onMounted(async () => {
await nextTick();
updateGroupWidth();
let panelSize = null;
panelSize = navPanelRef.value?.getSize?.() ?? null;
@@ -126,6 +139,26 @@ export function useAuthenticatedLayoutResizable() {
if (isNavCollapsed.value) {
resizeNavPanel(navCollapsedSize.value);
}
const element = panelGroupRef.value?.$el ?? panelGroupRef.value;
if (element && typeof ResizeObserver !== 'undefined') {
resizeObserver = new ResizeObserver(updateGroupWidth);
resizeObserver.observe(element);
} else if (typeof window !== 'undefined') {
windowResizeHandler = updateGroupWidth;
window.addEventListener('resize', windowResizeHandler);
}
});
onUnmounted(() => {
if (resizeObserver) {
resizeObserver.disconnect();
resizeObserver = null;
}
if (windowResizeHandler && typeof window !== 'undefined') {
window.removeEventListener('resize', windowResizeHandler);
windowResizeHandler = null;
}
});
return {

View File

@@ -19,12 +19,17 @@ export function useDataTableScrollHeight(containerRef, options = {}) {
return 0;
}
const style = getComputedStyle(el);
return (Number.parseFloat(style.paddingTop) || 0) + (Number.parseFloat(style.paddingBottom) || 0);
return (
(Number.parseFloat(style.paddingTop) || 0) +
(Number.parseFloat(style.paddingBottom) || 0)
);
};
const getHeight = (maybeRef) => {
const el = maybeRef?.value;
return el && typeof el.getBoundingClientRect === 'function' ? el.getBoundingClientRect().height : 0;
return el && typeof el.getBoundingClientRect === 'function'
? el.getBoundingClientRect().height
: 0;
};
const recalc = () => {
@@ -33,7 +38,10 @@ export function useDataTableScrollHeight(containerRef, options = {}) {
return;
}
const extraOffset = extraOffsetRefs.reduce((sum, ref) => sum + getHeight(ref), 0);
const extraOffset = extraOffsetRefs.reduce(
(sum, ref) => sum + getHeight(ref),
0
);
const available =
containerEl.clientHeight -
@@ -51,10 +59,12 @@ export function useDataTableScrollHeight(containerRef, options = {}) {
return;
}
const nextObserved = new Set([
containerRef?.value,
...extraOffsetRefs.map((ref) => ref?.value)
].filter(Boolean));
const nextObserved = new Set(
[
containerRef?.value,
...extraOffsetRefs.map((ref) => ref?.value)
].filter(Boolean)
);
for (const el of observedElements) {
if (!nextObserved.has(el)) {
@@ -93,7 +103,8 @@ export function useDataTableScrollHeight(containerRef, options = {}) {
});
const tableStyle = computed(() => {
if (!Number.isFinite(maxHeight.value) || maxHeight.value <= 0) return undefined;
if (!Number.isFinite(maxHeight.value) || maxHeight.value <= 0)
return undefined;
return { maxHeight: `${maxHeight.value}px` };
});