|
@@ -1,35 +1,27 @@
|
|
|
import React from "react";
|
|
|
+import {
|
|
|
+ ColorPicker,
|
|
|
+ TextInput,
|
|
|
+ SegmentedControl,
|
|
|
+ Group,
|
|
|
+ Modal,
|
|
|
+ Button,
|
|
|
+ Divider,
|
|
|
+ Grid,
|
|
|
+ ModalProps,
|
|
|
+ ColorInput,
|
|
|
+ Stack,
|
|
|
+} from "@mantine/core";
|
|
|
import { toBlob, toPng, toSvg } from "html-to-image";
|
|
|
-import { TwitterPicker } from "react-color";
|
|
|
-import { TwitterPickerStylesProps } from "react-color/lib/components/twitter/Twitter";
|
|
|
import toast from "react-hot-toast";
|
|
|
import { FiCopy, FiDownload } from "react-icons/fi";
|
|
|
-import { Button } from "src/components/Button";
|
|
|
-import { FileInput } from "src/components/FileInput";
|
|
|
-import { Modal, ModalProps } from "src/components/Modal";
|
|
|
-import styled from "styled-components";
|
|
|
-
|
|
|
-const ColorPickerStyles: Partial<TwitterPickerStylesProps> = {
|
|
|
- card: {
|
|
|
- background: "transparent",
|
|
|
- boxShadow: "none",
|
|
|
- },
|
|
|
- body: {
|
|
|
- padding: 0,
|
|
|
- },
|
|
|
- input: {
|
|
|
- background: "rgba(0, 0, 0, 0.2)",
|
|
|
- boxShadow: "none",
|
|
|
- textTransform: "none",
|
|
|
- whiteSpace: "nowrap",
|
|
|
- textOverflow: "ellipsis",
|
|
|
- },
|
|
|
- hash: {
|
|
|
- background: "rgba(180, 180, 180, 0.3)",
|
|
|
- },
|
|
|
-};
|
|
|
|
|
|
-const defaultColors = [
|
|
|
+enum Extensions {
|
|
|
+ SVG = "svg",
|
|
|
+ PNG = "png",
|
|
|
+}
|
|
|
+
|
|
|
+const swatches = [
|
|
|
"#B80000",
|
|
|
"#DB3E00",
|
|
|
"#FCCB00",
|
|
@@ -58,48 +50,11 @@ function downloadURI(uri: string, name: string) {
|
|
|
document.body.removeChild(link);
|
|
|
}
|
|
|
|
|
|
-const StyledContainer = styled.div`
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- gap: 16px;
|
|
|
- padding: 12px 0;
|
|
|
- border-top: 1px solid ${({ theme }) => theme.BACKGROUND_MODIFIER_ACCENT};
|
|
|
- font-size: 12px;
|
|
|
- line-height: 16px;
|
|
|
- font-weight: 600;
|
|
|
- text-transform: uppercase;
|
|
|
- color: ${({ theme }) => theme.INTERACTIVE_NORMAL};
|
|
|
-
|
|
|
- &:first-of-type {
|
|
|
- padding-top: 0;
|
|
|
- border: none;
|
|
|
- }
|
|
|
-`;
|
|
|
-
|
|
|
-const StyledColorWrapper = styled.div`
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
-`;
|
|
|
-
|
|
|
-const StyledColorIndicator = styled.div<{ color: string }>`
|
|
|
- flex: 1;
|
|
|
- width: 100%;
|
|
|
- height: auto;
|
|
|
- border-radius: 6px;
|
|
|
- background: ${({ color }) => color};
|
|
|
- border: 1px solid;
|
|
|
- border-color: rgba(0, 0, 0, 0.1);
|
|
|
-`;
|
|
|
-
|
|
|
-enum Extensions {
|
|
|
- svg,
|
|
|
- png,
|
|
|
-}
|
|
|
-export const DownloadModal: React.FC<ModalProps> = ({ visible, setVisible }) => {
|
|
|
- const [extension, setExtension] = React.useState(Extensions.png);
|
|
|
+export const DownloadModal: React.FC<ModalProps> = ({ opened, onClose }) => {
|
|
|
+ const [extension, setExtension] = React.useState(Extensions.PNG);
|
|
|
const [fileDetails, setFileDetails] = React.useState({
|
|
|
filename: "jsoncrack.com",
|
|
|
- backgroundColor: "transparent",
|
|
|
+ backgroundColor: "rgba(255, 255, 255, 1)",
|
|
|
quality: 1,
|
|
|
});
|
|
|
|
|
@@ -127,7 +82,7 @@ export const DownloadModal: React.FC<ModalProps> = ({ visible, setVisible }) =>
|
|
|
toast.error("Failed to copy to clipboard");
|
|
|
} finally {
|
|
|
toast.dismiss("toastClipboard");
|
|
|
- setVisible(false);
|
|
|
+ onClose();
|
|
|
}
|
|
|
};
|
|
|
|
|
@@ -137,19 +92,19 @@ export const DownloadModal: React.FC<ModalProps> = ({ visible, setVisible }) =>
|
|
|
|
|
|
const imageElement = document.querySelector("svg[id*='ref']") as HTMLElement;
|
|
|
|
|
|
- let exportImage = extension === Extensions.svg ? toSvg : toPng;
|
|
|
+ let exportImage = extension === Extensions.SVG ? toSvg : toPng;
|
|
|
|
|
|
const dataURI = await exportImage(imageElement, {
|
|
|
quality: fileDetails.quality,
|
|
|
backgroundColor: fileDetails.backgroundColor,
|
|
|
});
|
|
|
|
|
|
- downloadURI(dataURI, `${fileDetails.filename}.${Extensions[extension]}`);
|
|
|
+ downloadURI(dataURI, `${fileDetails.filename}.${extension}`);
|
|
|
} catch (error) {
|
|
|
toast.error("Failed to download image!");
|
|
|
} finally {
|
|
|
toast.dismiss("toastDownload");
|
|
|
- setVisible(false);
|
|
|
+ onClose();
|
|
|
}
|
|
|
};
|
|
|
|
|
@@ -157,46 +112,52 @@ export const DownloadModal: React.FC<ModalProps> = ({ visible, setVisible }) =>
|
|
|
setFileDetails({ ...fileDetails, [key]: value });
|
|
|
|
|
|
return (
|
|
|
- <Modal visible={visible} setVisible={setVisible}>
|
|
|
- <Modal.Header>Download Image</Modal.Header>
|
|
|
- <Modal.Content>
|
|
|
- <StyledContainer>
|
|
|
- File Name
|
|
|
- <StyledColorWrapper>
|
|
|
- <FileInput
|
|
|
- value={fileDetails.filename}
|
|
|
- onChange={e => updateDetails("filename", e.target.value)}
|
|
|
- setExtension={setExtension}
|
|
|
- activeExtension={extension}
|
|
|
- extensions={Object.keys(Extensions).filter(v => isNaN(Number(v)))}
|
|
|
- />
|
|
|
- </StyledColorWrapper>
|
|
|
- </StyledContainer>
|
|
|
- <StyledContainer>
|
|
|
- Background Color
|
|
|
- <StyledColorWrapper>
|
|
|
- <TwitterPicker
|
|
|
- triangle="hide"
|
|
|
- colors={defaultColors}
|
|
|
- color={fileDetails.backgroundColor}
|
|
|
- onChange={color => updateDetails("backgroundColor", color.hex)}
|
|
|
- styles={{
|
|
|
- default: ColorPickerStyles,
|
|
|
- }}
|
|
|
- />
|
|
|
- <StyledColorIndicator color={fileDetails.backgroundColor} />
|
|
|
- </StyledColorWrapper>
|
|
|
- </StyledContainer>
|
|
|
- </Modal.Content>
|
|
|
- <Modal.Controls setVisible={setVisible}>
|
|
|
- <Button status="SECONDARY" onClick={clipboardImage}>
|
|
|
- <FiCopy size={18} /> Clipboard
|
|
|
+ <Modal opened={opened} onClose={onClose} title="Download Image" centered>
|
|
|
+ <Grid py="sm" align="end" grow>
|
|
|
+ <Grid.Col span={8}>
|
|
|
+ <TextInput
|
|
|
+ label="File Name"
|
|
|
+ value={fileDetails.filename}
|
|
|
+ onChange={e => updateDetails("filename", e.target.value)}
|
|
|
+ />
|
|
|
+ </Grid.Col>
|
|
|
+ <Grid.Col span={4}>
|
|
|
+ <SegmentedControl
|
|
|
+ value={extension}
|
|
|
+ onChange={e => setExtension(e as Extensions)}
|
|
|
+ data={[
|
|
|
+ { label: "SVG", value: Extensions.SVG },
|
|
|
+ { label: "PNG", value: Extensions.PNG },
|
|
|
+ ]}
|
|
|
+ fullWidth
|
|
|
+ />
|
|
|
+ </Grid.Col>
|
|
|
+ </Grid>
|
|
|
+ <Stack py="sm">
|
|
|
+ <ColorInput
|
|
|
+ label="Background Color"
|
|
|
+ value={fileDetails.backgroundColor}
|
|
|
+ onChange={color => updateDetails("backgroundColor", color)}
|
|
|
+ withEyeDropper={false}
|
|
|
+ />
|
|
|
+ <ColorPicker
|
|
|
+ format="rgba"
|
|
|
+ value={fileDetails.backgroundColor}
|
|
|
+ onChange={color => updateDetails("backgroundColor", color)}
|
|
|
+ swatches={swatches}
|
|
|
+ withPicker={false}
|
|
|
+ fullWidth
|
|
|
+ />
|
|
|
+ </Stack>
|
|
|
+ <Divider py="xs" />
|
|
|
+ <Group position="right">
|
|
|
+ <Button leftIcon={<FiCopy />} onClick={clipboardImage}>
|
|
|
+ Clipboard
|
|
|
</Button>
|
|
|
- <Button status="SUCCESS" onClick={exportAsImage}>
|
|
|
- <FiDownload size={18} />
|
|
|
+ <Button color="green" leftIcon={<FiDownload />} onClick={exportAsImage}>
|
|
|
Download
|
|
|
</Button>
|
|
|
- </Modal.Controls>
|
|
|
+ </Group>
|
|
|
</Modal>
|
|
|
);
|
|
|
};
|