@myst-theme/site 0.3.3 → 0.3.5

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.3",
3
+ "version": "0.3.5",
4
4
  "main": "./src/index.ts",
5
5
  "types": "./src/index.ts",
6
6
  "files": [
@@ -16,20 +16,20 @@
16
16
  "dependencies": {
17
17
  "@headlessui/react": "^1.7.15",
18
18
  "@heroicons/react": "^2.0.18",
19
- "@myst-theme/diagrams": "^0.3.3",
20
- "@myst-theme/frontmatter": "^0.3.3",
21
- "@myst-theme/jupyter": "^0.3.3",
22
- "@myst-theme/providers": "^0.3.3",
19
+ "@myst-theme/diagrams": "^0.3.5",
20
+ "@myst-theme/frontmatter": "^0.3.5",
21
+ "@myst-theme/jupyter": "^0.3.5",
22
+ "@myst-theme/providers": "^0.3.5",
23
23
  "classnames": "^2.3.2",
24
24
  "lodash.throttle": "^4.1.1",
25
25
  "myst-common": "^1.0.1",
26
26
  "myst-config": "^1.0.0",
27
- "myst-demo": "^0.3.3",
28
- "myst-to-react": "^0.3.3",
27
+ "myst-demo": "^0.3.5",
28
+ "myst-to-react": "^0.3.5",
29
29
  "nbtx": "^0.2.3",
30
30
  "node-cache": "^5.1.2",
31
31
  "node-fetch": "^2.6.11",
32
- "thebe-react": "^0.2.5",
32
+ "thebe-react": "^0.2.9",
33
33
  "unist-util-select": "^4.0.1"
34
34
  },
35
35
  "peerDependencies": {
@@ -3,7 +3,11 @@ import { SourceFileKind } from 'myst-common';
3
3
  import type { GenericParent } from 'myst-common';
4
4
  import { useNodeRenderers } from '@myst-theme/providers';
5
5
  import classNames from 'classnames';
6
- import { ClearCell, RunCell } from './ComputeControls';
6
+ import {
7
+ NotebookClearCell,
8
+ NotebookRunCell,
9
+ NotebookRunCellSpinnerOnly,
10
+ } from '@myst-theme/jupyter';
7
11
 
8
12
  function isACodeCell(node: GenericParent) {
9
13
  return (
@@ -18,6 +22,7 @@ function isACodeCell(node: GenericParent) {
18
22
 
19
23
  function Block({
20
24
  id,
25
+ pageKind,
21
26
  node,
22
27
  className,
23
28
  }: {
@@ -41,13 +46,22 @@ function Block({
41
46
  [subGrid]: !noSubGrid,
42
47
  })}
43
48
  >
44
- {children}
45
- {isACodeCell(node) && (
46
- <div className="hidden group-hover/block:flex md:flex-col absolute -top-[28px] md:top-0 right-0 md:-right-[28px] mt-8">
47
- <RunCell id={id} />
48
- <ClearCell id={id} />
49
- </div>
49
+ {pageKind === SourceFileKind.Notebook && isACodeCell(node) && (
50
+ <>
51
+ <div className="flex sticky top-[80px] z-10 opacity-70 group-hover/block:opacity-100 group-hover/block:hidden">
52
+ <div className="absolute top-0 -right-[28px] flex md:flex-col">
53
+ <NotebookRunCellSpinnerOnly id={id} />
54
+ </div>
55
+ </div>
56
+ <div className="hidden sticky top-[80px] z-10 opacity-70 group-hover/block:opacity-100 group-hover/block:flex">
57
+ <div className="absolute top-0 -right-[28px] flex md:flex-col">
58
+ <NotebookRunCell id={id} />
59
+ <NotebookClearCell id={id} />
60
+ </div>
61
+ </div>
62
+ </>
50
63
  )}
64
+ {children}
51
65
  </div>
52
66
  );
53
67
  }
@@ -23,7 +23,7 @@ export function Navigation({
23
23
  {children}
24
24
  {open && (
25
25
  <div
26
- className="fixed inset-0 bg-black opacity-50"
26
+ className="fixed inset-0 z-30 bg-black opacity-50"
27
27
  style={{ marginTop: top }}
28
28
  onClick={() => setOpen(false)}
29
29
  ></div>
@@ -48,7 +48,7 @@ const HeadingLink = ({
48
48
  'border-l pl-4 text-blue-500 border-current dark:text-blue-400': !isIndex && isActive,
49
49
  'font-semibold': isActive,
50
50
  'border-l pl-4 border-transparent hover:border-slate-400 dark:hover:border-slate-500 text-slate-700 hover:text-slate-900 dark:text-slate-400 dark:hover:text-slate-300':
51
- !isActive,
51
+ !isIndex && !isActive,
52
52
  })
53
53
  }
54
54
  to={withBaseurl(path, baseurl)}
@@ -165,6 +165,7 @@ export const TableOfContents = ({
165
165
  className={classNames(
166
166
  'fixed xl:article-grid article-grid-gap xl:w-screen xl:pointer-events-none overflow-auto max-xl:min-w-[300px]',
167
167
  { hidden: !open },
168
+ { 'z-30': open },
168
169
  )}
169
170
  style={{
170
171
  top: top ?? 0,
@@ -191,7 +192,7 @@ export const TableOfContents = ({
191
192
  </nav>
192
193
  {footer && (
193
194
  <div
194
- className="flex-none py-4 opacity-0 transition-all duration-700 translate-y-6"
195
+ className="flex-none py-4 transition-all duration-700 translate-y-6 opacity-0"
195
196
  ref={footerRef}
196
197
  >
197
198
  {footer}
@@ -92,7 +92,7 @@ function NavItem({ item }: { item: SiteNavItem }) {
92
92
  leaveFrom="transform opacity-100 scale-100"
93
93
  leaveTo="transform opacity-0 scale-95"
94
94
  >
95
- <Menu.Items className="absolute w-48 py-1 mt-2 origin-top-left bg-white rounded-sm shadow-lg left-4 ring-1 ring-black ring-opacity-5 focus:outline-none">
95
+ <Menu.Items className="absolute w-48 py-1 mt-2 bg-white rounded-sm shadow-lg origin-top-left left-4 ring-1 ring-black ring-opacity-5 focus:outline-none">
96
96
  {item.children?.map((action) => (
97
97
  <Menu.Item key={action.url}>
98
98
  {/* This is really ugly, BUT, the action needs to be defined HERE or the click away doesn't work for some reason */}
@@ -160,7 +160,7 @@ function ActionMenu({ actions }: { actions?: SiteManifest['actions'] }) {
160
160
  leaveFrom="transform opacity-100 scale-100"
161
161
  leaveTo="transform opacity-0 scale-95"
162
162
  >
163
- <Menu.Items className="absolute right-0 w-48 py-1 mt-2 origin-top-right bg-white rounded-sm shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">
163
+ <Menu.Items className="absolute right-0 w-48 py-1 mt-2 bg-white rounded-sm shadow-lg origin-top-right ring-1 ring-black ring-opacity-5 focus:outline-none">
164
164
  {actions?.map((action) => (
165
165
  <Menu.Item key={action.url}>
166
166
  {({ active }) => (
@@ -1,55 +1,52 @@
1
1
  import React from 'react';
2
2
  import { ReferencesProvider } from '@myst-theme/providers';
3
- import { FrontmatterBlock } from '@myst-theme/frontmatter';
4
3
  import { Bibliography, ContentBlocks, FooterLinksBlock } from '../components';
5
4
  import { ErrorDocumentNotFound } from './ErrorDocumentNotFound';
6
5
  import { ErrorProjectNotFound } from './ErrorProjectNotFound';
7
6
  import type { PageLoader } from '../types';
8
- import { ThebeRenderMimeRegistryProvider, ThebeSessionProvider } from 'thebe-react';
9
7
  import type { GenericParent } from 'myst-common';
10
8
  import { SourceFileKind } from 'myst-common';
11
- import { EnableCompute } from '../components/EnableCompute';
12
- import { NotebookRunAll } from '../components/ComputeControls';
13
9
  import {
14
- NotebookProvider,
15
- BinderBadge,
16
10
  useComputeOptions,
11
+ ExecuteScopeProvider,
12
+ BusyScopeProvider,
13
+ NotebookToolbar,
17
14
  ConnectionStatusTray,
15
+ BinderBadge,
18
16
  } from '@myst-theme/jupyter';
17
+ import { FrontmatterBlock } from '@myst-theme/frontmatter';
19
18
 
20
19
  export const ArticlePage = React.memo(function ({ article }: { article: PageLoader }) {
21
20
  const computeOptions = useComputeOptions();
22
21
  const canCompute = computeOptions.canCompute && (article.frontmatter as any)?.thebe !== false;
23
- const { hide_title_block, hide_footer_links, binder } =
24
- (article.frontmatter as any)?.design ?? {};
25
- const isJupyter = article?.kind && article.kind === SourceFileKind.Notebook;
22
+ const { hide_title_block, hide_footer_links } = (article.frontmatter as any)?.design ?? {};
23
+
24
+ // take binder url from article frontmatter or fallback to project
25
+ const binderUrl = article.frontmatter.binder ?? computeOptions.binderBadgeUrl;
26
+
26
27
  return (
27
28
  <ReferencesProvider
28
29
  references={{ ...article.references, article: article.mdast }}
29
30
  frontmatter={article.frontmatter}
30
31
  >
31
- <ThebeRenderMimeRegistryProvider>
32
- <ThebeSessionProvider start={false} name={article.slug}>
32
+ <BusyScopeProvider>
33
+ <ExecuteScopeProvider contents={article}>
33
34
  {!hide_title_block && (
34
35
  <FrontmatterBlock kind={article.kind} frontmatter={article.frontmatter} />
35
36
  )}
36
- <NotebookProvider siteConfig={false} page={article}>
37
- <div className="flex items-center">
38
- <div className="flex-grow"></div>
39
- {binder && <BinderBadge binder={binder} />}
40
- {canCompute && isJupyter && (
41
- <EnableCompute canCompute={true} key={article.slug}>
42
- <NotebookRunAll />
43
- </EnableCompute>
44
- )}
37
+ {binderUrl && !canCompute && (
38
+ <div className="flex justify-end">
39
+ <BinderBadge binder={binderUrl} />
45
40
  </div>
46
- <ContentBlocks pageKind={article.kind} mdast={article.mdast as GenericParent} />
47
- <ConnectionStatusTray />
48
- <Bibliography />
49
- {!hide_footer_links && <FooterLinksBlock links={article.footer} />}
50
- </NotebookProvider>
51
- </ThebeSessionProvider>
52
- </ThebeRenderMimeRegistryProvider>
41
+ )}
42
+ {canCompute && article.kind === SourceFileKind.Notebook && <NotebookToolbar showLaunch />}
43
+ {/* {canCompute && article.kind === SourceFileKind.Article && <NotebookToolbar />} */}
44
+ <ContentBlocks pageKind={article.kind} mdast={article.mdast as GenericParent} />
45
+ <Bibliography />
46
+ <ConnectionStatusTray />
47
+ {!hide_footer_links && <FooterLinksBlock links={article.footer} />}
48
+ </ExecuteScopeProvider>
49
+ </BusyScopeProvider>
53
50
  </ReferencesProvider>
54
51
  );
55
52
  });
@@ -60,7 +60,7 @@ export function Document({
60
60
  analytics_plausible={config?.analytics_plausible}
61
61
  />
62
62
  </head>
63
- <body className="m-0 transition-colors duration-500 bg-white dark:bg-stone-900">
63
+ <body className="m-0 bg-white transition-colors duration-500 dark:bg-stone-900">
64
64
  <ThemeProvider theme={theme} renderers={renderers} {...links}>
65
65
  <BaseUrlProvider baseurl={baseurl}>
66
66
  <ThebeBundleLoaderProvider loadThebeLite publicPath={baseurl}>
@@ -1,131 +0,0 @@
1
- import { Spinner } from './Spinner';
2
- import PlayCircleIcon from '@heroicons/react/24/outline/PlayCircleIcon';
3
- import ArrowPathIcon from '@heroicons/react/24/outline/ArrowPathIcon';
4
- import MinusCircleIcon from '@heroicons/react/24/outline/MinusCircleIcon';
5
- import ArrowTopRightOnSquareIcon from '@heroicons/react/24/outline/ArrowTopRightOnSquareIcon';
6
- import classNames from 'classnames';
7
- import type { NotebookExecuteOptions } from 'thebe-react';
8
- import { useThebeServer } from 'thebe-react';
9
- import type { IThebeCellExecuteReturn } from 'thebe-core';
10
- import { useMDASTNotebook, useNotebookCellExecution } from '@myst-theme/jupyter';
11
-
12
- export function Run({
13
- ready,
14
- executing,
15
- disabled,
16
- execute,
17
- }: {
18
- ready: boolean;
19
- executing: boolean;
20
- disabled?: boolean;
21
- execute: (
22
- options?: NotebookExecuteOptions | undefined,
23
- ) => Promise<(IThebeCellExecuteReturn | null)[]>;
24
- }) {
25
- return (
26
- <div className="relative flex text-sm">
27
- <button
28
- className={classNames(
29
- 'cursor-pointer text-gray-700 active:text-green-700 hover:opacity-100',
30
- {
31
- 'opacity-10 hover:opacity-10': executing,
32
- 'opacity-60': !executing,
33
- },
34
- )}
35
- disabled={disabled || !ready || executing}
36
- onClick={() => execute()}
37
- >
38
- <PlayCircleIcon className="inline-block w-6 h-6 align-top" title="run all cells" />
39
- </button>
40
- {executing && (
41
- <span className="absolute top-0 left-0 z-10 w-[22px] h-[22px] opacity-100">
42
- <Spinner size={24} />
43
- </span>
44
- )}
45
- </div>
46
- );
47
- }
48
-
49
- export function Clear({
50
- ready,
51
- executing,
52
- disabled,
53
- clear,
54
- }: {
55
- ready: boolean;
56
- executing: boolean;
57
- disabled?: boolean;
58
- clear: () => void;
59
- }) {
60
- return (
61
- <button
62
- className="flex text-gray-700 cursor-pointer active:text-green-700 opacity-60 hover:opacity-100"
63
- disabled={disabled || !ready || executing}
64
- onClick={() => clear()}
65
- >
66
- <MinusCircleIcon className="inline-block w-6 h-6 align-top" title="clear all outputs" />
67
- </button>
68
- );
69
- }
70
-
71
- export function RunCell({ id }: { id: string }) {
72
- const exec = useNotebookCellExecution(id);
73
- if (!exec?.ready) return null;
74
- const { ready, executing, notebookIsExecuting, execute } = exec;
75
- return (
76
- <Run ready={ready} executing={executing} disabled={notebookIsExecuting} execute={execute} />
77
- );
78
- }
79
-
80
- export function ClearCell({ id }: { id: string }) {
81
- const exec = useNotebookCellExecution(id);
82
- if (!exec?.ready) return null;
83
- const { ready, executing, notebookIsExecuting, clear } = exec;
84
- return <Clear ready={ready} executing={executing} disabled={notebookIsExecuting} clear={clear} />;
85
- }
86
-
87
- export function NotebookRunAll() {
88
- const { ready: serverReady, server } = useThebeServer();
89
- const exec = useMDASTNotebook();
90
-
91
- if (!exec?.ready) return null;
92
- const { ready, executing, executeAll, restart, clear } = exec;
93
-
94
- const clickLaunchInJupyter = () => {
95
- if (!serverReady || !server?.settings) return;
96
- window.open(server.settings.baseUrl, '_blank');
97
- };
98
-
99
- return (
100
- <div className="flex">
101
- <div className="relative flex group space-x-1">
102
- <Run
103
- ready={ready}
104
- executing={executing}
105
- execute={(options) => {
106
- clear();
107
- return executeAll(options);
108
- }}
109
- />
110
- <button
111
- className="flex items-center text-gray-700 cursor-pointer active:text-green-700 opacity-60 hover:opacity-100"
112
- disabled={!ready || executing}
113
- onClick={() => restart()}
114
- >
115
- <ArrowPathIcon className="w-6 h-6" title="restart kernel" />
116
- </button>
117
- <Clear ready={ready} executing={executing} clear={clear} />
118
- <button
119
- className="flex items-center text-gray-700 cursor-pointer active:text-green-700 opacity-60 hover:opacity-100"
120
- disabled={!ready}
121
- onClick={clickLaunchInJupyter}
122
- >
123
- <ArrowTopRightOnSquareIcon
124
- className="inline-block w-6 h-6 align-top"
125
- title="launch in juptyer"
126
- />
127
- </button>
128
- </div>
129
- </div>
130
- );
131
- }
@@ -1,72 +0,0 @@
1
- import { useThebeLoader, useThebeServer, useThebeSession } from 'thebe-react';
2
- import PowerIcon from '@heroicons/react/24/outline/PowerIcon';
3
- import { useHasNotebookProvider } from '@myst-theme/jupyter';
4
- import { useNavigation } from '@remix-run/react';
5
- import { useEffect, useState } from 'react';
6
- import { Spinner } from './Spinner';
7
- import classNames from 'classnames';
8
-
9
- export function EnableCompute({
10
- canCompute,
11
- children,
12
- }: React.PropsWithChildren<{ canCompute: boolean }>) {
13
- const { load, loading, core } = useThebeLoader();
14
- const { connect, connecting, ready: serverReady, error: serverError } = useThebeServer();
15
- const { start, starting, shutdown, ready: sessionReady, error: sessionError } = useThebeSession();
16
- const hasNotebookProvider = useHasNotebookProvider();
17
- const navigation = useNavigation();
18
- const [enabling, setEnabling] = useState(false);
19
- const [enabled, setEnabled] = useState(false);
20
- const busy = enabling || loading || connecting || starting;
21
-
22
- useEffect(() => {
23
- if (!enabling) return;
24
- if (!core) return load();
25
- if (!serverReady) return connect();
26
- if (!sessionReady) start();
27
- if (sessionReady) {
28
- setEnabled(true);
29
- setEnabling(false);
30
- }
31
- }, [enabling, core, serverReady, sessionReady]);
32
-
33
- if (!canCompute || !hasNotebookProvider) return null;
34
- let title = 'Connect to a compute server';
35
- const error = !!sessionError || !!serverError;
36
- if (error) {
37
- title = 'Error connecting to compute server';
38
- }
39
- if (busy) {
40
- title = 'Connecting...';
41
- }
42
-
43
- useEffect(() => {
44
- if (navigation.state === 'loading') {
45
- shutdown();
46
- }
47
- }, [shutdown, navigation]);
48
-
49
- return (
50
- <div className="relative flex items-center mx-1 mb-2">
51
- {!enabled && (
52
- <button
53
- className={classNames(
54
- 'flex text-center mr-1 cursor-pointer rounded-full disabled:opacity-10 text-gray-700',
55
- { 'text-red-600 opacity-100': error },
56
- )}
57
- onClick={() => setEnabling(true)}
58
- disabled={connecting || starting}
59
- title={title}
60
- >
61
- <PowerIcon className="inline-block w-6 h-6 mx-1 align-top" />
62
- </button>
63
- )}
64
- {(connecting || starting) && !error && (
65
- <span className="absolute top-0 left-1 z-10 w-[22px] h-[22px] opacity-100" title={title}>
66
- <Spinner size={24} />
67
- </span>
68
- )}
69
- {enabled && <>{children}</>}
70
- </div>
71
- );
72
- }