index.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import React from "react";
  2. import toast from "react-hot-toast";
  3. import styled from "styled-components";
  4. import { Modal, ModalProps } from "src/components/Modal";
  5. import { Button } from "src/components/Button";
  6. import { BiErrorAlt } from "react-icons/bi";
  7. import { compress } from "compress-json";
  8. import useConfig from "src/hooks/store/useConfig";
  9. import { Input } from "src/components/Input";
  10. import { baseURL } from "src/constants/data";
  11. const StyledWarning = styled.p``;
  12. const StyledErrorWrapper = styled.div`
  13. display: flex;
  14. flex-direction: column;
  15. align-items: center;
  16. justify-content: center;
  17. color: ${({ theme }) => theme.TEXT_DANGER};
  18. font-weight: 600;
  19. `;
  20. const StyledFlex = styled.div`
  21. display: flex;
  22. gap: 12px;
  23. `;
  24. const StyledContainer = styled.div`
  25. display: flex;
  26. flex-direction: column;
  27. gap: 16px;
  28. padding: 12px 0;
  29. border-top: 1px solid ${({ theme }) => theme.BACKGROUND_MODIFIER_ACCENT};
  30. font-size: 12px;
  31. line-height: 16px;
  32. font-weight: 600;
  33. text-transform: uppercase;
  34. color: ${({ theme }) => theme.INTERACTIVE_NORMAL};
  35. &:first-of-type {
  36. padding-top: 0;
  37. border: none;
  38. }
  39. `;
  40. export const ShareModal: React.FC<ModalProps> = ({ visible, setVisible }) => {
  41. const json = useConfig((state) => state.json);
  42. const [encodedJson, setEncodedJson] = React.useState("");
  43. const embedText = `<iframe src="${baseURL}/widget?json=${encodedJson}" width="512" height="384" style="border: 2px solid #b9bbbe; border-radius: 6px;"></iframe>`;
  44. const shareURL = `${baseURL}/editor?json=${encodedJson}`;
  45. React.useEffect(() => {
  46. if (visible) {
  47. const jsonEncode = compress(JSON.parse(json));
  48. const jsonString = JSON.stringify(jsonEncode);
  49. setEncodedJson(encodeURIComponent(jsonString));
  50. }
  51. }, [json, visible]);
  52. const handleShare = (value: string) => {
  53. navigator.clipboard.writeText(value);
  54. toast.success(`Link copied to clipboard.`);
  55. setVisible(false);
  56. };
  57. return (
  58. <Modal visible={visible} setVisible={setVisible}>
  59. <Modal.Header>Create a Share Link</Modal.Header>
  60. <Modal.Content>
  61. {encodedJson.length > 5000 ? (
  62. <StyledErrorWrapper>
  63. <BiErrorAlt size={60} />
  64. <StyledWarning>
  65. Link size exceeds 5000 characters, unable to generate link for
  66. file of this size!
  67. </StyledWarning>
  68. </StyledErrorWrapper>
  69. ) : (
  70. <>
  71. <StyledContainer>
  72. Share Link
  73. <StyledFlex>
  74. <Input value={shareURL} type="url" readOnly />
  75. <Button
  76. status="SECONDARY"
  77. onClick={() => handleShare(shareURL)}
  78. >
  79. Copy
  80. </Button>
  81. </StyledFlex>
  82. </StyledContainer>
  83. <StyledContainer>
  84. Embed into your website
  85. <StyledFlex>
  86. <Input value={embedText} type="url" readOnly />
  87. <Button
  88. status="SECONDARY"
  89. onClick={() => handleShare(embedText)}
  90. >
  91. Copy
  92. </Button>
  93. </StyledFlex>
  94. </StyledContainer>
  95. </>
  96. )}
  97. </Modal.Content>
  98. <Modal.Controls setVisible={setVisible}></Modal.Controls>
  99. </Modal>
  100. );
  101. };