From 44816b4f29a8c9f036e416ed1b9259a7026c4157 Mon Sep 17 00:00:00 2001 From: Aditya Khatri Date: Thu, 10 Jul 2025 15:01:35 +0545 Subject: [PATCH 1/2] feat(standup): add standup conductors --- src/components/TextOutput/index.tsx | 60 +++++++++++++++++++ src/components/TextOutput/styles.module.css | 38 ++++++++++++ .../DailyStandup/DeadlineSection/index.tsx | 42 ++++++++++++- .../DeadlineSection/styles.module.css | 16 +++++ .../DailyStandup/Slide/styles.module.css | 8 +-- src/views/DailyStandup/StartSection/index.tsx | 57 +++++++++++++++++- .../StartSection/styles.module.css | 15 +++++ 7 files changed, 228 insertions(+), 8 deletions(-) create mode 100644 src/components/TextOutput/index.tsx create mode 100644 src/components/TextOutput/styles.module.css diff --git a/src/components/TextOutput/index.tsx b/src/components/TextOutput/index.tsx new file mode 100644 index 0000000..fbf45b0 --- /dev/null +++ b/src/components/TextOutput/index.tsx @@ -0,0 +1,60 @@ +import React from 'react'; +import { _cs } from '@togglecorp/fujs'; + +import styles from './styles.module.css'; + +interface Props { + className?: string; + label?: React.ReactNode; + labelContainerClassName?: string; + description?: React.ReactNode; + descriptionContainerClassName?: string; + valueContainerClassName?: string; + hideLabelColon?: boolean; + block?: boolean; + value?: React.ReactNode; +} + +function TextOutput(props: Props) { + const { + className, + label, + labelContainerClassName, + valueContainerClassName, + description, + descriptionContainerClassName, + hideLabelColon, + block, + value, + } = props; + + return ( +
+ {label && ( +
+ {label} +
+ )} +
+ {value} +
+ {description && ( +
+ {description} +
+ )} +
+ ); +} + +export default TextOutput; diff --git a/src/components/TextOutput/styles.module.css b/src/components/TextOutput/styles.module.css new file mode 100644 index 0000000..837924b --- /dev/null +++ b/src/components/TextOutput/styles.module.css @@ -0,0 +1,38 @@ +.text-output { + --spacing: var(--spacing-md); + display: flex; + align-items: baseline; + font-size: var(--font-size-sm); + gap: var(--spacing); + + &.blok { + align-items: initial; + flex-direction: column; + } + + >.label { + color: var(--color-text); + } + + >.value { + font-weight: var(--font-weight-bold); + + /* Useful for nested text outputs */ + .text-output { + font-weight: var(--font-weight-semibold); + } + } + + >.description { + color: var(--color-text-light); + font-size: var(--font-size-sm); + } + + &.with-label-colon { + >.label { + &:after { + content: ':'; + } + } + } +} diff --git a/src/views/DailyStandup/DeadlineSection/index.tsx b/src/views/DailyStandup/DeadlineSection/index.tsx index 9c615be..b6ae48a 100644 --- a/src/views/DailyStandup/DeadlineSection/index.tsx +++ b/src/views/DailyStandup/DeadlineSection/index.tsx @@ -9,20 +9,28 @@ import { FcNightLandscape, FcSportsMode, } from 'react-icons/fc'; -import { compareNumber } from '@togglecorp/fujs'; +import { + _cs, + compareNumber, + encodeDate, +} from '@togglecorp/fujs'; import { gql, useQuery, } from 'urql'; import Clock from '#components/Clock'; +import TextOutput from '#components/TextOutput'; import { type DeadlinesAndEventsQuery, type DeadlinesAndEventsQueryVariables, + type StandupConductorsQuery, + type StandupConductorsQueryVariables, } from '#generated/types/graphql'; import { type GeneralEvent } from '#utils/types'; import Slide from '../Slide'; +import { STANDUP_CONDUCTORS } from '../StartSection'; import GeneralEventOutput from './GeneralEvent'; import styles from './styles.module.css'; @@ -51,6 +59,8 @@ const DEADLINES_AND_EVENTS = gql` } `; +const todayDate = encodeDate(new Date()); + function DeadlineSection() { const [deadlinesAndEvents] = useQuery< DeadlinesAndEventsQuery, @@ -60,6 +70,14 @@ function DeadlineSection() { requestPolicy: 'cache-and-network', }); + const [conductorsResponse] = useQuery({ + query: STANDUP_CONDUCTORS, + variables: { date: todayDate }, + requestPolicy: 'cache-and-network', + }); + + const standupConductors = conductorsResponse.data?.private.dailyStandup; + const projects = deadlinesAndEvents.data?.private.allProjects; const events = deadlinesAndEvents.data?.private.relativeEvents; @@ -103,7 +121,27 @@ function DeadlineSection() { variant="split" primaryPreText="Welcome to" primaryHeading="Daily Standup" - primaryDescription={} + primaryDescription={( +
+ + + +
+ )} secondaryHeading="Upcoming Events" secondaryContent={upcomingEvents.map( (generalEvent, index) => ( diff --git a/src/views/DailyStandup/DeadlineSection/styles.module.css b/src/views/DailyStandup/DeadlineSection/styles.module.css index d1200ed..78f600f 100644 --- a/src/views/DailyStandup/DeadlineSection/styles.module.css +++ b/src/views/DailyStandup/DeadlineSection/styles.module.css @@ -13,6 +13,22 @@ flex-grow: 1; border-bottom: var(--width-separator-sm) solid var(--color-separator); } + + .primary-section{ + display: flex; + flex-direction: column; + text-align: center; + gap: var(--spacing-sm); + + .conductor { + justify-content: center; + font-size: var(--font-size-sm); + + &.hidden { + visibility: hidden; + } + } + } } @keyframes run { diff --git a/src/views/DailyStandup/Slide/styles.module.css b/src/views/DailyStandup/Slide/styles.module.css index d468301..269ed4c 100644 --- a/src/views/DailyStandup/Slide/styles.module.css +++ b/src/views/DailyStandup/Slide/styles.module.css @@ -11,7 +11,7 @@ gap: var(--spacing-lg); .heading { - word-break: break-word; + overflow-wrap: break-word; color: var(--color-primary); font-size: var(--font-size-3xl); font-weight: var(--font-weight-light); @@ -38,19 +38,19 @@ text-align: center; .primary-pre-text { - word-break: break-word; + overflow-wrap: break-word; font-size: var(--font-size-xl); } .primary-heading { - word-break: break-word; + overflow-wrap: break-word; color: var(--color-primary); font-size: var(--font-size-3xl); font-weight: var(--font-weight-light); } .primary-description { - word-break: break-word; + overflow-wrap: break-word; color: var(--color-text-light); font-size: var(--font-size-xl); } diff --git a/src/views/DailyStandup/StartSection/index.tsx b/src/views/DailyStandup/StartSection/index.tsx index 4fcc837..d1f6982 100644 --- a/src/views/DailyStandup/StartSection/index.tsx +++ b/src/views/DailyStandup/StartSection/index.tsx @@ -1,6 +1,8 @@ import { + _cs, compareNumber, compareString, + encodeDate, } from '@togglecorp/fujs'; import { gql, @@ -10,9 +12,12 @@ import { import AvailabilityIndicator from '#components/AvailabilityIndicator'; import Clock from '#components/Clock'; import DisplayPicture from '#components/DisplayPicture'; +import TextOutput from '#components/TextOutput'; import { type JournalLeaveTypeEnum, type JournalWorkFromHomeTypeEnum, + type StandupConductorsQuery, + type StandupConductorsQueryVariables, type UsersAvailabilityQuery, type UsersAvailabilityQueryVariables, } from '#generated/types/graphql'; @@ -55,6 +60,26 @@ const USERS_AVAILABILITY = gql` } `; +export const STANDUP_CONDUCTORS = gql` + query StandupConductors($date: Date!){ + private { + dailyStandup(date: $date) { + conductor { + id + displayName + displayPicture + } + fallbackConductor { + id + displayName + displayPicture + } + } + } + } +`; + +const todayDate = encodeDate(new Date()); function StartSection() { const [usersAvailability] = useQuery< UsersAvailabilityQuery, @@ -64,6 +89,14 @@ function StartSection() { requestPolicy: 'cache-and-network', }); + const [conductorsResponse] = useQuery({ + query: STANDUP_CONDUCTORS, + variables: { date: todayDate }, + requestPolicy: 'cache-and-network', + }); + + const standupConductors = conductorsResponse.data?.private.dailyStandup; + // FIXME: need to check how to sort these information const sortedUsers = usersAvailability.data?.private.users.items .filter((item) => item.leaveToday || item.workFromHomeToday) @@ -84,8 +117,28 @@ function StartSection() { className={styles.startSection} primaryPreText="Welcome to" primaryHeading="Daily Standup" - primaryDescription={} - secondaryHeading="Availability" + primaryDescription={( +
+ + + +
+ )} + secondaryHeading="Unavailability" secondaryContent={sortedUsers?.map((user) => (
Date: Tue, 15 Jul 2025 18:23:02 +0545 Subject: [PATCH 2/2] feat(auth): add nagbar for login expiry - Fix conductors styling - Create a separate component for Standup conductors --- backend | 2 +- src/App/index.tsx | 1 + src/components/Clock/index.tsx | 52 --------- src/components/Navbar/index.tsx | 2 +- src/components/StandupConductors/index.tsx | 100 ++++++++++++++++++ .../StandupConductors/styles.module.css | 24 +++++ src/components/TextOutput/styles.module.css | 5 +- src/contexts/user.tsx | 2 +- src/hooks/useCurrentDate.ts | 30 ++++++ src/utils/common.ts | 18 ++++ .../DailyStandup/DeadlineSection/index.tsx | 44 ++------ .../DeadlineSection/styles.module.css | 23 ++-- src/views/DailyStandup/StartSection/index.tsx | 57 ++-------- .../StartSection/styles.module.css | 11 +- src/views/RootLayout/index.tsx | 29 ++++- src/views/RootLayout/styles.module.css | 7 ++ 16 files changed, 234 insertions(+), 173 deletions(-) delete mode 100644 src/components/Clock/index.tsx create mode 100644 src/components/StandupConductors/index.tsx create mode 100644 src/components/StandupConductors/styles.module.css create mode 100644 src/hooks/useCurrentDate.ts diff --git a/backend b/backend index 6a90d8c..3f638e0 160000 --- a/backend +++ b/backend @@ -1 +1 @@ -Subproject commit 6a90d8c605a3e02ea16968b03e8732c2f95feb9c +Subproject commit 3f638e051c66d561b36758e28553a0f188f461bb diff --git a/src/App/index.tsx b/src/App/index.tsx index a2f378d..53db948 100644 --- a/src/App/index.tsx +++ b/src/App/index.tsx @@ -57,6 +57,7 @@ const ME_QUERY = gql` id lastName isStaff + loginExpire } } } diff --git a/src/components/Clock/index.tsx b/src/components/Clock/index.tsx deleted file mode 100644 index 3646d4c..0000000 --- a/src/components/Clock/index.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { - useEffect, - useState, -} from 'react'; - -const dateTimeFormatter = new Intl.DateTimeFormat( - [], - { - year: 'numeric', - month: 'short', - day: 'numeric', - weekday: 'short', - hour: 'numeric', - minute: 'numeric', - // second: 'numeric', - hour12: true, - }, -); - -function formatTime(date: Date) { - return dateTimeFormatter.format(date); -} - -function Clock() { - const [dateStr, setDateStr] = useState(() => { - const date = new Date(); - return formatTime(date); - }); - useEffect( - () => { - const timeout = window.setInterval( - () => { - const date = new Date(); - const dateAsString = formatTime(date); - setDateStr(dateAsString); - }, - 500, - ); - return () => { - window.clearInterval(timeout); - }; - }, - [], - ); - return ( -
- {dateStr} -
- ); -} - -export default Clock; diff --git a/src/components/Navbar/index.tsx b/src/components/Navbar/index.tsx index 1bb81e2..bfd4715 100644 --- a/src/components/Navbar/index.tsx +++ b/src/components/Navbar/index.tsx @@ -102,7 +102,7 @@ function Navbar(props: Props) { {isNotDefined(userAuth) && ( Login diff --git a/src/components/StandupConductors/index.tsx b/src/components/StandupConductors/index.tsx new file mode 100644 index 0000000..56d5172 --- /dev/null +++ b/src/components/StandupConductors/index.tsx @@ -0,0 +1,100 @@ +import { + _cs, + encodeDate, +} from '@togglecorp/fujs'; +import { + gql, + useQuery, +} from 'urql'; + +import DisplayPicture from '#components/DisplayPicture'; +import TextOutput from '#components/TextOutput'; +import { + type StandupConductorsQuery, + type StandupConductorsQueryVariables, +} from '#generated/types/graphql'; + +import styles from './styles.module.css'; + +const STANDUP_CONDUCTORS = gql` + query StandupConductors($date: Date!){ + private { + dailyStandup(date: $date) { + conductor { + id + displayName + displayPicture + } + fallbackConductor { + id + displayName + displayPicture + } + } + } + } +`; + +const todayDate = encodeDate(new Date()); + +function StandupConductors() { + const [conductorsResponse] = useQuery({ + query: STANDUP_CONDUCTORS, + variables: { date: todayDate }, + requestPolicy: 'cache-and-network', + }); + + const standupConductors = conductorsResponse.data?.private.dailyStandup; + + return ( +
+ + + + {standupConductors?.conductor?.displayName + ?? 'Anonymous'} + + + )} + block + hideLabelColon + /> + + + + {standupConductors?.fallbackConductor?.displayName + ?? 'Anonymous'} + + + )} + block + hideLabelColon + /> +
+ ); +} + +export default StandupConductors; diff --git a/src/components/StandupConductors/styles.module.css b/src/components/StandupConductors/styles.module.css new file mode 100644 index 0000000..3b44308 --- /dev/null +++ b/src/components/StandupConductors/styles.module.css @@ -0,0 +1,24 @@ +.conductors { + display: flex; + flex-direction: column; + gap: var(--spacing-md); + + .conductor-item { + display: flex; + justify-content: center; + gap: var(--spacing-xs); + + &.hidden { + visibility: hidden; + } + + .conductor-value { + display: flex; + align-items: center; + justify-content: center; + font-size: var(--font-size-lg); + font-weight: var(--font-weight-normal); + gap: var(--spacing-xs); + } + } +} diff --git a/src/components/TextOutput/styles.module.css b/src/components/TextOutput/styles.module.css index 837924b..58e4e17 100644 --- a/src/components/TextOutput/styles.module.css +++ b/src/components/TextOutput/styles.module.css @@ -2,8 +2,8 @@ --spacing: var(--spacing-md); display: flex; align-items: baseline; - font-size: var(--font-size-sm); - gap: var(--spacing); + font-size: var(--font-size-md); + gap: var(--spacing-sm); &.blok { align-items: initial; @@ -25,7 +25,6 @@ >.description { color: var(--color-text-light); - font-size: var(--font-size-sm); } &.with-label-colon { diff --git a/src/contexts/user.tsx b/src/contexts/user.tsx index e3ef297..f85d2b8 100644 --- a/src/contexts/user.tsx +++ b/src/contexts/user.tsx @@ -4,7 +4,7 @@ import { UserMeType } from '#generated/types/graphql'; export type UserAuth = Pick< UserMeType, - 'displayName' | 'displayPicture' | 'email' | 'firstName' | 'id' | 'lastName' | 'isStaff' + 'displayName' | 'displayPicture' | 'email' | 'firstName' | 'id' | 'lastName' | 'isStaff' | 'loginExpire' >; export interface UserContextProps { diff --git a/src/hooks/useCurrentDate.ts b/src/hooks/useCurrentDate.ts new file mode 100644 index 0000000..a21b08f --- /dev/null +++ b/src/hooks/useCurrentDate.ts @@ -0,0 +1,30 @@ +import { + useEffect, + useState, +} from 'react'; + +function useCurrentDate() { + const [dateStr, setDateStr] = useState(() => { + const date = new Date(); + return date; + }); + + useEffect( + () => { + const timeout = window.setInterval( + () => { + const date = new Date(); + setDateStr(date); + }, + 5000, + ); + return () => { + window.clearInterval(timeout); + }; + }, + [], + ); + return dateStr; +} + +export default useCurrentDate; diff --git a/src/utils/common.ts b/src/utils/common.ts index cc02a0b..10fab46 100644 --- a/src/utils/common.ts +++ b/src/utils/common.ts @@ -395,3 +395,21 @@ export function putUndefined(value: T) { return copy as PutUndefined; } + +const dateTimeFormatter = new Intl.DateTimeFormat( + [], + { + year: 'numeric', + month: 'short', + day: 'numeric', + weekday: 'short', + hour: 'numeric', + minute: 'numeric', + // second: 'numeric', + hour12: true, + }, +); + +export function formatDateTime(date: Date) { + return dateTimeFormatter.format(date); +} diff --git a/src/views/DailyStandup/DeadlineSection/index.tsx b/src/views/DailyStandup/DeadlineSection/index.tsx index b6ae48a..a7b297b 100644 --- a/src/views/DailyStandup/DeadlineSection/index.tsx +++ b/src/views/DailyStandup/DeadlineSection/index.tsx @@ -9,28 +9,22 @@ import { FcNightLandscape, FcSportsMode, } from 'react-icons/fc'; -import { - _cs, - compareNumber, - encodeDate, -} from '@togglecorp/fujs'; +import { compareNumber } from '@togglecorp/fujs'; import { gql, useQuery, } from 'urql'; -import Clock from '#components/Clock'; -import TextOutput from '#components/TextOutput'; +import StandupConductors from '#components/StandupConductors'; import { type DeadlinesAndEventsQuery, type DeadlinesAndEventsQueryVariables, - type StandupConductorsQuery, - type StandupConductorsQueryVariables, } from '#generated/types/graphql'; +import useCurrentDate from '#hooks/useCurrentDate'; +import { formatDateTime } from '#utils/common'; import { type GeneralEvent } from '#utils/types'; import Slide from '../Slide'; -import { STANDUP_CONDUCTORS } from '../StartSection'; import GeneralEventOutput from './GeneralEvent'; import styles from './styles.module.css'; @@ -59,8 +53,6 @@ const DEADLINES_AND_EVENTS = gql` } `; -const todayDate = encodeDate(new Date()); - function DeadlineSection() { const [deadlinesAndEvents] = useQuery< DeadlinesAndEventsQuery, @@ -70,14 +62,6 @@ function DeadlineSection() { requestPolicy: 'cache-and-network', }); - const [conductorsResponse] = useQuery({ - query: STANDUP_CONDUCTORS, - variables: { date: todayDate }, - requestPolicy: 'cache-and-network', - }); - - const standupConductors = conductorsResponse.data?.private.dailyStandup; - const projects = deadlinesAndEvents.data?.private.allProjects; const events = deadlinesAndEvents.data?.private.relativeEvents; @@ -115,6 +99,7 @@ function DeadlineSection() { })) ?? []), ].sort((a, b) => compareNumber(a.remainingDays, b.remainingDays)); }, [events, projects]); + const todayDate = useCurrentDate(); return ( - - - +
{formatDateTime(todayDate)}
+
)} secondaryHeading="Upcoming Events" diff --git a/src/views/DailyStandup/DeadlineSection/styles.module.css b/src/views/DailyStandup/DeadlineSection/styles.module.css index 78f600f..c7c5dcd 100644 --- a/src/views/DailyStandup/DeadlineSection/styles.module.css +++ b/src/views/DailyStandup/DeadlineSection/styles.module.css @@ -1,3 +1,10 @@ +.primary-section{ + display: flex; + flex-direction: column; + text-align: center; + gap: var(--spacing-2xl); +} + .separator { display: flex; align-items: center; @@ -13,22 +20,6 @@ flex-grow: 1; border-bottom: var(--width-separator-sm) solid var(--color-separator); } - - .primary-section{ - display: flex; - flex-direction: column; - text-align: center; - gap: var(--spacing-sm); - - .conductor { - justify-content: center; - font-size: var(--font-size-sm); - - &.hidden { - visibility: hidden; - } - } - } } @keyframes run { diff --git a/src/views/DailyStandup/StartSection/index.tsx b/src/views/DailyStandup/StartSection/index.tsx index d1f6982..f793aa4 100644 --- a/src/views/DailyStandup/StartSection/index.tsx +++ b/src/views/DailyStandup/StartSection/index.tsx @@ -1,8 +1,6 @@ import { - _cs, compareNumber, compareString, - encodeDate, } from '@togglecorp/fujs'; import { gql, @@ -10,17 +8,16 @@ import { } from 'urql'; import AvailabilityIndicator from '#components/AvailabilityIndicator'; -import Clock from '#components/Clock'; import DisplayPicture from '#components/DisplayPicture'; -import TextOutput from '#components/TextOutput'; +import StandupConductors from '#components/StandupConductors'; import { type JournalLeaveTypeEnum, type JournalWorkFromHomeTypeEnum, - type StandupConductorsQuery, - type StandupConductorsQueryVariables, type UsersAvailabilityQuery, type UsersAvailabilityQueryVariables, } from '#generated/types/graphql'; +import useCurrentDate from '#hooks/useCurrentDate'; +import { formatDateTime } from '#utils/common'; import Slide from '../Slide'; @@ -60,26 +57,6 @@ const USERS_AVAILABILITY = gql` } `; -export const STANDUP_CONDUCTORS = gql` - query StandupConductors($date: Date!){ - private { - dailyStandup(date: $date) { - conductor { - id - displayName - displayPicture - } - fallbackConductor { - id - displayName - displayPicture - } - } - } - } -`; - -const todayDate = encodeDate(new Date()); function StartSection() { const [usersAvailability] = useQuery< UsersAvailabilityQuery, @@ -89,14 +66,6 @@ function StartSection() { requestPolicy: 'cache-and-network', }); - const [conductorsResponse] = useQuery({ - query: STANDUP_CONDUCTORS, - variables: { date: todayDate }, - requestPolicy: 'cache-and-network', - }); - - const standupConductors = conductorsResponse.data?.private.dailyStandup; - // FIXME: need to check how to sort these information const sortedUsers = usersAvailability.data?.private.users.items .filter((item) => item.leaveToday || item.workFromHomeToday) @@ -110,6 +79,7 @@ function StartSection() { bar.displayName, ), ); + const todayDate = useCurrentDate(); return ( - - - +
{formatDateTime(todayDate)}
+ )} secondaryHeading="Unavailability" diff --git a/src/views/DailyStandup/StartSection/styles.module.css b/src/views/DailyStandup/StartSection/styles.module.css index 200b4c0..4f7dcf1 100644 --- a/src/views/DailyStandup/StartSection/styles.module.css +++ b/src/views/DailyStandup/StartSection/styles.module.css @@ -17,15 +17,6 @@ display: flex; flex-direction: column; text-align: center; - gap: var(--spacing-sm); - - .conductor { - justify-content: center; - font-size: var(--font-size-sm); - - &.hidden { - visibility: hidden; - } - } + gap: var(--spacing-2xl); } } diff --git a/src/views/RootLayout/index.tsx b/src/views/RootLayout/index.tsx index 74e1e6c..5001b4c 100644 --- a/src/views/RootLayout/index.tsx +++ b/src/views/RootLayout/index.tsx @@ -1,19 +1,41 @@ +import { + useContext, + useMemo, +} from 'react'; import { Outlet, useNavigation, } from 'react-router-dom'; -import { _cs } from '@togglecorp/fujs'; +import { + _cs, + compareDate, +} from '@togglecorp/fujs'; import Navbar from '#components/Navbar'; +import UserContext from '#contexts/user'; +import useCurrentDate from '#hooks/useCurrentDate'; import useDebouncedValue from '#hooks/useDebouncedValue'; import styles from './styles.module.css'; +const REMAINING_DAYS_THRESHOLD = 5; + // eslint-disable-next-line import/prefer-default-export export function Component() { const { state } = useNavigation(); const isLoading = state === 'loading'; const isLoadingDebounced = useDebouncedValue(isLoading); + const { + userAuth, + } = useContext(UserContext); + + const todayDate = useCurrentDate(); + const daysBeforeLogout = useMemo(() => ( + compareDate(userAuth?.loginExpire, todayDate) / (60 * 60 * 1000 * 24) + ), [ + todayDate, + userAuth?.loginExpire, + ]); return (
@@ -25,6 +47,11 @@ export function Component() { )} /> )} + {userAuth && daysBeforeLogout < REMAINING_DAYS_THRESHOLD && ( +
+ {`You'll be automatically logged out in ${Math.floor(daysBeforeLogout)} days. Please re-login to avoid unexpected logout.`} +
+ )}
diff --git a/src/views/RootLayout/styles.module.css b/src/views/RootLayout/styles.module.css index b8cea23..b19f316 100644 --- a/src/views/RootLayout/styles.module.css +++ b/src/views/RootLayout/styles.module.css @@ -20,6 +20,13 @@ } } + .nagbar { + flex-shrink: 0; + background: var(--color-primary); + padding: var(--spacing-xs); + text-align: center; + color: var(--color-tertiary); + } .navbar { flex-shrink: 0; }