fix(theme): Footer Column/Link should merge provided className (#10796)

This commit is contained in:
Sébastien Lorber 2024-12-26 12:46:43 +01:00 committed by GitHub
parent e5ed9a3894
commit 37184e581d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 27 additions and 18 deletions

View file

@ -308,6 +308,7 @@ const FooterLinkItemSchema = Joi.object({
href: URISchema, href: URISchema,
html: Joi.string(), html: Joi.string(),
label: Joi.string(), label: Joi.string(),
className: Joi.string(),
}) })
.xor('to', 'href', 'html') .xor('to', 'href', 'html')
.with('to', 'label') .with('to', 'label')
@ -317,6 +318,12 @@ const FooterLinkItemSchema = Joi.object({
// attributes like target, aria-role, data-customAttribute...) // attributes like target, aria-role, data-customAttribute...)
.unknown(); .unknown();
const FooterColumnItemSchema = Joi.object({
title: Joi.string().allow(null).default(null),
className: Joi.string(),
items: Joi.array().items(FooterLinkItemSchema).default([]),
});
const LogoSchema = Joi.object({ const LogoSchema = Joi.object({
alt: Joi.string().allow(''), alt: Joi.string().allow(''),
src: Joi.string().required(), src: Joi.string().required(),
@ -384,12 +391,7 @@ export const ThemeConfigSchema = Joi.object<ThemeConfig>({
logo: LogoSchema, logo: LogoSchema,
copyright: Joi.string(), copyright: Joi.string(),
links: Joi.alternatives( links: Joi.alternatives(
Joi.array().items( Joi.array().items(FooterColumnItemSchema),
Joi.object({
title: Joi.string().allow(null).default(null),
items: Joi.array().items(FooterLinkItemSchema).default([]),
}),
),
Joi.array().items(FooterLinkItemSchema), Joi.array().items(FooterLinkItemSchema),
) )
.messages({ .messages({

View file

@ -6,7 +6,7 @@
*/ */
import React, {type ReactNode} from 'react'; import React, {type ReactNode} from 'react';
import clsx from 'clsx';
import Link from '@docusaurus/Link'; import Link from '@docusaurus/Link';
import useBaseUrl from '@docusaurus/useBaseUrl'; import useBaseUrl from '@docusaurus/useBaseUrl';
import isInternalUrl from '@docusaurus/isInternalUrl'; import isInternalUrl from '@docusaurus/isInternalUrl';
@ -14,13 +14,13 @@ import IconExternalLink from '@theme/Icon/ExternalLink';
import type {Props} from '@theme/Footer/LinkItem'; import type {Props} from '@theme/Footer/LinkItem';
export default function FooterLinkItem({item}: Props): ReactNode { export default function FooterLinkItem({item}: Props): ReactNode {
const {to, href, label, prependBaseUrlToHref, ...props} = item; const {to, href, label, prependBaseUrlToHref, className, ...props} = item;
const toUrl = useBaseUrl(to); const toUrl = useBaseUrl(to);
const normalizedHref = useBaseUrl(href, {forcePrependBaseUrl: true}); const normalizedHref = useBaseUrl(href, {forcePrependBaseUrl: true});
return ( return (
<Link <Link
className="footer__link-item" className={clsx('footer__link-item', className)}
{...(href {...(href
? { ? {
href: prependBaseUrlToHref ? normalizedHref : href, href: prependBaseUrlToHref ? normalizedHref : href,

View file

@ -6,6 +6,7 @@
*/ */
import React, {type ReactNode} from 'react'; import React, {type ReactNode} from 'react';
import clsx from 'clsx';
import LinkItem from '@theme/Footer/LinkItem'; import LinkItem from '@theme/Footer/LinkItem';
import type {Props} from '@theme/Footer/Links/MultiColumn'; import type {Props} from '@theme/Footer/Links/MultiColumn';
@ -15,7 +16,7 @@ type ColumnItemType = ColumnType['items'][number];
function ColumnLinkItem({item}: {item: ColumnItemType}) { function ColumnLinkItem({item}: {item: ColumnItemType}) {
return item.html ? ( return item.html ? (
<li <li
className="footer__item" className={clsx('footer__item', item.className)}
// Developer provided the HTML, so assume it's safe. // Developer provided the HTML, so assume it's safe.
// eslint-disable-next-line react/no-danger // eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{__html: item.html}} dangerouslySetInnerHTML={{__html: item.html}}
@ -29,7 +30,7 @@ function ColumnLinkItem({item}: {item: ColumnItemType}) {
function Column({column}: {column: ColumnType}) { function Column({column}: {column: ColumnType}) {
return ( return (
<div className="col footer__col"> <div className={clsx('col footer__col', column.className)}>
<div className="footer__title">{column.title}</div> <div className="footer__title">{column.title}</div>
<ul className="footer__items clean-list"> <ul className="footer__items clean-list">
{column.items.map((item, i) => ( {column.items.map((item, i) => (

View file

@ -6,6 +6,7 @@
*/ */
import React, {type ReactNode} from 'react'; import React, {type ReactNode} from 'react';
import clsx from 'clsx';
import LinkItem from '@theme/Footer/LinkItem'; import LinkItem from '@theme/Footer/LinkItem';
import type {Props} from '@theme/Footer/Links/Simple'; import type {Props} from '@theme/Footer/Links/Simple';
@ -16,7 +17,7 @@ function Separator() {
function SimpleLinkItem({item}: {item: Props['links'][number]}) { function SimpleLinkItem({item}: {item: Props['links'][number]}) {
return item.html ? ( return item.html ? (
<span <span
className="footer__link-item" className={clsx('footer__link-item', item.className)}
// Developer provided the HTML, so assume it's safe. // Developer provided the HTML, so assume it's safe.
// eslint-disable-next-line react/no-danger // eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{__html: item.html}} dangerouslySetInnerHTML={{__html: item.html}}

View file

@ -67,12 +67,19 @@ export type PrismConfig = {
export type FooterLinkItem = { export type FooterLinkItem = {
label?: string; label?: string;
className?: string;
to?: string; to?: string;
href?: string; href?: string;
html?: string; html?: string;
prependBaseUrlToHref?: string; prependBaseUrlToHref?: string;
} & {[key: string]: unknown}; } & {[key: string]: unknown};
export type FooterColumnItem = {
title: string | null;
className?: string;
items: FooterLinkItem[];
};
export type FooterLogo = BaseLogo; export type FooterLogo = BaseLogo;
export type FooterBase = { export type FooterBase = {
@ -82,10 +89,7 @@ export type FooterBase = {
}; };
export type MultiColumnFooter = FooterBase & { export type MultiColumnFooter = FooterBase & {
links: { links: FooterColumnItem[];
title: string | null;
items: FooterLinkItem[];
}[];
}; };
export type SimpleFooter = FooterBase & { export type SimpleFooter = FooterBase & {

View file

@ -804,11 +804,12 @@ export default async function createConfigAsync() {
}, },
{ {
title: 'Legal', title: 'Legal',
// Please don't remove the privacy and terms, it's a legal className: 'footer-column-legal',
// requirement. // Don't remove the privacy and terms, it's a legal requirement.
items: [ items: [
{ {
label: 'Privacy', label: 'Privacy',
className: 'footer-item-privacy',
href: 'https://opensource.facebook.com/legal/privacy/', href: 'https://opensource.facebook.com/legal/privacy/',
}, },
{ {