Files
VRCX/src/composables/useAuthenticatedLayoutResizable.js

135 lines
3.9 KiB
JavaScript

import { computed, nextTick, onMounted, ref, watch } from 'vue';
import { storeToRefs } from 'pinia';
import { useAppearanceSettingsStore } from '../stores';
export function useAuthenticatedLayoutResizable() {
const navCollapsedPx = 64;
const navDefaultPx = 240;
const navMinPx = 180;
const navMaxPx = 300;
const asideMaxPx = 500;
const appearanceStore = useAppearanceSettingsStore();
const { setAsideWidth, setNavWidth } = appearanceStore;
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 getGroupWidth = () => {
const element = panelGroupRef.value?.$el ?? panelGroupRef.value;
const width = element?.getBoundingClientRect?.().width;
return Number.isFinite(width) && width > 0 ? width : fallbackWidth;
};
const pxToPercent = (px, groupWidth, min = 1) => {
const w = groupWidth ?? getGroupWidth();
return Math.min(100, Math.max(min, (px / w) * 100));
};
const percentToPx = (percent, groupWidth) => (percent / 100) * groupWidth;
const isAsideCollapsed = (layout) =>
Array.isArray(layout) &&
layout.length >= 3 &&
layout[layout.length - 1] <= 1;
const navCollapsedSize = computed(() => pxToPercent(navCollapsedPx));
const navExpandedPx = computed(() => navWidth.value || navDefaultPx);
const navDefaultSize = computed(() =>
isNavCollapsed.value
? navCollapsedSize.value
: pxToPercent(navExpandedPx.value)
);
const navMinSize = computed(() =>
isNavCollapsed.value ? navCollapsedSize.value : pxToPercent(navMinPx)
);
const navMaxSize = computed(() =>
isNavCollapsed.value ? navCollapsedSize.value : pxToPercent(navMaxPx)
);
const asideDefaultSize = computed(() =>
pxToPercent(asideWidth.value, undefined, 0)
);
const asideMaxSize = computed(() => pxToPercent(asideMaxPx, undefined, 0));
const handleLayout = (sizes) => {
if (!Array.isArray(sizes) || sizes.length < 2) {
return;
}
const groupWidth = getGroupWidth();
if (!Number.isFinite(groupWidth) || groupWidth <= 0) {
return;
}
const navSize = sizes[0];
if (!isNavCollapsed.value && Number.isFinite(navSize) && navSize > 0) {
navExpandedSize.value = navSize;
setNavWidth(Math.round(percentToPx(navSize, groupWidth)));
}
if (!isSideBarTabShow.value || sizes.length < 3) {
return;
}
const asideSize = sizes[sizes.length - 1];
if (!Number.isFinite(asideSize)) {
return;
}
if (asideSize <= 1) {
setAsideWidth(0);
return;
}
setAsideWidth(Math.round(percentToPx(asideSize, groupWidth)));
};
const resizeNavPanel = (targetSize) =>
navPanelRef.value?.resize?.(targetSize);
watch(isNavCollapsed, async (collapsed) => {
await nextTick();
if (collapsed) {
resizeNavPanel(navCollapsedSize.value);
return;
}
const targetSize =
navExpandedSize.value ?? pxToPercent(navExpandedPx.value);
resizeNavPanel(targetSize);
});
onMounted(() => {
navExpandedSize.value =
navPanelRef.value?.getSize?.() ?? navDefaultSize.value;
if (isNavCollapsed.value) {
resizeNavPanel(navCollapsedSize.value);
}
});
return {
panelGroupRef,
navPanelRef,
navDefaultSize,
navMinSize,
navMaxSize,
asideDefaultSize,
asideMaxSize,
handleLayout,
isAsideCollapsed,
isNavCollapsed,
isSideBarTabShow
};
}