{"version":3,"sources":["webpack:///./app/javascript/components/modal.js","webpack:///./app/javascript/components/spinner.js","webpack:///./app/javascript/designer/file-uploader.js","webpack:///./app/javascript/designer/icons.js","webpack:///./app/javascript/designer/save-to-s3.js"],"names":["sizes","md","lg","xl","ModalContext","createContext","portalId","Modal","children","enabled","onClose","size","focusOnProps","useState","isRendered","setIsRendered","useEffect","portalRef","useRef","Math","random","toString","substr","onClickOutside","onEscapeKey","classes","classnames","Provider","value","current","className","hidden","style","zIndex","id","ref","Hidable","rest","cx","Spinner","label","LoadingContainer","isLoading","LoadingImage","src","loaded","setLoaded","img","Image","onload","FileUploader","actionOptions","accept","container","useContext","apikey","library","add","faAlignLeft","faBold","faCopy","faCrop","faCaretDown","faGripLines","faCircle","faExpand","faEye","faImage","faItalic","faLayerGroup","faMinus","faArrowLeft","faPlus","faKerning","faSave","faPalette","faQuestion","faTintSlash","faSpinner","faTrash","faAlignCenter","faAlignRight","faBringForward","faSendBackward","faFillDrip","faDownload","faCheck","faBooks","fasRedo","fasUndo","faBan","faTimes","faUpload","faRedo","faUndo","faText","fasFillDrip","faFont","faChevronUp","faEclipse","faChevronRight","faChevronDown","faRectanglePortrait","bucket","assetHost","extensions","s3","S3","accessKeyId","secretAccessKey","upload","params","Promise","resolve","reject","err","data","uploadDesign","Body","ContentType","preview","filename","uuid","filepath","Bucket","Key","ACL","Tagging","assetUrl","then","uploadDesignFromDataUrl","dataUrl","contentType","blob","dataURLToBlob"],"mappings":"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","file":"js/3-22f670fd19b9bca90369.chunk.js","sourcesContent":["import React, { createContext, useEffect, useRef, useState } from \"react\"\nimport { FocusOn } from \"react-focus-on\"\nimport classnames from \"classnames\"\n\nconst sizes = {\n md: \"max-w-screen-md\",\n lg: \"max-w-screen-lg\",\n xl: \"max-w-screen-xl\"\n}\n\nexport const ModalContext = createContext({ portalId: null })\n\nconst Modal = ({\n children,\n enabled = true,\n onClose,\n size = \"lg\",\n focusOnProps = {}\n}) => {\n /*\n * Inside the focus trap for this modal we render a div with a ref on it\n * that is passed down via context to children that want to render things\n * at the \"root\" (to escape z-index, etc) but need to be within the focus trap\n * (so body won't work). We want this ref to be defined by the time the children\n * render so we want until the modal is rendered before rendering it's children.\n */\n const [isRendered, setIsRendered] = useState(false)\n\n useEffect(() => {\n setIsRendered(true)\n }, [])\n\n // Pass a reference to a DOM node at the bottom of the modal focus\n // area. Useful for escaping z-index but staying within the focus area.\n const portalRef = useRef()\n const portalId = useRef(\n \"modal_\" +\n Math.random()\n .toString(36)\n .substr(2, 9)\n )\n\n focusOnProps = { ...focusOnProps, enabled }\n\n if (onClose) {\n focusOnProps = {\n ...focusOnProps,\n onClickOutside: onClose,\n onEscapeKey: onClose\n }\n }\n\n const classes = classnames(\n \"z-10 shadow-lg w-full h-full\",\n \"sm:container sm:mx-auto sm:w-11/12 sm:h-auto\",\n sizes[size]\n )\n\n return (\n <ModalContext.Provider value={{ portalId: portalId.current, portalRef }}>\n <div\n className={classnames(\n \"modal z-50 fixed inset-0 flex items-center justify-center\",\n { hidden: !enabled }\n )}\n style={{ zIndex: 1025 }}\n >\n <div className=\"absolute inset-0 h-full w-full bg-gray-700 opacity-75\"></div>\n <div className={classes} style={{ zIndex: 999 }}>\n <FocusOn {...focusOnProps} className=\"h-full w-full\">\n <div\n className={classnames(\n \"rm-modal-content h-full w-full overflow-y-auto bg-white sm:rounded\"\n )}\n >\n {isRendered && children}\n </div>\n <div id={portalId.current} ref={portalRef} />\n </FocusOn>\n </div>\n </div>\n </ModalContext.Provider>\n )\n}\n\nexport default Modal\n","import React, { useEffect, useState } from \"react\"\nimport cx from \"classnames\"\n\nexport const Hidable = ({ className, hidden, ...rest }) => (\n <div className={cx(hidden && \"hidden\", className)} {...rest} />\n)\n\nexport const Spinner = ({ label }) => (\n <div className=\"h-full w-full flex flex-col items-center justify-center p-5\">\n <div className=\"ball-grid-container\">\n <div className=\"ball-grid-pulse bg-gray-500\">\n <div />\n <div />\n <div />\n <div />\n <div />\n <div />\n <div />\n <div />\n <div />\n </div>\n </div>\n {label && (\n <div className=\"mt-5 opacity-50 text-lg font-bold text-center\">\n {label}\n </div>\n )}\n </div>\n)\n\nexport const LoadingContainer = ({ isLoading, label, size, ...rest }) => (\n <>\n {isLoading && <Spinner size={size} label={label} />}\n <Hidable hidden={isLoading} {...rest} />\n </>\n)\n\nexport const LoadingImage = ({ label = \"Loading image\", src, ...rest }) => {\n const [loaded, setLoaded] = useState(false)\n\n useEffect(() => {\n if (src) {\n setLoaded(false)\n\n const img = new Image()\n img.onload = () => setLoaded(true)\n img.src = src\n }\n }, [src])\n\n return loaded ? <img src={src} {...rest} /> : <Spinner label={label} />\n}\n","import React, { useContext } from \"react\"\nimport ReactFilestack from \"filestack-react\"\nimport { ModalContext } from \"../components/modal\"\n\n/*\n * The FileStack component needs to be mounted inside\n * our designer modal focus area. It can't be rendered\n * here as it needs to escape its ancestors z-index to\n * be placed over the entire designer.\n */\nconst FileUploader = ({ actionOptions = {}, ...rest }) => {\n const { portalId } = useContext(ModalContext)\n\n actionOptions = {\n accept: \"image/*\",\n container: portalId,\n ...actionOptions\n }\n\n return (\n <ReactFilestack\n apikey=\"AQzBP0d3jTvi9yidzdGcdz\"\n actionOptions={actionOptions}\n {...rest}\n />\n )\n}\n\nexport default FileUploader\n","import { library } from \"@fortawesome/fontawesome-svg-core\"\n\nimport {\n faAlignCenter,\n faAlignLeft,\n faAlignRight,\n faArrowLeft,\n faBan,\n faBold,\n faCheck,\n faChevronDown,\n faChevronRight,\n faChevronUp,\n faCopy,\n faCrop,\n faDownload,\n faEclipse,\n faExpand,\n faEye,\n faFillDrip,\n faFont,\n faGripLines,\n faImage,\n faItalic,\n faKerning,\n faLayerGroup,\n faMinus,\n faPalette,\n faPlus,\n faQuestion,\n faRedo,\n faSave,\n faSpinner,\n faText,\n faTimes,\n faTintSlash,\n faTrash,\n faUndo,\n faUpload\n} from \"@fortawesome/pro-regular-svg-icons\"\n\nimport {\n faBooks,\n faBringForward,\n faCaretDown,\n faCircle,\n faRectanglePortrait,\n faSendBackward,\n faFillDrip as fasFillDrip,\n faRedo as fasRedo,\n faUndo as fasUndo\n} from \"@fortawesome/pro-solid-svg-icons\"\n\nlibrary.add(\n faAlignLeft,\n faBold,\n faCopy,\n faCrop,\n faCaretDown,\n faGripLines,\n faCircle,\n faExpand,\n faEye,\n faImage,\n faItalic,\n faLayerGroup,\n faMinus,\n faArrowLeft,\n faPlus,\n faKerning,\n faSave,\n faPalette,\n faQuestion,\n faTintSlash,\n faSpinner,\n faTrash,\n faAlignCenter,\n faAlignRight,\n faBringForward,\n faSendBackward,\n faFillDrip,\n faDownload,\n faCheck,\n faBooks,\n fasRedo,\n fasUndo,\n faBan,\n faTimes,\n faUpload,\n faRedo,\n faUndo,\n faText,\n fasFillDrip,\n faFont,\n faChevronUp,\n faEclipse,\n faChevronRight,\n faChevronDown,\n faRectanglePortrait\n)\n","import { dataURLToBlob } from \"blob-util\"\nimport { v4 as uuid } from \"uuid\"\nimport S3 from \"aws-sdk/clients/s3\"\n\n/*\n * This bucket has public read access with CORS enabled.\n * It also has a lifecycle policy that deletes objects\n * taggaed with tmp=true after 1 day.\n */\nconst bucket = \"personalwine.designs\"\n\n/*\n * We have a Cloudfront distribution in front of the S3\n * bucket configured to respect CORS headers and pointed\n * to be a CNAME.\n */\nconst assetHost = \"https://designs.personalwine.com\"\n\n/*\n * Map content types to file extensions.\n */\nconst extensions = {\n \"image/jpg\": \"jpg\",\n \"image/png\": \"png\"\n}\n\n/*\n * PersonalWineWeb IAM user w/ access to PutObject and PutObjectACL on our S3 buckets.\n */\nconst s3 = new S3({\n accessKeyId: \"AKIAY2YKAVY67USO5DVE\",\n secretAccessKey: \"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\"\n})\n\n// Wrap upload with a Promise\nconst upload = params =>\n new Promise((resolve, reject) => {\n s3.upload(params, (err, data) => {\n if (err) {\n reject(err)\n } else {\n resolve(data)\n }\n })\n })\n\n/*\n * Our S3 bucket is configured so objects tagged with tmp=true will\n * be deleted after one day. We use this ONLY for temporary images\n * we want to store to generate previews. Obviously this tag shouldn't\n * be used for the final save.\n */\nexport const uploadDesign = (Body, ContentType, preview = false) => {\n const filename = `${uuid()}.${extensions[ContentType]}`\n const filepath = (preview ? \"preview/\" : \"final/\") + filename\n const params = {\n Body,\n ContentType,\n Bucket: bucket,\n Key: filepath,\n ACL: \"public-read\"\n }\n\n if (preview) {\n params.Tagging = \"tmp=true\"\n }\n\n // Get the CDN path to the image\n const assetUrl = `${assetHost}/${filepath}`\n\n return upload(params).then(() => assetUrl)\n}\n\nexport const uploadDesignFromDataUrl = (\n dataUrl,\n contentType,\n preview = false\n) => {\n const blob = dataURLToBlob(dataUrl)\n return uploadDesign(blob, contentType, preview)\n}\n"],"sourceRoot":""}