Skip to content

Commit

Permalink
🗂 Support url slugs with multiple path segments (#489)
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 24, 2024
1 parent 8971790 commit 653bd6c
Show file tree
Hide file tree
Showing 22 changed files with 150 additions and 100 deletions.
8 changes: 8 additions & 0 deletions .changeset/early-plums-double.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@myst-theme/common': patch
'@myst-theme/article': patch
'@myst-theme/site': patch
'@myst-theme/book': patch
---

Support url slugs with multiple path segments
88 changes: 44 additions & 44 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions packages/common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
"build": "npm-run-all -l clean -p build:esm"
},
"dependencies": {
"myst-common": "^1.7.2",
"myst-config": "^1.7.2",
"myst-spec-ext": "^1.7.2",
"myst-common": "^1.7.3",
"myst-config": "^1.7.3",
"myst-spec-ext": "^1.7.3",
"nbtx": "^0.2.3",
"unist-util-select": "^4.0.3"
}
Expand Down
4 changes: 3 additions & 1 deletion packages/common/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { SiteManifest } from 'myst-config';
import { selectAll } from 'unist-util-select';
import type { Image as ImageSpec, Link as LinkSpec } from 'myst-spec';
import type { FooterLinks, Heading, NavigationLink, PageLoader } from './types.js';
import { slugToUrl } from 'myst-common';

