@myst-theme/site 0.4.2 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myst-theme/site",
3
- "version": "0.4.2",
3
+ "version": "0.5.1",
4
4
  "main": "./src/index.ts",
5
5
  "types": "./src/index.ts",
6
6
  "files": [
@@ -16,18 +16,18 @@
16
16
  "dependencies": {
17
17
  "@headlessui/react": "^1.7.15",
18
18
  "@heroicons/react": "^2.0.18",
19
- "@myst-theme/diagrams": "^0.4.2",
20
- "@myst-theme/frontmatter": "^0.4.2",
21
- "@myst-theme/jupyter": "^0.4.2",
22
- "@myst-theme/common": "^0.4.2",
23
- "@myst-theme/providers": "^0.4.2",
19
+ "@myst-theme/diagrams": "^0.5.1",
20
+ "@myst-theme/frontmatter": "^0.5.1",
21
+ "@myst-theme/jupyter": "^0.5.1",
22
+ "@myst-theme/common": "^0.5.1",
23
+ "@myst-theme/providers": "^0.5.1",
24
24
  "classnames": "^2.3.2",
25
25
  "lodash.throttle": "^4.1.1",
26
26
  "myst-common": "^1.1.1",
27
27
  "myst-spec-ext": "^1.1.1",
28
28
  "myst-config": "^1.1.1",
29
- "myst-demo": "^0.4.2",
30
- "myst-to-react": "^0.4.2",
29
+ "myst-demo": "^0.5.1",
30
+ "myst-to-react": "^0.5.1",
31
31
  "nbtx": "^0.2.3",
32
32
  "node-cache": "^5.1.2",
33
33
  "node-fetch": "^2.6.11",
@@ -1,17 +1,19 @@
1
- import { useReferences } from '@myst-theme/providers';
1
+ import { useGridSystemProvider, useReferences } from '@myst-theme/providers';
2
+ import classNames from 'classnames';
2
3
  import { useState } from 'react';
3
4
 
4
5
  const HIDE_OVER_N_REFERENCES = 5;
5
6
 
6
7
  export function Bibliography() {
7
8
  const references = useReferences();
9
+ const grid = useGridSystemProvider();
8
10
  const { order, data } = references?.cite ?? {};
9
11
  const filtered = order?.filter((l) => l);
10
12
  const [hidden, setHidden] = useState(true);
11
13
  if (!filtered || !data || filtered.length === 0) return null;
12
14
  const refs = hidden ? filtered.slice(0, HIDE_OVER_N_REFERENCES) : filtered;
13
15
  return (
14
- <section className="article-grid article-subgrid-gap col-screen">
16
+ <section className={classNames(grid, 'subgrid-gap col-screen')}>
15
17
  <div>
16
18
  {filtered.length > HIDE_OVER_N_REFERENCES && (
17
19
  <button
@@ -7,6 +7,7 @@ import {
7
7
  NotebookRunCell,
8
8
  NotebookRunCellSpinnerOnly,
9
9
  } from '@myst-theme/jupyter';
10
+ import { useGridSystemProvider } from '@myst-theme/providers';
10
11
 
11
12
  function isACodeCell(node: GenericParent) {
12
13
  return (
@@ -30,7 +31,8 @@ function Block({
30
31
  node: GenericParent;
31
32
  className?: string;
32
33
  }) {
33
- const subGrid = 'article-grid article-subgrid-gap col-screen';
34
+ const grid = useGridSystemProvider();
35
+ const subGrid = `${grid} subgrid-gap col-screen`;
34
36
  const dataClassName = typeof node.data?.class === 'string' ? node.data?.class : undefined;
35
37
  // Hide the subgrid if either the dataClass or the className exists and includes `col-`
36
38
  const noSubGrid =
@@ -1,7 +1,14 @@
1
+ import {
2
+ useBaseurl,
3
+ useNavLinkProvider,
4
+ useSiteManifest,
5
+ withBaseurl,
6
+ } from '@myst-theme/providers';
1
7
  import { useNavigation } from '@remix-run/react';
2
8
  import classNames from 'classnames';
3
9
  import throttle from 'lodash.throttle';
4
- import { useCallback, useEffect, useRef, useState } from 'react';
10
+ import React, { useCallback, useEffect, useRef, useState } from 'react';
11
+ import DocumentChartBarIcon from '@heroicons/react/24/outline/DocumentChartBarIcon';
5
12
 
6
13
  const SELECTOR = [1, 2, 3, 4].map((n) => `main h${n}`).join(', ');
7
14
  const HIGHLIGHT_CLASS = 'highlight';
@@ -180,13 +187,15 @@ const useIntersectionObserver = (highlight: () => void, onScreen: Set<HTMLHeadin
180
187
  return { observer };
181
188
  };
182
189
 
183
- export function useOutlineHeight<T extends HTMLElement = HTMLElement>() {
190
+ export function useOutlineHeight<T extends HTMLElement = HTMLElement>(
191
+ existingContainer?: React.RefObject<T>,
192
+ ) {
184
193
  const container = useRef<T>(null);
185
194
  const outline = useRef<T>(null);
186
195
  const transitionState = useNavigation().state;
187
196
  const setHeight = () => {
188
197
  if (!container.current || !outline.current) return;
189
- const height = container.current.offsetHeight - window.scrollY;
198
+ const height = container.current.offsetHeight - window.scrollY + container.current.offsetTop;
190
199
  outline.current.style.display = height < 50 ? 'none' : '';
191
200
  outline.current.style.height = height > window.innerHeight ? '' : `${height}px`;
192
201
  outline.current.style.opacity = height && height > 300 ? '' : '0';
@@ -201,6 +210,11 @@ export function useOutlineHeight<T extends HTMLElement = HTMLElement>() {
201
210
  window.removeEventListener('scroll', handleScroll);
202
211
  };
203
212
  }, [container.current, outline.current, transitionState]);
213
+
214
+ useEffect(() => {
215
+ if (!existingContainer || !existingContainer.current) return;
216
+ (container as any).current = existingContainer.current;
217
+ }, [existingContainer?.current]);
204
218
  return { container, outline };
205
219
  }
206
220
 
@@ -209,16 +223,18 @@ export const DocumentOutline = ({
209
223
  top,
210
224
  className,
211
225
  selector = SELECTOR,
226
+ children,
212
227
  }: {
213
228
  outlineRef?: React.RefObject<HTMLElement>;
214
229
  top?: number;
215
230
  height?: number;
216
231
  className?: string;
217
232
  selector?: string;
233
+ children?: React.ReactNode;
218
234
  }) => {
219
235
  const { activeId, headings, highlight } = useHeaders(selector);
220
236
  if (headings.length <= 1 || !onClient) {
221
- return <nav suppressHydrationWarning style={{ display: 'none' }} />;
237
+ return <nav suppressHydrationWarning>{children}</nav>;
222
238
  }
223
239
  return (
224
240
  <nav
@@ -238,6 +254,44 @@ export const DocumentOutline = ({
238
254
  In this article
239
255
  </div>
240
256
  <Headings headings={headings} activeId={activeId} highlight={highlight} selector={selector} />
257
+ {children}
241
258
  </nav>
242
259
  );
243
260
  };
261
+
262
+ export function SupportingDocuments() {
263
+ const { projects } = useSiteManifest() ?? {};
264
+ const NavLink = useNavLinkProvider();
265
+ const baseurl = useBaseurl();
266
+ const pages = projects?.[0]?.pages;
267
+ if (!pages || pages.length === 0) return null;
268
+ return (
269
+ <>
270
+ <div className="my-4 text-sm leading-6 uppercase text-slate-900 dark:text-slate-100">
271
+ Supporting Documents
272
+ </div>
273
+ <ul className="flex flex-col gap-2 pl-0 text-sm leading-6 list-none text-slate-700 dark:text-slate-300">
274
+ {pages
275
+ .filter((p) => 'slug' in p)
276
+ .map((p) => {
277
+ return (
278
+ <li key={p.slug}>
279
+ <NavLink
280
+ to={withBaseurl(`/${p.slug}#main`, baseurl)}
281
+ prefetch="intent"
282
+ className={({ isActive }) =>
283
+ classNames('no-underline flex self-center', {
284
+ 'text-blue-600': isActive,
285
+ })
286
+ }
287
+ >
288
+ <DocumentChartBarIcon className="inline h-5 pr-2 shrink-0" />
289
+ <span>{p.short_title || p.title}</span>
290
+ </NavLink>
291
+ </li>
292
+ );
293
+ })}
294
+ </ul>
295
+ </>
296
+ );
297
+ }
@@ -0,0 +1,74 @@
1
+ import {
2
+ FrontmatterBlock,
3
+ GitHubLink,
4
+ Journal,
5
+ LicenseBadges,
6
+ OpenAccessBadge,
7
+ } from '@myst-theme/frontmatter';
8
+ import { useGridSystemProvider } from '@myst-theme/providers';
9
+ import classNames from 'classnames';
10
+ import type { PageFrontmatter } from 'myst-frontmatter';
11
+
12
+ export function ArticleHeader({
13
+ frontmatter,
14
+ children,
15
+ className,
16
+ }: {
17
+ frontmatter: PageFrontmatter;
18
+ children?: React.ReactNode;
19
+ className?: string;
20
+ }) {
21
+ const grid = useGridSystemProvider();
22
+ const { subject, venue, biblio, ...rest } = frontmatter ?? {};
23
+ return (
24
+ <header
25
+ className={classNames(
26
+ 'w-full relative pt-[2rem] col-screen article',
27
+ grid,
28
+ 'subgrid-gap',
29
+ {
30
+ 'bg-no-repeat bg-cover bg-top': frontmatter?.banner,
31
+ 'pb-[4rem]': frontmatter?.banner,
32
+ },
33
+ className,
34
+ )}
35
+ style={{
36
+ backgroundImage: frontmatter?.banner ? `url(${frontmatter?.banner})` : undefined,
37
+ }}
38
+ >
39
+ {frontmatter?.banner && (
40
+ <div className="absolute border-white shadow-2xl bg-white/80 dark:bg-black/80 backdrop-blur top-[2rem] h-[calc(100%-4rem)] w-full col-screen md:col-screen-inset pointer-events-none"></div>
41
+ )}
42
+ <div
43
+ className={classNames('flex w-full align-middle z-10 py-2 mb-[1rem] text-sm', {
44
+ 'col-screen md:col-screen-inset px-4': frontmatter?.banner,
45
+ 'col-page-right': !frontmatter?.banner,
46
+ 'bg-white/80 dark:bg-black/80': frontmatter?.banner,
47
+ })}
48
+ >
49
+ {subject && (
50
+ <div
51
+ className={classNames('flex-none pr-2 smallcaps', {
52
+ 'border-r mr-2': venue,
53
+ })}
54
+ >
55
+ {subject}
56
+ </div>
57
+ )}
58
+ <Journal venue={venue} biblio={biblio} />
59
+ <div className="flex-grow"></div>
60
+ <LicenseBadges license={frontmatter?.license} />
61
+ <OpenAccessBadge open_access={frontmatter?.open_access} />
62
+ <GitHubLink github={frontmatter?.github} />
63
+ </div>
64
+ <FrontmatterBlock
65
+ frontmatter={rest}
66
+ authorStyle="list"
67
+ className={classNames('z-10', { 'pt-4': frontmatter?.banner })}
68
+ hideBadges
69
+ hideExports
70
+ />
71
+ {children}
72
+ </header>
73
+ );
74
+ }
@@ -8,6 +8,7 @@ import {
8
8
  useSiteManifest,
9
9
  useBaseurl,
10
10
  withBaseurl,
11
+ useGridSystemProvider,
11
12
  } from '@myst-theme/providers';
12
13
  import { getProjectHeadings, type Heading } from '@myst-theme/common';
13
14
 
@@ -139,10 +140,11 @@ export const TableOfContents = ({
139
140
  footer,
140
141
  }: {
141
142
  top?: number;
142
- tocRef?: React.RefObject<HTMLDivElement>;
143
+ tocRef?: React.RefObject<HTMLElement>;
143
144
  projectSlug?: string;
144
145
  footer?: React.ReactNode;
145
146
  }) => {
147
+ const grid = useGridSystemProvider();
146
148
  const footerRef = useRef<HTMLDivElement>(null);
147
149
  const [open] = useNavOpen();
148
150
  const config = useSiteManifest();
@@ -160,9 +162,11 @@ export const TableOfContents = ({
160
162
  if (!headings) return null;
161
163
  return (
162
164
  <div
163
- ref={tocRef}
165
+ ref={tocRef as any}
164
166
  className={classNames(
165
- 'fixed xl:article-grid article-grid-gap xl:w-screen xl:pointer-events-none overflow-auto max-xl:min-w-[300px]',
167
+ 'fixed',
168
+ `xl:${grid}`, // for example, xl:article-grid
169
+ 'grid-gap xl:w-screen xl:pointer-events-none overflow-auto max-xl:min-w-[300px]',
166
170
  { hidden: !open },
167
171
  { 'z-30': open },
168
172
  )}
@@ -1,8 +1,9 @@
1
1
  export { ContentBlocks } from './ContentBlocks';
2
- export { DocumentOutline, useOutlineHeight } from './DocumentOutline';
2
+ export { DocumentOutline, useOutlineHeight, SupportingDocuments } from './DocumentOutline';
3
3
  export { FooterLinksBlock } from './FooterLinksBlock';
4
4
  export { ContentReload } from './ContentReload';
5
5
  export { Bibliography } from './Bibliography';
6
+ export { ArticleHeader } from './Headers';
6
7
  export { ExternalOrInternalLink } from './ExternalOrInternalLink';
7
8
  export * from './Navigation';
8
9
  export { renderers } from './renderers';
@@ -92,7 +92,7 @@ export function AppCatchBoundary() {
92
92
  return (
93
93
  <Document theme={Theme.light}>
94
94
  <article className="article">
95
- <main className="article-grid article-subgrid-gap col-screen">
95
+ <main className="article-grid subgrid-gap col-screen">
96
96
  <Error404 />
97
97
  </main>
98
98
  </article>