Skip to content

Commit

Permalink
Merge pull request nasa-gcn#2135 from lpsinger/tooltips-suspense
Browse files Browse the repository at this point in the history
Add tooltips for cross references
  • Loading branch information
dakota002 authored Apr 11, 2024
2 parents 8a10793 + 19b2735 commit 0f262fc
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,73 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
import { AstroDataLink } from './AstroDataContext'
import { type Circular } from '../circulars/circulars.lib'
import { AstroDataLink, AstroDataLinkWithTooltip } from './AstroDataContext'
import { useOrigin } from '~/root'

export function GcnCircular({
children,
value,
}: JSX.IntrinsicElements['data']) {
return <AstroDataLink to={`/circulars/${value}`}>{children}</AstroDataLink>
const origin = useOrigin()

return (
<AstroDataLinkWithTooltip
to={`/circulars/${value}`}
fetch={async () => {
const response = await fetch(`${origin}/circulars/${value}.json`)
return (await response.json()) as Circular
}}
label={({ subject, submitter }) => (
<>
<div>GCN {value}</div>
<div>{submitter}</div>
<div>{subject}</div>
</>
)}
>
{children}
</AstroDataLinkWithTooltip>
)
}

export function Arxiv({ children, value }: JSX.IntrinsicElements['data']) {
return (
<AstroDataLink to={`https://arxiv.org/abs/${value}`}>
<AstroDataLinkWithTooltip
to={`https://arxiv.org/abs/${value}`}
fetch={async () => {
const response = await fetch(
`http://export.arxiv.org/api/query?id_list=${value}`
)
const text = await response.text()
const entry = new DOMParser()
.parseFromString(text, 'text/xml')
.getElementsByTagName('entry')[0]

const title = entry.getElementsByTagName('title')[0].textContent

const published = entry.getElementsByTagName('published')[0].textContent
const year = published && new Date(published).getFullYear()

const authorElements = entry.getElementsByTagName('author')
let authors =
authorElements[0].getElementsByTagName('name')[0].textContent
if (authorElements.length > 1) authors += ' et al.'

return { title, year, authors }
}}
label={({ title, year, authors }) => (
<>
<div>arXiv:{value}</div>
<div>
{authors}, {year}
</div>
<div>{title}</div>
</>
)}
>
{children}
</AstroDataLink>
</AstroDataLinkWithTooltip>
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.detail div {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
95 changes: 81 additions & 14 deletions app/routes/circulars.$circularId.($version)/AstroDataContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,19 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
import { Link, type LinkProps } from '@remix-run/react'
import { Await, Link, type LinkProps } from '@remix-run/react'
import { Tooltip } from '@trussworks/react-uswds'
import classNames from 'classnames'
import { createContext, useContext } from 'react'
import {
type ReactNode,
type Ref,
Suspense,
createContext,
forwardRef,
useContext,
} from 'react'

import styles from './AstroDataContext.module.css'

export type AstroDataContextProps = Pick<
JSX.IntrinsicElements['a'],
Expand All @@ -16,23 +26,80 @@ export type AstroDataContextProps = Pick<

export const AstroDataContext = createContext<AstroDataContextProps>({})

export function AstroDataLink({
/**
* An Astro Flavored Markdown enriched link.
*/
export const AstroDataLink = forwardRef(
(
{ children, className, rel: origRel, ...props }: Omit<LinkProps, 'target'>,
ref: Ref<HTMLAnchorElement>
) => {
const context = useContext(AstroDataContext)
const rel = [origRel, context.rel].filter(Boolean).join(' ') || undefined

return (
<Link
className={classNames('usa-link', className)}
target={context.target}
rel={rel}
ref={ref}
{...props}
>
{children}
</Link>
)
}
)

/**
* An Astro Flavored Markdown enriched link with a tooltip to show extra
* details about the data.
*
* The tooltip displays the text, "Loading...", until the content has been
* fetched. The tooltip has a fixed size because react-uswds cannot properly
* position the tooltip if the size changes when the content fills in.
*/
export function AstroDataLinkWithTooltip<T>({
fetch,
label,
children,
className,
rel: origRel,
...props
}: Omit<LinkProps, 'target'>) {
const context = useContext(AstroDataContext)
const rel = [origRel, context.rel].filter(Boolean).join(' ') || undefined

}: Omit<Parameters<typeof AstroDataLink>[0], 'ref'> & {
fetch: () => T
label: (resolved: Awaited<T>) => ReactNode
}) {
return (
<Link
className={classNames('usa-link', className)}
target={context.target}
rel={rel}
<Tooltip
{...props}
label={
<div className={classNames('width-card-lg font-ui-sm', styles.detail)}>
<Suspense
fallback={
<>
<div>Loading...</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
</>
}
>
<Await
resolve={fetch()}
errorElement={
<>
<div>Not found</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
</>
}
>
{label}
</Await>
</Suspense>
</div>
}
asCustom={AstroDataLink}
>
{children}
</Link>
</Tooltip>
)
}

0 comments on commit 0f262fc

Please sign in to comment.