@myst-theme/site 0.3.8 → 0.4.0

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.3.8",
3
+ "version": "0.4.0",
4
4
  "main": "./src/index.ts",
5
5
  "types": "./src/index.ts",
6
6
  "files": [
@@ -16,16 +16,17 @@
16
16
  "dependencies": {
17
17
  "@headlessui/react": "^1.7.15",
18
18
  "@heroicons/react": "^2.0.18",
19
- "@myst-theme/diagrams": "^0.3.8",
20
- "@myst-theme/frontmatter": "^0.3.8",
21
- "@myst-theme/jupyter": "^0.3.8",
22
- "@myst-theme/providers": "^0.3.8",
19
+ "@myst-theme/diagrams": "^0.4.0",
20
+ "@myst-theme/frontmatter": "^0.4.0",
21
+ "@myst-theme/jupyter": "^0.4.0",
22
+ "@myst-theme/providers": "^0.4.0",
23
23
  "classnames": "^2.3.2",
24
24
  "lodash.throttle": "^4.1.1",
25
- "myst-common": "^1.0.1",
26
- "myst-config": "^1.0.0",
27
- "myst-demo": "^0.3.8",
28
- "myst-to-react": "^0.3.8",
25
+ "myst-common": "^1.1.0",
26
+ "myst-spec-ext": "^1.1.0",
27
+ "myst-config": "^1.1.0",
28
+ "myst-demo": "^0.4.0",
29
+ "myst-to-react": "^0.4.0",
29
30
  "nbtx": "^0.2.3",
30
31
  "node-cache": "^5.1.2",
31
32
  "node-fetch": "^2.6.11",
@@ -1,7 +1,6 @@
1
- import { useParse, DEFAULT_RENDERERS } from 'myst-to-react';
2
- import { SourceFileKind } from 'myst-common';
1
+ import { MyST } from 'myst-to-react';
2
+ import { SourceFileKind } from 'myst-spec-ext';
3
3
  import type { GenericParent } from 'myst-common';
4
- import { useNodeRenderers } from '@myst-theme/providers';
5
4
  import classNames from 'classnames';
6
5
  import {
7
6
  NotebookClearCell,
@@ -31,8 +30,6 @@ function Block({
31
30
  node: GenericParent;
32
31
  className?: string;
33
32
  }) {
34
- const renderers = useNodeRenderers() ?? DEFAULT_RENDERERS;
35
- const children = useParse(node, renderers);
36
33
  const subGrid = 'article-grid article-subgrid-gap col-screen';
37
34
  const dataClassName = typeof node.data?.class === 'string' ? node.data?.class : undefined;
38
35
  // Hide the subgrid if either the dataClass or the className exists and includes `col-`
@@ -40,7 +37,7 @@ function Block({
40
37
  (dataClassName && dataClassName.includes('col-')) || (className && className.includes('col-'));
41
38
  return (
42
39
  <div
43
- key={id}
40
+ key={`block-${id}`}
44
41
  id={id}
45
42
  className={classNames('relative group/block', className, dataClassName, {
46
43
  [subGrid]: !noSubGrid,
@@ -61,7 +58,7 @@ function Block({
61
58
  </div>
62
59
  </>
63
60
  )}
64
- {children}
61
+ <MyST ast={node.children} />
65
62
  </div>
66
63
  );
67
64
  }
@@ -26,7 +26,7 @@ type Props = {
26
26
  * scrollIntoView is used to ensure that when a user clicks on an item, it will smoothly scroll.
27
27
  */
28
28
  const Headings = ({ headings, activeId, highlight, selector }: Props) => (
29
- <ul className="text-sm text-slate-400 leading-6">
29
+ <ul className="text-sm leading-6 text-slate-400">
30
30
  {headings.map((heading) => (
31
31
  <li
32
32
  key={heading.id}
@@ -43,7 +43,7 @@ const Headings = ({ headings, activeId, highlight, selector }: Props) => (
43
43
  'text-slate-500 dark:text-slate-300': heading.level >= 3 && heading.id !== activeId,
44
44
  'text-blue-600 dark:text-white font-bold': heading.id === activeId,
45
45
  'pr-2': heading.id !== activeId, // Allows for bold to change length
46
- 'pl-2': heading.level === 2,
46
+ 'pl-2': heading.level === 1 || heading.level === 2,
47
47
  'pl-4': heading.level === 3,
48
48
  'pl-8 text-xs': heading.level === 4,
49
49
  'pl-10 text-xs font-light': heading.level === 5,
@@ -86,11 +86,14 @@ function useHeaders(selector: string) {
86
86
 
87
87
  const highlight = useCallback(() => {
88
88
  const current = [...onScreen.current];
89
- const highlighted = current.reduce((a, b) => {
90
- if (a) return a;
91
- if (b.classList.contains('highlight')) return b.id;
92
- return null;
93
- }, null as string | null);
89
+ const highlighted = current.reduce(
90
+ (a, b) => {
91
+ if (a) return a;
92
+ if (b.classList.contains('highlight')) return b.id;
93
+ return null;
94
+ },
95
+ null as string | null,
96
+ );
94
97
  const active = [...onScreen.current].sort((a, b) => a.offsetTop - b.offsetTop)[0];
95
98
  if (highlighted || active) setActiveId(highlighted || active.id);
96
99
  }, []);
@@ -156,9 +159,6 @@ const useIntersectionObserver = (highlight: () => void, onScreen: Set<HTMLHeadin
156
159
  return { observer };
157
160
  };
158
161
 
159
- const DOC_OUTLINE_CLASS =
160
- 'fixed bottom-0 right-[max(0px,calc(50%-45rem))] w-[14rem] lg:w-[18rem] py-10 px-4 lg:px-8 overflow-y-auto hidden lg:block';
161
-
162
162
  export function useOutlineHeight<T extends HTMLElement = HTMLElement>() {
163
163
  const container = useRef<T>(null);
164
164
  const outline = useRef<T>(null);
@@ -186,7 +186,7 @@ export function useOutlineHeight<T extends HTMLElement = HTMLElement>() {
186
186
  export const DocumentOutline = ({
187
187
  outlineRef,
188
188
  top,
189
- className = DOC_OUTLINE_CLASS,
189
+ className,
190
190
  selector = SELECTOR,
191
191
  }: {
192
192
  outlineRef?: React.RefObject<HTMLElement>;
@@ -204,7 +204,7 @@ export const DocumentOutline = ({
204
204
  ref={outlineRef}
205
205
  aria-label="Document Outline"
206
206
  className={classNames(
207
- 'not-prose overflow-y-auto hidden',
207
+ 'not-prose overflow-y-auto',
208
208
  'transition-opacity duration-700', // Animation on load
209
209
  className,
210
210
  )}
@@ -213,7 +213,7 @@ export const DocumentOutline = ({
213
213
  maxHeight: `calc(100vh - ${(top ?? 0) + 20}px)`,
214
214
  }}
215
215
  >
216
- <div className="mb-4 text-sm uppercase text-slate-900 leading-6 dark:text-slate-100">
216
+ <div className="mb-4 text-sm leading-6 uppercase text-slate-900 dark:text-slate-100">
217
217
  In this article
218
218
  </div>
219
219
  <Headings headings={headings} activeId={activeId} highlight={highlight} selector={selector} />
@@ -1,9 +1,10 @@
1
+ import type { NodeRenderer } from '@myst-theme/providers';
1
2
  import { DEFAULT_RENDERERS } from 'myst-to-react';
2
3
  import { MystDemoRenderer } from 'myst-demo';
3
4
  import { MermaidNodeRenderer } from '@myst-theme/diagrams';
4
5
  import OUTPUT_RENDERERS from '@myst-theme/jupyter';
5
6
 
6
- export const renderers = {
7
+ export const renderers: Record<string, NodeRenderer> = {
7
8
  ...DEFAULT_RENDERERS,
8
9
  myst: MystDemoRenderer,
9
10
  mermaid: MermaidNodeRenderer,
@@ -101,6 +101,17 @@ export function updateSiteManifestStaticLinksInplace(
101
101
  if (data.logo_dark) data.logo_dark = updateUrl(data.logo_dark);
102
102
  // Update the thumbnails to point at the CDN
103
103
  data.projects?.forEach((project) => {
104
+ if (project.banner) project.banner = updateUrl(project.banner);
105
+ if (project.bannerOptimized) project.bannerOptimized = updateUrl(project.bannerOptimized);
106
+ if (project.thumbnail) project.thumbnail = updateUrl(project.thumbnail);
107
+ if (project.thumbnailOptimized)
108
+ project.thumbnailOptimized = updateUrl(project.thumbnailOptimized);
109
+ if (project?.exports) {
110
+ project.exports = project.exports.map((exp) => {
111
+ if (!exp.url) return exp;
112
+ return { ...exp, url: updateUrl(exp.url) };
113
+ });
114
+ }
104
115
  project.pages
105
116
  .filter((page): page is ManifestProjectItem => 'slug' in page)
106
117
  .forEach((page) => {
@@ -118,6 +129,12 @@ export function updatePageStaticLinksInplace(data: PageLoader, updateUrl: Update
118
129
  if (data?.frontmatter?.thumbnailOptimized) {
119
130
  data.frontmatter.thumbnailOptimized = updateUrl(data.frontmatter.thumbnailOptimized);
120
131
  }
132
+ if (data?.frontmatter?.banner) {
133
+ data.frontmatter.banner = updateUrl(data.frontmatter.banner);
134
+ }
135
+ if (data?.frontmatter?.bannerOptimized) {
136
+ data.frontmatter.bannerOptimized = updateUrl(data.frontmatter.bannerOptimized);
137
+ }
121
138
  if (data?.frontmatter?.exports) {
122
139
  data.frontmatter.exports = data.frontmatter.exports.map((exp) => {
123
140
  if (!exp.url) return exp;
@@ -142,8 +159,8 @@ export function updatePageStaticLinksInplace(data: PageLoader, updateUrl: Update
142
159
  outputs.forEach((node) => {
143
160
  if (!node.data) return;
144
161
  walkOutputs(node.data, (obj) => {
145
- // The path will be defined from output of myst-cli
146
- // Here we are re-asigning it to the current domain
162
+ // The path will be defined from output of myst
163
+ // Here we are re-assigning it to the current domain
147
164
  if (!obj.path) return;
148
165
  obj.path = updateUrl(obj.path);
149
166
  });
@@ -5,7 +5,7 @@ import { ErrorDocumentNotFound } from './ErrorDocumentNotFound';
5
5
  import { ErrorProjectNotFound } from './ErrorProjectNotFound';
6
6
  import type { PageLoader } from '../types';
7
7
  import type { GenericParent } from 'myst-common';
8
- import { SourceFileKind } from 'myst-common';
8
+ import { SourceFileKind } from 'myst-spec-ext';
9
9
  import {
10
10
  useComputeOptions,
11
11
  ExecuteScopeProvider,
@@ -14,10 +14,17 @@ import {
14
14
  ConnectionStatusTray,
15
15
  BinderBadge,
16
16
  useCanCompute,
17
+ ErrorTray,
17
18
  } from '@myst-theme/jupyter';
18
19
  import { FrontmatterBlock } from '@myst-theme/frontmatter';
19
20
 
20
- export const ArticlePage = React.memo(function ({ article }: { article: PageLoader }) {
21
+ export const ArticlePage = React.memo(function ({
22
+ article,
23
+ hide_all_footer_links,
24
+ }: {
25
+ article: PageLoader;
26
+ hide_all_footer_links?: boolean;
27
+ }) {
21
28
  const canCompute = useCanCompute(article);
22
29
  const { binderBadgeUrl } = useComputeOptions();
23
30
  const { hide_title_block, hide_footer_links } = (article.frontmatter as any)?.design ?? {};
@@ -33,7 +40,11 @@ export const ArticlePage = React.memo(function ({ article }: { article: PageLoad
33
40
  <BusyScopeProvider>
34
41
  <ExecuteScopeProvider contents={article}>
35
42
  {!hide_title_block && (
36
- <FrontmatterBlock kind={article.kind} frontmatter={article.frontmatter} />
43
+ <FrontmatterBlock
44
+ kind={article.kind}
45
+ frontmatter={article.frontmatter}
46
+ className="mb-8"
47
+ />
37
48
  )}
38
49
  {binderUrl && !canCompute && (
39
50
  <div className="flex justify-end">
@@ -41,11 +52,13 @@ export const ArticlePage = React.memo(function ({ article }: { article: PageLoad
41
52
  </div>
42
53
  )}
43
54
  {canCompute && article.kind === SourceFileKind.Notebook && <NotebookToolbar showLaunch />}
44
- {/* {canCompute && article.kind === SourceFileKind.Article && <NotebookToolbar />} */}
55
+ <ErrorTray pageSlug={article.slug} />
45
56
  <ContentBlocks pageKind={article.kind} mdast={article.mdast as GenericParent} />
46
57
  <Bibliography />
47
58
  <ConnectionStatusTray />
48
- {!hide_footer_links && <FooterLinksBlock links={article.footer} />}
59
+ {!hide_footer_links && !hide_all_footer_links && (
60
+ <FooterLinksBlock links={article.footer} />
61
+ )}
49
62
  </ExecuteScopeProvider>
50
63
  </BusyScopeProvider>
51
64
  </ReferencesProvider>
@@ -12,7 +12,7 @@ import {
12
12
  Link,
13
13
  NavLink,
14
14
  } from '@remix-run/react';
15
- import { ContentReload, renderers } from '../components';
15
+ import { renderers } from '../components';
16
16
  import { Analytics } from '../seo';
17
17
  import { Error404 } from './Error404';
18
18
  import classNames from 'classnames';
@@ -60,7 +60,7 @@ export function Document({
60
60
  analytics_plausible={config?.analytics_plausible}
61
61
  />
62
62
  </head>
63
- <body className="m-0 bg-white transition-colors duration-500 dark:bg-stone-900">
63
+ <body className="m-0 transition-colors duration-500 bg-white dark:bg-stone-900">
64
64
  <ThemeProvider theme={theme} renderers={renderers} {...links}>
65
65
  <BaseUrlProvider baseurl={baseurl}>
66
66
  <ThebeBundleLoaderProvider loadThebeLite publicPath={baseurl}>
@@ -88,21 +88,6 @@ export function App() {
88
88
  );
89
89
  }
90
90
 
91
- export function AppWithReload() {
92
- const { theme, config, CONTENT_CDN_PORT, MODE, BASE_URL } = useLoaderData<SiteLoader>();
93
- return (
94
- <Document
95
- theme={theme}
96
- config={config}
97
- scripts={MODE === 'static' ? undefined : <ContentReload port={CONTENT_CDN_PORT} />}
98
- staticBuild={MODE === 'static'}
99
- baseurl={BASE_URL}
100
- >
101
- <Outlet />
102
- </Document>
103
- );
104
- }
105
-
106
91
  export function AppCatchBoundary() {
107
92
  return (
108
93
  <Document theme={Theme.light}>
@@ -2,4 +2,4 @@ export { ErrorProjectNotFound } from './ErrorProjectNotFound';
2
2
  export { ErrorDocumentNotFound } from './ErrorDocumentNotFound';
3
3
  export { Error404 } from './Error404';
4
4
  export { ArticlePage, ArticlePageCatchBoundary, ProjectPageCatchBoundary } from './Article';
5
- export { App, AppWithReload, Document, AppCatchBoundary } from './Root';
5
+ export { App, Document, AppCatchBoundary } from './Root';
package/src/types.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { Root } from 'mdast';
2
- import type { References, Dependency, SourceFileKind } from 'myst-common';
2
+ import type { Dependency, SourceFileKind } from 'myst-spec-ext';
3
+ import type { References } from 'myst-common';
3
4
  import type { SiteManifest } from 'myst-config';
4
5
  import type { PageFrontmatter } from 'myst-frontmatter';
5
6
  import type { Theme } from '@myst-theme/providers';