Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pc/feat/nav bar update #881

Merged
merged 19 commits into from
Dec 4, 2023
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .prettierrc
Copy link
Member Author

Choose a reason for hiding this comment

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

I couldn't get prettier to work until I changed this. Is this a bad idea? @devinmatte

Copy link
Member

Choose a reason for hiding this comment

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

Hmm did a new update break .js prettierrcs?

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"trailingComma": "es5",
"tabWidth": 2,
"singleQuote": true,
"printWidth": 100,
"plugins": ["prettier-plugin-tailwindcss"]
}
7 changes: 0 additions & 7 deletions .prettierrc.js

This file was deleted.

15 changes: 8 additions & 7 deletions common/components/buttons/DonateButton.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React, { useState } from 'react';
import { faHeart } from '@fortawesome/free-regular-svg-icons';
import { faHeart as faHeartSolid } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import Link from 'next/link';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faHeart as faHeartSolid } from '@fortawesome/free-solid-svg-icons';

export const DonateButton: React.FC = () => {
const [hovered, setHovered] = useState<boolean>(false);
Expand All @@ -12,11 +11,13 @@ export const DonateButton: React.FC = () => {
href="https://transitmatters.org/donate"
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)}
className="flex w-full cursor-pointer justify-center gap-x-2 rounded-md bg-tm-red p-2 ring-white focus:outline-none focus:ring-1 md:justify-start"
className="group flex w-full cursor-pointer justify-start gap-x-2 rounded-md ring-white focus:outline-none focus:ring-1 md:justify-start"
>
<div className="relative flex flex-row items-center text-base text-stone-100 md:pl-1">
<FontAwesomeIcon icon={hovered ? faHeartSolid : faHeart} className="pr-2" size="lg" />
<p>Donate</p>
<div className="relative flex flex-row items-center gap-2 text-sm text-stone-100 md:pl-1 ">
<div className="group flex h-8 w-8 items-center justify-center rounded-full bg-tm-red group-hover:bg-white">
<FontAwesomeIcon icon={faHeartSolid} size="lg" className="group-hover:text-tm-red" />
</div>
<p className="group-hover:text-blue-500">Donate</p>
</div>
</Link>
</>
Expand Down
34 changes: 34 additions & 0 deletions common/components/nav/BusDropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';
import { SidebarTabs } from '../../../modules/navigation/SidebarTabs';
import { TRIP_PAGES, BUS_OVERVIEW } from '../../constants/pages';
import { BusRouteSelection } from './BusRouteSelection';

interface BusDropdownProps {
close?: (
focusableElement?:
| HTMLElement
| React.MouseEvent<HTMLElement, MouseEvent>
| React.MutableRefObject<HTMLElement | null>
| undefined
) => void;
}

export const BusDropdown: React.FC<BusDropdownProps> = ({ close }) => {
return (
<div className="rounded-b-md">
<div>
<BusRouteSelection />
</div>
<div
className={
'flex flex-col gap-[2px] rounded-b-md border border-t-0 border-mbta-bus border-opacity-50 bg-neutral-800 px-1 py-[4px]'
}
role={'navigation'}
>
<SidebarTabs tabs={BUS_OVERVIEW} close={close} />
<hr className="h-[1px] w-3/4 self-center border-neutral-500" />
<SidebarTabs tabs={TRIP_PAGES} close={close} />
</div>
</div>
);
};
70 changes: 70 additions & 0 deletions common/components/nav/BusRouteSelection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { faCheckCircle } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Listbox, Transition } from '@headlessui/react';
import { ChevronUpDownIcon } from '@heroicons/react/20/solid';
import { useRouter } from 'next/navigation';
import React, { Fragment } from 'react';
import { getBusRoutes } from '../../constants/stations';
import { getBusRouteSelectionItemHref, useDelimitatedRoute } from '../../utils/router';
export const BusRouteSelection: React.FC = () => {
const route = useDelimitatedRoute();
const router = useRouter();
const busRoutes = getBusRoutes();
const selected = route.query.busRoute;
return (
<div className="bg-mbta-lightBus p-1">
<Listbox
value={selected}
onChange={(key) => router.push(getBusRouteSelectionItemHref(key, route))}
>
<div className="relative text-white text-opacity-95">
<Listbox.Button className="relative w-full cursor-pointer rounded-lg bg-mbta-bus py-1 pl-3 pr-10 text-left focus:outline-none focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white/75 focus-visible:ring-offset-2 focus-visible:ring-offset-orange-300 sm:text-sm">
<span className="block truncate">{selected}</span>
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
<ChevronUpDownIcon className="h-5 w-5 " aria-hidden="true" />
</span>
</Listbox.Button>
<Transition
as={Fragment}
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Listbox.Options className="absolute mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black/5 focus:outline-none sm:text-sm">
{busRoutes.map((busRoute, personIdx) => (
<Listbox.Option
key={personIdx}
className={({ active }) =>
`relative cursor-pointer select-none py-2 pl-10 pr-4 ${
active ? 'bg-amber-100 text-amber-900' : 'text-gray-900'
}`
}
value={busRoute}
>
{({ selected }) => (
<>
<span
className={`block truncate ${selected ? 'font-medium' : 'font-normal'}`}
>
{busRoute}
</span>
{selected ? (
<span className="absolute inset-y-0 left-0 flex items-center pl-3 text-mbta-bus">
<FontAwesomeIcon
icon={faCheckCircle}
className="h-5 w-5"
aria-hidden="true"
/>
</span>
) : null}
</>
)}
</Listbox.Option>
))}
</Listbox.Options>
</Transition>
</div>
</Listbox>
</div>
);
};
25 changes: 25 additions & 0 deletions common/components/nav/BusSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';
import { useDelimitatedRoute } from '../../utils/router';
import { BusDropdown } from './BusDropdown';
import { MenuDropdown } from './MenuDropdown';

