From afd730d505658649dd325e3cc5abd4362c4eb127 Mon Sep 17 00:00:00 2001 From: Lene Gadewoll Date: Fri, 12 Jul 2024 14:00:59 +0200 Subject: [PATCH 1/4] refactor: eject more required components - ensures correct provider context for sub components --- .../src/theme/DocItem/Layout/index.tsx | 6 +- .../src/theme/DocItem/index.tsx | 2 +- .../src/theme/DocRoot/Layout/Main/index.tsx | 53 ++++++ .../Layout/Sidebar/ExpandButton/index.tsx | 60 ++++++ .../theme/DocRoot/Layout/Sidebar/index.tsx | 132 +++++++++++++ .../src/theme/DocRoot/Layout/index.tsx | 42 +++++ .../src/theme/DocRoot/index.tsx | 30 +++ .../src/theme/DocVersionBadge/index.tsx | 31 +++ .../src/theme/DocVersionBanner/index.tsx | 176 ++++++++++++++++++ .../src/theme/DocVersionRoot/index.tsx | 44 +++++ .../docusaurus-theme/src/theme/theme.d.ts | 76 ++++++++ 11 files changed, 648 insertions(+), 4 deletions(-) create mode 100644 packages/docusaurus-theme/src/theme/DocRoot/Layout/Main/index.tsx create mode 100644 packages/docusaurus-theme/src/theme/DocRoot/Layout/Sidebar/ExpandButton/index.tsx create mode 100644 packages/docusaurus-theme/src/theme/DocRoot/Layout/Sidebar/index.tsx create mode 100644 packages/docusaurus-theme/src/theme/DocRoot/Layout/index.tsx create mode 100644 packages/docusaurus-theme/src/theme/DocRoot/index.tsx create mode 100644 packages/docusaurus-theme/src/theme/DocVersionBadge/index.tsx create mode 100644 packages/docusaurus-theme/src/theme/DocVersionBanner/index.tsx create mode 100644 packages/docusaurus-theme/src/theme/DocVersionRoot/index.tsx diff --git a/packages/docusaurus-theme/src/theme/DocItem/Layout/index.tsx b/packages/docusaurus-theme/src/theme/DocItem/Layout/index.tsx index 151fd4dc30f..4208e80f890 100644 --- a/packages/docusaurus-theme/src/theme/DocItem/Layout/index.tsx +++ b/packages/docusaurus-theme/src/theme/DocItem/Layout/index.tsx @@ -3,13 +3,13 @@ import { css } from '@emotion/react'; import { useWindowSize } from '@docusaurus/theme-common'; import { useDoc } from '@docusaurus/theme-common/internal'; import DocItemPaginator from '@theme-original/DocItem/Paginator'; -import DocVersionBanner from '@theme-original/DocVersionBanner'; -import DocVersionBadge from '@theme-original/DocVersionBadge'; -import DocBreadcrumbs from '@theme-original/DocBreadcrumbs'; import Unlisted from '@theme-original/Unlisted'; import * as Props from '@theme-original/DocItem/Layout'; import { EuiHorizontalRule } from '@elastic/eui'; +import DocVersionBanner from '../../DocVersionBanner'; +import DocVersionBadge from '../../DocVersionBadge'; +import DocBreadcrumbs from '../../DocBreadcrumbs'; import DocItemContent from '../Content'; import DocItemTOCMobile from '../TOC/Mobile'; import DocItemTOCDesktop from '../TOC/Desktop'; diff --git a/packages/docusaurus-theme/src/theme/DocItem/index.tsx b/packages/docusaurus-theme/src/theme/DocItem/index.tsx index 872730a0cb6..75ab19586c3 100644 --- a/packages/docusaurus-theme/src/theme/DocItem/index.tsx +++ b/packages/docusaurus-theme/src/theme/DocItem/index.tsx @@ -1,9 +1,9 @@ import React from 'react'; import { HtmlClassNameProvider } from '@docusaurus/theme-common'; import { DocProvider } from '@docusaurus/theme-common/internal'; -import DocItemMetadata from '@theme-original/DocItem/Metadata'; import type { Props } from '@theme/DocItem'; +import DocItemMetadata from './Metadata'; import DocItemLayout from './Layout'; export default function DocItem(props: Props): JSX.Element { diff --git a/packages/docusaurus-theme/src/theme/DocRoot/Layout/Main/index.tsx b/packages/docusaurus-theme/src/theme/DocRoot/Layout/Main/index.tsx new file mode 100644 index 00000000000..8dac679c8e6 --- /dev/null +++ b/packages/docusaurus-theme/src/theme/DocRoot/Layout/Main/index.tsx @@ -0,0 +1,53 @@ +import React from 'react'; +import clsx from 'clsx'; +import { css } from '@emotion/react'; +import { useDocsSidebar } from '@docusaurus/theme-common/internal'; +import type { Props } from '@theme-original/DocRoot/Layout/Main'; + +// converted from css modules to Emotion +const styles = { + docMainContainer: css` + display: flex; + width: 100%; + + @media (min-width: 997px) { + flex-grow: 1; + max-width: calc(100% - var(--doc-sidebar-width)); + } + `, + docMainContainerEnhanced: css` + @media (min-width: 997px) { + max-width: calc(100% - var(--doc-sidebar-hidden-width)); + } + `, + docItemWrapperEnhanced: css` + @media (min-width: 997px) { + max-width: calc( + var(--ifm-container-width) + var(--doc-sidebar-width) + ) !important; + } + `, +}; + +export default function DocRootLayoutMain({ + hiddenSidebarContainer, + children, +}: any): JSX.Element { + const sidebar = useDocsSidebar(); + return ( +
+
+ {children} +
+
+ ); +} diff --git a/packages/docusaurus-theme/src/theme/DocRoot/Layout/Sidebar/ExpandButton/index.tsx b/packages/docusaurus-theme/src/theme/DocRoot/Layout/Sidebar/ExpandButton/index.tsx new file mode 100644 index 00000000000..81270945087 --- /dev/null +++ b/packages/docusaurus-theme/src/theme/DocRoot/Layout/Sidebar/ExpandButton/index.tsx @@ -0,0 +1,60 @@ +import React from 'react'; +import { css } from '@emotion/react'; +import { translate } from '@docusaurus/Translate'; +import IconArrow from '@theme-original/Icon/Arrow'; + +import type { Props } from '@theme-original/DocRoot/Layout/Sidebar/ExpandButton'; + +// converted from css modules to Emotion +const styles = { + expandButton: css` + @media (min-width: 997px) { + position: absolute; + top: 0; + right: 0; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + transition: background-color var(--ifm-transition-fast) ease; + background-color: var(--docusaurus-collapse-button-bg); + + &:hover, + &:focus { + background-color: var(--docusaurus-collapse-button-bg-hover); + } + } + `, + expandButtonIcon: css` + transform: rotate(0); + `, +}; + +export default function DocRootLayoutSidebarExpandButton({ + toggleSidebar, +}: Props): JSX.Element { + return ( +
+ +
+ ); +} diff --git a/packages/docusaurus-theme/src/theme/DocRoot/Layout/Sidebar/index.tsx b/packages/docusaurus-theme/src/theme/DocRoot/Layout/Sidebar/index.tsx new file mode 100644 index 00000000000..f033caa595e --- /dev/null +++ b/packages/docusaurus-theme/src/theme/DocRoot/Layout/Sidebar/index.tsx @@ -0,0 +1,132 @@ +import React, { type ReactNode, useState, useCallback } from 'react'; +import clsx from 'clsx'; +import { css } from '@emotion/react'; +import { + prefersReducedMotion, + ThemeClassNames, +} from '@docusaurus/theme-common'; +import { useDocsSidebar } from '@docusaurus/theme-common/internal'; +import { useLocation } from '@docusaurus/router'; +import DocSidebar from '@theme-original/DocSidebar'; +import type { Props } from '@theme-original/DocRoot/Layout/Sidebar'; +import { useEuiMemoizedStyles, UseEuiTheme } from '@elastic/eui'; + +import ExpandButton from './ExpandButton'; + +const getGlobalStyles = ({ euiTheme }: UseEuiTheme) => { + return { + sidebar: css` + --doc-sidebar-width: 258px; + --doc-sidebar-hidden-width: 30px; + + // ensure scrolling still works + display: flex; + + .theme-doc-sidebar-menu.menu__list { + padding: 0 ${euiTheme.size.s}; + } + `, + }; +}; + +// converted from css moduels to Emotion +const styles = { + docSidebarContainer: css` + display: none; + + @media (min-width: 997px) { + display: block; + width: var(--doc-sidebar-width); + margin-top: calc(-1 * var(--ifm-navbar-height)); + border-right: 1px solid var(--ifm-toc-border-color); + will-change: width; + transition: width var(--ifm-transition-fast) ease; + clip-path: inset(0); + } + `, + docSidebarContainerHidden: css` + width: var(--doc-sidebar-hidden-width); + cursor: pointer; + `, + sidebarViewport: css` + top: 0; + position: sticky; + height: 100%; + max-height: 100vh; + `, +}; + +// Reset sidebar state when sidebar changes +// Use React key to unmount/remount the children +// See https://github.com/facebook/docusaurus/issues/3414 +function ResetOnSidebarChange({ children }: { children: ReactNode }) { + const sidebar = useDocsSidebar(); + return ( + + {children} + + ); +} + +export default function DocRootLayoutSidebar({ + sidebar, + hiddenSidebarContainer, + setHiddenSidebarContainer, +}: Props): JSX.Element { + const { pathname } = useLocation(); + const globalStyles = useEuiMemoizedStyles(getGlobalStyles); + + const [hiddenSidebar, setHiddenSidebar] = useState(false); + const toggleSidebar = useCallback(() => { + if (hiddenSidebar) { + setHiddenSidebar(false); + } + // onTransitionEnd won't fire when sidebar animation is disabled + // fixes https://github.com/facebook/docusaurus/issues/8918 + if (!hiddenSidebar && prefersReducedMotion()) { + setHiddenSidebar(true); + } + setHiddenSidebarContainer((value) => !value); + }, [setHiddenSidebarContainer, hiddenSidebar]); + + return ( + + ); +} diff --git a/packages/docusaurus-theme/src/theme/DocRoot/Layout/index.tsx b/packages/docusaurus-theme/src/theme/DocRoot/Layout/index.tsx new file mode 100644 index 00000000000..c8d19f2d86d --- /dev/null +++ b/packages/docusaurus-theme/src/theme/DocRoot/Layout/index.tsx @@ -0,0 +1,42 @@ +import React, { useState } from 'react'; +import { css } from '@emotion/react'; +import { useDocsSidebar } from '@docusaurus/theme-common/internal'; +import BackToTopButton from '@theme-original/BackToTopButton'; +import type { Props } from '@theme-original/DocRoot/Layout'; + +import DocRootLayoutSidebar from './Sidebar'; +import DocRootLayoutMain from './Main'; + +// converted from css modules to Emotion +const styles = { + docRoot: css` + display: flex; + width: 100%; + `, + docsWrapper: css` + display: flex; + flex: 1 0 auto; + `, +}; + +export default function DocRootLayout({ children }: Props): JSX.Element { + const sidebar = useDocsSidebar(); + const [hiddenSidebarContainer, setHiddenSidebarContainer] = useState(false); + return ( +
+ +
+ {sidebar && ( + + )} + + {children} + +
+
+ ); +} diff --git a/packages/docusaurus-theme/src/theme/DocRoot/index.tsx b/packages/docusaurus-theme/src/theme/DocRoot/index.tsx new file mode 100644 index 00000000000..8dc4bb394b5 --- /dev/null +++ b/packages/docusaurus-theme/src/theme/DocRoot/index.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import clsx from 'clsx'; +import { + HtmlClassNameProvider, + ThemeClassNames, +} from '@docusaurus/theme-common'; +import { + DocsSidebarProvider, + useDocRootMetadata, +} from '@docusaurus/theme-common/internal'; +import DocRootLayout from '@theme-original/DocRoot/Layout'; +import NotFoundContent from '@theme-original/NotFound/Content'; +import type { Props } from '@theme-original/DocRoot'; + +export default function DocRoot(props: Props): JSX.Element { + const currentDocRouteMetadata = useDocRootMetadata(props); + if (!currentDocRouteMetadata) { + // We only render the not found content to avoid a double layout + // see https://github.com/facebook/docusaurus/pull/7966#pullrequestreview-1077276692 + return ; + } + const { docElement, sidebarName, sidebarItems } = currentDocRouteMetadata; + return ( + + + {docElement} + + + ); +} diff --git a/packages/docusaurus-theme/src/theme/DocVersionBadge/index.tsx b/packages/docusaurus-theme/src/theme/DocVersionBadge/index.tsx new file mode 100644 index 00000000000..26c64bb9e13 --- /dev/null +++ b/packages/docusaurus-theme/src/theme/DocVersionBadge/index.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import clsx from 'clsx'; +import Translate from '@docusaurus/Translate'; +import { ThemeClassNames } from '@docusaurus/theme-common'; +import { useDocsVersion } from '@docusaurus/theme-common/internal'; +import type { Props } from '@theme-original/DocVersionBadge'; + +export default function DocVersionBadge({ + className, +}: Props): JSX.Element | null { + const versionMetadata = useDocsVersion(); + if (versionMetadata.badge) { + return ( + + + {'Version: {versionLabel}'} + + + ); + } + return null; +} diff --git a/packages/docusaurus-theme/src/theme/DocVersionBanner/index.tsx b/packages/docusaurus-theme/src/theme/DocVersionBanner/index.tsx new file mode 100644 index 00000000000..f876a12c7b2 --- /dev/null +++ b/packages/docusaurus-theme/src/theme/DocVersionBanner/index.tsx @@ -0,0 +1,176 @@ +import React, { type ComponentType } from 'react'; +import clsx from 'clsx'; +import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; +import Link from '@docusaurus/Link'; +import Translate from '@docusaurus/Translate'; +import { + useActivePlugin, + useDocVersionSuggestions, + type GlobalVersion, +} from '@docusaurus/plugin-content-docs/client'; +import { ThemeClassNames } from '@docusaurus/theme-common'; +import { + useDocsPreferredVersion, + useDocsVersion, +} from '@docusaurus/theme-common/internal'; +import type { Props } from '@theme-original/DocVersionBanner'; +import type { + VersionBanner, + PropVersionMetadata, +} from '@docusaurus/plugin-content-docs'; + +type BannerLabelComponentProps = { + siteTitle: string; + versionMetadata: PropVersionMetadata; +}; + +function UnreleasedVersionLabel({ + siteTitle, + versionMetadata, +}: BannerLabelComponentProps) { + return ( + {versionMetadata.label}, + }} + > + { + 'This is unreleased documentation for {siteTitle} {versionLabel} version.' + } + + ); +} + +function UnmaintainedVersionLabel({ + siteTitle, + versionMetadata, +}: BannerLabelComponentProps) { + return ( + {versionMetadata.label}, + }} + > + { + 'This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.' + } + + ); +} + +const BannerLabelComponents: { + [banner in VersionBanner]: ComponentType; +} = { + unreleased: UnreleasedVersionLabel, + unmaintained: UnmaintainedVersionLabel, +}; + +function BannerLabel(props: BannerLabelComponentProps) { + const BannerLabelComponent = + BannerLabelComponents[props.versionMetadata.banner!]; + return ; +} + +function LatestVersionSuggestionLabel({ + versionLabel, + to, + onClick, +}: { + to: string; + onClick: () => void; + versionLabel: string; +}) { + return ( + + + + latest version + + + + ), + }} + > + { + 'For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).' + } + + ); +} + +function DocVersionBannerEnabled({ + className, + versionMetadata, +}: Props & { + versionMetadata: PropVersionMetadata; +}): JSX.Element { + const { + siteConfig: { title: siteTitle }, + } = useDocusaurusContext(); + const { pluginId } = useActivePlugin({ failfast: true })!; + + const getVersionMainDoc = (version: GlobalVersion) => + version.docs.find((doc) => doc.id === version.mainDocId)!; + + const { savePreferredVersionName } = useDocsPreferredVersion(pluginId); + + const { latestDocSuggestion, latestVersionSuggestion } = + useDocVersionSuggestions(pluginId); + + // Try to link to same doc in latest version (not always possible), falling + // back to main doc of latest version + const latestVersionSuggestedDoc = + latestDocSuggestion ?? getVersionMainDoc(latestVersionSuggestion); + + return ( +
+
+ +
+
+ savePreferredVersionName(latestVersionSuggestion.name)} + /> +
+
+ ); +} + +export default function DocVersionBanner({ + className, +}: Props): JSX.Element | null { + const versionMetadata = useDocsVersion(); + if (versionMetadata.banner) { + return ( + + ); + } + return null; +} diff --git a/packages/docusaurus-theme/src/theme/DocVersionRoot/index.tsx b/packages/docusaurus-theme/src/theme/DocVersionRoot/index.tsx new file mode 100644 index 00000000000..fcb2a6f7b5f --- /dev/null +++ b/packages/docusaurus-theme/src/theme/DocVersionRoot/index.tsx @@ -0,0 +1,44 @@ +import React from 'react'; +import { HtmlClassNameProvider, PageMetadata } from '@docusaurus/theme-common'; +import { + docVersionSearchTag, + DocsVersionProvider, +} from '@docusaurus/theme-common/internal'; +import renderRoutes from '@docusaurus/renderRoutes'; +import SearchMetadata from '@theme-original/SearchMetadata'; + +import type { Props } from '@theme-original/DocVersionRoot'; + +function DocVersionRootMetadata(props: any): JSX.Element { + const { version } = props; + return ( + <> + + + {version.noIndex && } + + + ); +} + +function DocVersionRootContent(props: any): JSX.Element { + const { version, route } = props; + return ( + + + {renderRoutes(route.routes!)} + + + ); +} +export default function DocVersionRoot(props: any): JSX.Element { + return ( + <> + + + + ); +} diff --git a/packages/docusaurus-theme/src/theme/theme.d.ts b/packages/docusaurus-theme/src/theme/theme.d.ts index dbc0c6d4142..75fb2339187 100644 --- a/packages/docusaurus-theme/src/theme/theme.d.ts +++ b/packages/docusaurus-theme/src/theme/theme.d.ts @@ -4,6 +4,82 @@ // NOTE: when using swizzle --wrap there is the approach to do the following: // type Props = WrapperProps but it will result in `any` type +// original: https://github.com/facebook/docusaurus/blob/8b877d27d4b1bcd5c2ee13dde8332407a1c26447/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts#L635 +declare module '@theme-original/DocRoot' { + import type { RouteConfigComponentProps } from 'react-router-config'; + import type { Required } from 'utility-types'; + + export interface Props extends Required {} + + export default function DocRoot(props: Props): JSX.Element; +} + +// original: https://github.com/facebook/docusaurus/blob/8b877d27d4b1bcd5c2ee13dde8332407a1c26447/packages/docusaurus-theme-classic/src/theme-classic.d.ts#L510 +declare module '@theme-original/DocRoot/Layout' { + import type { ReactNode } from 'react'; + + export interface Props { + readonly children: ReactNode; + } + + export default function DocRootLayout(props: Props): JSX.Element; +} + +// original: https://github.com/facebook/docusaurus/blob/8b877d27d4b1bcd5c2ee13dde8332407a1c26447/packages/docusaurus-theme-classic/src/theme-classic.d.ts#L543 +declare module '@theme-original/DocRoot/Layout/Main' { + import type { ReactNode } from 'react'; + + export interface Props { + readonly hiddenSidebarContainer: boolean; + readonly children: ReactNode; + } + + export default function DocRootLayoutMain(props: Props): JSX.Element; +} + +// original: https://github.com/facebook/docusaurus/blob/8b877d27d4b1bcd5c2ee13dde8332407a1c26447/packages/docusaurus-theme-classic/src/theme-classic.d.ts#L520 +declare module '@theme-original/DocRoot/Layout/Sidebar' { + import type { Dispatch, SetStateAction } from 'react'; + import type { PropSidebar } from '@docusaurus/plugin-content-docs'; + + export interface Props { + readonly sidebar: PropSidebar; + readonly hiddenSidebarContainer: boolean; + readonly setHiddenSidebarContainer: Dispatch>; + } + + export default function DocRootLayoutSidebar(props: Props): JSX.Element; +} + +// original: https://github.com/facebook/docusaurus/blob/8b877d27d4b1bcd5c2ee13dde8332407a1c26447/packages/docusaurus-theme-classic/src/theme-classic.d.ts#L533 +declare module '@theme-original/DocRoot/Layout/Sidebar/ExpandButton' { + export interface Props { + toggleSidebar: () => void; + } + + export default function DocRootLayoutSidebarExpandButton( + props: Props + ): JSX.Element; +} + +// original" https://github.com/facebook/docusaurus/blob/8b877d27d4b1bcd5c2ee13dde8332407a1c26447/packages/docusaurus-theme-classic/src/theme-classic.d.ts#L672 +declare module '@theme-original/DocVersionBanner' { + export interface Props { + readonly className?: string; + } + + export default function DocVersionBanner(props: Props): JSX.Element; +} + +// original: https://github.com/facebook/docusaurus/blob/8b877d27d4b1bcd5c2ee13dde8332407a1c26447/packages/docusaurus-theme-classic/src/theme-classic.d.ts#L680 +declare module '@theme-original/DocVersionBadge' { + export interface Props { + readonly className?: string; + } + + export default function DocVersionBadge(props: Props): JSX.Element; +} + // original: https://github.com/facebook/docusaurus/blob/d2bb74a8fd4ee92fc7ff806657dbb35de1de845f/packages/docusaurus-theme-classic/src/theme-classic.d.ts#L560 declare module '@theme-original/DocItem/Content' { export interface Props { From 3803294291950f59d97893307dcc6e18737e984d Mon Sep 17 00:00:00 2001 From: Lene Gadewoll Date: Fri, 12 Jul 2024 14:03:32 +0200 Subject: [PATCH 2/4] feat: update Breadcrumbs styles --- .../theme/DocBreadcrumbs/Items/Home/index.tsx | 31 ++++ .../theme/DocBreadcrumbs/Items/item.styles.ts | 39 +++++ .../src/theme/DocBreadcrumbs/index.tsx | 133 ++++++++++++++++++ 3 files changed, 203 insertions(+) create mode 100644 packages/docusaurus-theme/src/theme/DocBreadcrumbs/Items/Home/index.tsx create mode 100644 packages/docusaurus-theme/src/theme/DocBreadcrumbs/Items/item.styles.ts create mode 100644 packages/docusaurus-theme/src/theme/DocBreadcrumbs/index.tsx diff --git a/packages/docusaurus-theme/src/theme/DocBreadcrumbs/Items/Home/index.tsx b/packages/docusaurus-theme/src/theme/DocBreadcrumbs/Items/Home/index.tsx new file mode 100644 index 00000000000..580ea2ba32e --- /dev/null +++ b/packages/docusaurus-theme/src/theme/DocBreadcrumbs/Items/Home/index.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import { css } from '@emotion/react'; +import Link from '@docusaurus/Link'; +import useBaseUrl from '@docusaurus/useBaseUrl'; +import { translate } from '@docusaurus/Translate'; +import { EuiIcon, useEuiMemoizedStyles } from '@elastic/eui'; + +import { getItemStyles } from '../item.styles'; + +export default function HomeBreadcrumbItem(): JSX.Element { + const homeHref = useBaseUrl('/'); + + const styles = useEuiMemoizedStyles(getItemStyles); + + return ( +
  • + + EUI+ + + +
  • + ); +} diff --git a/packages/docusaurus-theme/src/theme/DocBreadcrumbs/Items/item.styles.ts b/packages/docusaurus-theme/src/theme/DocBreadcrumbs/Items/item.styles.ts new file mode 100644 index 00000000000..d184853b6c3 --- /dev/null +++ b/packages/docusaurus-theme/src/theme/DocBreadcrumbs/Items/item.styles.ts @@ -0,0 +1,39 @@ +import { css } from '@emotion/react'; +import { UseEuiTheme } from '@elastic/eui'; + +export const getItemStyles = ({ euiTheme }: UseEuiTheme) => ({ + item: css` + --ifm-breadcrumb-item-background: transparent; + --ifm-breadcrumb-item-background-active: transparent; + + // overwrite global styles + &.breadcrumbs__item:not(:last-child):after { + content: none; + } + + .breadcrumbs__link { + padding: 0 ${euiTheme.size.m}; + font-size: var(--eui-font-size-xs); + line-height: var(--eui-line-height-m); + } + + &.breadcrumbs__item:first-child .breadcrumbs__link { + padding-inline-start: 0; + } + + a.breadcrumbs__link { + color: ${euiTheme.colors.link}; + font-weight: ${euiTheme.font.weight.bold}; + text-decoration: underline; + } + + &.breadcrumbs__item--active .breadcrumbs__link { + color: ${euiTheme.colors.text}; + } + `, + icon: css` + block-size: ${euiTheme.size.s}; + inline-size: ${euiTheme.size.s}; + fill: ${euiTheme.colors.text}; + `, +}); diff --git a/packages/docusaurus-theme/src/theme/DocBreadcrumbs/index.tsx b/packages/docusaurus-theme/src/theme/DocBreadcrumbs/index.tsx new file mode 100644 index 00000000000..cf02b8e00e3 --- /dev/null +++ b/packages/docusaurus-theme/src/theme/DocBreadcrumbs/index.tsx @@ -0,0 +1,133 @@ +import React, { type ReactNode } from 'react'; +import clsx from 'clsx'; +import { css } from '@emotion/react'; +import { ThemeClassNames } from '@docusaurus/theme-common'; +import { + useSidebarBreadcrumbs, + useHomePageRoute, +} from '@docusaurus/theme-common/internal'; +import Link from '@docusaurus/Link'; +import { translate } from '@docusaurus/Translate'; +import { EuiIcon, useEuiMemoizedStyles, UseEuiTheme } from '@elastic/eui'; + +import HomeBreadcrumbItem from './Items/Home'; +import { getItemStyles } from './Items/item.styles'; + +// converted from css modules to Emotion +const styles = { + breadcrumbsContainer: css` + --ifm-breadcrumb-size-multiplier: 0.8; + `, +}; + +// TODO move to design system folder +function BreadcrumbsItemLink({ + children, + href, + isLast, +}: { + children: ReactNode; + href: string | undefined; + isLast: boolean; +}): JSX.Element { + const className = 'breadcrumbs__link'; + if (isLast) { + return ( + + {children} + + ); + } + return href ? ( + + {children} + + ) : ( + // TODO Google search console doesn't like breadcrumb items without href. + // The schema doesn't seem to require `id` for each `item`, although Google + // insist to infer one, even if it's invalid. Removing `itemProp="item + // name"` for now, since I don't know how to properly fix it. + // See https://github.com/facebook/docusaurus/issues/7241 + {children} + ); +} + +function BreadcrumbsItem({ + children, + active, + index, + addMicrodata, +}: { + children: ReactNode; + active?: boolean; + index: number; + addMicrodata: boolean; +}): JSX.Element { + const styles = useEuiMemoizedStyles(getItemStyles); + + return ( +
  • + {children} + + {!active && } +
  • + ); +} + +export default function DocBreadcrumbs(): JSX.Element | null { + const breadcrumbs = useSidebarBreadcrumbs(); + const homePageRoute = useHomePageRoute(); + + if (!breadcrumbs) { + return null; + } + + return ( + + ); +} From e827a4f5f41a4cee42619f8e0beab97b9c08ea7b Mon Sep 17 00:00:00 2001 From: Lene Gadewoll Date: Fri, 12 Jul 2024 14:28:13 +0200 Subject: [PATCH 3/4] refactor: improve breadcrumb alignment and positioning --- .../src/theme/DocBreadcrumbs/Items/item.styles.ts | 4 ---- .../docusaurus-theme/src/theme/DocBreadcrumbs/index.tsx | 9 +++++++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/docusaurus-theme/src/theme/DocBreadcrumbs/Items/item.styles.ts b/packages/docusaurus-theme/src/theme/DocBreadcrumbs/Items/item.styles.ts index d184853b6c3..c07cce2cd30 100644 --- a/packages/docusaurus-theme/src/theme/DocBreadcrumbs/Items/item.styles.ts +++ b/packages/docusaurus-theme/src/theme/DocBreadcrumbs/Items/item.styles.ts @@ -17,10 +17,6 @@ export const getItemStyles = ({ euiTheme }: UseEuiTheme) => ({ line-height: var(--eui-line-height-m); } - &.breadcrumbs__item:first-child .breadcrumbs__link { - padding-inline-start: 0; - } - a.breadcrumbs__link { color: ${euiTheme.colors.link}; font-weight: ${euiTheme.font.weight.bold}; diff --git a/packages/docusaurus-theme/src/theme/DocBreadcrumbs/index.tsx b/packages/docusaurus-theme/src/theme/DocBreadcrumbs/index.tsx index cf02b8e00e3..20cb18b1940 100644 --- a/packages/docusaurus-theme/src/theme/DocBreadcrumbs/index.tsx +++ b/packages/docusaurus-theme/src/theme/DocBreadcrumbs/index.tsx @@ -14,11 +14,14 @@ import HomeBreadcrumbItem from './Items/Home'; import { getItemStyles } from './Items/item.styles'; // converted from css modules to Emotion -const styles = { +const getStyles = ({ euiTheme }: UseEuiTheme) => ({ breadcrumbsContainer: css` --ifm-breadcrumb-size-multiplier: 0.8; + + // align breadcrumb items with content + margin-inline-start: -${euiTheme.size.m}; `, -}; +}); // TODO move to design system folder function BreadcrumbsItemLink({ @@ -88,6 +91,8 @@ export default function DocBreadcrumbs(): JSX.Element | null { const breadcrumbs = useSidebarBreadcrumbs(); const homePageRoute = useHomePageRoute(); + const styles = useEuiMemoizedStyles(getStyles); + if (!breadcrumbs) { return null; } From eaa14395eebbb6293977364c25d55d49d826a462 Mon Sep 17 00:00:00 2001 From: Lene Gadewoll Date: Tue, 16 Jul 2024 09:37:08 +0200 Subject: [PATCH 4/4] chore: cleanup --- .../src/theme/DocBreadcrumbs/Items/Home/index.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/docusaurus-theme/src/theme/DocBreadcrumbs/Items/Home/index.tsx b/packages/docusaurus-theme/src/theme/DocBreadcrumbs/Items/Home/index.tsx index 580ea2ba32e..22340929e7e 100644 --- a/packages/docusaurus-theme/src/theme/DocBreadcrumbs/Items/Home/index.tsx +++ b/packages/docusaurus-theme/src/theme/DocBreadcrumbs/Items/Home/index.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import { css } from '@emotion/react'; import Link from '@docusaurus/Link'; import useBaseUrl from '@docusaurus/useBaseUrl'; import { translate } from '@docusaurus/Translate'; @@ -23,7 +22,7 @@ export default function HomeBreadcrumbItem(): JSX.Element { className="breadcrumbs__link" href={homeHref} > - EUI+ + EUI