Skip to content

Commit

Permalink
📄 Update article theme for single project, consume dataUrl
Browse files Browse the repository at this point in the history
  • Loading branch information
fwkoch authored and rowanc1 committed May 11, 2023
1 parent a61aa03 commit e8c69a5
Show file tree
Hide file tree
Showing 11 changed files with 73 additions and 66 deletions.
6 changes: 6 additions & 0 deletions .changeset/giant-items-fail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@myst-theme/article': patch
'@myst-theme/site': patch
---

Modify article theme to only serve one project with no project slug
7 changes: 7 additions & 0 deletions .changeset/rude-socks-remember.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'myst-to-react': patch
'@myst-theme/providers': patch
'@myst-theme/site': patch
---

Consume dataUrl directly rather than imlpicitly constructing with appened .json
16 changes: 13 additions & 3 deletions packages/myst-to-react/src/crossReference.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,15 @@ export function ReferencedContent({
}) {
const Link = useLinkProvider();
const urlbase = useUrlbase();
const { remote, url } = useXRefState();
const { dataUrl, remote, url } = useXRefState();
// dataUrl should point directly to the cross reference mdast data.
// If dataUrl is not provided, it will be computed by appending .json to the url.
const external = url?.startsWith('http') ?? false;
const lookupUrl = external ? `/api/lookup?url=${url}.json` : `${withUrlbase(url, urlbase)}.json`;
const lookupUrl = external
? `/api/lookup?url=${url}.json`
: dataUrl
? `${withUrlbase(dataUrl, urlbase)}`
: `${withUrlbase(url, urlbase)}.json`;
const { data, error } = useSWR(remote ? lookupUrl : null, fetcher);
const references = useReferences();
const mdast = data?.mdast ?? references?.article;
Expand Down Expand Up @@ -131,7 +137,11 @@ export const CrossReferenceNode: NodeRenderer<CrossReference> = (node, children)
<ClickPopover
key={node.key}
card={({ close }) => (
<XRefProvider remote={(node as any).remote} url={(node as any).url}>
<XRefProvider
remote={(node as any).remote}
url={(node as any).url}
dataUrl={(node as any).dataUrl}
>
<ReferencedContent identifier={node.identifier as string} close={close} />
</XRefProvider>
)}
Expand Down
6 changes: 5 additions & 1 deletion packages/providers/src/xref.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ interface RemoteXRefState {
inCrossRef: boolean;
remote: boolean;
url?: string;
dataUrl?: string;
}

const XRefContext = createContext<RemoteXRefState | undefined>(undefined);
Expand All @@ -16,18 +17,21 @@ export function useXRefState(): RemoteXRefState {
// Create a provider for components to consume and subscribe to changes
export function XRefProvider({
remote,
url: url,
url,
dataUrl,
children,
}: {
remote?: boolean;
url?: string;
dataUrl?: string;
children: React.ReactNode;
}) {
const parent = useXRefState();
const value: RemoteXRefState = {
inCrossRef: true,
remote: remote ?? parent.remote,
url: url ?? parent.url,
dataUrl: dataUrl ?? parent.dataUrl,
};
if (value.remote && !value.url) {
value.remote = false;
Expand Down
7 changes: 4 additions & 3 deletions packages/site/src/loaders/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ export function getProject(
config?: SiteManifest,
projectSlug?: string,
): ManifestProject | undefined {
if (!projectSlug || !config) return undefined;
if (!config) return undefined;
if (!projectSlug) return config.projects?.[0];
const project = config.projects?.find((p) => p.slug === projectSlug);
return project;
}
Expand All @@ -32,12 +33,12 @@ export function getProjectHeadings(
{
title: project.title,
slug: project.index,
path: `/${project.slug}`,
path: project.slug ? `/${project.slug}` : '/',
level: 'index',
},
...project.pages.map((p) => {
if (!('slug' in p)) return p;
return { ...p, path: `/${project.slug}/${p.slug}` };
return { ...p, path: projectSlug ? `/${project.slug}/${p.slug}` : `/${p.slug}` };
}),
];
if (opts.addGroups) {
Expand Down
14 changes: 0 additions & 14 deletions themes/article/app/routes/$project._index.tsx

This file was deleted.

1 change: 0 additions & 1 deletion themes/article/app/routes/$project[.json].tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ export const meta: MetaFunction = (args) => {
export const links: LinksFunction = () => [KatexCSS];

export const loader: LoaderFunction = async ({ params, request }) => {
const { project, slug } = params;
return getPage(request, { project, slug, redirect: true });
const { slug } = params;
return getPage(request, { slug, redirect: true });
};

export function ArticlePageAndNavigation({
Expand All @@ -72,12 +72,12 @@ function ArticleNavigation() {
const Link = useLinkProvider();
const { pathname } = useLocation();
const project = site?.projects?.[0];
const exact = pathname === `/${project?.slug}`;
const exact = pathname === `/`;
return (
<nav className="col-page-inset">
<div className="border-y border-gray-200 py-3 mt-4 mb-6 flex flex-row justify-around">
<Link
to={`/${project?.slug}`}
to={`/`}
prefetch="intent"
className={classNames('no-underline', { 'text-blue-600': exact })}
>
Expand All @@ -86,20 +86,18 @@ function ArticleNavigation() {
{project?.pages
.filter((p) => 'slug' in p)
.map((p) => {
if (p.level === 1)
return (
<NavLink
key={p.slug}
to={`/${project?.slug}/${p.slug}`}
prefetch="intent"
className={({ isActive }) =>
classNames('no-underline', { 'text-blue-600': isActive })
}
>
{p.title}
</NavLink>
);
return null;
return (
<NavLink
key={p.slug}
to={`/${p.slug}`}
prefetch="intent"
className={({ isActive }) =>
classNames('no-underline', { 'text-blue-600': isActive })
}
>
{p.title}
</NavLink>
);
})}
</div>
</nav>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ function api404(message = 'No API route found at this URL') {
status: 404,
message,
},
{ status: 404 }
{ status: 404 },
);
}

export const loader: LoaderFunction = async ({ request, params }) => {
const { project, slug } = params;
const data = await getPage(request, { project, slug }).catch(() => null);
const { slug } = params;
const data = await getPage(request, { slug }).catch(() => null);
if (!data) return api404('No page found at this URL.');
return json(data);
};
28 changes: 12 additions & 16 deletions themes/article/app/routes/_index.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
import { responseNoArticle, responseNoSite } from '@myst-theme/site';
import type { LoaderFunction } from '@remix-run/node';
import { redirect } from '@remix-run/node';
import { Outlet } from '@remix-run/react';
import { getConfig } from '~/utils/loaders.server';
import { ProjectPageCatchBoundary } from '@myst-theme/site';
import Page, { ArticlePageAndNavigation } from './$slug';
export { loader, links } from './$slug';
export default Page;

export const loader: LoaderFunction = async (): Promise<Response | null> => {
const config = await getConfig();
if (!config) throw responseNoSite();
const project = config?.projects?.[0];
if (!project) throw responseNoArticle();
return redirect(`/${project.slug}`);
};

// Note this is necessary to propagate catch boundaries, even though there is a redirect
export default function Index() {
return <Outlet />;
export function CatchBoundary() {
return (
<ArticlePageAndNavigation>
<main className="article-content">
<ProjectPageCatchBoundary />
</main>
</ArticlePageAndNavigation>
);
}
14 changes: 7 additions & 7 deletions themes/article/app/utils/loaders.server.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import fetch from 'node-fetch';
import type { SiteManifest } from 'myst-config';
import type { PageLoader } from '@myst-theme/site';
import { getDomainFromRequest } from '@myst-theme/site';
import {
getDomainFromRequest,
getFooterLinks,
getProject,
responseNoArticle,
Expand Down Expand Up @@ -36,9 +36,9 @@ function updateLink(url: string) {
return `${CONTENT_CDN}${url}`;
}

async function getStaticContent(project?: string, slug?: string): Promise<PageLoader | null> {
if (!project || !slug) return null;
const url = `${CONTENT_CDN}/content/${project}/${slug}.json`;
async function getStaticContent(slug?: string): Promise<PageLoader | null> {
if (!slug) return null;
const url = `${CONTENT_CDN}/content/${slug}.json`;
const response = await fetch(url).catch(() => null);
if (!response || response.status === 404) return null;
const data = (await response.json()) as PageLoader;
Expand All @@ -52,18 +52,18 @@ export async function getPage(
loadIndexPage?: boolean;
slug?: string;
redirect?: boolean;
}
},
) {
const projectName = opts.project;
const config = await getConfig();
if (!config) throw responseNoSite();
const project = getProject(config, projectName);
if (!project) throw responseNoArticle();
if (opts.slug === project.index && opts.redirect) {
return redirect(`/${projectName}`);
return redirect(`/`);
}
const slug = opts.loadIndexPage || opts.slug == null ? project.index : opts.slug;
const loader = await getStaticContent(projectName, slug).catch(() => null);
const loader = await getStaticContent(slug).catch(() => null);
if (!loader) throw responseNoArticle();
const footer = getFooterLinks(config, projectName, slug);
return { ...loader, footer, domain: getDomainFromRequest(request) };
Expand Down

0 comments on commit e8c69a5

Please sign in to comment.