interface BusSectionProps {
close?: (
focusableElement?:
| HTMLElement
| React.MouseEvent<HTMLElement, MouseEvent>
| React.MutableRefObject<HTMLElement | null>
| undefined
) => void;
}

export const BusSection: React.FC<BusSectionProps> = ({ close }) => {
const route = useDelimitatedRoute();
return (
<div className="w-full gap-y-2">
<MenuDropdown line="line-bus" route={route}>
<BusDropdown close={close} />
</MenuDropdown>
</div>
);
};
60 changes: 60 additions & 0 deletions common/components/nav/MenuDropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { faTrainSubway, faTrainTram } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import classNames from 'classnames';
import Link from 'next/link';
import React, { useEffect, useState } from 'react';
import { LINE_OBJECTS } from '../../constants/lines';
import { BUS_DEFAULTS } from '../../state/defaults/dateDefaults';
import { lineColorBackground } from '../../styles/general';
import type { Line } from '../../types/lines';
import type { Route } from '../../types/router';
import { getLineSelectionItemHref } from '../../utils/router';

interface MenuDropdownProps {
line: Line;
route: Route;
children: React.ReactNode;
}

export const MenuDropdown: React.FC<MenuDropdownProps> = ({ line, route, children }) => {
const selected = line === route.line;
const [show, setShow] = useState<boolean>(false);

// Need a timeout so that the selected and previously selected dropdowns do not render as opened simultaneously.
useEffect(() => {
setTimeout(() => setShow(true), 0);
}, [selected]);
return (
<div className={classNames('w-full')}>
<Link
href={
line === 'line-bus'
? `/bus/trips/single?busRoute=1&date=${BUS_DEFAULTS.singleTripConfig.date}`
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be nice to have some helper fns to generate these URLs

: getLineSelectionItemHref(line, route)
}
>
<div
className={classNames(
'flex w-full flex-row items-center gap-2 rounded-t-md py-1 text-sm ',
`${lineColorBackground[line ?? 'DEFAULT']}`,
selected
? `bg-opacity-100 text-white text-opacity-95`
: `bg-opacity-0 hover:rounded-md hover:bg-opacity-30`
)}
>
<div
className={classNames(
lineColorBackground[line ?? 'DEFAULT'],
'flex h-8 w-8 items-center justify-center rounded-full bg-opacity-75'
)}
>
{/* TODO: add bus icon */}
<FontAwesomeIcon icon={line === 'line-green' ? faTrainTram : faTrainSubway} size="lg" />
</div>
{LINE_OBJECTS[line].name}
</div>
</Link>
{selected && show && children}
</div>
);
};
16 changes: 16 additions & 0 deletions common/components/nav/NavSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react';
import { NavSectionHeader } from './NavSectionHeader';

interface NavSectionProps {
title: string;
content: React.ReactNode;
}

export const NavSection: React.FC<NavSectionProps> = ({ title, content }) => {
return (
<div className="mt-1">
<NavSectionHeader title={title} />
<div>{content}</div>
</div>
);
};
8 changes: 8 additions & 0 deletions common/components/nav/NavSectionHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from 'react';
interface NavSectionHeaderProps {
title: string;
}

