mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-05-03 13:36:04 +02:00
refactor useNavLayout
This commit is contained in:
@@ -7,10 +7,15 @@ import {
|
|||||||
DASHBOARD_NAV_KEY_PREFIX,
|
DASHBOARD_NAV_KEY_PREFIX,
|
||||||
navDefinitions
|
navDefinitions
|
||||||
} from '../../../shared/constants';
|
} from '../../../shared/constants';
|
||||||
|
import { triggerNavEntryAction } from '../navActionUtils';
|
||||||
|
import {
|
||||||
|
buildMenuItems,
|
||||||
|
collectLayoutKeys,
|
||||||
|
findFirstNavEntry,
|
||||||
|
findFirstNavKey
|
||||||
|
} from '../navLayoutHelpers';
|
||||||
import { normalizeHiddenKeys, sanitizeLayout } from '../navMenuUtils';
|
import { normalizeHiddenKeys, sanitizeLayout } from '../navMenuUtils';
|
||||||
|
|
||||||
const DEFAULT_FOLDER_ICON = 'ri-folder-line';
|
|
||||||
|
|
||||||
export function useNavLayout({
|
export function useNavLayout({
|
||||||
t,
|
t,
|
||||||
locale,
|
locale,
|
||||||
@@ -72,82 +77,16 @@ export function useNavLayout({
|
|||||||
{ type: 'item', key: 'direct-access' }
|
{ type: 'item', key: 'direct-access' }
|
||||||
];
|
];
|
||||||
|
|
||||||
const menuItems = computed(() => {
|
const menuItems = computed(() =>
|
||||||
const items = [];
|
buildMenuItems(navLayout.value, navDefinitionMap.value, t)
|
||||||
navLayout.value.forEach((entry) => {
|
);
|
||||||
if (entry.type === 'item') {
|
|
||||||
const definition = navDefinitionMap.value.get(entry.key);
|
|
||||||
if (!definition) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
items.push({
|
|
||||||
...definition,
|
|
||||||
index: definition.key,
|
|
||||||
title: definition.tooltip || definition.labelKey,
|
|
||||||
titleIsCustom: Boolean(definition.isDashboard)
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry.type === 'folder') {
|
|
||||||
const folderDefinitions = (entry.items || [])
|
|
||||||
.map((key) => navDefinitionMap.value.get(key))
|
|
||||||
.filter(Boolean);
|
|
||||||
if (folderDefinitions.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const folderEntries = folderDefinitions.map((definition) => ({
|
|
||||||
label: definition.labelKey,
|
|
||||||
routeName: definition.routeName,
|
|
||||||
routeParams: definition.routeParams,
|
|
||||||
index: definition.key,
|
|
||||||
icon: definition.icon,
|
|
||||||
action: definition.action,
|
|
||||||
titleIsCustom: Boolean(definition.isDashboard)
|
|
||||||
}));
|
|
||||||
|
|
||||||
items.push({
|
|
||||||
index: entry.id,
|
|
||||||
icon: entry.icon || DEFAULT_FOLDER_ICON,
|
|
||||||
title:
|
|
||||||
entry.name?.trim() ||
|
|
||||||
t('nav_menu.custom_nav.folder_name_placeholder'),
|
|
||||||
titleIsCustom: true,
|
|
||||||
children: folderEntries
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return items;
|
|
||||||
});
|
|
||||||
|
|
||||||
const getFirstNavEntryLocal = (layout) => {
|
const getFirstNavEntryLocal = (layout) => {
|
||||||
for (const entry of layout) {
|
return findFirstNavEntry(layout, navDefinitionMap.value);
|
||||||
if (entry.type === 'item') {
|
|
||||||
const definition = navDefinitionMap.value.get(entry.key);
|
|
||||||
if (
|
|
||||||
definition?.routeName ||
|
|
||||||
definition?.action ||
|
|
||||||
definition?.path
|
|
||||||
) {
|
|
||||||
return definition;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (entry.type === 'folder' && entry.items?.length) {
|
|
||||||
const definition = entry.items
|
|
||||||
.map((key) => navDefinitionMap.value.get(key))
|
|
||||||
.find((def) => def?.routeName || def?.action || def?.path);
|
|
||||||
if (definition) {
|
|
||||||
return definition;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFirstNavKeyLocal = (layout) => {
|
const getFirstNavKeyLocal = (layout) => {
|
||||||
const entry = getFirstNavEntryLocal(layout);
|
return findFirstNavKey(layout, navDefinitionMap.value);
|
||||||
return entry?.key || null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const activeMenuIndex = computed(() => {
|
const activeMenuIndex = computed(() => {
|
||||||
@@ -182,27 +121,6 @@ export function useNavLayout({
|
|||||||
return `nav-folder-${dayjs().toISOString()}-${Math.random().toString().slice(2, 4)}`;
|
return `nav-folder-${dayjs().toISOString()}-${Math.random().toString().slice(2, 4)}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const collectLayoutKeys = (layout) => {
|
|
||||||
const keys = new Set();
|
|
||||||
if (!Array.isArray(layout)) {
|
|
||||||
return keys;
|
|
||||||
}
|
|
||||||
layout.forEach((entry) => {
|
|
||||||
if (entry?.type === 'item' && entry.key) {
|
|
||||||
keys.add(entry.key);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (entry?.type === 'folder' && Array.isArray(entry.items)) {
|
|
||||||
entry.items.forEach((key) => {
|
|
||||||
if (key) {
|
|
||||||
keys.add(key);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return keys;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getAppendDefinitions = (layout, hiddenKeys = []) => {
|
const getAppendDefinitions = (layout, hiddenKeys = []) => {
|
||||||
const keysInLayout = collectLayoutKeys(layout);
|
const keysInLayout = collectLayoutKeys(layout);
|
||||||
const hiddenSet = new Set(Array.isArray(hiddenKeys) ? hiddenKeys : []);
|
const hiddenSet = new Set(Array.isArray(hiddenKeys) ? hiddenKeys : []);
|
||||||
@@ -246,35 +164,8 @@ export function useNavLayout({
|
|||||||
return sanitizeLayoutLocal(base, []);
|
return sanitizeLayoutLocal(base, []);
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleRouteChange = (routeName, routeParams = undefined) => {
|
|
||||||
if (!routeName) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (routeParams) {
|
|
||||||
router.push({ name: routeName, params: routeParams });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
router.push({ name: routeName });
|
|
||||||
};
|
|
||||||
|
|
||||||
const triggerNavAction = (entry) => {
|
const triggerNavAction = (entry) => {
|
||||||
if (!entry) {
|
triggerNavEntryAction(entry, { router, directAccessPaste });
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry.action === 'direct-access') {
|
|
||||||
directAccessPaste();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry.routeName) {
|
|
||||||
handleRouteChange(entry.routeName, entry.routeParams);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry.path) {
|
|
||||||
router.push(entry.path);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const saveNavLayout = async (layout, hiddenKeys = []) => {
|
const saveNavLayout = async (layout, hiddenKeys = []) => {
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/**
|
||||||
|
* @param {object | null | undefined} entry
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isNavEntryActionable(entry) {
|
||||||
|
return Boolean(entry?.routeName || entry?.action || entry?.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {object} router
|
||||||
|
* @param {string} routeName
|
||||||
|
* @param {object | undefined} routeParams
|
||||||
|
*/
|
||||||
|
export function navigateToRoute(router, routeName, routeParams = undefined) {
|
||||||
|
if (!routeName) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (routeParams) {
|
||||||
|
router.push({ name: routeName, params: routeParams });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
router.push({ name: routeName });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {object | null | undefined} entry
|
||||||
|
* @param {object} deps
|
||||||
|
* @param {object} deps.router
|
||||||
|
* @param {Function} deps.directAccessPaste
|
||||||
|
*/
|
||||||
|
export function triggerNavEntryAction(entry, { router, directAccessPaste }) {
|
||||||
|
if (!entry) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.action === 'direct-access') {
|
||||||
|
directAccessPaste();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.routeName) {
|
||||||
|
navigateToRoute(router, entry.routeName, entry.routeParams);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.path) {
|
||||||
|
router.push(entry.path);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
import { isNavEntryActionable } from './navActionUtils';
|
||||||
|
|
||||||
|
const DEFAULT_FOLDER_ICON = 'ri-folder-line';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Array} layout
|
||||||
|
* @returns {Set<string>}
|
||||||
|
*/
|
||||||
|
export function collectLayoutKeys(layout) {
|
||||||
|
const keys = new Set();
|
||||||
|
if (!Array.isArray(layout)) {
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
layout.forEach((entry) => {
|
||||||
|
if (entry?.type === 'item' && entry.key) {
|
||||||
|
keys.add(entry.key);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry?.type === 'folder' && Array.isArray(entry.items)) {
|
||||||
|
entry.items.forEach((key) => {
|
||||||
|
if (key) {
|
||||||
|
keys.add(key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Array} layout
|
||||||
|
* @param {Map<string, any>} navDefinitionMap
|
||||||
|
* @param {Function} t
|
||||||
|
* @returns {Array}
|
||||||
|
*/
|
||||||
|
export function buildMenuItems(layout, navDefinitionMap, t) {
|
||||||
|
const items = [];
|
||||||
|
|
||||||
|
layout.forEach((entry) => {
|
||||||
|
if (entry.type === 'item') {
|
||||||
|
const definition = navDefinitionMap.get(entry.key);
|
||||||
|
if (!definition) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
items.push({
|
||||||
|
...definition,
|
||||||
|
index: definition.key,
|
||||||
|
title: definition.tooltip || definition.labelKey,
|
||||||
|
titleIsCustom: Boolean(definition.isDashboard)
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.type === 'folder') {
|
||||||
|
const folderDefinitions = (entry.items || [])
|
||||||
|
.map((key) => navDefinitionMap.get(key))
|
||||||
|
.filter(Boolean);
|
||||||
|
if (folderDefinitions.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
items.push({
|
||||||
|
index: entry.id,
|
||||||
|
icon: entry.icon || DEFAULT_FOLDER_ICON,
|
||||||
|
title:
|
||||||
|
entry.name?.trim() ||
|
||||||
|
t('nav_menu.custom_nav.folder_name_placeholder'),
|
||||||
|
titleIsCustom: true,
|
||||||
|
children: folderDefinitions.map((definition) => ({
|
||||||
|
label: definition.labelKey,
|
||||||
|
routeName: definition.routeName,
|
||||||
|
routeParams: definition.routeParams,
|
||||||
|
index: definition.key,
|
||||||
|
icon: definition.icon,
|
||||||
|
action: definition.action,
|
||||||
|
path: definition.path,
|
||||||
|
titleIsCustom: Boolean(definition.isDashboard)
|
||||||
|
}))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Array} layout
|
||||||
|
* @param {Map<string, any>} navDefinitionMap
|
||||||
|
* @returns {object | null}
|
||||||
|
*/
|
||||||
|
export function findFirstNavEntry(layout, navDefinitionMap) {
|
||||||
|
for (const entry of layout) {
|
||||||
|
if (entry.type === 'item') {
|
||||||
|
const definition = navDefinitionMap.get(entry.key);
|
||||||
|
if (isNavEntryActionable(definition)) {
|
||||||
|
return definition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.type === 'folder' && entry.items?.length) {
|
||||||
|
const definition = entry.items
|
||||||
|
.map((key) => navDefinitionMap.get(key))
|
||||||
|
.find((def) => isNavEntryActionable(def));
|
||||||
|
if (definition) {
|
||||||
|
return definition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Array} layout
|
||||||
|
* @param {Map<string, any>} navDefinitionMap
|
||||||
|
* @returns {string | null}
|
||||||
|
*/
|
||||||
|
export function findFirstNavKey(layout, navDefinitionMap) {
|
||||||
|
const entry = findFirstNavEntry(layout, navDefinitionMap);
|
||||||
|
return entry?.key || null;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user