feat: Add full screen preview feature to Survey Editor

feat: Add full screen preview feature to Survey Editor
This commit is contained in:
Johannes
2023-10-08 13:01:42 +05:30
committed by GitHub
4 changed files with 143 additions and 53 deletions

View File

@@ -234,7 +234,7 @@ export default function Navigation({
return (
<>
{product && (
<nav className="top-0 z-10 w-full border-b border-slate-200 bg-white">
<nav className="top-0 w-full border-b border-slate-200 bg-white">
{environment?.type === "development" && (
<div className="h-6 w-full bg-[#A33700] p-0.5 text-center text-sm text-white">
You&apos;re in development mode. Use it to test surveys, actions and attributes.

View File

@@ -8,7 +8,13 @@ import type { TProduct } from "@formbricks/types/v1/product";
import { TSurvey } from "@formbricks/types/v1/surveys";
import { Button } from "@formbricks/ui";
import { ArrowPathRoundedSquareIcon } from "@heroicons/react/24/outline";
import { ComputerDesktopIcon, DevicePhoneMobileIcon } from "@heroicons/react/24/solid";
import {
ComputerDesktopIcon,
DevicePhoneMobileIcon,
ArrowsPointingOutIcon,
ArrowsPointingInIcon,
} from "@heroicons/react/24/solid";
import { AnimatePresence, Variants, motion } from "framer-motion";
import { useEffect, useRef, useState } from "react";
type TPreviewType = "modal" | "fullwidth" | "email";
@@ -24,6 +30,65 @@ interface PreviewSurveyProps {
let surveyNameTemp;
const previewParentContainerVariant: Variants = {
expanded: {
position: "fixed",
height: "100%",
width: "100%",
backgroundColor: "rgba(0, 0, 0, 0.4)",
backdropFilter: "blur(15px)",
left: 0,
top: 0,
zIndex: 1040,
transition: {
ease: "easeIn",
duration: 0.001,
},
},
shrink: {
display: "none",
position: "fixed",
backgroundColor: "rgba(0, 0, 0, 0.0)",
backdropFilter: "blur(0px)",
transition: {
duration: 0,
},
zIndex: -1,
},
};
const previewScreenVariants: Variants = {
expanded: {
right: "5%",
bottom: "2%",
width: "90%",
height: "90%",
zIndex: 1050,
boxShadow: "0px 4px 5px 4px rgba(169, 169, 169, 0.25)",
transition: {
ease: "easeInOut",
duration: 0.3,
},
},
expanded_with_fixed_positioning: {
zIndex: 1050,
position: "fixed",
right: "5%",
bottom: "5%",
width: "90%",
height: "90%",
transition: {
ease: "easeOut",
duration: 0.2,
},
},
shrink: {
display: "relative",
width: ["83.33%"],
height: ["95%"],
},
};
export default function PreviewSurvey({
setActiveQuestionId,
activeQuestionId,
@@ -33,8 +98,10 @@ export default function PreviewSurvey({
environment,
}: PreviewSurveyProps) {
const [isModalOpen, setIsModalOpen] = useState(true);
const [isFullScreenPreview, setIsFullScreenPreview] = useState(false);
const [widgetSetupCompleted, setWidgetSetupCompleted] = useState(false);
const [previewMode, setPreviewMode] = useState("desktop");
const [previewPosition, setPreviewPosition] = useState("relative");
const ContentRef = useRef<HTMLDivElement | null>(null);
const { productOverwrites } = survey || {};
@@ -99,7 +166,22 @@ export default function PreviewSurvey({
return (
<div className="flex h-full w-full flex-col items-center justify-items-center">
<div className="relative flex h-[95%] max-h-[95%] w-5/6 items-center justify-center rounded-lg border border-slate-300 bg-slate-200">
<motion.div
variants={previewParentContainerVariant}
className="fixed hidden h-[95%] w-5/6"
animate={isFullScreenPreview ? "expanded" : "shrink"}
/>
<motion.div
layout
variants={previewScreenVariants}
animate={
isFullScreenPreview
? previewPosition === "relative"
? "expanded"
: "expanded_with_fixed_positioning"
: "shrink"
}
className="relative flex h-[95] max-h-[95%] w-5/6 items-center justify-center rounded-lg border border-slate-300 bg-slate-200">
{previewMode === "mobile" && (
<>
<div className="absolute right-0 top-0 m-2">
@@ -153,7 +235,26 @@ export default function PreviewSurvey({
</div>
<p className="ml-4 flex w-full justify-between font-mono text-sm text-slate-400">
{previewType === "modal" ? "Your web app" : "Preview"}
<ResetProgressButton resetQuestionProgress={resetQuestionProgress} />
<div className="flex items-center">
{isFullScreenPreview ? (
<ArrowsPointingInIcon
className="mr-2 h-4 w-4 cursor-pointer"
onClick={() => {
setIsFullScreenPreview(false);
setPreviewPosition("relative");
}}
/>
) : (
<ArrowsPointingOutIcon
className="mr-2 h-4 w-4 cursor-pointer"
onClick={() => {
setIsFullScreenPreview(true);
setTimeout(() => setPreviewPosition("fixed"), 300);
}}
/>
)}
<ResetProgressButton resetQuestionProgress={resetQuestionProgress} />
</div>
</p>
</div>
@@ -173,7 +274,7 @@ export default function PreviewSurvey({
/>
</Modal>
) : (
<div className="flex flex-grow flex-col overflow-y-auto" ref={ContentRef}>
<div className="flex flex-grow flex-col overflow-y-auto rounded-b-lg" ref={ContentRef}>
<div className="flex w-full flex-grow flex-col items-center justify-center bg-white p-4 py-6">
<div className="w-full max-w-md">
<SurveyInline
@@ -190,7 +291,8 @@ export default function PreviewSurvey({
)}
</div>
)}
</div>
</motion.div>
{/* for toggling between mobile and desktop mode */}
<div className="mt-2 flex rounded-full border-2 border-slate-300 p-1">
<TabOption

View File

@@ -32,7 +32,8 @@
"@t3-oss/env-nextjs": "^0.7.0",
"bcryptjs": "^2.4.3",
"encoding": "^0.1.13",
"eslint-config-next": "^13.5.4",
"eslint-config-next": "^13.5.3",
"framer-motion": "10.16.4",
"googleapis": "^126.0.1",
"jsonwebtoken": "^9.0.2",
"lodash": "^4.17.21",

79
pnpm-lock.yaml generated
View File

@@ -28,7 +28,7 @@ importers:
version: 3.12.7
turbo:
specifier: latest
version: 1.10.15
version: 1.10.12
apps/demo:
dependencies:
@@ -287,8 +287,11 @@ importers:
specifier: ^0.1.13
version: 0.1.13
eslint-config-next:
specifier: ^13.5.4
specifier: ^13.5.3
version: 13.5.4(eslint@8.50.0)(typescript@5.2.2)
framer-motion:
specifier: 10.16.4
version: 10.16.4(react-dom@18.2.0)(react@18.2.0)
googleapis:
specifier: ^126.0.1
version: 126.0.1(encoding@0.1.13)
@@ -456,7 +459,7 @@ importers:
version: 9.0.0(eslint@8.50.0)
eslint-config-turbo:
specifier: latest
version: 1.10.15(eslint@8.50.0)
version: 1.10.12(eslint@8.50.0)
eslint-plugin-react:
specifier: 7.33.2
version: 7.33.2(eslint@8.50.0)
@@ -12530,13 +12533,13 @@ packages:
resolution: {integrity: sha512-NB/L/1Y30qyJcG5xZxCJKW/+bqyj+llbcCwo9DEz8bESIP0SLTOQ8T1DWCCFc+wJ61AMEstj4511PSScqMMfCw==}
dev: true
/eslint-config-turbo@1.10.15(eslint@8.50.0):
resolution: {integrity: sha512-76mpx2x818JZE26euen14utYcFDxOahZ9NaWA+6Xa4pY2ezVKVschuOxS96EQz3o3ZRSmcgBOapw/gHbN+EKxQ==}
/eslint-config-turbo@1.10.12(eslint@8.50.0):
resolution: {integrity: sha512-z3jfh+D7UGYlzMWGh+Kqz++hf8LOE96q3o5R8X4HTjmxaBWlLAWG+0Ounr38h+JLR2TJno0hU9zfzoPNkR9BdA==}
peerDependencies:
eslint: '>6.6.0'
dependencies:
eslint: 8.50.0
eslint-plugin-turbo: 1.10.15(eslint@8.50.0)
eslint-plugin-turbo: 1.10.12(eslint@8.50.0)
dev: true
/eslint-import-resolver-node@0.3.9:
@@ -12742,8 +12745,8 @@ packages:
semver: 6.3.1
string.prototype.matchall: 4.0.8
/eslint-plugin-turbo@1.10.15(eslint@8.50.0):
resolution: {integrity: sha512-Tv4QSKV/U56qGcTqS/UgOvb9HcKFmWOQcVh3HEaj7of94lfaENgfrtK48E2CckQf7amhKs1i+imhCsNCKjkQyA==}
/eslint-plugin-turbo@1.10.12(eslint@8.50.0):
resolution: {integrity: sha512-uNbdj+ohZaYo4tFJ6dStRXu2FZigwulR1b3URPXe0Q8YaE7thuekKNP+54CHtZPH9Zey9dmDx5btAQl9mfzGOw==}
peerDependencies:
eslint: '>6.6.0'
dependencies:
@@ -19720,23 +19723,6 @@ packages:
postcss: 8.4.27
yaml: 2.3.1
/postcss-load-config@4.0.1(postcss@8.4.31):
resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==}
engines: {node: '>= 14'}
peerDependencies:
postcss: '>=8.0.9'
ts-node: '>=9.0.0'
peerDependenciesMeta:
postcss:
optional: true
ts-node:
optional: true
dependencies:
lilconfig: 2.1.0
postcss: 8.4.31
yaml: 2.3.1
dev: true
/postcss-loader@4.3.0(postcss@8.4.27)(webpack@4.46.0):
resolution: {integrity: sha512-M/dSoIiNDOo8Rk0mUqoj4kpGq91gcxCfb9PoyZVdZ76/AuhxylHDYZblNE8o+EQ9AMSASeMFEKxZf5aU6wlx1Q==}
engines: {node: '>= 10.13.0'}
@@ -24177,7 +24163,7 @@ packages:
execa: 5.1.1
globby: 11.1.0
joycon: 3.1.1
postcss-load-config: 4.0.1(postcss@8.4.31)
postcss-load-config: 4.0.1(postcss@8.4.27)
resolve-from: 5.0.0
rollup: 3.29.4
source-map: 0.8.0-beta.0
@@ -24233,64 +24219,65 @@ packages:
dependencies:
safe-buffer: 5.2.1
/turbo-darwin-64@1.10.15:
resolution: {integrity: sha512-Sik5uogjkRTe1XVP9TC2GryEMOJCaKE2pM/O9uLn4koQDnWKGcLQv+mDU+H+9DXvKLnJnKCD18OVRkwK5tdpoA==}
/turbo-darwin-64@1.10.12:
resolution: {integrity: sha512-vmDfGVPl5/aFenAbOj3eOx3ePNcWVUyZwYr7taRl0ZBbmv2TzjRiFotO4vrKCiTVnbqjQqAFQWY2ugbqCI1kOQ==}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/turbo-darwin-arm64@1.10.15:
resolution: {integrity: sha512-xwqyFDYUcl2xwXyGPmHkmgnNm4Cy0oNzMpMOBGRr5x64SErS7QQLR4VHb0ubiR+VAb8M+ECPklU6vD1Gm+wekg==}
/turbo-darwin-arm64@1.10.12:
resolution: {integrity: sha512-3JliEESLNX2s7g54SOBqqkqJ7UhcOGkS0ywMr5SNuvF6kWVTbuUq7uBU/sVbGq8RwvK1ONlhPvJne5MUqBCTCQ==}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/turbo-linux-64@1.10.15:
resolution: {integrity: sha512-dM07SiO3RMAJ09Z+uB2LNUSkPp3I1IMF8goH5eLj+d8Kkwoxd/+qbUZOj9RvInyxU/IhlnO9w3PGd3Hp14m/nA==}
/turbo-linux-64@1.10.12:
resolution: {integrity: sha512-siYhgeX0DidIfHSgCR95b8xPee9enKSOjCzx7EjTLmPqPaCiVebRYvbOIYdQWRqiaKh9yfhUtFmtMOMScUf1gg==}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/turbo-linux-arm64@1.10.15:
resolution: {integrity: sha512-MkzKLkKYKyrz4lwfjNXH8aTny5+Hmiu4SFBZbx+5C0vOlyp6fV5jZANDBvLXWiDDL4DSEAuCEK/2cmN6FVH1ow==}
/turbo-linux-arm64@1.10.12:
resolution: {integrity: sha512-K/ZhvD9l4SslclaMkTiIrnfcACgos79YcAo4kwc8bnMQaKuUeRpM15sxLpZp3xDjDg8EY93vsKyjaOhdFG2UbA==}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/turbo-windows-64@1.10.15:
resolution: {integrity: sha512-3TdVU+WEH9ThvQGwV3ieX/XHebtYNHv9HARHauPwmVj3kakoALkpGxLclkHFBLdLKkqDvmHmXtcsfs6cXXRHJg==}
/turbo-windows-64@1.10.12:
resolution: {integrity: sha512-7FSgSwvktWDNOqV65l9AbZwcoueAILeE4L7JvjauNASAjjbuzXGCEq5uN8AQU3U5BOFj4TdXrVmO2dX+lLu8Zg==}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/turbo-windows-arm64@1.10.15:
resolution: {integrity: sha512-l+7UOBCbfadvPMYsX08hyLD+UIoAkg6ojfH+E8aud3gcA1padpjCJTh9gMpm3QdMbKwZteT5uUM+wyi6Rbbyww==}
/turbo-windows-arm64@1.10.12:
resolution: {integrity: sha512-gCNXF52dwom1HLY9ry/cneBPOKTBHhzpqhMylcyvJP0vp9zeMQQkt6yjYv+6QdnmELC92CtKNp2FsNZo+z0pyw==}
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/turbo@1.10.15:
resolution: {integrity: sha512-mKKkqsuDAQy1wCCIjCdG+jOCwUflhckDMSRoeBPcIL/CnCl7c5yRDFe7SyaXloUUkt4tUR0rvNIhVCcT7YeQpg==}
/turbo@1.10.12:
resolution: {integrity: sha512-WM3+jTfQWnB9W208pmP4oeehZcC6JQNlydb/ZHMRrhmQa+htGhWLCzd6Q9rLe0MwZLPpSPFV2/bN5egCLyoKjQ==}
hasBin: true
requiresBuild: true
optionalDependencies:
turbo-darwin-64: 1.10.15
turbo-darwin-arm64: 1.10.15
turbo-linux-64: 1.10.15
turbo-linux-arm64: 1.10.15
turbo-windows-64: 1.10.15
turbo-windows-arm64: 1.10.15
turbo-darwin-64: 1.10.12
turbo-darwin-arm64: 1.10.12
turbo-linux-64: 1.10.12
turbo-linux-arm64: 1.10.12
turbo-windows-64: 1.10.12
turbo-windows-arm64: 1.10.12
dev: true
/tw-to-css@0.0.11: