@curvenote/renderers 0.8.0 → 1.0.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.
Files changed (93) hide show
  1. package/dist/articles.d.ts.map +1 -1
  2. package/dist/articles.js +2 -11
  3. package/dist/components/admonition.d.ts +18 -0
  4. package/dist/components/admonition.d.ts.map +1 -0
  5. package/dist/components/admonition.js +146 -0
  6. package/dist/components/cite-figurebar.d.ts +5 -0
  7. package/dist/components/cite-figurebar.d.ts.map +1 -0
  8. package/dist/components/cite-figurebar.js +73 -0
  9. package/dist/components/cite-youtube.d.ts +6 -0
  10. package/dist/components/cite-youtube.d.ts.map +1 -0
  11. package/dist/components/cite-youtube.js +45 -0
  12. package/dist/components/cite.d.ts +12 -0
  13. package/dist/components/cite.d.ts.map +1 -0
  14. package/dist/components/cite.js +76 -0
  15. package/dist/components/definition-list.d.ts +3 -0
  16. package/dist/components/definition-list.d.ts.map +1 -0
  17. package/dist/components/definition-list.js +20 -0
  18. package/dist/components/faq.d.ts +5 -0
  19. package/dist/components/faq.d.ts.map +1 -0
  20. package/dist/components/faq.js +34 -0
  21. package/dist/components/hero.css +6 -0
  22. package/dist/components/hero.d.ts +28 -0
  23. package/dist/components/hero.d.ts.map +1 -0
  24. package/dist/components/hero.example.d.ts +3 -0
  25. package/dist/components/hero.example.d.ts.map +1 -0
  26. package/dist/components/hero.example.js +30 -0
  27. package/dist/components/hero.js +89 -0
  28. package/dist/components/images.d.ts +5 -0
  29. package/dist/components/images.d.ts.map +1 -0
  30. package/dist/components/images.js +7 -0
  31. package/dist/components/index.d.ts +7 -0
  32. package/dist/components/index.d.ts.map +1 -0
  33. package/dist/components/index.js +6 -0
  34. package/dist/components/inlineError.d.ts +8 -0
  35. package/dist/components/inlineError.d.ts.map +1 -0
  36. package/dist/components/inlineError.js +6 -0
  37. package/dist/components/mermaid.d.ts +11 -0
  38. package/dist/components/mermaid.d.ts.map +1 -0
  39. package/dist/components/mermaid.js +59 -0
  40. package/dist/components/pdb.d.ts +5 -0
  41. package/dist/components/pdb.d.ts.map +1 -0
  42. package/dist/{pdbLink.js → components/pdb.js} +15 -5
  43. package/dist/hooks/useOpenAlex.d.ts +13 -0
  44. package/dist/hooks/useOpenAlex.d.ts.map +1 -0
  45. package/dist/hooks/useOpenAlex.js +33 -0
  46. package/dist/index.css +1 -0
  47. package/dist/index.d.ts +7 -2
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +29 -18
  50. package/dist/transforms/articles.d.ts +4 -1
  51. package/dist/transforms/articles.d.ts.map +1 -1
  52. package/dist/transforms/articles.js +37 -51
  53. package/dist/transforms/index.d.ts +4 -6
  54. package/dist/transforms/index.d.ts.map +1 -1
  55. package/dist/transforms/index.js +11 -24
  56. package/dist/transforms/{outputs.d.ts → notebooks.d.ts} +1 -1
  57. package/dist/transforms/notebooks.d.ts.map +1 -0
  58. package/dist/transforms/{outputs.js → notebooks.js} +3 -4
  59. package/dist/utils/abstract.d.ts +40 -0
  60. package/dist/utils/abstract.d.ts.map +1 -0
  61. package/dist/utils/abstract.js +76 -0
  62. package/package.json +40 -33
  63. package/README.md +0 -6
  64. package/dist/any/index.d.ts +0 -5
  65. package/dist/any/index.d.ts.map +0 -1
  66. package/dist/any/index.js +0 -8
  67. package/dist/any/models.d.ts +0 -18
  68. package/dist/any/models.d.ts.map +0 -1
  69. package/dist/any/models.js +0 -49
  70. package/dist/any/renderers.d.ts +0 -5
  71. package/dist/any/renderers.d.ts.map +0 -1
  72. package/dist/any/renderers.js +0 -113
  73. package/dist/any/types.d.ts +0 -22
  74. package/dist/any/types.d.ts.map +0 -1
  75. package/dist/any/types.js +0 -1
  76. package/dist/cards.d.ts +0 -8
  77. package/dist/cards.d.ts.map +0 -1
  78. package/dist/cards.js +0 -15
  79. package/dist/cite.d.ts +0 -17
  80. package/dist/cite.d.ts.map +0 -1
  81. package/dist/cite.js +0 -94
  82. package/dist/collections.d.ts +0 -6
  83. package/dist/collections.d.ts.map +0 -1
  84. package/dist/collections.js +0 -12
  85. package/dist/pdbLink.d.ts +0 -6
  86. package/dist/pdbLink.d.ts.map +0 -1
  87. package/dist/transforms/cards.d.ts +0 -52
  88. package/dist/transforms/cards.d.ts.map +0 -1
  89. package/dist/transforms/cards.js +0 -68
  90. package/dist/transforms/collections.d.ts +0 -15
  91. package/dist/transforms/collections.d.ts.map +0 -1
  92. package/dist/transforms/collections.js +0 -44
  93. package/dist/transforms/outputs.d.ts.map +0 -1
