@myst-theme/site 0.5.0 → 0.5.2

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.5.0",
3
+ "version": "0.5.2",
4
4
  "main": "./src/index.ts",
5
5
  "types": "./src/index.ts",
6
6
  "files": [
@@ -16,22 +16,22 @@
16
16
  "dependencies": {
17
17
  "@headlessui/react": "^1.7.15",
18
18
  "@heroicons/react": "^2.0.18",
19
- "@myst-theme/diagrams": "^0.5.0",
20
- "@myst-theme/frontmatter": "^0.5.0",
21
- "@myst-theme/jupyter": "^0.5.0",
22
- "@myst-theme/common": "^0.5.0",
23
- "@myst-theme/providers": "^0.5.0",
19
+ "@myst-theme/diagrams": "^0.5.2",
20
+ "@myst-theme/frontmatter": "^0.5.2",
21
+ "@myst-theme/jupyter": "^0.5.2",
22
+ "@myst-theme/common": "^0.5.2",
23
+ "@myst-theme/providers": "^0.5.2",
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.5.0",
30
- "myst-to-react": "^0.5.0",
29
+ "myst-demo": "^0.5.2",
30
+ "myst-to-react": "^0.5.2",
31
31
  "nbtx": "^0.2.3",
32
32
  "node-cache": "^5.1.2",
33
33
  "node-fetch": "^2.6.11",
34
- "thebe-react": "^0.3.0",
34
+ "thebe-react": "^0.3.2",
35
35
  "unist-util-select": "^4.0.1"
36
36
  },
37
37
  "peerDependencies": {
@@ -0,0 +1,40 @@
1
+ import type { GenericParent } from 'myst-common';
2
+ import { ContentBlocks } from './ContentBlocks';
3
+ import classNames from 'classnames';
4
+
5
+ export function Abstract({ content }: { content: GenericParent }) {
6
+ if (!content) return null;
7
+ return (
8
+ <>
9
+ <span className="mb-3 font-semibold">Abstract</span>
10
+ <div className="px-6 py-1 mb-3 rounded-sm bg-slate-50 dark:bg-slate-800">
11
+ <ContentBlocks mdast={content} className="col-body" />
12
+ </div>
13
+ </>
14
+ );
15
+ }
16
+
17
+ export function Keywords({
18
+ keywords,
19
+ hideKeywords,
20
+ }: {
21
+ keywords?: string[];
22
+ hideKeywords?: boolean;
23
+ }) {
24
+ if (hideKeywords || !keywords || keywords.length === 0) return null;
25
+ return (
26
+ <div className="mb-10">
27
+ <span className="mr-2 font-semibold">Keywords:</span>
28
+ {keywords.map((k, i) => (
29
+ <span
30
+ key={k}
31
+ className={classNames({
32
+ "after:content-[','] after:mr-1": i < keywords.length - 1,
33
+ })}
34
+ >
35
+ {k}
36
+ </span>
37
+ ))}
38
+ </div>
39
+ );
40
+ }
@@ -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
+ }
@@ -9,15 +9,29 @@ import { useGridSystemProvider } from '@myst-theme/providers';
9
9
  import classNames from 'classnames';
10
10
  import type { PageFrontmatter } from 'myst-frontmatter';
11
11
 
12
- export function ArticleHeader({ frontmatter }: { frontmatter: PageFrontmatter }) {
12
+ export function ArticleHeader({
13
+ frontmatter,
14
+ children,
15
+ className,
16
+ }: {
17
+ frontmatter: PageFrontmatter;
18
+ children?: React.ReactNode;
19
+ className?: string;
20
+ }) {
13
21
  const grid = useGridSystemProvider();
14
22
  const { subject, venue, biblio, ...rest } = frontmatter ?? {};
15
23
  return (
16
24
  <header
17
- className={classNames('w-full relative pt-[2rem] col-screen article', grid, 'subgrid-gap', {
18
- 'bg-no-repeat bg-cover bg-top': frontmatter?.banner,
19
- 'pb-[4rem] min-h-[300px]': frontmatter?.banner,
20
- })}
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
+ )}
21
35
  style={{
22
36
  backgroundImage: frontmatter?.banner ? `url(${frontmatter?.banner})` : undefined,
23
37
  }}
@@ -54,6 +68,7 @@ export function ArticleHeader({ frontmatter }: { frontmatter: PageFrontmatter })
54
68
  hideBadges
55
69
  hideExports
56
70
  />
71
+ {children}
57
72
  </header>
58
73
  );
59
74
  }
