@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
@@ -1 +1 @@
1
- {"version":3,"file":"articles.d.ts","sourceRoot":"","sources":["../src/articles.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAuC1D,eAAO,MAAM,kBAAkB;;CAA0C,CAAC"}
1
+ {"version":3,"file":"articles.d.ts","sourceRoot":"","sources":["../src/articles.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAoC1D,eAAO,MAAM,kBAAkB;;CAA0C,CAAC"}
package/dist/articles.js CHANGED
@@ -1,15 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { ArticleListing } from '@curvenote/theme';
2
+ import { ArticleCard } from '@curvenote-theme/ui';
3
3
  const ArticlesRenderer = ({ node }) => {
4
- var _a, _b, _c, _d, _e, _f, _g;
5
- return (_jsxs("div", { children: [!node.error && (_jsx(ArticleListing, { total: node.total, works: node.items, layout: node.layout, narrow: !node.wide, v2: true, show: {
6
- collection: (_a = node['show-collection']) !== null && _a !== void 0 ? _a : false,
7
- kind: (_b = node['show-kind']) !== null && _b !== void 0 ? _b : false,
8
- thumbnail: (_c = node['show-thumbnails']) !== null && _c !== void 0 ? _c : false,
9
- date: (_d = node['show-date']) !== null && _d !== void 0 ? _d : false,
10
- count: (_e = node['show-count']) !== null && _e !== void 0 ? _e : false,
11
- authors: (_f = node['show-authors']) !== null && _f !== void 0 ? _f : false,
12
- doi: (_g = node['show-doi']) !== null && _g !== void 0 ? _g : false,
13
- } })), !node.error && node.items.length === 0 && (_jsx("div", { className: "px-2 py-4 text-gray-600 border-gray-500 border-gray-[1px] rounded bg-gray-50", children: "There are no articles in this listing yet." })), node.error && (_jsx("div", { className: "text-red-500 p-4 my-2 bg-red-50 border-[1px] border-red-500 rounded", children: node.error }))] }));
4
+ return (_jsxs("div", { children: [!node.error && (_jsx("div", { className: "space-y-6", children: node.items.map((article) => (_jsx(ArticleCard, { to: `/articles/${article.slug ?? article.id}`, article: article, showThumbnails: node['show-thumbnails'] ?? false, showAuthors: node['show-authors'] ?? false, showDoi: node['show-doi'] ?? false, showDate: node['show-date'] ?? false }, article.id))) })), !node.error && node.items.length === 0 && (_jsx("div", { className: "px-2 py-4 text-gray-600 border-gray-500 border-gray-[1px] rounded-sm bg-gray-50", children: "There are no articles in this listing yet." })), node.error && (_jsx("div", { className: "text-red-500 p-4 my-2 bg-red-50 border-[1px] border-red-500 rounded-sm", children: node.error }))] }));
14
5
  };
15
6
  export const ARTICLES_RENDERERS = { curvenoteArticles: ArticlesRenderer };
@@ -0,0 +1,18 @@
1
+ import type { NodeRenderer } from '@myst-theme/providers';
2
+ export declare enum AdmonitionKind {
3
+ admonition = "admonition",
4
+ attention = "attention",
5
+ caution = "caution",
6
+ danger = "danger",
7
+ error = "error",
8
+ important = "important",
9
+ hint = "hint",
10
+ note = "note",
11
+ seealso = "seealso",
12
+ tip = "tip",
13
+ warning = "warning"
14
+ }
15
+ export declare const ADMONITION_RENDERERS: {
16
+ admonition: NodeRenderer;
17
+ };
18
+ //# sourceMappingURL=admonition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admonition.d.ts","sourceRoot":"","sources":["../../src/components/admonition.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AA8B1D,oBAAY,cAAc;IACxB,UAAU,eAAe;IACzB,SAAS,cAAc;IACvB,OAAO,YAAY;IACnB,MAAM,WAAW;IACjB,KAAK,UAAU;IACf,SAAS,cAAc;IACvB,IAAI,SAAS;IACb,IAAI,SAAS;IACb,OAAO,YAAY;IACnB,GAAG,QAAQ;IACX,OAAO,YAAY;CACpB;AA8PD,eAAO,MAAM,oBAAoB;;CAAqC,CAAC"}
@@ -0,0 +1,146 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Collapsible, CollapsibleContent, CollapsibleTrigger, Button, SimpleTooltip, } from '@curvenote-theme/ui';
3
+ import { ChevronRight, Link as LinkIcon, Info, AlertTriangle, AlertCircle, XCircle, Megaphone, Lightbulb, Zap, ArrowRight, SquarePen, } from 'lucide-react';
4
+ import { useState } from 'react';
5
+ import { MyST } from 'myst-to-react';
6
+ import { cn } from '@curvenote/react-utils';
7
+ import { toast } from 'sonner';
8
+ import { cva } from 'class-variance-authority';
9
+ import { Link } from 'react-router';
10
+ // Admonition types and their configurations
11
+ export var AdmonitionKind;
12
+ (function (AdmonitionKind) {
13
+ AdmonitionKind["admonition"] = "admonition";
14
+ AdmonitionKind["attention"] = "attention";
15
+ AdmonitionKind["caution"] = "caution";
16
+ AdmonitionKind["danger"] = "danger";
17
+ AdmonitionKind["error"] = "error";
18
+ AdmonitionKind["important"] = "important";
19
+ AdmonitionKind["hint"] = "hint";
20
+ AdmonitionKind["note"] = "note";
21
+ AdmonitionKind["seealso"] = "seealso";
22
+ AdmonitionKind["tip"] = "tip";
23
+ AdmonitionKind["warning"] = "warning";
24
+ })(AdmonitionKind || (AdmonitionKind = {}));
25
+ const ADMONITION_CONFIGS = {
26
+ [AdmonitionKind.note]: { kind: AdmonitionKind.note, color: 'blue', icon: Info },
27
+ [AdmonitionKind.important]: { kind: AdmonitionKind.important, color: 'blue', icon: Zap },
28
+ [AdmonitionKind.hint]: { kind: AdmonitionKind.hint, color: 'green', icon: Lightbulb },
29
+ [AdmonitionKind.seealso]: { kind: AdmonitionKind.seealso, color: 'green', icon: ArrowRight },
30
+ [AdmonitionKind.tip]: { kind: AdmonitionKind.tip, color: 'green', icon: SquarePen },
31
+ [AdmonitionKind.attention]: { kind: AdmonitionKind.attention, color: 'yellow', icon: Megaphone },
32
+ [AdmonitionKind.warning]: { kind: AdmonitionKind.warning, color: 'yellow', icon: AlertTriangle },
33
+ [AdmonitionKind.caution]: { kind: AdmonitionKind.caution, color: 'yellow', icon: AlertCircle },
34
+ [AdmonitionKind.danger]: { kind: AdmonitionKind.danger, color: 'red', icon: AlertCircle },
35
+ [AdmonitionKind.error]: { kind: AdmonitionKind.error, color: 'red', icon: XCircle },
36
+ [AdmonitionKind.admonition]: { kind: AdmonitionKind.admonition, color: 'blue', icon: Info },
37
+ };
38
+ // CVA variants for admonition styling
39
+ const admonitionVariants = cva('border border-muted border-l-2 bg-muted/30', {
40
+ variants: {
41
+ color: {
42
+ blue: 'border-l-blue-600',
43
+ green: 'border-l-green-600',
44
+ yellow: 'border-l-yellow-600',
45
+ red: 'border-l-red-600',
46
+ },
47
+ variant: {
48
+ default: '',
49
+ collapsible: 'group',
50
+ },
51
+ },
52
+ defaultVariants: {
53
+ color: 'blue',
54
+ variant: 'default',
55
+ },
56
+ });
57
+ const iconVariants = cva('w-5 h-5 mt-0.5 flex-shrink-0 self-center', {
58
+ variants: {
59
+ color: {
60
+ blue: 'text-blue-600 dark:text-blue-400',
61
+ green: 'text-green-600 dark:text-green-400',
62
+ yellow: 'text-yellow-600 dark:text-yellow-400',
63
+ red: 'text-red-600 dark:text-red-400',
64
+ },
65
+ },
66
+ defaultVariants: {
67
+ color: 'blue',
68
+ },
69
+ });
70
+ function getClasses(className) {
71
+ const classes = className
72
+ ?.split(' ')
73
+ .map((s) => s.trim().toLowerCase())
74
+ .filter((s) => !!s) ?? [];
75
+ return [...new Set(classes)];
76
+ }
77
+ function getFirstKind({ kind, classes = [], }) {
78
+ if (kind === AdmonitionKind.note || classes.includes('note')) {
79
+ return ADMONITION_CONFIGS[AdmonitionKind.note];
80
+ }
81
+ if (kind === AdmonitionKind.important || classes.includes('important')) {
82
+ return ADMONITION_CONFIGS[AdmonitionKind.important];
83
+ }
84
+ if (kind === AdmonitionKind.hint || classes.includes('hint')) {
85
+ return ADMONITION_CONFIGS[AdmonitionKind.hint];
86
+ }
87
+ if (kind === AdmonitionKind.seealso || classes.includes('seealso')) {
88
+ return ADMONITION_CONFIGS[AdmonitionKind.seealso];
89
+ }
90
+ if (kind === AdmonitionKind.tip || classes.includes('tip')) {
91
+ return ADMONITION_CONFIGS[AdmonitionKind.tip];
92
+ }
93
+ if (kind === AdmonitionKind.attention || classes.includes('attention')) {
94
+ return ADMONITION_CONFIGS[AdmonitionKind.attention];
95
+ }
96
+ if (kind === AdmonitionKind.warning || classes.includes('warning')) {
97
+ return ADMONITION_CONFIGS[AdmonitionKind.warning];
98
+ }
99
+ if (kind === AdmonitionKind.caution || classes.includes('caution')) {
100
+ return ADMONITION_CONFIGS[AdmonitionKind.caution];
101
+ }
102
+ if (kind === AdmonitionKind.danger || classes.includes('danger')) {
103
+ return ADMONITION_CONFIGS[AdmonitionKind.danger];
104
+ }
105
+ if (kind === AdmonitionKind.error || classes.includes('error')) {
106
+ return ADMONITION_CONFIGS[AdmonitionKind.error];
107
+ }
108
+ return ADMONITION_CONFIGS[AdmonitionKind.note];
109
+ }
110
+ const AdmonitionComponent = ({ id, title, content, defaultOpen, config, isDropdown, hideIcon, className, }) => {
111
+ const [isOpen, setIsOpen] = useState(defaultOpen);
112
+ const IconComponent = config.icon;
113
+ const handleCopyLink = async () => {
114
+ const url = `${window.location.origin}${window.location.pathname}#${id}`;
115
+ try {
116
+ await navigator.clipboard.writeText(url);
117
+ toast.success('Link copied to clipboard');
118
+ }
119
+ catch (err) {
120
+ console.error('Failed to copy link:', err);
121
+ }
122
+ };
123
+ if (!isDropdown) {
124
+ return (_jsx("div", { className: "overflow-hidden my-4 rounded-xs", children: _jsxs("div", { className: cn(admonitionVariants({ color: config.color }), className), children: [_jsxs("div", { className: "flex gap-3 items-start px-4 py-2", children: [!hideIcon && (_jsx(IconComponent, { className: iconVariants({ color: config.color }) })), _jsx("div", { className: "flex-1 min-w-0", children: title && _jsx("div", { className: "self-center font-medium text-foreground", children: title }) })] }), _jsx("div", { className: "mx-4 my-2 text-muted-foreground", children: content })] }) }));
125
+ }
126
+ return (_jsx("div", { className: "overflow-hidden my-4 rounded-xs", children: _jsx("div", { className: cn(admonitionVariants({
127
+ color: config.color,
128
+ variant: 'collapsible',
129
+ }), className), children: _jsxs(Collapsible, { open: isOpen, onOpenChange: setIsOpen, children: [_jsx(CollapsibleTrigger, { asChild: true, children: _jsxs("button", { className: "flex justify-between items-start p-4 w-full text-left cursor-pointer", children: [_jsxs("div", { className: "flex gap-3 items-start", children: [_jsx("div", { className: "flex-shrink-0 mt-1.5", children: _jsx(ChevronRight, { className: cn('w-4 h-4 transition-transform duration-200', {
130
+ 'rotate-90': isOpen,
131
+ }) }) }), _jsxs("div", { className: "flex gap-3 items-start", children: [!hideIcon && (_jsx(IconComponent, { className: iconVariants({ color: config.color }) })), _jsx("span", { className: "font-medium text-foreground", children: title })] })] }), _jsx(SimpleTooltip, { title: "Copy link", children: _jsx(Button, { variant: "ghost", size: "sm", onClick: (e) => {
132
+ e.stopPropagation();
133
+ handleCopyLink();
134
+ }, className: "opacity-0 transition-opacity group-hover:opacity-100 flex-0", asChild: true, children: _jsx(Link, { to: `#${id}`, children: _jsx(LinkIcon, { className: "w-4 h-4" }) }) }) })] }) }), _jsx(CollapsibleContent, { className: cn('px-7 pb-4 overflow-hidden', 'data-[state=closed]:animate-collapsible-up data-[state=open]:animate-collapsible-down duration-100'), children: _jsx("div", { className: "space-y-3 text-muted-foreground", children: content }) })] }) }) }));
135
+ };
136
+ const AdmonitionRenderer = ({ node, className }) => {
137
+ const [title, ...rest] = node.children;
138
+ const classes = getClasses(node.class);
139
+ const config = getFirstKind({ kind: node.kind, classes });
140
+ const isDropdown = classes.includes('dropdown');
141
+ const hideIcon = node.icon === false;
142
+ const isOpen = node.open === true;
143
+ const useTitle = title?.type === 'admonitionTitle';
144
+ return (_jsx(AdmonitionComponent, { id: node.identifier || node.key, title: useTitle ? _jsx(MyST, { ast: [title] }) : undefined, content: useTitle ? _jsx(MyST, { ast: rest }) : _jsx(MyST, { ast: node.children }), defaultOpen: isOpen, config: config, isDropdown: isDropdown, hideIcon: hideIcon, className: className }));
145
+ };
146
+ export const ADMONITION_RENDERERS = { admonition: AdmonitionRenderer };
@@ -0,0 +1,5 @@
1
+ export declare function CiteFigureBar({ doi: doiString, className }: {
2
+ doi: string;
3
+ className?: string;
4
+ }): import("react/jsx-runtime").JSX.Element | null;
5
+ //# sourceMappingURL=cite-figurebar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cite-figurebar.d.ts","sourceRoot":"","sources":["../../src/components/cite-figurebar.tsx"],"names":[],"mappings":"AAwFA,wBAAgB,aAAa,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,kDA2D/F"}
@@ -0,0 +1,73 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import useSWR from 'swr';
3
+ import { selectAll } from 'unist-util-select';
4
+ import { Image, LightboxContainer } from '@curvenote-theme/ui';
5
+ import { cn } from '@curvenote/react-utils';
6
+ import { MyST } from 'myst-to-react';
7
+ import { doi } from 'doi-utils';
8
+ // Fetcher function for the OpenRxiv API
9
+ async function openRxivFetcher(url) {
10
+ const response = await fetch(url);
11
+ if (!response.ok) {
12
+ throw new Error(`Failed to fetch OpenRxiv data: ${response.status} ${response.statusText}`);
13
+ }
14
+ return response.json();
15
+ }
16
+ // Hook to fetch OpenRxiv data
17
+ function useOpenRxivData(url) {
18
+ const { data, error, isLoading } = useSWR(url, openRxivFetcher, {
19
+ revalidateOnFocus: false,
20
+ revalidateOnReconnect: false,
21
+ dedupingInterval: 300000, // Cache for 5 minutes
22
+ errorRetryCount: 2,
23
+ errorRetryInterval: 1000,
24
+ });
25
+ return {
26
+ data,
27
+ error,
28
+ isLoading,
29
+ };
30
+ }
31
+ // Specialized image component for figures
32
+ function FigureImageComponent({ image, caption, }) {
33
+ return (_jsx("div", { className: "overflow-hidden relative bg-gray-50 rounded-lg", children: _jsx(Image, { src: image.url, srcOptimized: image.urlOptimized, urlSource: image.urlSource, alt: image.alt || 'Figure', className: "object-cover w-full h-auto", caption: caption }) }));
34
+ }
35
+ // Main component that renders up to 3 figures
36
+ export function CiteFigureBar({ doi: doiString, className }) {
37
+ const url = `https://overlay.curvenote.dev/doi/${doi.normalize(doiString)}.json`;
38
+ const { data, error, isLoading } = useOpenRxivData(url);
39
+ if (isLoading || error || !data?.mdast) {
40
+ return null;
41
+ }
42
+ // Extract figure containers from the mdast
43
+ const figures = selectAll('container[kind=figure]', data.mdast);
44
+ // Take only the first 3 figures
45
+ const displayFigures = figures.slice(0, 3);
46
+ if (displayFigures.length === 0) {
47
+ return null;
48
+ }
49
+ const imageList = figures
50
+ .map((figure) => {
51
+ const image = figure.children.find((child) => child.type === 'image');
52
+ const caption = figure.children.find((child) => child.type === 'caption');
53
+ if (!image)
54
+ return null;
55
+ return {
56
+ src: image.url,
57
+ srcOptimized: image.urlOptimized,
58
+ urlSource: image.urlSource,
59
+ alt: image.alt,
60
+ caption: caption,
61
+ };
62
+ })
63
+ .filter((image) => image !== null);
64
+ return (_jsx(LightboxContainer, { imageList: imageList, children: _jsx("div", { className: cn('grid grid-cols-1 gap-4 md:grid-cols-3', className), children: displayFigures.map((figure, index) => {
65
+ // Find the image within the figure container
66
+ const image = figure.children.find((child) => child.type === 'image');
67
+ const caption = figure.children.find((child) => child.type === 'caption');
68
+ if (!image) {
69
+ return null;
70
+ }
71
+ return (_jsxs("div", { className: "flex flex-col", children: [_jsx(FigureImageComponent, { image: image, caption: caption }), _jsx(MyST, { ast: caption, className: "text-xs line-clamp-5" })] }, figure.key || index));
72
+ }) }) }));
73
+ }
@@ -0,0 +1,6 @@
1
+ export declare function isYouTubeUrl(url?: string): boolean;
2
+ export declare function getYouTubeVideoId(url: string): string | null;
3
+ export declare function CiteYouTube({ url }: {
4
+ url: string;
5
+ }): import("react/jsx-runtime").JSX.Element | null;
6
+ //# sourceMappingURL=cite-youtube.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cite-youtube.d.ts","sourceRoot":"","sources":["../../src/components/cite-youtube.tsx"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAclD;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkB5D;AAED,wBAAgB,WAAW,CAAC,EAAE,GAAG,EAAE,EAAE;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,kDAgBnD"}
@@ -0,0 +1,45 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ export function isYouTubeUrl(url) {
3
+ if (!url)
4
+ return false;
5
+ try {
6
+ const urlObj = new URL(url);
7
+ const isValid = urlObj.hostname === 'youtube.com' ||
8
+ urlObj.hostname === 'www.youtube.com' ||
9
+ urlObj.hostname === 'youtu.be' ||
10
+ urlObj.hostname === 'www.youtu.be';
11
+ if (!isValid)
12
+ return false;
13
+ return !!getYouTubeVideoId(url);
14
+ }
15
+ catch {
16
+ return false;
17
+ }
18
+ }
19
+ export function getYouTubeVideoId(url) {
20
+ try {
21
+ const urlObj = new URL(url);
22
+ if (urlObj.hostname === 'youtu.be' || urlObj.hostname === 'www.youtu.be') {
23
+ return urlObj.pathname.slice(1);
24
+ }
25
+ if (urlObj.hostname === 'youtube.com' || urlObj.hostname === 'www.youtube.com') {
26
+ if (urlObj.pathname === '/watch' && urlObj.searchParams.has('v')) {
27
+ return urlObj.searchParams.get('v');
28
+ }
29
+ if (urlObj.pathname.startsWith('/embed/')) {
30
+ return urlObj.pathname.slice(7);
31
+ }
32
+ }
33
+ return null;
34
+ }
35
+ catch {
36
+ return null;
37
+ }
38
+ }
39
+ export function CiteYouTube({ url }) {
40
+ const videoId = getYouTubeVideoId(url);
41
+ if (!videoId)
42
+ return null;
43
+ const embedUrl = `https://www.youtube.com/embed/${videoId}`;
44
+ return (_jsx("div", { className: "aspect-video w-full mb-2", children: _jsx("iframe", { src: embedUrl, title: "YouTube video player", allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture", allowFullScreen: true, className: "w-full h-full" }) }));
45
+ }
@@ -0,0 +1,12 @@
1
+ import type { NodeRenderer } from '@myst-theme/providers';
2
+ import type { GenericParent } from 'myst-common';
3
+ export declare const CiteGroup: NodeRenderer<GenericParent>;
4
+ export declare const Cite: ({ label, error, children, className, }: {
5
+ label?: string;
6
+ error?: boolean;
7
+ children: React.ReactNode;
8
+ className?: string;
9
+ }) => import("react/jsx-runtime").JSX.Element;
10
+ export declare const CiteRenderer: NodeRenderer;
11
+ export declare const CITE_RENDERERS: Record<string, NodeRenderer>;
12
+ //# sourceMappingURL=cite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cite.d.ts","sourceRoot":"","sources":["../../src/components/cite.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAoHjD,eAAO,MAAM,SAAS,EAAE,YAAY,CAAC,aAAa,CAiBjD,CAAC;AAEF,eAAO,MAAM,IAAI,GAAI,wCAKlB;IACD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,4CAkCA,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,YAO1B,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAGvD,CAAC"}
@@ -0,0 +1,76 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useReferences, useSiteManifest } from '@myst-theme/providers';
3
+ import { doi } from 'doi-utils';
4
+ import { HoverPopover, MyST } from 'myst-to-react';
5
+ import { createId } from 'myst-common';
6
+ import { visit } from 'unist-util-visit';
7
+ import { cn } from '@curvenote/react-utils';
8
+ import { InlineError } from './inlineError';
9
+ import { useOpenAlexWork } from '../hooks/useOpenAlex';
10
+ import { reverseInvertedAbstract, formatAuthors } from '../utils/abstract';
11
+ import { LinkCard } from '@curvenote-theme/ui';
12
+ import { CiteFigureBar } from './cite-figurebar';
13
+ import { fromHtml } from 'hast-util-from-html';
14
+ import { toMdast } from 'hast-util-to-mdast';
15
+ import { CiteYouTube, isYouTubeUrl } from './cite-youtube';
16
+ // TODO:
17
+ // this should be turned into an upgrade step when we do citations.
18
+ // We are only expecting very basic HTML in the citations, so this should be fine.
19
+ function convertHtmlToMdast(html) {
20
+ const hast = fromHtml(html, { fragment: true });
21
+ const mdast = toMdast(hast);
22
+ // Ensure all nodes have a keys for react rendering errors
23
+ visit(mdast, (node) => {
24
+ node.key ??= createId();
25
+ });
26
+ return mdast;
27
+ }
28
+ function useNumberedReferences() {
29
+ const config = useSiteManifest();
30
+ const numbered_references = !!config?.options?.numbered_references;
31
+ return numbered_references;
32
+ }
33
+ function CiteChild({ html, doi: doiString, url }) {
34
+ const { data: openAlexData, error, isLoading } = useOpenAlexWork(doiString);
35
+ if (doiString && !error) {
36
+ const abstract = openAlexData?.abstract_inverted_index
37
+ ? reverseInvertedAbstract(openAlexData.abstract_inverted_index)
38
+ : '';
39
+ const authors = formatAuthors(openAlexData?.authorships);
40
+ const journal = openAlexData?.primary_location?.source?.display_name;
41
+ const year = openAlexData?.publication_year;
42
+ return (_jsx(LinkCard, { url: doi.buildUrl(doiString), title: journal && year ? `${journal} (${year})` : journal || year, size: "lg", description: _jsxs("div", { className: "flex flex-col gap-3 max-w-none prose", children: [openAlexData?.title && (_jsx("div", { className: "flex flex-col gap-1 font-bold", children: _jsx("div", { className: "text-sm leading-relaxed", children: openAlexData.title.replace(/<[^>]+>/g, '') }) })), authors && (_jsx("div", { className: "flex flex-col gap-1", children: _jsx("div", { className: "text-sm", children: authors }) })), abstract && (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("div", { className: "text-xs font-bold", children: "Abstract" }), _jsx("div", { className: "overflow-y-auto max-h-48 text-xs leading-relaxed", children: abstract })] })), _jsx(CiteFigureBar, { doi: doiString }), isLoading && (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("div", { className: "text-sm font-medium text-gray-900", children: "DOI" }), _jsx("div", { className: "text-sm", children: doiString }), _jsx("div", { className: "text-xs text-gray-500", children: "Loading additional information..." })] })), error && (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("div", { className: "text-sm font-medium text-gray-900", children: "DOI" }), _jsx("div", { className: "text-sm", children: doiString }), _jsx("div", { className: "text-xs text-gray-500", children: "Unable to load additional information" })] })), !isLoading && !error && !openAlexData && (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("div", { className: "text-sm font-medium text-gray-900", children: "DOI" }), _jsx("div", { className: "text-sm", children: doiString })] }))] }) }));
43
+ }
44
+ const mdast = convertHtmlToMdast(html);
45
+ return (_jsxs("div", { className: "hover-document article w-[500px] sm:max-w-[500px] p-3", children: [url && isYouTubeUrl(url) && _jsx(CiteYouTube, { url: url }), _jsx(MyST, { ast: mdast })] }));
46
+ }
47
+ export const CiteGroup = ({ node, className }) => {
48
+ const allCite = node.children?.every((child) => child.type === 'cite') ?? false;
49
+ return (_jsx("span", { className: cn({
50
+ 'cite-group': allCite,
51
+ 'xref-group': !allCite,
52
+ narrative: node.kind === 'narrative',
53
+ parenthetical: node.kind === 'parenthetical',
54
+ }, className), children: _jsx(MyST, { ast: node.children }) }));
55
+ };
56
+ export const Cite = ({ label, error, children, className, }) => {
57
+ const references = useReferences();
58
+ if (!label) {
59
+ return (_jsx(InlineError, { value: "cite (no label)", message: 'Citation Has No Label', className: className }));
60
+ }
61
+ const { html, doi: doiString, url: refUrl } = references?.cite?.data[label] ?? {};
62
+ if (error) {
63
+ return _jsx(InlineError, { value: label, message: 'Citation Not Found', className: className });
64
+ }
65
+ const url = doiString ? doi.buildUrl(doiString) : refUrl;
66
+ const isButtonLike = (className ?? '').split(' ').includes('button');
67
+ return (_jsx(HoverPopover, { openDelay: 300, card: _jsx(CiteChild, { html: html, doi: doiString, url: url }), children: _jsxs("cite", { className: className, children: [url && (_jsx("a", { href: url, target: "_blank", rel: "noreferrer", className: cn({ 'hover-link': !isButtonLike }), children: children })), !url && _jsx("span", { className: "hover-link", children: children })] }) }));
68
+ };
69
+ export const CiteRenderer = ({ node, className }) => {
70
+ const numbered = useNumberedReferences();
71
+ return (_jsx(Cite, { label: node.label, error: node.error, className: cn(className, node.class), children: numbered && node.kind === 'parenthetical' ? node.enumerator : _jsx(MyST, { ast: node.children }) }));
72
+ };
73
+ export const CITE_RENDERERS = {
74
+ citeGroup: CiteGroup,
75
+ cite: CiteRenderer,
76
+ };
@@ -0,0 +1,3 @@
1
+ import type { NodeRenderers } from '@myst-theme/providers';
2
+ export declare const DEFINITION_LIST_RENDERERS: NodeRenderers;
3
+ //# sourceMappingURL=definition-list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definition-list.d.ts","sourceRoot":"","sources":["../../src/components/definition-list.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAgB,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAuCzE,eAAO,MAAM,yBAAyB,EAAE,aAIvC,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from '@curvenote/react-utils';
3
+ import { HashLink, MyST } from 'myst-to-react';
4
+ const DefinitionListRenderer = ({ node, className }) => {
5
+ return (_jsx("dl", { className: cn('my-5', className), id: node.html_id || node.identifier || node.key, children: _jsx(MyST, { ast: node.children }) }));
6
+ };
7
+ const DefinitionTermRenderer = ({ node, className }) => {
8
+ const allowedStrongTypes = new Set(['text', 'emphasis']);
9
+ const makeStrong = node.children?.reduce((allowed, n) => allowed && allowedStrongTypes.has(n.type), true) ?? false;
10
+ const id = node.html_id || node.identifier || node.key;
11
+ return (_jsxs("dt", { id: id, className: cn('group', className), children: [makeStrong ? (_jsx("strong", { children: _jsx(MyST, { ast: node.children }) })) : (_jsx(MyST, { ast: node.children })), _jsx(HashLink, { id: id, title: "Link to Definition Term", hover: true, className: "ml-2" })] }));
12
+ };
13
+ const DefinitionDescriptionRenderer = ({ node, className }) => {
14
+ return (_jsx("dd", { id: node.html_id || node.identifier || node.key, className: className, children: _jsx(MyST, { ast: node.children }) }));
15
+ };
16
+ export const DEFINITION_LIST_RENDERERS = {
17
+ definitionList: DefinitionListRenderer,
18
+ definitionTerm: DefinitionTermRenderer,
19
+ definitionDescription: DefinitionDescriptionRenderer,
20
+ };
@@ -0,0 +1,5 @@
1
+ import type { NodeRenderer } from '@myst-theme/providers';
2
+ export declare const FAQ_RENDERERS: {
3
+ admonition: NodeRenderer;
4
+ };
5
+ //# sourceMappingURL=faq.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"faq.d.ts","sourceRoot":"","sources":["../../src/components/faq.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AA6F1D,eAAO,MAAM,aAAa;;CAA8B,CAAC"}
@@ -0,0 +1,34 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Collapsible, CollapsibleContent, CollapsibleTrigger, Button, SimpleTooltip, } from '@curvenote-theme/ui';
3
+ import { ChevronRight, Link } from 'lucide-react';
4
+ import { useState } from 'react';
5
+ import { MyST } from 'myst-to-react';
6
+ import { cn } from '@curvenote/react-utils';
7
+ import { toast } from 'sonner';
8
+ const FAQItemComponent = ({ id, title, content, defaultOpen, }) => {
9
+ const [isOpen, setIsOpen] = useState(defaultOpen);
10
+ const handleCopyLink = async () => {
11
+ const url = `${window.location.origin}${window.location.pathname}#${id}`;
12
+ try {
13
+ await navigator.clipboard.writeText(url);
14
+ toast.success('Link copied to clipboard');
15
+ }
16
+ catch (err) {
17
+ console.error('Failed to copy link:', err);
18
+ }
19
+ };
20
+ return (_jsx("div", { className: "border-b border-muted-background group", children: _jsxs(Collapsible, { open: isOpen, onOpenChange: setIsOpen, children: [_jsx(CollapsibleTrigger, { asChild: true, children: _jsxs("button", { className: "flex justify-between items-start py-4 w-full text-left cursor-pointer", children: [_jsxs("div", { className: "flex gap-3 items-start", children: [_jsx("div", { className: "flex-shrink-0 mt-1.5", children: _jsx(ChevronRight, { className: cn('w-4 h-4 transition-transform duration-200', {
21
+ 'rotate-90': isOpen,
22
+ }) }) }), _jsx("span", { className: "font-medium text-foreground", children: title })] }), _jsx(SimpleTooltip, { title: "Copy link", children: _jsx(Button, { variant: "ghost", size: "sm", onClick: (e) => {
23
+ e.stopPropagation();
24
+ handleCopyLink();
25
+ }, className: "opacity-0 transition-opacity group-hover:opacity-100 flex-0", children: _jsx(Link, { className: "w-4 h-4" }) }) })] }) }), _jsx(CollapsibleContent, { className: "px-7 pb-4 data-[state=closed]:animate-collapsible-up data-[state=open]:animate-collapsible-down overflow-hidden duration-100", children: _jsx("div", { className: "space-y-3 text-gray-700", children: content }) })] }) }));
26
+ };
27
+ const FAQRenderer = ({ node, className }) => {
28
+ const [title, ...rest] = node.children;
29
+ const classes = node.class || [];
30
+ const isOpen = node.open === true;
31
+ const useTitle = title?.type === 'admonitionTitle';
32
+ return (_jsx(FAQItemComponent, { id: node.identifier || node.key, title: useTitle ? _jsx(MyST, { ast: [title] }) : undefined, content: useTitle ? _jsx(MyST, { ast: rest }) : _jsx(MyST, { ast: node.children }), defaultOpen: isOpen }));
33
+ };
34
+ export const FAQ_RENDERERS = { admonition: FAQRenderer };
@@ -0,0 +1,6 @@
1
+ /* Hero Component Max-Width Classes */
2
+ @source inline("{sm:,md:,lg:,xl:,2xl:,}max-w-{[0%],[5%],[10%],[15%],[20%],[25%],[30%],[35%],[40%],[45%],[50%],[55%],[60%],[65%],[70%],[75%],[80%],[85%],[90%],[95%],[100%]}");
3
+
4
+ /* Hero Component Overlay Classes */
5
+ @source inline("{sm:,md:,lg:,xl:,2xl:,}bg-{white,black}/{0,10,20,30,40,50,60,70,80,90,100}");
6
+ @source inline("{sm:,md:,lg:,xl:,2xl:,}backdrop-blur{-xs,-sm,-md,-lg}");
@@ -0,0 +1,28 @@
1
+ import type { NodeRenderer } from '@myst-theme/providers';
2
+ import './hero.css';
3
+ interface HeroProps {
4
+ className?: string;
5
+ backgroundImage?: string;
6
+ kicker?: React.ReactNode;
7
+ title: React.ReactNode;
8
+ content?: React.ReactNode;
9
+ actions?: Array<{
10
+ label: React.ReactNode;
11
+ href?: string;
12
+ variant?: 'default' | 'outline';
13
+ className?: string;
14
+ onClick?: () => void;
15
+ }>;
16
+ light?: boolean;
17
+ footer?: React.ReactNode;
18
+ maxWidth?: number | [number, number?, number?, number?, number?];
19
+ overlay?: number | [number, number?, number?, number?, number?];
20
+ }
21
+ export declare function HeroComponent({ className, backgroundImage, kicker, title, content, actions, footer, maxWidth, overlay, light, }: HeroProps): import("react/jsx-runtime").JSX.Element;
22
+ export declare const HERO_RENDERERS: {
23
+ block: {
24
+ 'block[kind=hero]': NodeRenderer;
25
+ };
26
+ };
27
+ export {};
28
+ //# sourceMappingURL=hero.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hero.d.ts","sourceRoot":"","sources":["../../src/components/hero.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAM1D,OAAO,YAAY,CAAC;AAEpB,UAAU,SAAS;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,OAAO,CAAC,EAAE,KAAK,CAAC;QACd,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;QACvB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;QAChC,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;KACtB,CAAC,CAAC;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IACjE,OAAO,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;CACjE;AAiDD,wBAAgB,aAAa,CAAC,EAC5B,SAAS,EACT,eAAe,EACf,MAAM,EACN,KAAK,EACL,OAAO,EACP,OAAO,EACP,MAAM,EACN,QAAQ,EACR,OAAO,EACP,KAAa,GACd,EAAE,SAAS,2CA8FX;AAuCD,eAAO,MAAM,cAAc;;;;CAAkD,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare const HeroExamples: () => import("react/jsx-runtime").JSX.Element;
2
+ export default HeroExamples;
3
+ //# sourceMappingURL=hero.example.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hero.example.d.ts","sourceRoot":"","sources":["../../src/components/hero.example.tsx"],"names":[],"mappings":"AAIA,eAAO,MAAM,YAAY,+CAsDxB,CAAC;AAEF,eAAe,YAAY,CAAC"}
@@ -0,0 +1,30 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import { HeroComponent } from './hero';
4
+ // Example usage of the HeroComponent
5
+ export const HeroExamples = () => {
6
+ return (_jsxs("div", { className: "", children: [_jsx(HeroComponent, { backgroundImage: "https://agu.curve.space/build/_assets/header-AYU7MMYZ.webp", title: "Notebooks Now!", content: "In 2024, AGU will be developing the capability for authors to publish computational notebooks alongside their AGU publications. If you would like to be involved in this initiative, please indicate your interest at submission time or by completing the form below, and we will get in touch.", maxWidth: [100, 70, 70, 60, 50], overlay: [60, 30, 30, -10, 10], actions: [
7
+ {
8
+ label: 'Subscribe for Updates',
9
+ href: '/subscribe',
10
+ variant: 'default',
11
+ },
12
+ {
13
+ label: 'Read Editorial',
14
+ href: '/editorial',
15
+ variant: 'outline',
16
+ },
17
+ ], footer: "Note: as we are rolling out this pilot initiative, not all submissions will be chosen for this new publication format. Our aim is by the end of 2024 that this submission type can be chosen for any new AGU publication." }), _jsx(HeroComponent, { kicker: "SciPy Proceedings", backgroundImage: "https://cdn.curvenote.com/static/site/scipy/scipy-hero-v2-tilt.webp", title: "Python in Science Conferences", content: "Join us for an exciting exploration of how Python is transforming scientific research and conference presentations. Learn about the latest tools, techniques, and best practices.", maxWidth: [100, 60, 60, 50, 40], actions: [
18
+ {
19
+ label: 'Register Now',
20
+ href: '/register',
21
+ variant: 'default',
22
+ },
23
+ {
24
+ label: 'View Schedule',
25
+ href: '/schedule',
26
+ variant: 'outline',
27
+ },
28
+ ] }), _jsx(HeroComponent, { className: "bg-gradient-to-r from-blue-900 to-purple-900", title: "Simple Hero Section", content: "This is a hero section without a background image, using a gradient background instead." })] }));
29
+ };
30
+ export default HeroExamples;