Skip to content

Commit

Permalink
assorted iOS polish and bugfixes (#396)
Browse files Browse the repository at this point in the history
  • Loading branch information
macfarlandian committed Apr 19, 2021
1 parent 640fa4e commit 6493607
Show file tree
Hide file tree
Showing 9 changed files with 135 additions and 95 deletions.
1 change: 1 addition & 0 deletions spotlight-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
},
"dependencies": {
"@auth0/auth0-spa-js": "^1.13.1",
"@reach/auto-id": "^0.15.0",
"@reach/router": "^1.3.4",
"@recidiviz/case-triage-components": "^0.2.2",
"@types/body-scroll-lock": "^2.6.1",
Expand Down
112 changes: 63 additions & 49 deletions spotlight-client/src/SiteNavigation/SiteNavigationMobile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =============================================================================

import { disableBodyScroll, enableBodyScroll } from "body-scroll-lock";
import { observer } from "mobx-react-lite";
import { rem } from "polished";
import React from "react";
import React, { useRef } from "react";
import useCollapse from "react-collapsed";
import { animated, useSpring } from "react-spring/web.cjs";
import styled from "styled-components/macro";
Expand Down Expand Up @@ -65,9 +66,11 @@ const ExternalNavLink = styled(ExternalNavLinkBase)`
const NavMenu = styled.ul`
font-family: ${typefaces.display};
font-size: ${rem(20)};
height: calc(100vh - ${rem(NAV_BAR_HEIGHT)});
letter-spacing: -0.015em;
line-height: 1.3;
margin-left: ${rem(16)};
overflow: auto;
`;

const NavMenuItem = styled.li`
Expand All @@ -83,12 +86,21 @@ const NavMenuItem = styled.li`
const SiteNavigation: React.FC = () => {
const { tenant } = useDataStore();

const menuScrollRef = useRef<HTMLDivElement>(null);

const {
getCollapseProps,
getToggleProps,
isExpanded,
setExpanded,
} = useCollapse({});
} = useCollapse({
onCollapseStart: () => {
if (menuScrollRef.current) enableBodyScroll(menuScrollRef.current);
},
onExpandStart: () => {
if (menuScrollRef.current) disableBodyScroll(menuScrollRef.current);
},
});

const animatedStyles = useSpring({
from: { background: colors.background },
Expand Down Expand Up @@ -121,61 +133,63 @@ const SiteNavigation: React.FC = () => {
</NavGroup>
<MenuButton isOpen={isExpanded} {...getToggleProps()} />
</NavBar>
<NavMenu {...getCollapseProps()} data-testid="NavMenu">
{tenant && (
<>
<NavMenuItem>
<NavLink
onClick={() => setExpanded(false)}
to={getUrlForResource({
page: "tenant",
params: { tenantId: tenant.id },
})}
>
Home
</NavLink>
</NavMenuItem>
{Object.values(tenant.systemNarratives).map(
(narrative) =>
narrative && (
<NavMenuItem key={narrative.id}>
<NavLink
onClick={() => setExpanded(false)}
to={getUrlForResource({
page: "narrative",
params: {
tenantId: tenant.id,
narrativeTypeId: narrative.id,
},
})}
>
{narrative.title}
</NavLink>
</NavMenuItem>
)
)}
{tenant.racialDisparitiesNarrative && (
<div ref={menuScrollRef}>
<NavMenu {...getCollapseProps()} data-testid="NavMenu">
{tenant && (
<>
<NavMenuItem>
<NavLink
onClick={() => setExpanded(false)}
to={getUrlForResource({
page: "narrative",
params: {
tenantId: tenant.id,
narrativeTypeId: "RacialDisparities",
},
page: "tenant",
params: { tenantId: tenant.id },
})}
>
{tenant.racialDisparitiesNarrative.title}
Home
</NavLink>
</NavMenuItem>
)}
<NavMenuItem>
<ExternalNavLink href={FEEDBACK_URL}>Feedback</ExternalNavLink>
</NavMenuItem>
</>
)}
</NavMenu>
{Object.values(tenant.systemNarratives).map(
(narrative) =>
narrative && (
<NavMenuItem key={narrative.id}>
<NavLink
onClick={() => setExpanded(false)}
to={getUrlForResource({
page: "narrative",
params: {
tenantId: tenant.id,
narrativeTypeId: narrative.id,
},
})}
>
{narrative.title}
</NavLink>
</NavMenuItem>
)
)}
{tenant.racialDisparitiesNarrative && (
<NavMenuItem>
<NavLink
onClick={() => setExpanded(false)}
to={getUrlForResource({
page: "narrative",
params: {
tenantId: tenant.id,
narrativeTypeId: "RacialDisparities",
},
})}
>
{tenant.racialDisparitiesNarrative.title}
</NavLink>
</NavMenuItem>
)}
<NavMenuItem>
<ExternalNavLink href={FEEDBACK_URL}>Feedback</ExternalNavLink>
</NavMenuItem>
</>
)}
</NavMenu>
</div>
</NavContainer>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,8 @@ import HTMLReactParser from "html-react-parser";
import React from "react";
import SystemNarrative from "../contentModels/SystemNarrative";
import {
Chevron,
NarrativeIntroContainer,
NarrativeIntroCopy,
NarrativeScrollIndicator,
NarrativeSectionBody,
NarrativeSectionTitle,
NarrativeTitle,
Expand All @@ -44,11 +42,6 @@ const SystemNarrativePage: React.FC<{
<NarrativeIntroCopy>
{HTMLReactParser(narrative.introduction)}
</NarrativeIntroCopy>
<NarrativeScrollIndicator>
<span>SCROLL</span>
<Chevron direction="down" faded />
<Chevron direction="down" />
</NarrativeScrollIndicator>
</NarrativeIntroContainer>
),
},
Expand Down
20 changes: 0 additions & 20 deletions spotlight-client/src/UiLibrary/narrative.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import { rem } from "polished";
import styled from "styled-components/macro";
import breakpoints from "./breakpoints";
import colors from "./colors";
import CopyBlock from "./CopyBlock";
import { FullScreenSection } from "./PageSection";
import PageTitle from "./PageTitle";
Expand Down Expand Up @@ -52,25 +51,6 @@ export const NarrativeIntroCopy = styled(CopyBlock)`
}
`;

export const NarrativeScrollIndicator = styled.div`
align-items: center;
color: ${colors.caption};
display: flex;
flex-direction: column;
font-size: ${rem(12)};
font-weight: 500;
letter-spacing: 0.05em;
margin-top: ${rem(32)};
@media screen and (min-width: ${breakpoints.tablet[0]}px) {
margin-top: ${rem(144)};
}
span {
margin-bottom: ${rem(16)};
}
`;

export const NarrativeSectionTitle = styled.h2`
font-family: ${typefaces.display};
font-size: ${rem(24)};
Expand Down
9 changes: 3 additions & 6 deletions spotlight-client/src/VizControls/VizControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,11 @@ const ControlsGroup = styled.div`
display: flex;
flex-wrap: wrap;
margin-bottom: ${rem(16)};
padding-bottom: ${rem(16)};
`;

