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

📑 Add document outline mobile view #369

Merged
merged 12 commits into from
May 21, 2024
5 changes: 5 additions & 0 deletions .changeset/great-weeks-sit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@myst-theme/site': patch
---

Mark ArticlePage as deprecated
6 changes: 6 additions & 0 deletions .changeset/healthy-waves-sell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@myst-theme/article': patch
'@myst-theme/book': patch
---

Support inline navigation
5 changes: 5 additions & 0 deletions packages/site/src/pages/Article.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ function combineDownloads(
return pageFrontmatter.exports;
}

/**
* @deprecated This component is not maintained, in favor of theme-specific ArticlePages
*
* As examples, MyST book and article themes define their own ArticlePage components.
*/
export const ArticlePage = React.memo(function ({
article,
hide_all_footer_links,
Expand Down
7 changes: 5 additions & 2 deletions themes/article/app/components/Article.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ export function Article({
hideKeywords,
hideOutline,
hideTitle,
outlineMaxDepth,
}: {
article: PageLoader;
hideKeywords?: boolean;
hideOutline?: boolean;
hideTitle?: boolean;
outlineMaxDepth?: number;
}) {
const keywords = article.frontmatter?.keywords ?? [];
const tree = copyNode(article.mdast);
Expand All @@ -42,12 +44,13 @@ export function Article({
<ExecuteScopeProvider enable={compute?.enabled ?? false} contents={article}>
{!hideTitle && <FrontmatterBlock frontmatter={{ title, subtitle }} className="mb-5" />}
{!hideOutline && (
<div className="sticky top-0 z-10 hidden h-0 pt-2 ml-10 col-margin-right lg:block">
<DocumentOutline className="relative">
<div className="block my-10 lg:sticky lg:top-0 lg:z-10 lg:h-0 lg:pt-2 lg:my-0 lg:ml-10 lg:col-margin-right">
<DocumentOutline className="relative" maxdepth={outlineMaxDepth}>
<SupportingDocuments />
</DocumentOutline>
</div>
)}

{compute?.enabled &&
compute?.features.notebookCompute &&
article.kind === SourceFileKind.Notebook && <NotebookToolbar showLaunch />}
Expand Down
34 changes: 24 additions & 10 deletions themes/article/app/components/ArticlePage.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import type { PageLoader } from '@myst-theme/common';
import { FooterLinksBlock, ArticleHeader, Error404 } from '@myst-theme/site';
import {
FooterLinksBlock,
ArticleHeader,
Error404,
} from '@myst-theme/site';
import { LaunchBinder, useComputeOptions } from '@myst-theme/jupyter';
import { ArrowLeftIcon } from '@heroicons/react/24/outline';
import { DocumentArrowDownIcon } from '@heroicons/react/24/outline';
Expand All @@ -15,17 +19,20 @@ import classNames from 'classnames';
import { BusyScopeProvider, ExecuteScopeProvider } from '@myst-theme/jupyter';
import { DownloadLinksArea } from './Downloads';
import { Article } from './Article';

export interface ArticleTemplateOptions {
hide_toc?: boolean;
hide_footer_links?: boolean;
numbered_references?: boolean;
}
import type { TemplateOptions } from '../types.js';

export function ArticlePage({ article }: { article: PageLoader }) {
const grid = useGridSystemProvider();
const { projects, hide_footer_links } = (useSiteManifest() ?? {}) as SiteManifest &
ArticleTemplateOptions;

const siteManifest = useSiteManifest() as SiteManifest;
const pageDesign: TemplateOptions = (article.frontmatter as any)?.options ?? {};
const siteDesign: TemplateOptions = siteManifest?.options ?? {};

const { projects } = siteManifest;
const { hide_footer_links, hide_outline, outline_maxdepth } = {
...siteDesign,
...pageDesign,
};
const Link = useLinkProvider();
const baseurl = useBaseurl();
const compute = useComputeOptions();
Expand Down Expand Up @@ -91,11 +98,18 @@ export function ArticlePage({ article }: { article: PageLoader }) {
</a>
</div>
)}
<Article article={article} hideKeywords={!isIndex} hideTitle={isIndex} />
<Article
article={article}
hideKeywords={!isIndex}
hideTitle={isIndex}
hideOutline={hide_outline}
outlineMaxDepth={outline_maxdepth}
/>
</main>
{!hide_footer_links && <FooterLinksBlock links={article.footer} />}
</ExecuteScopeProvider>
</BusyScopeProvider>
</ReferencesProvider>
);
}

7 changes: 1 addition & 6 deletions themes/article/app/routes/_index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import {
ProjectPageCatchBoundary,
getMetaTagsForArticle,
responseNoArticle,
responseNoSite,
} from '@myst-theme/site';
import { getMetaTagsForArticle, responseNoArticle, responseNoSite, ProjectPageCatchBoundary} from '@myst-theme/site';
import Page from './$';
import { ArticlePageAndNavigation } from '../components/ArticlePageAndNavigation';
import { getConfig, getPage } from '../utils/loaders.server';
Expand Down
6 changes: 6 additions & 0 deletions themes/article/app/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface TemplateOptions {
hide_toc?: boolean;
hide_outline?: boolean;
hide_footer_links?: boolean;
outline_maxdepth?: number;
}
9 changes: 9 additions & 0 deletions themes/article/template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ options:
- type: boolean
id: hide_footer_links
description: Hide the previous/next links in the footer
- type: boolean
id: hide_outline
description: Hide the document outline on all pages
- type: number
id: outline_maxdepth
description: The maximum depth to show on the document outline, for example, `2` would show only two depths of headings (e.g. `<H1>` and `<H2>`).
min: 1
max: 6
integer: true
- type: string
id: twitter
description: Twitter handle related to the site
Expand Down
108 changes: 108 additions & 0 deletions themes/book/app/components/ArticlePage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import React from 'react';
import { ReferencesProvider, useProjectManifest, useSiteManifest } from '@myst-theme/providers';
import {
Bibliography,
ContentBlocks,
FooterLinksBlock,
FrontmatterParts,
BackmatterParts,
DocumentOutline,
extractKnownParts,
} from '@myst-theme/site';
import type { SiteManifest } from 'myst-config';
import type { PageLoader } from '@myst-theme/common';
import { copyNode, type GenericParent } from 'myst-common';
import { SourceFileKind } from 'myst-spec-ext';
import {
ExecuteScopeProvider,
BusyScopeProvider,
NotebookToolbar,
ConnectionStatusTray,
ErrorTray,
useComputeOptions,
} from '@myst-theme/jupyter';
import { FrontmatterBlock } from '@myst-theme/frontmatter';
import type { SiteAction } from 'myst-config';
import type { TemplateOptions } from '../types.js';

/**
* Combines the project downloads and the export options
*/
function combineDownloads(
siteDownloads: SiteAction[] | undefined,
pageFrontmatter: PageLoader['frontmatter'],
) {
if (pageFrontmatter.downloads) {
return pageFrontmatter.downloads;
}
// No downloads on the page, combine the exports if they exist
if (siteDownloads) {
return [...(pageFrontmatter.exports ?? []), ...siteDownloads];
}
return pageFrontmatter.exports;
}

export const ArticlePage = React.memo(function ({
article,
hide_all_footer_links,
hideKeywords,
}: {
article: PageLoader;
hide_all_footer_links?: boolean;
hideKeywords?: boolean;
}) {
const manifest = useProjectManifest();
const compute = useComputeOptions();

const pageDesign: TemplateOptions = (article.frontmatter as any)?.options ?? {};
const siteDesign: TemplateOptions =
(useSiteManifest() as SiteManifest & TemplateOptions)?.options ?? {};
const { hide_title_block, hide_footer_links, hide_outline, outline_maxdepth } = {
...siteDesign,
...pageDesign,
};
const downloads = combineDownloads(manifest?.downloads, article.frontmatter);
const tree = copyNode(article.mdast);
const keywords = article.frontmatter?.keywords ?? [];
const parts = extractKnownParts(tree);

return (
<ReferencesProvider
references={{ ...article.references, article: article.mdast }}
frontmatter={article.frontmatter}
>
<BusyScopeProvider>
<ExecuteScopeProvider enable={compute?.enabled ?? false} contents={article}>
{!hide_title_block && (
<FrontmatterBlock
kind={article.kind}
frontmatter={{ ...article.frontmatter, downloads }}
className="pt-5 mb-8"
/>
)}
{!hide_outline && (
<div className="block my-10 lg:sticky lg:top-0 lg:z-10 lg:h-0 lg:pt-2 lg:my-0 lg:ml-10 lg:col-margin-right">
<DocumentOutline className="relative" maxdepth={outline_maxdepth} />
</div>
)}
{compute?.enabled &&
compute.features.notebookCompute &&
article.kind === SourceFileKind.Notebook && <NotebookToolbar showLaunch />}
{compute?.enabled && article.kind === SourceFileKind.Article && (
<ErrorTray pageSlug={article.slug} />
)}
<div id="skip-to-article" />
<FrontmatterParts parts={parts} keywords={keywords} hideKeywords={hideKeywords} />
<ContentBlocks pageKind={article.kind} mdast={tree as GenericParent} />
<BackmatterParts parts={parts} />
<Bibliography />
<ConnectionStatusTray />
{!hide_footer_links && !hide_all_footer_links && (
<FooterLinksBlock links={article.footer} />
)}
</ExecuteScopeProvider>
</BusyScopeProvider>
</ReferencesProvider>
);
});

39 changes: 8 additions & 31 deletions themes/book/app/routes/$.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,12 @@ import {
import { getProject, isFlatSite, type PageLoader } from '@myst-theme/common';
import {
KatexCSS,
ArticlePage,
useOutlineHeight,
useTocHeight,
DocumentOutline,
Navigation,
TopNav,
ArticlePageCatchBoundary,
getMetaTagsForArticle,
ArticlePageCatchBoundary,
} from '@myst-theme/site';
import { getConfig, getPage } from '~/utils/loaders.server';
import { useLoaderData } from '@remix-run/react';
Expand All @@ -29,7 +27,8 @@ import {
} from '@myst-theme/providers';
import { MadeWithMyst } from '@myst-theme/icons';
import { ComputeOptionsProvider, ThebeLoaderAndServer } from '@myst-theme/jupyter';

import { ArticlePage } from '../components/ArticlePage.js';
import type { TemplateOptions } from '../types.js';
type ManifestProject = Required<SiteManifest>['projects'][0];

export const meta: V2_MetaFunction = ({ data, matches, location }) => {
Expand Down Expand Up @@ -107,24 +106,15 @@ export function ArticlePageAndNavigation({
);
}

export interface BookThemeTemplateOptions {
hide_toc?: boolean;
hide_outline?: boolean;
hide_footer_links?: boolean;
outline_maxdepth?: number;
numbered_references?: boolean;
}

export default function Page() {
const { container, outline } = useOutlineHeight();
const top = useThemeTop();
const { container } = useOutlineHeight();
const data = useLoaderData() as { page: PageLoader; project: ManifestProject };

const baseurl = useBaseurl();
const pageDesign: BookThemeTemplateOptions = (data.page.frontmatter as any)?.options ?? {};
const siteDesign: BookThemeTemplateOptions =
(useSiteManifest() as SiteManifest & BookThemeTemplateOptions)?.options ?? {};
const { hide_toc, hide_outline, hide_footer_links, outline_maxdepth } = {
const pageDesign: TemplateOptions = (data.page.frontmatter as any)?.options ?? {};
const siteDesign: TemplateOptions =
(useSiteManifest() as SiteManifest & TemplateOptions)?.options ?? {};
const { hide_toc, hide_footer_links } = {
...siteDesign,
...pageDesign,
};
Expand All @@ -137,19 +127,6 @@ export default function Page() {
>
<ThebeLoaderAndServer baseurl={baseurl}>
<main ref={container} className="article-grid subgrid-gap col-screen">
{!hide_outline && (
<div
className="sticky z-10 hidden h-0 col-margin-right-inset lg:block"
style={{ top }}
>
<DocumentOutline
top={16}
className="relative"
outlineRef={outline}
maxdepth={outline_maxdepth}
/>
</div>
)}
<ArticlePage article={data.page} hide_all_footer_links={hide_footer_links} />
</main>
</ThebeLoaderAndServer>
Expand Down
7 changes: 7 additions & 0 deletions themes/book/app/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export interface TemplateOptions {
hide_toc?: boolean;
hide_outline?: boolean;
hide_footer_links?: boolean;
outline_maxdepth?: number;
hide_title_block?: boolean;
agoose77 marked this conversation as resolved.
Show resolved Hide resolved
}
3 changes: 3 additions & 0 deletions themes/book/template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ options:
- type: boolean
id: hide_outline
description: Hide the document outline on all pages
- type: boolean
id: hide_title_block
description: Hide the document title on all pages
- type: number
id: outline_maxdepth
description: The maximum depth to show on the document outline, for example, `2` would show only two depths of headings (e.g. `<H1>` and `<H2>`).
Expand Down