UNPKG

@blocklet/ui-react

Version:

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

140 lines (131 loc) 3.85 kB
import PropTypes from 'prop-types'; import { Box } from '@mui/material'; import clsx from 'clsx'; import Brand from './brand'; import Links from './links'; import SocialMedia from './social-media'; import Copyright from './copyright'; import StandardLayout from './layout/standard'; import PlainLayout from './layout/plain'; const layouts = [ { name: 'plain', // 没有 navigation 和 socialMedia, 使用一个简单的两端对齐布局 support: (_, data) => !data.navigation?.length && !data.socialMedia?.length, component: PlainLayout, }, { name: 'standard', // 默认标准布局 support: () => true, component: StandardLayout, }, ]; const layoutsKeyByName = layouts.reduce((acc, cur) => ({ ...acc, [cur.name]: cur }), {}); /** * 通用的内部 footer 组件, 定义并渲染常见的几种 footer 元素: brand/navigation/social medial 等 */ function InternalFooter({ ...props }) { const { brand = null, navigation = null, socialMedia = null, copyright = null, links = null, layout = 'auto', ...rest } = props; const renderBrand = () => { return brand ? <Brand {...brand} /> : null; }; const renderNavigation = () => { return navigation?.length ? <Links links={navigation} columns={3} /> : null; }; const renderSocialMedia = () => { return socialMedia?.length ? <SocialMedia items={socialMedia} /> : null; }; const renderCopyright = () => { // 如果 copyright.owner 不存在, 则使用 brand.name, 如果 brand.name 也不存在, copyright 元素为空 const copyrightOwner = copyright?.owner || brand?.name; if (!copyrightOwner) { return null; } return <Copyright owner={copyrightOwner} year={copyright?.year || undefined} />; }; const renderLinks = () => { return links?.length ? <Links flowLayout links={links} /> : null; }; const elements = { brand: renderBrand(), navigation: renderNavigation(), socialMedia: renderSocialMedia(), copyright: renderCopyright(), links: renderLinks(), }; let LayoutComponent = null; if (layout === 'auto') { LayoutComponent = layouts.find((item) => item.support(elements, props)).component; } else { LayoutComponent = layoutsKeyByName[layout]?.component; } if (!LayoutComponent) { throw new Error(`layout ${layout} is not supported.`); } return ( <Box {...rest} className={clsx('blocklet__footer', rest.className)} sx={[ { position: 'relative', }, ...(Array.isArray(rest.sx) ? rest.sx : [rest.sx]), ]}> <LayoutComponent elements={elements} data={props} /> <Box sx={{ position: 'absolute', right: 16, bottom: 0, fontSize: 12, color: 'transparent', '::selection': { background: '#000', color: '#fff' }, }}> {window?.blocklet?.version} </Box> </Box> ); } InternalFooter.propTypes = { brand: PropTypes.shape({ name: PropTypes.node, description: PropTypes.string, logo: PropTypes.node, }), navigation: PropTypes.arrayOf( PropTypes.shape({ label: PropTypes.node, link: PropTypes.string, }) ), socialMedia: PropTypes.arrayOf( PropTypes.shape({ icon: PropTypes.node, link: PropTypes.string, }) ), copyright: PropTypes.shape({ owner: PropTypes.string, year: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), }), // privacy/legal 等链接, 常放于 footer 右下侧或最底部 links: PropTypes.arrayOf( PropTypes.shape({ label: PropTypes.node, link: PropTypes.string, }) ), // 可显式指定 footer layout, 默认根据内容自动决定 layout layout: PropTypes.oneOf(['auto', 'standard', 'plain']), }; export default InternalFooter;