UNPKG

@blocklet/ui-react

Version:

Some useful front-end web components that can be used in Blocklets.

178 lines (162 loc) 4.7 kB
import { mapRecursive, filterRecursive, isUrl } from './utils'; export const publicPath = window?.blocklet?.groupPrefix || window?.blocklet?.prefix || '/'; /** * 格式化 theme (目前仅考虑 background) */ export const formatTheme = (theme) => { const formatted = { ...theme }; const background = theme?.background; if (typeof background === 'string') { formatted.background = { header: background, footer: background, default: background }; } else if (background && typeof background === 'object') { formatted.background = { header: background.header || background.default, footer: background.footer || background.default, default: background.default, }; } return formatted; }; export const getLink = (link, locale = 'en') => { if (typeof link === 'string') { // http[s] 开头的 url if (isUrl(link)) { const url = new URL(link); url.searchParams.set('locale', locale); return url.href; } const url = new URL(link, window.location.origin); url.searchParams.set('locale', locale); return url.pathname + url.search; } if (typeof link === 'object') { return link[locale] || link?.en || link?.zh; } return link; }; /** * 获取指定 locale 对应的 navigation 数据, 仅考虑 zh/en */ export const getLocalizedNavigation = (navigation, locale = 'en') => { if (!navigation?.length) { return navigation; } const trans = (text, _locale) => { if (text && typeof text === 'object') { return text[_locale] || text?.en || text?.zh; } return text; }; return mapRecursive( navigation, (item) => { return { ...item, title: trans(item.title, locale), description: trans(item.description, locale), // 仅对叶结点进行处理 link: !item.items?.length ? getLink(item.link, locale) : item.link, _rawLink: item.link, }; }, 'items' ); }; /** * 格式化 navigation * * - role 统一为数组形式 */ export const formatNavigation = (navigation) => { return mapRecursive( navigation, (item) => { if (item.role) { return { ...item, role: Array.isArray(item.role) ? item.role : [item.role], }; } return item; }, 'items' ); }; export const parseNavigation = (navigation) => { if (!navigation?.length) { return null; } const formattedNav = formatNavigation(navigation); const sections = { header: [], footer: [], // 对应 footer social media social: [], // 对应 footer 底部 links bottom: [], // 对应 dashboard#sidenav 导航 dashboard: [], // session manager menus sessionManager: [], userCenter: [], }; // 对 navigation 顶层元素按 section 分组 formattedNav.forEach((item) => { // item#section 为空时, 表示只存在于 header if (!item.section) { sections.header.push(item); // item 出现在指定几个 section 中 (array) } else if (Array.isArray(item.section)) { item.section.forEach((sectionKey) => { sections[sectionKey]?.push(item); }); // item 出现在指定的一个 section 中 (string) } else if (typeof item.section === 'string') { sections[item.section]?.push(item); } }); return sections; }; /** * 格式化 blocklet info 数据 */ export const formatBlockletInfo = (blockletInfo) => { if (!blockletInfo) { return null; } const formatted = { ...blockletInfo }; // theme formatted.theme = formatTheme(formatted.theme); // navigation formatted.navigation = parseNavigation(filterValidNavItems(formatted.navigation)); return formatted; }; /** * 过滤掉无效结点 (无 link 且子元素为空) */ export const filterValidNavItems = (navigation = []) => { return filterRecursive(navigation, (item, context) => !!item.link || context.filteredChildren?.length, 'items'); }; /** * 根据 role 筛选 nav, 规则: * - 如果是枝结点, 必须至少存在一个符合条件的子结点 * - role 未定义, 符合条件 * - role 定义且包括当前的 userRole, 符合条件 * * @param {object[]} nav 导航菜单数据 * @param {string} userRole 当前用户 role * @returns 符合 role 权限的导航菜单数据 */ export const filterNavByRole = (nav, userRole) => { return filterRecursive( nav, (item, context) => { const isRoleMatched = !item.role || (userRole && (item.role.includes(userRole) || item.role.includes('guest'))); if (!context.isLeaf) { return isRoleMatched && context.filteredChildren?.length; } return isRoleMatched; }, 'items' ); };