[CAL-1095] Embed modal (floating pop up button) - UI/layout/spacing issues (#8217)

* [CAL-1095] Embed modal (floating pop up button) - UI/layout/spacing issues

* requested changes

---------

Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
tweak/eslint-disable-exhaustive-deps^2
GitStart-Cal.com 2023-05-02 20:57:01 +02:00 committed by GitHub
parent 5672a721d9
commit 4f466fd95d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 279 additions and 275 deletions

View File

@ -1,5 +1,6 @@
import { Collapsible, CollapsibleContent } from "@radix-ui/react-collapsible"; import { Collapsible, CollapsibleContent } from "@radix-ui/react-collapsible";
import classNames from "classnames"; import classNames from "classnames";
import type { TFunction } from "next-i18next";
import type { NextRouter } from "next/router"; import type { NextRouter } from "next/router";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import type { MutableRefObject, RefObject } from "react"; import type { MutableRefObject, RefObject } from "react";
@ -21,11 +22,10 @@ import {
TextArea, TextArea,
TextField, TextField,
ColorPicker, ColorPicker,
Select,
} from "@calcom/ui"; } from "@calcom/ui";
import { Code, Trello, Sun, ArrowLeft } from "@calcom/ui/components/icon"; import { Code, Trello, Sun, ArrowLeft } from "@calcom/ui/components/icon";
import Select from "@components/ui/form/Select";
type EmbedType = "inline" | "floating-popup" | "element-click"; type EmbedType = "inline" | "floating-popup" | "element-click";
type EmbedFramework = "react" | "HTML"; type EmbedFramework = "react" | "HTML";
@ -305,15 +305,12 @@ const getEmbedTypeSpecificString = ({
return ""; return "";
}; };
const embeds: { const embeds = (t: TFunction) =>
illustration: React.ReactElement; (() => {
title: string; return [
subtitle: string;
type: EmbedType;
}[] = [
{ {
title: "Inline Embed", title: t("inline_embed"),
subtitle: "Loads your event type directly inline with your other website content.", subtitle: t("load_inline_content"),
type: "inline", type: "inline",
illustration: ( illustration: (
<svg <svg
@ -385,8 +382,8 @@ const embeds: {
), ),
}, },
{ {
title: "Floating pop-up button", title: t("floating_pop_up_button"),
subtitle: "Adds a floating button on your site that launches Cal in a dialog.", subtitle: t("floating_button_trigger_modal"),
type: "floating-popup", type: "floating-popup",
illustration: ( illustration: (
<svg <svg
@ -411,8 +408,8 @@ const embeds: {
), ),
}, },
{ {
title: "Pop up via element click", title: t("pop_up_element_click"),
subtitle: "Open your Cal dialog when someone clicks an element.", subtitle: t("open_dialog_with_element_click"),
type: "element-click", type: "element-click",
illustration: ( illustration: (
<svg <svg
@ -489,6 +486,8 @@ const embeds: {
), ),
}, },
]; ];
})();
const tabs = [ const tabs = [
{ {
name: "HTML", name: "HTML",
@ -534,11 +533,7 @@ ${getEmbedTypeSpecificString({ embedFramework: "HTML", embedType, calLink, previ
<!-- Cal ${embedType} embed code ends -->` <!-- Cal ${embedType} embed code ends -->`
} }
/> />
<p className="text-subtle hidden text-sm"> <p className="text-subtle hidden text-sm">{t("need_help_embedding")}</p>
{t(
"Need help? See our guides for embedding Cal on Wix, Squarespace, or WordPress, check our common questions, or explore advanced embed options."
)}
</p>
</> </>
); );
}), }),
@ -622,7 +617,7 @@ Cal("init", {origin:"${WEBAPP_URL}"});
const ThemeSelectControl = ({ children, ...props }: ControlProps<{ value: Theme; label: string }, false>) => { const ThemeSelectControl = ({ children, ...props }: ControlProps<{ value: Theme; label: string }, false>) => {
return ( return (
<components.Control {...props}> <components.Control {...props}>
<Sun className="text-subtle ml-2 h-4 w-4" /> <Sun className="text-subtle mr-2 h-4 w-4" />
{children} {children}
</components.Control> </components.Control>
); );
@ -642,7 +637,7 @@ const ChooseEmbedTypesDialogContent = () => {
</div> </div>
</div> </div>
<div className="items-start space-y-2 md:flex md:space-y-0"> <div className="items-start space-y-2 md:flex md:space-y-0">
{embeds.map((embed, index) => ( {embeds(t).map((embed, index) => (
<button <button
className="hover:bg-subtle bg-muted w-full rounded-md border border-transparent p-6 text-left hover:rounded-md ltr:mr-4 ltr:last:mr-0 rtl:ml-4 rtl:last:ml-0 lg:w-1/3" className="hover:bg-subtle bg-muted w-full rounded-md border border-transparent p-6 text-left hover:rounded-md ltr:mr-4 ltr:last:mr-0 rtl:ml-4 rtl:last:ml-0 lg:w-1/3"
key={index} key={index}
@ -692,7 +687,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
}); });
const refOfEmbedCodesRefs = useRef(embedCodeRefs); const refOfEmbedCodesRefs = useRef(embedCodeRefs);
const embed = embeds.find((embed) => embed.type === embedType); const embed = embeds(t).find((embed) => embed.type === embedType);
const [isEmbedCustomizationOpen, setIsEmbedCustomizationOpen] = useState(true); const [isEmbedCustomizationOpen, setIsEmbedCustomizationOpen] = useState(true);
const [isBookingCustomizationOpen, setIsBookingCustomizationOpen] = useState(true); const [isBookingCustomizationOpen, setIsBookingCustomizationOpen] = useState(true);
@ -806,11 +801,11 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
const FloatingPopupPositionOptions = [ const FloatingPopupPositionOptions = [
{ {
value: "bottom-right", value: "bottom-right",
label: "Bottom Right", label: "Bottom right",
}, },
{ {
value: "bottom-left", value: "bottom-left",
label: "Bottom Left", label: "Bottom left",
}, },
]; ];
@ -834,7 +829,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
</button> </button>
{embed.title} {embed.title}
</h3> </h3>
<h4 className="text-emphasis mb-6 text-sm font-normal">{embed.subtitle}</h4> <h4 className="text-subtle mb-6 text-sm font-normal">{embed.subtitle}</h4>
<div className="flex flex-col"> <div className="flex flex-col">
<div className={classNames("font-medium", embedType === "element-click" ? "hidden" : "")}> <div className={classNames("font-medium", embedType === "element-click" ? "hidden" : "")}>
<Collapsible <Collapsible
@ -844,7 +839,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
<div className={classNames(embedType === "inline" ? "block" : "hidden")}> <div className={classNames(embedType === "inline" ? "block" : "hidden")}>
{/*TODO: Add Auto/Fixed toggle from Figma */} {/*TODO: Add Auto/Fixed toggle from Figma */}
<div className="text-default mb-[9px] text-sm">Window sizing</div> <div className="text-default mb-[9px] text-sm">Window sizing</div>
<div className="justify-left flex items-center !font-normal"> <div className="justify-left mb-6 flex items-center !font-normal ">
<div className="mr-[9px]"> <div className="mr-[9px]">
<TextField <TextField
labelProps={{ className: "hidden" }} labelProps={{ className: "hidden" }}
@ -892,10 +887,10 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
</div> </div>
<div <div
className={classNames( className={classNames(
"mt-4 items-center justify-between", "items-center justify-between",
embedType === "floating-popup" ? "text-emphasis" : "hidden" embedType === "floating-popup" ? "text-emphasis" : "hidden"
)}> )}>
<div className="mb-2 text-sm">Button Text</div> <div className="mb-2 text-sm">Button text</div>
{/* Default Values should come from preview iframe */} {/* Default Values should come from preview iframe */}
<TextField <TextField
labelProps={{ className: "hidden" }} labelProps={{ className: "hidden" }}
@ -910,7 +905,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
}; };
}); });
}} }}
defaultValue="Book my Cal" defaultValue={t("book_my_cal")}
required required
/> />
</div> </div>
@ -935,14 +930,14 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
}); });
}} }}
/> />
<div className="text-default text-sm">Display Calendar Icon Button</div> <div className="text-default my-2 text-sm">Display calendar icon</div>
</div> </div>
<div <div
className={classNames( className={classNames(
"mt-4 items-center justify-between", "mt-4 items-center justify-between",
embedType === "floating-popup" ? "text-emphasis" : "hidden" embedType === "floating-popup" ? "text-emphasis" : "hidden"
)}> )}>
<div className="mb-2">Position of Button</div> <div className="mb-2">Position of button</div>
<Select <Select
onChange={(position) => { onChange={(position) => {
setPreviewState((previewState) => { setPreviewState((previewState) => {
@ -959,14 +954,12 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
options={FloatingPopupPositionOptions} options={FloatingPopupPositionOptions}
/> />
</div> </div>
<div <div className="mt-3 flex flex-col xl:flex-row xl:justify-between">
className={classNames( <div className={classNames("mt-4", embedType === "floating-popup" ? "" : "hidden")}>
"mt-4", <div className="whitespace-nowrap">Button color</div>
embedType === "floating-popup" ? "text-emphasis" : "hidden" <div className="mt-2 w-40 xl:mt-0 xl:w-full">
)}>
<div>Button Color</div>
<div className="w-full">
<ColorPicker <ColorPicker
className="w-[130px]"
popoverAlign="start" popoverAlign="start"
container={dialogContentRef?.current ?? undefined} container={dialogContentRef?.current ?? undefined}
defaultValue="#000000" defaultValue="#000000"
@ -984,14 +977,11 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
/> />
</div> </div>
</div> </div>
<div <div className={classNames("mt-4", embedType === "floating-popup" ? "" : "hidden")}>
className={classNames( <div className="whitespace-nowrap">Text color</div>
"mt-4", <div className="mt-2 mb-6 w-40 xl:mt-0 xl:w-full">
embedType === "floating-popup" ? "text-emphasis" : "hidden"
)}>
<div>Text Color</div>
<div className="w-full">
<ColorPicker <ColorPicker
className="w-[130px]"
popoverAlign="start" popoverAlign="start"
container={dialogContentRef?.current ?? undefined} container={dialogContentRef?.current ?? undefined}
defaultValue="#000000" defaultValue="#000000"
@ -1009,6 +999,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
/> />
</div> </div>
</div> </div>
</div>
</CollapsibleContent> </CollapsibleContent>
</Collapsible> </Collapsible>
</div> </div>
@ -1017,7 +1008,30 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
open={isBookingCustomizationOpen} open={isBookingCustomizationOpen}
onOpenChange={() => setIsBookingCustomizationOpen((val) => !val)}> onOpenChange={() => setIsBookingCustomizationOpen((val) => !val)}>
<CollapsibleContent> <CollapsibleContent>
<div className="mt-6 text-sm"> <div className="text-sm">
<Label className="mb-6">
<div className="mb-2">Theme</div>
<Select
className="w-full"
defaultValue={ThemeOptions[0]}
components={{
Control: ThemeSelectControl,
IndicatorSeparator: () => null,
}}
onChange={(option) => {
if (!option) {
return;
}
setPreviewState((previewState) => {
return {
...previewState,
theme: option.value,
};
});
}}
options={ThemeOptions}
/>
</Label>
<div className="mb-6 flex items-center justify-start space-x-2 rtl:space-x-reverse"> <div className="mb-6 flex items-center justify-start space-x-2 rtl:space-x-reverse">
<Switch <Switch
checked={previewState.hideEventTypeDetails} checked={previewState.hideEventTypeDetails}
@ -1056,29 +1070,6 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
</div> </div>
</Label> </Label>
))} ))}
<Label>
<div className="mb-2">Theme</div>
<Select
className="w-full"
defaultValue={ThemeOptions[0]}
components={{
Control: ThemeSelectControl,
IndicatorSeparator: () => null,
}}
onChange={(option) => {
if (!option) {
return;
}
setPreviewState((previewState) => {
return {
...previewState,
theme: option.value,
};
});
}}
options={ThemeOptions}
/>
</Label>
</div> </div>
</CollapsibleContent> </CollapsibleContent>
</Collapsible> </Collapsible>

View File

@ -1800,5 +1800,13 @@
"payment_app_commission": "Require payment ({{paymentFeePercentage}}% + {{fee, currency}} commission per transaction)", "payment_app_commission": "Require payment ({{paymentFeePercentage}}% + {{fee, currency}} commission per transaction)",
"email_invite_team": "{{email}} has been invited", "email_invite_team": "{{email}} has been invited",
"error_collecting_card": "Error collecting card", "error_collecting_card": "Error collecting card",
"image_size_limit_exceed": "Uploaded image shouldn't exceed 5mb size limit" "image_size_limit_exceed": "Uploaded image shouldn't exceed 5mb size limit",
"inline_embed": "Inline Embed",
"load_inline_content": "Loads your event type directly inline with your other website content.",
"floating_pop_up_button": "Floating pop-up button",
"floating_button_trigger_modal": "Puts a floating button on your site that triggers a modal with your event type.",
"pop_up_element_click": "Pop up via element click",
"open_dialog_with_element_click": "Open your Cal dialog when someone clicks an element.",
"need_help_embedding": "Need help? See our guides for embedding Cal on Wix, Squarespace, or WordPress, check our common questions, or explore advanced embed options.",
"book_my_cal": "Book my Cal"
} }

