From cabb8247aaa958e8acbf9093384c2c3e5e7ff061 Mon Sep 17 00:00:00 2001 From: ivan-aksamentov Date: Fri, 15 Sep 2023 10:24:34 +0200 Subject: [PATCH] feat(web): prettify nav bar --- packages_rs/nextclade-web/package.json | 2 +- .../src/components/FilePicker/FilePicker.tsx | 6 +- .../components/Layout/LanguageSwitcher.tsx | 64 ++++++++++++----- .../src/components/Layout/NavigationBar.tsx | 28 +++++--- packages_rs/nextclade-web/src/i18n/i18n.ts | 72 ++++++------------- .../styles/components/LanguageSwitcher.scss | 19 ----- .../nextclade-web/src/styles/global.scss | 1 - packages_rs/nextclade-web/yarn.lock | 8 +-- 8 files changed, 97 insertions(+), 103 deletions(-) delete mode 100644 packages_rs/nextclade-web/src/styles/components/LanguageSwitcher.scss diff --git a/packages_rs/nextclade-web/package.json b/packages_rs/nextclade-web/package.json index 0c7446ac1..0f93187d9 100644 --- a/packages_rs/nextclade-web/package.json +++ b/packages_rs/nextclade-web/package.json @@ -133,7 +133,7 @@ "react-file-icon": "1.1.0", "react-helmet": "6.1.0", "react-i18next": "11.3.3", - "react-icons": "4.3.1", + "react-icons": "4.11.0", "react-if": "4.1.4", "react-loader-spinner": "5.1.4", "react-markdown": "6.0.3", diff --git a/packages_rs/nextclade-web/src/components/FilePicker/FilePicker.tsx b/packages_rs/nextclade-web/src/components/FilePicker/FilePicker.tsx index cdb00d85c..5e55a0109 100644 --- a/packages_rs/nextclade-web/src/components/FilePicker/FilePicker.tsx +++ b/packages_rs/nextclade-web/src/components/FilePicker/FilePicker.tsx @@ -39,7 +39,11 @@ export const FilePickerTitle = styled.h4` margin: auto 0; ` -export const TabsPanelStyled = styled(TabsPanel)`` +export const TabsPanelStyled = styled(TabsPanel)` + * { + background: transparent !important; + } +` const TabsContentStyled = styled(TabsContent)` height: 100%; diff --git a/packages_rs/nextclade-web/src/components/Layout/LanguageSwitcher.tsx b/packages_rs/nextclade-web/src/components/Layout/LanguageSwitcher.tsx index d0455bf72..a788f45ec 100644 --- a/packages_rs/nextclade-web/src/components/Layout/LanguageSwitcher.tsx +++ b/packages_rs/nextclade-web/src/components/Layout/LanguageSwitcher.tsx @@ -1,7 +1,13 @@ import React, { useCallback, useMemo, useState } from 'react' -import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem, DropdownProps } from 'reactstrap' +import { + Dropdown as DropdownBase, + DropdownToggle as DropdownToggleBase, + DropdownMenu as DropdownMenuBase, + DropdownItem, + DropdownProps, +} from 'reactstrap' import { useRecoilState } from 'recoil' - +import styled from 'styled-components' import { localeAtom } from 'src/state/locale.state' import { getLocaleWithKey, Locale, localesArray } from 'src/i18n/i18n' @@ -14,11 +20,11 @@ export function LanguageSwitcher({ ...restProps }: LanguageSwitcherProps) { const setLocaleLocal = useCallback((locale: Locale) => () => setCurrentLocale(locale.key), [setCurrentLocale]) return ( - + - + - + {localesArray.map((locale) => { const isCurrent = locale.key === currentLocale return ( @@ -33,20 +39,42 @@ export function LanguageSwitcher({ ...restProps }: LanguageSwitcherProps) { } export function LanguageSwitcherItem({ locale }: { locale: string }) { - const { Flag, name, native } = getLocaleWithKey(locale) - - const label = useMemo(() => { - if (name === native) { - return name - } - - return `${native} (${name})` + const { name, native } = getLocaleWithKey(locale) + const { label, tooltip } = useMemo(() => { + return { label: `(${native})`, tooltip: `${name} (${native})` } }, [name, native]) - return ( - <> - - {label} - + + + {label} + ) } + +export function LabelShort({ locale, ...restProps }: { locale: string; className?: string }) { + const { key } = getLocaleWithKey(locale) + return {key} +} + +const LabelShortText = styled.span` + font-family: ${(props) => props.theme.font.monospace}; + text-transform: uppercase !important; + color: unset !important; +` + +const Dropdown = styled(DropdownBase)` + padding: 0; + margin: 0; +` + +const DropdownToggle = styled(DropdownToggleBase)` + color: ${(props) => props.theme.bodyColor}; + padding: 0; + margin: 0; +` + +const DropdownMenu = styled(DropdownMenuBase)` + background-color: ${(props) => props.theme.bodyBg}; + box-shadow: 1px 1px 20px 0 #0005; + transition: opacity ease-out 0.25s; +` diff --git a/packages_rs/nextclade-web/src/components/Layout/NavigationBar.tsx b/packages_rs/nextclade-web/src/components/Layout/NavigationBar.tsx index b7933b6b3..89f737e01 100644 --- a/packages_rs/nextclade-web/src/components/Layout/NavigationBar.tsx +++ b/packages_rs/nextclade-web/src/components/Layout/NavigationBar.tsx @@ -8,7 +8,7 @@ import { } from 'reactstrap' import { useRecoilValue } from 'recoil' import { Link } from 'src/components/Link/Link' -import { FaDocker, FaGithub, FaTwitter } from 'react-icons/fa' +import { FaDocker, FaGithub, FaXTwitter, FaDiscourse } from 'react-icons/fa6' import { LinkSmart } from 'src/components/Link/LinkSmart' import { hasRanAtom, hasTreeAtom } from 'src/state/results.state' import styled from 'styled-components' @@ -18,15 +18,14 @@ import { CitationButton } from 'src/components/Citation/CitationButton' import { NextcladeTextLogo } from 'src/components/Layout/NextcladeTextLogo' import { LanguageSwitcher } from './LanguageSwitcher' -const LOGO_SIZE = 30 +const LOGO_SIZE = 36 export const Navbar = styled(NavbarBase)` - height: 38px; + height: 45px; display: flex; - vertical-align: middle; padding: 0 !important; margin: 0 !important; - box-shadow: ${(props) => props.theme.shadows.large}; + box-shadow: 0 0 8px 0 #0004; ` export const Nav = styled(NavBase)` @@ -40,7 +39,11 @@ export const NavItem = styled(NavItemBase)` padding: 0 0.5rem; flex-grow: 0; flex-shrink: 0; - margin: 0 !important; + margin: auto; + + * { + vertical-align: middle; + } ` const NavbarBrand = styled(NavbarBrandBase)` @@ -138,18 +141,23 @@ export function NavigationBar() { }, { url: 'https://twitter.com/nextstrain', - title: t('Link to our Twitter'), - content: , + title: t('Link to our X.com (Twitter)'), + content: , + }, + { + url: 'https://discussion.nextstrain.org/', + title: t('Link to our discussion forum'), + content: , }, { url: 'https://hub.docker.com/r/nextstrain/nextclade', title: t('Link to our Docker containers'), - content: , + content: , }, { url: 'https://github.com/nextstrain/nextclade', title: t('Link to our Github page'), - content: , + content: , }, { title: t('Change language'), diff --git a/packages_rs/nextclade-web/src/i18n/i18n.ts b/packages_rs/nextclade-web/src/i18n/i18n.ts index 7dfa189e8..abb25b55c 100644 --- a/packages_rs/nextclade-web/src/i18n/i18n.ts +++ b/packages_rs/nextclade-web/src/i18n/i18n.ts @@ -1,11 +1,7 @@ -import { ElementType, FC } from 'react' - import type { StrictOmit } from 'ts-essentials' import { get, isNil, mapValues } from 'lodash' - import i18nOriginal, { i18n as I18N, Resource } from 'i18next' import { initReactI18next } from 'react-i18next' - import { Settings as LuxonSettings } from 'luxon' import numbro from 'numbro' import { languages } from 'countries-list' @@ -15,28 +11,6 @@ import prettyBytesOriginal, { Options as PrettyBytesOptionsOriginal } from 'pret // @ts-ignore import numbroLanguages from 'numbro/dist/languages.min' -import CN from 'flag-icon-css/flags/1x1/cn.svg' -import DE from 'flag-icon-css/flags/1x1/de.svg' -import ES from 'flag-icon-css/flags/1x1/es.svg' -import FR from 'flag-icon-css/flags/1x1/fr.svg' -import GB from 'flag-icon-css/flags/1x1/gb.svg' -import GR from 'flag-icon-css/flags/1x1/gr.svg' -import ID from 'flag-icon-css/flags/1x1/id.svg' -import IL from 'flag-icon-css/flags/1x1/il.svg' -import IN from 'flag-icon-css/flags/1x1/in.svg' -import IR from 'flag-icon-css/flags/1x1/ir.svg' -import IT from 'flag-icon-css/flags/1x1/it.svg' -import JP from 'flag-icon-css/flags/1x1/jp.svg' -import KR from 'flag-icon-css/flags/1x1/kr.svg' -import NL from 'flag-icon-css/flags/1x1/nl.svg' -import PK from 'flag-icon-css/flags/1x1/pk.svg' -import PT from 'flag-icon-css/flags/1x1/pt.svg' -import RU from 'flag-icon-css/flags/1x1/ru.svg' -import SA from 'flag-icon-css/flags/1x1/sa.svg' -import TH from 'flag-icon-css/flags/1x1/th.svg' -import TR from 'flag-icon-css/flags/1x1/tr.svg' -import VN from 'flag-icon-css/flags/1x1/vn.svg' - import ar from './resources/ar/common.json' import de from './resources/de/common.json' import el from './resources/el/common.json' @@ -97,32 +71,32 @@ export interface Locale { readonly full: string readonly name: string readonly native: string - readonly Flag: ElementType + readonly rtl: number | undefined } export const locales: Record = { - en: { key: 'en', full: 'en-US', name: languages.en.name, native: languages.en.native, Flag: GB as FC }, - ar: { key: 'ar', full: 'ar-SA', name: languages.ar.name, native: languages.ar.native, Flag: SA as FC }, - de: { key: 'de', full: 'de-DE', name: languages.de.name, native: languages.de.native, Flag: DE as FC }, - el: { key: 'el', full: 'el-GR', name: languages.el.name, native: languages.el.native, Flag: GR as FC }, - es: { key: 'es', full: 'es-ES', name: languages.es.name, native: languages.es.native, Flag: ES as FC }, - fa: { key: 'fa', full: 'fa-IR', name: languages.fa.name, native: languages.fa.native, Flag: IR as FC }, - fr: { key: 'fr', full: 'fr-FR', name: languages.fr.name, native: languages.fr.native, Flag: FR as FC }, - he: { key: 'he', full: 'he-IL', name: languages.he.name, native: languages.he.native, Flag: IL as FC }, - hi: { key: 'hi', full: 'hi-IN', name: languages.hi.name, native: languages.hi.native, Flag: IN as FC }, - id: { key: 'id', full: 'id-ID', name: languages.id.name, native: languages.id.native, Flag: ID as FC }, - it: { key: 'it', full: 'it-IT', name: languages.it.name, native: languages.it.native, Flag: IT as FC }, - ja: { key: 'ja', full: 'ja-JP', name: languages.ja.name, native: languages.ja.native, Flag: JP as FC }, - ko: { key: 'ko', full: 'ko-KR', name: languages.ko.name, native: languages.ko.native, Flag: KR as FC }, - nl: { key: 'nl', full: 'nl-NL', name: languages.nl.name, native: languages.nl.native, Flag: NL as FC }, - pt: { key: 'pt', full: 'pt-PT', name: languages.pt.name, native: languages.pt.native, Flag: PT as FC }, - ru: { key: 'ru', full: 'ru-RU', name: languages.ru.name, native: languages.ru.native, Flag: RU as FC }, - ta: { key: 'ta', full: 'ta-IN', name: languages.ta.name, native: languages.ta.native, Flag: IN as FC }, - th: { key: 'th', full: 'th-TH', name: languages.th.name, native: languages.th.native, Flag: TH as FC }, - tr: { key: 'tr', full: 'tr-TR', name: languages.tr.name, native: languages.tr.native, Flag: TR as FC }, - ur: { key: 'ur', full: 'ur-PK', name: languages.ur.name, native: languages.ur.native, Flag: PK as FC }, - vi: { key: 'vi', full: 'vi-VN', name: languages.vi.name, native: languages.vi.native, Flag: VN as FC }, - zh: { key: 'zh', full: 'zh-CN', name: languages.zh.name, native: languages.zh.native, Flag: CN as FC }, + en: { key: 'en', full: 'en-US', name: languages.en.name, native: languages.en.native, rtl: languages.en.rtl }, + ar: { key: 'ar', full: 'ar-SA', name: languages.ar.name, native: languages.ar.native, rtl: languages.ar.rtl }, + de: { key: 'de', full: 'de-DE', name: languages.de.name, native: languages.de.native, rtl: languages.de.rtl }, + el: { key: 'el', full: 'el-GR', name: languages.el.name, native: languages.el.native, rtl: languages.el.rtl }, + es: { key: 'es', full: 'es-ES', name: languages.es.name, native: languages.es.native, rtl: languages.es.rtl }, + fa: { key: 'fa', full: 'fa-IR', name: languages.fa.name, native: languages.fa.native, rtl: languages.fa.rtl }, + fr: { key: 'fr', full: 'fr-FR', name: languages.fr.name, native: languages.fr.native, rtl: languages.fr.rtl }, + he: { key: 'he', full: 'he-IL', name: languages.he.name, native: languages.he.native, rtl: languages.he.rtl }, + hi: { key: 'hi', full: 'hi-IN', name: languages.hi.name, native: languages.hi.native, rtl: languages.hi.rtl }, + id: { key: 'id', full: 'id-ID', name: languages.id.name, native: languages.id.native, rtl: languages.id.rtl }, + it: { key: 'it', full: 'it-IT', name: languages.it.name, native: languages.it.native, rtl: languages.it.rtl }, + ja: { key: 'ja', full: 'ja-JP', name: languages.ja.name, native: languages.ja.native, rtl: languages.ja.rtl }, + ko: { key: 'ko', full: 'ko-KR', name: languages.ko.name, native: languages.ko.native, rtl: languages.ko.rtl }, + nl: { key: 'nl', full: 'nl-NL', name: languages.nl.name, native: languages.nl.native, rtl: languages.nl.rtl }, + pt: { key: 'pt', full: 'pt-PT', name: languages.pt.name, native: languages.pt.native, rtl: languages.pt.rtl }, + ru: { key: 'ru', full: 'ru-RU', name: languages.ru.name, native: languages.ru.native, rtl: languages.ru.rtl }, + ta: { key: 'ta', full: 'ta-IN', name: languages.ta.name, native: languages.ta.native, rtl: languages.ta.rtl }, + th: { key: 'th', full: 'th-TH', name: languages.th.name, native: languages.th.native, rtl: languages.th.rtl }, + tr: { key: 'tr', full: 'tr-TR', name: languages.tr.name, native: languages.tr.native, rtl: languages.tr.rtl }, + ur: { key: 'ur', full: 'ur-PK', name: languages.ur.name, native: languages.ur.native, rtl: languages.ur.rtl }, + vi: { key: 'vi', full: 'vi-VN', name: languages.vi.name, native: languages.vi.native, rtl: languages.vi.rtl }, + zh: { key: 'zh', full: 'zh-CN', name: languages.zh.name, native: languages.zh.native, rtl: languages.zh.rtl }, } as const export const localeKeys = Object.keys(locales) diff --git a/packages_rs/nextclade-web/src/styles/components/LanguageSwitcher.scss b/packages_rs/nextclade-web/src/styles/components/LanguageSwitcher.scss deleted file mode 100644 index bd2f66132..000000000 --- a/packages_rs/nextclade-web/src/styles/components/LanguageSwitcher.scss +++ /dev/null @@ -1,19 +0,0 @@ -@import '../variables'; - -.language-switcher { - margin-top: 3px; - - .language-switcher-menu.dropdown-menu { - background-color: $body-bg; - box-shadow: 1px 1px 2px 2px rgba($gray-600, 0.25); - } - - .language-switcher-flag { - width: 20px; - height: 20px; - margin-bottom: 5px; - background-size: cover; - border-radius: 2px; - box-shadow: 1px 1px 2px 2px rgba($gray-600, 0.25); - } -} diff --git a/packages_rs/nextclade-web/src/styles/global.scss b/packages_rs/nextclade-web/src/styles/global.scss index 5be3cef65..a8f6a4289 100644 --- a/packages_rs/nextclade-web/src/styles/global.scss +++ b/packages_rs/nextclade-web/src/styles/global.scss @@ -9,7 +9,6 @@ @import './auspice'; -@import './components/LanguageSwitcher'; @import './components/Results'; html, body, #__next { diff --git a/packages_rs/nextclade-web/yarn.lock b/packages_rs/nextclade-web/yarn.lock index 5c15055fe..2499a6d2d 100644 --- a/packages_rs/nextclade-web/yarn.lock +++ b/packages_rs/nextclade-web/yarn.lock @@ -13274,10 +13274,10 @@ react-i18next@11.3.3, react-i18next@^11.3.3: "@babel/runtime" "^7.3.1" html-parse-stringify2 "2.0.1" -react-icons@4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-4.3.1.tgz#2fa92aebbbc71f43d2db2ed1aed07361124e91ca" - integrity sha512-cB10MXLTs3gVuXimblAdI71jrJx8njrJZmNMEMC+sQu5B/BIOmlsAjskdqpn81y8UBVEGuHODd7/ci5DvoSzTQ== +react-icons@4.11.0: + version "4.11.0" + resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-4.11.0.tgz#4b0e31c9bfc919608095cc429c4f1846f4d66c65" + integrity sha512-V+4khzYcE5EBk/BvcuYRq6V/osf11ODUM2J8hg2FDSswRrGvqiYUYPRy4OdrWaQOBj4NcpJfmHZLNaD+VH0TyA== react-icons@^3.9.0: version "3.11.0"