Skip to content

Commit e0ac20c

Browse files
committed
Modify navbar to use Figma icons
1 parent 684185a commit e0ac20c

File tree

4 files changed

+177
-22
lines changed

4 files changed

+177
-22
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
.ls-svg-icon {
2+
display: inline-flex;
3+
align-items: center;
4+
justify-content: center;
5+
6+
img {
7+
display: block;
8+
max-width: 100%;
9+
height: auto;
10+
/* CSS filter to display SVGs in #ABBCCD color */
11+
filter: brightness(0) saturate(100%) invert(84%) sepia(5%) saturate(1013%) hue-rotate(178deg) brightness(89%) contrast(84%);
12+
}
13+
14+
&--active {
15+
img {
16+
/* The active pink color from the design - using precise filter values for #FD7BF4 */
17+
filter: brightness(0) saturate(100%) invert(65%) sepia(82%) saturate(5793%) hue-rotate(292deg) brightness(99%) contrast(98%);
18+
}
19+
}
20+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import React from 'react';
2+
import { IonText } from '@ionic/react';
3+
import classNames from 'classnames';
4+
import { useTranslation } from 'react-i18next';
5+
6+
import './SvgIcon.scss';
7+
import { BaseComponentProps } from '../types';
8+
9+
/**
10+
* Properties for the `SvgIcon` component.
11+
* @see {@link BaseComponentProps}
12+
*/
13+
export interface SvgIconProps extends BaseComponentProps {
14+
/** The SVG icon source */
15+
src: string;
16+
17+
/** Alt text for accessibility */
18+
alt?: string;
19+
20+
/** Whether the icon is active/selected */
21+
active?: boolean;
22+
23+
/** Optional color override */
24+
color?: string;
25+
26+
/** Optional width */
27+
width?: number | string;
28+
29+
/** Optional height */
30+
height?: number | string;
31+
}
32+
33+
/**
34+
* The `SvgIcon` component renders an SVG icon.
35+
*
36+
* @param {SvgIconProps} props - Component properties.
37+
* @returns {JSX.Element} JSX
38+
*/
39+
const SvgIcon = ({
40+
className,
41+
src,
42+
alt = '',
43+
active = false,
44+
color = '#ABBCCD',
45+
width = 24,
46+
height = 24,
47+
testid = 'svg-icon',
48+
...props
49+
}: SvgIconProps): JSX.Element => {
50+
const { t } = useTranslation();
51+
52+
const altText = alt || t('icon.alt', { ns: 'common', defaultValue: 'Icon' });
53+
54+
// Determine the appropriate filter based on active state and color
55+
const getImageStyle = () => {
56+
if (active) {
57+
// Pink color #FD7BF4 - let the CSS handle it
58+
return undefined;
59+
} else if (color && color !== '#ABBCCD') {
60+
// For custom colors other than the default
61+
return { filter: `brightness(0) saturate(100%) ${generateFilterForHexColor(color)}` };
62+
}
63+
return undefined; // Use the default CSS filter
64+
};
65+
66+
// Helper function to generate CSS filter for a hex color
67+
// This is a simplified approach and might not be perfect for all colors
68+
const generateFilterForHexColor = (hex: string) => {
69+
// For demonstration purposes - in a real implementation, you would
70+
// use a more sophisticated algorithm to convert hex to filter values
71+
return `drop-shadow(0 0 0 ${hex})`;
72+
};
73+
74+
return (
75+
<IonText
76+
className={classNames(
77+
'ls-svg-icon',
78+
{ 'ls-svg-icon--active': active },
79+
className
80+
)}
81+
data-testid={testid}
82+
{...props}
83+
>
84+
<img
85+
src={src}
86+
alt={altText}
87+
width={width}
88+
height={height}
89+
style={getImageStyle()}
90+
data-testid={`${testid}-img`}
91+
/>
92+
</IonText>
93+
);
94+
};
95+
96+
export default SvgIcon;

frontend/src/common/components/Router/TabNavigation.scss

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
padding-bottom: 0;
1111

1212
&-button {
13-
--color: #435ff0;
13+
--color: #ABBCCD;
1414
--color-selected: #fd7bf4;
1515

1616
/* Ensure consistent alignment across platforms */
@@ -21,11 +21,18 @@
2121
&-icon {
2222
margin: 0;
2323
font-size: 1.25rem;
24+
color: #ABBCCD;
2425
}
2526

2627
&.tab-selected {
2728
.ls-tab-navigation__bar-button-icon {
2829
color: var(--color-selected);
30+
31+
/* Apply to SvgIcon component */
32+
&.ls-svg-icon img {
33+
/* Pink color #FD7BF4 using precise filter values */
34+
filter: brightness(0) saturate(100%) invert(65%) sepia(82%) saturate(5793%) hue-rotate(292deg) brightness(99%) contrast(98%);
35+
}
2936
}
3037
}
3138

@@ -52,6 +59,11 @@
5259
.ls-tab-navigation__bar-button-icon {
5360
color: white;
5461
margin: 0;
62+
63+
/* Make sure the SVG is white */
64+
&.ls-svg-icon img {
65+
filter: brightness(0) invert(1);
66+
}
5567
}
5668
}
5769
}