View File

@ -2,6 +2,7 @@ import * as Popover from "@radix-ui/react-popover";
import { useState } from "react"; import { useState } from "react";
import { HexColorInput, HexColorPicker } from "react-colorful"; import { HexColorInput, HexColorPicker } from "react-colorful";
import cx from "@calcom/lib/classNames";
import { fallBackHex, isValidHexCode } from "@calcom/lib/getBrandColours"; import { fallBackHex, isValidHexCode } from "@calcom/lib/getBrandColours";
export type ColorPickerProps = { export type ColorPickerProps = {
@ -9,6 +10,7 @@ export type ColorPickerProps = {
onChange: (text: string) => void; onChange: (text: string) => void;
container?: HTMLElement; container?: HTMLElement;
popoverAlign?: React.ComponentProps<typeof Popover.Content>["align"]; popoverAlign?: React.ComponentProps<typeof Popover.Content>["align"];
className?: string;
}; };
const ColorPicker = (props: ColorPickerProps) => { const ColorPicker = (props: ColorPickerProps) => {
@ -44,7 +46,10 @@ const ColorPicker = (props: ColorPickerProps) => {
</Popover.Root> </Popover.Root>
<HexColorInput <HexColorInput
className="border-default text-default bg-default block h-full w-full border px-3 py-2 ltr:rounded-r-md rtl:rounded-l-md sm:text-sm" className={cx(
"border-default text-default bg-default block h-full w-full border px-3 py-2 ltr:rounded-r-md rtl:rounded-l-md sm:text-sm",
props.className
)}
color={color} color={color}
onChange={(val) => { onChange={(val) => {
setColor(val); setColor(val);