@myst-theme/site 0.1.37 → 0.1.38

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.1.37",
3
+ "version": "0.1.38",
4
4
  "main": "./src/index.ts",
5
5
  "types": "./src/index.ts",
6
6
  "files": [
@@ -16,16 +16,16 @@
16
16
  "dependencies": {
17
17
  "@headlessui/react": "^1.7.13",
18
18
  "@heroicons/react": "^2.0.14",
19
- "@myst-theme/diagrams": "^0.1.37",
20
- "@myst-theme/frontmatter": "^0.1.37",
21
- "@myst-theme/jupyter": "^0.1.37",
22
- "@myst-theme/providers": "^0.1.37",
19
+ "@myst-theme/diagrams": "^0.1.38",
20
+ "@myst-theme/frontmatter": "^0.1.38",
21
+ "@myst-theme/jupyter": "^0.1.38",
22
+ "@myst-theme/providers": "^0.1.38",
23
23
  "classnames": "^2.3.2",
24
24
  "lodash.throttle": "^4.1.1",
25
25
  "myst-common": "^0.0.16",
26
26
  "myst-config": "^0.0.14",
27
- "myst-demo": "^0.1.37",
28
- "myst-to-react": "^0.1.37",
27
+ "myst-demo": "^0.1.38",
28
+ "myst-to-react": "^0.1.38",
29
29
  "nbtx": "^0.2.3",
30
30
  "node-cache": "^5.1.2",
31
31
  "node-fetch": "^2.6.7",
@@ -1,13 +1,16 @@
1
1
  import { useParse, DEFAULT_RENDERERS } from 'myst-to-react';
2
- import type { GenericParent, SourceFileKind } from 'myst-common';
2
+ import { SourceFileKind } from 'myst-common';
3
+ import type { GenericParent } from 'myst-common';
3
4
  import { useNodeRenderers } from '@myst-theme/providers';
4
5
  import classNames from 'classnames';
5
6
  import { ClearCell, RunCell } from './ComputeControls';
6
7
 
7
8
  function isACodeCell(node: GenericParent) {
8
9
  return (
10
+ node &&
9
11
  node.type === 'block' &&
10
- node.children.length === 2 &&
12
+ node.children &&
13
+ node.children?.length === 2 &&
11
14
  node.children[0].type === 'code' &&
12
15
  node.children[1].type === 'output'
13
16
  );
@@ -50,16 +53,15 @@ function Block({
50
53
  }
51
54
 
52
55
  export function ContentBlocks({
53
- name,
54
- pageKind,
55
56
  mdast,
57
+ pageKind = SourceFileKind.Article,
56
58
  className,
57
59
  }: {
58
- name: string;
59
- pageKind: SourceFileKind;
60
60
  mdast: GenericParent;
61
+ pageKind?: SourceFileKind;
61
62
  className?: string;
62
63
  }) {
64
+ if (!mdast) return null;
63
65
  const blocks = mdast.children as GenericParent[];
64
66
  return (
65
67
  <>
@@ -55,12 +55,9 @@ async function mystLiveReloadConnect(config: { onOpen?: () => void; port?: strin
55
55
  }
56
56
 
57
57
  // Inspired by the LiveReload component in Remix
58
- export const ContentReload =
59
- process.env.NODE_ENV !== 'development'
60
- ? () => null
61
- : ({ port }: { port?: string | number }) => {
62
- useEffect(() => {
63
- mystLiveReloadConnect({ port });
64
- }, []);
65
- return null;
66
- };
58
+ export function ContentReload({ port }: { port?: string | number }) {
59
+ useEffect(() => {
60
+ mystLiveReloadConnect({ port });
61
+ }, []);
62
+ return null;
63
+ }
@@ -1,7 +1,7 @@
1
1
  import { useNavigation } from '@remix-run/react';
2
2
  import classNames from 'classnames';
3
3
  import throttle from 'lodash.throttle';
4
- import { useCallback, useEffect, useRef, useState } from 'react';
4
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
5
5
 
6
6
  const SELECTOR = [1, 2, 3, 4, 5, 6].map((n) => `main h${n}`).join(', ');
7
7
  const HIGHLIGHT_CLASS = 'highlight';
@@ -176,7 +176,7 @@ export function useOutlineHeight<T extends HTMLElement = HTMLElement>() {
176
176
  return () => {
177
177
  window.removeEventListener('scroll', handleScroll);
178
178
  };
179
- }, [container, outline, transitionState]);
179
+ }, [container.current, outline.current, transitionState]);
180
180
  return { container, outline };
181
181
  }
182
182
 
@@ -191,13 +191,18 @@ export const DocumentOutline = ({
191
191
  className?: string;
192
192
  }) => {
193
193
  const { activeId, headings, highlight } = useHeaders();
194
- if (headings.length <= 1) return <nav suppressHydrationWarning />;
194
+ if (headings.length <= 1 || !onClient) {
195
+ return <nav suppressHydrationWarning />;
196
+ }
195
197
  return (
196
198
  <nav
197
199
  ref={outlineRef}
198
200
  aria-label="Document Outline"
199
- suppressHydrationWarning
200
- className={classNames('not-prose transition-opacity overflow-y-auto', className)}
201
+ className={classNames(
202
+ 'not-prose overflow-y-auto hidden',
203
+ 'transition-opacity duration-700', // Animation on load
204
+ className,
205
+ )}
201
206
  style={{
202
207
  top: top ?? 0,
203
208
  maxHeight: `calc(100vh - ${(top ?? 0) + 20}px)`,
@@ -206,7 +211,7 @@ export const DocumentOutline = ({
206
211
  <div className="text-slate-900 mb-4 text-sm leading-6 dark:text-slate-100 uppercase">
207
212
  In this article
208
213
  </div>
209
- {onClient && <Headings headings={headings} activeId={activeId} highlight={highlight} />}
214
+ <Headings headings={headings} activeId={activeId} highlight={highlight} />
210
215
  </nav>
211
216
  );
212
217
  };
@@ -1,4 +1,4 @@
1
- import { Link } from '@remix-run/react';
1
+ import { useLinkProvider } from '@myst-theme/providers';
2
2
 
3
3
  export function ExternalOrInternalLink({
4
4
  to,
@@ -15,6 +15,7 @@ export function ExternalOrInternalLink({
15
15
  title?: string;
16
16
  children: React.ReactNode;
17
17
  }) {
18
+ const Link = useLinkProvider();
18
19
  if (to.startsWith('http') || isStatic) {
19
20
  return (
20
21
  <a href={to} className={className} target="_blank" rel="noopener noreferrer" title={title}>
@@ -1,13 +1,12 @@
1
1
  import classNames from 'classnames';
2
- import { Link } from '@remix-run/react';
3
2
  import ArrowLeftIcon from '@heroicons/react/24/outline/ArrowLeftIcon';
4
3
  import ArrowRightIcon from '@heroicons/react/24/outline/ArrowRightIcon';
5
4
  import type { FooterLinks, NavigationLink } from '../types';
6
- import { useUrlbase, withUrlbase } from '@myst-theme/providers';
7
- import { useEffect, useState } from 'react';
5
+ import { useLinkProvider, useUrlbase, withUrlbase } from '@myst-theme/providers';
8
6
 
9
7
  const FooterLink = ({ title, url, group, right }: NavigationLink & { right?: boolean }) => {
10
8
  const urlbase = useUrlbase();
9
+ const Link = useLinkProvider();
11
10
  return (
12
11
  <Link
13
12
  prefetch="intent"
@@ -1,4 +1,4 @@
1
- import { useTransition } from '@remix-run/react';
1
+ import { useNavigation } from '@remix-run/react';
2
2
  import { useEffect, useMemo, useState } from 'react';
3
3
  import classNames from 'classnames';
4
4
 
@@ -6,7 +6,7 @@ import classNames from 'classnames';
6
6
  * Show a loading progess bad if the load takes more than 150ms
7
7
  */
8
8
  function useLoading() {
9
- const transitionState = useTransition().state;
9
+ const transitionState = useNavigation().state;
10
10
  const ref = useMemo<{ start?: NodeJS.Timeout; finish?: NodeJS.Timeout }>(() => ({}), []);
11
11
  const [showLoading, setShowLoading] = useState(false);
12
12
 
@@ -138,6 +138,7 @@ export const TableOfContents = ({
138
138
  projectSlug?: string;
139
139
  footer?: React.ReactNode;
140
140
  }) => {
141
+ const footerRef = useRef<HTMLDivElement>(null);
141
142
  const [open] = useNavOpen();
142
143
  const config = useSiteManifest();
143
144
  const { folder, project } = useParams();
@@ -146,6 +147,13 @@ export const TableOfContents = ({
146
147
  const headings = getProjectHeadings(config, resolvedProjectSlug, {
147
148
  addGroups: false,
148
149
  });
150
+ useEffect(() => {
151
+ setTimeout(() => {
152
+ if (!footerRef.current) return;
153
+ footerRef.current.style.opacity = '1';
154
+ footerRef.current.style.transform = 'none';
155
+ }, 500);
156
+ }, [footerRef]);
149
157
  if (!headings) return null;
150
158
  return (
151
159
  <div
@@ -177,7 +185,14 @@ export const TableOfContents = ({
177
185
  >
178
186
  <Headings folder={resolvedProjectSlug} headings={headings} sections={config?.projects} />
179
187
  </nav>
180
- {footer && <div className="flex-none py-4">{footer}</div>}
188
+ {footer && (
189
+ <div
190
+ className="flex-none py-4 opacity-0 transition-all duration-700 translate-y-6"
191
+ ref={footerRef}
192
+ >
193
+ {footer}
194
+ </div>
195
+ )}
181
196
  </div>
182
197
  </div>
183
198
  );
@@ -1,4 +1,4 @@
1
- import { Link, NavLink } from '@remix-run/react';
1
+ import { NavLink } from '@remix-run/react';
2
2
  import { Fragment } from 'react';
3
3
  import classNames from 'classnames';
4
4
  import { Menu, Transition } from '@headlessui/react';
@@ -7,7 +7,7 @@ import MenuIcon from '@heroicons/react/24/solid/Bars3Icon';
7
7
  import ChevronDownIcon from '@heroicons/react/24/solid/ChevronDownIcon';
8
8
  import type { SiteManifest, SiteNavItem } from 'myst-config';
9
9
  import { ThemeButton } from './ThemeButton';
10
- import { useNavOpen, useSiteManifest } from '@myst-theme/providers';
10
+ import { useLinkProvider, useNavOpen, useSiteManifest } from '@myst-theme/providers';
11
11
  import { LoadingBar } from './Loading';
12
12
 
13
13
  export const DEFAULT_NAV_HEIGHT = 60;
@@ -25,6 +25,7 @@ function ExternalOrInternalLink({
25
25
  nav?: boolean;
26
26
  prefetch?: 'intent' | 'render' | 'none';
27
27
  }) {
28
+ const Link = useLinkProvider();
28
29
  const staticClass = typeof className === 'function' ? className({ isActive: false }) : className;
29
30
  if (to.startsWith('http') || to.startsWith('mailto:')) {
30
31
  return (
@@ -176,6 +177,7 @@ function ActionMenu({ actions }: { actions?: SiteManifest['actions'] }) {
176
177
  }
177
178
 
178
179
  function HomeLink({ logo, logoText, name }: { logo?: string; logoText?: string; name?: string }) {
180
+ const Link = useLinkProvider();
179
181
  const nothingSet = !logo && !logoText;
180
182
  return (
181
183
  <Link
@@ -37,11 +37,7 @@ export const ArticlePage = React.memo(function ({ article }: { article: PageLoad
37
37
  </EnableCompute>
38
38
  )}
39
39
  </div>
40
- <ContentBlocks
41
- name={article.slug}
42
- pageKind={article.kind}
43
- mdast={article.mdast as GenericParent}
44
- />
40
+ <ContentBlocks pageKind={article.kind} mdast={article.mdast as GenericParent} />
45
41
  <Bibliography />
46
42
  {!hide_footer_links && <FooterLinksBlock links={article.footer} />}
47
43
  </NotebookProvider>
@@ -21,17 +21,17 @@ import { ConfiguredThebeServerProvider } from '@myst-theme/jupyter';
21
21
 
22
22
  export function Document({
23
23
  children,
24
+ scripts,
24
25
  theme,
25
26
  config,
26
27
  title,
27
- CONTENT_CDN_PORT,
28
28
  scrollTopClass = 'scroll-p-20',
29
29
  }: {
30
30
  children: React.ReactNode;
31
+ scripts?: React.ReactNode;
31
32
  theme: Theme;
32
33
  config?: SiteManifest;
33
34
  title?: string;
34
- CONTENT_CDN_PORT?: number | string;
35
35
  scrollTopClass?: string;
36
36
  }) {
37
37
  return (
@@ -58,16 +58,25 @@ export function Document({
58
58
  <ScrollRestoration />
59
59
  <Scripts />
60
60
  <LiveReload />
61
- <ContentReload port={CONTENT_CDN_PORT} />
61
+ {scripts}
62
62
  </body>
63
63
  </html>
64
64
  );
65
65
  }
66
66
 
67
67
  export function App() {
68
+ const { theme, config } = useLoaderData<SiteLoader>();
69
+ return (
70
+ <Document theme={theme} config={config}>
71
+ <Outlet />
72
+ </Document>
73
+ );
74
+ }
75
+
76
+ export function AppWithReload() {
68
77
  const { theme, config, CONTENT_CDN_PORT } = useLoaderData<SiteLoader>();
69
78
  return (
70
- <Document theme={theme} config={config} CONTENT_CDN_PORT={CONTENT_CDN_PORT}>
79
+ <Document theme={theme} config={config} scripts={<ContentReload port={CONTENT_CDN_PORT} />}>
71
80
  <Outlet />
72
81
  </Document>
73
82
  );
@@ -2,4 +2,4 @@ export { ErrorProjectNotFound } from './ErrorProjectNotFound';
2
2
  export { ErrorDocumentNotFound } from './ErrorDocumentNotFound';
3
3
  export { ErrorSiteNotFound } from './ErrorSiteNotFound';
4
4
  export { ArticlePage, ArticlePageCatchBoundary, ProjectPageCatchBoundary } from './Article';
5
- export { App, Document, AppCatchBoundary, AppDebugErrorBoundary } from './Root';
5
+ export { App, AppWithReload, Document, AppCatchBoundary, AppDebugErrorBoundary } from './Root';