@@ -0,0 +1,89 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button } from '@curvenote-theme/ui';
3
+ import { MyST } from 'myst-to-react';
4
+ import { cn } from '@curvenote/react-utils';
5
+ import './hero.css';
6
+ // Generate Tailwind classes for max-width based on breakpoints
7
+ function getMaxWidthClasses(maxWidth) {
8
+ if (maxWidth == null)
9
+ return [];
10
+ const maxWidths = Array.isArray(maxWidth) ? maxWidth : [maxWidth];
11
+ // Round to nearest 5 and clamp between 0 and 100
12
+ const [sm, md, lg, xl, twoXl] = maxWidths.map((n) => {
13
+ if (n == null)
14
+ return undefined;
15
+ if (typeof n !== 'number' || isNaN(n))
16
+ return undefined;
17
+ return Math.max(0, Math.min(100, Math.round(n / 5) * 5));
18
+ });
19
+ return [
20
+ `max-w-[${sm || 100}%]`,
21
+ sm ? `sm:max-w-[${sm}%]` : undefined,
22
+ md ? `md:max-w-[${md}%]` : undefined,
23
+ lg ? `lg:max-w-[${lg}%]` : undefined,
24
+ xl ? `xl:max-w-[${xl}%]` : undefined,
25
+ twoXl ? `2xl:max-w-[${twoXl}%]` : undefined,
26
+ ].filter(Boolean);
27
+ }
28
+ // Generate Tailwind classes for overlays based on breakpoints
29
+ function getOverlayClasses(overlay) {
30
+ if (overlay == null)
31
+ return [];
32
+ const values = Array.isArray(overlay) ? overlay : [overlay, overlay, overlay, overlay, overlay];
33
+ // Round to nearest 5 and clamp between 0 and 100
34
+ const roundedValues = values.map((n) => {
35
+ if (n == null)
36
+ return undefined;
37
+ if (typeof n !== 'number' || isNaN(n))
38
+ return undefined;
39
+ return Math.max(-100, Math.min(100, Math.round(n / 10) * 10));
40
+ });
41
+ const backgrounds = roundedValues.map((value, index) => {
42
+ const modifier = ['sm', 'md', 'lg', 'xl', '2xl'][index];
43
+ if (modifier == 'sm' && value == null)
44
+ return `bg-black/10`;
45
+ if (value == null)
46
+ return undefined;
47
+ if (modifier == 'sm')
48
+ return `bg-${value < 0 ? 'white' : 'black'}/${Math.abs(value || 10)}`;
49
+ return `${modifier}:bg-${value < 0 ? 'white' : 'black'}/${Math.abs(value)}`;
50
+ });
51
+ return backgrounds.filter(Boolean);
52
+ }
53
+ export function HeroComponent({ className, backgroundImage, kicker, title, content, actions, footer, maxWidth, overlay, light = false, }) {
54
+ return (_jsxs("div", { className: cn('flex overflow-hidden relative flex-col min-h-[300px]', className), children: [backgroundImage && (_jsx("div", { className: "absolute inset-0 bg-center bg-no-repeat bg-cover", style: { backgroundImage: `url(${backgroundImage})` } })), overlay != null && _jsx("div", { className: cn('absolute inset-0', ...getOverlayClasses(overlay)) }), _jsx("div", { className: "container flex relative z-10 flex-1 items-center px-4 mx-auto my-20 sm:px-6 lg:px-8", children: _jsxs("div", { className: cn('max-w-4xl', ...getMaxWidthClasses(maxWidth)), children: [kicker && (_jsx("div", { className: cn('mb-2 text-sm font-medium tracking-wide uppercase', {
55
+ 'text-gray-300': light === false,
56
+ 'text-black': light === true,
57
+ }), children: kicker })), _jsx("h1", { className: cn('mb-6 text-4xl font-bold leading-tight sm:text-5xl lg:text-6xl', {
58
+ 'text-white': light === false,
59
+ 'text-black': light === true,
60
+ }), children: title }), content && (_jsx("div", { className: cn('mb-8 max-w-3xl text-lg leading-relaxed sm:text-xl', {
61
+ 'text-gray-200': light === false,
62
+ 'text-black': light === true,
63
+ }), children: content })), actions && actions.length > 0 && (_jsx("div", { className: "flex flex-col gap-4 sm:flex-row", children: actions.map((action, index) => (_jsx(Button, { variant: action.variant || 'default', size: "lg", className: cn('no-underline', {
64
+ 'bg-transparent border-white text-white hover:bg-white hover:text-gray-900': action.variant === 'outline' && light === false,
65
+ 'bg-white text-gray-900 hover:bg-gray-100': action.variant !== 'outline' && light === false,
66
+ 'bg-transparent border-black text-black hover:bg-black/10': action.variant === 'outline' && light === true,
67
+ 'bg-black text-gray-200 hover:bg-black/80': action.variant !== 'outline' && light === true,
68
+ }, action.className), asChild: !!action.href, onClick: action.onClick, children: action.href ? _jsx("a", { href: action.href, children: action.label }) : action.label }, index))) }))] }) }), footer && (_jsx("div", { className: "w-full backdrop-blur-lg bg-black/60", children: _jsx("div", { className: "container px-4 py-6 mx-auto sm:px-6 lg:px-8", children: _jsx("div", { className: "max-w-4xl text-sm leading-relaxed text-gray-300", children: footer }) }) }))] }));
69
+ }
70
+ const HeroRenderer = ({ node, className }) => {
71
+ // Extract properties from the node
72
+ const properties = node.data || {};
73
+ // Find children by type
74
+ const kicker = node.children?.find((child) => child.kind === 'kicker');
75
+ const title = node.children?.find((child) => child.kind === 'title');
76
+ const body = node.children?.find((child) => child.kind === 'body');
77
+ const actionNodes = node.children?.find((child) => child.kind === 'actions');
78
+ const footer = node.children?.find((child) => child.kind === 'footer');
79
+ const imageNode = node.children?.find((child) => child.kind === 'backgroundImage')
80
+ ?.children?.[0];
81
+ const imageUrl = imageNode?.urlOptimized || imageNode?.url;
82
+ const actions = actionNodes?.children?.filter((child) => child.type === 'link');
83
+ return (_jsx(HeroComponent, { className: cn(className, node.class), backgroundImage: imageUrl, maxWidth: properties.maxWidth, overlay: properties.overlay, light: properties.light, kicker: kicker ? _jsx(MyST, { ast: kicker }) : undefined, title: title ? _jsx(MyST, { ast: title }) : undefined, content: body ? _jsx(MyST, { ast: body }) : undefined, actions: actions?.map((action) => ({
84
+ label: _jsx(MyST, { ast: action.children }),
85
+ href: action.url,
86
+ variant: action.variant || 'default',
87
+ })), footer: footer ? _jsx(MyST, { ast: footer }) : undefined }));
88
+ };
89
+ export const HERO_RENDERERS = { block: { 'block[kind=hero]': HeroRenderer } };
@@ -0,0 +1,5 @@
1
+ import { type NodeRenderer } from '@myst-theme/providers';
2
+ export declare const IMAGE_RENDERERS: {
3
+ image: NodeRenderer;
4
+ };
5
+ //# sourceMappingURL=images.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"images.d.ts","sourceRoot":"","sources":["../../src/components/images.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAe1D,eAAO,MAAM,eAAe;;CAA2B,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import {} from '@myst-theme/providers';
3
+ import { Image } from '@curvenote-theme/ui';
4
+ const ImageRenderer = ({ node }) => {
5
+ return (_jsx(Image, { src: node.url, srcOptimized: node.urlOptimized, urlSource: node.urlSource, alt: node.alt }));
6
+ };
7
+ export const IMAGE_RENDERERS = { image: ImageRenderer };
@@ -0,0 +1,7 @@
1
+ export * from './images';
2
+ export * from './faq';
3
+ export * from './admonition';
4
+ export * from './hero';
5
+ export * from './definition-list';
6
+ export * from './cite-figurebar';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,OAAO,CAAC;AACtB,cAAc,cAAc,CAAC;AAC7B,cAAc,QAAQ,CAAC;AACvB,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,6 @@
1
+ export * from './images';
2
+ export * from './faq';
3
+ export * from './admonition';
4
+ export * from './hero';
5
+ export * from './definition-list';
6
+ export * from './cite-figurebar';
@@ -0,0 +1,8 @@
1
+ interface Props {
2
+ value: string;
3
+ message?: string;
4
+ className?: string;
5
+ }
6
+ export declare function InlineError({ value, message, className }: Props): import("react/jsx-runtime").JSX.Element;
7
+ export {};
8
+ //# sourceMappingURL=inlineError.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inlineError.d.ts","sourceRoot":"","sources":["../../src/components/inlineError.tsx"],"names":[],"mappings":"AAGA,UAAU,KAAK;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,KAAK,2CAO/D"}
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from '@curvenote/react-utils';
3
+ import { AlertCircle } from 'lucide-react';
4
+ export function InlineError({ value, message, className }) {
5
+ return (_jsxs("span", { className: cn('text-yellow-600', className), title: message || value, children: [_jsx(AlertCircle, { width: "1rem", height: "1rem", className: "inline mr-1" }), value] }));
6
+ }
@@ -0,0 +1,11 @@
1
+ import type { NodeRenderer } from '@myst-theme/providers';
2
+ export declare function MermaidRenderer({ id, value, className, }: {
3
+ value: string;
4
+ id: string;
5
+ className?: string;
6
+ }): import("react/jsx-runtime").JSX.Element;
7
+ export declare const MermaidNodeRenderer: NodeRenderer;
8
+ export declare const MERMAID_RENDERERS: {
9
+ mermaid: NodeRenderer;
10
+ };
11
+ //# sourceMappingURL=mermaid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mermaid.d.ts","sourceRoot":"","sources":["../../src/components/mermaid.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAiC1D,wBAAgB,eAAe,CAAC,EAC9B,EAAE,EACF,KAAK,EACL,SAAS,GACV,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,2CAyCA;AAED,eAAO,MAAM,mBAAmB,EAAE,YAQjC,CAAC;AAEF,eAAO,MAAM,iBAAiB;;CAAmC,CAAC"}
@@ -0,0 +1,59 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // Modified from @myst-theme/diagrams/src/components/mermaid.tsx
3
+ // MIC License:
4
+ // Copyright (c) Project Jupyter
5
+ // Additional changes Copyright (c) Curvenote, Inc.
6
+ import { cn } from '@curvenote/react-utils';
7
+ import { useEffect, useId, useRef, useState } from 'react';
8
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9
+ let mermaidInstance = null;
10
+ async function getMermaid() {
11
+ if (!mermaidInstance) {
12
+ mermaidInstance = (async () => {
13
+ const { default: mermaid } = await import('mermaid');
14
+ mermaid.initialize({ startOnLoad: false });
15
+ return mermaid;
16
+ })();
17
+ }
18
+ return mermaidInstance;
19
+ }
20
+ async function parse(id, text) {
21
+ const mermaid = await getMermaid();
22
+ const { svg, bindFunctions } = await mermaid.render(id, text);
23
+ return { svg, bindFunctions };
24
+ }
25
+ function applyParseResult(element, svg, bindFunctions) {
26
+ element.innerHTML = svg;
27
+ bindFunctions?.(element);
28
+ }
29
+ export function MermaidRenderer({ id, value, className, }) {
30
+ const key = useId();
31
+ const divRef = useRef(null);
32
+ const [error, setError] = useState();
33
+ useEffect(() => {
34
+ if (!divRef.current)
35
+ return;
36
+ let cancelled = false;
37
+ const element = divRef.current;
38
+ parse(`mermaid-${key.replace(/:/g, '')}`, value)
39
+ .then(({ svg, bindFunctions }) => {
40
+ if (!cancelled && divRef.current === element) {
41
+ applyParseResult(element, svg, bindFunctions);
42
+ setError(undefined);
43
+ }
44
+ })
45
+ .catch((err) => {
46
+ if (!cancelled) {
47
+ setError(err);
48
+ }
49
+ });
50
+ return () => {
51
+ cancelled = true;
52
+ };
53
+ }, [value, key]);
54
+ return (_jsxs("figure", { id: id, className: className, children: [_jsx("div", { ref: divRef }), error && (_jsxs("pre", { children: ["Error parsing mermaid graph.", '\n\n', error.message, '\n\n', value] }))] }));
55
+ }
56
+ export const MermaidNodeRenderer = ({ node, className }) => {
57
+ return (_jsx(MermaidRenderer, { id: node.html_id || node.identifier, value: node.value, className: cn(node.class, className) }));
58
+ };
59
+ export const MERMAID_RENDERERS = { mermaid: MermaidNodeRenderer };
@@ -0,0 +1,5 @@
1
+ import type { GenericNode } from 'myst-common';
2
+ import type { NodeRenderer, NodeRenderers } from '@myst-theme/providers';
3
+ export declare const PDBLinkRenderer: NodeRenderer<GenericNode>;
4
+ export declare const LINK_RENDERERS: NodeRenderers;
5
+ //# sourceMappingURL=pdb.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdb.d.ts","sourceRoot":"","sources":["../../src/components/pdb.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAkDzE,eAAO,MAAM,eAAe,EAAE,YAAY,CAAC,WAAW,CAgBrD,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,aAI5B,CAAC"}
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { default as useSWR } from 'swr';
3
- import { HoverPopover, LinkCard, MyST } from 'myst-to-react';
3
+ import { HoverPopover, MyST } from 'myst-to-react';
4
+ import { LinkCard } from '@curvenote-theme/ui';
4
5
  const createQuery = (id) => `{"query":"query structure ($id: String!) {\n entry(entry_id:$id){\n rcsb_id\n struct {\n title\n }\n pubmed {\n rcsb_pubmed_container_identifiers {\n pubmed_id\n }\n rcsb_pubmed_central_id\n rcsb_pubmed_doi\n rcsb_pubmed_abstract_text\n rcsb_pubmed_affiliation_info\n }\n }\n}\n","variables":{"id":"${id}"},"operationName":"structure"}`;
