Skip to content

Commit

Permalink
Merge pull request #369 from executablebooks/agoose77/wip-outline-inline
Browse files Browse the repository at this point in the history
📑 Add document outline mobile view
  • Loading branch information
fwkoch authored May 21, 2024
2 parents 5159f3b + a6b0152 commit 792f9f5
Show file tree
Hide file tree
Showing 12 changed files with 187 additions and 49 deletions.
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;
}
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

0 comments on commit 792f9f5

Please sign in to comment.