@curvenote/theme-ui 1.0.1 → 2.0.1

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 (166) hide show
  1. package/dist/components/layout/app-layout.d.ts +1 -1
  2. package/dist/components/layout/app-layout.d.ts.map +1 -1
  3. package/dist/components/layout/app-layout.js +6 -5
  4. package/dist/components/layout/app-sidebar.d.ts.map +1 -1
  5. package/dist/components/layout/app-sidebar.js +10 -6
  6. package/dist/components/layout/article-layout.d.ts +1 -1
  7. package/dist/components/layout/article-layout.d.ts.map +1 -1
  8. package/dist/components/layout/article-layout.js +6 -7
  9. package/dist/components/layout/header.js +1 -1
  10. package/dist/components/layout/index.d.ts +1 -0
  11. package/dist/components/layout/index.d.ts.map +1 -1
  12. package/dist/components/layout/index.js +1 -0
  13. package/dist/components/layout/loading-bar.d.ts +8 -1
  14. package/dist/components/layout/loading-bar.d.ts.map +1 -1
  15. package/dist/components/layout/loading-bar.js +12 -4
  16. package/dist/components/layout/site-header.d.ts +6 -1
  17. package/dist/components/layout/site-header.d.ts.map +1 -1
  18. package/dist/components/layout/site-header.js +7 -4
  19. package/dist/components/layout/types.d.ts +6 -0
  20. package/dist/components/layout/types.d.ts.map +1 -1
  21. package/dist/components/providers/analytics-boundary.d.ts +18 -0
  22. package/dist/components/providers/analytics-boundary.d.ts.map +1 -0
  23. package/dist/components/providers/analytics-boundary.js +53 -0
  24. package/dist/components/providers/analytics-dev-log.d.ts +11 -0
  25. package/dist/components/providers/analytics-dev-log.d.ts.map +1 -0
  26. package/dist/components/providers/analytics-dev-log.js +46 -0
  27. package/dist/components/providers/analytics-dev-tray.d.ts +2 -0
  28. package/dist/components/providers/analytics-dev-tray.d.ts.map +1 -0
  29. package/dist/components/providers/analytics-dev-tray.js +56 -0
  30. package/dist/components/providers/article-versions-provider.d.ts +19 -0
  31. package/dist/components/providers/article-versions-provider.d.ts.map +1 -0
  32. package/dist/components/providers/article-versions-provider.js +13 -0
  33. package/dist/components/providers/curvenote-providers.d.ts +12 -13
  34. package/dist/components/providers/curvenote-providers.d.ts.map +1 -1
  35. package/dist/components/providers/curvenote-providers.js +20 -27
  36. package/dist/components/providers/design.d.ts +3 -33
  37. package/dist/components/providers/design.d.ts.map +1 -1
  38. package/dist/components/providers/design.js +64 -21
  39. package/dist/components/providers/index.d.ts +4 -2
  40. package/dist/components/providers/index.d.ts.map +1 -1
  41. package/dist/components/providers/index.js +3 -1
  42. package/dist/components/providers/lightbox-provider.d.ts +8 -0
  43. package/dist/components/providers/lightbox-provider.d.ts.map +1 -1
  44. package/dist/components/providers/lightbox-provider.js +28 -5
  45. package/dist/components/providers/overlay-depth.d.ts +16 -0
  46. package/dist/components/providers/overlay-depth.d.ts.map +1 -0
  47. package/dist/components/providers/overlay-depth.js +16 -0
  48. package/dist/components/providers/ping-boundary.d.ts +3 -1
  49. package/dist/components/providers/ping-boundary.d.ts.map +1 -1
  50. package/dist/components/providers/ping-boundary.js +7 -4
  51. package/dist/components/providers/platform-providers.d.ts +0 -7
  52. package/dist/components/providers/platform-providers.d.ts.map +1 -1
  53. package/dist/components/providers/platform-providers.js +0 -14
  54. package/dist/components/ui/abbreviations.d.ts +3 -1
  55. package/dist/components/ui/abbreviations.d.ts.map +1 -1
  56. package/dist/components/ui/abbreviations.js +13 -6
  57. package/dist/components/ui/accessibility-skip-to.d.ts +13 -3
  58. package/dist/components/ui/accessibility-skip-to.d.ts.map +1 -1
  59. package/dist/components/ui/accessibility-skip-to.js +4 -1
  60. package/dist/components/ui/arrow.d.ts +6 -0
  61. package/dist/components/ui/arrow.d.ts.map +1 -0
  62. package/dist/components/ui/arrow.js +15 -0
  63. package/dist/components/ui/article-actions-downloads.d.ts.map +1 -1
  64. package/dist/components/ui/article-actions-downloads.js +74 -7
  65. package/dist/components/ui/article-actions-dropdown.d.ts +2 -1
  66. package/dist/components/ui/article-actions-dropdown.d.ts.map +1 -1
  67. package/dist/components/ui/article-actions-dropdown.js +102 -21
  68. package/dist/components/ui/article-actions-share.d.ts +18 -0
  69. package/dist/components/ui/article-actions-share.d.ts.map +1 -1
  70. package/dist/components/ui/article-actions-share.js +38 -2
  71. package/dist/components/ui/article-actions.d.ts.map +1 -1
  72. package/dist/components/ui/article-actions.js +16 -3
  73. package/dist/components/ui/article-bar.d.ts +3 -1
  74. package/dist/components/ui/article-bar.d.ts.map +1 -1
  75. package/dist/components/ui/article-bar.js +19 -5
  76. package/dist/components/ui/article-card.js +1 -1
  77. package/dist/components/ui/author-popover.d.ts +2 -1
  78. package/dist/components/ui/author-popover.d.ts.map +1 -1
  79. package/dist/components/ui/author-popover.js +42 -7
  80. package/dist/components/ui/backmatter.d.ts.map +1 -1
  81. package/dist/components/ui/backmatter.js +23 -5
  82. package/dist/components/ui/banner.d.ts.map +1 -1
  83. package/dist/components/ui/banner.js +1 -1
  84. package/dist/components/ui/bibliography.d.ts +2 -2
  85. package/dist/components/ui/bibliography.d.ts.map +1 -1
  86. package/dist/components/ui/bibliography.js +10 -9
  87. package/dist/components/ui/button.d.ts +1 -1
  88. package/dist/components/ui/button.d.ts.map +1 -1
  89. package/dist/components/ui/button.js +2 -0
  90. package/dist/components/ui/calendar.d.ts +10 -0
  91. package/dist/components/ui/calendar.d.ts.map +1 -0
  92. package/dist/components/ui/calendar.js +85 -0
  93. package/dist/components/ui/citation.d.ts +2 -2
  94. package/dist/components/ui/citation.d.ts.map +1 -1
  95. package/dist/components/ui/citation.js +45 -15
  96. package/dist/components/ui/collapsible-backmatter-section.d.ts +28 -0
  97. package/dist/components/ui/collapsible-backmatter-section.d.ts.map +1 -0
  98. package/dist/components/ui/collapsible-backmatter-section.js +52 -0
  99. package/dist/components/ui/cookie-banner.d.ts +1 -1
  100. package/dist/components/ui/cookie-banner.d.ts.map +1 -1
  101. package/dist/components/ui/cookie-banner.js +9 -2
  102. package/dist/components/ui/document-outline.d.ts.map +1 -1
  103. package/dist/components/ui/document-outline.js +38 -20
  104. package/dist/components/ui/footer-links.d.ts.map +1 -1
  105. package/dist/components/ui/footer-links.js +4 -0
  106. package/dist/components/ui/frontmatter-badges.d.ts +15 -5
  107. package/dist/components/ui/frontmatter-badges.d.ts.map +1 -1
  108. package/dist/components/ui/frontmatter-badges.js +41 -15
  109. package/dist/components/ui/frontmatter.js +1 -1
  110. package/dist/components/ui/hash-link.d.ts +56 -0
  111. package/dist/components/ui/hash-link.d.ts.map +1 -0
  112. package/dist/components/ui/hash-link.js +83 -0
  113. package/dist/components/ui/image.d.ts +5 -2
  114. package/dist/components/ui/image.d.ts.map +1 -1
  115. package/dist/components/ui/image.js +10 -8
  116. package/dist/components/ui/index.d.ts +10 -2
  117. package/dist/components/ui/index.d.ts.map +1 -1
  118. package/dist/components/ui/index.js +9 -2
  119. package/dist/components/ui/keywords.d.ts +4 -0
  120. package/dist/components/ui/keywords.d.ts.map +1 -0
  121. package/dist/components/ui/keywords.js +18 -0
  122. package/dist/components/ui/label.d.ts +4 -0
  123. package/dist/components/ui/label.d.ts.map +1 -0
  124. package/dist/components/ui/label.js +6 -0
  125. package/dist/components/ui/license-description.d.ts.map +1 -1
  126. package/dist/components/ui/license-description.js +8 -5
  127. package/dist/components/ui/license-frontmatter.d.ts.map +1 -1
  128. package/dist/components/ui/license-frontmatter.js +14 -3
  129. package/dist/components/ui/lightbox-container.d.ts.map +1 -1
  130. package/dist/components/ui/lightbox-container.js +2 -2
  131. package/dist/components/ui/lightbox.d.ts +3 -1
  132. package/dist/components/ui/lightbox.d.ts.map +1 -1
  133. package/dist/components/ui/lightbox.js +155 -25
  134. package/dist/components/ui/link-card.d.ts +2 -1
  135. package/dist/components/ui/link-card.d.ts.map +1 -1
  136. package/dist/components/ui/link-card.js +2 -2
  137. package/dist/components/ui/pagination.d.ts +15 -0
  138. package/dist/components/ui/pagination.d.ts.map +1 -0
  139. package/dist/components/ui/pagination.js +31 -0
  140. package/dist/components/ui/popover.js +1 -1
  141. package/dist/components/ui/search.d.ts +2 -1
  142. package/dist/components/ui/search.d.ts.map +1 -1
  143. package/dist/components/ui/search.js +24 -8
  144. package/dist/components/ui/select.d.ts +16 -0
  145. package/dist/components/ui/select.d.ts.map +1 -0
  146. package/dist/components/ui/select.js +38 -0
  147. package/dist/components/ui/separator.js +1 -1
  148. package/dist/components/ui/sidebar.d.ts +2 -12
  149. package/dist/components/ui/sidebar.d.ts.map +1 -1
  150. package/dist/components/ui/sidebar.js +2 -34
  151. package/dist/components/ui/tooltip.d.ts +4 -2
  152. package/dist/components/ui/tooltip.d.ts.map +1 -1
  153. package/dist/components/ui/tooltip.js +5 -4
  154. package/dist/components/ui/types.d.ts +9 -8
  155. package/dist/components/ui/types.d.ts.map +1 -1
  156. package/dist/components/ui/types.js +1 -0
  157. package/dist/lib/dedupeAbbreviations.d.ts +10 -0
  158. package/dist/lib/dedupeAbbreviations.d.ts.map +1 -0
  159. package/dist/lib/dedupeAbbreviations.js +36 -0
  160. package/dist/lib/knownParts.d.ts +18 -0
  161. package/dist/lib/knownParts.d.ts.map +1 -1
  162. package/dist/lib/knownParts.js +38 -1
  163. package/package.json +12 -9
  164. package/dist/components/providers/types.d.ts +0 -30
  165. package/dist/components/providers/types.d.ts.map +0 -1
  166. package/dist/components/providers/types.js +0 -1