5
6
  const fetcher = (id) => fetch('https://data.rcsb.org/graphql', {
6
7
  method: 'post',
@@ -19,12 +20,21 @@ function PDBChild({ pdb }) {
19
20
  if (error) {
20
21
  return (_jsxs("div", { className: "hover-document article w-[500px] sm:max-w-[500px]", children: ["Error loading ", pdb, "."] }));
21
22
  }
22
- // return <div>{JSON.stringify(data)}</div>;
23
+ console.log(data);
23
24
  const rcsb_id = data.data.entry.rcsb_id;
24
25
  const title = data.data.entry.struct.title;
25
26
  const abstract = data.data.entry.pubmed.rcsb_pubmed_abstract_text;
26
- return (_jsx(LinkCard, { loading: !data, url: `https://www.rcsb.org/structure/${pdb}`, title: _jsxs("p", { className: "flex items-stretch gap-2 text-sm font-light", children: [_jsx("span", { children: "PDB: " }), _jsx("a", { href: `https://www.rcsb.org/structure/${pdb}`, className: "self-center", target: "_blank", rel: "noopener noreferrer", children: _jsx("code", { children: rcsb_id }) })] }), thumbnail: 'https://cdn.rcsb.org/images/structures/4n3b_assembly-1.jpeg', description: _jsxs(_Fragment, { children: [_jsx("div", { className: "mb-4 font-bold", children: title }), _jsx("p", { className: "mb-4 text-sm", children: abstract })] }) }));
27
+ return (_jsx(LinkCard, { loading: !data, url: `https://www.rcsb.org/structure/${pdb}`, title: _jsxs("div", { className: "flex gap-2 items-stretch text-sm font-light", children: ["PDB ", rcsb_id] }), thumbnail: `https://cdn.rcsb.org/images/structures/${rcsb_id.toLowerCase()}_assembly-1.jpeg`, description: _jsxs(_Fragment, { children: [_jsx("div", { className: "mb-4 font-bold", children: title }), _jsx("p", { className: "overflow-hidden text-sm line-clamp-5", children: abstract })] }) }));
27
28
  }
28
- export function PDBLink({ node, pdb }) {
29
+ export const PDBLinkRenderer = ({ node }) => {
30
+ const pdb = node.data?.pdb;
31
+ if (!pdb) {
32
+ return (_jsx("a", { href: node.url, target: "_blank", rel: "noopener noreferrer", children: _jsx(MyST, { ast: node.children }) }));
33
+ }
29
34
  return (_jsx(HoverPopover, { card: _jsx(PDBChild, { pdb: pdb }), children: _jsx("a", { href: `https://www.rcsb.org/structure/${pdb}`, target: "_blank", rel: "noopener noreferrer", children: _jsx(MyST, { ast: node.children }) }) }));
30
- }
35
+ };
36
+ export const LINK_RENDERERS = {
37
+ link: {
38
+ 'link[kind=pdb]': PDBLinkRenderer,
39
+ },
40
+ };
@@ -0,0 +1,13 @@
1
+ import type { OpenAlexWork } from '../utils/abstract';
2
+ /**
3
+ * Hook to fetch OpenAlex work data by DOI
4
+ * @param doi - DOI string (can include protocol or be clean)
5
+ * @returns SWR response with OpenAlex work data
6
+ */
7
+ export declare function useOpenAlexWork(doiString?: string): {
8
+ data: OpenAlexWork | undefined;
9
+ error: any;
10
+ isLoading: boolean;
11
+ doi: string | null | undefined;
12
+ };
13
+ //# sourceMappingURL=useOpenAlex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useOpenAlex.d.ts","sourceRoot":"","sources":["../../src/hooks/useOpenAlex.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAgBtD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,SAAS,CAAC,EAAE,MAAM;;;;;EAqBjD"}
@@ -0,0 +1,33 @@
1
+ import useSWR from 'swr';
2
+ import { doi } from 'doi-utils';
3
+ /**
4
+ * Fetcher function for OpenAlex API
5
+ */
6
+ async function openAlexFetcher(url) {
7
+ const response = await fetch(url);
8
+ if (!response.ok) {
9
+ throw new Error(`Failed to fetch OpenAlex data: ${response.status} ${response.statusText}`);
10
+ }
11
+ return response.json();
12
+ }
13
+ /**
14
+ * Hook to fetch OpenAlex work data by DOI
15
+ * @param doi - DOI string (can include protocol or be clean)
16
+ * @returns SWR response with OpenAlex work data
17
+ */
18
+ export function useOpenAlexWork(doiString) {
19
+ const cleanDoi = doiString ? doi.normalize(doiString) : null;
20
+ const { data, error, isLoading } = useSWR(cleanDoi ? `https://api.openalex.org/works/doi:${cleanDoi}` : null, openAlexFetcher, {
21
+ revalidateOnFocus: false,
22
+ revalidateOnReconnect: false,
23
+ dedupingInterval: 60000, // Cache for 1 minute
24
+ errorRetryCount: 2,
25
+ errorRetryInterval: 1000,
26
+ });
27
+ return {
28
+ data,
29
+ error,
30
+ isLoading,
31
+ doi: cleanDoi,
32
+ };
33
+ }
package/dist/index.css ADDED
@@ -0,0 +1 @@
1
+ @import './components/hero.css';
package/dist/index.d.ts CHANGED
@@ -1,3 +1,8 @@
1
- export declare const curvenoteRenderers: import("@myst-theme/providers").NodeRenderers;
2
- export * from './transforms/index.js';
1
+ export { MYST_SPEC_VERSION } from '@myst-theme/common';
2
+ declare const renderers: import("@myst-theme/providers").NodeRenderers;
3
+ export * from './transforms';
4
+ export * from './components';
5
+ export * from './utils/abstract';
6
+ export * from './hooks/useOpenAlex';
7
+ export { renderers };
3
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAYA,eAAO,MAAM,kBAAkB,+CAW7B,CAAC;AAEH,cAAc,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,QAAA,MAAM,SAAS,+CAcb,CAAC;AAEH,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,CAAC"}
package/dist/index.js CHANGED
@@ -1,24 +1,35 @@
1
+ import { DEFAULT_RENDERERS as mystRenderers } from 'myst-to-react';
1
2
  import { mergeRenderers } from '@myst-theme/providers';
2
- import PERSON_CARD_RENDERERS from '@curvenote/ext-person/react';
3
- import BLOG_RENDERERS from '@curvenote/ext-blog/react';
4
- import LANDING_RENDERERS from '@curvenote/ext-landing/react';
5
- import FOOTER_RENDERERS from '@curvenote/ext-footer/react';
6
- import SCIENCEICON_RENDERERS from '@scienceicons/myst/react';
7
- import CITE_RENDERERS from './cite.js';
8
- import { ANY_RENDERERS } from './any/index.js';
9
- import { ARTICLES_RENDERERS } from './articles.js';
10
- import { COLLECTIONS_RENDERERS } from './collections.js';
11
- import { CARD_RENDERERS } from './cards.js';
12
- export const curvenoteRenderers = mergeRenderers([
3
+ import { MERMAID_RENDERERS } from './components/mermaid';
4
+ import { ARTICLES_RENDERERS } from './articles';
5
+ import { IMAGE_RENDERERS } from './components/images';
6
+ import { ADMONITION_RENDERERS } from './components/admonition';
7
+ import { HERO_RENDERERS } from './components/hero';
8
+ import { DEFINITION_LIST_RENDERERS } from './components/definition-list';
9
+ import { LINK_RENDERERS } from './components/pdb';
10
+ import { CITE_RENDERERS } from './components/cite';
11
+ import { PERSON_CARD_RENDERERS } from '@curvenote/ext-person/react';
12
+ import { BLOG_RENDERERS } from '@curvenote/ext-blog/react';
13
+ // import { FAQ_RENDERERS } from './faq';
14
+ import { ANY_RENDERERS } from '@curvenote/any-widget/react';
15
+ export { MYST_SPEC_VERSION } from '@myst-theme/common';
16
+ const renderers = mergeRenderers([
17
+ mystRenderers,
18
+ MERMAID_RENDERERS,
19
+ ARTICLES_RENDERERS,
20
+ IMAGE_RENDERERS,
21
+ ADMONITION_RENDERERS,
22
+ HERO_RENDERERS,
23
+ DEFINITION_LIST_RENDERERS,
24
+ LINK_RENDERERS,
13
25
  CITE_RENDERERS,
14
26
  PERSON_CARD_RENDERERS,
15
27
  BLOG_RENDERERS,
16
- LANDING_RENDERERS,
17
- FOOTER_RENDERERS,
18
- SCIENCEICON_RENDERERS,
19
28
  ANY_RENDERERS,
20
- CARD_RENDERERS,
21
- ARTICLES_RENDERERS,
22
- COLLECTIONS_RENDERERS,
29
+ // FAQ_RENDERERS,
23
30
  ]);
24
- export * from './transforms/index.js';
31
+ export * from './transforms';
32
+ export * from './components';
33
+ export * from './utils/abstract';
34
+ export * from './hooks/useOpenAlex';
35
+ export { renderers };
@@ -31,5 +31,8 @@ export type OutgoingArticlesDirective = IncomingArticlesDirective & {
31
31
  * @param node
32
32
  * @returns
33
33
  */
34
- export declare function transformArticles(node: GenericParent): Promise<void[]>;
34
+ export declare function transformArticles(node: GenericParent, { apiUrl, venue }: {
35
+ apiUrl: string;
36
+ venue?: string;
37
+ }): Promise<void[]>;
35
38
  //# sourceMappingURL=articles.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"articles.d.ts","sourceRoot":"","sources":["../../src/transforms/articles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE5D,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,CAAC,iBAAiB,CAAC,CAAC,EAAE,MAAM,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,CAAC,iBAAiB,CAAC,CAAC,EAAE,OAAO,CAAC;IAC9B,CAAC,iBAAiB,CAAC,CAAC,EAAE,OAAO,CAAC;IAC9B,CAAC,WAAW,CAAC,CAAC,EAAE,OAAO,CAAC;IACxB,CAAC,WAAW,CAAC,CAAC,EAAE,OAAO,CAAC;IACxB,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC;IACzB,CAAC,cAAc,CAAC,CAAC,EAAE,OAAO,CAAC;IAC3B,CAAC,UAAU,CAAC,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,MAAM,yBAAyB,GAAG,yBAAyB,GAAG;IAClE,KAAK,EAAE,kBAAkB,CAAC,OAAO,CAAC,CAAC;IACnC,KAAK,EAAE,kBAAkB,CAAC,OAAO,CAAC,CAAC;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,aAAa,mBA0C1D"}
1
+ {"version":3,"file":"articles.d.ts","sourceRoot":"","sources":["../../src/transforms/articles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE5D,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,CAAC,iBAAiB,CAAC,CAAC,EAAE,MAAM,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,CAAC,iBAAiB,CAAC,CAAC,EAAE,OAAO,CAAC;IAC9B,CAAC,iBAAiB,CAAC,CAAC,EAAE,OAAO,CAAC;IAC9B,CAAC,WAAW,CAAC,CAAC,EAAE,OAAO,CAAC;IACxB,CAAC,WAAW,CAAC,CAAC,EAAE,OAAO,CAAC;IACxB,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC;IACzB,CAAC,cAAc,CAAC,CAAC,EAAE,OAAO,CAAC;IAC3B,CAAC,UAAU,CAAC,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,MAAM,yBAAyB,GAAG,yBAAyB,GAAG;IAClE,KAAK,EAAE,kBAAkB,CAAC,OAAO,CAAC,CAAC;IACnC,KAAK,EAAE,kBAAkB,CAAC,OAAO,CAAC,CAAC;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,aAAa,EACnB,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,mBA0CtD"}
@@ -1,12 +1,3 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
1
  import { selectAll } from 'unist-util-select';
11
2
  import pLimit from 'p-limit';
12
3
  /**
@@ -16,46 +7,41 @@ import pLimit from 'p-limit';
16
7
  * @param node
17
8
  * @returns
18
9
  */
19
- export function transformArticles(node) {
20
- return __awaiter(this, void 0, void 0, function* () {
21
- const articlesDirectives = selectAll('curvenoteArticles', node);
22
- const applyLimit = pLimit(5);
23
- return Promise.all(articlesDirectives.map((n) => __awaiter(this, void 0, void 0, function* () {
24
- return applyLimit(() => __awaiter(this, void 0, void 0, function* () {
25
- const output = n; // same object, modified in place
26
- // ensure defaults
27
- if (!n.pagination)
28
- output.pagination = 'more';
29
- if (!n.layout)
30
- output.layout = 'list';
31
- // build the URL
32
- const apiUrl = process.env.JOURNALS_API_URL;
33
- const url = new URL(`${apiUrl}sites/${n.venue}/works`);
34
- if (n.collection)
35
- url.searchParams.set('collection', n.collection);
36
- if (n.status && n.collection)
37
- url.searchParams.set('status', n.status);
38
- else if (n.status && !n.collection)
39
- console.warn('cn:articles directive provides status without collection, status will be ignored');
40
- if (n['submission-kind'])
41
- url.searchParams.set('kind', n['submission-kind']);
42
- if (n.limit)
43
- url.searchParams.set('limit', n.limit.toString());
44
- try {
45
- const res = yield fetch(url.toString());
46
- if (!res.ok)
47
- throw new Error(`${res.status} ${res.statusText}`);
48
- const data = (yield res.json());
49
- output.items = data.items;
50
- output.total = data.total;
51
- output.prev = data.links.prev;
52
- output.next = data.links.next;
53
- }
54
- catch (e) {
55
- output.error = 'Could not load listing';
56
- console.error('Could not load listing', e);
57
- }
58
- }));
59
- })));
60
- });
10
+ export async function transformArticles(node, { apiUrl, venue }) {
11
+ const articlesDirectives = selectAll('curvenoteArticles', node);
12
+ const applyLimit = pLimit(5);
13
+ return Promise.all(articlesDirectives.map(async (n) => applyLimit(async () => {
14
+ const output = n; // same object, modified in place
15
+ // ensure defaults
16
+ if (!n.pagination)
17
+ output.pagination = 'more';
18
+ if (!n.layout)
19
+ output.layout = 'list';
20
+ // build the URL
21
+ const url = new URL(`${apiUrl}sites/${n.venue ?? venue}/works`);
22
+ if (n.collection)
23
+ url.searchParams.set('collection', n.collection);
24
+ if (n.status && n.collection)
25
+ url.searchParams.set('status', n.status);
26
+ else if (n.status && !n.collection)
27
+ console.warn('cn:articles directive provides status without collection, status will be ignored');
28
+ if (n['submission-kind'])
29
+ url.searchParams.set('kind', n['submission-kind']);
30
+ if (n.limit)
31
+ url.searchParams.set('limit', n.limit.toString());
32
+ try {
33
+ const res = await fetch(url.toString());
34
+ if (!res.ok)
35
+ throw new Error(`${res.status} ${res.statusText}`);
36
+ const data = (await res.json());
37
+ output.items = data.items;
38
+ output.total = data.total;
39
+ output.prev = data.links.prev;
40
+ output.next = data.links.next;
41
+ }
42
+ catch (e) {
43
+ output.error = 'Could not load listing';
44
+ console.error('Could not load listing', e);
45
+ }
46
+ })));
61
47
  }
@@ -1,8 +1,6 @@
1
1
  import type { PageLoader } from '@myst-theme/common';
2
- import type { SiteDTO } from '@curvenote/common';
3
- export * from './articles.js';
4
- export * from './collections.js';
5
- export * from './cards.js';
6
- export * from './outputs.js';
7
- export declare function applyCustomTransforms(site: SiteDTO, page: PageLoader): Promise<void>;
2
+ export declare function applyCustomPageTransformsInPlace(page: PageLoader, opts?: {
3
+ apiUrl?: string;
4
+ venue?: string;
5
+ }): Promise<void>;
8
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transforms/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAMjD,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAE7B,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,iBAK1E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transforms/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAKrD,wBAAsB,gCAAgC,CACpD,IAAI,EAAE,UAAU,EAChB,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,iBAS3C"}
@@ -1,25 +1,12 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { transformArticles } from './articles.js';
11
- import { transformCollections } from './collections.js';
12
- import { transformCards } from './cards.js';
13
- import { transformDecorateNotebookOutputsWithSlugs } from './outputs.js';
14
- export * from './articles.js';
15
- export * from './collections.js';
16
- export * from './cards.js';
17
- export * from './outputs.js';
18
- export function applyCustomTransforms(site, page) {
19
- return __awaiter(this, void 0, void 0, function* () {
20
- yield transformArticles(page.mdast);
21
- yield transformCollections(page.mdast);
22
- transformCards(site, page.mdast);
23
- transformDecorateNotebookOutputsWithSlugs(page);
24
- });
1
+ import {} from 'myst-common';
2
+ import { transformArticles } from './articles';
3
+ import { transformDecorateNotebookOutputsWithSlugs } from './notebooks';
4
+ export async function applyCustomPageTransformsInPlace(page, opts) {
5
+ if (opts?.apiUrl) {
6
+ await transformArticles(page.mdast, {
7
+ apiUrl: opts.apiUrl,
8
+ venue: opts.venue,
9
+ });
10
+ }
11
+ transformDecorateNotebookOutputsWithSlugs(page);
25
12
  }
@@ -1,3 +1,3 @@
1
1
  import type { PageLoader } from '@myst-theme/common';
2
2
  export declare function transformDecorateNotebookOutputsWithSlugs(page: PageLoader): void;
3
- //# sourceMappingURL=outputs.d.ts.map
3
+ //# sourceMappingURL=notebooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notebooks.d.ts","sourceRoot":"","sources":["../../src/transforms/notebooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAIrD,wBAAgB,yCAAyC,CAAC,IAAI,EAAE,UAAU,QAmBzE"}
@@ -1,14 +1,13 @@
1
1
  import { normalizeLabel } from 'myst-common';
2
2
  import { selectAll } from 'unist-util-select';
3
3
  export function transformDecorateNotebookOutputsWithSlugs(page) {
4
- selectAll('container[kind=figure]:has(outputs), embed:has(outputs), container[kind=table]:has(outputs)', page.mdast).forEach((node) => {
5
- var _a, _b;
4
+ selectAll('container[kind=figure]:has(output), embed:has(output), container[kind=table]:has(output)', page.mdast).forEach((node) => {
6
5
  const { source } = node;
7
6
  const outputs = selectAll('outputs', node);
8
7
  if (source) {
9
8
  const sideEffectOutputs = outputs[0];
10
- sideEffectOutputs.notebookSlug = (_a = source.slug) !== null && _a !== void 0 ? _a : 'unknown';
11
- sideEffectOutputs.html_id = (_b = normalizeLabel(source.label)) === null || _b === void 0 ? void 0 : _b.html_id;
9
+ sideEffectOutputs.notebookSlug = source.slug ?? 'unknown';
10
+ sideEffectOutputs.html_id = normalizeLabel(source.label)?.html_id;
12
11
  }
13
12
  else {
14
13
  console.warn(`no "source" on node`, node);