Initial commit
This commit is contained in:
38
src/components/App/App.css
Normal file
38
src/components/App/App.css
Normal file
@@ -0,0 +1,38 @@
|
||||
.App {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.App-logo {
|
||||
height: 40vmin;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.App-logo {
|
||||
animation: App-logo-spin infinite 20s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.App-header {
|
||||
background-color: #282c34;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: calc(10px + 2vmin);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.App-link {
|
||||
color: #61dafb;
|
||||
size: 1em;
|
||||
}
|
||||
|
||||
@keyframes App-logo-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
9
src/components/App/App.test.tsx
Normal file
9
src/components/App/App.test.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import App from './App';
|
||||
|
||||
test('renders learn react link', () => {
|
||||
const { getByText } = render(<App />);
|
||||
const linkElement = getByText(/learn react/i);
|
||||
expect(linkElement).toBeInTheDocument();
|
||||
});
|
||||
24
src/components/App/App.tsx
Normal file
24
src/components/App/App.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import React from "react";
|
||||
import { IconSearch, IconGrid } from "../";
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<div>
|
||||
<header>
|
||||
Phosphor Icons{" "}
|
||||
<a
|
||||
// className="App-link"
|
||||
href="https://play.google.com/store/apps/details?id=com.tobiasfried.phosphor"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
on the play store
|
||||
</a>
|
||||
</header>
|
||||
<IconSearch />
|
||||
<IconGrid />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
16
src/components/IconGrid/IconGrid.css
Normal file
16
src/components/IconGrid/IconGrid.css
Normal file
@@ -0,0 +1,16 @@
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
|
||||
}
|
||||
|
||||
.grid-item {
|
||||
margin: 4px;
|
||||
background-color: aquamarine;
|
||||
filter: grayscale(100%);
|
||||
transition: 0.5s ease;
|
||||
}
|
||||
|
||||
.grid-item:hover {
|
||||
filter: grayscale(0%);
|
||||
transition: 0.5s ease;
|
||||
}
|
||||
28
src/components/IconGrid/IconGrid.tsx
Normal file
28
src/components/IconGrid/IconGrid.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import React from "react";
|
||||
import { useRecoilValue } from "recoil";
|
||||
|
||||
import { filteredQueryResultsSelector } from "../../state/selectors";
|
||||
import "./IconGrid.css";
|
||||
|
||||
type IconGridProps = {};
|
||||
|
||||
const IconGrid: React.FC<IconGridProps> = () => {
|
||||
const filteredQueryResults = useRecoilValue(filteredQueryResultsSelector);
|
||||
|
||||
return (
|
||||
<div className="grid">
|
||||
{filteredQueryResults.map((icon) => (
|
||||
<div key={`${icon.name}-${icon.style.type.toString()}`} className="grid-item">
|
||||
<img
|
||||
src="https://i.imgur.com/zaO12Y8m.jpeg"
|
||||
alt={`${icon.name} icon`}
|
||||
width="100%"
|
||||
/>
|
||||
<div style={{ padding: 16 }}>{icon.name}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default IconGrid;
|
||||
34
src/components/IconSearch/IconSearch.tsx
Normal file
34
src/components/IconSearch/IconSearch.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import React from "react";
|
||||
import { useRecoilState } from "recoil";
|
||||
|
||||
import { searchQueryAtom, styleQueryAtom } from "../../state/atoms";
|
||||
import { IconFillStyle } from "../../lib/Icon";
|
||||
|
||||
type IconSearchProps = {};
|
||||
|
||||
const IconSearch: React.FC<IconSearchProps> = () => {
|
||||
const [query, setQuery] = useRecoilState(searchQueryAtom);
|
||||
const [style, setStyle] = useRecoilState(styleQueryAtom);
|
||||
|
||||
const handleSearchChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setQuery(event.target.value);
|
||||
};
|
||||
|
||||
const handleStyleChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
setStyle(event.target.value as IconFillStyle);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<input value={query} onChange={handleSearchChange} />
|
||||
<select value={style?.toString()} onChange={handleStyleChange}>
|
||||
<option value={""}>All</option>
|
||||
<option value={IconFillStyle.LINE}>Line</option>
|
||||
<option value={IconFillStyle.FILL}>Fill</option>
|
||||
<option value={IconFillStyle.DUOTONE}>Duotone</option>
|
||||
</select>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default IconSearch;
|
||||
3
src/components/index.ts
Normal file
3
src/components/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export { default as App } from "./App/App";
|
||||
export { default as IconGrid } from "./IconGrid/IconGrid";
|
||||
export { default as IconSearch } from "./IconSearch/IconSearch";
|
||||
Reference in New Issue
Block a user