Skip to content

Commit

Permalink
Merge branch 'feat/web-info-buttons' into origin/master
Browse files Browse the repository at this point in the history
  • Loading branch information
ivan-aksamentov committed Nov 27, 2023
2 parents 1d046f6 + 06f84f3 commit ebbe448
Show file tree
Hide file tree
Showing 8 changed files with 206 additions and 7 deletions.
1 change: 1 addition & 0 deletions packages_rs/nextclade-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
"types:generate": "yarn run:node:prod tools/generateTypes.js -i src/gen/_SchemaRoot.json -o src/gen/_SchemaRoot.d.ts"
},
"dependencies": {
"@floating-ui/react": "0.26.1",
"animate.css": "4.1.1",
"auspice": "2.51.0",
"autoprefixer": "10.4.5",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export interface CardCollapsibleProps extends PropsWithChildren<CardProps> {
}

export function CardCollapsible({ header, children, defaultCollapsed = true, ...restProps }: CardCollapsibleProps) {
const [collapsed, toggleCollapsed] = useToggle(defaultCollapsed)
const { state: collapsed, toggle: toggleCollapsed } = useToggle(defaultCollapsed)
const isOpen = useMemo(() => !collapsed && !!children, [children, collapsed])
const Icon = useMemo(
() => <ArrowIcon color={children ? '#999' : 'transparent'} size={22} $rotated={isOpen} />,
Expand Down
87 changes: 87 additions & 0 deletions packages_rs/nextclade-web/src/components/Common/InfoButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React, { PropsWithChildren } from 'react'
import { Button as ButtonBase, CardBody } from 'reactstrap'
import styled, { useTheme } from 'styled-components'
import { FaInfo as InfoIcon } from 'react-icons/fa6'
import { useTranslationSafe } from 'src/helpers/useTranslationSafe'
import { useToggle } from 'src/hooks/useToggle'
import {
useFloating,
useInteractions,
useFocus,
useDismiss,
useRole,
FloatingPortal,
autoPlacement,
} from '@floating-ui/react'

export interface InfoButtonProps {
size?: number
}

export function InfoButton({ size = 18, children }: PropsWithChildren<InfoButtonProps>) {
const { t } = useTranslationSafe()
const theme = useTheme()

const { state: isOpen, toggle, setState: setIsOpen } = useToggle(false)
const { refs, context, floatingStyles } = useFloating({
open: isOpen,
onOpenChange: setIsOpen,
middleware: [autoPlacement()],
})
const dismiss = useDismiss(context)
const focus = useFocus(context)
const role = useRole(context)
const { getReferenceProps, getFloatingProps } = useInteractions([focus, dismiss, role])

return (
<>
<Button
innerRef={refs.setReference} // NOTE: using `innerRef` to pass ref to `reactstrap` component underneath.
as={ButtonBase} // NOTE: this works with styled-components v5, but "as" prop is removed in v6.
title={t('Click to get help information')}
$size={size}
{...getReferenceProps({ onClick: toggle })}
>
<Icon color={theme.primary} size={size * 0.66} />
</Button>
{isOpen && (
<FloatingPortal>
<Floating ref={refs.setFloating} style={floatingStyles} {...getFloatingProps()}>
<Card>
<CardBody>{children}</CardBody>
</Card>
</Floating>
</FloatingPortal>
)}
</>
)
}

const Floating = styled.div`
z-index: 1005;
width: 500px;
max-width: 80vw;
max-height: 80vh;
`

const Card = styled.div`
overflow-y: auto;
box-shadow: 1px 1px 10px 5px #0005;
border-radius: 5px;
height: 100%;
background-color: ${(props) => props.theme.bodyBg};
`

const Button = styled.button<{ $size?: number }>`
display: flex;
width: ${(props) => props.$size}px;
height: ${(props) => props.$size}px;
border-radius: ${(props) => props.$size}px;
padding: 0 !important;
margin: auto 0.5rem;
`

const Icon = styled(InfoIcon)`
padding: 0 !important;
margin: auto !important;
`
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from 'react'
import { useTranslationSafe } from 'src/helpers/useTranslationSafe'
import { InfoButton } from 'src/components/Common/InfoButton'
import { LinkExternal } from 'src/components/Link/LinkExternal'

export function SelectDatasetHelp() {
const { t } = useTranslationSafe()

return (
<InfoButton>
<p>
{t(
'Nextclade software is built to be agnostic to pathogens it analyzes. The information about concrete pathogens is provided in the form of so-called Nextclade datasets.',
)}
</p>

<p>
{t(
'Datasets vary by the pathogen, strain and other attributes. Each dataset is based on a particular reference sequence. Certain datasets only have enough information for basic analysis, others - more information to allow for more in-depth analysis and checks. Dataset authors periodically update and improve their datasets.',
)}
</p>

<p>
{t(
'You can select one of the datasets manually or to use automatic dataset suggestion function. Automatic suggestion will attempt to guess the most appropriate dataset from your sequence data.',
)}
</p>

<p>
{t(
"If you don't find a dataset for a pathogen or a strain you need, then you can create your own dataset. You can also publish it to our community collection, so that other people can use it too.",
)}
</p>

<p>
{t('Learn more about Nextclade datasets in the {{documentation}}')}
<LinkExternal href="https://docs.nextstrain.org/projects/nextclade/en/stable/user/datasets.html">
{t('documentation')}
</LinkExternal>
{t('.')}
</p>
</InfoButton>
)
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useEffect, useState } from 'react'
import { useRecoilState } from 'recoil'
import { Container as ContainerBase } from 'reactstrap'
import { SelectDatasetHelp } from 'src/components/Help/SelectDatasetHelp'
import { DatasetSelectorList } from 'src/components/Main/DatasetSelectorList'
import { SuggestionPanel } from 'src/components/Main/SuggestionPanel'
import { useDatasetSuggestionResults } from 'src/hooks/useRunSeqAutodetect'
Expand Down Expand Up @@ -56,7 +57,10 @@ export function DatasetSelectorImpl({
return (
<Container>
<Header>
<Title>{t('Select dataset')}</Title>
<Title>
<H4Inline>{t('Select dataset')}</H4Inline>
<SelectDatasetHelp />
</Title>

<SearchBox searchTitle={t('Search datasets')} searchTerm={searchTerm} onSearchTermChange={setSearchTerm} />
</Header>
Expand Down Expand Up @@ -104,6 +108,11 @@ const Main = styled.div`
`

const Title = styled.h4`
display: flex;
flex: 1;
`

const H4Inline = styled.h4`
display: inline-flex;
margin: auto 0;
`
23 changes: 20 additions & 3 deletions packages_rs/nextclade-web/src/components/Main/MainInputForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import { useRouter } from 'next/router'
import React, { useCallback, useEffect, useMemo } from 'react'
import { isNil } from 'lodash'
import { useRecoilState, useRecoilValue } from 'recoil'
import styled from 'styled-components'
import { SelectDatasetHelp } from 'src/components/Help/SelectDatasetHelp'
import { ButtonRun } from 'src/components/Main/ButtonRun'
import { SuggestionPanel } from 'src/components/Main/SuggestionPanel'
import { useRunAnalysis } from 'src/hooks/useRunAnalysis'
import { AutodetectRunState, autodetectRunStateAtom } from 'src/state/autodetect.state'
import { shouldSuggestDatasetsOnDatasetPageAtom } from 'src/state/settings.state'
import styled from 'styled-components'
import { hasRequiredInputsAtom } from 'src/state/inputs.state'
import { datasetCurrentAtom } from 'src/state/dataset.state'
import { DatasetCurrentSummary } from 'src/components/Main/DatasetCurrentSummary'
Expand Down Expand Up @@ -133,7 +134,10 @@ function DatasetCurrentOrSelectButton({ toDatasetSelection }: DatasetCurrentOrSe
return (
<Container>
<Header>
<h4>{text}</h4>
<Title>
<H4Inline>{text}</H4Inline>
<SelectDatasetHelp />
</Title>
</Header>

<Main>
Expand All @@ -150,7 +154,10 @@ function DatasetCurrentOrSelectButton({ toDatasetSelection }: DatasetCurrentOrSe
return (
<Container>
<Header>
<h4>{text}</h4>
<Title>
<H4Inline>{text}</H4Inline>
<SelectDatasetHelp />
</Title>
</Header>

<Main>
Expand All @@ -168,3 +175,13 @@ function DatasetCurrentOrSelectButton({ toDatasetSelection }: DatasetCurrentOrSe
</Container>
)
}

const Title = styled.h4`
display: flex;
flex: 1;
`

const H4Inline = styled.h4`
display: inline-flex;
margin: auto 0;
`
4 changes: 2 additions & 2 deletions packages_rs/nextclade-web/src/hooks/useToggle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import { RecoilState, useRecoilState } from 'recoil'

export type VoidFunc = () => void

export function useToggle(initialState = false): [boolean, VoidFunc, VoidFunc, VoidFunc] {
export function useToggle(initialState = false) {
const [state, setState] = useState(initialState)
const toggle = useCallback(() => setState((state) => !state), [])
const enable = useCallback(() => setState(true), [])
const disable = useCallback(() => setState(false), [])
return [state, toggle, enable, disable]
return { state, setState, toggle, enable, disable }
}

export function useRecoilToggle(recoilState: RecoilState<boolean>) {
Expand Down
41 changes: 41 additions & 0 deletions packages_rs/nextclade-web/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2074,6 +2074,42 @@
minimatch "^3.0.4"
strip-json-comments "^3.1.1"

"@floating-ui/core@^1.4.2":
version "1.5.0"
resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.5.0.tgz#5c05c60d5ae2d05101c3021c1a2a350ddc027f8c"
integrity sha512-kK1h4m36DQ0UHGj5Ah4db7R0rHemTqqO0QLvUqi1/mUUp3LuAWbWxdxSIf/XsnH9VS6rRVPLJCncjRzUvyCLXg==
dependencies:
"@floating-ui/utils" "^0.1.3"

"@floating-ui/dom@^1.5.1":
version "1.5.3"
resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.5.3.tgz#54e50efcb432c06c23cd33de2b575102005436fa"
integrity sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==
dependencies:
"@floating-ui/core" "^1.4.2"
"@floating-ui/utils" "^0.1.3"

"@floating-ui/react-dom@^2.0.2":
version "2.0.2"
resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.0.2.tgz#fab244d64db08e6bed7be4b5fcce65315ef44d20"
integrity sha512-5qhlDvjaLmAst/rKb3VdlCinwTF4EYMiVxuuc/HVUjs46W0zgtbMmAZ1UTsDrRTxRmUEzl92mOtWbeeXL26lSQ==
dependencies:
"@floating-ui/dom" "^1.5.1"

"@floating-ui/[email protected]":
version "0.26.1"
resolved "https://registry.yarnpkg.com/@floating-ui/react/-/react-0.26.1.tgz#a790bd3cff5f334d9e87d3ec132a3dc39d937800"
integrity sha512-5gyJIJ2tZOPMgmZ/vEcVhdmQiy75b7LPO71sYIiDsxGcZ4hxLuygQWCuT0YXHqppt//Eese+L6t5KnX/gZ3tVA==
dependencies:
"@floating-ui/react-dom" "^2.0.2"
"@floating-ui/utils" "^0.1.5"
tabbable "^6.0.1"

"@floating-ui/utils@^0.1.3", "@floating-ui/utils@^0.1.5":
version "0.1.6"
resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.1.6.tgz#22958c042e10b67463997bd6ea7115fe28cbcaf9"
integrity sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==

"@google-cloud/common@^3.0.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@google-cloud/common/-/common-3.10.0.tgz#454d1155bb512109cd83c6183aabbd39f9aabda7"
Expand Down Expand Up @@ -15425,6 +15461,11 @@ synesthesia@^1.0.1:
dependencies:
css-color-names "0.0.3"

tabbable@^6.0.1:
version "6.2.0"
resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-6.2.0.tgz#732fb62bc0175cfcec257330be187dcfba1f3b97"
integrity sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==

table@^6.6.0, table@^6.8.0:
version "6.8.0"
resolved "https://registry.yarnpkg.com/table/-/table-6.8.0.tgz#87e28f14fa4321c3377ba286f07b79b281a3b3ca"
Expand Down

1 comment on commit ebbe448

@vercel
Copy link

@vercel vercel bot commented on ebbe448 Nov 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

nextclade – ./

nextclade-git-master-nextstrain.vercel.app
nextclade-nextstrain.vercel.app
nextclade.vercel.app

Please sign in to comment.