Skip to content

Commit

Permalink
Fixed final row not rendering in dual column mode
Browse files Browse the repository at this point in the history
Added search results page
Fixed content expanding weirdly on some browsers
Styling consistency changes
Fixed search bugs
  • Loading branch information
dons20 committed Mar 25, 2021
1 parent e912dbe commit df6efa4
Show file tree
Hide file tree
Showing 10 changed files with 259 additions and 39 deletions.
98 changes: 84 additions & 14 deletions src/components/Header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useContext, useState } from "react";
import { FaSearch, FaSun, FaMoon, FaHome, FaBars } from "react-icons/fa";
import { useDebouncedCallback } from "use-debounce";
import { useHistory } from "react-router-dom";
import { Button } from "components";
import { MainContext } from "App";
import Fuse from "fuse.js";
import {
Expand All @@ -21,27 +22,52 @@ import {
CloseButton,
Portal,
useColorModeValue,
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalCloseButton,
ModalBody,
VStack,
} from "@chakra-ui/react";
import "./Header.scss";
import { Button } from "components";

function Header() {
const history = useHistory();
const { songs } = useContext(MainContext);
const { colorMode, toggleColorMode } = useColorMode();
const { isOpen, onOpen, onClose } = useDisclosure();
const { isOpen: isModalOpen, onOpen: onModalOpen, onClose: onModalClose } = useDisclosure();
const fuse = new Fuse(songs!, { keys: ["number", "title"] });
const [query, setQuery] = useState("");
const [mobileQuery, setMobileQuery] = useState("");
const [queryResults, setQueryResults] = useState<Fuse.FuseResult<Song>[]>([]);
const [showMobileMenu] = useMediaQuery("(max-width: 550px)");
const resultsBG = useColorModeValue("white", "gray.800");
const fuse = new Fuse(songs!, { keys: ["number", "title"] });
const headerBG = useColorModeValue("gray.100", "gray.800");
const searchBG = useColorModeValue("gray.50", "gray.700");

/** Will navigate one level up in the application */
const back = () => history.push("/");

const searchSongs = () => {
history.push(`/search?${query}`);
setQueryResults([]);
const submitQuery = (e: React.FormEvent<HTMLDivElement>) => {
e.preventDefault();
if (query.length > 0) searchSongs();
};

const searchSongs = (e?: React.ChangeEvent<any>, mobile?: boolean) => {
const shouldSearchMobile = mobile && mobileQuery.length > 0;
const shouldSearchDesktop = !mobile && query.length > 0;
if (shouldSearchMobile || shouldSearchDesktop) {
onClose();
history.push(`/search?query=${shouldSearchMobile ? mobileQuery : query}`);
setQueryResults([]);
}
};

const mobileSearchQueryChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const searchValue = e.target.value;
setMobileQuery(searchValue);
};

const searchQueryChange = (e: React.ChangeEvent<HTMLInputElement>) => {
Expand All @@ -64,7 +90,7 @@ function Header() {
};

return (
<Box className="page-header" p="4">
<Box className="page-header" p={4} bg={headerBG}>
<Grid templateColumns="max-content 1fr" alignItems="center" gap={10} justifyContent="space-between">
<Heading size="md" onClick={back} cursor="pointer" display="flex" alignItems="center" width="auto">
Hymns for All Times
Expand All @@ -76,17 +102,18 @@ function Header() {
icon={<FaBars />}
aria-label="Open mobile menu"
justifySelf="flex-end"
disabled
onClick={onModalOpen}
/>
) : (
<Grid templateColumns="minmax(auto, 300px) auto" gap={2} justifyContent="flex-end">
<InputGroup size="md">
<InputGroup size="md" as="form" onSubmit={submitQuery}>
<Input
value={query}
onChange={searchQueryChange}
type="text"
type="search"
placeholder="Search songs..."
pr="4.5rem"
bg={searchBG}
/>
<InputRightElement>
<IconButton
Expand All @@ -95,7 +122,6 @@ function Header() {
icon={<FaSearch />}
aria-label="Search Song Database"
onClick={searchSongs}
disabled
/>
</InputRightElement>
</InputGroup>
Expand All @@ -114,21 +140,26 @@ function Header() {
<Portal>
<Box
bg={resultsBG}
pos="absolute"
zIndex={105}
top={20}
right="65"
w={350}
pos="absolute"
px={5}
pb={5}
hidden={!isOpen}
shadow="md"
hidden={!isOpen || showMobileMenu}
borderRadius="md"
shadow="md"
>
<CloseButton size="md" onClick={onClose} pos="absolute" top="1" right="5" />
<Grid gap={5} mt={10} w="100%">
{queryResults.map(result => (
<Button bg="blue.500" onClick={() => gotoSong(result.item.number)} overflow="hidden">
<Button
bg="blue.500"
onClick={() => gotoSong(result.item.number)}
overflow="hidden"
key={result.item.number}
>
<Grid templateColumns="auto 1fr" gap="3" w="100%" justifyItems="left">
<Text size="sm" color="white">
{result.item.number}
Expand All @@ -143,6 +174,45 @@ function Header() {
</Box>
</Portal>
</Fade>

<Modal isOpen={isModalOpen} onClose={onModalClose}>
<ModalOverlay />
<ModalContent pb={10}>
<ModalHeader>Menu</ModalHeader>
<ModalCloseButton />
<ModalBody>
<VStack spacing="4">
<InputGroup size="md" as="form" onSubmit={e => searchSongs(e, true)}>
<Input
type="search"
value={mobileQuery}
onChange={mobileSearchQueryChange}
placeholder="Search songs..."
pr="4.5rem"
/>
<InputRightElement>
<IconButton
size="sm"
h="1.75rem"
icon={<FaSearch />}
aria-label="Search Song Database"
onClick={e => searchSongs(e, true)}
disabled
/>
</InputRightElement>
</InputGroup>

<Button
leftIcon={colorMode === "light" ? <FaMoon /> : <FaSun />}
onClick={toggleColorMode}
w="100%"
>
Toggle {colorMode === "light" ? "Dark" : "Light"} Mode
</Button>
</VStack>
</ModalBody>
</ModalContent>
</Modal>
</Box>
);
}
Expand Down
4 changes: 2 additions & 2 deletions src/components/SongDisplay/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ function SongDisplay() {
const { songs, dispatch } = useContext(MainContext);
const { songID } = useParams<ParamTypes>();
const authorColor = useColorModeValue("#555555", "gray.300");
const songBG = useColorModeValue("white", "inherit");
const songBG = useColorModeValue("gray.100", "inherit");
const songShadow = useColorModeValue("md", undefined);
const songIndex = parseInt(songID || "1") - 1;
const songToRender = songs!.find(song => song.number === songIndex + 1);
Expand Down Expand Up @@ -61,7 +61,7 @@ function SongDisplay() {
<Helmet>
<title>{`Hymns | ${songToRender!.title}`}</title>
</Helmet>
<Button onClick={backToIndex} pos="fixed" left={-5} top="18%" zIndex={100}>
<Button onClick={backToIndex} pos="fixed" left={-5} top="14%" zIndex={100}>
Index
</Button>
<Box className="header">
Expand Down
5 changes: 0 additions & 5 deletions src/components/SongList/SongList.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@
grid-template-columns: repeat(2, minmax(60px, 1fr));
}

.list-wrapper {
position: relative;
overflow: hidden;
}

.listItem {
align-items: center;
// background-color: #fff;
Expand Down
8 changes: 4 additions & 4 deletions src/components/SongList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,12 @@ function SongList() {
const numColumns = useRef(dualColumns ? 2 : 1);
const numRows = useRef(0);

if (numColumns.current === 2) numRows.current = finalList.length / 2;
if (numColumns.current === 2) numRows.current = Math.ceil(finalList.length / 2);
else numRows.current = finalList.length;

/** Handles Filter Drawer display */
const { isOpen, onOpen, onToggle } = useDisclosure();
const modalBG = useColorModeValue("white", "gray.800");
const modalBG = useColorModeValue("gray.100", "gray.800");
const modalColors = useColorModeValue("gray.800", "gray.100");

/** Triggers navigation to a song at a specified index */
Expand Down Expand Up @@ -248,7 +248,7 @@ function SongList() {
/** Renders a single cell */
const Cell = ({ columnIndex, rowIndex, style, data }: GridChildComponentProps) => {
const itemIndex = rowIndex * numColumns.current + columnIndex;

if (itemIndex >= finalList.length) return null;
return (
<Box
key={data[itemIndex].number}
Expand Down Expand Up @@ -410,7 +410,7 @@ function SongList() {
</VStack>
</Slide>

<Box className="list-wrapper" ref={wrapperRef}>
<Box ref={wrapperRef} pos="relative" overflow="hidden">
<AutoSizer>
{({ height, width }) => (
<FixedSizeGrid
Expand Down
5 changes: 5 additions & 0 deletions src/helpers/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { Suspense } from "react";
import { SongsDB, version } from "data/songs";
import { useLocation } from "react-router";
import localForage from "localforage";
import { Loader } from "components";

Expand Down Expand Up @@ -76,3 +77,7 @@ export async function checkDB() {
loadNewSongs();
}
}

export function useQuery() {
return new URLSearchParams(useLocation().search);
}
5 changes: 2 additions & 3 deletions src/pages/Home/Home.scss
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
.card {
align-content: space-between;
display: grid;
grid-template-rows: auto 1fr auto;
grid-template-rows: auto 300px auto;
width: 100%;
height: 100%;
min-width: 300px;
min-width: 250px;
max-width: 380px;
}

Expand Down
5 changes: 3 additions & 2 deletions src/pages/Home/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ function HomeScreen() {
</Helmet>
<Box bg={pageBG} h="100%">
<SimpleGrid
minChildWidth={{ base: "300px", sm: "380px" }}
spacing="30px"
minChildWidth={{ base: "260px", sm: "380px" }}
spacingX="30px"
spacingY="15px"
className="grid"
maxWidth={{ md: "800px" }}
>
Expand Down
24 changes: 24 additions & 0 deletions src/pages/Search/Search.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.searchContainer {
display: grid;
grid-template-rows: minmax(450px, 100%);
height: 100%;
justify-items: stretch;
overflow-y: hidden;
}

.gridItemWrapper {
align-items: center;
// border-bottom: 1px solid rgba(0, 0, 0, 0.12);
// border-right: 1px solid rgba(0, 0, 0, 0.12);
cursor: pointer;
text-align: left;
user-select: none;
}

.gridItem {
transition: transform 0.1s ease-in-out;
will-change: transform;
&:hover {
transform: translateY(-2px);
}
}
Loading

0 comments on commit df6efa4

Please sign in to comment.