Skip to content

Commit

Permalink
🧭 Move collapsed top-bar to primary sidebar on small screens (#444)
Browse files Browse the repository at this point in the history
  • Loading branch information
agoose77 authored Aug 23, 2024
1 parent 8e5320b commit f0b5251
Show file tree
Hide file tree
Showing 19 changed files with 405 additions and 193 deletions.
7 changes: 7 additions & 0 deletions .changeset/forty-carrots-cry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@myst-theme/frontmatter': patch
'@myst-theme/site': patch
'@myst-theme/book': patch
---

Some alignment fixes, leaving more control over content top alignment to the theme
6 changes: 6 additions & 0 deletions .changeset/mighty-ears-breathe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@myst-theme/site': patch
'@myst-theme/book': patch
---

Renamed `Navigation` component and split for re-use in different (composed/multi-site) themes
6 changes: 6 additions & 0 deletions .changeset/olive-baboons-accept.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@myst-theme/site': minor
'@myst-theme/book': patch
---

Rework TOC to PrimarySidebar
5 changes: 5 additions & 0 deletions .changeset/strong-cars-beam.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@myst-theme/common': patch
---

Modified `getProjectHeadings` to work with plain `projectSlugs` to support custom theme routes that use `baseurl` but have no separate project.
5 changes: 4 additions & 1 deletion packages/common/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ export function getProjectHeadings(
},
...project.pages.map((p) => {
if (!('slug' in p)) return p;
return { ...p, path: projectSlug ? `/${project.slug}/${p.slug}` : `/${p.slug}` };
return {
...p,
path: projectSlug && project.slug ? `/${project.slug}/${p.slug}` : `/${p.slug}`,
};
}),
];
if (opts.addGroups) {
Expand Down
2 changes: 1 addition & 1 deletion packages/frontmatter/src/FrontmatterBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ export function FrontmatterBlock({
className={classNames(className)}
>
{showHeaderBlock && (
<div className="flex items-center h-6 mt-3 mb-5 text-sm font-light">
<div className="flex items-center h-6 mb-5 text-sm font-light">
{subject && (
<div
className={classNames('flex-none pr-2 smallcaps', {
Expand Down
4 changes: 2 additions & 2 deletions packages/site/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -1077,10 +1077,10 @@
- 8af808bf: Remove css updates for document nav and outline from React state

```tsx
const { container, toc } = useTocHeight(top);
const { container, toc } = useSidebarHeight(top);

// Update the nav and article, removing the height
<Navigation tocRef={toc} ... />
<Navigation sidebarRef={toc} ... />
<article ref={container} ... />
```

Expand Down
6 changes: 5 additions & 1 deletion packages/site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@
"license": "MIT",
"sideEffects": false,
"scripts": {
"clean": "rimraf dist",
"compile": "tsc --noEmit",
"lint": "eslint src/**/*.ts*",
"lint:format": "prettier --check \"src/**/*.{ts,tsx,md}\""
"lint:format": "prettier --check \"src/**/*.{ts,tsx,md}\"",
"dev": "npm-run-all --parallel \"build:* -- --watch\"",
"build:esm": "tsc",
"build": "npm-run-all -l clean -p build:esm"
},
"dependencies": {
"@headlessui/react": "^1.7.15",
Expand Down
2 changes: 1 addition & 1 deletion packages/site/src/components/Headers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export function ArticleHeader({
frontmatter={rest}
authorStyle="list"
className={classNames('flex-grow', {
'pt-4 px-6': frontmatter?.banner,
'pt-6 px-6': frontmatter?.banner,
...positionFrontmatter,
})}
hideBadges
Expand Down
25 changes: 25 additions & 0 deletions packages/site/src/components/Navigation/InlineTableOfContents.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { useSiteManifest } from '@myst-theme/providers';
import { getProjectHeadings } from '@myst-theme/common';
import { Toc } from './TableOfContentsItems.js';

export const InlineTableOfContents = ({
projectSlug,
sidebarRef,
className = 'flex-grow overflow-y-auto max-w-[350px]',
}: {
projectSlug?: string;
className?: string;
sidebarRef?: React.RefObject<HTMLElement>;
}) => {
const config = useSiteManifest();
if (!config) return null;
const headings = getProjectHeadings(config, projectSlug, {
addGroups: false,
});
if (!headings) return null;
return (
<nav aria-label="Table of Contents" className={className} ref={sidebarRef}>
<Toc headings={headings} />
</nav>
);
};
47 changes: 47 additions & 0 deletions packages/site/src/components/Navigation/Link.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react';
import { useLinkProvider, useNavLinkProvider } from '@myst-theme/providers';

export function ExternalOrInternalLink({
to,
className,
children,
nav,
onClick,
prefetch = 'intent',
}: {
to: string;
className?: string | ((props: { isActive: boolean }) => string);
children: React.ReactNode;
nav?: boolean;
onClick?: () => void;
prefetch?: 'intent' | 'render' | 'none';
}) {
const Link = useLinkProvider();
const NavLink = useNavLinkProvider();
const staticClass = typeof className === 'function' ? className({ isActive: false }) : className;
if (to.startsWith('http') || to.startsWith('mailto:')) {
return (
<a
href={to}
target="_blank"
rel="noopener noreferrer"
className={staticClass}
onClick={onClick}
>
{children}
</a>
);
}
if (nav) {
return (
<NavLink prefetch={prefetch} to={to} className={className} onClick={onClick}>
{children}
</NavLink>
);
}
return (
<Link prefetch={prefetch} to={to} className={staticClass} onClick={onClick}>
{children}
</Link>
);
}
87 changes: 78 additions & 9 deletions packages/site/src/components/Navigation/Navigation.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,106 @@
import { useNavOpen, useThemeTop } from '@myst-theme/providers';
import { TableOfContents } from './TableOfContents.js';
import { useNavOpen, useSiteManifest, useThemeTop } from '@myst-theme/providers';
import { PrimarySidebar } from './PrimarySidebar.js';
import type { Heading } from '@myst-theme/common';
import { getProjectHeadings } from '@myst-theme/common';
import type { SiteManifest } from 'myst-config';

export function Navigation({
/**
* PrimaryNavigation will load nav links and headers from the site manifest and display
* them in a mobile-friendly format.
*/
export const PrimaryNavigation = ({
children,
projectSlug,
tocRef,
sidebarRef,
hide_toc,
mobileOnly,
footer,
}: {
children?: React.ReactNode;
projectSlug?: string;
tocRef?: React.RefObject<HTMLDivElement>;
sidebarRef?: React.RefObject<HTMLDivElement>;
hide_toc?: boolean;
mobileOnly?: boolean;
footer?: React.ReactNode;
}) {
}) => {
const config = useSiteManifest();
if (!config) return null;

const headings = getProjectHeadings(config, projectSlug, {
addGroups: false,
});

const { nav } = config;

return (
<ConfigurablePrimaryNavigation
children={children}
sidebarRef={sidebarRef}
hide_toc={hide_toc}
mobileOnly={mobileOnly}
nav={nav}
headings={headings}
footer={footer}
/>
);
};

/**
@deprecated use PrimaryNavigation instead
*/
export const Navigation = PrimaryNavigation;

/**
* ConfigurablePrimaryNavigation will display a mobile-friendly navigation sidebar based on the
* nav, headings, and footer provided by the caller. Use this in situations where the PrimaryNavigation
* component may pick up the wrong SiteManifest.
*/
export const ConfigurablePrimaryNavigation = ({
children,
sidebarRef,
hide_toc,
mobileOnly,
nav,
headings,
footer,
}: {
children?: React.ReactNode;
sidebarRef?: React.RefObject<HTMLDivElement>;
hide_toc?: boolean;
mobileOnly?: boolean;
nav?: SiteManifest['nav'];
headings?: Heading[];
footer?: React.ReactNode;
}) => {
const [open, setOpen] = useNavOpen();
const top = useThemeTop();

if (children)
console.warn(
`Including children in Navigation can break keyboard accessbility and is deprecated. Please move children to the page component.`,
);

// the logic on the following line looks wrong, this will return `null` or `<></>`
// we should just return `null` if `hide_toc` is true?
if (hide_toc) return children ? null : <>{children}</>;

return (
<>
{open && (
{open && !mobileOnly && headings && (
<div
className="fixed inset-0 z-30 bg-black opacity-50"
style={{ marginTop: top }}
onClick={() => setOpen(false)}
></div>
)}
<TableOfContents tocRef={tocRef} projectSlug={projectSlug} footer={footer} />
<PrimarySidebar
sidebarRef={sidebarRef}
nav={nav}
headings={headings}
footer={footer}
mobileOnly={mobileOnly}
/>
{children}
</>
);
}
};
Loading

0 comments on commit f0b5251

Please sign in to comment.