type Image = ImageSpec & { urlOptimized?: string };
type Link = LinkSpec & { static?: boolean };
Expand Down Expand Up @@ -40,9 +41,10 @@ export function getProjectHeadings(
},
...project.pages.map((p) => {
if (!('slug' in p)) return p;
const slug = slugToUrl(p.slug);
return {
...p,
path: projectSlug && project.slug ? `/${project.slug}/${p.slug}` : `/${p.slug}`,
path: projectSlug && project.slug ? `/${project.slug}/${slug}` : `/${slug}`,
};
}),
];
Expand Down
8 changes: 4 additions & 4 deletions packages/jupyter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@
"buffer": "^6.0.3",
"classnames": "^2.5.1",
"jupyterlab-plotly": "^5.24.0",
"myst-common": "^1.7.2",
"myst-config": "^1.7.2",
"myst-frontmatter": "^1.7.2",
"myst-common": "^1.7.3",
"myst-config": "^1.7.3",
"myst-frontmatter": "^1.7.3",
"myst-spec": "^0.0.5",
"myst-spec-ext": "^1.7.2",
"myst-spec-ext": "^1.7.3",
"myst-to-react": "^0.13.2",
"nanoid": "^4.0.2",
"nbtx": "^0.2.3",
Expand Down
8 changes: 4 additions & 4 deletions packages/myst-demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,23 @@
"@heroicons/react": "^2.0.18",
"classnames": "^2.3.2",
"js-yaml": "^4.1.0",
"myst-common": "^1.7.2",
"myst-config": "^1.7.2",
"myst-common": "^1.7.3",
"myst-config": "^1.7.3",
"myst-directives": "^1.5.7",
"myst-ext-card": "^1.0.9",
"myst-ext-exercise": "^1.0.8",
"myst-ext-grid": "^1.0.8",
"myst-ext-proof": "^1.0.11",
"myst-ext-tabs": "^1.0.8",
"myst-frontmatter": "^1.7.2",
"myst-frontmatter": "^1.7.3",
"myst-parser": "^1.5.7",
"myst-spec": "^0.0.5",
"myst-to-docx": "^1.0.12",
"myst-to-html": "^1.5.7",
"myst-to-jats": "^1.0.30",
"myst-to-react": "^0.13.2",
"myst-to-tex": "^1.0.38",
"myst-to-typst": "^0.0.24",
"myst-to-typst": "^0.0.25",
"myst-transforms": "^1.3.26",
"unified": "^10.1.2",
"unist-util-remove": "^4.0.0",
Expand Down
4 changes: 2 additions & 2 deletions packages/myst-to-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
"@radix-ui/react-hover-card": "^1.0.6",
"buffer": "^6.0.3",
"classnames": "^2.3.2",
"myst-common": "^1.7.2",
"myst-config": "^1.7.2",
"myst-common": "^1.7.3",
"myst-config": "^1.7.3",
"myst-spec": "^0.0.5",
"nanoid": "^4.0.2",
"react-syntax-highlighter": "15.5.0",
Expand Down
6 changes: 3 additions & 3 deletions packages/providers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
"peerDependencies": {
"@types/react": "^16.8 || ^17.0 || ^18.0",
"@types/react-dom": "^16.8 || ^17.0 || ^18.0",
"myst-common": "^1.7.2",
"myst-config": "^1.7.2",
"myst-frontmatter": "^1.7.2",
"myst-common": "^1.7.3",
"myst-config": "^1.7.3",
"myst-frontmatter": "^1.7.3",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
Expand Down
6 changes: 3 additions & 3 deletions packages/site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@
"@radix-ui/react-visually-hidden": "^1.1.0",
"classnames": "^2.3.2",
"lodash.throttle": "^4.1.1",
"myst-common": "^1.7.2",
"myst-config": "^1.7.2",
"myst-common": "^1.7.3",
"myst-config": "^1.7.3",
"myst-demo": "^0.13.2",
"myst-spec-ext": "^1.7.2",
"myst-spec-ext": "^1.7.3",
"myst-to-react": "^0.13.2",
"nbtx": "^0.2.3",
"node-cache": "^5.1.2",
Expand Down
2 changes: 1 addition & 1 deletion packages/site/src/components/Navigation/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export const ConfigurablePrimaryNavigation = ({

if (children)
console.warn(
`Including children in Navigation can break keyboard accessbility and is deprecated. Please move children to the page component.`,
`Including children in Navigation can break keyboard accessibility and is deprecated. Please move children to the page component.`,
);

// the logic on the following line looks wrong, this will return `null` or `<></>`
Expand Down
10 changes: 8 additions & 2 deletions packages/site/src/components/Navigation/TableOfContentsItems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,16 @@ function nestToc(toc: Heading[]): NestedHeading[] {
return items;
}

function pathnameMatchesHeading(pathname: string, heading: Heading, baseurl?: string) {
const headingPath = withBaseurl(heading.path, baseurl);
if (pathname && headingPath === `${pathname}/index`) return true;
return headingPath === pathname;
}

function childrenOpen(headings: NestedHeading[], pathname: string, baseurl?: string): string[] {
return headings
.map((heading) => {
if (withBaseurl(heading.path, baseurl) === pathname) return [heading.id];
if (pathnameMatchesHeading(pathname, heading, baseurl)) return [heading.id];
const open = childrenOpen(heading.children, pathname, baseurl);
if (open.length === 0) return [];
return [heading.id, ...open];
Expand Down Expand Up @@ -110,7 +116,7 @@ const NestedToc = ({ heading }: { heading: NestedHeading }) => {
useEffect(() => {
if (nav.state === 'idle') setOpen(startOpen);
}, [nav.state]);
const exact = pathname === withBaseurl(heading.path, baseurl);
const exact = pathnameMatchesHeading(pathname, heading, baseurl);
if (!heading.children || heading.children.length === 0) {
return (
<LinkItem
Expand Down
3 changes: 2 additions & 1 deletion packages/site/src/seo/sitemap.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { slugToUrl } from 'myst-common';
import type { SiteManifest } from 'myst-config';

type ManifestProjectItem = Required<SiteManifest>['projects'][0]['pages'][0];
Expand Down Expand Up @@ -148,7 +149,7 @@ export function getSiteSlugs(
const projectSlug = project.slug ? `/${project.slug}` : '';
const pages = project.pages
.filter((page): page is ManifestProjectItem => 'slug' in page)
.map((page) => `${baseurl}${projectSlug}/${page.slug}`);
.map((page) => `${baseurl}${projectSlug}/${slugToUrl(page.slug)}`);
if (opts?.excludeIndex) return [...pages];
return [
opts?.explicitIndex
Expand Down
11 changes: 6 additions & 5 deletions themes/article/app/routes/$.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,15 @@ export const meta: V2_MetaFunction<typeof loader> = ({ data, matches, location }
export const links: LinksFunction = () => [KatexCSS];

export const loader: LoaderFunction = async ({ params, request }) => {
const [first, second] = new URL(request.url).pathname.slice(1).split('/');
const projectName = second ? first : undefined;
const slug = second || first;
const [first, ...rest] = new URL(request.url).pathname.slice(1).split('/');
const config = await getConfig();
const project = getProject(config, projectName ?? slug);
const project = getProject(config, first);
const projectName = project?.slug === first ? first : undefined;
const slugParts = projectName ? rest : [first, ...rest];
const slug = slugParts.length ? slugParts.join('.') : undefined;
const flat = isFlatSite(config);
const page = await getPage(request, {
project: flat ? projectName : projectName ?? slug,
project: flat ? projectName : (projectName ?? slug),
slug: flat ? slug : projectName ? slug : undefined,
redirect: process.env.MODE === 'static' ? false : true,
});
Expand Down
Loading

0 comments on commit 653bd6c

Please sign in to comment.