Massive interactivity updates to all components
This commit is contained in:
76
README.md
76
README.md
@@ -1,44 +1,64 @@
|
|||||||
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
|
# Phosphor Icons
|
||||||
|
|
||||||
## Available Scripts
|
Phosphor is a kickass and dead-simple set of open-source icons for web and digital media. We aim to provide variety, consistency, and above all, ease-of-use for digital content creators of all kinds.
|
||||||
|
|
||||||
In the project directory, you can run:
|
## For developers
|
||||||
|
|
||||||
### `yarn start`
|
Phosphor is available as an icon font and a React package, which can be sourced from NPM or from a CDN.
|
||||||
|
|
||||||
Runs the app in the development mode.<br />
|
### Vanilla JS
|
||||||
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
|
|
||||||
|
|
||||||
The page will reload if you make edits.<br />
|
- **This seems familiar...** – Using Phosphor in your web project might seem familiar. We use a similar approach as many other icon sets out there, providing icons as a webfont that uses Unicode's Private Use Area character codes to map normally non-rendering characters to icons. But you don't need to know that. All you need to do is source the stylesheet, and drop in an icon:
|
||||||
You will also see any lint errors in the console.
|
|
||||||
|
|
||||||
### `yarn test`
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script src="https://unpkg.com/phosphor-web@latest"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<i class="ph-smiley"></i>
|
||||||
|
<i class="ph-heart-fill" style="color: hotpink"></i>
|
||||||
|
<i class="ph-cube-duotone"></i>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
Launches the test runner in the interactive watch mode.<br />
|
- **Whatchacallit?** – We use a straightforward and semantic naming scheme that may mean only changing a few letters when switching from other icon sets. But don't switch on our account, there are some excellent sets out there!
|
||||||
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
|
- **That's it?** – Yep. That's it.
|
||||||
|
|
||||||
### `yarn build`
|
### React
|
||||||
|
|
||||||
Builds the app for production to the `build` folder.<br />
|
- **Flex or flow** – Phosphor's intuitive but powerful API can style the `color`, `size`, and `weight` of an icon with a few keystrokes, or directly manipulate the SVG at runtime through render props to do some amazing things! Check out some examples on [Github](https://github.com/rektdeckard/phosphor-react).
|
||||||
It correctly bundles React in production mode and optimizes the build for the best performance.
|
|
||||||
|
|
||||||
The build is minified and the filenames include the hashes.<br />
|
```jsx
|
||||||
Your app is ready to be deployed!
|
import React from "react";
|
||||||
|
import ReactDOM from "react-dom";
|
||||||
|
import { Smiley, Heart, Horse } from "phosphor-react";
|
||||||
|
|
||||||
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
|
const App = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Smiley />
|
||||||
|
<Heart size={32} color="hotpink" weight="fill" />
|
||||||
|
<Horse weight="duotone" />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
### `yarn eject`
|
ReactDOM.render(<App />, document.getElementById("root"));
|
||||||
|
```
|
||||||
|
|
||||||
**Note: this is a one-way operation. Once you `eject`, you can’t go back!**
|
- **Light as a Feather** – Supports tree-shaking, so your bundle only includes code for the icons you use.
|
||||||
|
- **Familiar** – Icon Components are a thin wrapper around SVG elements, so feel free to add your own inline `style` objects, `onClick` handler functions, and a multitude of other props you're used to using on React Elements.
|
||||||
|
|
||||||
If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
|
## For designers
|
||||||
|
|
||||||
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
|
### Raw Assets
|
||||||
|
- **SVGs** – Grab our individual icon SVGs, in both minified and original formats retaining design-time detail.
|
||||||
|
- **Icon Font** – Use the icons as you would text, in applications where full-fledged graphical elements are undesirable.
|
||||||
|
|
||||||
You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
|
### Source Files
|
||||||
|
- **Sketch**
|
||||||
## Learn More
|
- **Illustrator**
|
||||||
|
- **Figma**
|
||||||
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
|
|
||||||
|
|
||||||
To learn React, check out the [React documentation](https://reactjs.org/).
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
"react-dom": "^16.13.1",
|
"react-dom": "^16.13.1",
|
||||||
"react-list": "^0.8.15",
|
"react-list": "^0.8.15",
|
||||||
"react-scripts": "3.4.1",
|
"react-scripts": "3.4.1",
|
||||||
|
"react-use": "^15.3.2",
|
||||||
"react-virtual": "^2.2.1",
|
"react-virtual": "^2.2.1",
|
||||||
"react-virtualized": "^9.21.2",
|
"react-virtualized": "^9.21.2",
|
||||||
"recoil": "^0.0.10",
|
"recoil": "^0.0.10",
|
||||||
|
|||||||
@@ -17,11 +17,9 @@ const ColorInput: React.FC<ColorInputProps> = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="color-picker" hidden>
|
|
||||||
Icon Color
|
|
||||||
</label>
|
|
||||||
<input
|
<input
|
||||||
id="color-picker"
|
id="color-picker"
|
||||||
|
aria-label="Icon Color"
|
||||||
type="color"
|
type="color"
|
||||||
onChange={handleColorChange}
|
onChange={handleColorChange}
|
||||||
value={color}
|
value={color}
|
||||||
|
|||||||
@@ -10,9 +10,12 @@ const Header: React.FC<HeaderProps> = () => {
|
|||||||
<h1>Phosphor Icons</h1>
|
<h1>Phosphor Icons</h1>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ paddingRight: 32, textAlign: "end" }}>
|
<div style={{ paddingRight: 32, textAlign: "end" }}>
|
||||||
<button>Download All</button>
|
<button>Download all</button>
|
||||||
<button>Request</button>
|
<button>Request</button>
|
||||||
<button>Donate</button>
|
<button>Donate</button>
|
||||||
|
<a href="https://github.com/rektdeckard/phosphor-react">
|
||||||
|
<button>Github</button>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,21 +1,50 @@
|
|||||||
.grid {
|
.grid {
|
||||||
display: grid;
|
/* grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); */
|
||||||
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
|
|
||||||
|
/* display: grid; */
|
||||||
|
/* grid-template-columns: repeat(auto-fill, 160px);
|
||||||
|
grid-gap: 10px;
|
||||||
|
grid-auto-rows: minmax(160px, auto); */
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row wrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin: 16px;
|
||||||
|
|
||||||
/* min-height: 100vh; */
|
/* min-height: 100vh; */
|
||||||
}
|
}
|
||||||
|
|
||||||
.grid-item {
|
.grid-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
width: 160px;
|
||||||
|
height: 160px;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin: 4px;
|
margin: 4px;
|
||||||
border-radius: 8px;
|
border-radius: 16px;
|
||||||
background-color: white;
|
user-select: none;
|
||||||
/* transition: background-color 0.5s ease; */
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.grid-item:hover {
|
.grid-item:focus {
|
||||||
/* background-color: aquamarine; */
|
outline: none;
|
||||||
/* transition: background-color 0.5s ease; */
|
}
|
||||||
|
|
||||||
|
.info-box {
|
||||||
|
display: flex;
|
||||||
|
margin: 4px;
|
||||||
|
padding: 16px;
|
||||||
|
width: 100%;
|
||||||
|
height: 0px;
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 0 0 2px rgb(0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 24px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,46 +1,73 @@
|
|||||||
import React from "react";
|
import React, { useRef, useEffect } from "react";
|
||||||
import { useRecoilValue } from "recoil";
|
import { useRecoilValue } from "recoil";
|
||||||
import { motion } from "framer-motion";
|
import { motion, useAnimation } from "framer-motion";
|
||||||
|
import { useWindowSize } from "react-use";
|
||||||
|
|
||||||
import { filteredQueryResultsSelector } from "../../state/selectors";
|
import { filteredQueryResultsSelector } from "../../state/selectors";
|
||||||
import { iconColorAtom, iconSizeAtom, styleQueryAtom } from "../../state/atoms";
|
import {
|
||||||
|
iconColorAtom,
|
||||||
|
iconSizeAtom,
|
||||||
|
styleQueryAtom,
|
||||||
|
searchQueryAtom,
|
||||||
|
} from "../../state/atoms";
|
||||||
import "./IconGrid.css";
|
import "./IconGrid.css";
|
||||||
|
|
||||||
|
import GridItem from "./IconGridItem";
|
||||||
|
import { WarningTriangle, IconProps } from "phosphor-react";
|
||||||
|
|
||||||
type IconGridProps = {};
|
type IconGridProps = {};
|
||||||
|
|
||||||
// const variants = {
|
const IconGridAnimated: React.FC<IconGridProps> = () => {
|
||||||
// open: { opacity: 1, x: 0 },
|
|
||||||
// closed: { opacity: 0, x: "-100%" },
|
|
||||||
// }
|
|
||||||
|
|
||||||
const whileHover = {
|
|
||||||
boxShadow: "0 0 0 2px rgb(0, 0, 0)",
|
|
||||||
// scale: 1.2,
|
|
||||||
};
|
|
||||||
|
|
||||||
const transition = { duration: 0.2 };
|
|
||||||
|
|
||||||
const IconGrid: React.FC<IconGridProps> = () => {
|
|
||||||
const weight = useRecoilValue(styleQueryAtom);
|
const weight = useRecoilValue(styleQueryAtom);
|
||||||
const color = useRecoilValue(iconColorAtom);
|
const query = useRecoilValue(searchQueryAtom);
|
||||||
const size = useRecoilValue(iconSizeAtom);
|
const size = useRecoilValue(iconSizeAtom);
|
||||||
|
const color = useRecoilValue(iconColorAtom);
|
||||||
|
const iconProps: IconProps = { weight, color, size };
|
||||||
|
|
||||||
|
const { width } = useWindowSize();
|
||||||
|
const spans = Math.floor((width - 32) / 172);
|
||||||
|
|
||||||
const filteredQueryResults = useRecoilValue(filteredQueryResultsSelector);
|
const filteredQueryResults = useRecoilValue(filteredQueryResultsSelector);
|
||||||
|
|
||||||
|
const originOffset = useRef({ top: 0, left: 0 });
|
||||||
|
const controls = useAnimation();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
controls.start("visible");
|
||||||
|
}, [controls, filteredQueryResults]);
|
||||||
|
|
||||||
|
if (!filteredQueryResults.length)
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
className="empty-list"
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
transition={{ duration: 0.2 }}
|
||||||
|
>
|
||||||
|
<WarningTriangle size={92} color="darkmagenta" weight="duotone" />
|
||||||
|
<p>{`No results for '${query}'`}</p>
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<motion.div className="grid">
|
<motion.div
|
||||||
{filteredQueryResults.map(({ name, Icon }) => (
|
className="grid"
|
||||||
<motion.div
|
initial="hidden"
|
||||||
key={name}
|
animate={controls}
|
||||||
className="grid-item"
|
variants={{}}
|
||||||
whileHover={whileHover}
|
>
|
||||||
transition={transition}
|
{filteredQueryResults.map((iconEntry, i) => (
|
||||||
>
|
<GridItem
|
||||||
<Icon color={color} size={size} weight={weight} />
|
key={i}
|
||||||
<p>{name}</p>
|
index={i}
|
||||||
</motion.div>
|
spans={spans}
|
||||||
|
{...iconEntry}
|
||||||
|
{...iconProps}
|
||||||
|
originOffset={originOffset}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</motion.div>
|
</motion.div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default IconGrid;
|
export default IconGridAnimated;
|
||||||
|
|||||||
130
src/components/IconGrid/IconGridItem.tsx
Normal file
130
src/components/IconGrid/IconGridItem.tsx
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
import React, {
|
||||||
|
useRef,
|
||||||
|
useLayoutEffect,
|
||||||
|
useEffect,
|
||||||
|
MutableRefObject,
|
||||||
|
} from "react";
|
||||||
|
import { useRecoilState } from "recoil";
|
||||||
|
import { motion, AnimatePresence } from "framer-motion";
|
||||||
|
|
||||||
|
import { iconPreviewOpenAtom } from "../../state/atoms";
|
||||||
|
import { IconProps, Icon } from "phosphor-react";
|
||||||
|
|
||||||
|
interface IconGridItemProps extends IconProps {
|
||||||
|
index: number;
|
||||||
|
name: string;
|
||||||
|
Icon: Icon;
|
||||||
|
originOffset: MutableRefObject<{ top: number; left: number }>;
|
||||||
|
spans: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const itemVariants = {
|
||||||
|
hidden: { opacity: 0 },
|
||||||
|
visible: (delayRef: any) => ({
|
||||||
|
opacity: 1,
|
||||||
|
transition: { delay: delayRef.current },
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
const whileHover = { boxShadow: "0 0 0 2px rgb(0, 0, 0)" };
|
||||||
|
const whileTap = { boxShadow: "0 0 0 4px rgb(139, 0, 139)" };
|
||||||
|
const transition = { duration: 0.2 };
|
||||||
|
const originIndex = 0;
|
||||||
|
const delayPerPixel = 0.0004;
|
||||||
|
|
||||||
|
const infoVariants = {
|
||||||
|
open: { opacity: 1, height: 176, marginTop: 4, marginBottom: 4, padding: 16 },
|
||||||
|
collapsed: {
|
||||||
|
opacity: 0,
|
||||||
|
height: 0,
|
||||||
|
marginTop: 0,
|
||||||
|
marginBottom: 0,
|
||||||
|
padding: 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const IconGridItem: React.FC<IconGridItemProps> = (props) => {
|
||||||
|
const { index, spans, originOffset, name, Icon, ...iconProps } = props;
|
||||||
|
const [open, setOpen] = useRecoilState(iconPreviewOpenAtom);
|
||||||
|
const delayRef = useRef<number>(0);
|
||||||
|
const offset = useRef({ top: 0, left: 0 });
|
||||||
|
const ref = useRef<any>();
|
||||||
|
|
||||||
|
// The measurement for all elements happens in the layoutEffect cycle
|
||||||
|
// This ensures that when we calculate distance in the effect cycle
|
||||||
|
// all elements have already been measured
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
const element = ref.current;
|
||||||
|
if (!element) return;
|
||||||
|
|
||||||
|
offset.current = {
|
||||||
|
top: element.offsetTop,
|
||||||
|
left: element.offsetLeft,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (index === originIndex) {
|
||||||
|
originOffset.current = offset.current;
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const dx = Math.abs(offset.current.left - originOffset.current.left);
|
||||||
|
const dy = Math.abs(offset.current.top - originOffset.current.top);
|
||||||
|
const d = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
|
||||||
|
delayRef.current = d * delayPerPixel;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<motion.div
|
||||||
|
className="grid-item"
|
||||||
|
ref={ref}
|
||||||
|
style={{ order: index }}
|
||||||
|
custom={delayRef}
|
||||||
|
key={name}
|
||||||
|
whileHover={whileHover}
|
||||||
|
whileTap={whileTap}
|
||||||
|
transition={transition}
|
||||||
|
variants={itemVariants}
|
||||||
|
onClick={() =>
|
||||||
|
setOpen((openName) => (name === openName ? false : name))
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Icon {...iconProps} />
|
||||||
|
<p>{name}</p>
|
||||||
|
</motion.div>
|
||||||
|
<AnimatePresence initial={false}>
|
||||||
|
{open === name && <InfoPanel {...props} />}
|
||||||
|
</AnimatePresence>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const InfoPanel: React.FC<IconGridItemProps> = (props) => {
|
||||||
|
const { index, spans, name, Icon, color, weight } = props;
|
||||||
|
return (
|
||||||
|
<motion.section
|
||||||
|
className="info-box"
|
||||||
|
animate="open"
|
||||||
|
exit="collapsed"
|
||||||
|
variants={infoVariants}
|
||||||
|
style={{ order: index + (spans - (index % spans)) }}
|
||||||
|
>
|
||||||
|
<div style={{ height: "100%" }}>
|
||||||
|
<Icon color={color} weight={weight} size={128} />
|
||||||
|
<p>{name}</p>
|
||||||
|
</div>
|
||||||
|
<div style={{ flex: 1, padding: 32 }}>
|
||||||
|
HTML
|
||||||
|
<pre>{`<i class="ph-${name}${
|
||||||
|
weight === "regular" ? "" : `-${weight}`
|
||||||
|
}"></i>`}</pre>
|
||||||
|
React
|
||||||
|
<pre>{`<${Icon.displayName} ${
|
||||||
|
weight === "regular" ? "" : `weight="${weight}"`
|
||||||
|
}/>`}</pre>
|
||||||
|
</div>
|
||||||
|
</motion.section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default IconGridItem;
|
||||||
46
src/components/IconGrid/IconGridStatic.tsx
Normal file
46
src/components/IconGrid/IconGridStatic.tsx
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { useRecoilValue } from "recoil";
|
||||||
|
import { motion } from "framer-motion";
|
||||||
|
|
||||||
|
import { filteredQueryResultsSelector } from "../../state/selectors";
|
||||||
|
import { iconColorAtom, iconSizeAtom, styleQueryAtom } from "../../state/atoms";
|
||||||
|
import "./IconGrid.css";
|
||||||
|
|
||||||
|
type IconGridProps = {};
|
||||||
|
|
||||||
|
// const variants = {
|
||||||
|
// open: { opacity: 1, x: 0 },
|
||||||
|
// closed: { opacity: 0, x: "-100%" },
|
||||||
|
// }
|
||||||
|
|
||||||
|
const whileHover = { boxShadow: "0 0 0 2px rgb(0, 0, 0)" };
|
||||||
|
const whileTap = { boxShadow: "0 0 0 4px rgb(139, 0, 139)" }
|
||||||
|
|
||||||
|
const transition = { duration: 0.2 };
|
||||||
|
|
||||||
|
const IconGrid: React.FC<IconGridProps> = () => {
|
||||||
|
const weight = useRecoilValue(styleQueryAtom);
|
||||||
|
const color = useRecoilValue(iconColorAtom);
|
||||||
|
const size = useRecoilValue(iconSizeAtom);
|
||||||
|
const filteredQueryResults = useRecoilValue(filteredQueryResultsSelector);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<motion.div className="grid">
|
||||||
|
{filteredQueryResults.map(({ name, Icon }) => (
|
||||||
|
<motion.div
|
||||||
|
tabIndex={1}
|
||||||
|
key={name}
|
||||||
|
className="grid-item"
|
||||||
|
whileHover={whileHover}
|
||||||
|
whileTap={whileTap}
|
||||||
|
transition={transition}
|
||||||
|
>
|
||||||
|
<Icon color={color} size={size} weight={weight} />
|
||||||
|
<p>{name}</p>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default IconGrid;
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 250px;
|
flex: 2;
|
||||||
margin: 4px;
|
margin: 4px;
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
border: 1px solid black;
|
border: 1px solid black;
|
||||||
|
|||||||
@@ -16,11 +16,9 @@ const SearchInput: React.FC<SearchInputProps> = () => {
|
|||||||
return (
|
return (
|
||||||
<div className="search-bar">
|
<div className="search-bar">
|
||||||
<Search />
|
<Search />
|
||||||
<label htmlFor="search-input" hidden>
|
|
||||||
Search for an icon
|
|
||||||
</label>
|
|
||||||
<input
|
<input
|
||||||
id="search-input"
|
id="search-input"
|
||||||
|
aria-label="Search for an icon"
|
||||||
type="text"
|
type="text"
|
||||||
value={query}
|
value={query}
|
||||||
placeholder="Search for an icon"
|
placeholder="Search for an icon"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 250px;
|
flex: 2;
|
||||||
margin: 4px;
|
margin: 4px;
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
border: 1px solid black;
|
border: 1px solid black;
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
background-color: white;
|
background-color: white;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
font-size: 13.333px;
|
font-size: 13.333px;
|
||||||
height: 20px;
|
height: 17px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.size-bar:focus-within {
|
.size-bar:focus-within {
|
||||||
|
|||||||
@@ -15,11 +15,9 @@ const StyleInput: React.FC<StyleInputProps> = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="style-input" hidden>
|
|
||||||
Icon Size
|
|
||||||
</label>
|
|
||||||
<select
|
<select
|
||||||
id="style-input"
|
id="style-input"
|
||||||
|
aria-label="Icon Style"
|
||||||
value={style?.toString()}
|
value={style?.toString()}
|
||||||
onChange={handleStyleChange}
|
onChange={handleStyleChange}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
.toolbar {
|
.toolbar {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
padding: 8px;
|
padding: 4px;
|
||||||
background-color: #f2f2f2;
|
/* background-color: #f2f2f2; */
|
||||||
border: 1px 0px 1px solid black;
|
background-color: #e2e2e2;
|
||||||
z-index: 2px;
|
border-top: 1px solid black;
|
||||||
|
border-bottom: 1px solid black;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
z-index: 1;
|
||||||
|
flex-flow: wrap;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,3 +27,8 @@ export const iconColorAtom = atom<string>({
|
|||||||
key: "iconColorAtom",
|
key: "iconColorAtom",
|
||||||
default: "#000000",
|
default: "#000000",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const iconPreviewOpenAtom = atom<string | false>({
|
||||||
|
key: "iconPreviewOpenAtom",
|
||||||
|
default: false,
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user