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

Collapsible Legs in Route Overview screen #314

Merged
merged 5 commits into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion src/components/Itinerary.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.Itinerary {
padding: 32px 32px;
padding: 32px 20px;
}

.Itinerary_overallTimeHeading {
Expand Down
23 changes: 21 additions & 2 deletions src/components/Itinerary.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as React from 'react';
import { useDispatch } from 'react-redux';
import { FormattedMessage, useIntl } from 'react-intl';
import { formatDurationBetween } from '../lib/time';
import { getAgencyDisplayName } from '../lib/region';
Expand All @@ -7,6 +8,7 @@ import ItineraryBikeLeg from './ItineraryBikeLeg';
import ItineraryHeader from './ItineraryHeader';
import ItineraryTransitLeg from './ItineraryTransitLeg';
import ItineraryElevationProfile from './ItineraryElevationProfile';
import { isSignificantLeg } from '../lib/leg';

import { ReactComponent as NavLeftArrow } from 'iconoir/icons/nav-arrow-left.svg';
import { ReactComponent as ArriveIcon } from 'iconoir/icons/triangle-flag.svg';
Expand All @@ -17,8 +19,11 @@ export default function Itinerary({
destinationDescription,
onBackClick,
onStepClick,
onToggleLegExpand,
viewingLeg,
scrollToStep,
}) {
const dispatch = useDispatch();
const intl = useIntl();
const [scrollToLegIdx, scrollToStepIdx] = scrollToStep || [];

Expand All @@ -29,10 +34,16 @@ export default function Itinerary({
key={idx}
leg={leg}
onStopClick={onStepClick.bind(null, idx)}
onToggleLegExpand={onToggleLegExpand.bind(null, idx)}
expanded={viewingLeg === idx}
scrollTo={scrollToLegIdx === idx}
/>
);
} else {
} else if (isSignificantLeg(leg)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

don't hide these by default: figure out better solution

const isOnlyLeg = legs.length === 1;
if (isOnlyLeg) {
onToggleLegExpand(idx);
}
// Where are we biking to? (Either final destination, or name of transit stop to board)
const legDestination =
idx === legs.length - 1
Expand All @@ -43,8 +54,12 @@ export default function Itinerary({
key={idx}
leg={leg}
legDestination={legDestination}
isOnlyLeg={isOnlyLeg}
onStepClick={onStepClick.bind(null, idx)}
onToggleLegExpand={onToggleLegExpand.bind(null, idx)}
expanded={viewingLeg === idx}
scrollToStep={scrollToLegIdx === idx ? scrollToStepIdx : null}
displayLegElevation={false}
/>
);
}
Expand Down Expand Up @@ -130,7 +145,11 @@ export default function Itinerary({
</div>
<div className="Itinerary_timeline">
{renderedLegs}
<ItineraryHeader icon={arriveIcon} iconColor="#ea526f">
<ItineraryHeader
icon={arriveIcon}
iconColor="#ea526f"
displayArrow={false}
>
<FormattedMessage
defaultMessage="Arrive at destination"
description="header text at end of step by step travel instructions"
Expand Down
64 changes: 40 additions & 24 deletions src/components/ItineraryBikeLeg.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,27 @@ import * as React from 'react';
import { FormattedMessage, useIntl } from 'react-intl';
import { BIKEHOPPER_THEME_COLOR } from '../lib/colors';
import formatDistance from '../lib/formatDistance';
import formatMajorStreets from '../lib/formatMajorStreets';
import { describeBikeInfra } from '../lib/geometry';
import { formatDurationBetween } from '../lib/time';
import InstructionSigns from '../lib/InstructionSigns';
import useScrollToRef from '../hooks/useScrollToRef';
import ItineraryBikeStep from './ItineraryBikeStep';
import ItineraryHeader from './ItineraryHeader';
import ItineraryDivider from './ItineraryDivider';
import ItinerarySpacer from './ItinerarySpacer';

import { ReactComponent as BikeIcon } from 'iconoir/icons/bicycle.svg';
import ItineraryElevationProfile from './ItineraryElevationProfile';

export default function ItineraryBikeLeg({
leg,
legDestination,
isOnlyLeg,
expanded,
onStepClick,
onToggleLegExpand,
scrollToStep,
displayLegElevation,
}) {
const intl = useIntl();
const instructionsWithBikeInfra = React.useMemo(() => {
Expand Down Expand Up @@ -63,6 +68,9 @@ export default function ItineraryBikeLeg({
icon={bikeIcon}
iconColor={BIKEHOPPER_THEME_COLOR}
alerts={alerts}
expanded={expanded}
alertsExpanded={true}
onToggleLegExpand={onToggleLegExpand}
>
<span>
<FormattedMessage
Expand All @@ -75,32 +83,40 @@ export default function ItineraryBikeLeg({
{formatDistance(leg.distance, intl)}
{spacer}
{formatDurationBetween(leg.departure_time, leg.arrival_time, intl)}
{spacer}
{formatMajorStreets(leg)}
</span>
</ItineraryHeader>
<ItineraryDivider />
{instructionsWithBikeInfra.map((step, stepIdx) =>
isArriveStep(step)
? null
: [
<ItineraryBikeStep
key={stepIdx}
step={step}
isFirstStep={stepIdx === 0}
onClick={onStepClick.bind(null, stepIdx)}
rootRef={stepIdx === scrollToStep ? scrollToRef : null}
/>,
<ItineraryDivider
key={stepIdx + 'd'}
transit={false}
detail={`${
step.distance ? formatDistance(step.distance, intl) : null
}`}
>
{step.bikeInfra}
</ItineraryDivider>,
],

{expanded ? (
Copy link
Contributor Author

Choose a reason for hiding this comment

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

try to flatten this

<div onClick={onToggleLegExpand}>
<ItinerarySpacer />

{isOnlyLeg || !displayLegElevation ? null : (
<ItineraryElevationProfile route={{ legs: [leg] }} />
)}

{instructionsWithBikeInfra.map((step, stepIdx) =>
isArriveStep(step)
? null
: [
<ItineraryBikeStep
key={stepIdx}
step={step}
distance={
step.distance ? formatDistance(step.distance, intl) : null
}
infra={step.bikeInfra}
isFirstStep={stepIdx === 0}
onClick={onStepClick.bind(null, stepIdx)}
rootRef={stepIdx === scrollToStep ? scrollToRef : null}
/>,
],
)}
</div>
) : (
<ItinerarySpacer />
)}
<ItinerarySpacer />
</>
);
}
Expand Down
7 changes: 7 additions & 0 deletions src/components/ItineraryBikeStep.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.ItineraryBikeStep_content {
margin-bottom: 15px;
}

.ItineraryBikeStep_infra {
color: #438601;
}
26 changes: 25 additions & 1 deletion src/components/ItineraryBikeStep.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import { FormattedMessage, useIntl } from 'react-intl';
import BorderlessButton from './BorderlessButton';
import InstructionSigns from '../lib/InstructionSigns';
import ItineraryStep from './ItineraryStep';
import classnames from 'classnames';

import './ItineraryBikeStep.css';

import { ReactComponent as MapsTurnBack } from 'iconoir/icons/maps-turn-back.svg';
import { ReactComponent as LongArrowUpLeft } from 'iconoir/icons/long-arrow-up-left.svg';
Expand All @@ -13,9 +16,12 @@ import { ReactComponent as QuestionMarkCircle } from 'iconoir/icons/help-circle.
import { ReactComponent as ArrowTrCircle } from 'iconoir/icons/arrow-tr-circle.svg';

let _warnedOfFallback = false;
const spacerWithMiddot = ' \u00B7 ';

export default function ItineraryBikeStep({
step,
distance,
infra,
isFirstStep,
onClick,
rootRef,
Expand Down Expand Up @@ -313,7 +319,25 @@ export default function ItineraryBikeStep({

return (
<ItineraryStep IconSVGComponent={IconComponent} rootRef={rootRef}>
<BorderlessButton onClick={onClick}>{msg}</BorderlessButton>
<div
className={classnames({
ItineraryBikeStep_content: true,
})}
>
<BorderlessButton onClick={onClick}>
{msg}
{spacerWithMiddot}
{distance}
{infra ? spacerWithMiddot : null}
<span
className={classnames({
ItineraryBikeStep_infra: true,
})}
>
{infra}
</span>
</BorderlessButton>
</div>
</ItineraryStep>
);
}
Expand Down
20 changes: 3 additions & 17 deletions src/components/ItineraryDivider.css
Original file line number Diff line number Diff line change
@@ -1,24 +1,10 @@
.ItineraryDivider_subheading {
font-weight: bold;
font-size: 14px;
line-height: 14px;
margin: 0 0 8px;
}

.ItineraryDivider_subheadingTransit {
color: #626262;
}

.ItineraryDivider_subheadingBike {
color: #438601;
}

.ItineraryDivider_horizontalRule {
color: #626262;
font-size: 12px;
line-height: 12px;
margin-bottom: 12px;
margin-top: 8px;
margin-bottom: 5px;
margin-left: 25px;
margin-top: 5px;
display: inline-block;
height: 12px;

Expand Down
11 changes: 0 additions & 11 deletions src/components/ItineraryDivider.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,6 @@ export default function ItineraryDivider(props) {
return (
<ItineraryRow>
{'' /* no content for timeline side of row */}
{subheading && (
<span
className={classnames({
ItineraryDivider_subheading: true,
ItineraryDivider_subheadingBike: !transit,
ItineraryDivider_subheadingTransit: transit,
})}
>
{subheading}
</span>
)}
<span className="ItineraryDivider_horizontalRule">
{detail && <span className="ItineraryDivider_detail">{detail}</span>}
</span>
Expand Down
39 changes: 27 additions & 12 deletions src/components/ItineraryHeader.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@

.ItineraryHeader_iconContainer {
display: inline-flex;
width: 60px;
height: 60px;
border-radius: 30px;
width: 36px;
height: 36px;
border-radius: 18px;
text-align: center;
flex-direction: column;
justify-content: space-around;
Expand All @@ -21,35 +21,50 @@

.ItineraryHeader_icon {
top: 0;
width: 32px;
height: 32px;
width: 20px;
height: 20px;
}

.ItineraryHeader_headerRow {
display: flex;
}

.ItineraryHeader_header {
font-size: 20px;
font-weight: bold;
font-size: 17px;
font-weight: 500;
margin: 0;
}

.ItineraryHeader_subheading {
font-weight: normal;
font-size: 16px;
margin: 8px 0;
font-size: 14px;
margin: 2px 0 0 0;
opacity: 0.6;
}

.ItineraryHeader_alerts {
background-color: #fffbca;
background-color: #fff5c0;
padding: 8px;
margin: 0;
margin: 8px 0 0 0;
list-style-type: none;
border: 1px solid rgb(187, 187, 187);
border: 1px solid #f4d598;
Comment on lines +46 to +50
Copy link
Contributor

Choose a reason for hiding this comment

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

We are gradually migrating toward using Tailwind CSS and it might be an opportunity if changing the styles a lot to convert these components over.

Also, can we grab a color from Tailwind's palette for these? I've been using the Tailwind palette for minor UI stuff. Or if we want to use a custom color, it would be nice to define these new colors globally in tailwind.config.js so we can use them consistently

border-radius: 4px;
font-size: 14px;
}

.ItineraryHeader_alertIcon {
margin-right: 4px;
position: relative;
top: 4px;
width: 16px;
height: 16px;
display: inline-block;
vertical-align: top;
}

.ItineraryHeader_alertIcon svg {
width: 16px;
height: 16px;
}

.ItineraryHeader_alertHeader {
Expand Down
Loading