Improve Preview in Survey Editor with Mobile & Desktop View (#573)

* made modal component responsive

* added tab switch

* added mobile preview mode for surveys

* did some refactors

* did some refactors

* added type defs

* ran pnpm format

* removed an unused comment

* fixed variable name typo

* fixed UI bugs and added mobile mockup to link surveys

* restored changes from fix long description PR

* fixed scroll to top issue and toggle hide bug

* fixed minor animation bug

* fixed placement issue

* re-embed restart button, make phone preview more responsive

---------

Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
This commit is contained in:
Dhruwang Jariwala
2023-08-11 14:25:49 +05:30
committed by GitHub
parent 52a09aa3ae
commit 98cdf941e6
9 changed files with 312 additions and 112 deletions
+30 -7
View File
@@ -1,20 +1,23 @@
import { getPlacementStyle } from "@/lib/preview";
import { cn } from "@formbricks/lib/cn";
import { PlacementType } from "@formbricks/types/js";
import { ReactNode, useEffect, useMemo, useState } from "react";
import { ReactNode, useEffect, useMemo, useState, useRef } from "react";
export default function Modal({
children,
isOpen,
placement,
previewMode,
highlightBorderColor,
}: {
children: ReactNode;
isOpen: boolean;
placement: PlacementType;
previewMode: string;
highlightBorderColor: string | null | undefined;
}) {
const [show, setShow] = useState(false);
const modalRef = useRef<HTMLDivElement | null>(null);
const highlightBorderColorStyle = useMemo(() => {
if (!highlightBorderColor) return {};
@@ -29,15 +32,35 @@ export default function Modal({
setShow(isOpen);
}, [isOpen]);
// scroll to top whenever question in modal changes
useEffect(() => {
if (modalRef.current) {
modalRef.current.scrollTop = 0;
}
}, [children]);
const slidingAnimationClass =
previewMode === "desktop"
? show
? "translate-x-0 opacity-100"
: "translate-x-32 opacity-0"
: previewMode === "mobile"
? show
? "bottom-0"
: "-bottom-full"
: "";
return (
<div aria-live="assertive" className="relative h-full w-full">
<div aria-live="assertive" className="relative h-full w-full overflow-hidden">
<div
ref={modalRef}
style={highlightBorderColorStyle}
className={cn(
show ? "translate-x-0 opacity-100" : "translate-x-32 opacity-0",
"pointer-events-auto absolute h-fit max-h-[90%] w-full max-w-sm overflow-hidden overflow-y-auto rounded-lg bg-white shadow-lg ring-1 ring-black ring-opacity-5 transition-all duration-500 ease-in-out",
getPlacementStyle(placement)
)}
style={highlightBorderColorStyle}>
"pointer-events-auto absolute max-h-[90%] w-full h-fit max-w-sm overflow-y-auto rounded-lg bg-white shadow-lg ring-1 ring-black ring-opacity-5 transition-all duration-500 ease-in-out",
previewMode === "desktop" ? getPlacementStyle(placement) : "max-w-full ",
slidingAnimationClass
)}>
{children}
</div>
</div>
@@ -117,7 +117,7 @@ export default function MultipleChoiceMultiQuestion({
<div className="mt-4">
<fieldset>
<legend className="sr-only">Options</legend>
<div className="xs:max-h-[41vh] relative max-h-[60vh] space-y-2 overflow-y-auto rounded-md py-0.5 pr-2">
<div className="relative space-y-2 rounded-md py-0.5">
{questionChoices.map((choice) => (
<div key={choice.id}>
<label
@@ -102,7 +102,7 @@ export default function MultipleChoiceSingleQuestion({
<div className="mt-4">
<fieldset>
<legend className="sr-only">Options</legend>
<div className="xs:max-h-[41vh] relative max-h-[60vh] space-y-2 overflow-y-auto rounded-md py-0.5 pr-2">
<div className="relative space-y-2 rounded-md py-0.5">
{questionChoices.map((choice, idx) => (
<label
key={choice.id}
+17
View File
@@ -0,0 +1,17 @@
import { ReactNode } from "react";
export default function OptionButton({
active,
icon,
onClick,
}: {
active: boolean;
icon: ReactNode;
onClick: () => void;
}) {
return (
<div className={`${active ? "rounded-full bg-slate-200" : ""} cursor-pointer`} onClick={onClick}>
{icon}
</div>
);
}