starting dragable bottom panel

This commit is contained in:
2024-02-02 17:14:51 +05:00
parent 2f8aa5c516
commit a244e7b883
26 changed files with 379 additions and 73 deletions
@@ -1,4 +1,4 @@
import BackIcon from "../../../icons/BackIcon";
import BackIcon from "../icons/BackIcon";
const BackButton = () => {
return (
+15
View File
@@ -0,0 +1,15 @@
import GoBackIcon from "../icons/GoBackIcon";
type GoBackButtonProps = {
onClick?: () => void;
};
const GoBackButton = ({ onClick }: GoBackButtonProps) => {
return (
<button onClick={onClick} className="flex items-center justify-center p-2">
<GoBackIcon />
</button>
);
};
export default GoBackButton;
+20 -12
View File
@@ -2,7 +2,11 @@ import { useEffect, useState } from "react";
import LoadingIcon from "../icons/LoadingIcon";
import { loadingMessages } from "../consts/loading";
const LoaderModal = () => {
type LoaderModalProps = {
isSimleLoader?: boolean;
};
const LoaderModal = ({ isSimleLoader = false }: LoaderModalProps) => {
const [offset, setOffset] = useState(0);
useEffect(() => {
@@ -24,18 +28,22 @@ const LoaderModal = () => {
return (
<div className="bg-[#F3F2F0] h-full w-full flex justify-center items-center flex-col fixed z-30">
<LoadingIcon className="animate-spin w-16" />
<div className="relative h-7 overflow-hidden">
<div
className="flex flex-col items-center duration-300"
style={{ transform: `translateY(${offset * 28}px)` }}
>
{loadingMessages.map((message) => (
<div className="h-7" key={message.id}>
{message.value}
</div>
))}
{!isSimleLoader ? (
<div className="relative h-7 overflow-hidden">
<div
className="flex flex-col items-center duration-300"
style={{ transform: `translateY(${offset * 28}px)` }}
>
{loadingMessages.map((message) => (
<div className="h-7" key={message.id}>
{message.value}
</div>
))}
</div>
</div>
</div>
) : (
<></>
)}
</div>
);
};
+1 -1
View File
@@ -11,7 +11,7 @@ export const MapGraphic = (graphicProperties: __esri.GraphicProperties) => {
const graphicPoint = new Graphic(graphicProperties);
setGraphic(graphicPoint);
}, []);
}, [graphicProperties]);
useEffect(() => {
if (!graphic || !graphicsLayer) return;
@@ -2,7 +2,7 @@ import useStore from "../../../store/store";
import PopupModal from "./PopupModal";
import HelpPanel from "./HelpPanel";
import HelpButton from "../../HelpButton";
import BackButton from "./BackButton";
import BackButton from "../../BackButton";
const ButtonPanel = () => {
const { setModal, setPanel } = useStore();
@@ -9,7 +9,7 @@ const Parameters = () => {
<div className="flex flex-col gap-2 pt-4">
<div className="flex justify-between gap-4">
<div className="w-1/2 text-sm text-[#666668] font-medium">Type</div>
<div className="w-1/2 text-sm font-medium">
<div className="w-1/2 text-sm font-medium uppercase">
{currentVilla && currentVilla.type}
</div>
</div>
@@ -7,7 +7,6 @@ import ImageSlider from "./ImageSlider";
import ViewToggle from "../../ViewToggle";
const ViewControllerModal = () => {
// const { sliders } = parameters;
const [offset, setOffset] = useState(1);
const [isActive, setIsActive] = useState(false);
const [isTouchable, setIsTouchable] = useState(true);
@@ -54,25 +53,43 @@ const ViewControllerModal = () => {
};
const handlers = useSwipeable({
onSwiped: handleOnSwiped,
onSwiping: handleOnSwiping,
preventScrollOnSwipe: offset !== 0,
trackTouch: isTouchable,
// onSwiped: handleOnSwiped,
// onSwiping: handleOnSwiping,
onSwiping: () => {},
// onSwipedDown: () => {
// setOffset(1);
// setIsActive(false);
// },
// onSwipedUp: () => {
// setOffset(0);
// setIsActive(true);
// },
// preventScrollOnSwipe: offset !== 0,
// trackTouch: isTouchable,
});
return (
<div className="flex flex-col fixed left-0 top-0 z-20" {...handlers}>
<div
className="flex flex-col fixed left-0 top-0 z-20 select-none"
{...handlers}
>
<div
className={`${
isActive ? "rounded-ss-2xl rounded-se-2xl" : ""
!isActive ? "rounded-ss-2xl rounded-se-2xl" : ""
} bg-white w-full h-[calc(100vh)] border flex flex-col transition-all duration-500 fixed left-0 top-0 ease-in-out`}
style={{
transform: `translateY(calc(${offset * 80}vh))`,
transform: `${
offset === 1
? "translateY(calc(100vh - 64px))"
: "translateY(calc(0vh))"
} `,
}}
>
<ViewToggle offset={offset} />
<div className="mx-auto flex justify-center self-start w-full">
<div
className="mx-auto flex justify-center self-start w-full"
// {...handlers}
>
<ButtonSwipperIcon />
</div>
<div
@@ -0,0 +1,101 @@
import { useDrag } from "@use-gesture/react";
import { a, useSpring, config } from "@react-spring/web";
import styles from "./styles.module.css";
const items = ["save item", "open item", "share item", "delete item", "cancel"];
// const height = items.length * 60 + 80;
const height = items.length * 60 + 80;
export default function ButtomPanel() {
const [{ y }, api] = useSpring(() => ({ y: height }));
const open = ({ canceled }) => {
// when cancel is true, it means that the user passed the upwards threshold
// so we change the spring config to create a nice wobbly effect
api.start({
y: 0,
immediate: false,
config: canceled ? config.wobbly : config.stiff,
});
};
const close = (velocity = 0) => {
api.start({
y: height,
immediate: false,
config: { ...config.stiff, velocity },
});
};
const bind = useDrag(
({
last,
velocity: [, vy],
direction: [, dy],
offset: [, oy],
cancel,
canceled,
}) => {
// if the user drags up passed a threshold, then we cancel
// the drag so that the sheet resets to its open position
if (oy < -70) cancel();
// when the user releases the sheet, we check whether it passed
// the threshold for it to close, or if we reset it to its open positino
if (last) {
oy > height * 0.5 || (vy > 0.5 && dy > 0)
? close(vy)
: open({ canceled });
}
// when the user keeps dragging, we just move the sheet according to
// the cursor position
else api.start({ y: oy, immediate: true });
},
{
from: () => [0, y.get()],
filterTaps: true,
bounds: { top: 0 },
rubberband: true,
}
);
const display = y.to((py) => (py < height ? "block" : "none"));
const bgStyle = {
transform: y.to(
[0, height],
["translateY(-8%) scale(1.16)", "translateY(0px) scale(1.05)"]
),
opacity: y.to([0, height], [0.4, 1], "clamp"),
};
return (
<div className="flex" style={{ overflow: "hidden" }}>
<a.div className={styles.bg} onClick={() => close()} style={bgStyle}>
<img
src="https://images.pexels.com/photos/1239387/pexels-photo-1239387.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940"
alt=""
/>
<img
src="https://images.pexels.com/photos/5181179/pexels-photo-5181179.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940"
alt=""
/>
</a.div>
<div className={styles.actionBtn} onClick={open} />
<a.div
className={styles.sheet}
{...bind()}
style={{ display, bottom: `calc(-100vh + ${height - 100}px)`, y }} //
>
{items.map((entry, i) => (
<div
key={entry}
onClick={() =>
i < items.length - 1 ? alert("clicked on " + entry) : close()
}
children={entry}
/>
))}
</a.div>
</div>
);
}
@@ -0,0 +1,54 @@
.actionBtn {
position: fixed;
z-index: 100;
bottom: 80px;
right: 40px;
height: 48px;
width: 48px;
border-radius: 24px;
background: coral;
box-shadow: 0px 3px 5px -1px rgba(0, 0, 0, 0.2),
0px 6px 10px 0px rgba(0, 0, 0, 0.14), 0px 1px 18px 0px rgba(0, 0, 0, 0);
display: flex;
align-items: center;
justify-content: center;
}
.actionBtn:after {
content: " ";
display: block;
background: #fff;
height: 20%;
width: 20%;
border-radius: 50%;
}
.bg {
width: 100%;
}
.bg > img {
width: 100%;
margin: 0;
display: block;
}
.sheet {
z-index: 100;
position: fixed;
height: calc(100vh + 100px);
width: 100vw;
border-radius: 12px 12px 0px;
background: #fff;
touch-action: none;
}
.sheet > div {
height: 60px;
border-bottom: 1px solid #eee;
display: flex;
align-items: center;
justify-content: center;
padding: 0 20px;
text-transform: capitalize;
}
@@ -1,7 +1,28 @@
const SelectHousePanel = () => {
import useStore from "../../../store/store";
import GoBackButton from "../../GoBackButton";
import HouseListModal from "./HouseListModal";
type SelectHousePanelProps = {
isWithButton?: boolean;
};
const SelectHousePanel = ({ isWithButton = false }: SelectHousePanelProps) => {
const { setModal } = useStore();
const handleOnClick = () => {
setModal(<HouseListModal />);
};
return (
<div className="bg-[#F3F2F0] flex justify-center py-4 text-lg font-medium">
Select a House
<div className="bg-[#F3F2F0] flex justify-between text-lg font-medium items-center p-2 relative">
<div
className={`${isWithButton ? "absolute left-0 top-0 p-2" : "hidden"}`}
>
<GoBackButton onClick={handleOnClick} />
</div>
<div className="mx-auto py-2">Select a House</div>
{/* <GoBackButton onClick={handleOnClick} /> */}
<div />
</div>
);
};
@@ -11,38 +11,42 @@ const SelectedHouseModal = () => {
};
return (
<div className="absolute top-[72px] z-30 w-full px-6">
<div className="flex flex-col border border-[#DDD7D6] rounded-2xl bg-white">
<div className="flex p-1 h-[107px] w-full text-[12px] font-medium gap-4">
<div className="w-full overflow-hidden rounded-[4px] rounded-ss-xl">
{selectedOnMapVilla?.perspectiveWorkings[0]?.image && (
<img
className="h-full "
src={selectedOnMapVilla.perspectiveWorkings[0].image}
alt=""
/>
)}
</div>
<div className="w-full flex flex-col justify-center gap-1 text-[#666668]">
<p>Type</p>
<p>House Size</p>
<p>Bedrooms</p>
<p>Villa Theme</p>
</div>
<div className="flex flex-col w-[82px] pr-4 justify-center ">
<div className="uppercase">{selectedOnMapVilla?.type}</div>
<div className="w-full">
{selectedOnMapVilla?.totalBuildUpArea} Sq.m
<>
{selectedOnMapVilla && (
<div className="absolute top-[72px] z-30 w-full px-6">
<div className="flex flex-col border border-[#DDD7D6] rounded-2xl bg-white">
<div className="flex p-1 h-[107px] w-full text-[12px] font-medium gap-4">
<div className="w-full overflow-hidden rounded-[4px] rounded-ss-xl">
{selectedOnMapVilla?.perspectiveWorkings[0]?.image && (
<img
className="h-full "
src={selectedOnMapVilla.perspectiveWorkings[0].image}
alt=""
/>
)}
</div>
<div className="w-full flex flex-col justify-center gap-1 text-[#666668]">
<p>Type</p>
<p>House Size</p>
<p>Bedrooms</p>
<p>Villa Theme</p>
</div>
<div className="flex flex-col w-[82px] pr-4 justify-center ">
<div className="uppercase">{selectedOnMapVilla?.type}</div>
<div className="w-full">
{selectedOnMapVilla?.totalBuildUpArea} Sq.m
</div>
<div>{selectedOnMapVilla?.totalCountBedroms}</div>
<div>{selectedOnMapVilla?.villaTheme}</div>
</div>
</div>
<div className="border border-top text-sm flex justify-center">
<KnowMoreButton onClick={handleClickOnKnowMoreBtn} />
</div>
<div>{selectedOnMapVilla?.totalCountBedroms}</div>
<div>{selectedOnMapVilla?.villaTheme}</div>
</div>
</div>
<div className="border border-top text-sm flex">
<KnowMoreButton onClick={handleClickOnKnowMoreBtn} />
</div>
</div>
</div>
)}
</>
);
};