UNPKG

@blocklet/ui-react

Version:

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

94 lines (82 loc) 3.13 kB
import { useMemo } from 'react'; import PropTypes from 'prop-types'; import { styled, useTheme, deepmerge, ThemeProvider } from '@arcblock/ux/lib/Theme'; import { withErrorBoundary } from 'react-error-boundary'; import { useLocaleContext } from '@arcblock/ux/lib/Locale/context'; import { ErrorFallback } from '@arcblock/ux/lib/ErrorBoundary'; import useBlockletLogo from '@arcblock/ux/lib/hooks/use-blocklet-logo'; import omit from 'lodash/omit'; import InternalFooter from './internal-footer'; import { mapRecursive } from '../utils'; import { formatBlockletInfo, getLocalizedNavigation } from '../blocklets'; import { BlockletMetaProps } from '../types'; import withHideWhenEmbed from '../libs/with-hide-when-embed'; /** * 专门用于 (composable) blocklet 的 Footer 组件, 基于 blocklet meta 中的数据渲染 */ function Footer({ meta = {}, theme: themeOverrides = null, ...rest }) { const { locale } = useLocaleContext() || {}; const parentTheme = useTheme(); const formattedBlocklet = useMemo(() => { const blocklet = Object.assign({}, window.blocklet, meta); try { return formatBlockletInfo(blocklet); } catch (e) { console.error('Failed to format blocklet info', e, blocklet); return blocklet; } }, [meta]); const mergeTheme = useMemo(() => deepmerge(parentTheme, themeOverrides), [parentTheme, themeOverrides]); const appLogo = useBlockletLogo({ key: 'xs', // 始终优先长 logo meta, theme: themeOverrides, }); if (!formattedBlocklet.appName) { return null; } const { appName, appDescription, description, copyright } = formattedBlocklet; const $bgColor = mergeTheme.palette.background.default; const localized = { footerNav: getLocalizedNavigation(formattedBlocklet?.navigation?.footer, locale) || [], socialMedia: getLocalizedNavigation(formattedBlocklet?.navigation?.social, locale) || [], links: getLocalizedNavigation(formattedBlocklet?.navigation?.bottom, locale) || [], }; const props = { brand: { name: appName, description: appDescription || description, logo: appLogo, }, navigation: mapRecursive( localized.footerNav, (item) => ({ ...item, label: item.title, link: item.link, }), 'items' ), copyright, socialMedia: localized.socialMedia, links: localized.links.map((item) => ({ ...item, label: item.title })), }; return ( <ThemeProvider theme={mergeTheme}> <StyledInternalFooter {...props} {...omit(rest, ['bordered'])} $bordered={rest?.bordered} $bgcolor={$bgColor} /> </ThemeProvider> ); } Footer.propTypes = { meta: BlockletMetaProps, // 允许覆盖 footer 内置的 theme theme: PropTypes.object, }; const StyledInternalFooter = styled(InternalFooter)` ${({ $bordered, theme }) => `border-top: 1px solid ${$bordered && theme.palette.divider};`} color: ${({ theme }) => theme.palette.text.secondary}; ${({ $bgcolor }) => $bgcolor && `background-color: ${$bgcolor};`} `; export default withErrorBoundary(withHideWhenEmbed(Footer), { FallbackComponent: ErrorFallback, });