mirror of
https://github.com/facebook/docusaurus.git
synced 2025-12-26 01:33:02 +00:00
204 lines
5.3 KiB
TypeScript
204 lines
5.3 KiB
TypeScript
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
import React from 'react';
|
|
import clsx from 'clsx';
|
|
|
|
import Link from '@docusaurus/Link';
|
|
import {
|
|
type FooterLinkItem,
|
|
useThemeConfig,
|
|
type MultiColumnFooter,
|
|
type SimpleFooter,
|
|
} from '@docusaurus/theme-common';
|
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
|
import isInternalUrl from '@docusaurus/isInternalUrl';
|
|
import styles from './styles.module.css';
|
|
import ThemedImage, {type Props as ThemedImageProps} from '@theme/ThemedImage';
|
|
import IconExternalLink from '@theme/IconExternalLink';
|
|
|
|
function FooterLink({
|
|
to,
|
|
href,
|
|
label,
|
|
prependBaseUrlToHref,
|
|
...props
|
|
}: FooterLinkItem) {
|
|
const toUrl = useBaseUrl(to);
|
|
const normalizedHref = useBaseUrl(href, {forcePrependBaseUrl: true});
|
|
|
|
return (
|
|
<Link
|
|
className="footer__link-item"
|
|
{...(href
|
|
? {
|
|
href: prependBaseUrlToHref ? normalizedHref : href,
|
|
}
|
|
: {
|
|
to: toUrl,
|
|
})}
|
|
{...props}>
|
|
{href && !isInternalUrl(href) ? (
|
|
<span>
|
|
{label}
|
|
<IconExternalLink />
|
|
</span>
|
|
) : (
|
|
label
|
|
)}
|
|
</Link>
|
|
);
|
|
}
|
|
|
|
function FooterLogo({
|
|
sources,
|
|
alt,
|
|
width,
|
|
height,
|
|
}: Pick<ThemedImageProps, 'sources' | 'alt' | 'width' | 'height'>) {
|
|
return (
|
|
<ThemedImage
|
|
className="footer__logo"
|
|
alt={alt}
|
|
sources={sources}
|
|
width={width}
|
|
height={height}
|
|
/>
|
|
);
|
|
}
|
|
|
|
function MultiColumnLinks({links}: {links: MultiColumnFooter['links']}) {
|
|
return (
|
|
<>
|
|
{links.map((linkItem, i) => (
|
|
<div key={i} className="col footer__col">
|
|
<div className="footer__title">{linkItem.title}</div>
|
|
<ul className="footer__items">
|
|
{linkItem.items.map((item, key) =>
|
|
item.html ? (
|
|
<li
|
|
key={key}
|
|
className="footer__item"
|
|
// Developer provided the HTML, so assume it's safe.
|
|
// eslint-disable-next-line react/no-danger
|
|
dangerouslySetInnerHTML={{
|
|
__html: item.html,
|
|
}}
|
|
/>
|
|
) : (
|
|
<li key={item.href || item.to} className="footer__item">
|
|
<FooterLink {...item} />
|
|
</li>
|
|
),
|
|
)}
|
|
</ul>
|
|
</div>
|
|
))}
|
|
</>
|
|
);
|
|
}
|
|
|
|
function SimpleLinks({links}: {links: SimpleFooter['links']}) {
|
|
return (
|
|
<div className="footer__links">
|
|
{links.map((item, key) => (
|
|
<>
|
|
{item.html ? (
|
|
<span
|
|
key={key}
|
|
className="footer__link-item"
|
|
// Developer provided the HTML, so assume it's safe.
|
|
// eslint-disable-next-line react/no-danger
|
|
dangerouslySetInnerHTML={{
|
|
__html: item.html,
|
|
}}
|
|
/>
|
|
) : (
|
|
<FooterLink {...item} />
|
|
)}
|
|
{links.length !== key + 1 && (
|
|
<span className="footer__link-separator">·</span>
|
|
)}
|
|
</>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function isMultiColumnFooterLinks(
|
|
links: MultiColumnFooter['links'] | SimpleFooter['links'],
|
|
): links is MultiColumnFooter['links'] {
|
|
return 'title' in links[0];
|
|
}
|
|
|
|
function Footer(): JSX.Element | null {
|
|
const {footer} = useThemeConfig();
|
|
|
|
const {copyright, links = [], logo = {}} = footer || {};
|
|
const sources = {
|
|
light: useBaseUrl(logo.src),
|
|
dark: useBaseUrl(logo.srcDark || logo.src),
|
|
};
|
|
|
|
if (!footer) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<footer
|
|
className={clsx('footer', {
|
|
'footer--dark': footer.style === 'dark',
|
|
})}>
|
|
<div className="container container-fluid">
|
|
{links &&
|
|
links.length > 0 &&
|
|
(isMultiColumnFooterLinks(links) ? (
|
|
<div className="row footer__links">
|
|
<MultiColumnLinks links={links} />
|
|
</div>
|
|
) : (
|
|
<div className="footer__links text--center">
|
|
<SimpleLinks links={links} />
|
|
</div>
|
|
))}
|
|
{(logo || copyright) && (
|
|
<div className="footer__bottom text--center">
|
|
{logo && (logo.src || logo.srcDark) && (
|
|
<div className="margin-bottom--sm">
|
|
{logo.href ? (
|
|
<Link href={logo.href} className={styles.footerLogoLink}>
|
|
<FooterLogo
|
|
alt={logo.alt}
|
|
sources={sources}
|
|
width={logo.width}
|
|
height={logo.height}
|
|
/>
|
|
</Link>
|
|
) : (
|
|
<FooterLogo alt={logo.alt} sources={sources} />
|
|
)}
|
|
</div>
|
|
)}
|
|
{copyright ? (
|
|
<div
|
|
className="footer__copyright"
|
|
// Developer provided the HTML, so assume it's safe.
|
|
// eslint-disable-next-line react/no-danger
|
|
dangerouslySetInnerHTML={{
|
|
__html: copyright,
|
|
}}
|
|
/>
|
|
) : null}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</footer>
|
|
);
|
|
}
|
|
|
|
export default React.memo(Footer);
|