UNPKG

room-craft

Version:

A lightweight React component for displaying products in both Augmented Reality (AR) and 3D. Perfect for eCommerce applications where you want to showcase your products in an immersive and interactive way.

302 lines (300 loc) 14.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _qrcode = require("qrcode.react"); require("@google/model-viewer"); require("./styles.css"); var _react = _interopRequireWildcard(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; } function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } } function _arrayWithHoles(r) { if (Array.isArray(r)) return r; } function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { "default": e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n["default"] = e, t && t.set(e, n), n; } // import * as React from "react"; // import { useState, useEffect, useRef } from "react"; // import ProductCard from './ProductCard'; // Import the ProductCard component // import {QRCodeSVG} from 'qrcode.react'; // // QrScannerCard component // function QrScannerCard({ onCancel, url }) { // return ( // <article className="relative flex flex-col shadow-2xl py-3 pr-3 pl-12 -ml-px rounded-2xl max-w-[266px] bg-white"> // <div className="flex gap-3 items-start self-start mb-4"> // {/* Dynamically generate the QR code */} // <QRCodeSVG // value={url} // URL for the QR code // size={155} // Size of the QR code // bgColor="#FFFFFF" // Background color // fgColor="#000000" // Foreground color // className="shrink-0 pt-[10px] pl-2 w-[155px] h-[155px]" // /> // <button // onClick={onCancel} // Trigger onCancel function passed from Home // className="object-contain shrink-0 aspect-square w-[36px] h-[36px] sm:w-[36px] sm:h-[36px] md:w-[36px] md:h-[36px] p-1 rounded-full bg-gray-100 hover:bg-gray-200 focus:outline-none transition duration-200 ease-in-out" // > // <img // loading="lazy" // src="https://cdn.builder.io/api/v1/image/assets/TEMP/8413f1e3d7bad3c1c6a2161fe0a5e57db6bf71b385607571aa0c4b09275a751c?placeholderIfAbsent=true&apiKey=7c5c9b658efc49cc9c7f03d144c67cfb" // alt="Button cancel" // className="object-contain w-full h-full" // /> // </button> // </div> // <div // className="self-center mt-1 px-2 pt-1 pb-1.5 mr-10 text-xs font-semibold text-center text-white rounded-2xl bg-neutral-600 w-[98px]" // tabIndex="0" // > // Scan QR Code // </div> // </article> // ); // } // const Home = ({ // gltfPath = "/models/indoor_plant/scene.gltf", // imageSrc = "/image/1.png" // }) => { // const [showQrScanner, setShowQrScanner] = useState(false); // const [showPopup, setShowPopup] = useState(false); // const [isMobile, setIsMobile] = useState(false); // // Check if the device is mobile // useEffect(() => { // const handleResize = () => { // setIsMobile(window.innerWidth <= 768); // Consider screens <= 768px as mobile // }; // // Add event listener on mount // window.addEventListener('resize', handleResize); // // Check on initial render // handleResize(); // // Cleanup event listener on unmount // return () => { // window.removeEventListener('resize', handleResize); // }; // }, []); // const handleRightButtonClick = () => { // const baseUrl = window.location.origin; // const arUrl = `${baseUrl}/xr?gltfPath=${encodeURIComponent(gltfPath)}`; // if (isMobile) { // // For mobile, directly navigate to the AR URL // window.location.href = arUrl; // } else { // // For desktop, show the QR scanner card and pass the arUrl // setShowQrScanner(arUrl); // Pass arUrl as the state // } // }; // const handleLeftButtonClick = () => setShowPopup(true); // const handleCancel = () => setShowQrScanner(false); // const handleClosePopup = () => setShowPopup(false); // return ( // <div> // {showPopup && ( // <div className="fixed inset-0 bg-black bg-opacity-50 flex justify-center items-center z-50"> // <div className="bg-white p-5 rounded-lg relative"> // <div className="flex justify-end"> // <button // onClick={handleClosePopup} // className="object-contain aspect-square w-[36px] h-[36px] p-1 rounded-full bg-gray-100 hover:bg-gray-200 focus:outline-none" // > // <img // src="https://cdn.builder.io/api/v1/image/assets/TEMP/8413f1e3d7bad3c1c6a2161fe0a5e57db6bf71b385607571aa0c4b09275a751c" // alt="Close" // className="object-contain w-full h-full" // /> // </button> // </div> // <ProductCard gltfPath={gltfPath}/> // </div> // </div> // )} // {showQrScanner ? ( // <QrScannerCard onCancel={handleCancel} url={showQrScanner} /> // Pass the arUrl to QrScannerCard // ) : ( // <article className="relative flex flex-col shadow-2xl rounded-3xl max-w-[266px] bg-white"> // <img // src={imageSrc} // alt="Main gallery image" // className="object-cover rounded-2xl w-full h-full aspect-[1.204]" // /> // <button // onClick={handleLeftButtonClick} // className="absolute bottom-4 left-4 w-[42px] h-[42px] p-1 rounded-full bg-gray-100 hover:bg-gray-200" // > // <img // src="https://cdn.builder.io/api/v1/image/assets/TEMP/d2449bde7ca28a3beaa263bf12357cc8044b671bc122d0e6e55fb91f5afce627" // alt="360 view" // className="object-contain w-full h-full" // /> // </button> // <button // onClick={handleRightButtonClick} // className="absolute bottom-4 right-4 w-[42px] h-[42px] p-1 rounded-full bg-gray-100 hover:bg-gray-200" // > // <img // src="https://cdn.builder.io/api/v1/image/assets/TEMP/7344838b6c7244cc25bcab8cd8ceaf043201fa2fc9c5bde3a52bef437742f58c" // alt="AR View" // className="object-contain w-full h-full" // /> // </button> // </article> // )} // </div> // ); // }; // export default Home; // import React from 'react'; if (!customElements.get('model-viewer')) { Promise.resolve().then(function () { return _interopRequireWildcard(require('@google/model-viewer')); }); } // import ProductCard from './ProductCard'; function QrScannerCard(_ref) { var onCancel = _ref.onCancel, url = _ref.url; return /*#__PURE__*/_react["default"].createElement("article", { className: "qr-scanner-card" }, /*#__PURE__*/_react["default"].createElement("div", { className: "qr-scanner-header" }, /*#__PURE__*/_react["default"].createElement(_qrcode.QRCodeSVG, { value: url, size: 155, bgColor: "#FFFFFF", fgColor: "#000000" }), /*#__PURE__*/_react["default"].createElement("button", { onClick: onCancel, className: "cancel-button", style: { width: '20px', height: '20px', padding: '0' } // Set size here }, /*#__PURE__*/_react["default"].createElement("img", { loading: "lazy", src: "https://cdn.builder.io/api/v1/image/assets/TEMP/8413f1e3d7bad3c1c6a2161fe0a5e57db6bf71b385607571aa0c4b09275a751c?placeholderIfAbsent=true&apiKey=7c5c9b658efc49cc9c7f03d144c67cfb", alt: "Button cancel", style: { width: '100%', height: '100%' } // Make image fill the button }))), /*#__PURE__*/_react["default"].createElement("div", { className: "qr-scanner-footer" }, "Scan QR Code")); } var AR3DProductCard = function AR3DProductCard(_ref2) { var gltfPath = _ref2.gltfPath, imageSrc = _ref2.imageSrc; var _useState = (0, _react.useState)(false), _useState2 = _slicedToArray(_useState, 2), showQrScanner = _useState2[0], setShowQrScanner = _useState2[1]; var _useState3 = (0, _react.useState)(false), _useState4 = _slicedToArray(_useState3, 2), showPopup = _useState4[0], setShowPopup = _useState4[1]; var _useState5 = (0, _react.useState)(false), _useState6 = _slicedToArray(_useState5, 2), isMobile = _useState6[0], setIsMobile = _useState6[1]; var _useState7 = (0, _react.useState)([]), _useState8 = _slicedToArray(_useState7, 2), errors = _useState8[0], setErrors = _useState8[1]; (0, _react.useEffect)(function () { var handleResize = function handleResize() { setIsMobile(window.innerWidth <= 768); }; window.addEventListener('resize', handleResize); handleResize(); return function () { window.removeEventListener('resize', handleResize); }; }, []); (0, _react.useEffect)(function () { var missingFields = []; if (!gltfPath) missingFields.push("gltfPath"); if (!imageSrc) missingFields.push("imageSrc"); setErrors(missingFields); }, [gltfPath, imageSrc]); var handleRightButtonClick = function handleRightButtonClick() { var baseUrl = window.location.origin; var arUrl = "".concat(baseUrl, "/xr?gltfPath=").concat(gltfPath); if (isMobile) { window.location.href = arUrl; } else { setShowQrScanner(arUrl); } }; var handleLeftButtonClick = function handleLeftButtonClick() { return setShowPopup(true); }; var handleCancel = function handleCancel() { return setShowQrScanner(false); }; var handleClosePopup = function handleClosePopup() { return setShowPopup(false); }; if (errors.length > 0) { return /*#__PURE__*/_react["default"].createElement("div", { className: "error-container" }, /*#__PURE__*/_react["default"].createElement("h2", null, "Missing Required Props"), /*#__PURE__*/_react["default"].createElement("ul", null, errors.map(function (error) { return /*#__PURE__*/_react["default"].createElement("li", { key: error }, error, " is not provided"); }))); } return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, showPopup && /*#__PURE__*/_react["default"].createElement("div", { className: "popup-overlay" }, /*#__PURE__*/_react["default"].createElement("div", { className: "popup-content" }, /*#__PURE__*/_react["default"].createElement("div", { className: "rounded-lg", style: { width: "480px", height: "380px" } }, /*#__PURE__*/_react["default"].createElement("model-viewer", { src: gltfPath, alt: "Home Decor Product", "auto-rotate": true, "camera-controls": true, "shadow-intensity": "1", style: { width: "100%", height: "100%" } })), /*#__PURE__*/_react["default"].createElement("button", { onClick: handleClosePopup, className: "leave-button" }, "Leave"))), showQrScanner ? /*#__PURE__*/_react["default"].createElement(QrScannerCard, { onCancel: handleCancel, url: showQrScanner }) : /*#__PURE__*/_react["default"].createElement("article", { className: "main-card" }, /*#__PURE__*/_react["default"].createElement("img", { src: imageSrc, alt: "Main gallery image", className: "main-image" }), /*#__PURE__*/_react["default"].createElement("button", { onClick: handleLeftButtonClick, className: "left-button" }, /*#__PURE__*/_react["default"].createElement("img", { src: "https://cdn.builder.io/api/v1/image/assets/TEMP/d2449bde7ca28a3beaa263bf12357cc8044b671bc122d0e6e55fb91f5afce627", alt: "360 view" })), /*#__PURE__*/_react["default"].createElement("button", { onClick: handleRightButtonClick, className: "right-button" }, /*#__PURE__*/_react["default"].createElement("img", { src: "https://cdn.builder.io/api/v1/image/assets/TEMP/7344838b6c7244cc25bcab8cd8ceaf043201fa2fc9c5bde3a52bef437742f58c", alt: "AR View" })))); }; AR3DProductCard.propTypes = { gltfPath: _propTypes["default"].string, imageSrc: _propTypes["default"].string }; var _default = exports["default"] = AR3DProductCard;