PluginProbe
Extendify / 3.1.5
Extendify v3.1.5
3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 All 127 releases
extendify / src / Agent / components / layouts / MobileLayout.jsx

MobileLayout.jsx in Extendify 3.1.5, at src/Agent/components/layouts/MobileLayout.jsx

83 lines 2.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { useCanvasOpen } from '@agent/components/Canvas';
2 import { usePortal } from '@agent/hooks/usePortal';
3 import { useGlobalStore } from '@agent/state/global';
4 import { createPortal, useEffect } from '@wordpress/element';
5 import { __ } from '@wordpress/i18n';
6 import { chevronDown, Icon } from '@wordpress/icons';
7 import { AnimatePresence, motion } from 'framer-motion';
8
9 export const MobileLayout = ({ children }) => {
10 const mountNode = usePortal('extendify-agent-mount');
11 const { minimized, setMinimized, open, mode } = useGlobalStore();
12
13 const canvasOpen = useCanvasOpen();
14
15 const minimize = () => setMinimized(true);
16
17 // The full-screen chat would cover the canvas the user just opened.
18 useEffect(() => {
19 if (canvasOpen) setMinimized(true);
20 }, [canvasOpen, setMinimized]);
21
22 useEffect(() => {
23 if (!mountNode || minimized) return;
24 document.body.style.overflow = 'hidden';
25 return () => {
26 document.body.style.overflow = '';
27 };
28 }, [mountNode, minimized]);
29
30 // Only the frontend agent may show while the store says closed.
31 if (!mountNode || (!open && mode !== 'docked-left')) return null;
32
33 return createPortal(
34 <div
35 className={`fixed inset-0 z-max-1 items-center justify-center ${
36 minimized ? 'hidden' : 'flex'
37 }`}
38 aria-hidden={minimized ? 'true' : 'false'}
39 >
40 <div className="pointer-events-none absolute inset-0 bg-black/70" />
41 <AnimatePresence>
42 <motion.div
43 key="agent-popout-modal"
44 id="extendify-agent-popout-modal"
45 initial={{ opacity: 0 }}
46 animate={{ opacity: 1 }}
47 exit={{ y: 0, opacity: 0 }}
48 transition={{ duration: 0.4, delay: 0.1 }}
49 className="fixed bottom-[2vh] z-high flex h-full max-h-[80vh] w-full max-w-[90vw] flex-col rounded-lg border border-solid border-gray-600 bg-white shadow-2xl-flipped rtl:left-0 rtl:right-auto"
50 >
51 <div className="group flex shrink-0 items-center justify-between overflow-hidden rounded-t-[calc(0.5rem-1px)] bg-banner-main text-banner-text">
52 <div className="flex h-full grow items-center justify-between gap-1 p-0 py-3">
53 <div className="flex h-5 px-4 max-w-36 overflow-hidden">
54 <img
55 className="max-h-full max-w-full object-contain"
56 src={window.extSharedData.partnerLogo}
57 alt={window.extSharedData.partnerName}
58 />
59 </div>
60 </div>
61 <button
62 type="button"
63 className="relative z-10 flex h-full items-center rounded-none border-0 bg-banner-main py-3 pe-4 ps-2 text-banner-text outline-hidden ring-design-main focus:shadow-none focus:outline-hidden focus-visible:outline-design-main"
64 onClick={minimize}
65 >
66 <Icon
67 className="pointer-events-none fill-current leading-none"
68 icon={chevronDown}
69 size={24}
70 />
71 <span className="sr-only">
72 {__('Minimize window', 'extendify-local')}
73 </span>
74 </button>
75 </div>
76 {children}
77 </motion.div>
78 </AnimatePresence>
79 </div>,
80 mountNode,
81 );
82 };
83