Skip to content

Commit

Permalink
feat(ts/components/vehicleMarker): implement shuttle colors
Browse files Browse the repository at this point in the history
  • Loading branch information
firestack committed Oct 21, 2024
2 parents 5a5355f + a3150de commit f78ae95
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 10 deletions.
19 changes: 19 additions & 0 deletions assets/css/map/markers/_vehicle_marker.scss
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,25 @@
filter: drop-shadow(1px 1px 4px $color-eggplant-400);
}


&.c-vehicle-marker--shuttle {
// Shuttle Colors
&.c-vehicle-marker--blue {
fill: var(--color-blue-line);
}
&.c-vehicle-marker--orange {
fill: var(--color-orange-line);
}
&.c-vehicle-marker--green {
fill: var(--color-green-line);
}
&.c-vehicle-marker--red {
fill: var(--color-red-line);
}
&.c-vehicle-marker--cr {
fill: var(--color-cr-line);
}
}
}

.c-vehicle-map__label {
Expand Down
49 changes: 45 additions & 4 deletions assets/src/components/map/markers/vehicleMarker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@ import { LatLngExpression, Marker } from "leaflet"
import React, {
PropsWithChildren,
useContext,
useEffect,
useRef,
useState,
useEffect,
} from "react"

import { StateDispatchContext } from "../../../contexts/stateDispatchContext"
import { joinClasses } from "../../../helpers/dom"
import { vehicleLabel } from "../../../helpers/vehicleLabel"
import { statusClasses, drawnStatus } from "../../../models/vehicleStatus"

import {
shuttleVariantFromRunId,
ShuttleVariant,
} from "../../../models/shuttle"
import { drawnStatus, statusClasses } from "../../../models/vehicleStatus"
import { Vehicle } from "../../../realtime"
import { ReactMarker } from "../utilities/reactMarker"

Expand All @@ -24,6 +27,41 @@ interface VehicleMarkerProps extends PropsWithChildren {
onShouldShowPopupChange?: (newValue: boolean) => void
}

/**
* If the supplied {@linkcode vehicle} is a shuttle, returns
* classes to more specifically style shuttles matching certain conditions.
* For example, specific styles depending on Rapid Transit Line the shuttle is
* associated with.
*
* @param vehicle The vehicle to return styles for
* @returns Array of classes to add to a vehicle marker
*/
const stylesForShuttle = (vehicle: Vehicle) => {
// If this vehicle isn't a shuttle, return no styles
if (vehicle.isShuttle === false) {
return []
}

// Otherwise return a generic shuttle class and any more
// specific styles for the shuttle.
const classFor = (variant: string) => `c-vehicle-marker--${variant}`
const shuttleClasses = ["c-vehicle-marker--shuttle"]
switch (vehicle.runId && shuttleVariantFromRunId(vehicle.runId)) {
case ShuttleVariant.Blue:
return shuttleClasses.concat(classFor("blue"))
case ShuttleVariant.CommuterRail:
return shuttleClasses.concat(classFor("cr"))
case ShuttleVariant.Green:
return shuttleClasses.concat(classFor("green"))
case ShuttleVariant.Orange:
return shuttleClasses.concat(classFor("orange"))
case ShuttleVariant.Red:
return shuttleClasses.concat(classFor("red"))
default:
return shuttleClasses
}
}

export const VehicleMarker = ({
children,
vehicle,
Expand Down Expand Up @@ -95,7 +133,10 @@ export const VehicleMarker = ({
}}
icon={
<svg
className="c-vehicle-map__icon"
className={joinClasses([
"c-vehicle-map__icon",
...stylesForShuttle(vehicle),
])}
height="24"
viewBox="0 0 24 24"
width="24"
Expand Down
35 changes: 34 additions & 1 deletion assets/src/models/shuttle.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,37 @@
import { Vehicle } from "../realtime"
import { RunId, Vehicle } from "../realtime"

export enum ShuttleVariant {
// Rapid Transit Lines
Blue = "Blue",
Green = "Green",
Orange = "Orange",
Red = "Red",

// Other Shuttle Types
CommuterRail = "CR",
Special = "Special",
}

export const shuttleVariantFromRunId = (
runId: RunId
): ShuttleVariant | null => {
switch (runId) {
case "999-0501":
return ShuttleVariant.Blue
case "999-0502":
return ShuttleVariant.Green
case "999-0503":
return ShuttleVariant.Orange
case "999-0504":
return ShuttleVariant.Red
case "999-0505":
return ShuttleVariant.CommuterRail
case "999-0555":
return ShuttleVariant.Special
default:
return null
}
}

export const formattedRunNumber = ({ runId }: Vehicle): string => {
if (runId === null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ exports[`Shuttle Map Page renders 1`] = `
tabindex="0"
>
<svg
class="c-vehicle-map__icon"
class="c-vehicle-map__icon c-vehicle-marker--shuttle"
height="24"
viewBox="0 0 24 24"
width="24"
Expand Down Expand Up @@ -923,7 +923,7 @@ exports[`Shuttle Map Page renders selected shuttle routes 1`] = `
tabindex="0"
>
<svg
class="c-vehicle-map__icon"
class="c-vehicle-map__icon c-vehicle-marker--shuttle"
height="24"
viewBox="0 0 24 24"
width="24"
Expand Down Expand Up @@ -1632,7 +1632,7 @@ exports[`Shuttle Map Page renders with all shuttles selected 1`] = `
tabindex="0"
>
<svg
class="c-vehicle-map__icon"
class="c-vehicle-map__icon c-vehicle-marker--shuttle"
height="24"
viewBox="0 0 24 24"
width="24"
Expand Down Expand Up @@ -2650,7 +2650,7 @@ exports[`Shuttle Map Page renders with train vehicles 1`] = `
tabindex="0"
>
<svg
class="c-vehicle-map__icon"
class="c-vehicle-map__icon c-vehicle-marker--shuttle"
height="24"
viewBox="0 0 24 24"
width="24"
Expand Down
73 changes: 72 additions & 1 deletion assets/tests/components/map/markers/vehicleMarker.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import "@testing-library/jest-dom/jest-globals"

import { VehicleMarker } from "../../../../src/components/map/markers/vehicleMarker"

import { vehicleFactory } from "../../../factories/vehicle"
import { shuttleFactory, vehicleFactory } from "../../../factories/vehicle"
import { MapContainer } from "react-leaflet"

const TestMap = ({ children }: PropsWithChildren): React.JSX.Element => (
Expand Down Expand Up @@ -38,4 +38,75 @@ describe("VehicleMarker", () => {
expect(container.querySelector(".c-vehicle-map__icon")).toBeInTheDocument()
expect(screen.getByText("101")).toBeInTheDocument()
})

describe.each([
{
forRunId: "999-0501",
assertSpecialClass: ".c-vehicle-marker--blue",
},
{
forRunId: "999-0502",
assertSpecialClass: ".c-vehicle-marker--green",
},
{
forRunId: "999-0503",
assertSpecialClass: ".c-vehicle-marker--orange",
},
{
forRunId: "999-0504",
assertSpecialClass: ".c-vehicle-marker--red",
},
{
forRunId: "999-0505",
assertSpecialClass: ".c-vehicle-marker--cr",
},
{
forRunId: "999-0555",
assertSpecialClass: null,
},
{
forRunId: "101",
assertSpecialClass: null,
},
])(
"when vehicle is shuttle with runId:`$runId`",
({ forRunId, assertSpecialClass }) => {
test("should render with shuttle class", () => {
const { container } = render(
<VehicleMarker
vehicle={shuttleFactory.build({
runId: forRunId,
})}
isPrimary={true}
/>,
{
wrapper: TestMap,
}
)

expect(
container.querySelector(".c-vehicle-marker--shuttle")
).toBeInTheDocument()
})

assertSpecialClass !== null &&
test(`should render with class \`${assertSpecialClass}\``, () => {
const { container } = render(
<VehicleMarker
vehicle={shuttleFactory.build({
runId: forRunId,
})}
isPrimary={true}
/>,
{
wrapper: TestMap,
}
)

expect(
container.querySelector(assertSpecialClass)
).toBeInTheDocument()
})
}
)
})

0 comments on commit f78ae95

Please sign in to comment.