Skip to content

Commit

Permalink
Styled navigation bar (#284)
Browse files Browse the repository at this point in the history
  • Loading branch information
macfarlandian committed Dec 18, 2020
1 parent 2995abf commit 25afc4d
Show file tree
Hide file tree
Showing 14 changed files with 408 additions and 78 deletions.
14 changes: 14 additions & 0 deletions spotlight-client/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,20 @@
{ "js": "never", "ts": "never", "tsx": "never" }
],

// make sure we are using the Babel macro for styled-components
"no-restricted-imports": [
"error",
{
"paths": [
{
"name": "styled-components",
"message": "Please import from styled-components/macro."
}
],
"patterns": ["!styled-components/macro"]
}
],

// support typescript as well as javascript file extensions
"react/jsx-filename-extension": ["error", { "extensions": [".tsx", ".js"] }]
},
Expand Down
6 changes: 6 additions & 0 deletions spotlight-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,24 @@
"@types/reach__router": "^1.3.6",
"@types/react": "^16.9.0",
"@types/react-dom": "^16.9.0",
"@types/styled-components": "^5.1.5",
"assert-never": "^1.2.1",
"change-case": "^4.1.2",
"jest-fetch-mock": "^3.0.3",
"mobx": "^6.0.4",
"mobx-react-lite": "^3.0.1",
"mobx-utils": "^6.0.1",
"polished": "^4.0.5",
"qs": "^6.9.4",
"react": "^16.13.1",
"react-app-polyfill": "^1.0.6",
"react-dom": "^16.13.1",
"react-error-boundary": "^3.0.2",
"react-helmet-async": "^1.0.7",
"react-is": "^16.13.1",
"react-scripts": "3.4.3",
"styled-components": "^5.2.1",
"styled-reset": "^4.3.3",
"typescript": "^4.0.0",
"utility-types": "^3.10.0",
"wait-for-localhost": "^3.3.0"
Expand Down
11 changes: 7 additions & 4 deletions spotlight-client/src/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,23 +121,26 @@ describe("navigation", () => {
});

test("nav bar", async () => {
const dataPortalLabel = "Explore";
const narrativesLabel = "Collections";

const {
history: { navigate },
} = renderNavigableApp();
const inNav = within(screen.getByRole("navigation"));

expect(
inNav.queryByRole("link", { name: "Explore Data" })
inNav.queryByRole("link", { name: dataPortalLabel })
).not.toBeInTheDocument();
expect(
inNav.queryByRole("link", { name: "Collections" })
inNav.queryByRole("link", { name: narrativesLabel })
).not.toBeInTheDocument();

await act(() => navigate("/us-nd"));
const homeLink = inNav.getByRole("link", { name: "Spotlight" });
const tenantLink = inNav.getByRole("link", { name: "North Dakota" });
const portalLink = inNav.getByRole("link", { name: "Explore Data" });
const narrativesLink = inNav.getByRole("link", { name: "Collections" });
const portalLink = inNav.getByRole("link", { name: dataPortalLabel });
const narrativesLink = inNav.getByRole("link", { name: narrativesLabel });

const verifyNavLinks = () => {
expect(homeLink).toBeInTheDocument();
Expand Down
53 changes: 29 additions & 24 deletions spotlight-client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@

import { RouteComponentProps, Router } from "@reach/router";
import React from "react";
import { HelmetProvider } from "react-helmet-async";
import AuthWall from "./AuthWall";
import GlobalStyles from "./GlobalStyles";
import PageExplore from "./PageExplore";
import PageHome from "./PageHome";
import PageMetric from "./PageMetric";
Expand All @@ -37,33 +39,36 @@ const PassThroughPage: React.FC<RouteComponentProps> = ({ children }) => (

const App: React.FC = () => {
return (
<StoreProvider>
<AuthWall>
<SiteNavigation />
<div role="main">
<Router>
{/*
NOTE: every leaf route component in this router should be wrapped
by the withRouteSync higher-order component to keep data and UI in sync!
*/}
<PageHome path="/" />
<PassThroughPage path="/:tenantId">
<PageTenant path="/" />
<PassThroughPage path={`/${DataPortalSlug}`}>
<PageExplore path="/" />
<PageMetric path="/:metricTypeId" />
<HelmetProvider>
<StoreProvider>
<GlobalStyles />
<AuthWall>
<SiteNavigation />
<div role="main">
<Router>
{/*
NOTE: every leaf route component in this router should be wrapped
by the withRouteSync higher-order component to keep data and UI in sync!
*/}
<PageHome path="/" />
<PassThroughPage path="/:tenantId">
<PageTenant path="/" />
<PassThroughPage path={`/${DataPortalSlug}`}>
<PageExplore path="/" />
<PageMetric path="/:metricTypeId" />
<PageNotFound default />
</PassThroughPage>
<PassThroughPage path={`/${NarrativesSlug}`}>
<PageNarrativeHome path="/" />
</PassThroughPage>
<PageNotFound default />
</PassThroughPage>
<PassThroughPage path={`/${NarrativesSlug}`}>
<PageNarrativeHome path="/" />
</PassThroughPage>
<PageNotFound default />
</PassThroughPage>
<PageNotFound default />
</Router>
</div>
</AuthWall>
</StoreProvider>
</Router>
</div>
</AuthWall>
</StoreProvider>
</HelmetProvider>
);
};

Expand Down
60 changes: 60 additions & 0 deletions spotlight-client/src/GlobalStyles/GlobalStyles.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Recidiviz - a data platform for criminal justice reform
// Copyright (C) 2020 Recidiviz, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =============================================================================

import React from "react";
import { Helmet } from "react-helmet-async";
import { createGlobalStyle } from "styled-components/macro";
import reset from "styled-reset";
import { colors, typefaces } from "../UiLibrary";

const BaseStyles = createGlobalStyle`
${reset}
html {
box-sizing: border-box;
* {
font-family: ${typefaces.body};
}
*, *:before, *:after {
box-sizing: inherit;
}
}
body {
background-color: ${colors.background};
color: ${colors.text};
}
`;

const GlobalStyles: React.FC = () => {
return (
<>
<Helmet>
<link rel="preconnect" href="https://fonts.gstatic.com" />
<link
href="https://fonts.googleapis.com/css2?family=Libre+Franklin&display=swap"
rel="stylesheet"
/>
</Helmet>
<BaseStyles />
</>
);
};

export default GlobalStyles;
18 changes: 18 additions & 0 deletions spotlight-client/src/GlobalStyles/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Recidiviz - a data platform for criminal justice reform
// Copyright (C) 2020 Recidiviz, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =============================================================================

export { default } from "./GlobalStyles";
28 changes: 20 additions & 8 deletions spotlight-client/src/PageHome/PageHome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,28 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =============================================================================

import { RouteComponentProps } from "@reach/router";
import { Link, RouteComponentProps } from "@reach/router";
import React from "react";
import { TenantIdList } from "../contentApi/types";
import getUrlForResource from "../routerUtils/getUrlForResource";
import withRouteSync from "../withRouteSync";

const PageHome: React.FC<RouteComponentProps> = () => (
<div>
<header>
const PageHome: React.FC<RouteComponentProps> = () => {
return (
<div>
<h1>Spotlight</h1>
</header>
</div>
);

<ul>
{TenantIdList.map((tenantId) => (
<li key={tenantId}>
<Link
to={getUrlForResource({ page: "tenant", params: { tenantId } })}
>
{tenantId}
</Link>
</li>
))}
</ul>
</div>
);
};
export default withRouteSync(PageHome);
Loading

0 comments on commit 25afc4d

Please sign in to comment.