Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions apps/site/components/Common/ArticleWithSidebarState.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use client';

import Article from '@node-core/ui-components/Containers/Article';

import { useSidebarState } from '#site/providers/sidebarStateProvider';

import type { FC, PropsWithChildren } from 'react';

const ArticleWithSidebarState: FC<PropsWithChildren> = ({ children }) => {
const { isLeftSidebarCollapsed, isRightSidebarCollapsed } = useSidebarState();

return (
<Article
data-left-sidebar-collapsed={isLeftSidebarCollapsed ? 'true' : 'false'}
data-right-sidebar-collapsed={isRightSidebarCollapsed ? 'true' : 'false'}
>
{children}
</Article>
);
};

export default ArticleWithSidebarState;
27 changes: 27 additions & 0 deletions apps/site/components/Common/ContentLayoutWithSidebarState.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
'use client';

import { useSidebarState } from '#site/providers/sidebarStateProvider';

import type { FC, PropsWithChildren } from 'react';

type ContentLayoutWithSidebarStateProps = {
className?: string;
};

const ContentLayoutWithSidebarState: FC<
PropsWithChildren<ContentLayoutWithSidebarStateProps>
> = ({ children, className = '' }) => {
const { isLeftSidebarCollapsed, isRightSidebarCollapsed } = useSidebarState();

return (
<div
className={className}
data-left-sidebar-collapsed={isLeftSidebarCollapsed ? 'true' : 'false'}
data-right-sidebar-collapsed={isRightSidebarCollapsed ? 'true' : 'false'}
>
{children}
</div>
);
};

export default ContentLayoutWithSidebarState;
57 changes: 55 additions & 2 deletions apps/site/components/withMetaBar.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
'use client';

import CollapsedSidebarRail from '@node-core/ui-components/Common/CollapsedSidebarRail';
import SidebarToggleButton from '@node-core/ui-components/Common/SidebarToggleButton';
import MetaBar from '@node-core/ui-components/Containers/MetaBar';
import GitHubIcon from '@node-core/ui-components/Icons/Social/GitHub';
import { defaultLocale } from '@node-core/website-i18n';
Expand All @@ -11,11 +13,14 @@ import useClientContext from '#site/hooks/useClientContext';
import useMediaQuery from '#site/hooks/useMediaQuery';
import { DEFAULT_DATE_FORMAT } from '#site/next.calendar.constants.mjs';
import { TRANSLATION_URL } from '#site/next.constants.mjs';
import { useSidebarState } from '#site/providers/sidebarStateProvider';
import { getGitHubBlobUrl } from '#site/util/github';

import type { FC } from 'react';

const WithMetaBar: FC = () => {
const WithMetaBar: FC<{ disableToggle?: boolean }> = ({
disableToggle = false,
}) => {
const { headings, readingTime, frontmatter, filename } = useClientContext();
const formatter = useFormatter();
const lastUpdated = frontmatter.date
Expand All @@ -34,12 +39,40 @@ const WithMetaBar: FC = () => {

const t = useTranslations();
const locale = useLocale();
const { isRightSidebarCollapsed, toggleRightSidebar } = useSidebarState();

// Since we cannot show the same number of avatars in Mobile / Tablet
// resolution as we do on desktop and there is overflow, we are adjusting
// the number of avatars manually for the resolutions below
const isSmallerThanDesktop = useMediaQuery('(max-width: 1280px)');

// Check if there's any content to show in the metabar
const hasContent =
lastUpdated ||
readingTimeText ||
usernames.length > 0 ||
headings.length > 0;

// If no content, render empty div to preserve grid structure
if (!hasContent) {
return <div />;
}

// Show collapsed rail when right sidebar is collapsed and toggle is enabled
if (isRightSidebarCollapsed && !disableToggle) {
return (
<CollapsedSidebarRail side="right">
<SidebarToggleButton
side="right"
isCollapsed={isRightSidebarCollapsed}
onToggle={toggleRightSidebar}
ariaLabel={t('components.common.sidebar.expandRightSidebar')}
title={t('components.common.sidebar.expandRightSidebar')}
/>
</CollapsedSidebarRail>
);
}

return (
<MetaBar
heading={t('components.metabar.tableOfContents')}
Expand Down Expand Up @@ -74,7 +107,27 @@ const WithMetaBar: FC = () => {
),
}}
headings={{ items: headings }}
/>
>
{!disableToggle && (
<div className="mb-1 flex justify-end pr-2">
<SidebarToggleButton
side="right"
isCollapsed={isRightSidebarCollapsed}
onToggle={toggleRightSidebar}
ariaLabel={
isRightSidebarCollapsed
? t('components.common.sidebar.expandRightSidebar')
: t('components.common.sidebar.collapseRightSidebar')
}
title={
isRightSidebarCollapsed
? t('components.common.sidebar.expandRightSidebar')
: t('components.common.sidebar.collapseRightSidebar')
}
/>
</div>
)}
</MetaBar>
);
};