export const NavSectionHeader: React.FC<NavSectionHeaderProps> = ({ title }) => {
return <h3 className="text-xs italic text-stone-300">{title}</h3>;
};
35 changes: 35 additions & 0 deletions common/components/nav/SubwayDropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import classNames from 'classnames';
import React from 'react';
import { SidebarTabs } from '../../../modules/navigation/SidebarTabs';
import { OVERVIEW_PAGE, LINE_PAGES, TRIP_PAGES } from '../../constants/pages';
import { lineColorBorder } from '../../styles/general';
import type { Line } from '../../types/lines';

interface SubwayDropdownProps {
line: Line;
close?: (
focusableElement?:
| HTMLElement
| React.MouseEvent<HTMLElement, MouseEvent>
| React.MutableRefObject<HTMLElement | null>
| undefined
) => void;
}

export const SubwayDropdown: React.FC<SubwayDropdownProps> = ({ line, close }) => {
return (
<div
className={classNames(
'flex flex-col gap-[2px] rounded-b-md border border-opacity-50 bg-neutral-800 px-1 py-[4px]',
lineColorBorder[line ?? 'DEFAULT']
)}
role={'navigation'}
>
<SidebarTabs tabs={OVERVIEW_PAGE} close={close} />
<hr className="h-[1px] w-3/4 self-center border-neutral-500" />
<SidebarTabs tabs={LINE_PAGES} close={close} />
<hr className="h-[1px] w-3/4 self-center border-neutral-500" />
<SidebarTabs tabs={TRIP_PAGES} close={close} />
</div>
);
};
35 changes: 35 additions & 0 deletions common/components/nav/SubwaySection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import { useDelimitatedRoute } from '../../utils/router';
import { MenuDropdown } from './MenuDropdown';
import { SubwayDropdown } from './SubwayDropdown';

interface SubwaySectionProps {
close?: (
focusableElement?:
| HTMLElement
| React.MouseEvent<HTMLElement, MouseEvent>
| React.MutableRefObject<HTMLElement | null>
| undefined
) => void;
}

export const SubwaySection: React.FC<SubwaySectionProps> = ({ close }) => {
const route = useDelimitatedRoute();

return (
<div className="w-full gap-y-2">
<MenuDropdown line="line-red" route={route}>
<SubwayDropdown line="line-red" close={close} />
</MenuDropdown>
<MenuDropdown line="line-orange" route={route}>
<SubwayDropdown line="line-orange" close={close} />
</MenuDropdown>
<MenuDropdown line="line-blue" route={route}>
<SubwayDropdown line="line-blue" close={close} />
</MenuDropdown>
<MenuDropdown line="line-green" route={route}>
<SubwayDropdown line="line-green" close={close} />
</MenuDropdown>
</div>
);
};
7 changes: 2 additions & 5 deletions common/constants/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ export const ALL_PAGES: PageMap = {
icon: faGaugeHigh,
dateStoreSection: 'line',
sectionTitle: 'Line',
sub: true,
},
service: {
key: 'service',
Expand All @@ -116,7 +115,6 @@ export const ALL_PAGES: PageMap = {
dateStoreSection: 'line',
sectionTitle: 'Line',
icon: faClockFour,
sub: true,
},
slowzones: {
key: 'slowzones',
Expand All @@ -126,7 +124,6 @@ export const ALL_PAGES: PageMap = {
icon: faWarning,
dateStoreSection: 'line',
sectionTitle: 'Line',
sub: true,
},
systemSlowzones: {
key: 'systemSlowzones',
Expand All @@ -145,7 +142,6 @@ export const ALL_PAGES: PageMap = {
icon: faUsers,
dateStoreSection: 'line',
sectionTitle: 'Line',
sub: true,
},
};

Expand All @@ -156,8 +152,9 @@ export const TODAY = [ALL_PAGES.today];

export const BUS_OVERVIEW = [ALL_PAGES.ridership];

export const OVERVIEW_PAGE = [ALL_PAGES.overview];

export const LINE_PAGES = [
ALL_PAGES.overview,
ALL_PAGES.service,
ALL_PAGES.slowzones,
ALL_PAGES.speed,
Expand Down
2 changes: 1 addition & 1 deletion common/layouts/PrimaryLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const queryClient = new QueryClient({
export const Layout: React.FC<LayoutProps> = ({ children }) => {
return (
<QueryClientProvider client={queryClient}>
<ReactQueryDevtools position="top-left" />
<ReactQueryDevtools position="bottom-right" />
<div className="flex h-screen flex-col">
<main className="relative h-full">{children}</main>
</div>
Expand Down
Loading
Loading