From 7cd27c509b69858d0fc924af37cd63ca418386db Mon Sep 17 00:00:00 2001
From: rektdeckard
Date: Mon, 21 Jun 2021 17:07:52 -0400
Subject: [PATCH] app: Generify Modal and restructure imports
---
package.json | 2 -
src/components/App/App.css | 2 +-
src/components/App/App.tsx | 18 +++--
src/components/App/index.ts | 2 +
src/components/ColorInput/ColorInput.tsx | 7 +-
src/components/ColorInput/index.ts | 2 +
src/components/ErrorBoundary/index.ts | 2 +
src/components/Footer/Footer.tsx | 14 ++--
src/components/Footer/index.ts | 2 +
src/components/Header/Header.tsx | 34 ++++----
src/components/Header/index.ts | 2 +
src/components/IconGrid/DetailsPanel.tsx | 9 ++-
src/components/IconGrid/IconGrid.tsx | 19 +++--
src/components/IconGrid/IconGridItem.tsx | 10 +--
src/components/IconGrid/TagCloud.tsx | 3 +-
src/components/IconGrid/index.ts | 2 +
src/components/Links/Links.css | 9 ++-
src/components/Links/Links.tsx | 34 +++-----
src/components/Links/index.ts | 2 +
.../{ => DonationModal}/DonationModal.tsx | 57 +++++++++----
.../DonationStepDropin.tsx | 10 ++-
.../DonationStepMethod.tsx | 48 +++++------
.../DonationStepThanks.tsx | 0
src/components/Modal/DonationModal/index.ts | 2 +
src/components/Modal/DonationStepCC.tsx | 80 -------------------
src/components/Modal/Modal.css | 20 ++++-
src/components/Modal/Modal.tsx | 25 ++++--
src/components/Modal/index.ts | 3 +
src/components/Notice/Notice.tsx | 12 ++-
src/components/Notice/index.ts | 2 +
src/components/SearchInput/SearchInput.tsx | 6 +-
src/components/SearchInput/index.ts | 2 +
src/components/SizeInput/SizeInput.tsx | 3 +-
src/components/SizeInput/index.ts | 2 +
src/components/StyleInput/StyleInput.tsx | 5 +-
src/components/StyleInput/index.ts | 2 +
src/components/Toolbar/Toolbar.tsx | 9 ++-
src/components/Toolbar/index.ts | 2 +
src/hooks/index.ts | 8 ++
src/index.tsx | 3 +-
src/state/atoms.ts | 8 +-
src/state/selectors.ts | 49 +++++++++---
tsconfig.json | 41 ++++------
43 files changed, 305 insertions(+), 269 deletions(-)
create mode 100644 src/components/App/index.ts
create mode 100644 src/components/ColorInput/index.ts
create mode 100644 src/components/ErrorBoundary/index.ts
create mode 100644 src/components/Footer/index.ts
create mode 100644 src/components/Header/index.ts
create mode 100644 src/components/IconGrid/index.ts
create mode 100644 src/components/Links/index.ts
rename src/components/Modal/{ => DonationModal}/DonationModal.tsx (51%)
rename src/components/Modal/{ => DonationModal}/DonationStepDropin.tsx (88%)
rename src/components/Modal/{ => DonationModal}/DonationStepMethod.tsx (68%)
rename src/components/Modal/{ => DonationModal}/DonationStepThanks.tsx (100%)
create mode 100644 src/components/Modal/DonationModal/index.ts
delete mode 100644 src/components/Modal/DonationStepCC.tsx
create mode 100644 src/components/Modal/index.ts
create mode 100644 src/components/Notice/index.ts
create mode 100644 src/components/SearchInput/index.ts
create mode 100644 src/components/SizeInput/index.ts
create mode 100644 src/components/StyleInput/index.ts
create mode 100644 src/components/Toolbar/index.ts
create mode 100644 src/hooks/index.ts
diff --git a/package.json b/package.json
index 3dcf799..c58aec3 100644
--- a/package.json
+++ b/package.json
@@ -21,9 +21,7 @@
"repository": "github:phosphor-icons/phosphor-home",
"private": true,
"dependencies": {
- "@types/braintree-web": "^3.75.3",
"@types/braintree-web-drop-in": "^1.22.3",
- "braintree-web": "^3.78.2",
"braintree-web-drop-in": "^1.30.1",
"file-saver": "^2.0.2",
"framer-motion": "^3.10.0",
diff --git a/src/components/App/App.css b/src/components/App/App.css
index d076926..3db5216 100644
--- a/src/components/App/App.css
+++ b/src/components/App/App.css
@@ -144,7 +144,7 @@ button.text-button svg {
display: flex;
flex-flow: row wrap;
justify-content: space-around;
- row-gap: 16px;
+ row-gap: 8px;
}
.radio-button input[type="radio"] {
diff --git a/src/components/App/App.tsx b/src/components/App/App.tsx
index d426e3e..e144c9b 100644
--- a/src/components/App/App.tsx
+++ b/src/components/App/App.tsx
@@ -1,14 +1,16 @@
import React, { Suspense } from "react";
+import Header from "components/Header";
+import Modal from "components/Modal";
+import Toolbar from "components/Toolbar";
+import IconGrid from "components/IconGrid";
+import Footer from "components/Footer";
+import ErrorBoundary from "components/ErrorBoundary";
+import Notice from "components/Notice";
+
+import useIconParameters from "hooks/useIconParameters";
+
import "./App.css";
-import Header from "../Header/Header";
-import Modal from "../Modal/Modal";
-import Toolbar from "../Toolbar/Toolbar";
-import IconGrid from "../IconGrid/IconGrid";
-import Footer from "../Footer/Footer";
-import ErrorBoundary from "../ErrorBoundary/ErrorBoundary";
-import Notice from "../Notice/Notice";
-import useIconParameters from "../../hooks/useIconParameters";
const errorFallback = ;
const paymentFallback = ;
diff --git a/src/components/App/index.ts b/src/components/App/index.ts
new file mode 100644
index 0000000..9ba5deb
--- /dev/null
+++ b/src/components/App/index.ts
@@ -0,0 +1,2 @@
+import App from "./App";
+export default App;
diff --git a/src/components/ColorInput/ColorInput.tsx b/src/components/ColorInput/ColorInput.tsx
index b98df2a..71061db 100644
--- a/src/components/ColorInput/ColorInput.tsx
+++ b/src/components/ColorInput/ColorInput.tsx
@@ -1,9 +1,10 @@
import React, { useCallback } from "react";
import { useRecoilState, useRecoilValue } from "recoil";
-import { iconColorAtom } from "../../state/atoms";
-import { isDarkThemeSelector } from "../../state/selectors";
-import useThrottled from "../../hooks/useThrottled";
+import { iconColorAtom } from "state/atoms";
+import { isDarkThemeSelector } from "state/selectors";
+import useThrottled from "hooks/useThrottled";
+
import "./ColorInput.css";
type ColorInputProps = {};
diff --git a/src/components/ColorInput/index.ts b/src/components/ColorInput/index.ts
new file mode 100644
index 0000000..9c761d8
--- /dev/null
+++ b/src/components/ColorInput/index.ts
@@ -0,0 +1,2 @@
+import ColorInput from "./ColorInput";
+export default ColorInput;
diff --git a/src/components/ErrorBoundary/index.ts b/src/components/ErrorBoundary/index.ts
new file mode 100644
index 0000000..bbeca7b
--- /dev/null
+++ b/src/components/ErrorBoundary/index.ts
@@ -0,0 +1,2 @@
+import ErrorBoundary from "./ErrorBoundary";
+export default ErrorBoundary;
diff --git a/src/components/Footer/Footer.tsx b/src/components/Footer/Footer.tsx
index ff15879..6d32a47 100644
--- a/src/components/Footer/Footer.tsx
+++ b/src/components/Footer/Footer.tsx
@@ -1,10 +1,12 @@
import React from "react";
import { Coffee, Heart } from "phosphor-react";
-import uArrowUpLeft from "../../assets/u-arrow-up-left.svg";
-import markerGreen from "../../assets/marker-green.svg";
-import postIt from "../../assets/footer-mobile.svg";
-import Links from "../Links/Links";
+import uArrowUpLeft from "assets/u-arrow-up-left.svg";
+import markerGreen from "assets/marker-green.svg";
+import postIt from "assets/footer-mobile.svg";
+
+import Links from "components/Links";
+
import "./Footer.css";
type FooterProps = {};
@@ -34,8 +36,8 @@ const Footer: React.FC = () => {
a little quirky, too.
- We're thankful for the tools we've benefited from and
- this is our contribution towards a collaborative community.
+ We're thankful for the tools we've benefited from and this is our
+ contribution towards a collaborative community.
Phosphor is free and open-source, licensed under{" "}
diff --git a/src/components/Footer/index.ts b/src/components/Footer/index.ts
new file mode 100644
index 0000000..ccb5e78
--- /dev/null
+++ b/src/components/Footer/index.ts
@@ -0,0 +1,2 @@
+import Footer from "./Footer";
+export default Footer;
diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx
index fd2cce6..28fa7dd 100644
--- a/src/components/Header/Header.tsx
+++ b/src/components/Header/Header.tsx
@@ -1,22 +1,24 @@
import React from "react";
import { ArrowCircleUpRight, ArrowCircleDown } from "phosphor-react";
-import markerPurple from "../../assets/marker-purple.svg";
-import paperclips from "../../assets/paperclips-header-mobile.svg";
-import paperclipsThree from "../../assets/paperclips-header.svg";
-import tablet from "../../assets/tablet.svg";
-import tabletSpec from "../../assets/tablet-spec.svg";
-import billiardBall from "../../assets/billiard-ball.svg";
-import billiardBallSpec from "../../assets/billiard-ball-spec.svg";
-import warning from "../../assets/warning.svg";
-import warningSpec from "../../assets/warning-spec.svg";
-import cuttingMat from "../../assets/cutting-mat.svg";
-import cuttingMatSpec from "../../assets/cutting-mat-spec.svg";
-import receipt from "../../assets/receipt.svg";
-import receiptSpec from "../../assets/receipt-spec.svg";
-import calculator from "../../assets/calculator.svg";
-import calculatorSpec from "../../assets/calculator-spec.svg";
-import Links from "../Links/Links";
+import markerPurple from "assets/marker-purple.svg";
+import paperclips from "assets/paperclips-header-mobile.svg";
+import paperclipsThree from "assets/paperclips-header.svg";
+import tablet from "assets/tablet.svg";
+import tabletSpec from "assets/tablet-spec.svg";
+import billiardBall from "assets/billiard-ball.svg";
+import billiardBallSpec from "assets/billiard-ball-spec.svg";
+import warning from "assets/warning.svg";
+import warningSpec from "assets/warning-spec.svg";
+import cuttingMat from "assets/cutting-mat.svg";
+import cuttingMatSpec from "assets/cutting-mat-spec.svg";
+import receipt from "assets/receipt.svg";
+import receiptSpec from "assets/receipt-spec.svg";
+import calculator from "assets/calculator.svg";
+import calculatorSpec from "assets/calculator-spec.svg";
+
+import Links from "components/Links";
+
import "./Header.css";
type HeaderProps = {};
diff --git a/src/components/Header/index.ts b/src/components/Header/index.ts
new file mode 100644
index 0000000..aa3e4e8
--- /dev/null
+++ b/src/components/Header/index.ts
@@ -0,0 +1,2 @@
+import Header from "./Header";
+export default Header;
diff --git a/src/components/IconGrid/DetailsPanel.tsx b/src/components/IconGrid/DetailsPanel.tsx
index 766fc0c..cc94217 100644
--- a/src/components/IconGrid/DetailsPanel.tsx
+++ b/src/components/IconGrid/DetailsPanel.tsx
@@ -3,18 +3,19 @@ import { useRecoilValue, useSetRecoilState } from "recoil";
import { motion } from "framer-motion";
import { Svg2Png } from "svg2png-converter";
import { saveAs } from "file-saver";
-import { Copy, X, CheckCircle, Download } from "phosphor-react";
import ReactGA from "react-ga";
+import { Copy, X, CheckCircle, Download } from "phosphor-react";
import {
iconWeightAtom,
iconSizeAtom,
iconColorAtom,
iconPreviewOpenAtom,
-} from "../../state/atoms";
-import useTransientState from "../../hooks/useTransientState";
+} from "state/atoms";
+import { IconEntry } from "lib";
+import useTransientState from "hooks/useTransientState";
+
import TagCloud from "./TagCloud";
-import { IconEntry } from "../../lib";
const panelVariants = {
open: {
diff --git a/src/components/IconGrid/IconGrid.tsx b/src/components/IconGrid/IconGrid.tsx
index efa94fd..75bb599 100644
--- a/src/components/IconGrid/IconGrid.tsx
+++ b/src/components/IconGrid/IconGrid.tsx
@@ -3,18 +3,27 @@ import { useRecoilValue } from "recoil";
import { motion, useAnimation } from "framer-motion";
import { IconContext } from "phosphor-react";
-import { iconWeightAtom, iconSizeAtom, iconColorAtom } from "../../state/atoms";
+import { iconWeightAtom, iconSizeAtom, iconColorAtom } from "state/atoms";
import {
filteredQueryResultsSelector,
isDarkThemeSelector,
-} from "../../state/selectors";
-import useGridSpans from "../../hooks/useGridSpans";
+} from "state/selectors";
+import useGridSpans from "hooks/useGridSpans";
+
import IconGridItem from "./IconGridItem";
import TagCloud from "./TagCloud";
-import Notice from "../Notice/Notice";
+import Notice from "components/Notice";
+
import "./IconGrid.css";
-const defaultSearchTags = ["*new*", "communication", "editor", "emoji", "maps", "weather"];
+const defaultSearchTags = [
+ "*new*",
+ "communication",
+ "editor",
+ "emoji",
+ "maps",
+ "weather",
+];
type IconGridProps = {};
diff --git a/src/components/IconGrid/IconGridItem.tsx b/src/components/IconGrid/IconGridItem.tsx
index ecd2ee4..7c78777 100644
--- a/src/components/IconGrid/IconGridItem.tsx
+++ b/src/components/IconGrid/IconGridItem.tsx
@@ -7,9 +7,9 @@ import React, {
import { useRecoilState } from "recoil";
import { motion, AnimatePresence } from "framer-motion";
-import { iconPreviewOpenAtom } from "../../state/atoms";
+import { IconEntry } from "lib";
+import { iconPreviewOpenAtom } from "state/atoms";
import DetailsPanel from "./DetailsPanel";
-import { IconEntry } from "../../lib";
interface IconGridItemProps {
index: number;
@@ -86,9 +86,9 @@ const IconGridItem: React.FC = (props) => {
{name}
-
- {isOpen && }
-
+
+ {isOpen && }
+
>
);
};
diff --git a/src/components/IconGrid/TagCloud.tsx b/src/components/IconGrid/TagCloud.tsx
index 5d376b4..3e32a83 100644
--- a/src/components/IconGrid/TagCloud.tsx
+++ b/src/components/IconGrid/TagCloud.tsx
@@ -1,7 +1,8 @@
import React, { useCallback } from "react";
import { useSetRecoilState } from "recoil";
-import { searchQueryAtom } from "../../state/atoms";
+import { searchQueryAtom } from "state/atoms";
+
import "./TagCloud.css";
interface TagCloudProps {
diff --git a/src/components/IconGrid/index.ts b/src/components/IconGrid/index.ts
new file mode 100644
index 0000000..272fd4a
--- /dev/null
+++ b/src/components/IconGrid/index.ts
@@ -0,0 +1,2 @@
+import IconGrid from "./IconGrid";
+export default IconGrid;
diff --git a/src/components/Links/Links.css b/src/components/Links/Links.css
index fd241ef..b6893a7 100644
--- a/src/components/Links/Links.css
+++ b/src/components/Links/Links.css
@@ -20,13 +20,14 @@
margin-right: 12px;
}
-a.nav-link {
+.nav-link {
text-decoration: none;
position: relative;
color: black;
+ cursor: pointer;
}
-a.nav-link:after {
+.nav-link:after {
content: "";
position: absolute;
bottom: -2px;
@@ -36,6 +37,6 @@ a.nav-link:after {
transition: 0.2s;
}
-a.nav-link:hover:after {
+.nav-link:hover:after {
width: 100%;
-}
\ No newline at end of file
+}
diff --git a/src/components/Links/Links.tsx b/src/components/Links/Links.tsx
index 0dc800f..e91171c 100644
--- a/src/components/Links/Links.tsx
+++ b/src/components/Links/Links.tsx
@@ -3,17 +3,19 @@ import { OutboundLink } from "react-ga";
import { useSetRecoilState } from "recoil";
import { ArrowElbowDownRight } from "phosphor-react";
-import { iconCount } from "../../lib/icons";
-import { modalOpenAtom } from "../../state/atoms";
+import { iconCount } from "lib/icons";
+import { modalSelector } from "state/selectors";
+import DonationModal from "components/Modal/DonationModal";
import "./Links.css";
interface LinksProps {}
const Links: React.FC = () => {
- const setModalOpen = useSetRecoilState(modalOpenAtom);
+ const openModal = useSetRecoilState(modalSelector);
+ const openDonationModal = () => openModal({ type: DonationModal });
- const openDonationModal = () => setTimeout(() => setModalOpen(true), 1000);
+ const delayedOpenDonationModal = () => setTimeout(openDonationModal, 2000);
return (
@@ -25,7 +27,7 @@ const Links: React.FC = () => {
eventLabel="Download all"
download
type="application/zip"
- onClick={openDonationModal}
+ onClick={delayedOpenDonationModal}
>
Download all ({iconCount})
@@ -59,27 +61,11 @@ const Links: React.FC = () => {
Request an icon
- {/* */}
diff --git a/src/components/Links/index.ts b/src/components/Links/index.ts
new file mode 100644
index 0000000..a49c54e
--- /dev/null
+++ b/src/components/Links/index.ts
@@ -0,0 +1,2 @@
+import Links from "./Links";
+export default Links;
diff --git a/src/components/Modal/DonationModal.tsx b/src/components/Modal/DonationModal/DonationModal.tsx
similarity index 51%
rename from src/components/Modal/DonationModal.tsx
rename to src/components/Modal/DonationModal/DonationModal.tsx
index f5eb029..1043483 100644
--- a/src/components/Modal/DonationModal.tsx
+++ b/src/components/Modal/DonationModal/DonationModal.tsx
@@ -1,23 +1,40 @@
import React, { useState } from "react";
-import { useSetRecoilState } from "recoil";
-import { X } from "phosphor-react";
-import { modalOpenAtom } from "../../state/atoms";
+import { ModalInstance } from "../Modal";
import DonationStepMethod from "./DonationStepMethod";
import DonationStepDropin from "./DonationStepDropin";
import DonationStepThanks from "./DonationStepThanks";
const routes = [DonationStepMethod, DonationStepDropin, DonationStepThanks];
+export enum DonationType {
+ FIVE_DOLLARS = 5,
+ TEN_DOLLARS = 10,
+ TWENTY_DOLLARS = 20,
+ FIFTY_DOLLARS = 50,
+ ONE_HUNDRED_DOLLARS = 100,
+ CUSTOM = -1,
+}
+
+interface RouteProps {
+ donationType: DonationType | undefined;
+ setDonationType: React.Dispatch<
+ React.SetStateAction
+ >;
+ donationAmount: number;
+ setDonationAmount: React.Dispatch>;
+}
+
export interface StepProps {
previousStep: () => void;
nextStep: () => void;
close: () => void;
+ routeProps: RouteProps;
}
interface StepperProps {
routes: Array>;
- routeProps: any;
+ routeProps: RouteProps;
close: () => void;
}
@@ -42,26 +59,32 @@ const Stepper: React.FC = ({ routes, routeProps, close }) => {
previousStep={previousStep}
nextStep={nextStep}
close={close}
- {...routeProps}
+ routeProps={routeProps}
/>
>
);
};
-const DonationModal: React.FC<{}> = () => {
- const setModalOpen = useSetRecoilState(modalOpenAtom);
- const close = () => setModalOpen(false);
+const DonationModal = ({ close }: ModalInstance): JSX.Element => {
+ const [donationType, setDonationType] = useState();
+ const [donationAmount, setDonationAmount] = useState(0);
return (
-
- setModalOpen(false)}
- >
-
-
-
-
+ <>
+
+
Donate
+
+
+ >
);
};
diff --git a/src/components/Modal/DonationStepDropin.tsx b/src/components/Modal/DonationModal/DonationStepDropin.tsx
similarity index 88%
rename from src/components/Modal/DonationStepDropin.tsx
rename to src/components/Modal/DonationModal/DonationStepDropin.tsx
index ca13cd4..4c5b361 100644
--- a/src/components/Modal/DonationStepDropin.tsx
+++ b/src/components/Modal/DonationModal/DonationStepDropin.tsx
@@ -17,10 +17,12 @@ const BT_PAYMENT_FIELDS = {
},
};
-const PaymentModal: React.FC = ({ previousStep }) => {
+const PaymentModal: React.FC = ({ previousStep, routeProps }) => {
const instance = useRef();
const [isValid, setIsValid] = useState(false);
+ const { donationAmount } = routeProps;
+
const submit = async () => {
if (!instance.current) return;
const payload = await instance.current.requestPaymentMethod();
@@ -43,13 +45,13 @@ const PaymentModal: React.FC = ({ previousStep }) => {
},
paypal: {
flow: "checkout",
- amount: "10.00",
+ amount: donationAmount.toFixed(2).toString(),
currency: "USD",
commit: true,
},
paypalCredit: {
flow: "checkout",
- amount: "10.00",
+ amount: donationAmount.toFixed(2).toString(),
currency: "USD",
commit: true,
},
@@ -65,7 +67,7 @@ const PaymentModal: React.FC = ({ previousStep }) => {
};
initializePayments();
- }, []);
+ }, [donationAmount]);
return (
<>
diff --git a/src/components/Modal/DonationStepMethod.tsx b/src/components/Modal/DonationModal/DonationStepMethod.tsx
similarity index 68%
rename from src/components/Modal/DonationStepMethod.tsx
rename to src/components/Modal/DonationModal/DonationStepMethod.tsx
index 236119e..a17b9ed 100644
--- a/src/components/Modal/DonationStepMethod.tsx
+++ b/src/components/Modal/DonationModal/DonationStepMethod.tsx
@@ -1,27 +1,19 @@
-import React, { useState } from "react";
+import React from "react";
-import { StepProps } from "./DonationModal";
-
-enum DonationAmount {
- FIVE_DOLLARS = 5,
- TEN_DOLLARS = 10,
- TWENTY_DOLLARS = 20,
- FIFTY_DOLLARS = 50,
- ONE_HUNDRED_DOLLARS = 100,
- CUSTOM = -1,
-}
+import { StepProps, DonationType } from "./DonationModal";
const DonationStepMethod: React.FC = ({
previousStep,
nextStep,
close,
+ routeProps,
}) => {
- const [donationType, setDonationType] = useState();
- const [donationAmount, setDonationAmount] = useState(0);
+ const { donationType, donationAmount, setDonationType, setDonationAmount } =
+ routeProps;
const onDonationChange = (e: React.ChangeEvent) => {
- setDonationType(+e.target.value as DonationAmount);
- if (!(+e.target.value === DonationAmount.CUSTOM))
+ setDonationType(+e.target.value as DonationType);
+ if (!(+e.target.value === DonationType.CUSTOM))
setDonationAmount(+e.target.value);
};
@@ -39,8 +31,8 @@ const DonationStepMethod: React.FC = ({
type="radio"
id="donate-5"
name="donation-type"
- value={DonationAmount.FIVE_DOLLARS}
- checked={donationType === DonationAmount.FIVE_DOLLARS}
+ value={DonationType.FIVE_DOLLARS}
+ checked={donationType === DonationType.FIVE_DOLLARS}
onChange={onDonationChange}
/>
$5
@@ -50,8 +42,8 @@ const DonationStepMethod: React.FC = ({
type="radio"
id="donate-10"
name="donation-type"
- value={DonationAmount.TEN_DOLLARS}
- checked={donationType === DonationAmount.TEN_DOLLARS}
+ value={DonationType.TEN_DOLLARS}
+ checked={donationType === DonationType.TEN_DOLLARS}
onChange={onDonationChange}
/>
$10
@@ -61,8 +53,8 @@ const DonationStepMethod: React.FC = ({
type="radio"
id="donate-20"
name="donation-type"
- value={DonationAmount.TWENTY_DOLLARS}
- checked={donationType === DonationAmount.TWENTY_DOLLARS}
+ value={DonationType.TWENTY_DOLLARS}
+ checked={donationType === DonationType.TWENTY_DOLLARS}
onChange={onDonationChange}
/>
$20
@@ -72,8 +64,8 @@ const DonationStepMethod: React.FC = ({
type="radio"
id="donate-50"
name="donation-type"
- value={DonationAmount.FIFTY_DOLLARS}
- checked={donationType === DonationAmount.FIFTY_DOLLARS}
+ value={DonationType.FIFTY_DOLLARS}
+ checked={donationType === DonationType.FIFTY_DOLLARS}
onChange={onDonationChange}
/>
$50
@@ -83,8 +75,8 @@ const DonationStepMethod: React.FC = ({
type="radio"
id="donate-100"
name="donation-type"
- value={DonationAmount.ONE_HUNDRED_DOLLARS}
- checked={donationType === DonationAmount.ONE_HUNDRED_DOLLARS}
+ value={DonationType.ONE_HUNDRED_DOLLARS}
+ checked={donationType === DonationType.ONE_HUNDRED_DOLLARS}
onChange={onDonationChange}
/>
$100
@@ -94,8 +86,8 @@ const DonationStepMethod: React.FC = ({
type="radio"
id="donate-custom"
name="donation-type"
- value={DonationAmount.CUSTOM}
- checked={donationType === DonationAmount.CUSTOM}
+ value={DonationType.CUSTOM}
+ checked={donationType === DonationType.CUSTOM}
onChange={onDonationChange}
/>
@@ -106,7 +98,7 @@ const DonationStepMethod: React.FC = ({
max={1000000}
id="donate-custom"
value={donationAmount}
- disabled={donationType !== DonationAmount.CUSTOM}
+ disabled={donationType !== DonationType.CUSTOM}
onChange={(e) => setDonationAmount(+e.target.value)}
/>
diff --git a/src/components/Modal/DonationStepThanks.tsx b/src/components/Modal/DonationModal/DonationStepThanks.tsx
similarity index 100%
rename from src/components/Modal/DonationStepThanks.tsx
rename to src/components/Modal/DonationModal/DonationStepThanks.tsx
diff --git a/src/components/Modal/DonationModal/index.ts b/src/components/Modal/DonationModal/index.ts
new file mode 100644
index 0000000..36af021
--- /dev/null
+++ b/src/components/Modal/DonationModal/index.ts
@@ -0,0 +1,2 @@
+import DonationModal from "./DonationModal";
+export default DonationModal;
diff --git a/src/components/Modal/DonationStepCC.tsx b/src/components/Modal/DonationStepCC.tsx
deleted file mode 100644
index d250dc6..0000000
--- a/src/components/Modal/DonationStepCC.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-import React, { useRef, useEffect } from "react";
-import { client, hostedFields, Client, HostedFields } from "braintree-web";
-
-const BT_STYLES = {
- ":focus": {
- color: "blue",
- },
- ".valid": {
- color: "green",
- },
- ".invalid": {
- color: "red",
- },
-};
-const BT_PAYMENT_FIELDS = {
- number: {
- container: "#card-number",
- placeholder: "4111 1111 1111 1111",
- },
- cvv: {
- container: "#cvv",
- placeholder: "123",
- },
- expirationDate: {
- container: "#expiration-date",
- placeholder: "10/2022",
- },
-};
-
-const PaymentModal: React.FC<{}> = () => {
- const bt = useRef();
- const form = useRef();
-
- const handleSubmit = async (event: React.FormEvent) => {
- event.preventDefault();
- if (!form.current || !bt.current) return;
-
- const response = await form.current.tokenize();
- console.log({ response });
- };
-
- useEffect(() => {
- const initializeBt = async () => {
- try {
- bt.current = await client.create({
- authorization: "sandbox_246jdjxq_8h7hm5rvngkykjds",
- });
-
- form.current = await hostedFields.create({
- client: bt.current!!,
- fields: BT_PAYMENT_FIELDS,
- styles: BT_STYLES,
- });
- } catch (err) {
- console.error(err);
- }
- };
-
- initializeBt();
- }, []);
-
- return (
-
- );
-};
-
-export default PaymentModal;
diff --git a/src/components/Modal/Modal.css b/src/components/Modal/Modal.css
index a52a4f4..678e2ff 100644
--- a/src/components/Modal/Modal.css
+++ b/src/components/Modal/Modal.css
@@ -13,7 +13,6 @@
flex-direction: column;
width: 400px;
min-height: 600px;
- /* background-color: #ffe8dc; */
background-color: white;
border-radius: 8px;
border: 2px solid black;
@@ -22,8 +21,10 @@
@media screen and (max-width: 480px) {
.modal-content {
- min-width: 90%;
- min-height: 100%;
+ position: fixed;
+ inset: 0;
+ width: unset;
+ min-height: unset;
border: none;
border-radius: 0;
}
@@ -48,6 +49,17 @@ button.modal-close-button {
z-index: 1;
}
+.modal-titlebar {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-between;
+}
+
+.modal-titlebar > * {
+ margin: 0;
+}
+
.payment-methods {
display: grid;
gap: 16px;
@@ -64,4 +76,4 @@ button.modal-close-button {
.payment-methods button > svg {
margin: 0;
-}
\ No newline at end of file
+}
diff --git a/src/components/Modal/Modal.tsx b/src/components/Modal/Modal.tsx
index 9c0746b..d044a27 100644
--- a/src/components/Modal/Modal.tsx
+++ b/src/components/Modal/Modal.tsx
@@ -1,23 +1,36 @@
import React from "react";
-import { useRecoilState } from "recoil";
+import { useRecoilState, useRecoilValue } from "recoil";
import { useLockBodyScroll } from "react-use";
import { useHotkeys } from "react-hotkeys-hook";
+import { X } from "phosphor-react";
-import { modalOpenAtom } from "../../state/atoms";
-import DonationModal from "./DonationModal";
+import { modalAtom, modalOpenAtom } from "state/atoms";
import "./Modal.css";
-const Modal: React.FC<{}> = () => {
+export interface ModalInstance {
+ close: () => void;
+ children?: JSX.Element;
+}
+
+const Modal = (): JSX.Element | null => {
+ const Instance = useRecoilValue(modalAtom);
const [isModalOpen, setModalOpen] = useRecoilState(modalOpenAtom);
useHotkeys("esc", () => isModalOpen && setModalOpen(false), [isModalOpen]);
useLockBodyScroll(isModalOpen);
- if (!isModalOpen) return null;
+ const close = () => setModalOpen(false);
+
+ if (!Instance || !isModalOpen) return null;
return (
);
};
diff --git a/src/components/Modal/index.ts b/src/components/Modal/index.ts
new file mode 100644
index 0000000..920453e
--- /dev/null
+++ b/src/components/Modal/index.ts
@@ -0,0 +1,3 @@
+import Modal from "./Modal";
+export default Modal;
+
diff --git a/src/components/Notice/Notice.tsx b/src/components/Notice/Notice.tsx
index a89d20f..fcc348e 100644
--- a/src/components/Notice/Notice.tsx
+++ b/src/components/Notice/Notice.tsx
@@ -1,17 +1,21 @@
import React from "react";
import { motion } from "framer-motion";
import { useRecoilValue } from "recoil";
-
-import { isDarkThemeSelector } from "../../state/selectors";
-import { searchQueryAtom } from "../../state/atoms";
import { HourglassMedium, Question, SmileyXEyes } from "phosphor-react";
+import { isDarkThemeSelector } from "state/selectors";
+import { searchQueryAtom } from "state/atoms";
+
interface NoticeProps {
message?: string;
type?: "wait" | "help" | "warn" | "none";
}
-const Notice: React.FC = ({ message, type = "warn", children }) => {
+const Notice: React.FC = ({
+ message,
+ type = "warn",
+ children,
+}) => {
const isDark = useRecoilValue(isDarkThemeSelector);
const query = useRecoilValue(searchQueryAtom);
diff --git a/src/components/Notice/index.ts b/src/components/Notice/index.ts
new file mode 100644
index 0000000..5fdedb9
--- /dev/null
+++ b/src/components/Notice/index.ts
@@ -0,0 +1,2 @@
+import Notice from "./Notice";
+export default Notice;
diff --git a/src/components/SearchInput/SearchInput.tsx b/src/components/SearchInput/SearchInput.tsx
index d308cc3..c76463c 100644
--- a/src/components/SearchInput/SearchInput.tsx
+++ b/src/components/SearchInput/SearchInput.tsx
@@ -5,7 +5,8 @@ import { useHotkeys } from "react-hotkeys-hook";
import { Command, MagnifyingGlass, X, HourglassHigh } from "phosphor-react";
import ReactGA from "react-ga";
-import { searchQueryAtom } from "../../state/atoms";
+import { searchQueryAtom } from "state/atoms";
+
import "./SearchInput.css";
const apple = /iPhone|iPod|iPad|Macintosh|MacIntel|MacPPC/i;
@@ -19,7 +20,8 @@ type SearchInputProps = {};
const SearchInput: React.FC = () => {
const [value, setValue] = useState("");
const [query, setQuery] = useRecoilState(searchQueryAtom);
- const inputRef = useRef() as MutableRefObject;
+ const inputRef =
+ useRef() as MutableRefObject;
useHotkeys("ctrl+k,cmd+k", (e) => {
e.preventDefault();
diff --git a/src/components/SearchInput/index.ts b/src/components/SearchInput/index.ts
new file mode 100644
index 0000000..90c2283
--- /dev/null
+++ b/src/components/SearchInput/index.ts
@@ -0,0 +1,2 @@
+import SearchInput from "./SearchInput";
+export default SearchInput;
diff --git a/src/components/SizeInput/SizeInput.tsx b/src/components/SizeInput/SizeInput.tsx
index d8e37be..c09ea54 100644
--- a/src/components/SizeInput/SizeInput.tsx
+++ b/src/components/SizeInput/SizeInput.tsx
@@ -1,7 +1,8 @@
import React, { useCallback } from "react";
import { useRecoilState } from "recoil";
-import { iconSizeAtom } from "../../state/atoms";
+import { iconSizeAtom } from "state/atoms";
+
import "./SizeInput.css";
type SizeInputProps = {};
diff --git a/src/components/SizeInput/index.ts b/src/components/SizeInput/index.ts
new file mode 100644
index 0000000..357c511
--- /dev/null
+++ b/src/components/SizeInput/index.ts
@@ -0,0 +1,2 @@
+import SizeInput from "./SizeInput";
+export default SizeInput;
diff --git a/src/components/StyleInput/StyleInput.tsx b/src/components/StyleInput/StyleInput.tsx
index 644573d..778c921 100644
--- a/src/components/StyleInput/StyleInput.tsx
+++ b/src/components/StyleInput/StyleInput.tsx
@@ -3,8 +3,9 @@ import { useRecoilState } from "recoil";
import Select from "react-dropdown-select";
import { PencilLine } from "phosphor-react";
-import { iconWeightAtom } from "../../state/atoms";
-import { IconStyle } from "../../lib";
+import { iconWeightAtom } from "state/atoms";
+import { IconStyle } from "lib";
+
import "./StyleInput.css";
type WeightOption = { key: string; value: IconStyle; icon: JSX.Element };
diff --git a/src/components/StyleInput/index.ts b/src/components/StyleInput/index.ts
new file mode 100644
index 0000000..fe7e478
--- /dev/null
+++ b/src/components/StyleInput/index.ts
@@ -0,0 +1,2 @@
+import StyleInput from "./StyleInput";
+export default StyleInput;
diff --git a/src/components/Toolbar/Toolbar.tsx b/src/components/Toolbar/Toolbar.tsx
index e5a939c..93b5577 100644
--- a/src/components/Toolbar/Toolbar.tsx
+++ b/src/components/Toolbar/Toolbar.tsx
@@ -1,10 +1,11 @@
import React from "react";
+import StyleInput from "components/StyleInput";
+import SearchInput from "components/SearchInput";
+import SizeInput from "components/SizeInput";
+import ColorInput from "components/ColorInput";
+
import "./Toolbar.css";
-import StyleInput from "../StyleInput/StyleInput";
-import SearchInput from "../SearchInput/SearchInput";
-import SizeInput from "../SizeInput/SizeInput";
-import ColorInput from "../ColorInput/ColorInput";
type ToolbarProps = {};
diff --git a/src/components/Toolbar/index.ts b/src/components/Toolbar/index.ts
new file mode 100644
index 0000000..df607a5
--- /dev/null
+++ b/src/components/Toolbar/index.ts
@@ -0,0 +1,2 @@
+import Toolbar from "./Toolbar";
+export default Toolbar;
diff --git a/src/hooks/index.ts b/src/hooks/index.ts
new file mode 100644
index 0000000..e883a9f
--- /dev/null
+++ b/src/hooks/index.ts
@@ -0,0 +1,8 @@
+export { default as useDebounce } from "./useDebounce";
+export { default as useGridSpans } from "./useGridSpans";
+export { default as useIconParameters } from "./useIconParameters";
+export { default as useThrottle } from "./useThrottle";
+export { default as useThrottled } from "./useThrottled";
+export { default as useTimeoutFn } from "./useTimeoutFn";
+export { default as useTransientState } from "./useTransientState";
+export { default as useUnmount } from "./useUnmount";
diff --git a/src/index.tsx b/src/index.tsx
index 9a0e59d..3407269 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -2,7 +2,7 @@ import React from "react";
import ReactDOM from "react-dom";
import { RecoilRoot } from "recoil";
import * as serviceWorker from "./serviceWorker";
-import App from "./components/App/App";
+import App from "./components/App";
import ReactGA from "react-ga";
ReactGA.initialize("UA-179205759-1", { titleCase: false });
@@ -23,7 +23,6 @@ ReactDOM.render(
serviceWorker.unregister();
console.log(`
-
%c sphorphosphor %co%cspho
%c s%cphorphosphor %co%csphorpho%cs
%c o %cp%chorphosphor %co%csphorphosph%co
diff --git a/src/state/atoms.ts b/src/state/atoms.ts
index 7a2a5bb..97c9149 100644
--- a/src/state/atoms.ts
+++ b/src/state/atoms.ts
@@ -1,4 +1,5 @@
import { atom } from "recoil";
+import { ModalInstance } from "../components/Modal/Modal";
import { IconStyle } from "../lib";
export const searchQueryAtom = atom({
@@ -26,7 +27,12 @@ export const iconPreviewOpenAtom = atom({
default: false,
});
+export const modalAtom = atom<((props: ModalInstance) => JSX.Element) | null>({
+ key: "modalAtom",
+ default: null,
+});
+
export const modalOpenAtom = atom({
key: "modalOpenAtom",
- default: true,
+ default: false,
});
diff --git a/src/state/selectors.ts b/src/state/selectors.ts
index c76205a..518a0d0 100644
--- a/src/state/selectors.ts
+++ b/src/state/selectors.ts
@@ -1,10 +1,16 @@
-import { selector, selectorFamily } from "recoil";
+import { DefaultValue, selector, selectorFamily } from "recoil";
import TinyColor from "tinycolor2";
import Fuse from "fuse.js";
-import { searchQueryAtom, iconColorAtom } from "./atoms";
+import {
+ searchQueryAtom,
+ iconColorAtom,
+ modalAtom,
+ modalOpenAtom,
+} from "./atoms";
import { IconEntry, IconCategory } from "../lib";
import { icons } from "../lib/icons";
+import { ModalInstance } from "../components/Modal/Modal";
const fuse = new Fuse(icons, {
keys: [{ name: "name", weight: 4 }, "tags", "categories"],
@@ -52,17 +58,40 @@ export const singleCategoryQueryResultsSelector = selectorFamily<
IconCategory
>({
key: "singleCategoryQueryResultsSelector",
- get: (category: IconCategory) => ({ get }) => {
- const filteredResults = get(filteredQueryResultsSelector);
- return new Promise((resolve) =>
- resolve(
- filteredResults.filter((icon) => icon.categories.includes(category))
- )
- );
- },
+ get:
+ (category: IconCategory) =>
+ ({ get }) => {
+ const filteredResults = get(filteredQueryResultsSelector);
+ return new Promise((resolve) =>
+ resolve(
+ filteredResults.filter((icon) => icon.categories.includes(category))
+ )
+ );
+ },
});
export const isDarkThemeSelector = selector({
key: "isDarkThemeSelector",
get: ({ get }) => TinyColor(get(iconColorAtom)).isLight(),
});
+
+export const modalSelector = selector<{
+ type: (props: ModalInstance) => JSX.Element;
+} | null>({
+ key: "openModalSelector",
+ set: ({ set }, instance) => {
+ if (instance instanceof DefaultValue || instance === null) {
+ set(modalAtom, null);
+ set(modalOpenAtom, false);
+ return;
+ }
+
+ set(modalAtom, () => instance.type!!);
+ set(modalOpenAtom, true);
+ },
+ get: ({ get }) => {
+ const currentModal = get(modalAtom);
+ if (!currentModal) return null;
+ return { type: currentModal };
+ },
+});
diff --git a/tsconfig.json b/tsconfig.json
index cf0f8ac..331d55e 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,36 +1,27 @@
{
"compilerOptions": {
- "target": "es5",
- "lib": [
- "es6",
- "dom",
- "dom.iterable",
- "esnext"
- ],
"allowJs": true,
- "skipLibCheck": true,
- "esModuleInterop": true,
"allowSyntheticDefaultImports": true,
- "strict": true,
+ "baseUrl": "./src/",
+ "declaration": true,
+ "esModuleInterop": true,
+ "experimentalDecorators": true,
"forceConsistentCasingInFileNames": true,
- "module": "esnext",
- "moduleResolution": "node",
- "resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react",
- "sourceMap": true,
- "declaration": true,
+ "lib": ["es6", "dom", "dom.iterable", "esnext"],
+ "module": "esnext",
+ "moduleResolution": "node",
+ "noEmit": true,
+ "noFallthroughCasesInSwitch": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
- "experimentalDecorators": true,
- "noFallthroughCasesInSwitch": true,
- "noEmit": true
+ "resolveJsonModule": true,
+ "skipLibCheck": true,
+ "sourceMap": true,
+ "strict": true,
+ "target": "es5"
},
- "include": [
- "src"
- ],
- "exclude": [
- "node_modules",
- "build"
- ]
+ "include": ["src"],
+ "exclude": ["node_modules", "build"]
}