@@ -1,8 +1,10 @@
1
1
  export declare function AuthorsList({ source }: {
2
2
  source?: 'project' | 'article';
3
3
  }): import("react/jsx-runtime").JSX.Element | null;
4
- export declare function ArticleBar({ source, sticky, }: {
4
+ export declare function ArticleBar({ source, sticky, tight, className, }: {
5
5
  source?: 'project' | 'article';
6
6
  sticky?: 'top' | 'bottom';
7
+ tight?: boolean;
8
+ className?: string;
7
9
  }): import("react/jsx-runtime").JSX.Element;
8
10
  //# sourceMappingURL=article-bar.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"article-bar.d.ts","sourceRoot":"","sources":["../../../src/components/ui/article-bar.tsx"],"names":[],"mappings":"AA6BA,wBAAgB,WAAW,CAAC,EAAE,MAAkB,EAAE,EAAE;IAAE,MAAM,CAAC,EAAE,SAAS,GAAG,SAAS,CAAA;CAAE,kDAcrF;AAED,wBAAgB,UAAU,CAAC,EACzB,MAAkB,EAClB,MAAM,GACP,EAAE;IACD,MAAM,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAC/B,MAAM,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;CAC3B,2CAmCA"}
1
+ {"version":3,"file":"article-bar.d.ts","sourceRoot":"","sources":["../../../src/components/ui/article-bar.tsx"],"names":[],"mappings":"AAiDA,wBAAgB,WAAW,CAAC,EAAE,MAAkB,EAAE,EAAE;IAAE,MAAM,CAAC,EAAE,SAAS,GAAG,SAAS,CAAA;CAAE,kDAcrF;AAED,wBAAgB,UAAU,CAAC,EACzB,MAAkB,EAClB,MAAM,EACN,KAAa,EACb,SAAS,GACV,EAAE;IACD,MAAM,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAC/B,MAAM,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,2CAwDA"}
@@ -6,7 +6,12 @@ import { ArticleActions } from './article-actions';
6
6
  import { useFrontmatter, useProjectManifest } from '@myst-theme/providers';
7
7
  import { cn } from '@curvenote/react-utils';
8
8
  function AuthorsPopoverList({ authors = [], affiliations = [], }) {
9
- return (_jsx("div", { className: "flex flex-row flex-wrap gap-x-2", children: authors.map((author, idx) => (_jsxs("div", { className: "flex items-center", children: [_jsx(AuthorPopover, { author: author, affiliations: affiliations }), author.corresponding && _jsx(EmailLink, { email: author.email }), author.orcid && _jsx(OrcidBadge, { orcid: author.orcid, className: "ml-1" }), idx < authors.length - 1 && _jsx("span", { className: "text-muted-foreground", children: "," })] }, author.orcid || author.email || idx))) }));
9
+ return (_jsx("div", { className: "flex flex-row flex-wrap gap-x-2", children: authors.map((author, idx) => {
10
+ const authorName = author.nameParsed
11
+ ? `${author.nameParsed?.given ?? ''} ${author.nameParsed?.family ?? ''}`.trim()
12
+ : author.name;
13
+ return (_jsxs("div", { className: "flex items-center", children: [_jsx(AuthorPopover, { author: author, affiliations: affiliations, authorIndex: idx }), author.corresponding && (_jsx(EmailLink, { email: author.email, authorIndex: idx, authorName: authorName, isCorresponding: true })), author.orcid && (_jsx(OrcidBadge, { orcid: author.orcid, className: "ml-1", authorIndex: idx, authorName: authorName, isCorresponding: !!author.corresponding })), idx < authors.length - 1 && _jsx("span", { className: "text-muted-foreground", children: "," })] }, author.orcid || author.email || idx));
14
+ }) }));
10
15
  }
11
16
  export function AuthorsList({ source = 'article' }) {
12
17
  const project = useProjectManifest();
@@ -19,14 +24,23 @@ export function AuthorsList({ source = 'article' }) {
19
24
  }
20
25
  return (_jsx(AuthorsPopoverList, { authors: frontmatter.authors, affiliations: frontmatter.affiliations }));
21
26
  }
22
- export function ArticleBar({ source = 'article', sticky, }) {
27
+ export function ArticleBar({ source = 'article', sticky, tight = false, className, }) {
23
28
  const project = useProjectManifest();
24
29
  const page = useFrontmatter();
25
30
  const frontmatter = source === 'project' ? project : page;
26
- return (_jsx("div", { className: cn('my-4 pointer-events-none', {
31
+ return (_jsx("div", { className: cn('pointer-events-none', {
32
+ 'my-4': !tight,
27
33
  'sticky top-0 pb-4': sticky === 'top',
28
34
  'sticky bottom-0 pt-4': sticky === 'bottom',
29
35
  // Add a full-width gradient fade-in pseudo element when sticky bottom
30
- 'before:absolute before:top-0 before:left-0 before:w-full before:h-4 before:pointer-events-none before:z-[-1] before:content-[""] before:bg-gradient-to-t before:from-background before:to-transparent': sticky === 'bottom',
31
- }), children: _jsxs("div", { className: cn('bg-background flex flex-col items-center py-3 sm:flex-row border-y border-border', 'pointer-events-auto'), children: [_jsx("div", { className: "flex flex-col flex-1 gap-1", children: _jsxs("div", { className: "flex gap-1 items-center mb-2 font-sans text-sm text-muted-foreground", children: [frontmatter?.date && (_jsx(DateString, { date: frontmatter?.date, spacer: !!frontmatter?.doi })), frontmatter?.doi && _jsx(DoiLink, { doi: frontmatter?.doi }), _jsx(LicenseBadges, { license: frontmatter?.license }), _jsx(OpenAccessBadge, { open_access: frontmatter?.open_access })] }) }), _jsx(ArticleActions, {})] }) }));
36
+ 'before:absolute before:top-0 before:left-0 before:w-full before:h-4 before:pointer-events-none before:z-[-1] before:content-[""] before:bg-linear-to-t before:from-background before:to-transparent': sticky === 'bottom',
37
+ }, className), children: _jsxs("div", { className: cn('flex flex-row items-center py-3 bg-background border-y border-border', 'pointer-events-auto'), children: [_jsx("div", { className: "flex flex-col flex-1 gap-1", children: _jsxs("div", { className: "flex gap-1 items-center pl-3 font-sans text-sm text-muted-foreground", children: [frontmatter?.date && (_jsx(DateString, { date: frontmatter?.date, spacer: !!frontmatter?.doi, format: {
38
+ year: 'numeric',
39
+ month: 'long',
40
+ day: 'numeric',
41
+ }, mobileFormat: {
42
+ year: 'numeric',
43
+ month: 'short',
44
+ day: 'numeric',
45
+ } })), frontmatter?.doi && _jsx(DoiLink, { doi: frontmatter?.doi, shortenOnSmallScreens: true }), _jsx(LicenseBadges, { license: frontmatter?.license, className: "hidden sm:inline-block" }), _jsx(OpenAccessBadge, { open_access: frontmatter?.open_access, className: "hidden sm:inline-block" })] }) }), _jsx(ArticleActions, {})] }) }));
32
46
  }
@@ -8,7 +8,7 @@ export function ArticleCard({ to, article, showThumbnails, showAuthors, showDoi
8
8
  src: article.links?.thumbnail || '',
9
9
  minDelay: 300,
10
10
  });
11
- return (_jsx(Link, { to: to, className: "block no-underline group hover:no-underline", prefetch: "intent", children: _jsx("article", { className: "overflow-hidden font-sans rounded-sm border transition-shadow border-gray-200/50 hover:shadow-md not-prose", children: _jsxs("div", { className: "flex", children: [showThumbnails && article.links?.thumbnail && (_jsxs("div", { className: "hidden relative flex-shrink-0 w-40 sm:block lg:w-50 xl:w-60", children: [_jsx("div", { className: "absolute inset-0 bg-center bg-no-repeat bg-cover transition-opacity duration-750", style: {
11
+ return (_jsx(Link, { to: to, className: "block no-underline group hover:no-underline", prefetch: "intent", children: _jsx("article", { className: "overflow-hidden font-sans rounded-sm border transition-shadow border-gray-200/50 hover:shadow-md not-prose", children: _jsxs("div", { className: "flex", children: [showThumbnails && article.links?.thumbnail && (_jsxs("div", { className: "hidden relative w-40 shrink-0 sm:block lg:w-50 xl:w-60", children: [_jsx("div", { className: "absolute inset-0 bg-center bg-no-repeat bg-cover transition-opacity duration-750", style: {
12
12
  backgroundImage: imageLoaded ? `url(${article.links.thumbnail})` : 'none',
13
13
  opacity: imageLoaded ? 1 : 0,
14
14
  } }), showPlaceholder && (_jsx("div", { className: "flex relative justify-center items-center h-full bg-gray-100 dark:bg-gray-800", children: _jsx(CurvenoteIcon, { className: "fill-gray-200 dark:fill-gray-900", height: 60, width: 60 }) })), _jsx("img", { ref: imgRef, src: article.links.thumbnail, className: "hidden", onLoad: handleImageLoad })] })), _jsxs("div", { className: "flex-1 p-6 min-w-0", children: [_jsx("div", { className: "mb-2 text-lg text-foreground", children: _jsx("span", { className: "transition-colors group-hover:text-blue-800 dark:group-hover:text-blue-500", children: article.title }) }), article.description && (_jsx("p", { className: "mb-3 text-sm font-light text-muted-foreground line-clamp-2", children: article.description })), _jsxs("div", { className: "flex flex-wrap gap-4 items-center text-xs font-light text-muted-foreground", children: [showAuthors && article.authors && article.authors.length > 0 && (_jsx("div", { className: "flex items-center", children: _jsx("span", { children: article.authors.length <= 3 ? (article.authors.map((author, index) => (_jsxs("span", { children: [author.name, index < (article.authors?.length ?? 0) - 1
@@ -1,7 +1,8 @@
1
1
  import type { PageFrontmatter } from 'myst-frontmatter';
2
- export declare function AuthorPopover({ author, affiliations, className, }: {
2
+ export declare function AuthorPopover({ author, affiliations, className, authorIndex, }: {
3
3
  author: Required<PageFrontmatter>['authors'][0];
4
4
  affiliations: PageFrontmatter['affiliations'];
5
5
  className?: string;
6
+ authorIndex?: number;
6
7
  }): import("react/jsx-runtime").JSX.Element;
7
8
  //# sourceMappingURL=author-popover.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"author-popover.d.ts","sourceRoot":"","sources":["../../../src/components/ui/author-popover.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAsBxD,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,YAAY,EACZ,SAAS,GACV,EAAE;IACD,MAAM,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,YAAY,EAAE,eAAe,CAAC,cAAc,CAAC,CAAC;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,2CAkGA"}
1
+ {"version":3,"file":"author-popover.d.ts","sourceRoot":"","sources":["../../../src/components/ui/author-popover.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAuBxD,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,YAAY,EACZ,SAAS,EACT,WAAW,GACZ,EAAE;IACD,MAAM,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,YAAY,EAAE,eAAe,CAAC,cAAc,CAAC,CAAC;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,2CA8IA"}
@@ -4,6 +4,7 @@ import { cn } from '../../lib/utils';
4
4
  import { PopoverArrow } from '@radix-ui/react-popover';
5
5
  import { Copy } from 'lucide-react';
6
6
  import { toast } from 'sonner';
7
+ import { useAnalytics } from '../providers';
7
8
  function Affiliation({ affiliations, affiliationId, }) {
8
9
  const affiliation = affiliations?.find((a) => a.id === affiliationId);
9
10
  if (!affiliation) {
@@ -12,25 +13,59 @@ function Affiliation({ affiliations, affiliationId, }) {
12
13
  }
13
14
  return _jsx("div", { className: "text-xs text-muted-foreground", children: affiliation.name });
14
15
  }
15
- export function AuthorPopover({ author, affiliations, className, }) {
16
+ export function AuthorPopover({ author, affiliations, className, authorIndex, }) {
17
+ const capture = useAnalytics();
18
+ const authorName = author.nameParsed
19
+ ? [author.nameParsed?.given, author.nameParsed?.family].filter(Boolean).join(' ').trim()
20
+ : author.name;
21
+ const baseAuthorProps = {
22
+ authorIndex,
23
+ authorName,
24
+ isCorresponding: !!author.corresponding,
25
+ };
16
26
  const handleCopyEmail = () => {
17
27
  if (author.email) {
18
28
  navigator.clipboard.writeText(author.email);
29
+ capture('article_author_interaction', {
30
+ ...baseAuthorProps,
31
+ action: 'email_copied',
32
+ surface: 'author_popover',
33
+ authorEmail: author.email,
34
+ });
19
35
  toast.success('Email copied to clipboard');
20
36
  }
21
37
  };
22
38
  const handleCopyOrcid = () => {
23
39
  if (author.orcid) {
24
40
  navigator.clipboard.writeText(author.orcid);
41
+ capture('article_author_interaction', {
42
+ ...baseAuthorProps,
43
+ action: 'orcid_copied',
44
+ surface: 'author_popover',
45
+ authorOrcid: author.orcid,
46
+ });
25
47
  toast.success('ORCID copied to clipboard');
26
48
  }
27
49
  };
28
- return (_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx("button", { className: cn('cursor-pointer hover:underline text-[15px]', className), type: "button", children: author.nameParsed
29
- ? `${author.nameParsed?.given} ${author.nameParsed?.family}`
30
- : author.name }) }), _jsxs(PopoverContent, { className: "p-4 w-80", onOpenAutoFocus: (event) => {
50
+ return (_jsxs(Popover, { onOpenChange: (open) => open &&
51
+ capture('article_author_interaction', {
52
+ ...baseAuthorProps,
53
+ action: 'popover_opened',
54
+ surface: 'article_bar',
55
+ authorOrcid: author.orcid,
56
+ authorEmail: author.email,
57
+ }), children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx("button", { className: cn('cursor-pointer hover:underline text-[15px]', className), type: "button", children: authorName }) }), _jsxs(PopoverContent, { className: "p-4 w-80", onOpenAutoFocus: (event) => {
31
58
  // This stops the popover from automatically focusing on the first input, the tooltip, when it opens
32
59
  event.preventDefault();
33
- }, children: [_jsx("div", { className: "mb-1 text-base font-semibold", children: author.nameParsed
34
- ? `${author.nameParsed?.given} ${author.nameParsed?.family}`
35
- : author.name }), author.email && (_jsxs("div", { className: "flex gap-1 items-center mb-1 text-xs text-muted-foreground", children: [_jsx("span", { className: "font-medium", children: "Email:" }), ' ', _jsx("a", { href: `mailto:${author.email}`, target: "_blank", rel: "noopener noreferrer", className: "underline", children: author.email }), _jsx(SimpleTooltip, { title: "Copy email address", children: _jsx(Button, { onClick: handleCopyEmail, variant: "ghost", size: "xs", children: _jsx(Copy, {}) }) })] })), author.orcid && (_jsxs("div", { className: "flex gap-1 items-center mb-1 text-xs text-muted-foreground", children: [_jsx("span", { className: "font-medium", children: "ORCID:" }), ' ', _jsx("a", { href: `https://orcid.org/${author.orcid}`, target: "_blank", rel: "noopener noreferrer", className: "underline", children: author.orcid }), _jsx(SimpleTooltip, { title: "Copy ORCID", children: _jsx(Button, { onClick: handleCopyOrcid, variant: "ghost", size: "xs", children: _jsx(Copy, {}) }) })] })), author.affiliations && author.affiliations.length > 0 && (_jsxs("div", { className: "mb-1", children: [_jsx("span", { className: "text-xs font-medium", children: "Affiliations:" }), _jsx("div", { className: "ml-2 flex flex-col gap-0.5", children: author.affiliations.map((affiliationId) => (_jsx(Affiliation, { affiliations: affiliations, affiliationId: affiliationId }, affiliationId))) })] })), author.roles && author.roles.length > 0 && (_jsxs("div", { className: "mt-2 text-xs", children: [_jsx("span", { className: "font-medium", children: "Roles:" }), " ", author.roles.join(', ')] })), _jsx(PopoverArrow, { className: "fill-gray-200" })] })] }));
60
+ }, children: [_jsx("div", { className: "mb-1 text-base font-semibold", children: authorName }), author.email && (_jsxs("div", { className: "flex gap-1 items-center mb-1 text-xs text-muted-foreground", children: [_jsx("span", { className: "font-medium", children: "Email:" }), ' ', _jsx("a", { href: `mailto:${author.email}`, target: "_blank", rel: "noopener noreferrer", className: "underline", onClick: () => capture('article_author_interaction', {
61
+ ...baseAuthorProps,
62
+ action: 'email_clicked',
63
+ surface: 'author_popover',
64
+ authorEmail: author.email,
65
+ }), children: author.email }), _jsx(SimpleTooltip, { title: "Copy email address", children: _jsx(Button, { onClick: handleCopyEmail, variant: "ghost", size: "xs", children: _jsx(Copy, {}) }) })] })), author.orcid && (_jsxs("div", { className: "flex gap-1 items-center mb-1 text-xs text-muted-foreground", children: [_jsx("span", { className: "font-medium", children: "ORCID:" }), ' ', _jsx("a", { href: `https://orcid.org/${author.orcid}`, target: "_blank", rel: "noopener noreferrer", className: "underline", onClick: () => capture('article_author_interaction', {
66
+ ...baseAuthorProps,
67
+ action: 'orcid_opened',
68
+ surface: 'author_popover',
69
+ authorOrcid: author.orcid,
70
+ }), children: author.orcid }), _jsx(SimpleTooltip, { title: "Copy ORCID", children: _jsx(Button, { onClick: handleCopyOrcid, variant: "ghost", size: "xs", children: _jsx(Copy, {}) }) })] })), author.affiliations && author.affiliations.length > 0 && (_jsxs("div", { className: "mb-1", children: [_jsx("span", { className: "text-xs font-medium", children: "Affiliations:" }), _jsx("div", { className: "ml-2 flex flex-col gap-0.5", children: author.affiliations.map((affiliationId) => (_jsx(Affiliation, { affiliations: affiliations, affiliationId: affiliationId }, affiliationId))) })] })), author.roles && author.roles.length > 0 && (_jsxs("div", { className: "mt-2 text-xs", children: [_jsx("span", { className: "font-medium", children: "Roles:" }), " ", author.roles.join(', ')] })), _jsx(PopoverArrow, { className: "fill-gray-200" })] })] }));
36
71
  }
@@ -1 +1 @@
1
- {"version":3,"file":"backmatter.d.ts","sourceRoot":"","sources":["../../../src/components/ui/backmatter.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,aAAa,EAAE,MAAM,aAAa,CAAC;AAQ5D,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAC;AAkCvE,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,WAAW,GACZ,GAAE;IACD,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,WAAW,CAAC,EAAE,4BAA4B,CAAC;CACvC,GAAG,OAAO,CAiBf;AAED,wBAAgB,UAAU,mDAczB;AAED,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"backmatter.d.ts","sourceRoot":"","sources":["../../../src/components/ui/backmatter.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,aAAa,EAAE,MAAM,aAAa,CAAC;AAS5D,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAC;AA4CvE,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,WAAW,GACZ,GAAE;IACD,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,WAAW,CAAC,EAAE,4BAA4B,CAAC;CACvC,GAAG,OAAO,CA2Bf;AAED,wBAAgB,UAAU,mDAoBzB;AAED,eAAe,UAAU,CAAC"}
@@ -5,11 +5,13 @@ import { Bibliography } from './bibliography';
5
5
  import { Footnotes } from './footnotes';
6
6
  import { Acknowledgements } from './acknowledgements';
7
7
  import { DataAvailability } from './data-availability';
8
+ import { Keywords } from './keywords';
8
9
  import { selectAll } from 'unist-util-select';
9
10
  import { extractKnownParts } from '../../lib/knownParts';
10
11
  import { copyNode } from 'myst-common';
11
12
  import { LicenseDescription } from './license-description';
12
- import { PART_IDS } from './types';
13
+ import { useDesign } from '../providers/design';
14
+ import { SkipToAnchor } from './accessibility-skip-to';
13
15
  function getTrees(mdast, parts) {
14
16
  return [mdast, ...Object.values(parts ?? {}).map((part) => part.mdast)].filter(Boolean);
15
17
  }
@@ -24,6 +26,13 @@ function hasAbbreviations(frontmatter, trees) {
24
26
  function hasBibliography(cite) {
25
27
  return Object.keys(cite?.data ?? 0).length > 0;
26
28
  }
29
+ function hasLicenseDescription(frontmatter) {
30
+ return frontmatter?.license?.content !== undefined || frontmatter?.authors !== undefined;
31
+ }
32
+ function hasKeywords(frontmatter) {
33
+ const keywords = frontmatter?.keywords;
34
+ return Array.isArray(keywords) && keywords.length > 0;
35
+ }
27
36
  export function useBackmatter({ mdast, frontmatter, } = {}) {
28
37
  const references = useReferences();
29
38
  const pageFrontmatter = useFrontmatter();
@@ -33,17 +42,26 @@ export function useBackmatter({ mdast, frontmatter, } = {}) {
33
42
  const footnotes = hasFootnotes(trees);
34
43
  const abbreviations = hasAbbreviations(frontmatter, trees);
35
44
  const bibliography = hasBibliography(references?.cite);
36
- // Check for acknowledgements and data availability
45
+ const licenseDescription = hasLicenseDescription(pageFrontmatter);
46
+ const keywords = hasKeywords(frontmatter ?? pageFrontmatter);
47
+ // Check for acknowledgments and data availability
37
48
  const tree = copyNode(page || { type: 'root', children: [] });
38
49
  const knownParts = page ? extractKnownParts(tree, parts) : null;
39
50
  const acknowledgements = !!knownParts?.acknowledgments;
40
51
  const dataAvailability = !!knownParts?.data_availability;
41
- return footnotes || abbreviations || bibliography || acknowledgements || dataAvailability;
52
+ return (footnotes ||
53
+ abbreviations ||
54
+ bibliography ||
55
+ acknowledgements ||
56
+ dataAvailability ||
57
+ licenseDescription ||
58
+ keywords);
42
59
  }
43
60
  export function Backmatter() {
61
+ const design = useDesign();
44
62
  const hasBackmatter = useBackmatter();
45
- if (!hasBackmatter)
63
+ if (design.hide_backmatter || !hasBackmatter)
46
64
  return null;
47
- return (_jsxs(_Fragment, { children: [_jsx("div", { id: PART_IDS.skip_to_backmatter }), _jsx(Acknowledgements, {}), _jsx(DataAvailability, {}), _jsx(LicenseDescription, {}), _jsx(Footnotes, {}), _jsx(Abbreviations, {}), _jsx(Bibliography, {})] }));
65
+ return (_jsxs(_Fragment, { children: [_jsx(SkipToAnchor, { id: "skip-to-backmatter" }), !design.hide_acknowledgements && _jsx(Acknowledgements, {}), !design.hide_data_availability && _jsx(DataAvailability, {}), !design.hide_license_description && _jsx(LicenseDescription, {}), !design.hide_footnotes && _jsx(Footnotes, {}), design.hide_keywords === false && _jsx(Keywords, {}), design.hide_abbreviation_list !== true && (_jsx(Abbreviations, { hideManyAbbreviations: design.hide_abbreviation_list })), design.hide_bibliography !== true && (_jsx(Bibliography, { hideManyReferences: design.hide_bibliography }))] }));
48
66
  }
49
67
  export default Backmatter;
@@ -1 +1 @@
1
- {"version":3,"file":"banner.d.ts","sourceRoot":"","sources":["../../../src/components/ui/banner.tsx"],"names":[],"mappings":"AA0BA,wBAAgB,MAAM,CAAC,EACrB,MAAM,EACN,eAAe,EACf,KAAa,EACb,IAAY,GACb,EAAE;IACD,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,2CAiEA"}
1
+ {"version":3,"file":"banner.d.ts","sourceRoot":"","sources":["../../../src/components/ui/banner.tsx"],"names":[],"mappings":"AA0BA,wBAAgB,MAAM,CAAC,EACrB,MAAM,EACN,eAAe,EACf,KAAa,EACb,IAAY,GACb,EAAE;IACD,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,2CAoEA"}
@@ -33,7 +33,7 @@ export function Banner({ banner, bannerOptimized, inset = false, thin = false, }
33
33
  'h-[100px]': thin,
34
34
  'mb-[-50px]': inset && thin,
35
35
  'mb-8': !inset,
36
- }), children: _jsx("img", { ref: imgRef, src: bannerOptimized ?? banner, className: cn('mt-0 mb-0 object-cover object-center w-full h-full transition-[opacity,filter]', duration, {
36
+ }), children: _jsx("img", { ref: imgRef, src: bannerOptimized ?? banner, alt: "", role: "presentation", "aria-hidden": "true", className: cn('mt-0 mb-0 object-cover object-center w-full h-full transition-[opacity,filter]', duration, {
37
37
  'opacity-0 grayscale': !imageLoaded,
38
38
  'opacity-100 grayscale-0': imageLoaded,
39
39
  }), style: {
@@ -1,6 +1,6 @@
1
- export declare function Bibliography({ className, innerClassName, hideLongBibliography, }: {
1
+ export declare function Bibliography({ className, innerClassName, hideManyReferences, }: {
2
2
  className?: string;
3
3
  innerClassName?: string;
4
- hideLongBibliography?: false | number;
4
+ hideManyReferences?: boolean | number;
5
5
  }): import("react/jsx-runtime").JSX.Element | null;
6
6
  //# sourceMappingURL=bibliography.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bibliography.d.ts","sourceRoot":"","sources":["../../../src/components/ui/bibliography.tsx"],"names":[],"mappings":"AAOA,wBAAgB,YAAY,CAAC,EAC3B,SAAS,EACT,cAAc,EACd,oBAAyB,GAC1B,EAAE;IACD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;CACvC,kDAgDA"}
1
+ {"version":3,"file":"bibliography.d.ts","sourceRoot":"","sources":["../../../src/components/ui/bibliography.tsx"],"names":[],"mappings":"AAWA,wBAAgB,YAAY,CAAC,EAC3B,SAAS,EACT,cAAc,EACd,kBAA4C,GAC7C,EAAE;IACD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CACvC,kDAoDA"}
@@ -1,20 +1,21 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useReferences } from '@myst-theme/providers';
3
3
  import { cn } from '@curvenote/react-utils';
4
- import { HashLink } from 'myst-to-react';
5
- import { useState } from 'react';
6
- import { Button } from './button';
7
4
  import { PART_IDS } from './types';
8
- export function Bibliography({ className, innerClassName, hideLongBibliography = 15, }) {
5
+ import { useCollapsibleBackmatter, CollapsibleBackmatterHeader, CollapsibleBackmatterFooterButton, } from './collapsible-backmatter-section';
6
+ const DEFAULT_MANY_REFERENCES = 15;
7
+ export function Bibliography({ className, innerClassName, hideManyReferences = DEFAULT_MANY_REFERENCES, }) {
8
+ if (hideManyReferences === true)
9
+ hideManyReferences = DEFAULT_MANY_REFERENCES;
9
10
  const references = useReferences();
10
11
  const { order, data } = references?.cite ?? {};
11
12
  const filtered = order?.filter((l) => l);
12
- const [hidden, setHidden] = useState(true);
13
13
  if (!filtered || !data || filtered.length === 0)
14
14
  return null;
15
- const refs = hidden && hideLongBibliography ? filtered.slice(0, hideLongBibliography) : filtered;
16
- return (_jsxs("section", { id: PART_IDS.bibliography, className: cn(className), children: [_jsxs("div", { className: innerClassName, children: [!!hideLongBibliography && filtered.length > hideLongBibliography && (_jsx(Button, { variant: "outline", onClick: () => setHidden(!hidden), className: "float-right text-xs", children: hidden ? 'Show All' : 'Collapse' })), _jsxs("header", { className: "text-lg font-semibold text-stone-900 dark:text-white group", children: ["References", _jsx(HashLink, { id: PART_IDS.bibliography, title: "Link to References", hover: true, className: "ml-2" })] })] }), _jsx("div", { className: cn('pl-3 mb-8 text-xs text-stone-500 dark:text-stone-300', innerClassName), children: _jsxs("ol", { children: [refs.map((label) => {
15
+ const { hidden, toggle, displayedCount, isCollapsible } = useCollapsibleBackmatter(filtered.length, hideManyReferences, DEFAULT_MANY_REFERENCES);
16
+ const refs = filtered.slice(0, displayedCount);
17
+ return (_jsxs("section", { id: PART_IDS.bibliography, className: cn(className), children: [_jsx("div", { className: innerClassName, children: _jsx(CollapsibleBackmatterHeader, { id: PART_IDS.bibliography, title: "References", linkTitle: "Link to References", hidden: hidden, onToggle: toggle, isCollapsible: isCollapsible }) }), _jsx("div", { className: cn('pl-3 mb-8 text-xs text-stone-500 dark:text-stone-300', innerClassName), children: _jsxs("ol", { children: [refs.map((label) => {
17
18
  const { html } = data[label];
18
- return (_jsx("li", { className: "break-words", id: `cite-${label}`, dangerouslySetInnerHTML: { __html: html || '' } }, label));
19
- }), !!hideLongBibliography && filtered.length > hideLongBibliography && (_jsx("li", { className: "list-none text-center", children: _jsx(Button, { variant: "outline", onClick: () => setHidden(!hidden), className: "text-xs", children: hidden ? `Show all ${filtered.length} references` : 'Collapse references' }) }))] }) })] }));
19
+ return (_jsx("li", { className: "wrap-break-words", id: `cite-${label}`, dangerouslySetInnerHTML: { __html: html || '' } }, label));
20
+ }), isCollapsible && (_jsx(CollapsibleBackmatterFooterButton, { hidden: hidden, onToggle: toggle, totalCount: filtered.length, itemLabel: "references", sectionId: PART_IDS.bibliography, className: "list-none text-center", as: "li" }))] }) })] }));
20
21
  }
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import { type VariantProps } from 'class-variance-authority';
3
3
  declare const buttonVariants: (props?: ({
4
- variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | null | undefined;
4
+ variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | "action" | null | undefined;
5
5
  size?: "default" | "xs" | "sm" | "lg" | "icon" | null | undefined;
6
6
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
7
  declare function Button({ className, variant, size, asChild, ...props }: React.ComponentProps<'button'> & VariantProps<typeof buttonVariants> & {
@@ -1 +1 @@
1
- {"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../../src/components/ui/button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAIlE,QAAA,MAAM,cAAc;;;8EA2BnB,CAAC;AAEF,iBAAS,MAAM,CAAC,EACd,SAAS,EACT,OAAO,EACP,IAAI,EACJ,OAAe,EACf,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,GAC/B,YAAY,CAAC,OAAO,cAAc,CAAC,GAAG;IACpC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,2CAUF;AAED,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../../src/components/ui/button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAIlE,QAAA,MAAM,cAAc;;;8EA8BnB,CAAC;AAEF,iBAAS,MAAM,CAAC,EACd,SAAS,EACT,OAAO,EACP,IAAI,EACJ,OAAe,EACf,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,GAC/B,YAAY,CAAC,OAAO,cAAc,CAAC,GAAG;IACpC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,2CAUF;AAED,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC"}
@@ -12,6 +12,8 @@ const buttonVariants = cva("inline-flex items-center justify-center gap-2 whites
12
12
  secondary: 'bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80',
13
13
  ghost: 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
14
14
  link: 'text-primary underline-offset-4 hover:underline',
15
+ /** White, lightly-bordered control used for toolbar filter chips (e.g. date pickers). */
16
+ action: 'border border-stone-200 bg-white shadow-[0px_1px_2px_0px_rgba(68,64,60,0.24),0px_1px_3px_0px_rgba(68,64,60,0.12)] hover:bg-stone-50 dark:border-stone-700 dark:bg-stone-800 dark:hover:bg-stone-700/50 disabled:hover:bg-white dark:disabled:hover:bg-stone-800',
15
17
  },
16
18
  size: {
17
19
  default: 'h-9 px-4 py-2 has-[>svg]:px-3',
@@ -0,0 +1,10 @@
1
+ import * as React from 'react';
2
+ import { DayPicker } from 'react-day-picker';
3
+ export type CalendarProps = React.ComponentProps<typeof DayPicker>;
4
+ export type { DateRange } from 'react-day-picker';
5
+ declare function Calendar({ className, classNames, showOutsideDays, captionLayout, numberOfMonths, components: componentsProp, ...props }: CalendarProps): import("react/jsx-runtime").JSX.Element;
6
+ declare namespace Calendar {
7
+ var displayName: string;
8
+ }
9
+ export { Calendar };
10
+ //# sourceMappingURL=calendar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calendar.d.ts","sourceRoot":"","sources":["../../../src/components/ui/calendar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAM7C,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC,cAAc,CAAC,OAAO,SAAS,CAAC,CAAC;AACnE,YAAY,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAoDlD,iBAAS,QAAQ,CAAC,EAChB,SAAS,EACT,UAAU,EACV,eAAsB,EACtB,aAAa,EACb,cAAc,EACd,UAAU,EAAE,cAAc,EAC1B,GAAG,KAAK,EACT,EAAE,aAAa,2CAmEf;kBA3EQ,QAAQ;;;AA8EjB,OAAO,EAAE,QAAQ,EAAE,CAAC"}
@@ -0,0 +1,85 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import * as React from 'react';
3
+ import { ChevronDown, ChevronLeft, ChevronRight } from 'lucide-react';
4
+ import { DayPicker } from 'react-day-picker';
5
+ import { cn } from '../../lib/utils';
6
+ import { buttonVariants } from './button';
7
+ /** Shared shell for each month/year `<select>` (invisible select over a text label). */
8
+ const dropdownFieldShell = 'relative inline-flex h-7 items-center';
9
+ const dropdownCaptionLabel = cn('relative z-[1] inline-flex h-7 w-auto items-center gap-1 px-1 text-sm', 'pointer-events-none select-none');
10
+ /** Month nav chevrons: no persistent focus ring after mouse use. */
11
+ const navButtonClass = cn(buttonVariants({ variant: 'outline' }), 'h-7 w-7 bg-transparent p-0 opacity-80 hover:opacity-100', 'outline-none focus:outline-none focus-visible:ring-0 focus-visible:outline-none');
12
+ /**
13
+ * react-day-picker v8 dropdown captions: native `<select>` overlays a faux label.
14
+ * These classNames mirror the library layout but use our input/button tokens.
15
+ */
16
+ function dropdownCaptionClassNames(multiMonth) {
17
+ return {
18
+ caption: cn('relative mb-2 block min-h-8 px-9 text-center', multiMonth && 'pt-0.5'),
19
+ caption_dropdowns: 'relative inline-flex items-center justify-center gap-1.5',
20
+ dropdown_month: dropdownFieldShell,
21
+ dropdown_year: dropdownFieldShell,
22
+ caption_label: dropdownCaptionLabel,
23
+ dropdown: 'absolute inset-0 z-[2] h-full w-full cursor-pointer appearance-none border-0 bg-transparent opacity-0',
24
+ dropdown_icon: 'size-3.5 shrink-0 opacity-50',
25
+ vhidden: 'sr-only',
26
+ nav: 'inline-flex items-center whitespace-nowrap',
27
+ nav_button: navButtonClass,
28
+ nav_button_previous: 'absolute top-1/2 left-0 z-[3] -translate-y-1/2',
29
+ nav_button_next: 'absolute top-1/2 right-0 z-[3] -translate-y-1/2',
30
+ caption_start: multiMonth ? 'relative' : undefined,
31
+ caption_end: multiMonth ? 'relative' : undefined,
32
+ };
33
+ }
34
+ function defaultCaptionClassNames() {
35
+ return {
36
+ caption: 'relative flex items-center justify-center pt-1',
37
+ caption_label: 'text-sm font-medium',
38
+ nav: 'flex items-center space-x-1',
39
+ nav_button: cn(navButtonClass, 'opacity-50 hover:opacity-100'),
40
+ nav_button_previous: 'absolute left-1',
41
+ nav_button_next: 'absolute right-1',
42
+ };
43
+ }
44
+ function Calendar({ className, classNames, showOutsideDays = true, captionLayout, numberOfMonths, components: componentsProp, ...props }) {
45
+ const captionUsesDropdown = captionLayout === 'dropdown' || captionLayout === 'dropdown-buttons';
46
+ const multiMonth = (numberOfMonths ?? 1) > 1;
47
+ /** Fixed outer width; the 1rem between columns is flexible (captions may overlap into it). */
48
+ const multiMonthDropdown = multiMonth && captionUsesDropdown;
49
+ return (_jsx(DayPicker, { showOutsideDays: showOutsideDays, ...(captionLayout != null ? { captionLayout } : {}), ...(numberOfMonths != null ? { numberOfMonths } : {}), className: cn('p-3', className), classNames: {
50
+ root: cn('m-0', multiMonth && 'rdp-multiple_months'),
51
+ months: 'flex flex-col space-y-4 sm:flex-row sm:space-y-0 sm:space-x-4',
52
+ month: 'space-y-4',
53
+ table: 'w-full border-collapse space-y-1',
54
+ head_row: 'flex',
55
+ head_cell: 'w-8 rounded-md text-[0.8rem] font-normal text-muted-foreground',
56
+ row: 'mt-2 flex w-full',
57
+ cell: cn('relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-accent [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected].day-range-end)]:rounded-r-md', props.mode === 'range'
58
+ ? '[&:has(>.day-range-end)]:rounded-r-md [&:has(>.day-range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md'
59
+ : '[&:has([aria-selected])]:rounded-md'),
60
+ day: cn(buttonVariants({ variant: 'ghost' }), 'h-8 w-8 p-0 font-normal aria-selected:opacity-100'),
61
+ day_range_start: 'day-range-start',
62
+ day_range_end: 'day-range-end',
63
+ day_selected: 'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground',
64
+ day_today: 'bg-accent text-accent-foreground',
65
+ day_outside: 'day-outside text-muted-foreground aria-selected:bg-accent/50 aria-selected:text-muted-foreground',
66
+ day_disabled: 'text-muted-foreground opacity-50',
67
+ day_range_middle: 'aria-selected:bg-accent aria-selected:text-accent-foreground',
68
+ day_hidden: 'invisible',
69
+ ...(captionUsesDropdown
70
+ ? dropdownCaptionClassNames(multiMonth)
71
+ : defaultCaptionClassNames()),
72
+ ...classNames,
73
+ }, components: {
74
+ IconLeft: ({ className: chevronClassName, ...chevronProps }) => (_jsx(ChevronLeft, { className: cn('w-4 h-4', chevronClassName), ...chevronProps })),
75
+ IconRight: ({ className: chevronClassName, ...chevronProps }) => (_jsx(ChevronRight, { className: cn('w-4 h-4', chevronClassName), ...chevronProps })),
76
+ ...(captionUsesDropdown
77
+ ? {
78
+ IconDropdown: ({ className: iconClassName, ...iconProps }) => (_jsx(ChevronDown, { className: cn('size-3.5 shrink-0 opacity-50', iconClassName), ...iconProps })),
79
+ }
80
+ : {}),
81
+ ...componentsProp,
82
+ }, ...props }));
83
+ }
84
+ Calendar.displayName = 'Calendar';
85
+ export { Calendar };
@@ -1,7 +1,7 @@
1
1
  export declare function useShowCitation(): boolean;
2
2
  export declare function BibTeXCitationMenuItem(): import("react/jsx-runtime").JSX.Element | null;
3
- export declare function Citation({ className, children, }: {
4
- className?: string;
3
+ export declare function Citation({ children, onOpenChange, }: {
5
4
  children: React.ReactNode;
5
+ onOpenChange?: (open: boolean) => void;
6
6
  }): import("react/jsx-runtime").JSX.Element | null;
7
7
  //# sourceMappingURL=citation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"citation.d.ts","sourceRoot":"","sources":["../../../src/components/ui/citation.tsx"],"names":[],"mappings":"AAyDA,wBAAgB,eAAe,YAI9B;AAeD,wBAAgB,sBAAsB,mDAYrC;AAED,wBAAgB,QAAQ,CAAC,EACvB,SAAS,EACT,QAAQ,GACT,EAAE;IACD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,kDAoGA"}
1
+ {"version":3,"file":"citation.d.ts","sourceRoot":"","sources":["../../../src/components/ui/citation.tsx"],"names":[],"mappings":"AAgFA,wBAAgB,eAAe,YAI9B;AAeD,wBAAgB,sBAAsB,mDAuBrC;AAED,wBAAgB,QAAQ,CAAC,EACvB,QAAQ,EACR,YAAY,GACb,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACxC,kDA8GA"}
@@ -1,13 +1,26 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, DropdownMenuItem, } from '.';
3
- import { useProjectManifest } from '@myst-theme/providers';
2
+ import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger, DropdownMenuItem, } from '.';
3
+ import { useFrontmatter, useProjectManifest } from '@myst-theme/providers';
4
4
  import { getYear } from '../../lib/parse-date';
5
5
  import { doi } from 'doi-utils';
6
- import { cn } from '../../lib/utils';
7
6
  import { triggerBlobDownload } from './article-actions-downloads';
8
7
  import { DownloadIcon, Copy, FileHeart } from 'lucide-react';
9
8
  import { Button } from './button';
10
9
  import { toast } from 'sonner';
10
+ import { useAnalytics } from '../providers';
11
+ function useCitationMetadata() {
12
+ const project = useProjectManifest();
13
+ const frontmatter = useFrontmatter();
14
+ if (!project && !frontmatter)
15
+ return null;
16
+ return {
17
+ title: project?.title ?? frontmatter?.title,
18
+ date: project?.date ?? frontmatter?.date,
19
+ doi: project?.doi ?? frontmatter?.doi,
20
+ authors: project?.authors ?? frontmatter?.authors,
21
+ venue: project?.venue ?? frontmatter?.venue,
22
+ };
23
+ }
11
24
  function generateBibTeX(project) {
12
25
  const year = getYear(project.date);
13
26
  // Generate citation key from first author's family name and year
@@ -41,8 +54,8 @@ function generateBibTeX(project) {
41
54
  return bibtex;
42
55
  }
43
56
  export function useShowCitation() {
44
- const project = useProjectManifest();
45
- const doiUrl = doi.buildUrl(project?.doi);
57
+ const metadata = useCitationMetadata();
58
+ const doiUrl = doi.buildUrl(metadata?.doi);
46
59
  return !!doiUrl;
47
60
  }
48
61
  function handleDownloadBibTeX(project) {
@@ -53,18 +66,28 @@ function handleDownloadBibTeX(project) {
53
66
  triggerBlobDownload(blob, filename);
54
67
  }
55
68
  export function BibTeXCitationMenuItem() {
56
- const project = useProjectManifest();
69
+ const metadata = useCitationMetadata();
57
70
  const showCitation = useShowCitation();
58
- if (!showCitation || !project)
71
+ const capture = useAnalytics();
72
+ if (!showCitation || !metadata)
59
73
  return null;
60
- return (_jsxs(DropdownMenuItem, { onClick: () => handleDownloadBibTeX(project), children: [_jsx(FileHeart, { className: "mr-2 h-4 w-4" }), "BibTeX Citation"] }));
74
+ return (_jsxs(DropdownMenuItem, { onClick: () => {
75
+ capture('citation_download', {
76
+ action: 'clicked',
77
+ category: 'export',
78
+ format: 'bibtex',
79
+ surface: 'actions_menu_exports_submenu',
80
+ });
81
+ handleDownloadBibTeX(metadata);
82
+ }, children: [_jsx(FileHeart, { className: "mr-2 w-4 h-4" }), "BibTeX Citation"] }));
61
83
  }
62
- export function Citation({ className, children, }) {
63
- const project = useProjectManifest();
64
- const doiUrl = doi.buildUrl(project?.doi);
84
+ export function Citation({ children, onOpenChange, }) {
85
+ const metadata = useCitationMetadata();
86
+ const doiUrl = doi.buildUrl(metadata?.doi);
87
+ const capture = useAnalytics();
65
88
  if (!doiUrl)
66
89
  return null;
67
- return (_jsxs(Dialog, { children: [_jsx(DialogTrigger, { asChild: true, children: _jsx("div", { className: cn('cursor-pointer', className), children: children }) }), _jsxs(DialogContent, { children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { className: "mb-2 text-2xl font-semibold", children: "Cite Article" }) }), _jsx("div", { className: "space-y-4", children: _jsx("div", { children: _jsxs("p", { className: "p-3 text-sm rounded text-muted-foreground bg-muted", children: [project?.authors
90
+ return (_jsxs(Dialog, { onOpenChange: onOpenChange, children: [_jsx(DialogTrigger, { asChild: true, children: children }), _jsxs(DialogContent, { children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { className: "mb-2 text-2xl font-semibold", children: "Cite Article" }), _jsx(DialogDescription, { className: "sr-only", children: "Citation details for this article, including a formatted reference, DOI link, and BibTeX download." })] }), _jsx("div", { className: "space-y-4", children: _jsx("div", { children: _jsxs("p", { className: "p-3 text-sm rounded text-muted-foreground bg-muted", children: [metadata?.authors
68
91
  ?.map((author, idx, arr) => {
69
92
  const family = author.nameParsed
70
93
  ? (author.nameParsed?.family ?? '')
@@ -88,12 +111,19 @@ export function Citation({ className, children, }) {
88
111
  }
89
112
  return `${idx === 0 ? '' : sep}${family}${initials ? ', ' + initials : ''}`;
90
113
  })
91
- .join(''), ' ', "(", getYear(project?.date), "). ", project?.title, ".", project?.venue?.title ? ` ${project.venue.title},` : '', project?.doi && (_jsxs(_Fragment, { children: [' ', _jsx("a", { href: doiUrl, target: "_blank", rel: "noopener noreferrer", className: "underline", children: doiUrl })] }))] }) }) }), _jsxs("div", { className: "mb-4 prose prose-sm dark:prose-invert", children: [_jsxs("div", { className: "mb-4 flex gap-2 justify-end", children: [doiUrl && (_jsxs(Button, { variant: "outline", size: "sm", onClick: () => {
114
+ .join(''), ' ', "(", getYear(metadata?.date), "). ", metadata?.title, ".", metadata?.venue?.title ? ` ${metadata.venue.title},` : '', metadata?.doi && (_jsxs(_Fragment, { children: [' ', _jsx("a", { href: doiUrl, target: "_blank", rel: "noopener noreferrer", className: "underline", children: doiUrl })] }))] }) }) }), _jsxs("div", { className: "mb-4 prose prose-sm dark:prose-invert", children: [_jsxs("div", { className: "flex gap-2 justify-end mb-4", children: [doiUrl && (_jsxs(Button, { variant: "outline", size: "sm", onClick: () => {
92
115
  navigator.clipboard.writeText(doiUrl);
116
+ capture('article_doi_copied', { doi: doiUrl, surface: 'citation_dialog' });
93
117
  toast.success(_jsxs("div", { children: ["DOI copied to clipboard: ", _jsx("br", {}), _jsx("a", { href: doiUrl, children: doiUrl })] }));
94
118
  }, className: "gap-2", children: [_jsx(Copy, { className: "w-4 h-4" }), "Copy DOI"] })), _jsxs(Button, { variant: "outline", size: "sm", onClick: () => {
95
- if (!project)
119
+ if (!metadata)
96
120
  return;
97
- handleDownloadBibTeX(project);
121
+ capture('citation_download', {
122
+ action: 'clicked',
123
+ category: 'export',
124
+ format: 'bibtex',
125
+ surface: 'citation_dialog',
126
+ });
127
+ handleDownloadBibTeX(metadata);
98
128
  }, className: "gap-2", children: [_jsx(DownloadIcon, { className: "w-4 h-4" }), "Download BibTeX"] })] }), doiUrl && (_jsxs("div", { className: "mb-2", children: [_jsx("div", { className: "font-medium", children: "DOI" }), _jsx("a", { href: doiUrl, className: "break-all", target: "_blank", rel: "noopener noreferrer", children: doiUrl })] }))] })] })] }));
99
129
  }
@@ -0,0 +1,28 @@
1
+ import React from 'react';
2
+ export declare function useCollapsibleBackmatter(totalCount: number, limit?: boolean | number, defaultLimit?: number): {
3
+ hidden: boolean;
4
+ toggle: () => void;
5
+ displayedCount: number;
6
+ isCollapsible: boolean;
7
+ limit: number | undefined;
8
+ };
9
+ export declare function CollapsibleBackmatterHeader({ id, title, linkTitle, hidden, onToggle, isCollapsible, className, buttonClassName, }: {
10
+ id: string;
11
+ title: string;
12
+ linkTitle: string;
13
+ hidden: boolean;
14
+ onToggle: () => void;
15
+ isCollapsible: boolean;
16
+ className?: string;
17
+ buttonClassName?: string;
18
+ }): import("react/jsx-runtime").JSX.Element;
19
+ export declare function CollapsibleBackmatterFooterButton({ hidden, onToggle, totalCount, itemLabel, sectionId, className, as: Wrapper, }: {
20
+ hidden: boolean;
21
+ onToggle: () => void;
22
+ totalCount: number;
23
+ itemLabel: string;
24
+ sectionId?: string;
25
+ className?: string;
26
+ as?: React.ElementType;
27
+ }): import("react/jsx-runtime").JSX.Element;
28
+ //# sourceMappingURL=collapsible-backmatter-section.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collapsible-backmatter-section.d.ts","sourceRoot":"","sources":["../../../src/components/ui/collapsible-backmatter-section.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AA+BxC,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,MAAM,EAClB,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,EACxB,YAAY,SAAK,GAChB;IACD,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B,CAcA;AAED,wBAAgB,2BAA2B,CAAC,EAC1C,EAAE,EACF,KAAK,EACL,SAAS,EACT,MAAM,EACN,QAAQ,EACR,aAAa,EACb,SAAS,EACT,eAAe,GAChB,EAAE;IACD,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,2CA6BA;AAED,wBAAgB,iCAAiC,CAAC,EAChD,MAAM,EACN,QAAQ,EACR,UAAU,EACV,SAAS,EACT,SAAS,EACT,SAAS,EACT,EAAE,EAAE,OAAe,GACpB,EAAE;IACD,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,EAAE,CAAC,EAAE,KAAK,CAAC,WAAW,CAAC;CACxB,2CAuBA"}