Skip to content

Commit

Permalink
🏗 Support parts mdast trees in page frontmatter (#486)
Browse files Browse the repository at this point in the history
Co-authored-by: Rowan Cockett <rowanc1@gmail.com>
  • Loading branch information
fwkoch and rowanc1 authored Oct 17, 2024
1 parent 348bf3b commit 4d55ef2
Show file tree
Hide file tree
Showing 12 changed files with 72 additions and 36 deletions.
12 changes: 12 additions & 0 deletions .changeset/itchy-doors-leave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
'myst-to-react': patch
'@myst-theme/frontmatter': patch
'myst-demo': patch
'@myst-theme/providers': patch
'@myst-theme/common': patch
'@myst-theme/article': patch
'@myst-theme/site': patch
'@myst-theme/book': patch
---

Support parts mdast trees in page frontmatter
3 changes: 2 additions & 1 deletion packages/common/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ export type FooterLinks = {
};
};

type PageFrontmatterWithDownloads = Omit<PageFrontmatter, 'downloads' | 'exports'> & {
type PageFrontmatterWithDownloads = Omit<PageFrontmatter, 'parts' | 'downloads' | 'exports'> & {
parts?: Record<string, { frontmatter?: PageFrontmatter; mdast: GenericParent }>;
downloads?: SiteAction[];
exports?: SiteExport[];
};
Expand Down
47 changes: 25 additions & 22 deletions packages/common/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,28 +188,31 @@ export function updatePageStaticLinksInplace(data: PageLoader, updateUrl: Update
return { ...exp, url: updateUrl(exp.url) };
});
}
// Fix all of the images to point to the CDN
const images = selectAll('image', data.mdast) as Image[];
images.forEach((node) => {
node.url = updateUrl(node.url);
if (node.urlOptimized) {
node.urlOptimized = updateUrl(node.urlOptimized);
}
});
const links = selectAll('link,linkBlock,card', data.mdast) as Link[];
const staticLinks = links.filter((node) => node.static);
staticLinks.forEach((node) => {
// These are static links to thinks like PDFs or other referenced files
node.url = updateUrl(node.url);
});
const outputs = selectAll('output', data.mdast) as Output[];
outputs.forEach((node) => {
if (!node.data) return;
walkOutputs(node.data, (obj) => {
// The path will be defined from output of myst
// Here we are re-assigning it to the current domain
if (!obj.path) return;
obj.path = updateUrl(obj.path);
const allMdastTrees = [data, ...Object.values(data.frontmatter?.parts ?? {})];
allMdastTrees.forEach(({ mdast }) => {
// Fix all of the images to point to the CDN
const images = selectAll('image', mdast) as Image[];
images.forEach((node) => {
node.url = updateUrl(node.url);
if (node.urlOptimized) {
node.urlOptimized = updateUrl(node.urlOptimized);
}
});
const links = selectAll('link,linkBlock,card', mdast) as Link[];
const staticLinks = links?.filter((node) => node.static);
staticLinks.forEach((node) => {
// These are static links to thinks like PDFs or other referenced files
node.url = updateUrl(node.url);
});
const outputs = selectAll('output', mdast) as Output[];
outputs.forEach((node) => {
if (!node.data) return;
walkOutputs(node.data, (obj) => {
// The path will be defined from output of myst
// Here we are re-assigning it to the current domain
if (!obj.path) return;
obj.path = updateUrl(obj.path);
});
});
});
return data;
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 @@ -194,7 +194,7 @@ export function FrontmatterBlock({
hideExports,
className,
}: {
frontmatter: PageFrontmatter;
frontmatter: Omit<PageFrontmatter, 'parts'>;
kind?: SourceFileKind;
authorStyle?: 'block' | 'list';
hideBadges?: boolean;
Expand Down
3 changes: 2 additions & 1 deletion packages/myst-demo/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ export function MySTRenderer({
);

const mdastStage = astStage === 'pre' ? mdastPre : mdastPost;
const { downloads, exports, parts, ...reducedFrontmatter } = frontmatter;

Check warning on line 389 in packages/myst-demo/src/index.tsx

View workflow job for this annotation

GitHub Actions / lint

'downloads' is assigned a value but never used

Check warning on line 389 in packages/myst-demo/src/index.tsx

View workflow job for this annotation

GitHub Actions / lint

'exports' is assigned a value but never used

Check warning on line 389 in packages/myst-demo/src/index.tsx

View workflow job for this annotation

GitHub Actions / lint

'parts' is assigned a value but never used

return (
<figure
Expand Down Expand Up @@ -437,7 +438,7 @@ export function MySTRenderer({
>
{previewType === 'DEMO' && (
<>
<ReferencesProvider references={references} frontmatter={frontmatter}>
<ReferencesProvider references={references} frontmatter={reducedFrontmatter}>
{TitleBlock && <TitleBlock frontmatter={frontmatter}></TitleBlock>}
<MyST ast={references.article?.children as GenericNode[]} />
</ReferencesProvider>
Expand Down
15 changes: 13 additions & 2 deletions packages/myst-to-react/src/crossReference.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import {
XRefProvider,
useXRefState,
type NodeRenderer,
useFrontmatter,
} from '@myst-theme/providers';
import { InlineError } from './inlineError.js';
import { default as useSWR } from 'swr';
import { HoverPopover } from './components/index.js';
import { MyST } from './MyST.js';
import type { GenericNode, GenericParent } from 'myst-common';
import { selectMdastNodes } from 'myst-common';
import { scrollToElement } from './hashLink.js';

Expand Down Expand Up @@ -100,11 +102,20 @@ export function useFetchMdast({

function useSelectNodes({ load, identifier }: { load?: boolean; identifier: string }) {
const references = useReferences();
const frontmatter = useFrontmatter();
const { remote, url, remoteBaseUrl, dataUrl } = useXRefState();
if (!load) return;
const { data, error } = useFetchMdast({ remote, url, remoteBaseUrl, dataUrl });
const mdast = data?.mdast ?? references?.article;
const { nodes, htmlId } = selectMdastNodes(mdast, identifier, 3);
const mdast = data ? (data.mdast as GenericParent) : references?.article;
const parts = data ? (data.frontmatter?.parts as { mdast: GenericParent }) : frontmatter?.parts;
let nodes: GenericNode[] = [];
let htmlId: string | undefined;
[{ mdast }, ...Object.values(parts ?? {})].forEach(({ mdast: tree }) => {
if (!tree || nodes.length > 0) return;
const selected = selectMdastNodes(tree, identifier, 3);
nodes = selected.nodes;
htmlId = selected.htmlId;
});
return { htmlId, nodes, loading: remote && !data, error: remote && error };
}

Expand Down
6 changes: 3 additions & 3 deletions packages/providers/src/references.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React, { useContext } from 'react';
import type { References } from 'myst-common';
import type { PageFrontmatter } from 'myst-frontmatter';
import type { PageLoader } from '@myst-theme/common';

const ReferencesContext = React.createContext<{
frontmatter?: PageFrontmatter;
frontmatter?: PageLoader['frontmatter'];
references?: References;
}>({});

Expand All @@ -12,7 +12,7 @@ export function ReferencesProvider({
frontmatter,
children,
}: {
frontmatter?: PageFrontmatter;
frontmatter?: PageLoader['frontmatter'];
references?: References;
children: React.ReactNode;
}) {
Expand Down
2 changes: 1 addition & 1 deletion packages/site/src/pages/Article.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const ArticlePage = React.memo(function ({
const downloads = combineDownloads(manifest?.downloads, article.frontmatter);
const tree = copyNode(article.mdast);
const keywords = article.frontmatter?.keywords ?? [];
const parts = extractKnownParts(tree);
const parts = extractKnownParts(tree, article.frontmatter?.parts);

return (
<ReferencesProvider
Expand Down
2 changes: 1 addition & 1 deletion packages/site/src/pages/ErrorUnhandled.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export function ErrorUnhandled({ error }: { error: ErrorResponse }) {
<>
<h1>Unexpected Error Occurred</h1>
<p>Status: {error.status}</p>
<p>{error.data.message}</p>
<p>{error.data?.message ?? ''}</p>
</>
);
}
12 changes: 10 additions & 2 deletions packages/site/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,21 @@ export type KnownParts = {
acknowledgments?: GenericParent;
};

export function extractKnownParts(tree: GenericParent): KnownParts {
export function extractKnownParts(
tree: GenericParent,
parts?: Record<string, { mdast?: GenericParent }>,
): KnownParts {
const abstract = extractPart(tree, 'abstract');
const summary = extractPart(tree, 'summary', { requireExplicitPart: true });
const keypoints = extractPart(tree, ['keypoints'], { requireExplicitPart: true });
const data_availability = extractPart(tree, ['data_availability', 'data availability']);
const acknowledgments = extractPart(tree, ['acknowledgments', 'acknowledgements']);
return { abstract, summary, keypoints, data_availability, acknowledgments };
const otherParts = Object.fromEntries(
Object.entries(parts ?? {}).map(([k, v]) => {
return [k, v.mdast];
}),
);
return { abstract, summary, keypoints, data_availability, acknowledgments, ...otherParts };
}

/**
Expand Down
2 changes: 1 addition & 1 deletion themes/article/app/components/Article.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export function Article({
}) {
const keywords = article.frontmatter?.keywords ?? [];
const tree = copyNode(article.mdast);
const parts = extractKnownParts(tree);
const parts = extractKnownParts(tree, article.frontmatter?.parts);
const { title, subtitle } = article.frontmatter;
const compute = useComputeOptions();
const top = useThemeTop();
Expand Down
2 changes: 1 addition & 1 deletion themes/book/app/components/ArticlePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export const ArticlePage = React.memo(function ({
const downloads = combineDownloads(manifest?.downloads, article.frontmatter);
const tree = copyNode(article.mdast);
const keywords = article.frontmatter?.keywords ?? [];
const parts = extractKnownParts(tree);
const parts = extractKnownParts(tree, article.frontmatter?.parts);
const isOutlineMargin = useMediaQuery('(min-width: 1024px)');
return (
<ReferencesProvider
Expand Down

0 comments on commit 4d55ef2

Please sign in to comment.