@@ -140,7 +140,7 @@ export const TableOfContents = ({
140
140
  footer,
141
141
  }: {
142
142
  top?: number;
143
- tocRef?: React.RefObject<HTMLDivElement>;
143
+ tocRef?: React.RefObject<HTMLElement>;
144
144
  projectSlug?: string;
145
145
  footer?: React.ReactNode;
146
146
  }) => {
@@ -162,7 +162,7 @@ export const TableOfContents = ({
162
162
  if (!headings) return null;
163
163
  return (
164
164
  <div
165
- ref={tocRef}
165
+ ref={tocRef as any}
166
166
  className={classNames(
167
167
  'fixed',
168
168
  `xl:${grid}`, // for example, xl:article-grid
@@ -1,9 +1,10 @@
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
6
  export { ArticleHeader } from './Headers';
7
+ export { Abstract, Keywords } from './Abstract';
7
8
  export { ExternalOrInternalLink } from './ExternalOrInternalLink';
8
9
  export * from './Navigation';
9
10
  export { renderers } from './renderers';
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { ReferencesProvider } from '@myst-theme/providers';
3
- import { Bibliography, ContentBlocks, FooterLinksBlock } from '../components';
3
+ import { Abstract, Bibliography, ContentBlocks, FooterLinksBlock, Keywords } from '../components';
4
4
  import { ErrorDocumentNotFound } from './ErrorDocumentNotFound';
5
5
  import { ErrorProjectNotFound } from './ErrorProjectNotFound';
6
6
  import type { PageLoader } from '@myst-theme/common';
@@ -17,7 +17,6 @@ import {
17
17
  ErrorTray,
18
18
  } from '@myst-theme/jupyter';
19
19
  import { FrontmatterBlock } from '@myst-theme/frontmatter';
20
- import classNames from 'classnames';
21
20
 
22
21
  export const ArticlePage = React.memo(function ({
23
22
  article,
@@ -61,29 +60,8 @@ export const ArticlePage = React.memo(function ({
61
60
  )}
62
61
  {canCompute && article.kind === SourceFileKind.Notebook && <NotebookToolbar showLaunch />}
63
62
  <ErrorTray pageSlug={article.slug} />
64
- {abstract && (
65
- <>
66
- <span className="font-semibold">Abstract</span>
67
- <div className="px-6 py-1 m-3 rounded-sm bg-slate-50 dark:bg-slate-800">
68
- <ContentBlocks mdast={abstract as GenericParent} className="col-body" />
69
- </div>
70
- {!hideKeywords && keywords.length > 0 && (
71
- <div className="mb-10">
72
- <span className="mr-2 font-semibold">Keywords:</span>
73
- {keywords.map((k, i) => (
74
- <span
75
- key={k}
76
- className={classNames({
77
- "after:content-[','] after:mr-1": i < keywords.length - 1,
78
- })}
79
- >
80
- {k}
81
- </span>
82
- ))}
83
- </div>
84
- )}
85
- </>
86
- )}
63
+ <Abstract content={abstract as GenericParent} />
64
+ {abstract && <Keywords keywords={keywords} hideKeywords={hideKeywords} />}
87
65
  <ContentBlocks pageKind={article.kind} mdast={tree as GenericParent} />
88
66
  <Bibliography />
89
67
  <ConnectionStatusTray />