Skip to content

Commit

Permalink
Adds Overlay and FilterMenu components with responsive styles and fun…
Browse files Browse the repository at this point in the history
…ctionality
  • Loading branch information
TylerMatteo committed May 24, 2024
1 parent c2506bb commit e09abaa
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 22 deletions.
99 changes: 99 additions & 0 deletions app/components/FilterMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { useState, FormEvent } from "react";
import {
Button,
Flex,
FormControl,
FormLabel,
Heading,
Show,
Hide,
Select,
HStack,
} from "@nycplanning/streetscape";
import { ChevronDownIcon } from "@chakra-ui/icons";

export type GeographyType = "cd" | "ccd" | null;

export const FilterMenu = ({ onClose }: FilterMenuProps) => {
const [geographyType, setGeorgaphyType] = useState<GeographyType>("cd");
return (
<Flex
borderRadius={"base"}
padding={{ base: 3, lg: 4 }}
background={"white"}
direction={"column"}
width={{ base: "full", lg: "21.25rem" }}
maxW={{ base: "21.25rem", lg: "unset" }}
boxShadow={"0px 8px 4px 0px rgba(0, 0, 0, 0.08)"}
>
<Hide above="lg">
<ChevronDownIcon
onClick={() => {
onClose();
}}
role={"button"}
width={"full"}
height={8}
color={"gray.300"}
aria-label="Close geography filter menu"
/>
</Hide>
<Flex gap={4} direction={"column"}>
<Show above="lg">
<Heading
fontSize={"lg"}
textAlign={"left"}
fontWeight={"medium"}
width={"full"}
borderBottomStyle={"dotted"}
borderBottomWidth={"1px"}
borderBottomColor={"gray.400"}
>
Filter by Geography
</Heading>
</Show>
<FormControl id="geographyType">
<FormLabel>Geography Type</FormLabel>
<Select
placeholder="-Select-"
variant="base"
onChange={(e: FormEvent<HTMLSelectElement>) => {
setGeorgaphyType(e.currentTarget.value as GeographyType);
}}
value={geographyType}
>
<option value={"cd"}>Community District</option>
<option value={"ccd"}>City Council District</option>
</Select>
</FormControl>
<HStack spacing={2} width={"full"}>
{geographyType !== "ccd" ? (
<FormControl id="borough">
<FormLabel>Borough</FormLabel>
<Select
isDisabled={true}
placeholder="-Select-"
variant="base"
></Select>
</FormControl>
) : null}
<FormControl id="district">
<FormLabel>District</FormLabel>
<Select
placeholder="-Select-"
variant="base"
isDisabled={true}
></Select>
</FormControl>
</HStack>
<Button width="full" isDisabled={true}>
Go to Selected Geography
</Button>
</Flex>
</Flex>
);
};

export interface FilterMenuProps {
onClose: () => void;
}
51 changes: 51 additions & 0 deletions app/components/Overlay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Flex, Button, Hide, Show } from "@nycplanning/streetscape";
import { ReactNode, useState } from "react";
import { FilterMenu } from "./FilterMenu";

export const Overlay = () => {
const [shouldShowFilterMenu, setShouldShowFilterMenu] = useState(false);

return (
<Flex
position="relative"
padding={{ base: 3, lg: 8 }}
height={"100vh"}
width={"100vw"}
direction={{ base: "column", lg: "row" }}
justify={{ base: "flex-end", lg: "flex-start" }}
align={{ base: "center", lg: "flex-start" }}
pointerEvents={"none"}
sx={{
"*": {
pointerEvents: "auto",
},
}}
>
<Show above="lg">
<FilterMenu onClose={() => setShouldShowFilterMenu(false)} />
</Show>
{shouldShowFilterMenu ? (
<Hide above="lg">
<FilterMenu onClose={() => setShouldShowFilterMenu(false)} />
</Hide>
) : null}
{!shouldShowFilterMenu ? (
<Hide above="lg">
<Button
width={"full"}
maxW={"21.25rem"}
onClick={() => {
setShouldShowFilterMenu(true);
}}
>
Filter by Geography
</Button>
</Hide>
) : null}
</Flex>
);
};

export interface OverlayProps {
children: ReactNode;
}
10 changes: 8 additions & 2 deletions app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
} from "@remix-run/react";
import { Atlas } from "./components/atlas.client";
import { ClientOnly } from "remix-utils/client-only";
import { Overlay } from "./components/Overlay";

function Document({
children,
Expand All @@ -22,6 +23,7 @@ function Document({
<html lang="en">
<head>
<Meta />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{title}</title>
{/* Silence /favicon.ico error by pointing to null image. Remove link to null image after creating valid favicon. */}
<link
Expand All @@ -45,8 +47,12 @@ export default function App() {
<Document>
<StreetscapeProvider>
<Outlet />
<ClientOnly fallback={<h2>Loading map...</h2>}>
{() => <Atlas />}
<ClientOnly>
{() => (
<>
<Atlas /> <Overlay />
</>
)}
</ClientOnly>
</StreetscapeProvider>
</Document>
Expand Down
4 changes: 4 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"kubb:generate": "kubb generate"
},
"dependencies": {
"@chakra-ui/icons": "^2.1.1",
"@deck.gl/react": "^9.0.8",
"@emotion/react": "^11.11.3",
"@emotion/server": "^11.11.0",
Expand Down
29 changes: 29 additions & 0 deletions tests/app.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { test, expect } from '@playwright/test';

test('filter by geography button on mobile', async ({ page }) => {
await page.goto('http://localhost:5173/');
await page.setViewportSize({
width: 375,
height: 812,
});
await page.getByText('Filter by Geography').click();
await expect(page.getByText('Geography Type')).toBeVisible();
});

test('filter menu shows by default on desktop', async ({ page }) => {
await page.goto('http://localhost:5173/');
await expect(
page.getByRole('button', { name: 'Filter by Geography', exact: true }),
).not.toBeVisible();
await page.getByText('Filter by Geography').click();
await expect(page.getByText('Geography Type')).toBeVisible();
});

test('selecting City Council District hides borough select input', async ({
page,
}) => {
await page.goto('http://localhost:5173/');
await expect(page.getByLabel('Borough')).toBeVisible();
await page.getByLabel('Geography Type').selectOption('City Council District');
await expect(page.getByLabel('Borough')).not.toBeVisible();
});
20 changes: 0 additions & 20 deletions tests/example.spec.ts

This file was deleted.

0 comments on commit e09abaa

Please sign in to comment.