const FilterWrapper = styled.div`
margin: 0 ${rem(16)};
&:first-child {
margin-left: 0;
}
margin-bottom: ${rem(16)};
margin-right: ${rem(32)};
&:last-child {
margin-right: 0;
Expand All @@ -57,6 +53,7 @@ const Button = styled.button`
cursor: pointer;
font-size: ${rem(14)};
font-weight: 500;
margin-bottom: ${rem(16)};
padding: none;
`;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
// =============================================================================

import { observer } from "mobx-react-lite";
import React from "react";
import React, { useState } from "react";
import Measure from "react-measure";
import { animated, useSpring, useTransition } from "react-spring/web.cjs";
import styled from "styled-components/macro";
Expand Down Expand Up @@ -70,7 +70,12 @@ type VizRecidivismRateSingleFollowupProps = {
const VizRecidivismRateSingleFollowup: React.FC<VizRecidivismRateSingleFollowupProps> = ({
metric,
}) => {
const { singleFollowupDemographics, demographicView, unknowns } = metric;
const {
demographicView,
followUpYears,
singleFollowupDemographics,
unknowns,
} = metric;

const [chartContainerStyles, setChartContainerStyles] = useSpring(() => ({
from: { height: singleChartHeight },
Expand All @@ -84,6 +89,14 @@ const VizRecidivismRateSingleFollowup: React.FC<VizRecidivismRateSingleFollowupP
animation.crossFade
);

const [containerWidth, setContainerWidth] = useState<number>();
// this is NOT a sophisticated heuristic, but the bar labels
// (which are years) tend to get cramped around this size
const useAngledLabels =
typeof containerWidth === "number" &&
containerWidth < 400 &&
followUpYears === 1;

if (demographicView === "nofilter")
throw new Error(
"Unable to display this metric without demographic filter."
Expand All @@ -94,7 +107,10 @@ const VizRecidivismRateSingleFollowup: React.FC<VizRecidivismRateSingleFollowupP
<Measure
bounds
onResize={({ bounds }) => {
if (bounds) setChartContainerStyles({ height: bounds.height });
if (bounds) {
setChartContainerStyles({ height: bounds.height });
setContainerWidth(bounds.width);
}
}}
>
{({ measureRef }) => (
Expand All @@ -115,6 +131,7 @@ const VizRecidivismRateSingleFollowup: React.FC<VizRecidivismRateSingleFollowupP
// but it should always be defined if we've gotten this far
item.singleFollowupDemographics && (
<BarChartTrellis
angledLabels={useAngledLabels}
barAxisLabel="Release Cohort"
data={item.singleFollowupDemographics}
getTooltipProps={getTooltipProps}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =============================================================================

import { useId } from "@reach/auto-id";
import { scaleLinear } from "d3-scale";
import { rgba } from "polished";
import React, { useState } from "react";
Expand All @@ -26,7 +27,7 @@ import { $Keys } from "utility-types";
import ResponsiveTooltipController from "../charts/ResponsiveTooltipController";
import { formatAsNumber } from "../utils";
import MeasureWidth from "../MeasureWidth";
import { animation, breakpoints, colors, typefaces } from "../UiLibrary";
import { breakpoints, colors, typefaces } from "../UiLibrary";

export const CHART_BOTTOM_PADDING = 80;
export const CHART_HEIGHT = 500;
Expand Down Expand Up @@ -119,9 +120,9 @@ const targetColor = rgba(baseColor, 0.5);

const hoverColor = rgba(baseColor, 0.2);

const Gradients = (
const Gradients = ({ idPrefix }: { idPrefix: string | undefined }) => (
<>
<linearGradient id="incarcerationGradient">
<linearGradient id={`${idPrefix}incarcerationGradient`}>
<stop offset="0" stopColor={sourceColors.Incarceration} stopOpacity="1" />
<stop
offset="15%"
Expand All @@ -130,12 +131,12 @@ const Gradients = (
/>
<stop offset="90%" stopColor={targetColor} stopOpacity="1" />
</linearGradient>
<linearGradient id="probationGradient">
<linearGradient id={`${idPrefix}probationGradient`}>
<stop offset="0" stopColor={sourceColors.Probation} stopOpacity="1" />
<stop offset="15%" stopColor={sourceColors.Probation} stopOpacity="0.8" />
<stop offset="90%" stopColor={targetColor} stopOpacity="1" />
</linearGradient>
<linearGradient id="bothGradient">
<linearGradient id={`${idPrefix}bothGradient`}>
<stop offset="0" stopColor={sourceColors.Both} stopOpacity="1" />
<stop offset="15%" stopColor={sourceColors.Both} stopOpacity="0.8" />
<stop offset="90%" stopColor={targetColor} stopOpacity="1" />
Expand Down Expand Up @@ -221,6 +222,12 @@ export default function SingleStepSankey({
);
};

// some browsers (most notably iOS Safari) fail to render these gradients
// if this component appears more than once on the page, because the ids
// are then non-unique in the context of the HTML document. Thus the prefix,
// which should be unique per component instance.
const gradientIdPrefix = useId();

return (
<MeasureWidth>
{({ measureRef, width }) => (
Expand All @@ -232,18 +239,20 @@ export default function SingleStepSankey({
setHighlighted={setHighlighted}
>
<NetworkFrame
additionalDefs={Gradients}
additionalDefs={<Gradients idPrefix={gradientIdPrefix} />}
baseMarkProps={{
transitionDuration: {
fill: animation.defaultDuration,
// transitions don't work well with our gradient fills;
// less janky to just disable them
fill: 0,
},
}}
edges={edges}
edgeStyle={(d) => {
return {
fill: shouldFade(d)
? hoverColor
: `url(#${d.source.id.toLowerCase()}Gradient)`,
: `url(#${gradientIdPrefix}${d.source.id.toLowerCase()}Gradient)`,
};
}}
margin={{ ...MARGIN, right: rightMargin }}
Expand Down

0 comments on commit 6493607

Please sign in to comment.