Expand Down
57 changes: 55 additions & 2 deletions apps/site/components/withSidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
'use client';

import CollapsedSidebarRail from '@node-core/ui-components/Common/CollapsedSidebarRail';
import SidebarToggleButton from '@node-core/ui-components/Common/SidebarToggleButton';
import Sidebar from '@node-core/ui-components/Containers/Sidebar';
import { useTranslations } from 'next-intl';
import { useRef } from 'react';
Expand All @@ -9,6 +11,7 @@ import useClientContext from '#site/hooks/useClientContext';
import useScrollToElement from '#site/hooks/useScrollToElement';
import useSiteNavigation from '#site/hooks/useSiteNavigation';
import { useRouter, usePathname } from '#site/navigation.mjs';
import { useSidebarState } from '#site/providers/sidebarStateProvider';

import type { FormattedMessage, NavigationKeys } from '#site/types';
import type { RichTranslationValues } from 'next-intl';
Expand All @@ -17,6 +20,7 @@ import type { FC } from 'react';
type WithSidebarProps = {
navKeys: Array<NavigationKeys>;
context?: Record<string, RichTranslationValues>;
disableToggle?: boolean;
};

type MappedItem = {
Expand All @@ -40,14 +44,20 @@ const mapItem = ([, item]: [string, MappedItem]): SidebarMappedEntry => ({
items: item.items ? item.items.map(mapItem) : [],
});

const WithSidebar: FC<WithSidebarProps> = ({ navKeys, context, ...props }) => {
const WithSidebar: FC<WithSidebarProps> = ({
navKeys,
context,
disableToggle = false,
...props
}) => {
const { getSideNavigation } = useSiteNavigation();
const pathname = usePathname()!;
const t = useTranslations();
const { push } = useRouter();
const { frontmatter } = useClientContext();
const sidebarRef = useRef<HTMLElement>(null);
const sideNavigation = getSideNavigation(navKeys, context);
const { isLeftSidebarCollapsed, toggleLeftSidebar } = useSidebarState();

// Preserve sidebar scroll position across navigations
useScrollToElement('sidebar', sidebarRef);
Expand All @@ -62,6 +72,29 @@ const WithSidebar: FC<WithSidebarProps> = ({ navKeys, context, ...props }) => {
})
);

const hasNavigationContent =
mappedSidebarItems.length > 0 && navKeys.length > 0;

// If no navigation content, render empty div to preserve grid structure
if (!hasNavigationContent) {
return <div />;
}

// Show collapsed rail when sidebar is collapsed and toggle is enabled
if (isLeftSidebarCollapsed && !disableToggle) {
return (
<CollapsedSidebarRail side="left">
<SidebarToggleButton
side="left"
isCollapsed={isLeftSidebarCollapsed}
onToggle={toggleLeftSidebar}
ariaLabel={t('components.common.sidebar.expandLeftSidebar')}
title={t('components.common.sidebar.expandLeftSidebar')}
/>
</CollapsedSidebarRail>
);
}

return (
<Sidebar
ref={sidebarRef}
Expand All @@ -72,7 +105,27 @@ const WithSidebar: FC<WithSidebarProps> = ({ navKeys, context, ...props }) => {
onSelect={push}
as={Link}
{...props}
/>
>
{!disableToggle && (
<div className="mb-1 flex justify-end pr-2">
<SidebarToggleButton
side="left"
isCollapsed={isLeftSidebarCollapsed}
onToggle={toggleLeftSidebar}
ariaLabel={
isLeftSidebarCollapsed
? t('components.common.sidebar.expandLeftSidebar')
: t('components.common.sidebar.collapseLeftSidebar')
}
title={
isLeftSidebarCollapsed
? t('components.common.sidebar.expandLeftSidebar')
: t('components.common.sidebar.collapseLeftSidebar')
}
/>
</div>
)}
</Sidebar>
);
};

Expand Down
11 changes: 5 additions & 6 deletions apps/site/layouts/About.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Article from '@node-core/ui-components/Containers/Article';

import ArticleWithSidebarState from '#site/components/Common/ArticleWithSidebarState';
import WithBreadcrumbs from '#site/components/withBreadcrumbs';
import WithFooter from '#site/components/withFooter';
import WithMetaBar from '#site/components/withMetaBar';
Expand All @@ -12,19 +11,19 @@ const AboutLayout: FC<PropsWithChildren> = ({ children }) => (
<>
<WithNavBar />

<Article>
<WithSidebar navKeys={['about', 'getInvolved']} />
<ArticleWithSidebarState>
<WithSidebar navKeys={['about', 'getInvolved']} disableToggle />

<div>
<main id="main" tabIndex={-1}>
{children}
</main>

<WithMetaBar />
<WithMetaBar disableToggle />
</div>

<WithBreadcrumbs navKeys={['about', 'getInvolved']} />
</Article>
</ArticleWithSidebarState>

<WithFooter />
</>
Expand Down
7 changes: 3 additions & 4 deletions apps/site/layouts/ArticlePage.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Article from '@node-core/ui-components/Containers/Article';

import ArticleWithSidebarState from '#site/components/Common/ArticleWithSidebarState';
import WithFooter from '#site/components/withFooter';
import WithMetaBar from '#site/components/withMetaBar';
import WithNavBar from '#site/components/withNavBar';
Expand All @@ -11,7 +10,7 @@ const ArticlePageLayout: FC<PropsWithChildren> = ({ children }) => (
<>
<WithNavBar />

<Article>
<ArticleWithSidebarState>
<WithSidebar navKeys={[]} />

<div>
Expand All @@ -21,7 +20,7 @@ const ArticlePageLayout: FC<PropsWithChildren> = ({ children }) => (

<WithMetaBar />
</div>
</Article>
</ArticleWithSidebarState>

<WithFooter />
</>
Expand Down
5 changes: 4 additions & 1 deletion apps/site/layouts/Base.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { NavigationStateProvider } from '#site/providers/navigationStateProvider';
import { SidebarStateProvider } from '#site/providers/sidebarStateProvider';

import type { FC, PropsWithChildren } from 'react';

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

const BaseLayout: FC<PropsWithChildren> = ({ children }) => (
<NavigationStateProvider>
<div className={styles.baseLayout}>{children}</div>
<SidebarStateProvider>
<div className={styles.baseLayout}>{children}</div>
</SidebarStateProvider>
</NavigationStateProvider>
);

Expand Down
7 changes: 3 additions & 4 deletions apps/site/layouts/Default.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Article from '@node-core/ui-components/Containers/Article';

import ArticleWithSidebarState from '#site/components/Common/ArticleWithSidebarState';
import WithFooter from '#site/components/withFooter';
import WithNavBar from '#site/components/withNavBar';
import WithSidebar from '#site/components/withSidebar';
Expand All @@ -10,15 +9,15 @@ const DefaultLayout: FC<PropsWithChildren> = ({ children }) => (
<>
<WithNavBar />

<Article>
<ArticleWithSidebarState>
<WithSidebar navKeys={[]} />

<div>
<main id="main" tabIndex={-1}>
{children}
</main>
</div>
</Article>
</ArticleWithSidebarState>

<WithFooter />
</>
Expand Down
8 changes: 5 additions & 3 deletions apps/site/layouts/Post.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import Preview from '@node-core/ui-components/Common/Preview';

import { getClientContext } from '#site/client-context';
import ContentLayoutWithSidebarState from '#site/components/Common/ContentLayoutWithSidebarState';
import EOLAlert from '#site/components/EOL/EOLAlert';
import WithAvatarGroup from '#site/components/withAvatarGroup';
import WithBlogCrossLinks from '#site/components/withBlogCrossLinks';
import WithFooter from '#site/components/withFooter';
import WithMetaBar from '#site/components/withMetaBar';
import WithNavBar from '#site/components/withNavBar';
import WithSidebar from '#site/components/withSidebar';
import { mapAuthorToCardAuthors } from '#site/util/author';
import { mapBlogCategoryToPreviewType } from '#site/util/blog';

Expand All @@ -25,8 +27,8 @@ const PostLayout: FC<PropsWithChildren> = ({ children }) => {
<>
<WithNavBar />

<div className={styles.contentLayout}>
<div></div>
<ContentLayoutWithSidebarState className={styles.contentLayout}>
<WithSidebar navKeys={[]} />

<div className={styles.postLayout}>
<main id="main" tabIndex={-1}>
Expand All @@ -49,7 +51,7 @@ const PostLayout: FC<PropsWithChildren> = ({ children }) => {
</div>

<WithMetaBar />
</div>
</ContentLayoutWithSidebarState>

<WithFooter />
</>
Expand Down
Loading