frontend/src/common/components/Router/TabNavigation.tsx

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { IonRouterOutlet, IonTabBar, IonTabButton, IonTabs } from '@ionic/react';
22
import { Redirect, Route } from 'react-router';
33
import { useState } from 'react';
4-
import { useHistory } from 'react-router-dom';
4+
import { useHistory, useLocation } from 'react-router-dom';
5+
import { useTranslation } from 'react-i18next';
56

67
import './TabNavigation.scss';
78
import AppMenu from '../Menu/AppMenu';
8-
import Icon from '../Icon/Icon';
9+
import SvgIcon from '../Icon/SvgIcon';
910
import UploadModal from '../Upload/UploadModal';
1011
import HomePage from 'pages/Home/HomePage';
1112
import UserDetailPage from 'pages/Users/components/UserDetail/UserDetailPage';
@@ -20,6 +21,13 @@ import ReportsListPage from 'pages/Reports/ReportsListPage';
2021
import ReportDetailPage from 'pages/Reports/ReportDetailPage';
2122
import ProcessingPage from 'pages/Processing/ProcessingPage';
2223

24+
// Import SVG icons
25+
import homeIcon from 'assets/icons/home.svg';
26+
import reportsIcon from 'assets/icons/reports.svg';
27+
import uploadIcon from 'assets/icons/upload.svg';
28+
import chatIcon from 'assets/icons/chat.svg';
29+
import profileIcon from 'assets/icons/profile.svg';
30+
2331
/**
2432
* The `TabNavigation` component provides a router outlet for all of the
2533
* application routes. The component renders two main application
@@ -38,6 +46,13 @@ import ProcessingPage from 'pages/Processing/ProcessingPage';
3846
const TabNavigation = (): JSX.Element => {
3947
const [isUploadModalOpen, setIsUploadModalOpen] = useState(false);
4048
const history = useHistory();
49+
const location = useLocation();
50+
const { t } = useTranslation();
51+
52+
// Check if the current path starts with the tab path
53+
const isTabActive = (tabPath: string) => {
54+
return location.pathname.startsWith(tabPath);
55+
};
4156

4257
const handleUploadClick = () => {
4358
setIsUploadModalOpen(true);
@@ -101,19 +116,27 @@ const TabNavigation = (): JSX.Element => {
101116

102117
<IonTabBar slot="bottom" className="ls-tab-navigation__bar ion-hide-md-up">
103118
<IonTabButton className="ls-tab-navigation__bar-button" tab="home" href="/tabs/home">
104-
<Icon className="ls-tab-navigation__bar-button-icon" icon="home" size="xl" fixedWidth />
119+
<SvgIcon
120+
className="ls-tab-navigation__bar-button-icon"
121+
src={homeIcon}
122+
active={isTabActive('/tabs/home')}
123+
alt={t('navigation.home', { ns: 'common', defaultValue: 'Home' })}
124+
width={24}
125+
height={24}
126+
/>
105127
</IonTabButton>
106128
<IonTabButton
107129
className="ls-tab-navigation__bar-button"
108130
tab="reports"
109131
href="/tabs/reports"
110132
>
111-
<Icon
133+
<SvgIcon
112134
className="ls-tab-navigation__bar-button-icon"
113-
icon="fileLines"
114-
iconStyle="regular"
115-
size="xl"
116-
fixedWidth
135+
src={reportsIcon}
136+
active={isTabActive('/tabs/reports')}
137+
alt={t('navigation.reports', { ns: 'common', defaultValue: 'Reports' })}
138+
width={24}
139+
height={24}
117140
/>
118141
</IonTabButton>
119142
<IonTabButton
@@ -122,33 +145,37 @@ const TabNavigation = (): JSX.Element => {
122145
onClick={handleUploadClick}
123146
>
124147
<div className="ls-tab-navigation__bar-button-upload-wrapper">
125-
<Icon
148+
<SvgIcon
126149
className="ls-tab-navigation__bar-button-icon"
127-
icon="arrowUpFromBracket"
128-
size="xl"
129-
fixedWidth
150+
src={uploadIcon}
151+
alt={t('navigation.upload', { ns: 'common', defaultValue: 'Upload' })}
152+
width={24}
153+
height={24}
130154
/>
131155
</div>
132156
</IonTabButton>
133157
<IonTabButton className="ls-tab-navigation__bar-button" tab="chat" href="/tabs/chat">
134-
<Icon
158+
<SvgIcon
135159
className="ls-tab-navigation__bar-button-icon"
136-
icon="comment"
137-
iconStyle="regular"
138-
size="xl"
139-
fixedWidth
160+
src={chatIcon}
161+
active={isTabActive('/tabs/chat')}
162+
alt={t('navigation.chat', { ns: 'common', defaultValue: 'Chat' })}
163+
width={24}
164+
height={24}
140165
/>
141166
</IonTabButton>
142167
<IonTabButton
143168
className="ls-tab-navigation__bar-button"
144169
tab="account"
145170
href="/tabs/account"
146171
>
147-
<Icon
172+
<SvgIcon
148173
className="ls-tab-navigation__bar-button-icon"
149-
icon="userCircle"
150-
size="xl"
151-
fixedWidth
174+
src={profileIcon}
175+
active={isTabActive('/tabs/account')}
176+
alt={t('navigation.account', { ns: 'common', defaultValue: 'Account' })}
177+
width={24}
178+
height={24}
152179
/>
153180
</IonTabButton>
154181
</IonTabBar>

0 commit comments

Comments
 (0)