UNPKG

@blocklet/ui-react

Version:

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

196 lines (180 loc) 5.48 kB
import { getUTMUrl } from '@arcblock/ux/lib/withTracker/libs/utm'; import { mapRecursive, filterRecursive, isUrl, isMailProtocol } 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', defaultLocale = 'en') => { if (typeof link === 'string') { // http[s] 开头的 url if (isUrl(link)) { const url = new URL(link); url.searchParams.set('locale', locale); return url.href; } // 如果是 mailto 协议, 直接返回 if (isMailProtocol(link)) { return link; } 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[defaultLocale] || link.en; } return link; }; /** * 获取本地化后的导航菜单 * * @param {Object} params * @param {Array<{ * title?: string | Record<string, string>, * description?: string | Record<string, string>, * link?: string | Record<string, string>, * items?: any[], * [key: string]: any * }>} params.navigation - 导航菜单数据 * @param {string} params.locale - 当前语言 * @param {string} params.defaultLocale - 默认语言 * @param {'header' | 'footer'} [params.section='header'] - 导航区域,可选 * @returns {Array} 本地化处理后的导航数据 */ export const getLocalizedNavigation = ({ navigation, locale, defaultLocale, section = 'header' }) => { if (!navigation?.length) { return navigation; } const trans = (text, _locale) => { if (text && typeof text === 'object') { return text[_locale] || text[defaultLocale] || text.en; } return text; }; return mapRecursive( navigation, (item) => { return { ...item, title: trans(item.title, locale), description: trans(item.description, locale), // 仅对叶结点进行处理 link: getUTMUrl(!item.items?.length ? getLink(item.link, locale, defaultLocale) : item.link, section), _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' ); };