From 193c08c8010bd30047517a3debed61adfb09bd14 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Fri, 20 Dec 2019 15:45:50 -0500 Subject: [PATCH] feat(ModeButton, ModeSelector-first draft): Add ModeButton, ModeSelector, Trimet/Biketown icons New ModeButton, first draft of ModeSelector (no events), add missing/unpublished TriMet and Biketown icons. --- packages/icons/src/index.js | 4 + packages/icons/src/index.story.js | 10 ++ packages/icons/src/trimet/TriMet.js | 28 ++++++ packages/icons/src/trimet/index.js | 2 + packages/settings-selector/package.json | 28 ++++++ packages/settings-selector/src/mode-button.js | 76 +++++++++++++++ .../src/mode-button.story.js | 76 +++++++++++++++ .../settings-selector/src/mode-selector.js | 94 +++++++++++++++++++ .../src/mode-selector.story.js | 34 +++++++ packages/settings-selector/src/styled.js | 84 +++++++++++++++++ 10 files changed, 436 insertions(+) create mode 100644 packages/icons/src/trimet/TriMet.js create mode 100644 packages/settings-selector/package.json create mode 100644 packages/settings-selector/src/mode-button.js create mode 100644 packages/settings-selector/src/mode-button.story.js create mode 100644 packages/settings-selector/src/mode-selector.js create mode 100644 packages/settings-selector/src/mode-selector.story.js create mode 100644 packages/settings-selector/src/styled.js diff --git a/packages/icons/src/index.js b/packages/icons/src/index.js index c7fad850d..862edcb0f 100644 --- a/packages/icons/src/index.js +++ b/packages/icons/src/index.js @@ -6,6 +6,7 @@ import TriMetLegIcon from "./trimet-leg-icon"; import TriMetModeIcon from "./trimet-mode-icon"; const { + Biketown, Bird, Bolt, Car2go, @@ -73,6 +74,7 @@ const { StreetcarCircle, Transittracker, TransittrackerSolid, + TriMet, TripPlanner, TripPlannerSolid, Walk, @@ -96,6 +98,7 @@ export { BikeLocker, BikeParking, BikeStaple, + Biketown, Bird, Bolt, Bus, @@ -146,6 +149,7 @@ export { StreetcarCircle, Transittracker, TransittrackerSolid, + TriMet, TriMetLegIcon, TriMetModeIcon, TripPlanner, diff --git a/packages/icons/src/index.story.js b/packages/icons/src/index.story.js index 2e96400c8..4f1f37964 100644 --- a/packages/icons/src/index.story.js +++ b/packages/icons/src/index.story.js @@ -73,6 +73,11 @@ storiesOf("Icons", module) )) + .add("Biketown", () => ( + + + + )) .add("Bird", () => ( @@ -328,6 +333,11 @@ storiesOf("Icons", module) )) + .add("TriMet", () => ( + + + + )) .add("TripPlannerSolid", () => ( diff --git a/packages/icons/src/trimet/TriMet.js b/packages/icons/src/trimet/TriMet.js new file mode 100644 index 000000000..90bff427e --- /dev/null +++ b/packages/icons/src/trimet/TriMet.js @@ -0,0 +1,28 @@ +import React from "react"; + +const SvgTriMet = () => ( + + + + + + +); + +export default SvgTriMet; diff --git a/packages/icons/src/trimet/index.js b/packages/icons/src/trimet/index.js index 3f0d7d044..7f0e9e5d1 100644 --- a/packages/icons/src/trimet/index.js +++ b/packages/icons/src/trimet/index.js @@ -36,6 +36,7 @@ import Streetcar from "./Streetcar"; import StreetcarCircle from "./StreetcarCircle"; import Transittracker from "./Transittracker"; import TransittrackerSolid from "./TransittrackerSolid"; +import TriMet from "./TriMet"; import TripPlanner from "./TripPlanner"; import TripPlannerSolid from "./TripPlannerSolid"; import Walk from "./Walk"; @@ -83,6 +84,7 @@ export { StreetcarCircle, Transittracker, TransittrackerSolid, + TriMet, TripPlanner, TripPlannerSolid, Walk, diff --git a/packages/settings-selector/package.json b/packages/settings-selector/package.json new file mode 100644 index 000000000..910671ae9 --- /dev/null +++ b/packages/settings-selector/package.json @@ -0,0 +1,28 @@ +{ + "name": "@opentripplanner/settings-selector", + "version": "0.0.1", + "description": "Trip Settings Selector and Related Components", + "author": "@binh-dam-ibigroup", + "homepage": "https://github.com/opentripplanner/otp-ui/#readme", + "license": "MIT", + "main": "index.js", + "module": "src/index.js", + "private": false, + "dependencies": { + "@opentripplanner/icons": "^0.0.1", + "@opentripplanner/core-utils": "^0.0.2" + }, + "publishConfig": { + "registry": "https://registry.yarnpkg.com" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/opentripplanner/otp-ui.git" + }, + "scripts": { + "test": "echo \"Error: run tests from root\" && exit 1" + }, + "bugs": { + "url": "https://github.com/opentripplanner/otp-ui/issues" + } +} diff --git a/packages/settings-selector/src/mode-button.js b/packages/settings-selector/src/mode-button.js new file mode 100644 index 000000000..d1e2a909d --- /dev/null +++ b/packages/settings-selector/src/mode-button.js @@ -0,0 +1,76 @@ +import React from "react"; +import PropTypes from "prop-types"; + +import { ModeButtonContainer, ModeButtonBtn, ModeButtonTitle } from "./styled"; + +/** + * ModeButton lets the user pick a travel mode. + * It includes the actual button that supports HTML/React text and graphics, + * and a title displayed when hovering the mouse over the button, and, optionally, underneath it. + * A ModeButton can be enabled or disabled, active or inactive. + */ +const ModeButton = props => { + const { selected, children, enabled, showTitle, title, onClick } = props; + + const activeClassName = selected ? "active" : ""; + const disabledClassName = enabled ? "" : "disabled"; + + return ( + + + {children} + + + {showTitle && ( + {title} + )} + + ); +}; + +ModeButton.propTypes = { + /** + * The contents of the button. Can be any HTML/React content. + */ + children: PropTypes.oneOfType([ + PropTypes.node, + PropTypes.arrayOf(PropTypes.node) + ]), + /** + * Determines whether the button is currently enabled. + */ + enabled: PropTypes.bool, + /** + * Triggered when the user clicks the button. + */ + onClick: PropTypes.func, + /** + * Determines whether the button should appear selected. + */ + selected: PropTypes.bool, + /** + * Determines whether the title should be displayed (underneath the button). + */ + showTitle: PropTypes.bool, + /** + * A title text for the button, displayed as popup when the user hover the mouse over the button, + * and optionally displayed underneath the button if showTitle is true. + */ + title: PropTypes.string +}; + +ModeButton.defaultProps = { + children: null, + enabled: true, + onClick: null, + selected: false, + showTitle: true, + title: null +}; + +export default ModeButton; diff --git a/packages/settings-selector/src/mode-button.story.js b/packages/settings-selector/src/mode-button.story.js new file mode 100644 index 000000000..bdf4dbbc9 --- /dev/null +++ b/packages/settings-selector/src/mode-button.story.js @@ -0,0 +1,76 @@ +import React from "react"; +import { action } from "@storybook/addon-actions"; +import { withInfo } from "@storybook/addon-info"; +import * as Icons from "@opentripplanner/icons"; + +import ModeButton from "./mode-button"; + +const background = story => ( +
+ {story()} +
+); + +export default { + title: "Mode Button", + component: "ModeButton", + decorators: [withInfo, background], + parameters: { + info: { + text: ` + ModeButton lets the user pick a travel mode. + It includes the actual button that supports HTML/React text and graphics, + and a title displayed when hovering the mouse over the button, and, optionally, underneath it. + A ModeButton can be enabled or disabled, and active or inactive. + ` + } + } +}; + +const onClick = action("onClick"); + +export const normal = () => ( + + + + + + Go by train or bike + +); + +export const active = () => ( + + + Train + +); + +export const disabled = () => ( + + + Can't select! + + +); + +export const labelOnly = () => ( + + + Walk Only + +); diff --git a/packages/settings-selector/src/mode-selector.js b/packages/settings-selector/src/mode-selector.js new file mode 100644 index 000000000..01a9bc8f1 --- /dev/null +++ b/packages/settings-selector/src/mode-selector.js @@ -0,0 +1,94 @@ +import React from "react"; +import PropTypes from "prop-types"; +import * as Icons from "@opentripplanner/icons"; +import { isTransit } from "@opentripplanner/core-utils/lib/itinerary"; + +import { MainModeRow, SecondaryModeRow, TertiaryModeRow } from "./styled"; +import ModeButton from "./mode-button"; + +/** + * ModeSelector is the control container where the OTP user selects + * the primary transportation modes, e.g. transit+bike, walk, micromobility... + */ +const ModeSelector = props => { + const { selectedModes } = props; + const modesHaveTransit = selectedModes.some(isTransit); + + return ( +
+ + + + Take Transit + + + + + + + + + + + + + + + + + + + + + + + + + + + + Walk Only + + + + Bike Only + + +
+ ); +}; + +ModeSelector.propTypes = { + /** + * An array of strings, each representing one transportation mode used for OTP queries. + */ + selectedModes: PropTypes.arrayOf(PropTypes.string) +}; + +ModeSelector.defaultProps = { + selectedModes: null +}; + +export default ModeSelector; diff --git a/packages/settings-selector/src/mode-selector.story.js b/packages/settings-selector/src/mode-selector.story.js new file mode 100644 index 000000000..f35523cfd --- /dev/null +++ b/packages/settings-selector/src/mode-selector.story.js @@ -0,0 +1,34 @@ +import React from "react"; +import { withInfo } from "@storybook/addon-info"; + +import ModeSelector from "./mode-selector"; + +const background = story => ( +
+ {story()} +
+); + +const selectedModes = ["BICYCLE", "TRAM", "RAIL", "BUS"]; + +export default { + title: "Mode Selector", + decorators: [withInfo, background], + parameters: { + info: { + text: ` + ModeSelector is the control container where the OTP user selects + the primary transportation modes such as transit, bike, walk, or micromobility. + ` + } + } +}; + +export const normal = () => ; diff --git a/packages/settings-selector/src/styled.js b/packages/settings-selector/src/styled.js new file mode 100644 index 000000000..78f70c099 --- /dev/null +++ b/packages/settings-selector/src/styled.js @@ -0,0 +1,84 @@ +import styled from "styled-components"; + +export const ModeButtonContainer = styled.div` + display: inline-block; + text-align: center; + box-sizing: border-box; +`; + +export const ModeButtonBtn = styled.button` + border: 1px solid rgb(187, 187, 187); + padding: 3px; + border-radius: 3px; + width: 100%; + height: 100%; + font-size: inherit; + font-family: inherit; + background: none; + outline: none; + cursor: pointer; + box-sizing: border-box; + + :hover { + background-color: rgb(173, 216, 230); + } + + &.active { + border: 2px solid rgb(0, 0, 0); + background-color: rgb(173, 216, 230); + } + svg { + vertical-align: middle; + width: 1.25em; + margin: 0 5px; + } + &.disabled { + cursor: default; + } + &.disabled svg { + fill: #ccc; + } +`; + +export const ModeButtonTitle = styled.div` + font-size: 10px; + padding: 4px; + + &.disabled { + color: #ccc; + } +`; + +const ModeRow = styled.div` + margin-bottom: 10px; + > * { + width: 33.333333%; + padding: 5px; + box-sizing: border-box; + } +`; + +export const MainModeRow = styled.div` + padding: 5px; + font-size: 200%; + margin-bottom: 10px; + box-sizing: border-box; + > * { + width: 100%; + height: 55px; + } +`; + +export const SecondaryModeRow = styled(ModeRow)` + font-size: 150%; + > * { + height: 58px; + } +`; + +export const TertiaryModeRow = styled(ModeRow)` + font-size: 90%; + > * { + height: 48px; + } +`;