use reka splitter config api

This commit is contained in:
pa
2026-02-01 02:44:07 +09:00
parent 564f5bc73c
commit a33faf6b1a
4 changed files with 142 additions and 299 deletions

View File

@@ -1,173 +1,43 @@
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
import { computed, ref } from 'vue';
import { storeToRefs } from 'pinia';
import { useAppearanceSettingsStore } from '../stores';
export function useMainLayoutResizable() {
const asideMaxPx = 700;
const mainMinPx = 320;
const appearanceStore = useAppearanceSettingsStore();
const { setAsideWidth } = appearanceStore;
const { asideWidth, isSideBarTabShow, isNavCollapsed } =
storeToRefs(appearanceStore);
const { isSideBarTabShow } = storeToRefs(appearanceStore);
const fallbackWidth =
typeof window !== 'undefined' && window.innerWidth
? window.innerWidth
: 1200;
const asideDefaultSize = 25;
const mainDefaultSize = 75;
const asideMinSize = 12;
const asideMaxPx = 700;
const panelGroupRef = ref(null);
const asidePanelRef = ref(null);
const groupWidth = ref(fallbackWidth);
let resizeObserver = null;
// size helpers: panelGroupRef, groupWidth, fallbackWidth
const getGroupWidthRaw = () => {
const element = panelGroupRef.value?.$el ?? panelGroupRef.value;
const width = element?.getBoundingClientRect?.().width;
return Number.isFinite(width) ? width : null;
};
const getGroupWidth = () => {
const width = getGroupWidthRaw();
return Number.isFinite(width) && width > 0 ? width : fallbackWidth;
};
const pxToPercent = (px, width, min = 1) => {
const w = Number.isFinite(width) && width > 0 ? width : getGroupWidth();
return Math.min(100, Math.max(min, (px / w) * 100));
};
const percentToPx = (percent, groupWidth) => (percent / 100) * groupWidth;
const getMaxAsidePx = (width) =>
Math.min(asideMaxPx, Math.max(0, width - mainMinPx));
const clampAsidePx = (px, width) =>
Math.min(getMaxAsidePx(width), Math.max(0, px));
// layout state: isAsideCollapsed, asideMaxSize, asideDefaultSize, mainDefaultSize
const isAsideCollapsed = (layout) =>
Array.isArray(layout) &&
layout.length >= 2 &&
layout[layout.length - 1] <= 1;
const asideMaxSize = computed(() =>
pxToPercent(getMaxAsidePx(groupWidth.value), groupWidth.value, 0)
);
const asideDefaultSize = computed(() => {
if (!isSideBarTabShow.value) {
return 0;
}
const percent = pxToPercent(asideWidth.value, groupWidth.value, 0);
return Math.min(asideMaxSize.value, percent);
});
const mainDefaultSize = computed(
() => 100 - (isSideBarTabShow.value ? asideDefaultSize.value : 0)
);
// drag -> store: handleLayout, asideWidth
const isAsideCollapsedState = ref(false);
const handleLayout = (sizes) => {
if (!Array.isArray(sizes) || sizes.length < 1) {
if (!Array.isArray(sizes) || sizes.length < 2) {
isAsideCollapsedState.value = false;
return;
}
if (!isSideBarTabShow.value || sizes.length < 2) {
return;
}
const rawWidth = getGroupWidthRaw();
if (!Number.isFinite(rawWidth) || rawWidth <= 0) {
return;
}
const width = rawWidth;
const asideSize = sizes[sizes.length - 1];
if (!Number.isFinite(asideSize)) {
return;
}
const nextAsidePx =
asideSize <= 1
? 0
: clampAsidePx(
Math.round(percentToPx(asideSize, width)),
width
);
if (nextAsidePx === asideWidth.value) {
return;
}
setAsideWidth(nextAsidePx);
isAsideCollapsedState.value = isAsideCollapsed(sizes);
};
// sync store -> panel: resizeAsidePanel, syncAsidePanelSize
const resizeAsidePanel = (targetSize) =>
asidePanelRef.value?.resize?.(targetSize);
const syncAsidePanelSize = (width) => {
if (!isSideBarTabShow.value) {
return;
}
const maxAsidePx = getMaxAsidePx(width);
const clampedAsidePx = Math.min(
maxAsidePx,
Math.max(0, asideWidth.value)
);
if (maxAsidePx > 0 && clampedAsidePx !== asideWidth.value) {
setAsideWidth(clampedAsidePx);
}
const asideTargetSize =
maxAsidePx > 0 && clampedAsidePx > 0
? pxToPercent(clampedAsidePx, width, 0)
: 0;
resizeAsidePanel(asideTargetSize);
};
// window resize: updateGroupWidth, resizeObserver
const updateGroupWidth = () => {
const width = getGroupWidth();
groupWidth.value = width;
syncAsidePanelSize(width);
};
onMounted(async () => {
await nextTick();
updateGroupWidth();
const element = panelGroupRef.value?.$el ?? panelGroupRef.value;
if (element && typeof ResizeObserver !== 'undefined') {
resizeObserver = new ResizeObserver(updateGroupWidth);
resizeObserver.observe(element);
}
});
watch(
() => [isSideBarTabShow.value, asideWidth.value],
() => {
syncAsidePanelSize(groupWidth.value);
}
const isAsideCollapsedStatic = computed(
() => !isSideBarTabShow.value || isAsideCollapsedState.value
);
onUnmounted(() => {
if (resizeObserver) {
resizeObserver.disconnect();
resizeObserver = null;
}
});
return {
panelGroupRef,
asidePanelRef,
asideDefaultSize,
asideMaxSize,
asideMinSize,
asideMaxPx,
mainDefaultSize,
handleLayout,
isAsideCollapsed,
isNavCollapsed,
isAsideCollapsedStatic,
isSideBarTabShow
};
}

View File

@@ -73,7 +73,6 @@ export const useAppearanceSettingsStore = defineStore(
'Sort by Time in Instance',
'Sort by Last Active'
]);
const asideWidth = ref(300);
const navWidth = ref(240);
const isSidebarGroupByInstance = ref(true);
const isHideFriendsInSameInstance = ref(false);
@@ -145,7 +144,6 @@ export const useAppearanceSettingsStore = defineStore(
dtHour12Config,
dtIsoFormatConfig,
sidebarSortMethodsConfig,
asideWidthConfig,
navWidthConfig,
isSidebarGroupByInstanceConfig,
isHideFriendsInSameInstanceConfig,
@@ -195,7 +193,6 @@ export const useAppearanceSettingsStore = defineStore(
'Sort by Last Active'
])
),
configRepository.getInt('VRCX_sidePanelWidth', 300),
configRepository.getInt('VRCX_navPanelWidth', 240),
configRepository.getBool('VRCX_sidebarGroupByInstance', true),
configRepository.getBool(
@@ -288,7 +285,6 @@ export const useAppearanceSettingsStore = defineStore(
);
}
trustColor.value = { ...TRUST_COLOR_DEFAULTS };
asideWidth.value = asideWidthConfig;
navWidth.value = clampInt(navWidthConfig, 64, 480);
isSidebarGroupByInstance.value = isSidebarGroupByInstanceConfig;
isHideFriendsInSameInstance.value =
@@ -680,22 +676,6 @@ export const useAppearanceSettingsStore = defineStore(
});
}
}
function setAsideWidth(widthOrArray) {
let width = null;
if (Array.isArray(widthOrArray) && widthOrArray.length) {
width = widthOrArray[widthOrArray.length - 1];
} else if (typeof widthOrArray === 'number') {
width = widthOrArray;
}
if (!Number.isFinite(width) || width === null) {
return;
}
const normalized = Math.max(0, Math.round(width));
requestAnimationFrame(() => {
asideWidth.value = normalized;
configRepository.setInt('VRCX_sidePanelWidth', normalized);
});
}
function setIsSidebarGroupByInstance() {
isSidebarGroupByInstance.value = !isSidebarGroupByInstance.value;
configRepository.setBool(
@@ -972,7 +952,6 @@ export const useAppearanceSettingsStore = defineStore(
sidebarSortMethod2,
sidebarSortMethod3,
sidebarSortMethods,
asideWidth,
navWidth,
isSidebarGroupByInstance,
isHideFriendsInSameInstance,
@@ -1011,7 +990,6 @@ export const useAppearanceSettingsStore = defineStore(
setSidebarSortMethod3,
setSidebarSortMethods,
setNavWidth,
setAsideWidth,
setIsSidebarGroupByInstance,
setIsHideFriendsInSameInstance,
setIsSidebarDivideByFriendGroup,

View File

@@ -16,8 +16,8 @@
<SidebarInset class="min-w-0 bg-sidebar">
<ResizablePanelGroup
ref="panelGroupRef"
direction="horizontal"
auto-save-id="vrcx-main-layout-right-sidebar"
:class="['group/main-layout flex-1 h-full min-w-0', { 'aside-collapsed': isAsideCollapsedStatic }]"
@layout="handleLayout">
<template #default="{ layout }">
@@ -37,9 +37,8 @@
'z-20 [&>div]:-translate-x-1/2'
]"></ResizableHandle>
<ResizablePanel
ref="asidePanelRef"
:default-size="asideDefaultSize"
:max-size="asideMaxSize"
:min-size="asideMinSize"
:collapsed-size="0"
collapsible
:order="2"
@@ -114,7 +113,7 @@
const router = useRouter();
const appearanceSettingsStore = useAppearanceSettingsStore();
const { navWidth, isNavCollapsed, asideWidth } = storeToRefs(appearanceSettingsStore);
const { navWidth, isNavCollapsed } = storeToRefs(appearanceSettingsStore);
const sidebarOpen = computed(() => !isNavCollapsed.value);
@@ -163,18 +162,16 @@
});
const {
panelGroupRef,
asideDefaultSize,
asideMaxSize,
asideMinSize,
asideMaxPx,
mainDefaultSize,
handleLayout,
isAsideCollapsed,
isAsideCollapsedStatic,
isSideBarTabShow
} = useMainLayoutResizable();
const isAsideCollapsedStatic = computed(() => !isSideBarTabShow.value || asideWidth.value === 0);
watch(
() => watchState.isLoggedIn,
(isLoggedIn) => {