Skip to content

Commit

Permalink
馃摉 Major updates for static sites & flat URLs
Browse files Browse the repository at this point in the history
  • Loading branch information
rowanc1 committed May 11, 2023
1 parent 487d4c5 commit b59e1a3
Show file tree
Hide file tree
Showing 35 changed files with 237 additions and 170 deletions.
7 changes: 7 additions & 0 deletions .changeset/gold-guests-dream.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
---

Add new baseurl provider and remove previous one in article references provider
6 changes: 6 additions & 0 deletions .changeset/ninety-coats-cross.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'myst-to-react': patch
'@myst-theme/providers': patch
---

Add NavLink to the providers in Theme
5 changes: 5 additions & 0 deletions .changeset/sharp-boats-count.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@myst-theme/site': patch
---

Make the table of contents require a specific project slug
5 changes: 5 additions & 0 deletions .changeset/swift-flowers-cheer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@myst-theme/site': patch
---

Improve error message and remove debug error boundary
2 changes: 1 addition & 1 deletion packages/myst-to-react/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@
### Patch Changes

- 4e20392: Fix bug in tab set when it doesn't have items
- d221bf9: Update urlbase on crossReference links
- d221bf9: Update baseurl on crossReference links
- 28fc827: Update components to new myst-parser
- a3399e5: Simple admonitions and hide the icons
- Updated dependencies [28fc827]
Expand Down
6 changes: 3 additions & 3 deletions packages/myst-to-react/src/card.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import type { NodeRenderer } from '@myst-theme/providers';
import classNames from 'classnames';
import { useLinkProvider, useUrlbase, withUrlbase } from '@myst-theme/providers';
import { useLinkProvider, useBaseurl, withBaseurl } from '@myst-theme/providers';

