Skip to content

Commit

Permalink
Merge pull request #314 from bikehopper/collapsible-legs
Browse files Browse the repository at this point in the history
Collapsible Legs in Route Overview screen
  • Loading branch information
abhumbla authored Apr 18, 2024
2 parents 0d47d60 + 8af51ea commit 2c739da
Show file tree
Hide file tree
Showing 21 changed files with 480 additions and 189 deletions.
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)) {
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 ? (
<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;
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

0 comments on commit 2c739da

Please sign in to comment.