Skip to content

Commit 51ee10a

Browse files
authored
feat(app): CSS Modules-apply for navbar Desktop app (#18777)
* feat(app): CSS Modules-apply for navbar Desktop app
1 parent 5273183 commit 51ee10a

File tree

3 files changed

+203
-0
lines changed

3 files changed

+203
-0
lines changed

app/src/App/Navbar/index.tsx

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { useCallback } from 'react'
2+
import { useTranslation } from 'react-i18next'
3+
import { NavLink, useNavigate } from 'react-router-dom'
4+
import debounce from 'lodash/debounce'
5+
6+
import { Icon, LegacyStyledText, Link } from '@opentrons/components'
7+
8+
import logoSvgThree from '/app/assets/images/logo_nav_three.svg'
9+
import logoSvg from '/app/assets/images/logo_nav.svg'
10+
11+
import styles from './navbar.module.css'
12+
13+
import type { MouseEvent } from 'react'
14+
import type { RouteProps } from '../types'
15+
16+
const SALESFORCE_HELP_LINK = 'https://support.opentrons.com/s/'
17+
const PROJECT: string = _OPENTRONS_PROJECT_
18+
const DEBOUNCE_DURATION_MS = 300
19+
20+
export function Navbar({ routes }: { routes: RouteProps[] }): JSX.Element {
21+
const { t } = useTranslation('top_navigation')
22+
const navigate = useNavigate()
23+
const navRoutes = routes.filter(
24+
({ navLinkTo }: RouteProps) => navLinkTo != null
25+
)
26+
const debouncedNavigate = useCallback(
27+
debounce((path: string) => {
28+
navigate(path)
29+
}, DEBOUNCE_DURATION_MS),
30+
[navigate]
31+
)
32+
33+
return (
34+
<div className={styles.navbar}>
35+
<div className={styles.nav_container}>
36+
<img
37+
src={PROJECT === 'ot3' ? logoSvgThree : logoSvg}
38+
alt="opentrons logo"
39+
className={styles.logo_img}
40+
/>
41+
{navRoutes.map(({ name, navLinkTo }: RouteProps) => (
42+
<NavLink
43+
key={name}
44+
to={navLinkTo as string}
45+
className={({ isActive }) =>
46+
`${styles.navbar_link} ${isActive ? 'active' : ''}`
47+
}
48+
>
49+
<LegacyStyledText as="h3" className={styles.nav_link_text}>
50+
{t(name)}
51+
</LegacyStyledText>
52+
</NavLink>
53+
))}
54+
</div>
55+
<div className={styles.bottom_container}>
56+
<Link
57+
role="button"
58+
data-testid="Navbar_settingsLink"
59+
className={styles.nav_icon_link}
60+
onClick={(e: MouseEvent<HTMLButtonElement>) => {
61+
e.preventDefault()
62+
debouncedNavigate('/app-settings')
63+
}}
64+
>
65+
<Icon name="gear" className={styles.navbar_icon} />
66+
</Link>
67+
<Link href={SALESFORCE_HELP_LINK} external className={styles.icon_link}>
68+
<Icon
69+
data-testid="Navbar_helpLink"
70+
name="help"
71+
className={styles.navbar_icon}
72+
/>
73+
</Link>
74+
</div>
75+
</div>
76+
)
77+
}

app/src/App/Navbar/navbar.module.css

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
.navbar {
2+
display: flex;
3+
width: 5.625rem;
4+
height: 100vh;
5+
flex: none;
6+
flex-direction: column;
7+
align-items: center;
8+
justify-content: space-between;
9+
background-color: var(--black-90);
10+
font-size: var(--font-size-h3);
11+
font-weight: 400;
12+
line-height: var(--line-height-20);
13+
}
14+
15+
.nav_container {
16+
display: flex;
17+
flex: none;
18+
flex-direction: column;
19+
align-items: flex-start;
20+
align-self: stretch;
21+
}
22+
23+
.logo_img {
24+
align-self: center;
25+
padding: var(--spacing-24) 0;
26+
}
27+
28+
.navbar_link {
29+
display: block;
30+
height: 2.25rem;
31+
align-self: stretch;
32+
background-color: var(--black-90);
33+
color: var(--white);
34+
text-decoration: none;
35+
}
36+
37+
.navbar_link:hover {
38+
background-color: var(--black-80);
39+
}
40+
41+
.navbar_link:focus-visible {
42+
background-color: var(--grey-60);
43+
box-shadow: inset 0 0 0 3px var(--blue-50);
44+
outline: none;
45+
}
46+
47+
.navbar_link:active {
48+
background-color: var(--black-90);
49+
}
50+
51+
/* Use global selector for React Router's active class */
52+
.navbar_link:global(.active) {
53+
background-color: var(--black-70);
54+
}
55+
56+
.navbar_link:global(.active):focus-visible {
57+
box-shadow: none;
58+
outline: none;
59+
}
60+
61+
.navbar_link.active:has(svg) {
62+
background-color: var(--black-90);
63+
}
64+
65+
.nav_link_text {
66+
padding: var(--spacing-8) 0 var(--spacing-8) var(--spacing-12);
67+
font-size: 1rem;
68+
font-weight: 400;
69+
line-height: var(--line-height-20);
70+
}
71+
72+
.bottom_container {
73+
display: flex;
74+
align-self: stretch;
75+
justify-content: space-evenly;
76+
margin-bottom: var(--spacing-8);
77+
}
78+
79+
.nav_icon_link {
80+
display: inline-block;
81+
}
82+
83+
.icon_link {
84+
display: inline-block;
85+
}
86+
87+
.navbar_icon {
88+
width: 2rem;
89+
height: 2rem;
90+
padding: var(--spacing-6);
91+
border: none;
92+
border-radius: 50%;
93+
background-color: transparent;
94+
color: var(--grey-30);
95+
cursor: pointer;
96+
}
97+
98+
.navbar_icon:hover {
99+
background-color: var(--black-80);
100+
}
101+
102+
.navbar_icon:focus-visible {
103+
background-color: var(--grey-60);
104+
box-shadow: inset 0 0 0 3px var(--blue-50);
105+
outline: none;
106+
}
107+
108+
.navbar_icon:active {
109+
background-color: var(--black-90);
110+
color: var(--grey-30);
111+
}
112+
113+
.navbar_icon.active {
114+
background-color: var(--black-70);
115+
color: var(--grey-30);
116+
}
117+
118+
.nav_icon_link.active > .navbar_icon {
119+
background-color: var(--black-70);
120+
color: var(--grey-30);
121+
}
122+
123+
.icon_link.active > .navbar_icon {
124+
background-color: var(--black-70);
125+
color: var(--grey-30);
126+
}
File renamed without changes.

0 commit comments

Comments
 (0)