Download dashboard/src/utils/sidebarCustomization.js from qa1145/astrbbbb: direct link, hf CLI and curl.
- Browser
- Download file 5.72 kB
-
https://huggingface.co/spaces/qa1145/astrbbbb/resolve/main/dashboard/src/utils/sidebarCustomization.js
- Command line
-
hf download hf://spaces/qa1145/astrbbbb/dashboard/src/utils/sidebarCustomization.js
-
curl -L -o sidebarCustomization.js https://huggingface.co/spaces/qa1145/astrbbbb/resolve/main/dashboard/src/utils/sidebarCustomization.js
5.72 kB
| // Utility for managing sidebar customization in localStorage | |
| const STORAGE_KEY = 'astrbot_sidebar_customization'; | |
| /** | |
| * Get the customized sidebar configuration from localStorage | |
| * @returns {Object|null} The customization config or null if not set | |
| */ | |
| export function getSidebarCustomization() { | |
| try { | |
| const stored = localStorage.getItem(STORAGE_KEY); | |
| return stored ? JSON.parse(stored) : null; | |
| } catch (error) { | |
| console.error('Error reading sidebar customization:', error); | |
| return null; | |
| } | |
| } | |
| /** | |
| * Save the sidebar customization to localStorage | |
| * @param {Object} config - The customization configuration | |
| * @param {Array} config.mainItems - Array of item titles for main sidebar | |
| * @param {Array} config.moreItems - Array of item titles for "More Features" group | |
| */ | |
| export function setSidebarCustomization(config) { | |
| try { | |
| localStorage.setItem(STORAGE_KEY, JSON.stringify(config)); | |
| } catch (error) { | |
| console.error('Error saving sidebar customization:', error); | |
| } | |
| } | |
| /** | |
| * Clear the sidebar customization (reset to default) | |
| */ | |
| export function clearSidebarCustomization() { | |
| try { | |
| localStorage.removeItem(STORAGE_KEY); | |
| } catch (error) { | |
| console.error('Error clearing sidebar customization:', error); | |
| } | |
| } | |
| /** | |
| * 解析侧边栏默认项与用户定制,返回主区/更多区及可选的合并结果 | |
| * @param {Array} defaultItems - 默认侧边栏结构 | |
| * @param {Object|null} customization - 用户定制(mainItems/moreItems) | |
| * @param {Object} options | |
| * @param {boolean} [options.cloneItems=false] - 是否克隆条目以避免外部引用被修改 | |
| * @param {boolean} [options.assembleMoreGroup=false] - 是否组装带更多分组的整体数组 | |
| * @returns {{ mainItems: Array, moreItems: Array, merged?: Array }} | |
| */ | |
| export function resolveSidebarItems(defaultItems, customization, options = {}) { | |
| const { cloneItems = false, assembleMoreGroup = false } = options; | |
| const normalizeKeys = (keys = []) => { | |
| const list = Array.isArray(keys) ? keys : []; | |
| const deduped = []; | |
| const seen = new Set(); | |
| list.forEach((key) => { | |
| if (typeof key !== 'string') return; | |
| if (seen.has(key)) return; | |
| seen.add(key); | |
| deduped.push(key); | |
| }); | |
| return deduped; | |
| }; | |
| const all = new Map(); | |
| const defaultMain = []; | |
| const defaultMore = []; | |
| // 收集所有条目,按 title 建索引 | |
| defaultItems.forEach(item => { | |
| if (item.children && item.title === 'core.navigation.groups.more') { | |
| item.children.forEach(child => { | |
| all.set(child.title, cloneItems ? { ...child } : child); | |
| defaultMore.push(child.title); | |
| }); | |
| } else { | |
| all.set(item.title, cloneItems ? { ...item } : item); | |
| defaultMain.push(item.title); | |
| } | |
| }); | |
| const hasCustomization = Boolean(customization); | |
| let mainKeys = hasCustomization ? normalizeKeys(customization.mainItems || []) : [...defaultMain]; | |
| let moreKeys = hasCustomization ? normalizeKeys(customization.moreItems || []) : [...defaultMore]; | |
| if (hasCustomization) { | |
| mainKeys = mainKeys.filter(title => all.has(title)); | |
| moreKeys = moreKeys.filter(title => all.has(title)); | |
| } | |
| if (hasCustomization) { | |
| // 如果同一项同时出现在主区与更多区,主区优先。 | |
| const mainSet = new Set(mainKeys); | |
| moreKeys = moreKeys.filter(title => !mainSet.has(title)); | |
| } | |
| const used = hasCustomization | |
| ? new Set([...mainKeys, ...moreKeys]) | |
| : new Set(defaultMain.concat(defaultMore)); | |
| const mainItems = mainKeys | |
| .map(title => all.get(title)) | |
| .filter(Boolean); | |
| if (hasCustomization) { | |
| // 补充新增默认主区项 | |
| defaultMain.forEach(title => { | |
| if (!used.has(title)) { | |
| const item = all.get(title); | |
| if (item) mainItems.push(item); | |
| } | |
| }); | |
| } | |
| const moreItems = moreKeys | |
| .map(title => all.get(title)) | |
| .filter(Boolean); | |
| if (hasCustomization) { | |
| // 补充新增默认更多区项 | |
| defaultMore.forEach(title => { | |
| if (!used.has(title)) { | |
| const item = all.get(title); | |
| if (item) moreItems.push(item); | |
| } | |
| }); | |
| } | |
| let merged; | |
| if (assembleMoreGroup) { | |
| const children = cloneItems ? moreItems.map(item => ({ ...item })) : [...moreItems]; | |
| if (children.length > 0) { | |
| merged = [ | |
| ...mainItems, | |
| { | |
| title: 'core.navigation.groups.more', | |
| icon: 'mdi-dots-horizontal', | |
| children | |
| } | |
| ]; | |
| } else { | |
| merged = [...mainItems]; | |
| } | |
| } | |
| return { | |
| mainItems, | |
| moreItems, | |
| merged, | |
| normalizedMainKeys: [...mainKeys], | |
| normalizedMoreKeys: [...moreKeys] | |
| }; | |
| } | |
| /** | |
| * 应用侧边栏定制,返回包含更多分组的完整结构 | |
| * @param {Array} defaultItems - 默认侧边栏结构 | |
| * @returns {Array} 自定义后的结构(新数组,不修改入参) | |
| */ | |
| export function applySidebarCustomization(defaultItems) { | |
| const customization = getSidebarCustomization(); | |
| const { | |
| merged, | |
| normalizedMainKeys, | |
| normalizedMoreKeys | |
| } = resolveSidebarItems(defaultItems, customization, { | |
| cloneItems: true, | |
| assembleMoreGroup: true | |
| }); | |
| if (customization) { | |
| const rawMainKeys = Array.isArray(customization.mainItems) ? customization.mainItems : []; | |
| const rawMoreKeys = Array.isArray(customization.moreItems) ? customization.moreItems : []; | |
| const hasChanged = | |
| JSON.stringify(rawMainKeys) !== JSON.stringify(normalizedMainKeys) || | |
| JSON.stringify(rawMoreKeys) !== JSON.stringify(normalizedMoreKeys); | |
| if (hasChanged) { | |
| setSidebarCustomization({ | |
| mainItems: normalizedMainKeys, | |
| moreItems: normalizedMoreKeys | |
| }); | |
| } | |
| } | |
| return merged || defaultItems; | |
| } | |