@myst-theme/site 0.1.28 → 0.1.29

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.28",
3
+ "version": "0.1.29",
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.8",
18
18
  "@heroicons/react": "^2.0.14",
19
- "@myst-theme/diagrams": "^0.1.28",
20
- "@myst-theme/frontmatter": "^0.1.28",
21
- "@myst-theme/jupyter": "^0.1.28",
22
- "@myst-theme/providers": "^0.1.28",
19
+ "@myst-theme/diagrams": "^0.1.29",
20
+ "@myst-theme/frontmatter": "^0.1.29",
21
+ "@myst-theme/jupyter": "^0.1.29",
22
+ "@myst-theme/providers": "^0.1.29",
23
23
  "classnames": "^2.3.2",
24
24
  "lodash.throttle": "^4.1.1",
25
25
  "myst-common": "^0.0.14",
26
26
  "myst-config": "^0.0.10",
27
- "myst-demo": "^0.1.28",
28
- "myst-to-react": "^0.1.28",
27
+ "myst-demo": "^0.1.29",
28
+ "myst-to-react": "^0.1.29",
29
29
  "nbtx": "^0.2.3",
30
30
  "node-cache": "^5.1.2",
31
31
  "node-fetch": "^2.6.7",
@@ -12,15 +12,17 @@ export function Bibliography() {
12
12
  const refs = hidden ? filtered.slice(0, HIDE_OVER_N_REFERENCES) : filtered;
13
13
  return (
14
14
  <section className="article-grid article-subgrid-gap col-screen">
15
- {filtered.length > HIDE_OVER_N_REFERENCES && (
16
- <button
17
- onClick={() => setHidden(!hidden)}
18
- className="float-right text-xs p-1 px-2 border rounded hover:border-blue-500 dark:hover:border-blue-400"
19
- >
20
- {hidden ? 'Show All' : 'Collapse'}
21
- </button>
22
- )}
23
- <header className="text-lg font-semibold text-stone-900 dark:text-white">References</header>
15
+ <div>
16
+ {filtered.length > HIDE_OVER_N_REFERENCES && (
17
+ <button
18
+ onClick={() => setHidden(!hidden)}
19
+ className="float-right text-xs p-1 px-2 border rounded hover:border-blue-500 dark:hover:border-blue-400"
20
+ >
21
+ {hidden ? 'Show All' : 'Collapse'}
22
+ </button>
23
+ )}
24
+ <header className="text-lg font-semibold text-stone-900 dark:text-white">References</header>
25
+ </div>
24
26
  <div className="text-xs mb-8 pl-3 text-stone-500 dark:text-stone-300">
25
27
  <ol>
26
28
  {refs.map((label) => {
@@ -171,13 +171,14 @@ export const DocumentOutline = ({
171
171
  <nav
172
172
  aria-label="Document Outline"
173
173
  suppressHydrationWarning
174
- className={classNames('not-prose transition-opacity', className)}
174
+ className={classNames('not-prose transition-opacity overflow-y-auto', className)}
175
175
  style={{
176
176
  top: top ?? 0,
177
177
  height:
178
178
  typeof document === 'undefined' || (height && height > window.innerHeight)
179
179
  ? undefined
180
180
  : height,
181
+ maxHeight: `calc(100vh - ${(top ?? 0) + 20}px)`,
181
182
  opacity: height && height > 300 ? undefined : 0,
182
183
  pointerEvents: height && height > 300 ? undefined : 'none',
183
184
  }}
@@ -1,6 +1,6 @@
1
1
  import fetch from 'node-fetch';
2
2
  import NodeCache from 'node-cache';
3
- import type { SiteManifest as Config } from 'myst-config';
3
+ import type { SiteManifest } from 'myst-config';
4
4
  import { responseNoArticle, responseNoSite } from './errors.server';
5
5
  import {
6
6
  getFooterLinks,
@@ -21,7 +21,9 @@ declare global {
21
21
  var cdnRouterCache: NodeCache | undefined, configCache: NodeCache | undefined;
22
22
  }
23
23
 
24
- const CDN = 'https://cdn.curvenote.com/';
24
+ export type Host = string | { CDN: string; id: string };
25
+
26
+ const DEFAULT_CDN = 'https://cdn.curvenote.com/';
25
27
 
26
28
  function getCdnRouterCache() {
27
29
  if (global.cdnRouterCache) return global.cdnRouterCache;
@@ -31,7 +33,7 @@ function getCdnRouterCache() {
31
33
  return global.cdnRouterCache;
32
34
  }
33
35
 
34
- function getConfigCache() {
36
+ export function getConfigCache() {
35
37
  if (global.configCache) return global.configCache;
36
38
  console.log('Creating configCache');
37
39
  // The config can be long lived as it is static (0 == ∞)
@@ -52,9 +54,27 @@ async function getCdnPath(hostname: string): Promise<string | undefined> {
52
54
  return data.cdn;
53
55
  }
54
56
 
55
- function withCDN<T extends string | undefined>(id: string, url: T): T {
57
+ function withPublicFolderUrl(baseUrl: string, url: string): string {
58
+ return withBaseUrl(baseUrl, `public${url}`);
59
+ }
60
+
61
+ export async function getCdnLocation(host: Host) {
62
+ if (typeof host === 'string') {
63
+ const id = await getCdnPath(host);
64
+ if (!id) throw responseNoSite();
65
+ return { CDN: DEFAULT_CDN, id };
66
+ }
67
+ return host;
68
+ }
69
+
70
+ export async function getCdnBaseUrl(host: Host): Promise<string> {
71
+ const { CDN, id } = await getCdnLocation(host);
72
+ return `${CDN}${id}/`;
73
+ }
74
+
75
+ function withBaseUrl<T extends string | undefined>(baseUrl: string, url: T): T {
56
76
  if (!url) return url;
57
- return `${CDN}${id}/public${url}` as T;
77
+ return `${baseUrl}${url}` as T;
58
78
  }
59
79
 
60
80
  /**
@@ -67,7 +87,7 @@ function foldTitleString(title?: string): string | undefined {
67
87
  /**
68
88
  * If the site title and the first nav item are the same, remove it.
69
89
  */
70
- function removeSingleNavItems(config: Config) {
90
+ function removeSingleNavItems(config: SiteManifest) {
71
91
  if (
72
92
  config?.nav?.length === 1 &&
73
93
  foldTitleString(config.nav[0].title) === foldTitleString(config.title)
@@ -76,48 +96,51 @@ function removeSingleNavItems(config: Config) {
76
96
  }
77
97
  }
78
98
 
79
- export async function getConfig(hostname: string): Promise<Config> {
80
- const id = await getCdnPath(hostname);
99
+ export async function getConfig(host: Host): Promise<SiteManifest> {
100
+ const location = await getCdnLocation(host);
101
+ const baseUrl = await getCdnBaseUrl(location);
102
+ const { id } = location;
81
103
  if (!id) throw responseNoSite();
82
- const cached = getConfigCache().get<Config>(id);
104
+ const cached = getConfigCache().get<SiteManifest>(id);
83
105
  // Load the data from an in memory cache.
84
106
  if (cached) return cached;
85
- const response = await fetch(`${CDN}${id}/config.json`);
107
+ const response = await fetch(withBaseUrl(baseUrl, 'config.json'));
86
108
  if (response.status === 404) throw responseNoSite();
87
- const data = (await response.json()) as Config;
109
+ const data = (await response.json()) as SiteManifest;
88
110
  data.id = id;
89
111
  removeSingleNavItems(data);
90
- updateSiteManifestStaticLinksInplace(data, (url) => withCDN(id, url));
91
- getConfigCache().set<Config>(id, data);
112
+ updateSiteManifestStaticLinksInplace(data, (url) => withPublicFolderUrl(baseUrl, url));
113
+ getConfigCache().set<SiteManifest>(id, data);
92
114
  return data;
93
115
  }
94
116
 
95
- export async function getObjectsInv(hostname: string): Promise<Buffer | undefined> {
96
- const id = await getCdnPath(hostname);
97
- if (!id) return;
98
- const url = `${CDN}${id}/objects.inv`;
117
+ export async function getObjectsInv(host: Host): Promise<Buffer | undefined> {
118
+ const baseUrl = await getCdnBaseUrl(host);
119
+ if (!baseUrl) return;
120
+ const url = `${baseUrl}objects.inv`;
99
121
  const response = await fetch(url);
100
122
  if (response.status === 404) return;
101
123
  const buffer = await response.buffer();
102
124
  return buffer;
103
125
  }
104
126
 
105
- export async function getData(
106
- config?: Config,
127
+ async function getData(
128
+ baseUrl: string,
129
+ config?: SiteManifest,
107
130
  project?: string,
108
131
  slug?: string,
109
132
  ): Promise<PageLoader | null> {
110
133
  if (!project || !slug || !config) throw responseNoArticle();
111
134
  const { id } = config;
112
135
  if (!id) throw responseNoSite();
113
- const response = await fetch(`${CDN}${id}/content/${project}/${slug}.json`);
136
+ const response = await fetch(withBaseUrl(baseUrl, `content/${project}/${slug}.json`));
114
137
  if (response.status === 404) throw responseNoArticle();
115
138
  const data = (await response.json()) as PageLoader;
116
- return updatePageStaticLinksInplace(data, (url) => withCDN(id, url));
139
+ return updatePageStaticLinksInplace(data, (url) => withPublicFolderUrl(baseUrl, url));
117
140
  }
118
141
 
119
142
  export async function getPage(
120
- hostname: string,
143
+ host: Host,
121
144
  opts: {
122
145
  domain?: string;
123
146
  project?: string;
@@ -127,7 +150,8 @@ export async function getPage(
127
150
  },
128
151
  ): Promise<PageLoader | Response | null> {
129
152
  const projectName = opts.project;
130
- const config = await getConfig(hostname);
153
+ const baseUrl = await getCdnBaseUrl(host);
154
+ const config = await getConfig(host);
131
155
  if (!config) throw responseNoSite();
132
156
  const project = getProject(config, projectName);
133
157
  if (!project) throw responseNoArticle();
@@ -135,7 +159,7 @@ export async function getPage(
135
159
  return redirect(`${typeof opts.redirect === 'string' ? opts.redirect : '/'}${projectName}`);
136
160
  }
137
161
  const slug = opts.loadIndexPage || opts.slug == null ? project.index : opts.slug;
138
- const loader = await getData(config, projectName, slug).catch((e) => {
162
+ const loader = await getData(baseUrl, config, projectName, slug).catch((e) => {
139
163
  console.error(e);
140
164
  return null;
141
165
  });