type CardSpec = {
type: 'card';
Expand Down Expand Up @@ -82,7 +82,7 @@ function ExternalOrInternalLink({
children: React.ReactNode;
}) {
const Link = useLinkProvider();
const urlbase = useUrlbase();
const baseurl = useBaseurl();
if (to.startsWith('http') || isStatic) {
return (
<a href={to} className={className} target="_blank" rel="noopener noreferrer">
Expand All @@ -91,7 +91,7 @@ function ExternalOrInternalLink({
);
}
return (
<Link to={withUrlbase(to, urlbase)} className={className} prefetch={prefetch}>
<Link to={withBaseurl(to, baseurl)} className={className} prefetch={prefetch}>
{children}
</Link>
);
Expand Down
12 changes: 6 additions & 6 deletions packages/myst-to-react/src/crossReference.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import {
useLinkProvider,
useNodeRenderers,
useReferences,
useUrlbase,
useBaseurl,
useXRefState,
withUrlbase,
withBaseurl,
XRefProvider,
} from '@myst-theme/providers';
import { useParse } from '.';
Expand Down Expand Up @@ -62,16 +62,16 @@ export function ReferencedContent({
close: () => void;
}) {
const Link = useLinkProvider();
const urlbase = useUrlbase();
const baseurl = useBaseurl();
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`
: dataUrl
? `${withUrlbase(dataUrl, urlbase)}`
: `${withUrlbase(url, urlbase)}.json`;
? `${withBaseurl(dataUrl, baseurl)}`
: `${withBaseurl(url, baseurl)}.json`;
const { data, error } = useSWR(remote ? lookupUrl : null, fetcher);
const references = useReferences();
const mdast = data?.mdast ?? references?.article;
Expand Down Expand Up @@ -109,7 +109,7 @@ export function ReferencedContent({
</a>
)}
{remote && !external && (
<Link to={withUrlbase(url, urlbase)} className="absolute top-4 right-1" prefetch="intent">
<Link to={withBaseurl(url, baseurl)} className="absolute top-4 right-1" prefetch="intent">
<ExternalLinkIcon className="w-4 h-4" />
</Link>
)}
Expand Down
21 changes: 7 additions & 14 deletions packages/myst-to-react/src/links/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Link } from 'myst-spec';
import ExternalLinkIcon from '@heroicons/react/24/outline/ArrowTopRightOnSquareIcon';
import LinkIcon from '@heroicons/react/24/outline/LinkIcon';
import { useLinkProvider, useSiteManifest, useUrlbase, withUrlbase } from '@myst-theme/providers';
import { useLinkProvider, useSiteManifest, useBaseurl, withBaseurl } from '@myst-theme/providers';
import type { SiteManifest } from 'myst-config';
import type { NodeRenderer } from '@myst-theme/providers';
import { HoverPopover } from '../components/HoverPopover';
Expand All @@ -12,30 +12,23 @@ import { GithubLink } from './github';

type TransformedLink = Link & { internal?: boolean; protocol?: string };

type ManifestProjectItem = Required<SiteManifest>['projects'][0]['pages'][0];

function getPageInfo(
site: SiteManifest | undefined,
path: string,
): ManifestProjectItem | undefined {
function getPageInfo(site: SiteManifest | undefined, path: string) {
if (!site) return undefined;
const [projectSlug, pageSlug] = path.replace(/^\//, '').split('/');
const project = site.projects?.find((p) => p.slug === projectSlug);
const project = site.projects?.find((p) => p.slug === projectSlug || (!p.slug && !pageSlug));
if (!project) return undefined;
return project.pages.find(
(p) => (p as ManifestProjectItem).slug === pageSlug,
) as ManifestProjectItem;
return project.pages.find((p) => p.slug === (pageSlug || projectSlug));
}

function InternalLink({ url, children }: { url: string; children: React.ReactNode }) {
const Link = useLinkProvider();
const site = useSiteManifest();
const page = getPageInfo(site, url);
const urlbase = useUrlbase();
const baseurl = useBaseurl();
const skipPreview = !page || (!page.description && !page.thumbnail);
if (!page || skipPreview) {
return (
<Link to={withUrlbase(url, urlbase)} prefetch="intent">
<Link to={withBaseurl(url, baseurl)} prefetch="intent">
{children}
</Link>
);
Expand All @@ -52,7 +45,7 @@ function InternalLink({ url, children }: { url: string; children: React.ReactNod
/>
}
>
<Link to={withUrlbase(url, urlbase)} prefetch="intent">
<Link to={withBaseurl(url, baseurl)} prefetch="intent">
{children}
</Link>
</HoverPopover>
Expand Down
25 changes: 25 additions & 0 deletions packages/providers/src/baseurl.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React, { useContext } from 'react';

const BaseUrlContext = React.createContext<{
baseurl?: string;
}>({});

export function BaseUrlProvider({
baseurl,
children,
}: {
baseurl?: string;
children: React.ReactNode;
}) {
return <BaseUrlContext.Provider value={{ baseurl }}>{children}</BaseUrlContext.Provider>;
}

export function useBaseurl() {
const data = useContext(BaseUrlContext);
return data?.baseurl;
}

export function withBaseurl(url?: string, baseurl?: string) {
if (baseurl) return baseurl + url;
return url as string;
}
1 change: 1 addition & 0 deletions packages/providers/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from './hooks';
export * from './theme';
export * from './references';
export * from './baseurl';
export * from './ui';
export * from './site';
export * from './tabs';
Expand Down
15 changes: 1 addition & 14 deletions packages/providers/src/references.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,19 @@ import type { PageFrontmatter } from 'myst-frontmatter';
const ReferencesContext = React.createContext<{
frontmatter?: PageFrontmatter;
references?: References;
urlbase?: string;
}>({});

export function ReferencesProvider({
references,
frontmatter,
urlbase,
children,
}: {
frontmatter?: PageFrontmatter;
references?: References;
urlbase?: string;
children: React.ReactNode;
}) {
return (
<ReferencesContext.Provider value={{ references, frontmatter, urlbase }}>
<ReferencesContext.Provider value={{ references, frontmatter }}>
{children}
</ReferencesContext.Provider>
);
Expand All @@ -35,13 +32,3 @@ export function useFrontmatter() {
const data = useContext(ReferencesContext);
return data?.frontmatter;
}

export function useUrlbase() {
const data = useContext(ReferencesContext);
return data?.urlbase;
}

export function withUrlbase(url?: string, urlbase?: string) {
if (urlbase) return urlbase + url;
return url as string;
}
32 changes: 28 additions & 4 deletions packages/providers/src/theme.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,29 @@ export type LinkProps = {
title?: string;
className?: string;
children: React.ReactNode;
onClick?: () => void;
suppressHydrationWarning?: boolean;
};

export type NavLinkProps = Omit<LinkProps, 'className'> & {
className?: string | ((opts: { isActive: boolean }) => string);
};

export type Link = (props: LinkProps) => JSX.Element;
export type NavLink = (props: NavLinkProps) => JSX.Element;

function HtmlLink({ to, className, children, ...props }: LinkProps) {
return (
<a href={to} className={className} {...props}>
{children}
</a>
);
}

function HtmlLink({ to, className, children }: LinkProps) {
function HtmlNavLink({ to, className, children, ...props }: NavLinkProps) {
const staticClass = typeof className === 'function' ? className({ isActive: false }) : className;
return (
<a href={to} className={className}>
<a href={to} className={staticClass} {...props}>
{children}
</a>
);
Expand All @@ -33,6 +49,7 @@ type ThemeContextType = {
setTheme: (theme: Theme) => void;
renderers?: Record<string, NodeRenderer>;
Link?: Link;
NavLink?: NavLink;
};

const ThemeContext = React.createContext<ThemeContextType | undefined>(undefined);
Expand All @@ -45,11 +62,13 @@ export function ThemeProvider({
theme: startingTheme,
renderers,
Link,
NavLink,
}: {
children: React.ReactNode;
theme: Theme | null;
renderers?: Record<string, NodeRenderer>;
Link?: Link;
NavLink?: NavLink;
}) {
const [theme, setTheme] = React.useState<Theme | null>(() => {
if (startingTheme) {
Expand All @@ -74,9 +93,8 @@ export function ThemeProvider({
},
[theme],
);

return (
<ThemeContext.Provider value={{ theme, setTheme: nextTheme, renderers, Link }}>
<ThemeContext.Provider value={{ theme, setTheme: nextTheme, renderers, Link, NavLink }}>
{children}
</ThemeContext.Provider>
);
Expand Down Expand Up @@ -120,3 +138,9 @@ export function useLinkProvider(): Link {
const { Link } = context ?? {};
return Link ?? HtmlLink;
}

export function useNavLinkProvider(): NavLink {
const context = React.useContext(ThemeContext);
const { NavLink } = context ?? {};
return NavLink ?? HtmlNavLink;
}
2 changes: 1 addition & 1 deletion packages/site/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@

### Patch Changes

- a41df47: Update table of contents to allow not setting a urlbase
- a41df47: Update table of contents to allow not setting a baseurl
- @curvenote/site-common@0.0.6
- @myst-theme/providers@0.0.6

Expand Down
6 changes: 3 additions & 3 deletions packages/site/src/components/FooterLinksBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ import classNames from 'classnames';
import ArrowLeftIcon from '@heroicons/react/24/outline/ArrowLeftIcon';
import ArrowRightIcon from '@heroicons/react/24/outline/ArrowRightIcon';
import type { FooterLinks, NavigationLink } from '../types';
import { useLinkProvider, useUrlbase, withUrlbase } from '@myst-theme/providers';
import { useLinkProvider, useBaseurl, withBaseurl } from '@myst-theme/providers';

const FooterLink = ({ title, url, group, right }: NavigationLink & { right?: boolean }) => {
const urlbase = useUrlbase();
const baseurl = useBaseurl();
const Link = useLinkProvider();
return (
<Link
prefetch="intent"
className="group flex-1 p-4 block border font-normal hover:border-blue-600 dark:hover:border-blue-400 no-underline hover:text-blue-600 dark:hover:text-blue-400 text-gray-600 dark:text-gray-100 border-gray-200 dark:border-gray-500 rounded shadow-sm hover:shadow-lg dark:shadow-neutral-700"
to={withUrlbase(url, urlbase)}
to={withBaseurl(url, baseurl)}
>
<div className="flex align-middle h-full">
{right && (
Expand Down
21 changes: 13 additions & 8 deletions packages/site/src/components/Navigation/TableOfContents.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import React, { useEffect, useRef } from 'react';
import classNames from 'classnames';
import { NavLink, useParams, useLocation, useNavigation } from '@remix-run/react';
import { useLocation, useNavigation } from '@remix-run/react';
import type { SiteManifest } from 'myst-config';
import { useNavOpen, useSiteManifest, useUrlbase, withUrlbase } from '@myst-theme/providers';
import {
useNavLinkProvider,
useNavOpen,
useSiteManifest,
useBaseurl,
withBaseurl,
} from '@myst-theme/providers';
import { getProjectHeadings } from '../../loaders';
import type { Heading } from '../../types';

Expand All @@ -26,8 +32,9 @@ const HeadingLink = ({
children: React.ReactNode;
}) => {
const { pathname } = useLocation();
const NavLink = useNavLinkProvider();
const exact = pathname === path;
const urlbase = useUrlbase();
const baseurl = useBaseurl();
const [, setOpen] = useNavOpen();
return (
<NavLink
Expand All @@ -44,7 +51,7 @@ const HeadingLink = ({
!isActive,
})
}
to={withUrlbase(path, urlbase)}
to={withBaseurl(path, baseurl)}
suppressHydrationWarning // The pathname is not defined on the server always.
onClick={() => {
// Close the nav panel if it is open
Expand Down Expand Up @@ -141,10 +148,8 @@ export const TableOfContents = ({
const footerRef = useRef<HTMLDivElement>(null);
const [open] = useNavOpen();
const config = useSiteManifest();
const { folder, project } = useParams();
const resolvedProjectSlug = projectSlug || (folder ?? project);
if (!config) return null;
const headings = getProjectHeadings(config, resolvedProjectSlug, {
const headings = getProjectHeadings(config, projectSlug, {
addGroups: false,
});
useEffect(() => {
Expand Down Expand Up @@ -183,7 +188,7 @@ export const TableOfContents = ({
aria-label="Table of Contents"
className="flex-grow overflow-y-auto transition-opacity mt-6 pb-3 ml-3 xl:ml-0 mr-3"
>
<Headings folder={resolvedProjectSlug} headings={headings} sections={config?.projects} />
<Headings folder={projectSlug} headings={headings} sections={config?.projects} />
</nav>
{footer && (
<div
Expand Down
Loading

0 comments on commit b59e1a3

Please sign in to comment.