Skip to content

Commit

Permalink
split footer into smaller components and various cleanups + swizzle c…
Browse files Browse the repository at this point in the history
…onfig
  • Loading branch information
slorber committed Mar 10, 2022
1 parent e97dc0d commit ac65927
Show file tree
Hide file tree
Showing 11 changed files with 307 additions and 151 deletions.
38 changes: 37 additions & 1 deletion packages/docusaurus-theme-classic/src/getSwizzleConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,47 @@ export default function getSwizzleConfig(): SwizzleConfig {
},
Footer: {
actions: {
eject: 'unsafe', // TODO split footer into smaller parts
eject: 'safe',
wrap: 'safe',
},
description: "The footer component of you site's layout",
},
'Footer/Copyright': {
actions: {
eject: 'safe',
wrap: 'safe',
},
description: 'The footer copyright',
},
'Footer/LinkItem': {
actions: {
eject: 'safe',
wrap: 'safe',
},
description: 'The footer link item component',
},
'Footer/Logo': {
actions: {
eject: 'safe',
wrap: 'safe',
},
description: 'The footer logo',
},
'Footer/MultiColumn': {
actions: {
eject: 'safe',
wrap: 'safe',
},
description: 'The footer component for the multi-column layout',
},
'Footer/Simple': {
actions: {
eject: 'safe',
wrap: 'safe',
},
description:
'The footer component for the simple layout (single link row)',
},
IconArrow: {
actions: {
eject: 'safe',
Expand Down
50 changes: 49 additions & 1 deletion packages/docusaurus-theme-classic/src/theme-classic.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ declare module '@theme/DocSidebar/Desktop/Content' {
readonly sidebar: readonly PropSidebarItem[];
}

export default function CollapseButton(props: Props): JSX.Element;
export default function Content(props: Props): JSX.Element;
}

declare module '@theme/DocSidebar/Desktop/CollapseButton' {
Expand Down Expand Up @@ -280,6 +280,54 @@ declare module '@theme/Footer' {
export default function Footer(): JSX.Element | null;
}

declare module '@theme/Footer/Logo' {
import type {FooterLogo} from '@docusaurus/theme-common';

export interface Props {
logo: FooterLogo;
}

export default function Logo(props: Props): JSX.Element;
}

declare module '@theme/Footer/Copyright' {
export interface Props {
copyright: string;
}

export default function Copyright(props: Props): JSX.Element;
}

declare module '@theme/Footer/LinkItem' {
import type {FooterLinkItem} from '@docusaurus/theme-common';

export interface Props {
item: FooterLinkItem;
}

export default function LinkItem(props: Props): JSX.Element;
}

declare module '@theme/Footer/MultiColumn' {
import type {MultiColumnFooter} from '@docusaurus/theme-common';

export interface Props {
columns: MultiColumnFooter['links'];
}

export default function MultiColumn(props: Props): JSX.Element;
}

declare module '@theme/Footer/Simple' {
import type {SimpleFooter} from '@docusaurus/theme-common';

export interface Props {
links: SimpleFooter['links'];
}

export default function Simple(props: Props): JSX.Element;
}

declare module '@theme/Heading' {
import type {ComponentProps} from 'react';

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* 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 type {Props} from '@theme/Footer/Copyright';

export default function Logo({copyright}: Props): JSX.Element {
return (
<div
className="footer__copyright"
// Developer provided the HTML, so assume it's safe.
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{
__html: copyright,
}}
/>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* 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 Link from '@docusaurus/Link';
import useBaseUrl from '@docusaurus/useBaseUrl';
import isInternalUrl from '@docusaurus/isInternalUrl';
import IconExternalLink from '@theme/IconExternalLink';
import type {Props} from '@theme/Footer/LinkItem';

export default function LinkItem({item}: Props): JSX.Element {
const {to, href, label, prependBaseUrlToHref, ...props} = item;
const toUrl = useBaseUrl(to);
const normalizedHref = useBaseUrl(href, {forcePrependBaseUrl: true});

return (
<Link
className="footer__link-item"
{...(href
? {
href: prependBaseUrlToHref ? normalizedHref : href,
}
: {
to: toUrl,
})}
{...props}>
<span>
{label}
{href && !isInternalUrl(href) && <IconExternalLink />}
</span>
</Link>
);
}
45 changes: 45 additions & 0 deletions packages/docusaurus-theme-classic/src/theme/Footer/Logo/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* 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 Link from '@docusaurus/Link';
import {useBaseUrlUtils} from '@docusaurus/useBaseUrl';
import styles from './styles.module.css';
import ThemedImage from '@theme/ThemedImage';
import type {Props} from '@theme/Footer/Logo';

function LogoImage({logo}: Props) {
const {withBaseUrl} = useBaseUrlUtils();
const sources = {
light: withBaseUrl(logo.src),
dark: withBaseUrl(logo.srcDark ?? logo.src),
};
return (
<ThemedImage
className="footer__logo"
alt={logo.alt}
sources={sources}
width={logo.width}
height={logo.height}
/>
);
}

export default function Logo({logo}: Props): JSX.Element {
return (
<div className="margin-bottom--sm">
{logo.href ? (
<Link href={logo.href} className={styles.footerLogoLink}>
<LogoImage logo={logo} />
</Link>
) : (
<LogoImage logo={logo} />
)}
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* 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 type {Props} from '@theme/Footer/MultiColumn';
import LinkItem from '@theme/Footer/LinkItem';

type ColumnType = Props['columns'][number];
type ColumnItemType = ColumnType['items'][number];

function ColumnLinkItem({item}: {item: ColumnItemType}) {
return item.html ? (
<li
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">
<LinkItem item={item} />
</li>
);
}

function Column({column}: {column: ColumnType}) {
return (
<div className="col footer__col">
<div className="footer__title">{column.title}</div>
<ul className="footer__items">
{column.items.map((item, i) => (
<ColumnLinkItem key={i} item={item} />
))}
</ul>
</div>
);
}

export default function MultiColumn({columns}: Props): JSX.Element {
return (
<div className="row footer__links">
{columns.map((column, i) => (
<Column key={i} column={column} />
))}
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* 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 type {Props} from '@theme/Footer/Simple';
import LinkItem from '@theme/Footer/LinkItem';

function Separator() {
return <span className="footer__link-separator">·</span>;
}

function SimpleLinkItem({item}: {item: Props['links'][number]}) {
return item.html ? (
<span
className="footer__link-item"
// Developer provided the HTML, so assume it's safe.
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{
__html: item.html,
}}
/>
) : (
<LinkItem item={item} />
);
}

export default function Simple({links}: Props): JSX.Element {
return (
<div className="footer__links text--center">
<div className="footer__links">
{links.map((item, i) => (
<React.Fragment key={i}>
<SimpleLinkItem item={item} />
{links.length !== i + 1 && <Separator />}
</React.Fragment>
))}
</div>
</div>
);
}
Loading

0 comments on commit ac65927

Please sign in to comment.