diff --git a/.github/workflows/npm-publish-beta.yml b/.github/workflows/npm-publish-beta.yml index 7b29e512..d03b58cb 100644 --- a/.github/workflows/npm-publish-beta.yml +++ b/.github/workflows/npm-publish-beta.yml @@ -1,9 +1,7 @@ name: Publish NPM Beta Package on: - pull_request: - types: - - closed + push: branches: - master diff --git a/.storybook/preview.js b/.storybook/preview.js index 120376b3..dc75aff7 100644 --- a/.storybook/preview.js +++ b/.storybook/preview.js @@ -50,6 +50,12 @@ export const globalTypes = { defaultValue: false, control: { type: "boolean" }, }, + unifyMediaContent: { + name: "Unify media content", + description: "Set IFrame to eligible media contents", + defaultValue: false, + control: { type: "boolean" }, + }, }; const options = { @@ -67,6 +73,7 @@ const options = { wizardStepButtons: true, enableForwardSkip: true, startingStep: 1, + unifyMediaContent: true, debugMode: false, users: [ { id: "http://fel.cvut.cz/people/max-chopart", label: "Max Chopart" }, diff --git a/package-lock.json b/package-lock.json index c4c34d5b..ff13dff1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "prop-types": "^15.7.2", "react-bootstrap": "1.0.1", "react-datepicker": "^4.2.1", + "react-image-zooom": "^1.0.4", "react-intl": "^5.24.6", "react-loader-spinner": "^5.1.0", "react-select": "^3.1.0", @@ -7482,6 +7483,22 @@ "react-docgen": "^5.0.0" } }, + "node_modules/babel-plugin-styled-components": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.0.7.tgz", + "integrity": "sha512-i7YhvPgVqRKfoQ66toiZ06jPNA3p6ierpfUuEWxNF+fV27Uv5gxBkf8KZLHUCc1nFA9j6+80pYoIpqCeyW3/bA==", + "peer": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.16.0", + "@babel/helper-module-imports": "^7.16.0", + "babel-plugin-syntax-jsx": "^6.18.0", + "lodash": "^4.17.11", + "picomatch": "^2.3.0" + }, + "peerDependencies": { + "styled-components": ">= 2" + } + }, "node_modules/babel-plugin-syntax-jsx": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", @@ -8432,6 +8449,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/camelize": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", + "integrity": "sha512-W2lPwkBkMZwFlPCXhIlYgxu+7gC/NUlCtdK652DAJ1JdgV0sTrvuPFshNPrFa1TY2JOkLhgdeEBplB4ezEa+xg==", + "peer": true + }, "node_modules/caniuse-api": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", @@ -10361,6 +10384,15 @@ "source-map-resolve": "^0.6.0" } }, + "node_modules/css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU=", + "peer": true, + "engines": { + "node": ">=4" + } + }, "node_modules/css-loader": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz", @@ -10451,6 +10483,17 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/css-to-react-native": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.0.0.tgz", + "integrity": "sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ==", + "peer": true, + "dependencies": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, "node_modules/css-tree": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", @@ -21846,6 +21889,16 @@ "react-dom": "^16.6.0 || ^17.0.0" } }, + "node_modules/react-image-zooom": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/react-image-zooom/-/react-image-zooom-1.0.4.tgz", + "integrity": "sha512-Mqi++XgazQ1aG9P2rDprKTUQr/h/VNMrbNGIWtxfgi2dCI2oqI/Gx/9MP5nLyrWityzbGccxWZpuCj1DxAUo/Q==", + "peerDependencies": { + "react": "^17.0.1", + "react-dom": "^17.0.1", + "styled-components": "^5.2.1" + } + }, "node_modules/react-input-autosize": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-3.0.0.tgz", @@ -21900,8 +21953,7 @@ "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, "node_modules/react-lifecycles-compat": { "version": "3.0.4", @@ -23794,8 +23846,7 @@ "node_modules/shallowequal": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", - "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", - "dev": true + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" }, "node_modules/shasum": { "version": "1.0.2", @@ -25036,6 +25087,46 @@ "tslib": "^2.1.0" } }, + "node_modules/styled-components": { + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.5.tgz", + "integrity": "sha512-ndETJ9RKaaL6q41B69WudeqLzOpY1A/ET/glXkNZ2T7dPjPqpPCXXQjDFYZWwNnE5co0wX+gTCqx9mfxTmSIPg==", + "hasInstallScript": true, + "peer": true, + "dependencies": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/traverse": "^7.4.5", + "@emotion/is-prop-valid": "^1.1.0", + "@emotion/stylis": "^0.8.4", + "@emotion/unitless": "^0.7.4", + "babel-plugin-styled-components": ">= 1.12.0", + "css-to-react-native": "^3.0.0", + "hoist-non-react-statics": "^3.0.0", + "shallowequal": "^1.1.0", + "supports-color": "^5.5.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/styled-components" + }, + "peerDependencies": { + "react": ">= 16.8.0", + "react-dom": ">= 16.8.0", + "react-is": ">= 16.8.0" + } + }, + "node_modules/styled-components/node_modules/@emotion/is-prop-valid": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.1.2.tgz", + "integrity": "sha512-3QnhqeL+WW88YjYbQL5gUIkthuMw7a0NGbZ7wfFVk2kg/CK5w8w5FFa0RzWjyY1+sujN0NWbtSHH6OJmWHtJpQ==", + "peer": true, + "dependencies": { + "@emotion/memoize": "^0.7.4" + } + }, "node_modules/subarg": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", @@ -33570,6 +33661,19 @@ "react-docgen": "^5.0.0" } }, + "babel-plugin-styled-components": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.0.7.tgz", + "integrity": "sha512-i7YhvPgVqRKfoQ66toiZ06jPNA3p6ierpfUuEWxNF+fV27Uv5gxBkf8KZLHUCc1nFA9j6+80pYoIpqCeyW3/bA==", + "peer": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.16.0", + "@babel/helper-module-imports": "^7.16.0", + "babel-plugin-syntax-jsx": "^6.18.0", + "lodash": "^4.17.11", + "picomatch": "^2.3.0" + } + }, "babel-plugin-syntax-jsx": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", @@ -34346,6 +34450,12 @@ "quick-lru": "^4.0.1" } }, + "camelize": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", + "integrity": "sha512-W2lPwkBkMZwFlPCXhIlYgxu+7gC/NUlCtdK652DAJ1JdgV0sTrvuPFshNPrFa1TY2JOkLhgdeEBplB4ezEa+xg==", + "peer": true + }, "caniuse-api": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", @@ -35918,6 +36028,12 @@ } } }, + "css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU=", + "peer": true + }, "css-loader": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz", @@ -35984,6 +36100,17 @@ "nth-check": "^2.0.1" } }, + "css-to-react-native": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.0.0.tgz", + "integrity": "sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ==", + "peer": true, + "requires": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, "css-tree": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", @@ -44654,6 +44781,12 @@ "shallowequal": "^1.1.0" } }, + "react-image-zooom": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/react-image-zooom/-/react-image-zooom-1.0.4.tgz", + "integrity": "sha512-Mqi++XgazQ1aG9P2rDprKTUQr/h/VNMrbNGIWtxfgi2dCI2oqI/Gx/9MP5nLyrWityzbGccxWZpuCj1DxAUo/Q==", + "requires": {} + }, "react-input-autosize": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-3.0.0.tgz", @@ -44693,8 +44826,7 @@ "react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, "react-lifecycles-compat": { "version": "3.0.4", @@ -46198,8 +46330,7 @@ "shallowequal": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", - "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", - "dev": true + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" }, "shasum": { "version": "1.0.2", @@ -47204,6 +47335,35 @@ "tslib": "^2.1.0" } }, + "styled-components": { + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.5.tgz", + "integrity": "sha512-ndETJ9RKaaL6q41B69WudeqLzOpY1A/ET/glXkNZ2T7dPjPqpPCXXQjDFYZWwNnE5co0wX+gTCqx9mfxTmSIPg==", + "peer": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/traverse": "^7.4.5", + "@emotion/is-prop-valid": "^1.1.0", + "@emotion/stylis": "^0.8.4", + "@emotion/unitless": "^0.7.4", + "babel-plugin-styled-components": ">= 1.12.0", + "css-to-react-native": "^3.0.0", + "hoist-non-react-statics": "^3.0.0", + "shallowequal": "^1.1.0", + "supports-color": "^5.5.0" + }, + "dependencies": { + "@emotion/is-prop-valid": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.1.2.tgz", + "integrity": "sha512-3QnhqeL+WW88YjYbQL5gUIkthuMw7a0NGbZ7wfFVk2kg/CK5w8w5FFa0RzWjyY1+sujN0NWbtSHH6OJmWHtJpQ==", + "peer": true, + "requires": { + "@emotion/memoize": "^0.7.4" + } + } + } + }, "subarg": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", diff --git a/package.json b/package.json index 669cce0e..9a791c3c 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "prop-types": "^15.7.2", "react-bootstrap": "1.0.1", "react-datepicker": "^4.2.1", + "react-image-zooom": "^1.0.4", "react-intl": "^5.24.6", "react-loader-spinner": "^5.1.0", "react-select": "^3.1.0", diff --git a/src/components/LinkIcon.jsx b/src/components/LinkIcon.jsx index d3169e60..84189017 100644 --- a/src/components/LinkIcon.jsx +++ b/src/components/LinkIcon.jsx @@ -4,7 +4,7 @@ import ExternalLink from "../styles/icons/ExternalLink"; import IconOverlay from "./IconOverlay"; const LinkIcon = (props) => { - return ( + return props.showOverlay ? ( { + ) : ( + + + ); }; @@ -30,12 +38,14 @@ LinkIcon.propTypes = { iconClass: PropTypes.string, overlayPlacement: PropTypes.string, absolutePosition: PropTypes.bool, + showOverlay: PropTypes.bool, }; LinkIcon.defaultProps = { iconClassContainer: "", iconClass: "", absolutePosition: true, + showOverlay: true, }; export default LinkIcon; diff --git a/src/components/MediaContent.tsx b/src/components/MediaContent.tsx index 18391823..17ee34bc 100644 --- a/src/components/MediaContent.tsx +++ b/src/components/MediaContent.tsx @@ -1,48 +1,127 @@ -import React from "react"; +import React, { useContext } from "react"; import Constants from "../constants/Constants"; +import LinkIcon from "./LinkIcon"; +// @ts-ignore +import ImageZoom from "react-image-zooom"; +import { ConfigurationContext } from "../contexts/ConfigurationContext"; interface Props { question: object; } +const YOUTUBE_URL = "https://www.youtube.com/"; +const YOUTUBE_WATCH_URL_PARAMETER = "watch?v="; +const GOOGLE_DRIVE_URL = "https://drive.google.com/"; +const EMBED_URL_PARAMETER = "embed/"; +const GOOGLE_DRIVE_FILE_PATH = "/file/d/"; +const GOOGLE_DRIVE = "uc?export=view&id="; + const MediaContent = ({ question }: Props) => { - const renderMedia = () => { + // @ts-ignore + const { options } = useContext(ConfigurationContext); + + const isGoogleDriveImage = (mediaContentUrl: string) => { + return ( + mediaContentUrl.includes(GOOGLE_DRIVE_FILE_PATH) && + mediaContentUrl.includes(GOOGLE_DRIVE_URL) + ); + }; + + const isYoutubeVideo = (mediaContentUrl: string) => { + return ( + mediaContentUrl.includes(YOUTUBE_URL) && + (mediaContentUrl.includes(YOUTUBE_WATCH_URL_PARAMETER) || + mediaContentUrl.includes(EMBED_URL_PARAMETER)) + ); + }; + + const getMediaId = (mediaContentUrl: string) => { + if (isGoogleDriveImage(mediaContentUrl)) { + return mediaContentUrl.substring( + mediaContentUrl.indexOf(GOOGLE_DRIVE_FILE_PATH) + + GOOGLE_DRIVE_FILE_PATH.length, + mediaContentUrl.lastIndexOf("/") + ); + } + if (isYoutubeVideo(mediaContentUrl)) { + return mediaContentUrl.substring( + mediaContentUrl.indexOf(YOUTUBE_WATCH_URL_PARAMETER) + + YOUTUBE_WATCH_URL_PARAMETER.length + ); + } + }; + + const getEmbedLink = (mediaContentUrl: string) => { + if (isGoogleDriveImage(mediaContentUrl)) { + return GOOGLE_DRIVE_URL + GOOGLE_DRIVE + getMediaId(mediaContentUrl); + } + if ( + isYoutubeVideo(mediaContentUrl) && + !mediaContentUrl.includes(EMBED_URL_PARAMETER) + ) { + return YOUTUBE_URL + EMBED_URL_PARAMETER + getMediaId(mediaContentUrl); + } + return mediaContentUrl; + }; + + const getMediaType = (mediaContentUrl: string) => { + if ( + isYoutubeVideo(mediaContentUrl) || + (isGoogleDriveImage(mediaContentUrl) && options.unifyMediaContent) + ) { + return ( +
+ +