diff --git a/packages/building-blocks/i18n/en-US.yml b/packages/building-blocks/i18n/en-US.yml new file mode 100644 index 000000000..153b1e162 --- /dev/null +++ b/packages/building-blocks/i18n/en-US.yml @@ -0,0 +1,4 @@ +otpUi: + buildingBlocks: + alert: + expand: Expand diff --git a/packages/building-blocks/i18n/fr.yml b/packages/building-blocks/i18n/fr.yml new file mode 100644 index 000000000..87a926396 --- /dev/null +++ b/packages/building-blocks/i18n/fr.yml @@ -0,0 +1,4 @@ +otpUi: + buildingBlocks: + alert: + expand: Développer diff --git a/packages/building-blocks/package.json b/packages/building-blocks/package.json index 9ee6fc64d..c33248d0a 100644 --- a/packages/building-blocks/package.json +++ b/packages/building-blocks/package.json @@ -14,6 +14,7 @@ }, "peerDependencies": { "react": "^18.2.0", + "react-animate-height": "^3.0.4", "styled-components": "^5.3.0" }, "repository": { @@ -27,5 +28,8 @@ "bugs": { "url": "https://github.com/opentripplanner/otp-ui/issues" }, - "gitHead": "0af1b7cda60bd4252b219dcf893e01c2acb2ed5d" + "gitHead": "0af1b7cda60bd4252b219dcf893e01c2acb2ed5d", + "dependencies": { + "@styled-icons/bootstrap": "^10.47.0" + } } diff --git a/packages/building-blocks/src/alert/Alert.tsx b/packages/building-blocks/src/alert/Alert.tsx new file mode 100644 index 000000000..7a5f4eef6 --- /dev/null +++ b/packages/building-blocks/src/alert/Alert.tsx @@ -0,0 +1,136 @@ +import React, { ReactChild, useState } from "react"; +import styled from "styled-components"; +import AnimateHeight from "react-animate-height"; +import { ChevronUp } from "@styled-icons/bootstrap/ChevronUp"; +import { Bell } from "@styled-icons/bootstrap/Bell"; +import { StyledIcon } from "@styled-icons/styled-icon"; +import { useIntl } from "react-intl"; +import blue from "../colors/blue"; + +interface Props { + alertHeader: string; + alertSubheader?: string; + backgroundColor?: string; + collapsible?: boolean; + children?: ReactChild; + Icon?: StyledIcon; +} + +const AlertContainer = styled.div<{ + backgroundColor: string; + collapsible: boolean; + expandAlert: boolean; +}>` + background-color: ${props => + props.backgroundColor ? props.backgroundColor : blue[50]}; + display: grid; + grid-template-columns: 50px auto auto; + grid-template-rows: minmax(25px, auto) auto; + max-width: 715px; + padding: 1.5em 2em; + + svg { + align-self: center; + grid-column: 1; + grid-row: 1 / span 2; + justify-self: start; + } + + button { + background: transparent; + border: none; + width: 40px; + + svg { + transform: ${props => !props.expandAlert && "rotate(180deg)"}; + transition: all 0.2s ease-in; + } + } + + @media (max-width: 550px) { + grid-template-columns: 40px auto auto; + padding: 1.25em 1.25em; + } +`; + +const ButtonContainer = styled.span` + align-items: center; + display: flex; + justify-content: center; + justify-self: right; +`; + +const AlertHeader = styled.span` + align-self: center; + font-weight: 700; + grid-column: 2; +`; + +const AlertSubheader = styled(AlertHeader)` + font-weight: 400; + margin-top: 0.3em; +`; + +const AlertContent = styled.div` + grid-column: 2; + grid-row: 3; +`; + +const ContentPadding = styled.div<{ + collapsible: boolean; +}>` + margin-top: ${props => (props.collapsible ? "1em" : ".5em")}; +`; + +const Alert = ({ + alertHeader, + alertSubheader, + backgroundColor, + children, + collapsible, + Icon = Bell +}: Props): JSX.Element => { + const [expandAlert, setExpandAlert] = useState(false); + const intl = useIntl(); + const label = intl.formatMessage({ + id: "otpUi.buildingBlocks.alert.expand", + defaultMessage: "Expand" + }); + return ( + + + {alertHeader} + + {collapsible && ( + + )} + + {alertSubheader && {alertSubheader}} + {children && ( + + + + {children} + + + + )} + + ); +}; + +export default Alert; diff --git a/packages/building-blocks/src/stories/__snapshots__/alerts.story.tsx.snap b/packages/building-blocks/src/stories/__snapshots__/alerts.story.tsx.snap new file mode 100644 index 000000000..5fa187bd8 --- /dev/null +++ b/packages/building-blocks/src/stories/__snapshots__/alerts.story.tsx.snap @@ -0,0 +1,104 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Building-Blocks/Alert BasicAlert smoke-test 1`] = ` +
+ + + Next trip starts on Wednesday April 17th + + + + + Trip is due to begin at 7:43 AM (Realtime monitoring will being at 7:13 AM) + +
+
+
+
+ Here is more content +
+
+
+
+
+`; + +exports[`Building-Blocks/Alert CollapsibleAlertWithTransitAlerts smoke-test 1`] = ` +
+ + + Your trip has alerts + + + + +
+ +
+
+`; diff --git a/packages/building-blocks/src/stories/alerts.story.tsx b/packages/building-blocks/src/stories/alerts.story.tsx new file mode 100644 index 000000000..751a4fba8 --- /dev/null +++ b/packages/building-blocks/src/stories/alerts.story.tsx @@ -0,0 +1,77 @@ +import React, { ReactElement } from "react"; +import { Meta } from "@storybook/react"; +import { ExclamationTriangle } from "@styled-icons/bootstrap/ExclamationTriangle"; +import Alert from "../alert/Alert"; +import red from "../colors/red"; + +const meta: Meta = { + title: "Building-Blocks/Alert", + component: Alert +}; + +export default meta; + +const alerts = [ + { + alertUrl: "http://trimet.org/alerts/", + effectiveStartDate: 1576471800, + alertDescriptionText: + "TriMet Customer Service will be unavailable to serve text messages or Twitter responses from 9:00 p.m.- 11:30 p.m. For immediate assistance regarding safety or security concerns, please contact the police via 911." + }, + { + alertUrl: + "https://news.trimet.org/2019/11/next-up-for-elevator-improvements-sunset-transit-center-park-ride/", + effectiveStartDate: 1573083439, + alertDescriptionText: + "The Park and Ride garage elevator at Sunset Transit Center is closed for approximately 3 months for improvements. During this time garage users must use the stairs or find alternate parking. Visit trimet.org/parkandride for a complete list of Park and Ride garages." + }, + { + alertUrl: "http://trimet.org/alerts/", + effectiveStartDate: 1572827580, + alertDescriptionText: + "The west elevators at the Washington Park MAX Station are out of service. Please use east elevators to access street level and platforms. " + } +]; + +const AlertContent = () => { + return ( + <> + {alerts.map((alert, i) => { + const alertKey = crypto.randomUUID(); + return ( + <> +
+ {`${i + 1}) `} + {alert.alertDescriptionText} +
+
+ + ); + })} + + ); +}; + +export const BasicAlert = (): ReactElement => { + return ( + + Here is more content + + ); +}; + +export const CollapsibleAlertWithTransitAlerts = (): ReactElement => { + return ( + + + + ); +}; diff --git a/yarn.lock b/yarn.lock index 6f0dcc55c..0b5b615f0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6168,6 +6168,14 @@ "@babel/runtime" "^7.14.0" "@styled-icons/styled-icon" "^10.6.3" +"@styled-icons/bootstrap@^10.47.0": + version "10.47.0" + resolved "https://registry.yarnpkg.com/@styled-icons/bootstrap/-/bootstrap-10.47.0.tgz#c3e363dfe87b732a5da818f320f90f5ab4961b84" + integrity sha512-xpnPdrLhAhpTRE4iljQIEK73twVj7VPglwHSL+8nQdH7EsW5RJIOWsmlkZMyqhQHN0H7fGmT10F3/6OQhSpfGg== + dependencies: + "@babel/runtime" "^7.20.7" + "@styled-icons/styled-icon" "^10.7.0" + "@styled-icons/boxicons-logos@10.38.0": version "10.38.0" resolved "https://registry.yarnpkg.com/@styled-icons/boxicons-logos/-/boxicons-logos-10.38.0.tgz#f51442c49f1a28c61927d6d2f8c1e2d7946faf46"