Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(blog): group sidebar items by year (themeConfig.blog.sidebar.groupByYear) #10252

Merged
merged 12 commits into from
Jun 28, 2024
Prev Previous commit
Next Next commit
polish and factorize theme
  • Loading branch information
slorber committed Jun 28, 2024
commit 57911bf7ece4815c20633c30d5c0e8dadd17fe6d
13 changes: 13 additions & 0 deletions packages/docusaurus-theme-classic/src/theme-classic.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,19 @@ declare module '@theme/BlogListPaginator' {
export default function BlogListPaginator(props: Props): JSX.Element;
}

declare module '@theme/BlogSidebar/Content' {
import type {ReactNode, ComponentType} from 'react';
import type {BlogSidebarItem} from '@docusaurus/plugin-content-blog';

export interface Props {
readonly items: BlogSidebarItem[];
readonly ListComponent: ComponentType<{items: BlogSidebarItem[]}>;
readonly yearGroupHeadingClassName?: string;
}

export default function BlogSidebarYearGroup(props: Props): ReactNode;
}

declare module '@theme/BlogSidebar/Desktop' {
import type {BlogSidebar} from '@docusaurus/plugin-content-blog';

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
* 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, {type ReactNode} from 'react';
import {groupBlogSidebarItemsByYear} from '@docusaurus/theme-common/internal';
import Heading from '@theme/Heading';
import type {Props} from '@theme/BlogSidebar/Content';

function BlogSidebarYearGroup({
year,
yearGroupHeadingClassName,
children,
}: {
year: string;
yearGroupHeadingClassName?: string;

children: ReactNode;
}) {
return (
<div role="group">
<Heading as="h3" className={yearGroupHeadingClassName}>
{year}
</Heading>
{children}
</div>
);
}

export default function BlogSidebarContent({
items,
yearGroupHeadingClassName,
ListComponent,
}: Props): ReactNode {
const groupByYear = true; // TODO wire appropriate config here

if (groupByYear) {
const itemsByYear = groupBlogSidebarItemsByYear(items);
return (
<>
{itemsByYear.map(([year, yearItems]) => (
<BlogSidebarYearGroup
key={year}
year={year}
yearGroupHeadingClassName={yearGroupHeadingClassName}>
<ListComponent items={yearItems} />
</BlogSidebarYearGroup>
))}
</>
);
} else {
return <ListComponent items={items} />;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,19 @@ import clsx from 'clsx';
import {translate} from '@docusaurus/Translate';
import {
useVisibleBlogSidebarItems,
groupBlogSidebarItemsByYear,
BlogSidebarItemList,
} from '@docusaurus/theme-common/internal';
import Heading from '@theme/Heading';
import type {
Props as BlogSidebarContentProps,
} from '@theme/BlogSidebar/Content';
import BlogSidebarContent from '@theme/BlogSidebar/Content';

import type {Props} from '@theme/BlogSidebar/Desktop';
import type {BlogSidebarItem} from '@docusaurus/plugin-content-blog';

import styles from './styles.module.css';

function BlogSidebarItemListDesktop({
year,
items,
}: {
year?: string;
items: BlogSidebarItem[];
}) {
const list = (
const ListComponent: BlogSidebarContentProps['ListComponent'] = ({items}) => {
return (
<BlogSidebarItemList
items={items}
ulClassName={clsx(styles.sidebarItemList, 'clean-list')}
Expand All @@ -36,39 +31,7 @@ function BlogSidebarItemListDesktop({
linkActiveClassName={styles.sidebarItemLinkActive}
/>
);

if (typeof year === 'undefined') {
return list;
}
return (
<div role="group">
<Heading as="h3" className={styles.sidebarItemYearSeparator}>
{year}
</Heading>
{list}
</div>
);
}

function BlogSidebarItems({items}: {items: BlogSidebarItem[]}) {
const groupByYear = true; // TODO wire appropriate config here
if (groupByYear) {
const itemsByYear = groupBlogSidebarItemsByYear(items);
return (
<>
{itemsByYear.map(([year, yearItems]) => (
<BlogSidebarItemListDesktop
key={year}
year={year}
items={yearItems}
/>
))}
</>
);
} else {
return <BlogSidebarItemListDesktop items={items} />;
}
}
};

function BlogSidebarDesktop({sidebar}: Props) {
const items = useVisibleBlogSidebarItems(sidebar.items);
Expand All @@ -84,7 +47,11 @@ function BlogSidebarDesktop({sidebar}: Props) {
<div className={clsx(styles.sidebarItemTitle, 'margin-bottom--md')}>
{sidebar.title}
</div>
<BlogSidebarItems items={items} />
<BlogSidebarContent
items={items}
ListComponent={ListComponent}
yearGroupHeadingClassName={styles.yearGroupHeading}
/>
</nav>
</aside>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
}
}

.sidebarItemYearSeparator {
.yearGroupHeading {
margin-top: 1.6rem;
margin-bottom: 0.4rem;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,39 @@
*/

import React from 'react';
import Link from '@docusaurus/Link';
import {useVisibleBlogSidebarItems} from '@docusaurus/theme-common/internal';
import {
useVisibleBlogSidebarItems,
BlogSidebarItemList,
} from '@docusaurus/theme-common/internal';
import {NavbarSecondaryMenuFiller} from '@docusaurus/theme-common';
import type {Props} from '@theme/BlogSidebar/Mobile';
import type {
Props as BlogSidebarContentProps,
} from '@theme/BlogSidebar/Content';
import BlogSidebarContent from '@theme/BlogSidebar/Content';

import styles from './styles.module.css';

const ListComponent: BlogSidebarContentProps['ListComponent'] = ({items}) => {
return (
<BlogSidebarItemList
items={items}
ulClassName="menu__list"
liClassName="menu__list-item"
linkClassName="menu__link"
linkActiveClassName="menu__link--active"
/>
);
};

function BlogSidebarMobileSecondaryMenu({sidebar}: Props): JSX.Element {
const items = useVisibleBlogSidebarItems(sidebar.items);
return (
<ul className="menu__list">
{items.map((item) => (
<li key={item.permalink} className="menu__list-item">
<Link
isNavLink
to={item.permalink}
className="menu__link"
activeClassName="menu__link--active">
{item.title}
</Link>
</li>
))}
</ul>
<BlogSidebarContent
items={items}
ListComponent={ListComponent}
yearGroupHeadingClassName={styles.yearGroupHeading}
/>
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* 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.
*/

.yearGroupHeading {
margin: 1rem 0.75rem 0.5rem;
}
Loading