Feature/site detail page (#99)

* site: pull data from "icons" dir

* site: display icons

* site: remove redundant code

* site: colour mode support

* site: header

* site: order imports

* site: search

* site: add toast when copying icon

* site: styling

* site: hero

* fix: disable theme toggle transitions

* feat: Use Yarn Workspaces

* refactor: Update site deploy scripts

* refactor: Remove dark mode for now

* feat: Add site title

* refactor: Fix warning and format

* feat: Add dark mode back 👀

* feat: Escape key to reset query

* Fix by aelfric

* Add Github link

* Fix #40

* Add site overlay

* sort categories

* Add detail page

* Add first categories

* add box

* move site to root directory

* fix merge issues

* Fix routing issues

* Fix icon overlay

* Add copy and download icon

* Fix style issues

* Add text

* update chakra UI

* remove import

* update dependecies

* add lucide react

* Fix bugs

* delete stats files

* update charkra version

Co-authored-by: John Letey <johnletey@gmail.com>
Co-authored-by: appmachine <appmachine@appmachines-iMac.local>
This commit is contained in:
Eric Fennis
2020-10-26 08:59:56 +01:00
committed by GitHub
parent 2c38fac9b1
commit 5c96b8d848
22 changed files with 1227 additions and 712 deletions

View File

@@ -1,4 +1,4 @@
{
module.exports = {
"env": {
"browser": true,
"node": true

19
categories.json Normal file
View File

@@ -0,0 +1,19 @@
{
"arrows": [],
"brands": [],
"code": [],
"connectivity": ["airplay"],
"cursors": [],
"development": [],
"devices": ["alarm-clock"],
"file-system": [],
"layout": [],
"maths": ["activity"],
"multimedia": [],
"notifications": ["alert-circle", "alert-octagon", "alert-triangle"],
"nature": [],
"shopping": [],
"shapes": [],
"sports": [],
"text-edit": ["align-center","align-right","align-left","align-justify" ]
}

View File

@@ -1,3 +0,0 @@
{
"presets": ["next/babel"]
}

4
site/.eslintrc.js Normal file
View File

@@ -0,0 +1,4 @@
const { builtinModules } = require('module')
const rootConfig = require('../.eslintrc.js')
module.exports = rootConfig;

3
site/babel.config.js Normal file
View File

@@ -0,0 +1,3 @@
module.exports = {
presets: ['next/babel'],
};

View File

@@ -2,6 +2,6 @@ module.exports = {
testPathIgnorePatterns: ['<rootDir>/.next/', '<rootDir>/node_modules/'],
setupFilesAfterEnv: ['<rootDir>/setupTests.js'],
transform: {
'^.+\\.(js|jsx|ts|tsx)$': '<rootDir>/../../node_modules/babel-jest',
'^.+\\.(js|jsx|ts|tsx)$': '<rootDir>/node_modules/babel-jest',
},
};

View File

@@ -11,16 +11,17 @@
"test": "jest"
},
"dependencies": {
"@chakra-ui/core": "^0.8.0",
"@emotion/core": "^10.0.28",
"@emotion/styled": "^10.0.27",
"@chakra-ui/core": "next",
"downloadjs": "^1.4.7",
"emotion-theming": "^10.0.27",
"framer-motion": "^2.9.4",
"fuse.js": "^6.0.4",
"jszip": "^3.4.0",
"lodash": "^4.17.20",
"lucide-react": "^0.1.2-beta.1",
"next": "^9.5.4",
"react": "^16.13.1",
"react-dom": "^16.13.1"
"react-dom": "^16.13.1",
"react-spring": "^8.0.27"
},
"devDependencies": {
"@testing-library/dom": "^7.24.4",

View File

@@ -0,0 +1,19 @@
.icon-large svg {
width: 100%;
height: 100%;
position: relative;
z-index: 1;
}
.icon-grid {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
body {
min-height: 100%;
padding-bottom: 80px;
}

View File

@@ -0,0 +1,62 @@
import {
Button,
Flex,
Stack,
Text,
Link,
} from "@chakra-ui/core";
import download from "downloadjs";
import JSZip from "jszip";
import { Download, GitHub } from 'lucide-react';
import theme from "../lib/theme";
function generateZip(icons) {
const zip = new JSZip();
Object.values(icons).forEach((icon) =>
// @ts-ignore
zip.file(`${icon.name}.svg`, icon.src)
);
return zip.generateAsync({ type: 'blob' });
}
const Header = ({ data }) => {
const downloadAllIcons = async () => {
const zip = await generateZip(data);
download(zip, 'feather.zip');
};
const repositoryUrl = 'https://github.com/lucide-icons/lucide';
return (
<Flex direction="column" align="center" justify="center">
<Text fontSize="3xl" as="b" mb="4" textAlign="center">
Simply beautiful open source icons, community-sourced
</Text>
<Text fontSize="lg" as="p" textAlign="center" mb="8">
An open-source icon library, a fork of <Link href="https://github.com/feathericons/feather" isExternal>Feather Icons</Link>. <br/>We're expanding the icon set as much as possible while keeping it nice-looking - <Link href={repositoryUrl} isExternal>join us</Link>!
</Text>
<Stack isInline marginTop={3} marginBottom={10}>
<Button
leftIcon={<Download/>}
size="lg"
onClick={downloadAllIcons}
>
Download all
</Button>
<Button
as="a"
leftIcon={<GitHub/>}
size="lg"
href={repositoryUrl}
target="__blank"
onClick={downloadAllIcons}
>
Github
</Button>
</Stack>
</Flex>
)
};
export default Header;

View File

@@ -0,0 +1,192 @@
import { useSpring, animated } from "react-spring";
import { Box, Text, IconButton, useColorMode, Flex, ButtonGroup, Button, useToast } from "@chakra-ui/core";
import theme from "../lib/theme";
import download from 'downloadjs';
import copy from "copy-to-clipboard";
import { X as Close } from 'lucide-react';
const IconDetailOverlay = ({ isOpen = true, onClose, icon }) => {
const toast = useToast();
const { colorMode } = useColorMode();
const { tags = [], name } = icon;
const { transform, opacity } = useSpring({
opacity: isOpen ? 1 : 0,
transform: `translateY(${isOpen ? -120 : 0}%)`,
config: { mass: 5, tension: 500, friction: 80 },
});
const handleClose = () => {
onClose();
};
const panelStyling = {
transform: transform.interpolate(t => t),
opacity: opacity.interpolate(o => o),
width: "100%",
willChange: "transform"
}
const iconStyling = (isLight) => ({
height: "25vw",
width: "25vw",
minHeight: "160px",
minWidth: "160px",
maxHeight: "240px",
maxWidth: "240px",
color: (isLight ? theme.colors.gray[800] : theme.colors.white),
});
const downloadIcon = ({src, name}) => download(src, `${name}.svg`, 'image/svg+xml');
const copyIcon = ({src, name}) => {
copy(src);
toast({
title: "Copied!",
description: `Icon "${name}" copied to clipboard.`,
status: "success",
duration: 1500,
});
}
const donwloadPNG = ({src, name}) => {
const canvas = document.createElement('canvas');
canvas.width = 24;
canvas.height = 24;
const ctx = canvas.getContext("2d");
const image = new Image();
image.src = `data:image/svg+xml;base64,${btoa(src)}`;
image.onload = function() {
ctx.drawImage(image, 0, 0);
const link = document.createElement('a');
link.download = `${name}.png`;
link.href = canvas.toDataURL('image/png')
link.click();
}
}
return (
<Box
position="fixed"
bottom={0}
zIndex={2}
width="100%"
left={0}
height={0}
key={name}
>
<Flex
alignItems="center"
justifyContent="space-between"
pt={4}
pb={4}
maxW="850px"
margin="0 auto"
w="full"
px={8}
>
<animated.div
style={panelStyling}
>
<Box
borderWidth="1px"
rounded="lg"
width="full"
boxShadow={theme.shadows.xl}
position="relative"
bg={
colorMode == "light"
? theme.colors.white
: theme.colors.gray[700]
}
padding={8}
>
<IconButton
size="sm"
aria-label="Close overlay"
variant="ghost"
color="current"
ml="3"
position="absolute"
top={4}
right={4}
onClick={handleClose}
icon={<Close />}
/>
<Flex direction={['column', 'row']} alignItems={['center', 'flex-start']}>
<Flex>
<Box
borderWidth="1px"
rounded="md"
position="relative"
bg={
colorMode == "light"
? theme.colors.whiteAlpha[800]
: theme.colors.blackAlpha[500]
}
padding={0}
>
<div
dangerouslySetInnerHTML={{ __html: icon.src }}
style={iconStyling(colorMode == "light")}
className="icon-large"
/>
<svg className="icon-grid" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke={colorMode == "light" ? '#E2E8F0' : theme.colors.gray[600]} strokeWidth="0.1" xmlns="http://www.w3.org/2000/svg">
{ Array.from({ length:23 }, (_, i) => (
<g key={`grid-${i}`}>
<line key={`horizontal-${i}`} x1={0} y1={i + 1} x2={24} y2={i + 1} />
<line key={`vertical-${i}`} x1={i + 1} y1={0} x2={i + 1} y2={24} />
</g>
)) }
</svg>
</Box>
</Flex>
<Flex marginLeft={[0, 8]}>
<Box>
<Text fontSize="3xl" style={{ cursor: "pointer" }} mb={1}>
{icon.name}
</Text>
<Box mb={4}>
{ tags?.length ? (
<Text
fontSize="xl"
fontWeight="bold"
color={
colorMode === "light"
? 'gray.600'
: 'gray.500'
}
>
{ tags.join(' • ') }
</Text>
) : ''}
{/* <Button size="sm" fontSize="md" variant="ghost" onClick={() => downloadIcon(icon)}>
Edit Tags
</Button> */}
</Box>
<ButtonGroup spacing={4}>
<Button variant="solid" onClick={() => downloadIcon(icon)} mb={1}>
Download SVG
</Button>
<Button variant="solid" onClick={() => copyIcon(icon)} mb={1}>
Copy SVG
</Button>
<Button variant="solid" onClick={() => donwloadPNG(icon)} mb={1}>
Download PNG
</Button>
</ButtonGroup>
</Box>
</Flex>
</Flex>
</Box>
</animated.div>
</Flex>
</Box>
);
};
export default IconDetailOverlay;

View File

@@ -0,0 +1,60 @@
import { Button, Flex, Grid, Text, useToast } from "@chakra-ui/core";
import download from 'downloadjs';
import Link from 'next/link'
import copy from "copy-to-clipboard";
const IconList = ({icons}) => {
const toast = useToast();
return (
<Grid
templateColumns={`repeat(auto-fill, minmax(160px, 1fr))`}
gap={5}
marginBottom="320px"
>
{ icons.map((icon) => {
// @ts-ignore
const actualIcon = icon.item ? icon.item : icon;
const { name, src } = actualIcon;
return (
<Link key={name} href={`/?iconName=${name}`} as={`/icon/${name}`} scroll={false}>
<Button
variant="ghost"
borderWidth="1px"
rounded="lg"
padding={16}
onClick={(event) => {
if (event.shiftKey) {
copy(actualIcon.src);
toast({
title: "Copied!",
description: `Icon "${name}" copied to clipboard.`,
status: "success",
duration: 1500,
});
}
if (event.metaKey) {
download(
actualIcon.src,
`${name}.svg`,
"image/svg+xml"
);
}
}}
key={name}
alignItems="center"
>
<Flex direction="column" align="center" justify="center">
<div dangerouslySetInnerHTML={{ __html: src }} />
<Text marginTop={5}>{name}</Text>
</Flex>
</Button>
</Link>
);
})}
</Grid>
);
}
export default IconList;

View File

@@ -0,0 +1,82 @@
import { Box, Input, InputGroup, InputLeftElement, Text, useColorMode, Icon } from "@chakra-ui/core";
import IconList from "./IconList";
import { useEffect, useRef, useState } from "react";
import useSearch from "../lib/search";
import { useRouter } from 'next/router';
import { useDebounce } from '../lib/useDebounce';
import theme from "../lib/theme";
import { Search as SearchIcon } from 'lucide-react';
const IconOverview = ({data}) => {
const router = useRouter();
const { query } = router.query;
const [queryText, setQueryText] = useState(query || '');
const debouncedQuery = useDebounce(queryText, 1000);
const results = useSearch(data, queryText);
const { colorMode } = useColorMode();
const inputElement = useRef(null);
function handleKeyDown(event) {
if (event.key === "/" && inputElement.current !== document.activeElement) {
event.preventDefault();
inputElement.current.focus();
}
}
useEffect(() => {
setQueryText(query || '');
}, [query]);
useEffect(() => {
const { query } = router;
router.push({
query: {
...query,
query: debouncedQuery
},
});
}, [debouncedQuery]);
useEffect(() => {
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, []);
return (
<>
<InputGroup position="sticky" top={4} zIndex={1} bg={
colorMode == "light"
? theme.colors.white
: theme.colors.gray[700]
}>
<InputLeftElement children={(<Icon><SearchIcon /></Icon>)} />
<Input
ref={inputElement}
placeholder={`Search ${Object.keys(data).length} icons (Press "/" to focus)`}
value={queryText}
onChange={(event) => setQueryText(event.target.value)}
/>
</InputGroup>
<Box marginTop={5}>
{results.length > 0 ? (
<IconList icons={results} />
) : (
<Text
fontSize="2xl"
fontWeight="bold"
textAlign="center"
style={{ wordBreak: "break-word" }}
>
No results found for "{query}"
</Text>
)}
</Box>
</>
);
}
export default IconOverview;

View File

@@ -1,10 +1,13 @@
import { Box, Divider, Flex, Text, Link, Icon, useColorMode } from "@chakra-ui/core";
import { Box, Divider, Flex, Text, Link, Icon, useColorMode, useColorModeValue, IconButton } from "@chakra-ui/core";
import { useKeyBindings } from "../lib/key";
import {useRouter} from "next/router";
import { useRouter } from "next/router";
import { Moon, Sun } from 'lucide-react';
const Layout = ({ children }) => {
const router = useRouter();
const { colorMode, toggleColorMode } = useColorMode();
const text = useColorModeValue('dark', 'light')
const ColorModeToggle = useColorModeValue(Moon, Sun);
function setQuery(query){
router.push({
@@ -12,6 +15,7 @@ const Layout = ({ children }) => {
query: { query: query }
}).then();
}
useKeyBindings({
Escape: {
fn: () => setQuery(""),
@@ -47,15 +51,22 @@ const Layout = ({ children }) => {
<Link href="https://github.com/lucide-icons/lucide" isExternal style={{ fontSize: "18px", marginRight: '24px' }}>
Github
</Link>
<div onClick={toggleColorMode} style={{ cursor: "pointer" }}>
<Icon name={colorMode == "light" ? "moon" : "sun"} size="24px" />
</div>
<IconButton
size="md"
fontSize="lg"
aria-label={`Switch to ${text} mode`}
variant="ghost"
color="current"
ml="3"
onClick={toggleColorMode}
icon={<ColorModeToggle />}
/>
</Flex>
</Flex>
</Flex>
<Flex margin="0 auto" direction="column" maxW="1250px" px={8}>
{children}
<Divider marginTop={10} marginBottom={10} />
<Divider marginTop={4} marginBottom={8} />
</Flex>
</Box>
);

View File

@@ -4,70 +4,7 @@ const theme = {
...chakraTheme,
fonts: {
...chakraTheme.fonts,
body: `Jost,-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"`,
},
icons: {
...chakraTheme.icons,
sun: {
path: (
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<circle cx="12" cy="12" r="5" />
<line x1="12" y1="1" x2="12" y2="3" />
<line x1="12" y1="21" x2="12" y2="23" />
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64" />
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78" />
<line x1="1" y1="12" x2="3" y2="12" />
<line x1="21" y1="12" x2="23" y2="12" />
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36" />
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22" />
</svg>
),
},
moon: {
path: (
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" />
</svg>
),
},
search: {
path: (
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<circle cx="11" cy="11" r="8" />
<line x1="21" y1="21" x2="16.65" y2="16.65" />
</svg>
),
},
body: `'Mukta', sans-serif`,
},
};

View File

@@ -1,5 +1,6 @@
import { CSSReset, ThemeProvider, ColorModeProvider } from '@chakra-ui/core';
import { CSSReset, ChakraProvider, ColorModeProvider } from '@chakra-ui/core';
import customTheme from '../lib/theme';
import '../assets/styling.css';
import Head from 'next/head';
const App = ({ Component, pageProps }) => {
@@ -8,12 +9,9 @@ const App = ({ Component, pageProps }) => {
<Head>
<title>Lucide</title>
</Head>
<ThemeProvider theme={customTheme}>
<ColorModeProvider>
<CSSReset />
<Component {...pageProps} />
</ColorModeProvider>
</ThemeProvider>
<ChakraProvider theme={customTheme}>
<Component {...pageProps} />
</ChakraProvider>
</>
);
};

View File

@@ -1,4 +1,5 @@
import Document, { Head, Html, Main, NextScript } from "next/document";
import { ColorModeScript } from "@chakra-ui/core"
class MyDocument extends Document {
render() {
@@ -6,7 +7,7 @@ class MyDocument extends Document {
<Html>
<Head>
<link
href="https://indestructibletype.com/fonts/Jost.css"
href="https://fonts.googleapis.com/css2?family=Mukta:wght@400;600;700&display=swap"
rel="stylesheet"
/>
</Head>
@@ -20,6 +21,7 @@ class MyDocument extends Document {
}
`}</style>
<body>
<ColorModeScript />
<Main />
<NextScript />
</body>

View File

@@ -0,0 +1,39 @@
import { useEffect } from 'react'
import { useRouter } from 'next/router'
import IconDetailOverlay from '../../components/IconDetailOverlay'
import { getAllData, getData } from '../../lib/icons';
import IconOverview from '../../components/IconOverview';
import Layout from '../../components/Layout';
import Header from '../../components/Header';
const IconPage = ({ icon, data }) => {
const router = useRouter()
return (
<Layout>
<IconDetailOverlay
icon={icon}
onClose={() => router.push('/')}
/>
<Header {...{data}}/>
<IconOverview {...{data}}/>
</Layout>
)
}
export default IconPage
export function getStaticProps({ params: { iconName } }) {
const data = getAllData();
const icon = getData(iconName);
return { props: { icon, data } }
}
export function getStaticPaths() {
return {
paths: getAllData().map(({name: iconName }) => ({
params: { iconName },
})),
fallback: false,
}
}

View File

@@ -1,148 +1,31 @@
import {
Button,
Flex,
Grid,
Link,
Icon,
Input,
InputGroup,
InputLeftElement,
Stack,
Text,
useToast,
} from '@chakra-ui/core';
import copy from 'copy-to-clipboard';
import download from 'downloadjs';
import JSZip from 'jszip';
import { useEffect, useRef, useState } from 'react';
import Layout from '../components/Layout';
import { getAllData } from '../lib/icons';
import useSearch from '../lib/search';
import { useRouter } from 'next/router';
import { useDebounce } from '../lib/useDebounce';
import Layout from "../components/Layout";
import { getAllData } from "../lib/icons";
function generateZip(icons) {
const zip = new JSZip();
Object.values(icons).forEach((icon) =>
// @ts-ignore
zip.file(`${icon.name}.svg`, icon.src)
);
return zip.generateAsync({ type: 'blob' });
}
import IconOverview from "../components/IconOverview";
import IconDetailOverlay from "../components/IconDetailOverlay";
import { useRouter } from "next/router";
import Header from "../components/Header";
const IndexPage = ({ data }) => {
const router = useRouter();
const { query } = router.query;
const [queryText, setQueryText] = useState(query || '');
const toast = useToast();
const debouncedQuery = useDebounce(queryText, 1000);
const results = useSearch(data, queryText);
useEffect(() => {
setQueryText(query);
}, [query]);
useEffect(() => {
router.push({
pathname: '/',
query: { query: debouncedQuery },
});
}, [debouncedQuery]);
const inputElement = useRef(null);
function handleKeyDown(event) {
if (event.key === '/' && inputElement.current !== document.activeElement) {
event.preventDefault();
inputElement.current.focus();
}
}
useEffect(() => {
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, []);
const getIcon = (iconName) => data.find(({name}) => name === iconName) || {};
return (
<Layout>
<Flex direction="column" align="center" justify="center">
<Text fontSize="3xl" as="b" mb="4">
Simply beautiful open source icons, community-sourced
</Text>
<Text fontSize="lg" as="p" textAlign="center" mb="8">
An open-source icon library, a fork of Feather Icons. <br/>We're expanding the icon set as much as possible while keeping it nice-looking - <Link href="https://github.com/lucide-icons/lucide" isExternal>join us</Link>!
</Text>
<Stack isInline marginTop={3} marginBottom={10}>
<Button
onClick={async () => {
const zip = await generateZip(data);
download(zip, 'feather.zip');
}}
>
Download all
</Button>
</Stack>
</Flex>
<InputGroup position="sticky" top={2} zIndex={1}>
<InputLeftElement children={<Icon name="search" />} />
<Input
ref={inputElement}
placeholder={`Search ${Object.keys(data).length} icons (Press "/" to focus)`}
value={queryText}
onChange={(event) => setQueryText(event.target.value)}
marginBottom={5}
/>
</InputGroup>
{results.length > 0 ? (
<Grid templateColumns={`repeat(auto-fill, minmax(160px, 1fr))`} gap={5}>
{results.map((icon) => {
// @ts-ignore
const actualIcon = icon.item ? icon.item : icon;
return (
<Button
variant="ghost"
borderWidth="1px"
rounded="lg"
padding={16}
onClick={(event) => {
if (event.shiftKey) {
copy(actualIcon.src);
toast({
title: 'Copied!',
description: `Icon "${actualIcon.name}" copied to clipboard.`,
status: 'success',
duration: 1500,
});
} else {
download(actualIcon.src, `${actualIcon.name}.svg`, 'image/svg+xml');
}
}}
key={actualIcon.name}
alignItems="center"
>
<Flex direction="column" align="center" justify="center">
<div dangerouslySetInnerHTML={{ __html: actualIcon.src }} />
<Text marginTop={5}>{actualIcon.name}</Text>
</Flex>
</Button>
);
})}
</Grid>
) : (
<Text
fontSize="2xl"
fontWeight="bold"
textAlign="center"
style={{ wordBreak: 'break-word' }}
>
No results found for "{query}"
</Text>
)}
<IconDetailOverlay
isOpen={!!router.query.iconName}
icon={getIcon(router.query.iconName)}
onClose={() => router.push('/')}
/>
<Header {...{data}}/>
<IconOverview {...{data}}/>
</Layout>
);
};
export async function getStaticProps() {
let data = getAllData();
return {
props: {
data,

View File

@@ -0,0 +1,18 @@
import { getAllData } from '../lib/icons';
import { renderHook } from '@testing-library/react-hooks';
import useSearch from '../lib/search';
describe('Icon Overview', () => {
it('can search filter icons', async () => {
let allData = getAllData();
const { result: result1, waitForNextUpdate: wait1 } = renderHook(() => useSearch(allData, ''));
expect(result1.current).toHaveLength(allData.length);
const { result: result2, waitForNextUpdate: wait2 } = renderHook(() =>
useSearch(allData, 'airplay')
);
await wait2();
expect(result2.current).toHaveLength(2);
});
});

View File

@@ -3,9 +3,8 @@ import Index from '../pages/index';
import React from 'react';
import { render } from './test-utils';
import { getAllData } from '../lib/icons';
import App from '../pages/_app';
import { renderHook } from '@testing-library/react-hooks';
import useSearch from '../lib/search';
describe('App', () => {
it('renders without crashing', () => {
@@ -15,16 +14,4 @@ describe('App', () => {
screen.getByText('Simply beautiful open source icons, community-sourced')
).toBeInTheDocument();
});
it('can search filter icons', async () => {
let allData = getAllData();
const { result: result1, waitForNextUpdate: wait1 } = renderHook(() => useSearch(allData, ''));
expect(result1.current).toHaveLength(allData.length);
const { result: result2, waitForNextUpdate: wait2 } = renderHook(() =>
useSearch(allData, 'airplay')
);
await wait2();
expect(result2.current).toHaveLength(2);
});
});

File diff suppressed because it is too large Load Diff

233
yarn.lock

File diff suppressed because it is too large Load Diff