lanxin 1 ماه پیش
والد
کامیت
44f3a61b2a
99فایلهای تغییر یافته به همراه1799 افزوده شده و 8697 حذف شده
  1. 7 4
      config-overrides.js
  2. 1 1
      package.json
  3. BIN
      public/Chenzhebei-ShanxiMuseum/Build/Build.data.unityweb
  4. BIN
      public/Chenzhebei-ShanxiMuseum/Build/Build.framework.js.unityweb
  5. 1 0
      public/Chenzhebei-ShanxiMuseum/Build/Build.loader.js
  6. BIN
      public/Chenzhebei-ShanxiMuseum/Build/Build.wasm.unityweb
  7. 6 0
      public/Chenzhebei-ShanxiMuseum/ServiceWorker.js
  8. BIN
      public/Chenzhebei-ShanxiMuseum/TemplateData/favicon.ico
  9. BIN
      public/Chenzhebei-ShanxiMuseum/TemplateData/progress-bar-empty-dark.png
  10. BIN
      public/Chenzhebei-ShanxiMuseum/TemplateData/progress-bar-empty-light.png
  11. BIN
      public/Chenzhebei-ShanxiMuseum/TemplateData/progress-bar-full-dark.png
  12. BIN
      public/Chenzhebei-ShanxiMuseum/TemplateData/progress-bar-full-light.png
  13. 50 0
      public/Chenzhebei-ShanxiMuseum/TemplateData/style.css
  14. BIN
      public/Chenzhebei-ShanxiMuseum/TemplateData/webmemd-icon.png
  15. 115 0
      public/Chenzhebei-ShanxiMuseum/index.html
  16. 111 0
      public/Chenzhebei-ShanxiMuseum/main.html
  17. 65 0
      public/Chenzhebei-ShanxiMuseum/unityExport.js
  18. 5 1
      public/index.html
  19. 0 7
      public/krpano.js
  20. BIN
      public/myData/home.ts
  21. 0 4572
      public/myData/hot.js
  22. BIN
      public/myData/img/btn_back.png
  23. 103 35
      public/myData/myData.js
  24. BIN
      public/myData/play.ts
  25. BIN
      public/myData/qfk.TTF
  26. BIN
      public/myData/ybwx.ts
  27. 0 5
      public/plugins/bingmaps.js
  28. 0 516
      public/plugins/combobox.xml
  29. 0 48
      public/plugins/doubleclick_style.xml
  30. 0 28
      public/plugins/fps.xml
  31. 0 5
      public/plugins/googlemaps.js
  32. 0 5
      public/plugins/gyro2.js
  33. 0 5
      public/plugins/pp_blur.js
  34. 0 5
      public/plugins/pp_light.js
  35. 0 5
      public/plugins/pp_sharpen.js
  36. 0 19
      public/plugins/scrollarea.js
  37. 0 212
      public/plugins/showtext.xml
  38. 0 5
      public/plugins/soundinterface.js
  39. 0 5
      public/plugins/videoplayer.js
  40. 0 5
      public/plugins/webvr.js
  41. 0 942
      public/plugins/webvr.xml
  42. BIN
      public/plugins/webvr_handcursor.png
  43. BIN
      public/plugins/webvr_laser.png
  44. BIN
      public/plugins/webvr_light.png
  45. BIN
      public/plugins/webvr_vrcursor.png
  46. BIN
      public/skin/rotate_device.png
  47. 0 33
      public/skin/videointerface.xml
  48. BIN
      public/skin/vtourskin.png
  49. BIN
      public/skin/vtourskin_light.png
  50. 50 22
      src/App.tsx
  51. BIN
      src/assets/img/bg_home.png
  52. BIN
      src/assets/img/home_loading.png
  53. BIN
      src/assets/img/hotSelected_bg.png
  54. BIN
      src/assets/img/icon_dot2.png
  55. BIN
      src/assets/img/intro_bg.png
  56. BIN
      src/assets/img/menu_item.png
  57. BIN
      src/assets/img/menu_item_ac.png
  58. 118 60
      src/assets/styles/base.css
  59. 143 3
      src/assets/styles/base.less
  60. 0 214
      src/components/BaseImg/index.module.scss
  61. 0 168
      src/components/BaseImg/index.tsx
  62. 2 2
      src/components/EndVideo/index.tsx
  63. 0 134
      src/components/FloorBtn/index.module.scss
  64. 0 135
      src/components/FloorBtn/index.tsx
  65. 0 161
      src/components/ZHot0/index.module.scss
  66. 0 121
      src/components/ZHot0/index.tsx
  67. 0 352
      src/components/Zhot/index.module.scss
  68. 0 320
      src/components/Zhot/index.tsx
  69. 0 77
      src/components/Zhot/type.d.ts
  70. 23 16
      src/index.tsx
  71. 5 0
      src/pages/A0base/index.module.scss
  72. 5 5
      src/pages/A0base/index.tsx
  73. 26 7
      src/pages/A1home/index.module.scss
  74. 28 15
      src/pages/A1home/index.tsx
  75. 66 42
      src/pages/A2yblm/components/Detail/index.module.scss
  76. 49 22
      src/pages/A2yblm/components/Detail/index.tsx
  77. 3 0
      src/pages/A2yblm/components/Intro/index.module.scss
  78. 7 20
      src/pages/A2yblm/components/Intro/index.tsx
  79. 10 85
      src/pages/A2yblm/components/ModalTxt/index.module.scss
  80. 87 118
      src/pages/A2yblm/components/ModalTxt/index.tsx
  81. 165 3
      src/pages/A2yblm/index.module.scss
  82. 78 14
      src/pages/A2yblm/index.tsx
  83. 5 1
      src/pages/A3beie/index.module.scss
  84. 13 3
      src/pages/A3beie/index.tsx
  85. 4 1
      src/pages/A4quanwen/index.module.scss
  86. 22 5
      src/pages/A4quanwen/index.tsx
  87. 5 3
      src/pages/A5wenwu/index.module.scss
  88. 58 12
      src/pages/A5wenwu/index.tsx
  89. 48 0
      src/pages/A6ybwx/index.module.scss
  90. 58 0
      src/pages/A6ybwx/index.tsx
  91. 20 0
      src/pages/A7wjwj/index.module.scss
  92. 26 0
      src/pages/A7wjwj/index.tsx
  93. 4 4
      src/types/declaration.d.ts
  94. 6 1
      src/types/function.d.ts
  95. 30 6
      src/utils/history.ts
  96. 1 4
      src/utils/http.ts
  97. 31 0
      src/utils/reactToHtml.tsx
  98. 1 1
      tsconfig.json
  99. 138 77
      yarn.lock

+ 7 - 4
config-overrides.js

@@ -1,10 +1,13 @@
 const path = require('path')
-const { override, addWebpackAlias } = require('customize-cra')
+const { override, addWebpackAlias, setWebpackTarget } = require('customize-cra')
 
-// 添加 @ 别名
+// 添加 @ 别名(移除错误的 ssr 配置)
 const webpackAlias = addWebpackAlias({
-  '@': path.resolve(__dirname, 'src'),
+  '@': path.resolve(__dirname, 'src')
 })
 
 // 导出要进行覆盖的 webpack 配置
-module.exports = override(webpackAlias)
+module.exports = override(
+  webpackAlias,
+  setWebpackTarget('web') // 显式指定为浏览器环境(禁用Node.js/SSR相关处理)
+)

+ 1 - 1
package.json

@@ -61,4 +61,4 @@
     "react-app-rewired": "^2.2.1"
   },
   "homepage": "."
-}
+}

BIN
public/Chenzhebei-ShanxiMuseum/Build/Build.data.unityweb


BIN
public/Chenzhebei-ShanxiMuseum/Build/Build.framework.js.unityweb


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 0
public/Chenzhebei-ShanxiMuseum/Build/Build.loader.js


BIN
public/Chenzhebei-ShanxiMuseum/Build/Build.wasm.unityweb


+ 6 - 0
public/Chenzhebei-ShanxiMuseum/ServiceWorker.js

@@ -0,0 +1,6 @@
+
+self.addEventListener('install', function (e) {
+    console.log('[Service Worker] Install');
+    
+});
+

BIN
public/Chenzhebei-ShanxiMuseum/TemplateData/favicon.ico


BIN
public/Chenzhebei-ShanxiMuseum/TemplateData/progress-bar-empty-dark.png


BIN
public/Chenzhebei-ShanxiMuseum/TemplateData/progress-bar-empty-light.png


BIN
public/Chenzhebei-ShanxiMuseum/TemplateData/progress-bar-full-dark.png


BIN
public/Chenzhebei-ShanxiMuseum/TemplateData/progress-bar-full-light.png


+ 50 - 0
public/Chenzhebei-ShanxiMuseum/TemplateData/style.css

@@ -0,0 +1,50 @@
+html {}
+body { padding: 0; margin: 0 }
+#unity-container { position: fixed; width: 100%; height: 100%; }
+#unity-canvas { width: 100%; height: 100%; background:  url('bg.jpg') no-repeat center; background-size: cover; }
+#unity-loading-bar { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); display: none }
+#unity-progress-bar-empty { margin-left: auto; margin-right: auto; width: 141px; height: 18px; margin-top: 10px; background: url('progress-bar-empty-dark.png') no-repeat center }
+#unity-progress-bar-full { width: 0%; height: 18px; margin-top: 10px; background: url('progress-bar-full-dark.png') no-repeat center }
+#unity-warning { position: absolute; left: 50%; top: 5%; transform: translate(-50%); background: white; padding: 10px; display: none }
+
+@media all and (orientation: landscape) {
+    .landscape {
+        transform: rotate(0deg);
+        width: 100vw;
+        width: 100dvw;
+        height: 100vh;
+        height: 100dvh;
+        top: 0;
+        left: 0;
+    }
+    .portrait {
+        transform: rotate(90deg);
+        transform-origin: left top;
+        width: 100vh;
+        width: 100dvh;
+        height: 100vw;
+        height: 100dvw;
+        left: 100%;
+    }
+}
+
+@media all and (orientation: portrait) {
+    .landscape {
+        transform: rotate(90deg);
+        transform-origin: left top;
+        width: 100vh;
+        width: 100dvh;
+        height: 100vw;
+        height: 100dvw;
+        left: 100%;
+    }
+    .portrait {
+        transform: rotate(0deg);
+        width: 100vw;
+        width: 100dvw;
+        height: 100vh;
+        height: 100dvh;
+        top: 0;
+        left: 0;
+    }
+}

BIN
public/Chenzhebei-ShanxiMuseum/TemplateData/webmemd-icon.png


+ 115 - 0
public/Chenzhebei-ShanxiMuseum/index.html

@@ -0,0 +1,115 @@
+<!DOCTYPE html>
+<html lang="en-us">
+<head>
+    <meta charset="utf-8">
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+    <title>Chenzhebei-ShanxiMuseum</title>
+    <link rel="shortcut icon" href="TemplateData/favicon.ico">
+    <link rel="stylesheet" href="TemplateData/style.css">
+    <script src="./unityExport.js"></script>
+</head>
+<body>
+    <div id="unity-container">
+        <canvas id="unity-canvas" width=960 height=600 tabindex="-1"></canvas>
+        <div id="unity-loading-bar">
+            <div id="unity-progress-bar-empty">
+                <div id="unity-progress-bar-full"></div>
+            </div>
+        </div>
+        <div id="unity-warning"></div>
+    </div>
+</body>
+<script>
+
+    var container = document.querySelector("#unity-container");
+    var canvas = document.querySelector("#unity-canvas");
+    var loadingBar = document.querySelector("#unity-loading-bar");
+    var progressBarFull = document.querySelector("#unity-progress-bar-full");
+    var warningBanner = document.querySelector("#unity-warning");
+
+    // Shows a temporary message banner/ribbon for a few seconds, or
+    // a permanent error message on top of the canvas if type=='error'.
+    // If type=='warning', a yellow highlight color is used.
+    // Modify or remove this function to customize the visually presented
+    // way that non-critical warnings and error messages are presented to the
+    // user.
+    function unityShowBanner(msg, type) {
+        function updateBannerVisibility() {
+            warningBanner.style.display = warningBanner.children.length ? 'block' : 'none';
+        }
+        var div = document.createElement('div');
+        div.innerHTML = msg;
+        warningBanner.appendChild(div);
+        if (type == 'error') div.style = 'background: red; padding: 10px;';
+        else {
+            if (type == 'warning') div.style = 'background: yellow; padding: 10px;';
+            setTimeout(function () {
+                warningBanner.removeChild(div);
+                updateBannerVisibility();
+            }, 5000);
+        }
+        updateBannerVisibility();
+    }
+
+    var buildUrl = "Build";
+    var loaderUrl = buildUrl + "/Build.loader.js";
+    var config = {
+        dataUrl: buildUrl + "/Build.data.unityweb",
+        frameworkUrl: buildUrl + "/Build.framework.js.unityweb",
+        codeUrl: buildUrl + "/Build.wasm.unityweb",
+        streamingAssetsUrl: "StreamingAssets",
+        devicePixelRatio: 2,
+        companyName: "DefaultCompany",
+        productName: "Chenzhebei-ShanxiMuseum",
+        productVersion: "0.1",
+        showBanner: unityShowBanner,
+    };
+
+    // By default Unity keeps WebGL canvas render target size matched with
+    // the DOM size of the canvas element (scaled by window.devicePixelRatio)
+    // Set this to false if you want to decouple this synchronization from
+    // happening inside the engine, and you would instead like to size up
+    // the canvas DOM size and WebGL render target sizes yourself.
+    // config.matchWebGLToCanvasSize = false;
+
+    if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
+        // Mobile device style: fill the whole browser client area with the game canvas:
+        var meta = document.createElement('meta');
+        meta.name = 'viewport';
+        meta.content = 'width=device-width, height=device-height, initial-scale=1.0, user-scalable=no, shrink-to-fit=yes';
+        document.getElementsByTagName('head')[0].appendChild(meta);
+        document.querySelector("#unity-container").className = "unity-mobile";
+        canvas.className = "unity-mobile";
+
+        // To lower canvas resolution on mobile devices to gain some
+        // performance, uncomment the following line:
+        // config.devicePixelRatio = 1;
+    }
+
+
+
+loadingBar.style.display = "block";
+    var script = document.createElement("script");
+    script.src = loaderUrl;
+    script.onload = () => {
+        createUnityInstance(canvas, config, (progress) => {
+
+            if (window.parent && window.parent !== window) {
+                window.parent.unityLoading(progress);
+            }
+            progressBarFull.style.width = 100 * progress + "%";
+        }).then((unityInstance) => {
+            loadingBar.style.display = "none";
+            window.unityInstance = unityInstance;
+            
+            if (window.parent && window.parent !== window) {
+                window.parent.unityLoading(1);
+            }
+        }).catch((message) => {
+            alert(message);
+        });
+    };
+    document.body.appendChild(script);
+</script>
+
+</html>

+ 111 - 0
public/Chenzhebei-ShanxiMuseum/main.html

@@ -0,0 +1,111 @@
+<!DOCTYPE html>
+<html lang="en-us">
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Chenzhebei-ShanxiMuseum</title>
+    <link rel="shortcut icon" href="TemplateData/favicon.ico">
+      <style>
+        * {
+          margin: 0;
+          padding: 0;
+          box-sizing: border-box;
+        }
+
+        body {
+          overflow: hidden;
+        }
+
+        .root {
+          position: absolute;
+        }
+
+        iframe {
+          width: 100%;
+          height: 100%;
+        }
+
+        @media all and (orientation: landscape) {
+          .landscape {
+            transform: rotate(0deg);
+            width: 100vw;
+            width: 100dvw;
+            height: 100vh;
+            height: 100dvh;
+            top: 0;
+            left: 0;
+          }
+          .portrait {
+            transform: rotate(90deg);
+            transform-origin: left top;
+            width: 100vh;
+            width: 100dvh;
+            height: 100vw;
+            height: 100dvw;
+            left: 100%;
+          }
+        }
+        
+        @media all and (orientation: portrait) {
+          .landscape {
+            transform: rotate(90deg);
+            transform-origin: left top;
+            width: 100vh;
+            width: 100dvh;
+            height: 100vw;
+            height: 100dvw;
+            left: 100%;
+          }
+          .portrait {
+            transform: rotate(0deg);
+            width: 100vw;
+            width: 100dvw;
+            height: 100vh;
+            height: 100dvh;
+            top: 0;
+            left: 0;
+          }
+        }
+      </style>
+  </head>
+  <body>
+    <div class="root">
+      <iframe
+        id="main"
+        frameborder="0">
+      </iframe>
+    </div>
+  </body>
+  <script>
+    const rootDom = document.querySelector('.root')
+    const iframe = document.querySelector('#main')
+    let isPortrait = false;
+
+    function internal_ChangeViewType(portrait){
+      if(portrait){
+        rootDom.classList.remove('landscape');
+        rootDom.classList.add('portrait');
+      }else{
+        rootDom.classList.add('landscape');
+        rootDom.classList.remove('portrait');
+      }
+    }
+    
+    window.changeViewType = function(landscape){
+      if (isPortrait !== landscape){
+        isPortrait = landscape;
+        internal_ChangeViewType(landscape);
+      }
+    }
+    internal_ChangeViewType(isPortrait);
+    
+    window.onUnityClickBack = function () {
+        if (window.parent && window.parent !== window) {
+            window.parent.onUnityClickBack();
+        }
+    }
+    
+    iframe.src = "./main.html"
+  </script>
+</html>

+ 65 - 0
public/Chenzhebei-ShanxiMuseum/unityExport.js

@@ -0,0 +1,65 @@
+
+//当需要显示热点Tag的时候触发, 该函数为unity主动调用的函数
+window.showTag = function (index) {
+    if (window.parent && window.parent !== window) {
+        window.parent.showTag(index);
+    }
+}
+//当需要隐藏热点Tag的时候触发, 该函数为unity主动调用的函数
+window.hideTag = function () {
+    if (window.parent && window.parent !== window) {
+        window.parent.hideTag();
+    }
+}
+
+//当模型被操控的时候触发, 任何时候模型进行了移动/旋转/缩放, 都会触发这个函数, 包括主动调用addModelScale函数时, 该函数为unity主动调用的函数
+window.onModelControlled = function () {
+    // if (window.parent && window.parent !== window) {
+    //     window.parent.onModelControlled();
+    // }
+}
+
+
+
+
+
+//切换背景图 (0目录页, 1玄石可观, 2石上春秋, 3碑刻密码, 4模型鉴赏) 这些名字对应的蓝湖设计的标题
+window.changePanel = function (index) {
+    window.unityInstance.SendMessage('MainCanvas', 'ChangePanel', index)
+}
+
+//聚焦热点, 对应玄石可观中的热点, 在调用之前需要先调用changPanel(1), 退出页面时需要调用showHotspot(-1)
+window.showHotspot = function (index) {
+    window.unityInstance.SendMessage('MainCanvas', 'ShowHotspot', index)
+}
+
+//聚焦碑文, 对应碑刻密码中的碑文, 在调用之前需要先调用changPanel(3), 退出页面时需要调用showInscription(-1)
+//参数分别对应 0碑额 1碑文第一段 2碑文第二段 3碑文第三段 10全文赏析
+window.showInscription = function (index) {
+    window.unityInstance.SendMessage('MainCanvas', 'ShowInscription', index)
+}
+
+//显示或隐藏碑文, 默认是显示状态, 离开页面时如果是隐藏状态, 则需要再次调用此函数让碑文显示
+window.openHightlight = function (isShow) {
+    window.unityInstance.SendMessage('MainCanvas', 'SetInscriptionActive', isShow ? 1 : 0)
+}
+
+
+//显示模型尺寸(待定) 对应蓝湖设计 "文物鉴赏-尺寸"
+window.showSize = function () {
+    window.unityInstance.SendMessage('MainCanvas', 'SetSizeActive', 1)
+}
+//隐藏模型尺寸(待定) 对应蓝湖设计 "文物鉴赏-尺寸"
+window.hideSize = function () {
+    window.unityInstance.SendMessage('MainCanvas', 'SetSizeActive', 0)
+}
+
+//改变模型缩放, 正数为放大, 负数为缩小, 对应蓝湖设计 "文物鉴赏-尺寸" 右侧的放大缩小按钮
+window.addModelScale = function (value) {
+    window.unityInstance.SendMessage('MainCanvas', 'AddModelScale', value)
+}
+
+//重置模型, 对应蓝湖设计 "文物鉴赏-尺寸" 右侧的重置按钮
+window.resetModel = function () {
+    window.unityInstance.SendMessage('MainCanvas', 'ResetModel')
+}

+ 5 - 1
public/index.html

@@ -19,11 +19,15 @@
         src: url('./myData/qfk.TTF');
       }
     </style>
-    <title>河南-邀你至汉家</title>
+    <title>程哲碑</title>
   </head>
   <body>
     <noscript>You need to enable JavaScript to run this app.</noscript>
     <div id="root"></div>
+    <div id="A7Back">
+      <img src="./myData/img/btn_back.png" alt="" />
+    </div>
+    <iframe style="display: none" id="wjwjScene" title="wjwjScene" src=""></iframe>
   </body>
 
   <script src="./krpano.js"></script>

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 7
public/krpano.js


BIN
public/myData/home.ts


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 4572
public/myData/hot.js


BIN
public/myData/img/btn_back.png


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 103 - 35
public/myData/myData.js


BIN
public/myData/play.ts


BIN
public/myData/qfk.TTF


BIN
public/myData/ybwx.ts


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 5
public/plugins/bingmaps.js


+ 0 - 516
public/plugins/combobox.xml

@@ -1,516 +0,0 @@
-<krpano>
-
-	<!--
-		combobox.xml
-		krpano 1.21 
-		
-		https://krpano.com/plugins/combobox/
-
-		Combobox Plugin
-		- This plugin converts <combobox> elements in the current xml
-		  into <layer> container, scrollarea and textfield elements.
-		- Additionally it's also possible to add and remove combobox
-		  elements also dynamically.
-		- The full xml implementation allows many ways of customizing
-		  for own needs - custom designs/styles, custom functionality.
-
-
-		Syntax for Static XML Code:
-
-			<combobox name="..." design="..." ...any layer settings...>
-				<item name="..." caption="..." onclick="..." />
-				<item name="..." caption="..." onclick="..." />
-			</combobox>
-
-		Syntax for Dynamic XML Code:
-
-		 - Global Actions:
-
-			addComboboxLayer(cbname, design*)
-			removeComboboxLayer(cbname);
-
-		 - Combobox Layer Actions:
-
-			layer[cbname].addItem(caption, onclick)
-			layer[cbname].addNamedItem(name, caption, onclick)
-			layer[cbname].addIdItem(name, caption, onclick);       same as addNamedItem (for combobox.js compatibility)
-			layer[cbname].selectItem(caption)
-			layer[cbname].selectItemByName(name_or_index)
-			layer[cbname].selectIdItem(name_or_index)              same as selectItemByName (for combobox.js compatibility)
-			layer[cbname].removeAll()
-			layer[cbname].openList()
-			layer[cbname].closeList()
-
-		 - Events/Callbacks:
-
-			layer[cbname].onChange
-
-		- Combobox Layer Attributes:
-
-			layer[cbname].item              - krpano Array of the items
-			layer[cbname].selecteditemindex - current selected item index
-	-->
-
-
-	<!-- core internal layer styles -->
-	<style name="combobox_container_style" type="container" maskchildren="true" bgcapture="true" visible="false" onclick="combobox_onclick_event();" alpha="1.0" />
-	<style name="combobox_marker_style" type="text" align="righttop" edge="center" html="▼" havemarkersize="false" onautosized="set(havemarkersize,true);" alpha="1.0" />
-	<style name="combobox_item_style" type="text" wordwrap="false" vcenter="true" align="lefttop" onover="if(!combbox_item_pressed,onoveritem());asyncloop(hovering,,if(!combbox_item_pressed,onoutitem()));" ondown="onoveritem(); set(combbox_item_pressed,true);" onup="onoutitem(); set(combbox_item_pressed,false);" onoveritem="set(bg,true);" onoutitem="set(bg,false);" alpha="1.0" />
-
-	<!-- several pre-defined designs -->
-	<combobox_design name="default" margin="2" open_close_speed="0.25">
-		<!-- default design - white box with black text and blue selection -->
-		<style name="combobox_container_style" bgalpha="1.0" bgcolor="0xFFFFFF" bgborder="1 0xFFFFFF 0.5" bgroundedge="1" bgshadow="0 1 3 0x000000 1.0" />
-		<style name="combobox_marker_style" css="color:#FFFFFF;" bg="false" txtshadow="0 0 2 0x000000 1" />
-		<style name="combobox_item_style" css="color:#222222;" padding="4 4" bg="false" bgcolor="0xC7E4FC" bgalpha="1.0" bgroundedge="1" txtshadow="0 0 1 0xFFFFFF 1.0" />
-	</combobox_design>
-
-	<combobox_design name="vtour" margin="4" open_close_speed="0.25">
-		<!-- default vtourskin.xml design -->
-		<style name="combobox_container_style" bgalpha="0.8" bgcolor="0x2D3E50" bgborder="0" bgroundedge="1" bgshadow="0 4 10 0x000000 0.3" />
-		<style name="combobox_marker_style" css="color:#FFFFFF;" bg="false" txtshadow="0 0 2 0x000000 1" />
-		<style name="combobox_item_style" css="color:#FFFFFF;" padding="4 4" bg="false" bgcolor="0xFFFFFF" bgalpha="0.5" bgroundedge="0" txtshadow="0 0 2 0x000000 1" />
-	</combobox_design>
-
-
-	
-	
-
-	<!-- internal events -->
-	<events name="combobox_xml_plugin_events" keep="true"
-	        onresize="combobox_closelist();"
-	        />
-
-	<!-- krpano version check -->
-	<action name="combobox_versioncheck" autorun="preinit">
-		if(build LT '2022-01-01',
-			error('combobox.xml - too old krpano version!');
-			set(events[combobox_xml_plugin_events].name, null);
-			set(action[addComboboxLayer].content, '');
-			set(action[removeComboboxLayer].content, '');
-		  ,
-			combobox_xml_init();
-		);
-	</action>
-
-	<action name="combobox_xml_init">
-		<!-- set auto call again on next xml load -->
-		set(action[combobox_xml_init].autorun, onload);
-		
-		combobox_parse_xml_elements();
-	</action>
-	
-
-	<!-- convert all <combobox> elements to layers -->
-	<action name="combobox_parse_xml_elements" scope="localonly">
-		if(global.combobox,
-			copy(combobox_src, global.combobox);
-			delete(global.combobox);
-			def(i, integer, 0);
-			def(cnt, integer, get(combobox_src.count));
-			if(cnt GT 0, loop(i LT cnt,
-				copy(cb, combobox_src[get(i)]);
-				if(cb AND cb.name AND cb.parsed != true,
-					set(cb.parsed, true);
-					addComboboxLayer(get(cb.name), get(cb.design));
-					copy(ly, global.layer[get(cb.name)]);
-					copyattributes(get(ly), get(cb));
-					set(ly.keep, true);
-					def(item_cnt, integer, get(cb.item.count));
-					if(item_cnt GT 0,
-						def(item_i, integer, 0);
-						loop(item_i LT  item_cnt,
-							combobox_additem(get(ly.name), get(cb.item[get(item_i)].name), get(cb.item[get(item_i)].caption), get(cb.item[get(item_i)].onclick), get(cb.item[get(item_i)].oninit));
-							inc(item_i);
-						);
-					);
-				);
-				inc(i);
-			));
-		);
-	</action>
-
-
-	<!-- dynamically add a combobox layer -->
-	<action name="addComboboxLayer" scope="localonly" args="cbname, design">
-		<!-- create the layer -->
-		addlayer(get(cbname));
-		copy(cb, global.layer[get(cbname)]);
-		set(cb.keep, true);
-		set(cb.maxopenheight, 1000);
-		
-		<!-- copy the design settings (or set defaults) -->
-		if(!global.combobox_design[get(design)].name, set(design,'default'));
-		copy(cb.cbdesign, global.combobox_design[get(design)]);
-		calc(cb.margin, cb.cbdesign.margin !== null ? cb.cbdesign.margin : 2);
-		calc(cb.open_close_speed, cb.cbdesign.open_close_speed !== null ? cb.cbdesign.open_close_speed : 0.25);
-		<!-- load the styles and copy the design style settings -->
-		cb.loadstyle(combobox_container_style);
-		copyattributes(get(cb), get(cb.cbdesign.style[combobox_container_style]));
-
-		<!-- add/build/map actions -->
-		calc(cb.addItem,          'combobox_additem(' + cbname + ', null, "%%1", "%%2");');
-		calc(cb.addNamedItem,     'combobox_additem(' + cbname + ', "%%1", "%%2", "%%3");');
-		calc(cb.addIdItem,        'combobox_additem(' + cbname + ', "%%1", "%%2", "%%3");');
-		calc(cb.selectItem,       'combobox_finditem(' + cbname + ', "%%1", __cb_fi); if(__cb_fi GE 0, combobox_selectitem(' + cbname + ', get(__cb_fi))); delete(__cb_fi);');
-		calc(cb.selectItemByName, 'combobox_selectitem(' + cbname + ', "%%1");');
-		calc(cb.selectIdItem,     'combobox_selectitem(' + cbname + ', "%%1");');
-		calc(cb.removeAll,        'combobox_removeitems(' + cbname + ');');
-		calc(cb.openList,         'combobox_openlist(' + cbname + ');');
-		calc(cb.closeList,        'combobox_closelist(' + cbname + ');');
-
-		<!-- create sub-layers -->
-		calc(saname, 'combobox_' + cbname + '_scrollarea');
-		addlayer(get(saname));
-		copy(sa, global.layer[get(saname)]);
-		copy(sa.parent, cbname);
-		copy(sa.keep, true);
-		copy(sa.align, lefttop);
-		set(sa.type, 'scrollarea');
-		set(sa.direction, v);
-		set(sa.enabled, false);
-		set(sa.width, 100%);
-		set(sa.height, 100%);
-		copy(cb.scrollarea, sa);
-
-		calc(mkname, 'combobox_' + cbname + '_marker');
-		addlayer(get(mkname));
-		copy(mk, global.layer[get(mkname)]);
-		copy(mk.parent, saname);
-		copy(mk.keep, true);
-		mk.loadstyle(combobox_marker_style);
-		copyattributes(get(mk), get(cb.cbdesign.style[combobox_marker_style]));
-		copy(cb.marker, mk);
-
-		<!-- item data array -->
-		cb.createarray('item');
-
-		<!-- item autosizing information -->
-		set(cb.autosize_i, 0);
-		set(cb.autosize_cnt, 0);
-		set(cb.autosize_max_w, 0);
-		set(cb.autosize_max_h, 0);
-
-		set(cb.lastselecteditemindex, 0);
-		set(cb.selecteditemindex, 0);
-	</action>
-
-
-	<!-- dynamically remove a combobox element -->
-	<action name="removeComboboxLayer" scope="localonly" args="cbname">
-		if(global.layer[get(cbname)],
-			copy(cb, global.layer[get(cbname)]);
-			if(cb === global.openedcombobox, delete(global.openedcombobox));
-			if(cb,
-				removelayer(get(cbname), true);
-			);
-		);
-	</action>
-
-
-	<!-- default onclick event for combobox elements: open the list -->
-	<action name="combobox_onclick_event">
-		combobox_openlist(get(name));
-	</action>
-
-
-	<!-- dynamically add items -->
-	<action name="combobox_additem" scope="localonly" args="cbname, itemname, itemcaption, itemonclick, itemoninit">
-		copy(cb, global.layer[get(cbname)]);
-		
-		<!-- when no item name is set, generate an automatic one -->
-		if(itemname === null, calc(itemname, 'autoname_' + cb.item.count); );
-		
-		<!-- save the item caption and onclick event -->
-		copy(cb.item[get(itemname)].caption, itemcaption);
-		copy(cb.item[get(itemname)].onclick, itemonclick);
-
-		inc(cb.autosize_cnt);
-
-		<!-- create the item layer/textfield -->
-		calc(itemlayername, 'comboboxitem_' + cbname + '_' + itemname);
-		addlayer(get(itemlayername));
-		copy(li, global.layer[get(itemlayername)]);
-		li.loadstyle(combobox_item_style);
-		copyattributes(get(li), get(cb.cbdesign.style[combobox_item_style]));
-		copy(li.parent, cb.scrollarea.name);
-		copy(li.keep, true);
-		copy(li.cblayername, cb.name);
-		copy(li.itemname, itemname);
-		copy(li.html, itemcaption);
-		set(li.onautosized, delayedcall(0,combobox_item_autosize_update()) );
-		set(li.onclick, combobox_item_onclick() );
-		if (isset(itemoninit), callwith(li, itemoninit));
-
-		copy(cb.item[get(itemname)].itemlayername, itemlayername);
-		copy(cb.item[get(itemname)].itemlayer, li);
-	</action>
-
-
-	<!-- onautosized callback from the item textfield -->
-	<action name="combobox_item_autosize_update" scope="localonly">
-		copy(cb, global.layer[get(caller.cblayername)]);
-		inc(cb.autosize_i);
-		Math.max(cb.autosize_max_w, caller.width);
-		Math.max(cb.autosize_max_h, caller.height);
-		delayedcall(calc(cb.name + '_combobox_align_items'), 0.01, calc('combobox_align_items('+cb.name+')') );
-	</action>
-
-
-	<!-- align the image and set the combobox size -->
-	<action name="combobox_align_items" scope="localonly" args="cbname">
-		copy(cb, global.layer[get(cbname)]);
-		if(cb.marker.havemarkersize == false OR cb.scrollarea.loaded == false,
-			<!-- wait until everything is ready -->
-			delayedcall(calc(cb.name + '_waitformarkersize'), 0.01, combobox_align_items(get(cbname)) );
-		  ,
-			<!-- set the item positions and the combobox size -->
-			if(global.openedcombobox === cb, combobox_closelist() );
-			copy(sa, cb.scrollarea);
-			calc(itemwidth, cb.margin GT 0 ? -2 * cb.margin : '100%');
-			copy(mk_w, cb.marker.width);
-			copy(item_cnt, cb.autosize_cnt);
-
-			for(def(item_i, integer, 0), item_i LT item_cnt, inc(item_i),
-				copy(li, global.layer[get(cb.item[get(item_i)].itemlayername)]);
-				set(li.x, get(cb.margin));
-				copy(li.width, itemwidth);
-				copy(li.height, cb.autosize_max_h);
-				calc(li.y, cb.margin + item_i * (cb.autosize_max_h + cb.margin));
-			);
-
-			if(cb.width == null OR cb.width == cb.lastautosizedwidth,
-				<!-- no combobox width (or an autosized width) set - set the largest item width -->
-				calc(cb.width, cb.margin + cb.autosize_max_w + 2 + mk_w + cb.margin);
-				copy(cb.lastautosizedwidth, cb.width);
-			);
-
-			calc(cb.height, 2*cb.margin + cb.autosize_max_h);
-			calc(sa.height, cb.margin + item_cnt*(cb.margin+cb.autosize_max_h));
-			calc(sa.y, -(cb.selecteditemindex * (cb.autosize_max_h + cb.margin)));
-			calc(cb.marker.x, cb.margin + mk_w/2);
-			tween(global.layer[get(cb.name)].marker.y, calc(cb.margin + cb.selecteditemindex*(cb.autosize_max_h + cb.margin) + cb.autosize_max_h/2), 0.1);
-
-			<!-- when all is done, show the combobox -->
-			delayedcall(0.1, set(global.layer[get(cb.name)].visible,true); );
-		);
-	</action>
-
-
-	<!-- helper action for calling a plugin event-code with 'global' and 'caller' scope -->
-	<action name="combobox_do_event_call" scope="local" args="cb, eventcode">
-		if(eventcode !== null, callwith(cb, get(eventcode) ); );
-	</action>
-	
-
-	<!-- default onclick event for items: select the current item, close the list and call the item onclick event -->
-	<action name="combobox_item_onclick" scope="localonly">
-		copy(cb, global.layer[get(caller.cblayername)]);
-		copy(itemname, caller.itemname);
-		combobox_selectitem(get(cb.name), get(itemname));
-
-		if(global.openedcombobox === cb, combobox_closelist() );
-
-		if(cb.item[get(itemname)].onclick,
-			if(cb.callonclickafterclose === false,
-				<!-- call instantly -->
-				combobox_do_event_call(get(cb), get(cb.item[get(itemname)].onclick));
-			  ,
-				<!-- call the onclick event after the combobox has closed -->
-				delayedcall(get(cb.open_close_speed),
-					copy(cb.curitem, cb.item[get(itemname)]);
-					combobox_do_event_call(get(cb), get(cb.item[get(itemname)].onclick));
-				);
-			);
-		);
-	</action>
-
-
-	<!-- select an item -->
-	<action name="combobox_selectitem" scope="localonly" args="cbname, itemname">
-		if(global.combbox_item_pressed != true,
-			copy(cb, global.layer[get(cbname)]);
-			copy(cb.lastselecteditemindex, cb.selecteditemindex);
-			copy(cb.selecteditemindex, cb.item[get(itemname)].index);
-			<!-- call onchange event on selection change -->
-			if(cb.lastselecteditemindex != cb.selecteditemindex AND cb.onchange,
-				combobox_do_event_call(get(cb), get(cb.onchange));
-			);
-			if(global.openedcombobox === cb,
-				<!-- when opened, just close to the selected item -->
-				combobox_closelist();
-			  ,
-				if(global.layer[get(cbname)].scrollarea.loaded AND cb.autosize_max_h GT 0,
-					global.layer[get(cbname)].scrollarea.stopscrolling();
-					calc(offset, cb.selecteditemindex*(cb.autosize_max_h + cb.margin));
-					tween(global.layer[get(cbname)].marker.y, calc(cb.margin + offset + cb.autosize_max_h/2), 0);
-					tween(global.layer[get(cbname)].scrollarea.y, calc(-offset), 0, default, global.layer[get(cbname)].scrollarea.update(); );
-				);
-			);
-		);
-	</action>
-
-
-	<!-- find an item by its caption, the global variable defined in 'returnvariable' will contain the index  -->
-	<action name="combobox_finditem" scope="localonly" args="cbname, itemcaption, returnvariable">
-		copy(cb, global.layer[get(cbname)]);
-		copy(item_cnt, cb.item.count);
-		set(calc('global.' + returnvariable), -1);
-		for(def(item_i, integer, 0), item_i LT  item_cnt, inc(item_i),
-			if(cb.item[get(item_i)].caption == itemcaption,
-				copy(calc('global.' + returnvariable), item_i);
-				copy(item_i, item_cnt);
-			);
-		);
-	</action>
-
-
-	<!-- remove all items (to be able to add new ones) -->
-	<action name="combobox_removeitems" scope="localonly" args="cbname">
-		copy(cb, global.layer[get(cbname)]);
-		if(global.openedcombobox === cb, combobox_closelist() );
-
-		<!-- remove all item layers -->
-		calc(item_i, cb.item.count - 1);
-		loop(item_i GE 0,
-			removelayer(get(cb.item[get(item_i)].itemlayername));
-			dec(item_i);
-		);
-
-		<!-- reset the item information -->
-		set(cb.item.count, 0);
-		set(cb.autosize_i,0);
-		set(cb.autosize_cnt, 0);
-		set(cb.autosize_max_w, 0);
-		set(cb.autosize_max_h, 0);
-		set(cb.selecteditemindex, 0);
-		set(cb.lastselecteditemindex, 0);
-		if(cb.width == cb.lastautosizedwidth, set(cb.width, null));
-	</action>
-
-
-	<!-- open the combobox list -->
-	<action name="combobox_openlist" scope="localonly" args="cbname">
-		<!-- if another combobox is already open, close that one first -->
-		if(global.openedcombobox !== null, combobox_closelist() );
-
-		copy(cb, global.layer[get(cbname)]);
-		copy(global.openedcombobox, cb);
-		
-		<!-- move to top -->
-		copy(cb.backupzorder, cb.zorder);
-		set(cb.zorder, 999);
-
-		<!-- find the available screen space above or below the combobox -->
-		calc(cbheight, 2*cb.margin + cb.autosize_max_h);
-		set(lx1, 0);
-		set(ly1, 0);
-		copy(lx2, cb.pixelwidth);
-		copy(ly2, cbheight);
-		layertoscreen(get(cbname), lx1,ly1, lx1,ly1);
-		layertoscreen(get(cbname), lx2,ly2, lx2,ly2);
-		calc(space_above, ly1 - global.area.pixely);
-		calc(space_below, global.area.pixelheight - (ly2 - global.area.pixely));
-
-		<!-- the required space for full opening: -->
-		calc(openheight, cb.margin + cb.autosize_cnt*(cb.margin+cb.autosize_max_h) );
-		
-		<!-- vertical centered alignment? -->
-		calc(cb_edge, cb.edge ? cb.edge : cb.align);
-		calc(iscentered, cb_edge == 'left' OR cb_edge == 'center' OR cb_edge == 'right');
-		if(iscentered,
-			calc(openheight_max, space_above + space_below);
-		  ,
-			Math.max(openheight_max, space_above, space_below);
-		);
-
-		<!-- limit the height to the available space (minus some margin) -->
-		Math.min(openheight, calc(openheight_max + cbheight - 20));
-
-		clamp(openheight, 0, get(cb.maxopenheight));
-		
-		<!-- need vertical offset? (depending on the available space and the align/edge setting) -->
-		set(yoffset, null);
-		calc(top_overflow, -ly1 + global.area.pixely + openheight/2);
-		calc(bottom_overflow, ly2 - global.area.pixely + openheight/2 - global.area.pixelheight);
-		
-		if(cb.parentobject AND cb.parentobject.autoheight == false,
-			<!-- no vertical offset inside other layers, do only a height clipping -->
-			Math.max(max_overflow, top_overflow, bottom_overflow, 0);
-			sub(openheight, max_overflow);
-		  ,
-			if(iscentered,
-				if(openheight GE (global.area.pixelheight - 20),
-					set(yoffset,0);
-				  ,
-					if(top_overflow GT 0, calc(yoffset, cb.y + top_overflow); );
-					if(bottom_overflow GT 0, calc(yoffset, cb.y - bottom_overflow); );
-				);
-			,
-				indexoftxt(isbottomalign, get(cb_edge), 'bottom');
-				if(space_above GT space_below,
-					if(isbottomalign LT 0, calc(yoffset, cb.y - openheight + cbheight); );
-				  ,
-					if(isbottomalign GE 0, calc(yoffset, cb.y - openheight + cbheight); );
-				);
-			);
-		);
-		if(yoffset != null,
-			copy(cb.ybackup, cb.y);
-			tween(global.layer[get(cbname)].y, calc(yoffset), get(cb.open_close_speed));
-		);
-
-		<!-- center the opened list at the selected item -->
-		if( indexof(cb_edge,'top') GE 0,
-			calc(centeritem_y, -1 * (cb.margin + cb.selecteditemindex*(cb.margin+cb.autosize_max_h) - cb.margin));
-			clamp(centeritem_y, calc(openheight - cb.scrollarea.height), 0);
-		  ,
-			indexof(cb_edge,'bottom') GE 0,
-			calc(centeritem_y, -1 * (cb.margin + cb.selecteditemindex*(cb.margin+cb.autosize_max_h) + cb.autosize_max_h - openheight + cb.margin));
-			clamp(centeritem_y, calc(openheight - cb.scrollarea.height), 0);
-		  ,
-			calc(centeritem_y, -1 * (cb.margin + cb.selecteditemindex*(cb.margin+cb.autosize_max_h) + cb.autosize_max_h/2 - openheight/2));
-			clamp(centeritem_y, calc(openheight - cb.scrollarea.height), 0);
-		);
-
-		<!-- apply the changes now -->
-		tween(global.layer[get(cbname)].height, get(openheight), get(cb.open_close_speed));
-		tween(global.layer[get(cbname)].scrollarea.y, get(centeritem_y), get(cb.open_close_speed), default, global.layer[get(cbname)].scrollarea.update(); );
-
-		tween(global.layer[get(cbname)].marker.rotate, 90, get(cb.open_close_speed));
-		
-		<!-- enable the scrollarea to allow the user to drag it -->
-		set(cb.scrollarea.enabled, true);
-
-		<!-- install a global onmousedown event to close the list when clicking at the pano -->
-		set(global.events[combobox_xml_plugin_events].onmousedown, combobox_closelist() );
-	</action>
-
-
-	<!-- close the current open list -->
-	<action name="combobox_closelist" scope="localonly">
-		if(global.openedcombobox !== null,
-			copy(cb, global.openedcombobox);
-			delete(global.openedcombobox);
-			
-			<!-- restore zorder -->
-			copy(cb.zorder, cb.backupzorder);
-			
-			<!-- clear the global onmousedown event -->
-			set(global.events[combobox_xml_plugin_events].onmousedown, null);
-
-			<!-- disable the dragging -->
-			set(cb.scrollarea.enabled, false);
-
-			<!-- closing animations -->
-			calc(offset, cb.selecteditemindex*(cb.autosize_max_h + cb.margin));
-			if(cb.ybackup !== null, tween(cb.y, get(cb.ybackup), get(cb.open_close_speed)));
-			global.layer[get(cb.name)].scrollarea.stopscrolling();
-			tween(global.layer[get(cb.name)].height, calc(2*cb.margin + cb.autosize_max_h), get(cb.open_close_speed));
-			tween(global.layer[get(cb.name)].scrollarea.y, calc(-offset), get(cb.open_close_speed), default, global.layer[get(cb.name)].scrollarea.update(); );
-			tween(global.layer[get(cb.name)].marker.y, calc(cb.margin + offset + cb.autosize_max_h/2), get(cb.open_close_speed));
-			tween(global.layer[get(cb.name)].marker.rotate, 0, get(cb.open_close_speed));
-		);
-	</action>
-
-</krpano>

+ 0 - 48
public/plugins/doubleclick_style.xml

@@ -1,48 +0,0 @@
-<krpano>
-	
-	<!--
-		doubleclick_style.xml
-		krpano 1.21
-	
-		A helper style for single/double-click detection for layer and hotspot elements.
-		
-		Example:
-		
-		<layer ...
-		       style="doubleclick"
-		       onsingleclick="trace('-single click-');"
-		       ondoubleclick="trace('-double click-');"
-		       />
-	-->
-	
-	<style name="doubleclick"
-	       downx="0"
-	       downy="0"
-	       clicks="0"
-	       onsingleclick=""
-	       ondoubleclick=""
-	       onclick.addevent="doubleclick_style_onclick();"
-	       />
-
-	<action name="doubleclick_style_onclick">
-	    inc(clicks);
-	    if(clicks == 2,
-	        set(clicks,0); 
-	        stopdelayedcall(doubleclickdetector);
-	        if((((mouse.x-downx)^2 + (mouse.y-downy)^2)^0.5) LT (device.touch ? 10 : 2),
-	            ondoubleclick();
-	          ,
-	            onsingleclick();
-	            onsingleclick();
-	        );
-	      ,
-	        copy(downx, mouse.x); 
-	        copy(downy, mouse.y);
-	        delayedcall(doubleclickdetector, 0.3, 
-	            set(clicks,0); 
-	            onsingleclick();
-	        );
-	    );
-	</action>
-	
-</krpano>

+ 0 - 28
public/plugins/fps.xml

@@ -1,28 +0,0 @@
-<krpano>
-
-	<!--
-		FPS (frames per second) performance measuring tool.
-		This tools shows the current average rendering frame-rate in the left-top corner.
-	-->
-
-	<action name="fps_install" autorun="preinit" scope="local">
-		delayedcall(0.5,
-			addlayer(fps_display);
-			set(layer[fps_display],
-				type=text,
-				keep=true,
-				align='lefttop',
-				css=calc('font-size:'+(device.mobile AND stagescale LT 1.0 ? 24 : 12)+'px; color:#FFFFFF;'),
-				txtshadow='0 0 1 0x000000 1.0',
-				bg=false,
-				parent=STAGE,
-				vr=true,
-				enabled=false
-			);
-			setinterval(fps_plugin, 0.5,
-				calc(layer[fps_display].html, 'FPS: ' + ((display.currentfps+0.5) BOR 0));
-			);
-		);
-	</action>
-
-</krpano>

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 5
public/plugins/googlemaps.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 5
public/plugins/gyro2.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 5
public/plugins/pp_blur.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 5
public/plugins/pp_light.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 5
public/plugins/pp_sharpen.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 19
public/plugins/scrollarea.js


+ 0 - 212
public/plugins/showtext.xml

@@ -1,212 +0,0 @@
-<krpano>
-	<!--
-		showtext() xml plugin
-		- showtext() and <textstyle> support for HTML5
-		- docu: https://krpano.com/plugins/showtext/
-		- krpano 1.21
-	-->
-
-
-	<!-- predefine a DEFAULT textstyle element -->
-	<textstyle name="DEFAULT" />
-	
-	
-
-
-	<!-- the automatic running (autorun=preinit) install action -->
-	<action name="showtext_install" autorun="preinit" scope="private:showtext">
-		<!-- remove the built-in 'showtext' function to use the 'showtext' <action> instead: -->
-		delete(global.showtext);
-
-		<!-- initialize internal variables -->
-		set(showtext_style, DEFAULT);
-		set(showtext_prevstyle, null);
-		set(showtext_text, '');
-		set(showtext_prevtext, '');
-		set(showtext_timeout, 0.1);
-		set(showtext_fadeout, 0.0);
-		set(showtext_clipping, false);
-	</action>
-	
-
-	<action name="showtext" scope="private:showtext" args="text, style">
-		if(!style, set(style, DEFAULT));
-		
-		if(global.textstyle[get(style)], 
-			copy(showtext_style, style);
-		  ,
-			warning("showtext() - there is no textstyle '", style, "' defined!");
-			global.textstyle.createarrayitem(get(style));
-		);
-
-		copy(showtext_text, text);
-		
-		if(showtext_text != showtext_prevtext,
-			copy(showtext_prevtext, showtext_text);
-			showtext_createnewtext();
-		  ,
-			delayedcall(showtext_timer, get(showtext_timeout), showtext_hide() );
-		  );
-	</action>
-	
-
-	<action name="showtext_createnewtext" scope="private:showtext">
-		<!-- stop running mouse and alpha update calls -->
-		stopdelayedcall(showtext_mouseupdates);
-		stoptween(global.layer[showtext_tf].alpha);
-
-		<!-- remove the old textfield when the style has changed -->
-		if(showtext_style != showtext_prevstyle,
-			copy(showtext_prevstyle, showtext_style);
-			removelayer(showtext_tf);
-		  );
-		  
-		<!-- create a new textfield plugin layer -->
-		addlayer(showtext_tf);
-
-		<!-- create 'shortcut' variables (tf,ts) for faster access -->
-		copy(tf, global.layer[showtext_tf]);
-		copy(ts, global.textstyle[get(showtext_style)]);
-
-		<!-- get the position settings -->
-		if(ts.origin  !== null, copy(ts_origin,  ts.origin),  set(ts_origin, 'cursor'));
-		if(ts.edge    !== null, copy(ts_edge,    ts.edge),    set(ts_edge, 'bottom'));
-		if(ts.xoffset !== null, copy(ts_xoffset, ts.xoffset), set(ts_xoffset, 0));
-		if(ts.yoffset !== null, copy(ts_yoffset, ts.yoffset), set(ts_yoffset, -3));
-
-		<!-- set the position settings -->
-		if(ts_origin == 'cursor',
-			set(tf.align, 'lefttop');
-			showtext_movetomouse();
-		  ,
-			copy(tf.align, ts_origin);
-		  );
-		copy(tf.edge, ts_edge);
-		copy(tf.ox, ts_xoffset);
-		copy(tf.oy, ts_yoffset);
-
-		<!-- get the font settings -->
-		if(ts.font      !== null, copy(ts_font,      ts.font),      set(ts_font, 'Times'));
-		if(ts.fontsize  !== null, copy(ts_fontsize,  ts.fontsize),  set(ts_fontsize, 12.0));
-		if(ts.bold      !== null, copy(ts_bold,      ts.bold),      set(ts_bold, true));
-		if(ts.italic    !== null, copy(ts_italic,    ts.italic),    set(ts_italic, false));
-		if(ts.textcolor !== null, copy(ts_textcolor, ts.textcolor), set(ts_textcolor, 0x000000));
-		if(ts.textalign !== null, copy(ts_textalign, ts.textalign), set(ts_textalign, 'left'));
-
-		<!-- use the font settings to build the CSS style -->
-		set(tf_css, '');
-		tohex(ts_textcolor, '#', 6);
-		txtadd(tf_css, 'font-family:',get(ts_font),'; font-size:',get(ts_fontsize),'px; color:',get(ts_textcolor),'; ');
-		if(ts_textalign != 'none', txtadd(tf_css, get(tf_css), 'text-align:',get(ts_textalign),'; '));
-		if(ts_bold,   txtadd(tf_css, 'font-weight:bold; '));
-		if(ts_italic, txtadd(tf_css, 'font-style:italic; '));
-		if(ts.css !== null, txtadd(tf_css, get(ts.css)));
-		copy(tf.css, tf_css);
-
-		<!-- size settings -->
-		if(ts.width   !== null AND ts.width   !== '', copy(tf.width,   ts.width));
-		if(ts.height  !== null AND ts.height  !== '', copy(tf.height,  ts.height));
-		if(ts.vcenter !== null AND ts.vcenter !== '', copy(tf.vcenter, ts.vcenter));
-		if(ts.padding !== null AND ts.padding !== '', copy(tf.padding, ts.padding), set(tf.padding,1));
-
-		<!-- background, border, shadow settings -->
-		if(ts.background      !== null, copy(tf.background,      ts.background));
-		if(ts.backgroundcolor !== null, copy(tf.backgroundcolor, ts.backgroundcolor));
-		if(ts.backgroundalpha !== null, copy(tf.backgroundalpha, ts.backgroundalpha));
-		if(ts.border          !== null, copy(tf.border,          ts.border), set(tf.border,true));
-		if(ts.bordercolor     !== null, copy(tf.bordercolor,     ts.bordercolor));
-		if(ts.borderalpha     !== null, copy(tf.borderalpha,     ts.borderalpha));
-		if(ts.borderwidth     !== null, copy(tf.borderwidth,     ts.borderwidth));
-		if(ts.roundedge       !== null, copy(tf.roundedge,       ts.roundedge));
-		if(ts.shadow          !== null, copy(tf.shadow,          ts.shadow));
-		if(ts.shadowrange     !== null, copy(tf.shadowrange,     ts.shadowrange));
-		if(ts.shadowangle     !== null, copy(tf.shadowangle,     ts.shadowangle));
-		if(ts.shadowcolor     !== null, copy(tf.shadowcolor,     ts.shadowcolor));
-		if(ts.shadowalpha     !== null, copy(tf.shadowalpha,     ts.shadowalpha));
-		if(ts.textshadow      !== null, copy(tf.textshadow,      ts.textshadow));
-		if(ts.textshadowrange !== null, copy(tf.textshadowrange, ts.textshadowrange));
-		if(ts.textshadowangle !== null, copy(tf.textshadowangle, ts.textshadowangle));
-		if(ts.textshadowcolor !== null, copy(tf.textshadowcolor, ts.textshadowcolor));
-		if(ts.textshadowalpha !== null, copy(tf.textshadowalpha, ts.textshadowalpha));
-
-		<!-- showing settings -->
-		if(ts.alpha      !== null, copy(ts_alpha,      ts.alpha),      set(ts_alpha, 1.0));
-		if(ts.showtime   !== null, copy(ts_showtime,   ts.showtime),   set(ts_showtime, 0.1));
-		if(ts.fadetime   !== null, copy(ts_fadetime,   ts.fadetime),   set(ts_fadetime, 0.0));
-		if(ts.fadeintime !== null, copy(ts_fadeintime, ts.fadeintime), set(ts_fadeintime, 0.0));
-		copy(showtext_timeout, ts_showtime);
-		copy(showtext_fadeout, ts_fadetime);
-		if(ts_fadeintime GT 0,
-			set(tf.alpha, 0.0);
-			tween(global.layer[showtext_tf].alpha, get(ts_alpha), get(ts_fadeintime), linear);
-		  ,
-			copy(tf.alpha, ts_alpha);
-		  );
-
-		if(ts.noclip !== null, copy(showtext_clipping,ts.noclip), set(showtext_clipping, true));
-		
-		if(showtext_clipping,
-			set(tf.onloaded,    showtext_do_clipping() );
-			set(tf.onautosized, showtext_do_clipping() );
-		  );
-
-		<!-- special flash-only settings -->
-		if(ts.embeddedfonts !== null, copy(tf.embeddedfonts, ts.embeddedfonts));
-		if(ts.effect        !== null, copy(tf.effect,        ts.effect));
-		if(ts.blendmode     !== null, copy(tf.blendmode,     ts.blendmode));
-
-		<!-- set the text and the basic settings to start showing the textfield -->
-		copy(tf.html, showtext_text);
-		set(tf.enabled, false);
-		set(tf.zorder, 999999);
-		if(ts.parent, copy(tf.parent, ts.parent) );
-		set(tf.type, 'text');
-
-		<!-- start the text-hiding timer -->
-		delayedcall(showtext_timer, get(showtext_timeout), showtext_hide() );
-	</action>
-
-
-	<action name="showtext_do_clipping" scope="private:showtext">
-		if(showtext_clipping,
-			global.layer[showtext_tf].updatepos();
-			copy(tf_px, global.layer[showtext_tf].pixelx);
-			copy(tf_py, global.layer[showtext_tf].pixely);
-			if(tf_px LT 0,
-				sub(global.layer[showtext_tf].x, tf_px);
-			  ,
-				add(tf_rightedge, tf_px, global.layer[showtext_tf].pixelwidth);
-				if(tf_rightedge GE global.stagewidth, sub(tf_rightedge,global.stagewidth); sub(global.layer[showtext_tf].x,tf_rightedge); );
-			  );
-			if(tf_py LT 0,
-				sub(global.layer[showtext_tf].y,  tf_py);
-			  ,
-				add(tf_bottomedge, tf_py, global.layer[showtext_tf].pixelheight);
-				if(tf_bottomedge GE global.stageheight, sub(tf_bottomedge,global.stageheight); sub(global.layer[showtext_tf].y,tf_bottomedge); );
-			  );
-		  );
-	</action>
-
-
-	<action name="showtext_movetomouse" scope="private:showtext">
-		copy(global.layer[showtext_tf].x, global.mouse.stagex);
-		copy(global.layer[showtext_tf].y, global.mouse.stagey);
-
-		showtext_do_clipping();
-
-		delayedcall(showtext_mouseupdates, 0, showtext_movetomouse() );
-	</action>
-
-
-	<action name="showtext_hide" scope="private:showtext">
-		if(global.layer[showtext_tf],
-			tween(global.layer[showtext_tf].alpha, 0.0, get(showtext_fadeout), linear,
-					stopdelayedcall(showtext_mouseupdates);
-					removelayer(showtext_tf);
-					set(showtext_text, '');
-					set(showtext_prevtext, '');
-				);
-		  );
-	</action>
-
-</krpano>

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 5
public/plugins/soundinterface.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 5
public/plugins/videoplayer.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 5
public/plugins/webvr.js


+ 0 - 942
public/plugins/webvr.xml

@@ -1,942 +0,0 @@
-<krpano>
-	
-	<!--
-		webvr.xml
-		krpano 1.21
-		
-		https://krpano.com/plugins/xmlextensions/#webvr
-		https://krpano.com/plugins/webvr/
-	-->
-	
-
-	<!-- load the WebVR plugin and assign it to a global 'webvr' variable -->
-	<plugin name="webvr" devices="html5" keep="true"
-	        url="webvr.js"
-	        mobilevr_support="true"
-	        mobilevr_touch_support="true"
-	        mobilevr_fake_support="true"
-	        mobilevr_profile.normal="90|60|42|0|0|0"
-	        mobilevr_profile.mobile="80|60|42|35|0.441|0.156"
-	        mobilevr_wakelock="true"
-	        fullscreen_mirroring="false"
-	        mouse_pointerlock="true"
-	        vr_cursor_onover="if(handcursor, tween(hotspot[vr_cursor].scale,0.4,0.1); vr_auto_click(get(vr_timeout)); );"
-	        vr_cursor_onout="tween(hotspot[vr_cursor].scale,0.3,0.1);"
-	        onavailable="webvr_onavailable();"
-	        onunavailable=""
-	        onunknowndevice="webvr_onunknowndevice();"
-	        onvrcontrollers="webvr_onvrcontrollers();"
-	        onentervr="webvr_onentervr();"
-	        onexitvr="webvr_onexitvr();"
-	        ondenied="webvr_ondenied();"
-	        />
-
-
-
-	<!-- the VR cursor hotspot -->
-	<style name="vr_cursor_style" 
-		url="webvr_vrcursor.png"
-		visible="false"
-		enabled="false"
-		distorted="true"
-		crop="0|0|80|80"
-		scale="0.3"
-		depth="120"
-		/>
-	
-	<action name="webvr_load_vr_cursor_hs" scope="local">
-		addhotspot('vr_cursor', hs);
-		hs.loadstyle(vr_cursor_style);
-		set(hs.keep, true);
-		set(webvr.vr_cursor, 'hotspot[vr_cursor]');
-	</action>
-	
-	<action name="webvr_load_vr_controller_hs" scope="private:VRCONTROLLERS" args="controllerstyle">
-		removehotspot('vr_controller_l');
-		removehotspot('vr_controller_r');
-		addhotspot('vr_controller_l', vr_ctrl_l);
-		addhotspot('vr_controller_r', vr_ctrl_r);
-		set(vr_ctrl_l.keep, true);
-		set(vr_ctrl_r.keep, true);
-		vr_ctrl_l.loadstyle(calc(controllerstyle ? controllerstyle : (global.display.depthbuffer ? 'vrcontroller_laser' : 'vrcontroller_light_and_point')));
-		vr_ctrl_r.loadstyle(calc(controllerstyle ? controllerstyle : (global.display.depthbuffer ? 'vrcontroller_laser' : 'vrcontroller_light_and_point')));
-
-		<!-- optional: vibrate the controllers on hovering:
-		vr_ctrl_l.addevent('onover', pulse(1.0, 0.25) );
-		vr_ctrl_r.addevent('onover', pulse(1.0, 0.25) ); -->
-		if(!global.webvr.iswebxr,
-			vr_ctrl_l.addevent('onvrcontrollerbutton', 'if(vrbuttonindex == 3 AND vrbuttonstate == "up", vrsetup_open(); );' );
-			vr_ctrl_r.addevent('onvrcontrollerbutton', 'if(vrbuttonindex == 3 AND vrbuttonstate == "up", vrsetup_open(); );' );
-		);
-		
-		set(global.webvr.vr_controller, 'vr_controller_l,vr_controller_r');
-		set(global.have_vr_controllers, true);
-		
-		if(global.webvr.isvrbrowser AND global.webvr.vrcontrollers[0].buttons.length LE 2,
-			<!-- when there are only two buttons on the VR controller (e.g. Oculus Go) use an extra hotspot for the VR-setup -->
-			addhotspot('webvr_vrsetup', vr_setup_hs);
-			vr_setup_hs.loadstyle('webvr_button_style');
-			set(vr_setup_hs, keep=true, ath=0, atv=90, depth=160, zorder=999, torigin=view, html='VR SETUP', oversampling=3, scale=0.2, onclick='vrsetup_open();', onloaded='renderloop( copy(ath,view.hlookat); );');
-		);
-	</action>
-	
-	<action name="webvr_onvrcontrollers" scope="private:VRCONTROLLERS">
-		if(!global.have_vr_controllers, webvr_load_vr_controller_hs(); );
-	</action>
-		
-	<style name="vrcontroller_laser" 
-			url="webvr_laser.png"
-			distorted="true"
-			enabled="false"
-			visible="false"
-			width="0.5" height="1000" edge="bottom" oref="1" oy="0"
-			torigin="world" tx="0" ty="0" tz="0" depth="0"
-			zorder="99999"
-			depthbuffer="true"
-			targethitd.number="0"
-			onover="copy(targethitd, target.hitd);"
-			onout="set(targethitd, 0);"
-			onloaded="asyncloop(loaded, calc(height, (targethitd GT 0 ? targethitd : (hitd GT 0 ? hitd : 1000)) / display.hotspotworldscale); );"
-			/>
-			
-	<style name="vrcontroller_light_and_point" 
-			url="webvr_light.png"
-			distorted="true"
-			enabled="false"
-			visible="false"
-			width="0.5" height="18" edge="bottom" oref="1" oy="0"
-			torigin="world" tx="0" ty="0" tz="0" depth="0"
-			zorder="99999"
-			depthbuffer="true"
-			onloaded="vrcontroller_target_point();"
-			/>
-	
-	<style name="vrcontroller_handcursor_and_point" 
-			url="webvr_handcursor.png"
-			distorted="true"
-			enabled="false"
-			visible="false"
-			width="10" height="10" edge="center" oref="1" oy="-1"
-			torigin="world" tx="0" ty="0" tz="0" depth="0"
-			zorder="99999"
-			depthbuffer="true"
-			onloaded="vrcontroller_target_point();"
-			/>
-	
-	<action name="vrcontroller_target_point" scope="localonly">
-		addhotspot(auto, hs);
-		set(hs, keep=true, type=text, bgcolor=0xFFFFFF, bgalpha=1.0, width=10, height=10, bgroundedge=5, bgborder='1 0x000000 1.0', oversampling=2,
-			scale=0.4, torigin=world, depth=0, distorted=false, zoom=true, zorder=99998, enabled=false
-		  );
-		renderloop(
-			if(!caller.loaded,
-				removehotspot(get(hs.name));
-				stoprenderloop();
-			  ,
-				if(global.display.havedepthmap,
-					<!-- use the laser for depthmap panos -->
-					removehotspot(get(hs.name));
-					stoprenderloop();
-					webvr_load_vr_controller_hs('vrcontroller_laser');
-				  ,
-					calc(hs.bgcolor, caller.pressed ? 0x049AFF : (caller.hovering ? 0x00FF00 : 0xFFFFFF));
-					calc(distance, (caller.target AND caller.target.hitd GT 0 ? caller.target.hitd : (caller.hitd GT 0 ? caller.hitd : 1000)));
-					calc(hs.scale, 0.4 * (distance GT 1000 ? distance / 1000 : (distance LT 200 ? 0.25 : (0.25 + (distance - 200)/800 * 0.75))));
-					calc(hs.tx, caller.tx + caller.dx * distance);
-					calc(hs.ty, caller.ty + caller.dy * distance);
-					calc(hs.tz, caller.tz + caller.dz * distance);
-				);
-			);
-		);
-	</action>
-	
-
-
-
-	<!-- vr_auto_click() - call this action in the onover event of a
-	     hotspot to trigger automatically a click after some time.  -->
-	<action name="vr_auto_click" scope="local" args="vr_aclk_timeout">
-		if(webvr.isenabled,
-			if(vr_aclk_timeout == null, set(vr_aclk_timeout, 2000));
-			copy(vr_aclk_t1, timertick);
-			set(vr_aclk_waiting, true);
-			copy(webvr.vr_aclk_hotspot, caller.name);
-			set(hotspot[vr_cursor].crop,'0|0|80|80');
-
-			asyncloop(vr_aclk_waiting AND webvr.vr_aclk_hotspot == caller.name,
-				sub(dt, timertick, vr_aclk_t1);
-
-				if(!caller.hovering,
-					set(vr_aclk_waiting, false);
-					set(hotspot[vr_cursor].crop,'0|0|80|80');
-				  ,
-					div(f, dt, vr_aclk_timeout);
-					mul(f, 16);
-					roundval(f);
-					Math.min(f, 16);
-					mul(f, 80);
-
-					txtadd(hotspot[vr_cursor].crop,get(f),'|0|80|80');
-
-					<!-- wait another 100ms delay after finishing the animation before doing the click -->
-					sub(dt, 100);
-					if(dt GT vr_aclk_timeout,
-						set(vr_aclk_waiting,false);
-						set(hotspot[vr_cursor].crop,'0|0|80|80');
-						<!-- call onclick -->
-						callwith(caller, scope(global, ondown();onup();onclick(); ); );
-					);
-				);
-			);
-		);
-	</action>
-
-
-	<!-- by pressing SPACE the headset could be re-centered -->
-	<events name="webvr_events" devices="html5" keep="true"
-	        onmousedown="if(webvr AND webvr.isenabled, webvr_showbuttons() );"
-	        />
-
-
-
-	<!-- when WebVR support is available show an EnterVR button -->
-	<action name="webvr_onavailable">
-		webvr.loadsettings();
-		if(layer[webvr_enterbutton], delayedcall(0.5, tween(layer[webvr_enterbutton].alpha,1.0); ); );
-	</action>
-	
-	
-	<action name="webvr_onunknowndevice">
-		if(webvr.isfake AND device.desktop AND webvr.havesettings == false,
-			<!-- set the 'no distortion' headset for fake desktop usage -->
-			set(webvr.mobilevr_lens_overlap, 1.0);
-			set(webvr.mobilevr_lens_fov, 96.0);
-			set(webvr.mobilevr_lens_dist, 0.0);
-			set(webvr.mobilevr_lens_dist2, '1|0|0|0');
-			set(webvr.mobilevr_lens_ca, 0.0);
-			set(webvr.mobilevr_lens_vign, 100);
-		  );
-	</action>
-
-
-	<action name="webvr_onentervr">
-		if(layer[webvr_enterbutton], tween(layer[webvr_enterbutton].alpha,0,0); );
-
-		webvr_showbuttons();
-		webvr_hide_all_non_vr_layers();
-
-		if(webvr.isfake, webvr_show_fakemode_info(true); );
-		
-		webvr_load_vr_cursor_hs();
-	</action>
-
-
-	<action name="webvr_onexitvr">
-		removehotspot('vr_cursor');
-		removehotspot('vr_controller_l');
-		removehotspot('vr_controller_r');
-		set(have_vr_controllers, false);
-		
-		stopdelayedcall(vr_button_fadeout);
-
-		if(layer[webvr_enterbutton], tween(layer[webvr_enterbutton].alpha,1); );
-		tween(layer[webvr_exitbutton].alpha,0);
-		tween(layer[webvr_setupbutton].alpha,0);
-		
-		webvr_show_fakemode_info(false);
-
-		webvr_restore_layers();
-	</action>
-	
-	
-	<action name="webvr_ondenied" scope="local">
-		addlayer(webvr_ondenied_info);
-		layer[webvr_ondenied_info].loadstyle(webvr_button_style);
-		set(layer[webvr_ondenied_info],
-			align='center',
-			html='Entering VR mode was denied!',
-			onclick='set(enabled,false); tween(alpha,0,0.5,default,removelayer(get(name)));'
-		);
-		delayedcall(2.0,
-			callwith(layer[webvr_ondenied_info], onclick(); );
-		);
-	</action>
-
-
-	<action name="webvr_hide_all_non_vr_layers" scope="local">
-		for(set(i,0), i LT layer.count, inc(i),
-			copy(lr, layer[get(i)]);
-			if(lr.vr !== true,
-				copy(lr.vr_backup_visible, lr.visible);
-				set(lr.visible, false);
-			);
-		);
-	</action>
-
-	<action name="webvr_restore_layers" scope="local">
-		for(set(i,0), i LT layer.count, inc(i),
-			copy(lr, layer[get(i)]);
-			if(lr.vr_backup_visible,
-				copy(lr.visible, lr.vr_backup_visible);
-				delete(lr.vr_backup_visible);
-			);
-		);
-	</action>
-	
-	<action name="webvr_show_fakemode_info" scope="local" args="show">
-		if(show == true,
-			addlayer(webvr_fakemode_info);
-			set(layer[webvr_fakemode_info],
-				type='text',
-				keep=true,
-				align='bottom',
-				y=80,
-				bg=false,
-				css='color:#FFFFFF;text-align:center;',
-				html='[i][u]Simulated WebVR Mode![/u][br]For real WebVR with headset tracking use a [a href="http://webvr.info" target="_blank" style="color:#FFFFFF;"]WebVR-capable[/a] browser or a mobile device and a VR headset.[/i]'
-			);
-		  ,
-			removelayer(webvr_fakemode_info);
-		);
-	</action>
-	
-	
-	<!-- ensure the same scaling on mobiles (regardless if mobilescale is 0.5 or 1.0) -->
-	<krpano webvr_setup_scale="calc:(1.0 + 1.0*(device.mobile AND stagescale LT 1.0)) / (1.0 + 1.0*device.mobile)"
-	        webvr_button_scale.normal="1.0"
-	        webvr_button_scale.mobile="1.6"
-	        />
-
-	
-	<!-- the EnterVR/ExitVR and SetupVR buttons -->
-	<style name="webvr_button_style"
-	       type="text"
-	       bgcolor="0x000000"
-	       bgalpha="0.5"
-	       bgroundedge="0"
-	       css="calc:'color:#FFFFFF;font-size:' + 20*webvr_setup_scale*webvr_button_scale + 'px;'"
-	       padding="calc:6*webvr_setup_scale*webvr_button_scale + ' ' + 10*webvr_setup_scale*webvr_button_scale"
-	       />
-	
-	<layer name="webvr_enterbutton" keep="true" vr="true"
-	       style="webvr_button_style"
-	       html="Enter VR"
-	       align="top" y="24"
-	       autoalpha="true" alpha="0.0"
-	       onclick="webvr.enterVR();"
-	       />
-
-	<layer name="webvr_exitbutton" keep="true" vr="true"
-	       style="webvr_button_style"
-	       html="Exit VR"
-	       align="top" y="24"
-	       autoalpha="true" alpha="0.0"
-	       onclick="webvr.exitVR();"
-	       />
-
-	<layer name="webvr_setupbutton" keep="true" vr="true"
-	       style="webvr_button_style"
-	       html="VR Setup"
-	       align="bottom" y="24"
-	       autoalpha="true" alpha="0.0"
-	       onclick="vrsetup_open();"
-	       />
-
-
-	<action name="webvr_showbuttons">
-		stopdelayedcall(vr_button_fadeout);
-		tween(layer[webvr_exitbutton].alpha|layer[webvr_setupbutton].alpha, 1.0|1.0, 0.25);
-		delayedcall(vr_button_fadeout, 3.0, tween(layer[webvr_exitbutton].alpha|layer[webvr_setupbutton].alpha, 0.0|0.0, 1.0); );
-	</action>
-
-	
-		
-	<!-- VR SETUP -->
-	
-	
-	<mobilevr_presets>
-		<headset name="cbv1" caption="Cardboard V1"  profile="80|60|42|35|0.441|0.156" />
-		<headset name="cbv2" caption="Cardboard V2"  profile="120|64|39|35|0.34|0.55" />
-		<headset name="dydm" caption="Daydream"      profile="104|60|41|35|0.42|0.51" />
-		<headset name="nodt" caption="No Distortion" profile="90|60|42|0|0|0" />
-	</mobilevr_presets>
-
-	<action name="vrsetup_open">
-		if(!vrsetup_open_js, vrsetup_init(); );
-		vrsetup_open_js();
-	</action>
-		
-
-	<action name="vrsetup_init" type="Javascript"><![CDATA[
-		
-		var webvr = krpano.webvr;
-		var padding = 20;
-		
-		function vrsetup_dlg_create(type)
-		{
-			var dlg = {type:type, bg:null, y:0, scale:1, elements:[]};
-		
-			if (type == 'layer')
-			{
-				dlg.bg = krpano.addlayer();
-				dlg.bg.keep = true;
-				dlg.bg.type = 'container';
-				dlg.bg.align = 'center';
-			}
-			else	// 'hotspot'
-			{
-				dlg.scale = 0.15;
-				dlg.bg = krpano.addhotspot();
-				dlg.bg.keep = true;
-				dlg.bg.type = 'text';
-				dlg.bg.distorted = true;
-				dlg.bg.ath = krpano.view.hlookat;
-				dlg.bg.atv = 0;
-				dlg.bg.depth = 150;
-				dlg.bg.torigin = 'world';
-				dlg.bg.tx = krpano.view.tx;
-				dlg.bg.ty = krpano.view.ty;
-				dlg.bg.tz = krpano.view.tz;
-			}
-			
-			dlg.bg.bgcolor = 0x000000;
-			dlg.bg.bgalpha = 0.5;
-			dlg.bg.bgcapture = true;
-			dlg.bg.handcursor = false;
-			dlg.bg.capture = false;
-			dlg.bg.zorder = 100;
-			dlg.bg.visible = false;
-			
-			dlg.y = 0;
-			
-			return dlg;
-		}
-		
-		function vrsetup_dlg_addline(dlg, linetext, customcss, onclick)
-		{
-			var txt;
-			
-			if (dlg.type == 'layer')
-			{
-				txt = krpano.addlayer();
-				txt.keep = true;
-				txt.type = 'text';
-				txt.align = 'center';
-				txt.zorder = 101;
-			}
-			else	// 'hotspot'
-			{
-				txt = krpano.addhotspot();
-				txt.keep = true;
-				txt.type = 'text';
-				txt.distorted = true;
-				txt.zorder = 101;
-				txt.ath = dlg.bg.ath;
-				txt.atv = dlg.bg.atv;
-				txt.depth = dlg.bg.depth - 1;
-				txt.oversampling = 2;
-				txt.scale = dlg.scale;
-				txt.torigin = dlg.bg.torigin;
-				txt.tx = dlg.bg.tx;
-				txt.ty = dlg.bg.ty;
-				txt.tz = dlg.bg.tz;
-			}
-			
-			txt.onautosized = function()
-			{
-				txt.havesize = true;
-			}
-			
-			txt.edge = 'top';
-			txt.visible = false;
-			txt.bg = false;
-			txt.html = "" + linetext;
-			txt.css = 'font-size:32px;font-weight:bold;color:#FFFFFF; line-height:90%;' + (customcss || '');
-			
-			if (onclick)
-			{
-				txt.onclick = onclick;
-			}
-			else
-			{
-				txt.enabled = false;
-			}
-			
-			dlg.elements.push( txt );
-			
-			return txt;
-		}
-		
-		function vrsetup_dlg_addctrl(dlg, changedelay, callback)
-		{
-			var txt = vrsetup_dlg_addline(dlg, callback(0) );
-			
-			var inc;
-			var dec;
-			
-			if(dlg.type == 'layer')
-			{
-				inc = krpano.addlayer();
-				inc.keep = true;
-				inc.type = 'text';
-				inc.align = 'center';
-				inc.zorder = 101;
-				
-				dec = krpano.addlayer();
-				dec.keep = true;
-				dec.type = 'text';
-				dec.align = 'center';
-				dec.zorder = 101;
-			}
-			else	// 'hotspot'
-			{
-				inc = krpano.addhotspot();
-				inc.keep = true;
-				inc.type = 'text';
-				inc.distorted = true;
-				inc.zorder = 101;
-				inc.ath = dlg.bg.ath;
-				inc.atv = dlg.bg.atv;
-				inc.depth = dlg.bg.depth - 1;
-				inc.oversampling = 2;
-				inc.scale = dlg.scale;
-				inc.torigin = dlg.bg.torigin;
-				inc.tx = dlg.bg.tx;
-				inc.ty = dlg.bg.ty;
-				inc.tz = dlg.bg.tz;
-				
-				dec = krpano.addhotspot();
-				dec.keep = true;
-				dec.type = 'text';
-				dec.distorted = true;
-				dec.zorder = 101;
-				dec.ath = dlg.bg.ath;
-				dec.atv = dlg.bg.atv;
-				dec.depth = dlg.bg.depth - 1;
-				dec.oversampling = 2;
-				dec.scale = dlg.scale;
-				dec.torigin = dlg.bg.torigin;
-				dec.tx = dlg.bg.tx;
-				dec.ty = dlg.bg.ty;
-				dec.tz = dlg.bg.tz;
-			}
-			
-			inc.edge = 'top';
-			inc.visible = false;
-			inc.bg = false;
-			inc.html = '&#62;';
-			inc.css = 'font-size:32px;font-weight:bold;color:#FFFFFF; line-height:90%;';
-			inc.padding = '0 10';
-					
-			dec.edge = 'top';
-			dec.visible = false;
-			dec.bg = false;
-			dec.html = '&#60;';
-			dec.css = 'font-size:32px;font-weight:bold;color:#FFFFFF; line-height:90%;';
-			dec.padding = '0 10';
-			
-			inc.vr_timeout = changedelay * 1000;
-			dec.vr_timeout = changedelay * 1000;
-			inc.ondown = function(){ txt.html = ""+callback(+1); inc.enabled = false; setTimeout(function(){ inc.enabled = true; },0); };
-			dec.ondown = function(){ txt.html = ""+callback(-1); dec.enabled = false; setTimeout(function(){ dec.enabled = true; },0); };
-			
-			txt.ctrlchilds = [inc,dec];
-			
-			txt.updateControl = function()
-			{
-				txt.html = callback(0);
-			}
-			
-			return txt;
-		}
-		
-		function vrsetup_dlg_addspace(dlg, customspace)
-		{
-			dlg.elements.push(customspace|| padding);
-		}
-		
-		function vrsetup_dlg_finish(dlg)
-		{
-			var i, w=0, h=0;
-			var waitforsizes=false;
-			
-			for (i=0; i < dlg.elements.length; i++)
-			{
-				var e = dlg.elements[i];
-				if ( isNaN(e) )
-				{
-					if ( e.havesize )
-					{
-						w = Math.max( w, e.width * 1);
-						h += e.height * 1;
-					}
-					else
-					{
-						waitforsizes = true;
-						break;
-					}
-				}
-				else
-				{
-					h += e;
-				}
-			}
-			
-			if (waitforsizes)
-			{
-				setTimeout( function(){ vrsetup_dlg_finish(dlg); }, 16 ); 
-			}
-			else
-			{
-				var y = 0;
-				
-				dlg.bg.width = Math.ceil((w + padding*2)*dlg.scale);
-				dlg.bg.height = Math.ceil((h + padding*2)*dlg.scale);
-					
-				for (i=0; i < dlg.elements.length; i++)
-				{
-					var e = dlg.elements[i];
-					if ( isNaN(e) )
-					{
-						e.oy = Math.round((-h/2 + y) * dlg.scale);
-						e.visible = true;
-						
-						y += e.height * 1;
-						
-						if (e.ctrlchilds )
-						{
-							for (var j=0; j < e.ctrlchilds.length; j++)
-							{
-								var sube = e.ctrlchilds[j];
-								sube.ox = Math.round(((j&1)-0.5) * (-w) * dlg.scale);
-								sube.oy = e.oy;
-								sube.visible = true;
-							}
-						}
-					}
-					else
-					{
-						y += e;
-					}
-				}
-				
-				dlg.bg.visible = true;
-			}
-		}
-		
-		function vrsetup_dlg_remove(dlg)
-		{
-			var removefu = dlg.type == 'layer' ? krpano.removelayer : krpano.removehotspot;
-			
-			var i,j;
-			for (i=0; i < dlg.elements.length; i++)
-			{
-				var e = dlg.elements[i];
-				if ( isNaN(e) )
-				{
-					if (e.ctrlchilds )
-					{
-						for (j=0; j < e.ctrlchilds.length; j++)
-						{
-							var sube = e.ctrlchilds[j];
-							removefu(sube.name);
-						}
-					}
-					
-					removefu(e.name);
-				}
-			}
-			
-			removefu(dlg.bg.name);
-		}
-		
-		
-		function vrsetup_webvr_dialog()
-		{
-			// WebVR API rendering
-			var dlg = vrsetup_dlg_create('hotspot');
-			vrsetup_dlg_addline(dlg, 'WebVR Setup');
-			vrsetup_dlg_addspace(dlg);
-			
-			vrsetup_dlg_addline(dlg, 'Oversampling:', 'font-size:16px;')
-			var ctrl_ss = vrsetup_dlg_addctrl(dlg, 1.0, function(change)
-			{
-				var p = webvr.oversampling;
-				
-				if (change < 0) { p = Math.max(0.2, Number(p) - 0.1); webvr.oversampling = p;  } else 
-				if (change > 0) { p = Math.min(4.0, Number(p) + 0.1); webvr.oversampling = p;  }
-				
-				krpano.actions.delayedcall(0.3, function()
-				{
-					renderres.html = webvr.renderwidth + "x" + webvr.renderheight;
-				});
-				
-				return p.toFixed(1);
-			});
-			vrsetup_dlg_addspace(dlg,8);
-			vrsetup_dlg_addline(dlg, 'Rendering Resolution:', 'font-size:16px;');
-			var renderres = vrsetup_dlg_addline(dlg, '');
-			vrsetup_dlg_addspace(dlg);
-			vrsetup_dlg_addline(dlg, 'CLOSE', '', vrsetup_close);
-			vrsetup_dlg_finish(dlg);
-			
-			return dlg;
-		}
-		
-		function vrsetup_mobilevr_dialog()
-		{
-			// MobileVR / Cardboard rendering
-			var dlg = vrsetup_dlg_create(0 ? 'hotspot' : 'layer');
-			vrsetup_dlg_addline(dlg, 'MobileVR SETUP');
-			vrsetup_dlg_addspace(dlg);
-			vrsetup_dlg_addline(dlg, 'Screensize (inch):', 'font-size:16px;')
-			vrsetup_dlg_addctrl(dlg, 1.0, function(change){ var ss = Number(webvr.mobilevr_screensize); if (isNaN(ss)) ss = 5.0; if (change < 0) { ss = Math.max(4.0, ss - 0.1); webvr.mobilevr_screensize = ss; } else if (change > 0) { ss = Math.min(10.0, ss + 0.1); webvr.mobilevr_screensize = ss; } return ss.toFixed(1); });
-			vrsetup_dlg_addspace(dlg);
-			vrsetup_dlg_addline(dlg, 'VR Headset Preset:', 'font-size:16px;')
-			var ctrl_ps = vrsetup_dlg_addctrl(dlg, 1.0, function(change)
-			{
-				var preset_index = -1;
-				var i;
-				
-				var profile = webvr.mobilevr_profile;
-				var presets = krpano.get("mobilevr_presets.headset");
-				if (presets)
-				{
-					presets = presets.getArray();
-					
-					for (i=0; i < presets.length; i++)
-					{
-						if ( profile == presets[i].profile )
-						{
-							preset_index = i;
-							break;
-						}
-					}
-					
-					if (change < 0)
-					{
-						preset_index--;
-						if (preset_index < 0)
-							preset_index = presets.length - 1;
-								
-						webvr.mobilevr_profile = presets[preset_index].profile;
-					}
-					else if (change > 0)
-					{
-						preset_index++;
-						if (preset_index >= presets.length)
-							preset_index = 0;
-						
-						webvr.mobilevr_profile = presets[preset_index].profile;
-					}
-				}
-					
-				if (preset_index >= 0)
-				{
-					return presets[preset_index].caption;
-				}
-				
-				return 'Custom';
-			});
-			vrsetup_dlg_addspace(dlg);
-			vrsetup_dlg_addline(dlg, 'Customize Headset', 'font-size:25px;', function()
-			{
-				vrsetup_dlg_remove(dlg); 
-				dlg=null; 
-				
-				vrsetup_dialog = vrsetup_mobilevr_interactive_dialog();
-				
-			});
-			vrsetup_dlg_addline(dlg, '(Interactive Adjustment in VR)', 'font-size:12px;');
-			vrsetup_dlg_addspace(dlg);
-			vrsetup_dlg_addline(dlg, 'CLOSE', '', vrsetup_close);
-			vrsetup_dlg_finish(dlg);
-			
-			return dlg;
-		}
-		
-		function vrsetup_mobilevr_interactive_dialog()
-		{
-			// MobileVR / Cardboard rendering
-			var ctrl_preset, ctrl_fov, ctrl_ild, ctrl_stl, ctrl_ttl, ctrl_k1, ctrl_k2, ctrl_os;
-			
-			var dlg = vrsetup_dlg_create('hotspot');
-			vrsetup_dlg_addline(dlg, 'MobileVR SETUP');
-			vrsetup_dlg_addspace(dlg);
-			vrsetup_dlg_addline(dlg, 'Preset:', 'font-size:16px;')
-			
-			ctrl_preset = vrsetup_dlg_addctrl(dlg, 1.0, function(change)
-			{
-				var preset_index = -1;
-				var i;
-				
-				var profile = webvr.mobilevr_profile;
-				var presets = krpano.get("mobilevr_presets.headset");
-				if (presets)
-				{
-					presets = presets.getArray();
-					
-					for (i=0; i < presets.length; i++)
-					{
-						if ( profile == presets[i].profile )
-						{
-							preset_index = i;
-							break;
-						}
-					}
-					
-					if (change < 0)
-					{
-						preset_index--;
-						if (preset_index < 0)
-							preset_index = presets.length - 1;
-								
-						webvr.mobilevr_profile = presets[preset_index].profile;
-					}
-					else if (change > 0)
-					{
-						preset_index++;
-						if (preset_index >= presets.length)
-							preset_index = 0;
-						
-						webvr.mobilevr_profile = presets[preset_index].profile;
-					}
-					
-					if (change != 0)
-					{
-						ctrl_fov.updateControl();
-						ctrl_ild.updateControl();
-						ctrl_stl.updateControl();
-						if (ctrl_ttl) ctrl_ttl.updateControl();
-						ctrl_k1.updateControl();
-						ctrl_k2.updateControl();
-					}
-				}
-			
-				if (preset_index >= 0)
-				{
-					return presets[preset_index].caption;
-				}
-				
-				return 'Custom';
-			});
-			
-			vrsetup_dlg_addspace(dlg);
-			vrsetup_dlg_addline(dlg, 'Lens-Field-of-View:', 'font-size:16px;');
-			ctrl_fov = vrsetup_dlg_addctrl(dlg, 0.25, function(change){ var p = webvr.mobilevr_profile.split("|"); if (change < 0) { p[0] = Number(p[0]) - 1.0; webvr.mobilevr_profile = p.join("|"); } else if (change > 0) { p[0] = Number(p[0]) + 1.0; webvr.mobilevr_profile = p.join("|"); } if (change != 0) ctrl_preset.updateControl(); return Number(p[0]).toFixed(0); });
-			vrsetup_dlg_addspace(dlg, 8);
-			vrsetup_dlg_addline(dlg, 'Inter-Lens-Distance (mm):', 'font-size:16px;');
-			ctrl_ild = vrsetup_dlg_addctrl(dlg, 0.25, function(change){ var p = webvr.mobilevr_profile.split("|"); if (change < 0) { p[1] = Number(p[1]) - 1.0; webvr.mobilevr_profile = p.join("|"); } else if (change > 0) { p[1] = Number(p[1]) + 1.0; webvr.mobilevr_profile = p.join("|"); } if (change != 0) ctrl_preset.updateControl(); return Number(p[1]).toFixed(0); });
-			vrsetup_dlg_addspace(dlg, 8);
-			vrsetup_dlg_addline(dlg, 'Screen-to-Lens-Distance (mm):', 'font-size:16px;');
-			ctrl_stl = vrsetup_dlg_addctrl(dlg, 0.25, function(change){ var p = webvr.mobilevr_profile.split("|"); if (change < 0) { p[2] = Number(p[2]) - 1.0; webvr.mobilevr_profile = p.join("|"); } else if (change > 0) { p[2] = Number(p[2]) + 1.0; webvr.mobilevr_profile = p.join("|"); } if (change != 0) ctrl_preset.updateControl(); return Number(p[2]).toFixed(0); });
-			vrsetup_dlg_addspace(dlg, 8);
-			if (!webvr.isfake)
-			{
-				vrsetup_dlg_addline(dlg, 'Tray-to-Lens-Center-Distance: (mm):', 'font-size:16px;');
-				ctrl_ttl = vrsetup_dlg_addctrl(dlg, 0.25, function(change){ var p = webvr.mobilevr_profile.split("|"); if (change < 0) { p[3] = Number(p[3]) - 1.0; webvr.mobilevr_profile = p.join("|"); } else if (change > 0) { p[3] = Number(p[3]) + 1.0; webvr.mobilevr_profile = p.join("|"); } if (change != 0) ctrl_preset.updateControl(); return Number(p[3]).toFixed(0); });
-				vrsetup_dlg_addspace(dlg, 8);
-			}
-			vrsetup_dlg_addline(dlg, 'Lens-Distortion Coefficients:', 'font-size:16px;');
-			ctrl_k1 = vrsetup_dlg_addctrl(dlg, 0.1, function(change){ var p = webvr.mobilevr_profile.split("|"); if (change < 0) { p[4] = Number(p[4]) - 0.01; webvr.mobilevr_profile = p.join("|"); } else if (change > 0) { p[4] = Number(p[4]) + 0.01; webvr.mobilevr_profile = p.join("|"); } if (change != 0) ctrl_preset.updateControl(); return Number(p[4]).toFixed(3); });
-			ctrl_k2 = vrsetup_dlg_addctrl(dlg, 0.1, function(change){ var p = webvr.mobilevr_profile.split("|"); if (change < 0) { p[5] = Number(p[5]) - 0.01; webvr.mobilevr_profile = p.join("|"); } else if (change > 0) { p[5] = Number(p[5]) + 0.01; webvr.mobilevr_profile = p.join("|"); } if (change != 0) ctrl_preset.updateControl(); return Number(p[5]).toFixed(3); });
-			vrsetup_dlg_addspace(dlg);
-			vrsetup_dlg_addline(dlg, 'Oversampling:', 'font-size:16px;');
-			ctrl_os = vrsetup_dlg_addctrl(dlg, 0.25, function(change){ var p = webvr.oversampling; if (change < 0) { p = Math.max(0.2, Number(p) - 0.1); webvr.oversampling = p;  } else if (change > 0) { p = Math.min(4.0, Number(p) + 0.1); webvr.oversampling = p;  } return p.toFixed(1); });
-			vrsetup_dlg_addspace(dlg);
-			vrsetup_dlg_addline(dlg, 'CLOSE', '', vrsetup_close);
-			vrsetup_dlg_finish(dlg);
-			
-			return dlg;
-		}
-		
-		var vrsetup_dialog = null;
-		var vrsetup_events = null;
-		
-		function vrsetup_close()
-		{
-			if (vrsetup_dialog)
-			{
-				webvr.savesettings();
-			
-				vrsetup_dlg_remove(vrsetup_dialog); 
-				vrsetup_dialog = null;
-			}
-		
-			if (vrsetup_events)
-			{
-				krpano.events.removeItem(vrsetup_events.name);
-				vrsetup_events = null;
-			}
-		}
-		
-		krpano.vrsetup_close = function()
-		{
-			vrsetup_close();
-		}
-		
-		krpano.vrsetup_open_js = function()
-		{
-			if (vrsetup_dialog != null)
-			{
-				// already open...
-				return;
-			}
-				
-			if (webvr.iswebvr)
-			{
-				vrsetup_dialog = vrsetup_webvr_dialog();
-			}
-			else
-			{
-				vrsetup_dialog = vrsetup_mobilevr_dialog();
-			}
-			
-			vrsetup_events = krpano.events.createItem("auto");
-			vrsetup_events.keep = true;
-			
-			vrsetup_events.webvr_onexitvr = function()
-			{
-				vrsetup_close();
-			}
-		}
-		
-	]]></action>
-	
-
-	<!-- A list of devices and their screensize -->
-	<mobilevr_device_database>
-		<device name="iPhone 5/5S/SE" screen="320x568x2" size="4.0" bevel="3" />
-		<device name="iPhone 6/6S/7/8" screen="375x667x2" size="4.7" />
-		<device name="iPhone 6/6S/7/8 Plus" screen="414x736" size="5.5" />
-		<device name="iPhone 6/6S/7/8 Plus (zoomed)" screen="375x667x3" size="5.5" />
-		<device name="iPhone X/XS/11Pro" screen="375x812x3" size="5.85|5.33" />
-		<device name="iPhone XS/11Pro Max" screen="414x896x3" size="6.46|5.95" />
-		<device name="iPhone XR/11" screen="414x896x2" size="6.06|5.58" />
-		<device name="iPhone 12/12Pro" screen="390x844" size="6.1" />
-		<device name="iPhone 12Pro Max" screen="428x926" size="6.7" />
-		<device name="Samsung S6" ua="sm-g930" size="5.1" />
-		<device name="Samsung S6 Edge" ua="sm-g925" size="5.1" />
-		<device name="Samsung S6 Edge Plus" ua="sm-g928" size="5.7" />
-		<device name="Samsung S7" ua="sm-g930" size="5.1" />
-		<device name="Samsung S7 Edge" ua="sm-g935" size="5.5" />
-		<device name="Samsung S8" ua="sm-g950" size="5.8" />
-		<device name="Samsung S8+" ua="sm-g955" size="6.2" />
-		<device name="Samsung S9" ua="sm-g960" size="5.8" />
-		<device name="Samsung S9+" ua="sm-g965" size="6.2" />
-		<device name="Samsung S10e" ua="sm-g970" size="5.8" />
-		<device name="Samsung S10" ua="sm-g973" size="6.1" />
-		<device name="Samsung S10+" ua="sm-g975" size="6.4" />
-		<device name="Samsung S10 5G" ua="sm-g977" size="6.7" />
-		<device name="Samsung Note 7" ua="sm-n930" size="5.7" />
-		<device name="Samsung Note 8" ua="sm-n950" size="6.3" />
-		<device name="Samsung Note 9" ua="sm-n960" size="6.4" />
-		<device name="Samsung Note 10" ua="sm-n970" size="6.3" />
-		<device name="Samsung Note 10 5G" ua="sm-n971" size="6.3" />
-		<device name="Samsung Note 10+" ua="sm-n975" size="6.8" />
-		<device name="Samsung Note 10+ 5G" ua="sm-n976" size="6.8" />
-		<device name="Huawei P10 Lite" ua="HUAWEIWAS-TL10" size="5.2" />
-		<device name="Huawei P20 Lite" ua="HUAWEIANE-LX1" size="5.84" />
-	</mobilevr_device_database>
-
-</krpano>

BIN
public/plugins/webvr_handcursor.png


BIN
public/plugins/webvr_laser.png


BIN
public/plugins/webvr_light.png


BIN
public/plugins/webvr_vrcursor.png


BIN
public/skin/rotate_device.png


+ 0 - 33
public/skin/videointerface.xml

@@ -1,33 +0,0 @@
-<krpano>
-	<action name="skin_video_setup">
-		if(skin_video_setup_done !== true,
-			set(skin_video_setup_done, true);
-
-			<!-- use the video events for getting state updates -->
-			set(plugin[video].onvideoready, jscall(window.onVideoSceneReady()););
-			set(plugin[video].onvideoplay, jscall(window.onVideoScenePlay()););
-			set(plugin[video].onvideopaused, jscall(window.onVideoScenePaused()););
-			set(plugin[video].onvideocomplete, jscall(window.onVideoSceneComplete()););
-			set(plugin[video].onerror, jscall(calc('window.onVideoSceneError("' + videoerror + '")')));
-		  );
-	</action>
-
-	<!-- videointerface_addsource (name, videourl, posterurl)
-		%1 - name
-		%2 - videourl
-		%3 - posterurl
-	-->
-	<action name="videointerface_addsource">
-		<!-- init/setup the video interface skin -->
-		skin_video_setup();
-
-		set(videosources['v%1'].sourcename, '%1');
-		set(videosources['v%1'].videourl, '%2');
-		set(videosources['v%1'].posterurl, '%3');
-	</action>
-
-	<action name="videointerface_play">
-		copy(vs, videosources['v%1']);
-		plugin[video].playvideo(get(vs.videourl), get(vs.posterurl), get(plugin[video].pausedonstart), get(plugin[video].time));
-	</action>
-</krpano>

BIN
public/skin/vtourskin.png


BIN
public/skin/vtourskin_light.png


+ 50 - 22
src/App.tsx

@@ -2,15 +2,13 @@ import '@/assets/styles/base.css'
 // 关于路由
 import React, { useCallback, useEffect, useRef } from 'react'
 import { Router, Route, Switch } from 'react-router-dom'
-import history from './utils/history'
+import history, { callIframeFu } from './utils/history'
 import SpinLoding from './components/SpinLoding'
 
 import NotFound from '@/components/NotFound'
-import store, { RootState } from './store'
+import store from './store'
 import { baseURL, isLoc, myData } from './utils/http'
 import AsyncSpinLoding from './components/AsyncSpinLoding'
-import { useSelector } from 'react-redux'
-import Zguide from './components/Zguide'
 
 // import Vconsole from 'vconsole'
 // new Vconsole()
@@ -22,6 +20,10 @@ const A2yblm = React.lazy(() => import('./pages/A2yblm'))
 const A3beie = React.lazy(() => import('./pages/A3beie'))
 const A4quanwen = React.lazy(() => import('./pages/A4quanwen'))
 const A5wenwu = React.lazy(() => import('./pages/A5wenwu'))
+const A6ybwx = React.lazy(() => import('./pages/A6ybwx'))
+const A7Wjwj = React.lazy(() => import('./pages/A7wjwj'))
+
+
 
 declare global {
   //设置全局属性
@@ -50,11 +52,11 @@ const planSize = {
 export default function App() {
   useEffect(() => {
     // 打包环境 刷新页面从 首页 开始
-    // if (!isLoc && myData.isLdong) {
-    //   if (window.location.hash !== '#/') {
-    //     window.location.href = window.location.origin
-    //   }
-    // }
+    if (!isLoc && myData.isLdong) {
+      if (window.location.hash !== '#/') {
+        window.location.href = window.location.href.split('#')[0] + '#/'
+      }
+    }
   }, [])
 
   // 根元素
@@ -122,10 +124,10 @@ export default function App() {
   const audioPlayFu = useCallback(() => {
     // 播放背景音乐
     const audioDom: HTMLAudioElement = document.querySelector('#bgMp3')!
-    if (audioDom) {
-      if (audioDom.paused) audioDom.play()
-      else rootRef.current.removeEventListener('click', audioPlayFu)
-    }
+    // if (audioDom) {
+    //   if (audioDom.paused) audioDom.play()
+    //   else rootRef.current.removeEventListener('click', audioPlayFu)
+    // }
   }, [])
 
   useEffect(() => {
@@ -140,8 +142,36 @@ export default function App() {
     if (myData.isLdong && !isLoc) rootRef.current.addEventListener('click', audioPlayFu)
   }, [audioPlayFu, pageFullChangeFu])
 
-  // 分享和点赞
-  const { guideVideo } = useSelector((state: RootState) => state.A0Layout)
+  // 动态根据路由更改背景图
+  const handleHashChange = () => {
+
+    if (window.location.hash === '#/base') {
+      callIframeFu('changePanel', 0)
+      callIframeFu('showInscription', -1)
+      callIframeFu('showHotspot', -1)
+    };
+    if (window.location.hash === '#/yblm') {
+      callIframeFu('changePanel', 1)
+      callIframeFu('showInscription', -1)
+      callIframeFu('showHotspot', -1)
+    };
+    if (window.location.hash === '#/beie') { callIframeFu('changePanel', 3); callIframeFu('showInscription', 0) }
+    if (window.location.hash === '#/quanwen') {
+      callIframeFu('changePanel', 3);
+      callIframeFu('showInscription', -1)
+    }
+    if (window.location.hash === '#/wenwu') {
+      callIframeFu('changePanel', 4)
+      callIframeFu('showInscription', -1)
+      callIframeFu('showHotspot', -1)
+    };
+  };
+  useEffect(() => {
+    window.addEventListener('hashchange', handleHashChange);
+    return () => {
+      window.removeEventListener('hashchange', handleHashChange);
+    };
+  }, []);
 
   return (
     <>
@@ -155,23 +185,21 @@ export default function App() {
             <Route path='/beie' component={A3beie} exact />
             <Route path='/quanwen' component={A4quanwen} exact />
             <Route path='/wenwu' component={A5wenwu} exact />
+            <Route path='/ybwx' component={A6ybwx} exact />
+            <Route path='/wjwj' component={A7Wjwj} exact />
             <Route path='*' component={NotFound} />
           </Switch>
         </React.Suspense>
       </Router>
 
+      <iframe id='modalIframe' title='modal' src='Chenzhebei-ShanxiMuseum/index.html'></iframe>
+
       {/* 背景音乐 */}
       <audio id='bgMp3' loop style={{ display: 'none' }} src={baseURL + 'home/bg.mp3'}></audio>
 
       {/* 发送请求的加载组件 */}
       <AsyncSpinLoding />
-      {/* 操作指引视频 */}
-      {guideVideo ? (
-        <Zguide
-          src={guideVideo}
-          closeFu={() => store.dispatch({ type: 'layout/guideVideo', payload: '' })}
-        />
-      ) : null}
+
     </>
   )
 }

BIN
src/assets/img/bg_home.png


BIN
src/assets/img/home_loading.png


BIN
src/assets/img/hotSelected_bg.png


BIN
src/assets/img/icon_dot2.png


BIN
src/assets/img/intro_bg.png


BIN
src/assets/img/menu_item.png


BIN
src/assets/img/menu_item_ac.png


+ 118 - 60
src/assets/styles/base.css

@@ -4,7 +4,7 @@
   box-sizing: border-box;
   word-wrap: break-word;
   -webkit-tap-highlight-color: transparent;
-  /* font-family: qfk; */
+  font-family: qfk;
 }
 /* 全局css变量 */
 :root {
@@ -23,6 +23,29 @@ body {
   height: 100%;
   color: black;
   overflow: auto;
+  background-color: #cbc5b7;
+}
+body #wjwjScene {
+  width: 100%;
+  height: 100%;
+  border: none;
+  position: fixed;
+  top: 0;
+  left: 0;
+}
+body #A7Back {
+  display: none;
+  width: 136px;
+  height: 67px;
+  position: absolute;
+  z-index: 3;
+  top: 3%;
+  left: 4%;
+  cursor: pointer;
+}
+body #A7Back > img {
+  height: 100%;
+  object-fit: contain;
 }
 #root {
   overflow: hidden;
@@ -185,10 +208,23 @@ textarea {
   .adm-toast-wrap {
     transform: rotate(90deg) !important;
   }
-  .ant-tooltip {
-    /* transform: rotate(90deg) scale(0.7) !important;
-    transform-origin: center center !important; */
-
+  #root .ant-tooltip {
+    transform: rotate(0) !important;
+    inset: 120px auto auto 450px !important;
+  }
+  body #A7Back {
+    display: none;
+    width: 60px;
+    height: 30px;
+    position: absolute;
+    z-index: 3;
+    top: 3%;
+    left: 4%;
+    cursor: pointer;
+  }
+  body #A7Back > img {
+    height: 100%;
+    object-fit: contain;
   }
 }
 #myIframe {
@@ -208,12 +244,25 @@ textarea {
     opacity: 1;
   }
   50% {
+    scale: 0.9;
     opacity: 0.2;
   }
   100% {
     opacity: 1;
   }
 }
+@keyframes zhiti {
+  0% {
+    opacity: 1;
+  }
+  50% {
+    scale: 0.98;
+    opacity: 0.7;
+  }
+  100% {
+    opacity: 1;
+  }
+}
 .likeImg2 {
   animation: likeImg2 1.5s linear forwards;
 }
@@ -226,21 +275,22 @@ textarea {
   }
 }
 /* 隐藏静音按钮 */
-
 #root .ant-tooltip {
-  width: 100px !important;
-  height: 100px !important;
-  max-width: 100px !important;
-  .ant-tooltip-content {
-    width: 100px !important;
-    height: 100px !important;
-    .ant-tooltip-content-inner {
-      width: 100px !important;
-      height: 100px !important;
-    }
-  }
+  width: 190px !important;
+  height: 92px !important;
+  max-width: 200px !important;
+}
+#root .ant-tooltip .ant-tooltip-content {
+  width: 100% !important;
+  height: 100% !important;
+}
+#root .ant-tooltip .ant-tooltip-inner {
+  background: url(../img/tooltipBg.png) no-repeat;
+  background-size: 100% 100%;
+  box-shadow: none !important;
+  width: 100% !important;
+  height: 100% !important;
 }
-
 #root .ant-tooltip .tooltip_MT {
   height: 100%;
   font-size: 16px;
@@ -250,45 +300,53 @@ textarea {
   flex-direction: column;
   padding-bottom: 8px;
   gap: 4px;
-  .top {
-    width: 100%;
-    height: 15px;
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    .title {
-      width: 30px;
-      height: 100%;
-      font-size: 10px;
-      line-height: 15px;
-      color: rgba(255, 233, 182, 1);
-    }
-    .close {
-      width: 40px;
-      height: 100%;
-      cursor: pointer;
-      display: flex;
-      justify-content: end;
-      align-items: center;
-      & > img {
-        height: 90%;
-        object-fit: contain;
-      }
-    }
-  }
-  .content {
-    width: 100%;
-    height: calc(100% - 16px);
-    font-size: 7px;
-    line-height: 10px;
-    color: #fff;
-    font-weight: lighter;
-    overflow: auto;
-    &::-webkit-scrollbar {
-      width: 1px;
-    }
-    &::-webkit-scrollbar-thumb {
-      background: rgba(255, 233, 182, 1);
-    }
-  }
-}
+}
+#root .ant-tooltip .tooltip_MT .top {
+  width: 100%;
+  height: 15px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+#root .ant-tooltip .tooltip_MT .top .title {
+  width: 30px;
+  height: 100%;
+  font-size: 10px;
+  line-height: 15px;
+  color: #ffe9b6;
+}
+#root .ant-tooltip .tooltip_MT .top .close {
+  width: 40px;
+  height: 100%;
+  cursor: pointer;
+  display: flex;
+  justify-content: end;
+  align-items: center;
+}
+#root .ant-tooltip .tooltip_MT .top .close > img {
+  height: 90%;
+  object-fit: contain;
+}
+#root .ant-tooltip .tooltip_MT .content {
+  width: 100%;
+  height: calc(100% - 16px);
+  font-size: 7px;
+  line-height: 10px;
+  color: #fff;
+  font-weight: lighter;
+  overflow: auto;
+}
+#root .ant-tooltip .tooltip_MT .content::-webkit-scrollbar {
+  width: 1px;
+}
+#root .ant-tooltip .tooltip_MT .content::-webkit-scrollbar-thumb {
+  background: #ffe9b6;
+}
+#root #modalIframe {
+  width: 100%;
+  height: 100%;
+  border: none;
+  position: fixed;
+  top: 0;
+  left: 0;
+}

+ 143 - 3
src/assets/styles/base.less

@@ -31,6 +31,35 @@ body {
   // background-color: rgba(0, 0, 0, 0.8);
 }
 
+body #wjwjScene {
+  width: 100%;
+  height: 100%;
+  position: fixed;
+  border: none;
+  position: fixed;
+  top: 0;
+  left: 0;
+
+
+}
+
+
+
+body #A7Back {
+  display: none;
+  width: 136px;
+  height: 67px;
+  position: absolute;
+  z-index: 3;
+  top: 3%;
+  left: 4%;
+  cursor: pointer;
+  & > img {
+    height: 100%;
+    object-fit: contain;
+  }
+}
+
 #root {
   overflow: hidden;
   margin: auto;
@@ -226,8 +255,23 @@ textarea {
   .adm-toast-wrap {
     transform: rotate(90deg) !important;
   }
-  .ant-tooltip {
-    transform: rotate(90deg) !important;
+  #root .ant-tooltip {
+    transform: rotate(0) !important;
+    inset: 120px auto auto 450px !important;
+  }
+  body #A7Back {
+    display: none;
+    width: 60px;
+    height: 30px;
+    position: absolute;
+    z-index: 3;
+    top: 3%;
+    left: 4%;
+    cursor: pointer;
+    & > img {
+      height: 100%;
+      object-fit: contain;
+    }
   }
 }
 
@@ -252,6 +296,7 @@ textarea {
   }
 
   50% {
+    scale: 0.9;
     opacity: 0.2;
   }
 
@@ -260,6 +305,21 @@ textarea {
   }
 }
 
+@keyframes zhiti {
+  0% {
+    opacity: 1;
+  }
+
+  50% {
+    scale: 0.98;
+    opacity: 0.7;
+  }
+
+  100% {
+    opacity: 1;
+  }
+}
+
 // 点赞的+1
 .likeImg2 {
   animation: likeImg2 1.5s linear forwards;
@@ -287,4 +347,84 @@ textarea {
 // /* 隐藏音量调节滑块 */
 // video::-webkit-media-controls-volume-slider {
 //   display: none !important;
-// }
+// }
+
+#root .ant-tooltip {
+  width: 190px !important;
+  height: 92px !important;
+  max-width: 200px !important;
+
+  .ant-tooltip-content {
+    width: 100% !important;
+    height: 100% !important;
+  }
+  .ant-tooltip-inner {
+    background: url(../img/tooltipBg.png) no-repeat;
+    background-size: 100% 100%;
+    box-shadow: none !important;
+    width: 100% !important;
+    height: 100% !important;
+  }
+}
+
+#root .ant-tooltip .tooltip_MT {
+  height: 100%;
+  font-size: 16px;
+  line-height: 24px;
+  color: #000;
+  display: flex;
+  flex-direction: column;
+  padding-bottom: 8px;
+  gap: 4px;
+  .top {
+    width: 100%;
+    height: 15px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    .title {
+      width: 30px;
+      height: 100%;
+      font-size: 10px;
+      line-height: 15px;
+      color: rgba(255, 233, 182, 1);
+    }
+    .close {
+      width: 40px;
+      height: 100%;
+      cursor: pointer;
+      display: flex;
+      justify-content: end;
+      align-items: center;
+      & > img {
+        height: 90%;
+        object-fit: contain;
+      }
+    }
+  }
+  .content {
+    width: 100%;
+    height: calc(100% - 16px);
+    font-size: 7px;
+    line-height: 10px;
+    color: #fff;
+    font-weight: lighter;
+    overflow: auto;
+    &::-webkit-scrollbar {
+      width: 1px;
+    }
+    &::-webkit-scrollbar-thumb {
+      background: rgba(255, 233, 182, 1);
+    }
+  }
+}
+
+#root #modalIframe {
+  width: 100%;
+  height: 100%;
+  position: fixed;
+  border: none;
+  position: fixed;
+  top: 0;
+  left: 0;
+}

+ 0 - 214
src/components/BaseImg/index.module.scss

@@ -1,214 +0,0 @@
-.BaseImg {
-  width: 100%;
-  height: 100%;
-  position: absolute;
-  top: 0;
-  left: 0;
-  z-index: 11;
-  opacity: 1;
-  transition: opacity 1s;
-  &::after {
-    content: '';
-    position: absolute;
-    pointer-events: none;
-    width: 100%;
-    height: 100%;
-    background-color: rgba(0, 0, 0, 0.4);
-  }
-
-  :global {
-    .BIcon {
-      position: absolute;
-      top: -60px;
-      left: 50%;
-      transform: translateX(-50%);
-      width: 30px;
-      z-index: 10;
-      cursor: pointer;
-      display: none;
-    }
-
-    .BIlogo {
-      z-index: 5;
-      position: absolute;
-      top: -60px;
-      width: 650px;
-      max-width: 90%;
-      left: 50%;
-      transform: translateX(-50%);
-    }
-
-    .BItxt {
-      text-indent: 2em;
-      position: absolute;
-      top: 35%;
-      left: 50%;
-      transform: translateX(-50%);
-      z-index: 10;
-      width: 60%;
-      height: 160px;
-      background-size: 100% 100%;
-      padding: 26px;
-      background-color: rgba(242, 242, 215, 0.3);
-      backdrop-filter: blur(4px);
-      display: flex;
-      align-items: center;
-      & > img {
-        position: absolute;
-        top: 0;
-        left: 0;
-        width: 100%;
-        object-fit: fill !important;
-        pointer-events: none;
-      }
-      .BItxtImg {
-        top: auto;
-        bottom: 0;
-      }
-      & > div {
-        text-align: justify;
-        width: 100%;
-        max-height: 100%;
-        color: #fffddc;
-        font-size: 11px;
-        letter-spacing: 3px;
-        line-height: 22px;
-        overflow-y: auto;
-
-        &::-webkit-scrollbar {
-          display: none;
-        }
-      }
-    }
-
-    .BIbaseBtn {
-      position: absolute;
-      bottom: 40px;
-      left: 50%;
-      transform: translateX(-50%);
-      cursor: pointer;
-      width: 120px;
-      height: 36px;
-      z-index: 10;
-      background-size: 100% 100%;
-      background-image: url('../../assets/img/btn.png');
-      color: #fffddc;
-      transition: all 0.3s;
-
-      .BIBtxt {
-        font-size: 18px;
-        position: absolute;
-        top: 0;
-        left: 0;
-        width: 100%;
-        height: 100%;
-        display: flex;
-        justify-content: center;
-        align-items: center;
-        font-family: 'Microsoft Yahei', 'PingFang SC', 'Avenir', 'Segoe UI', 'Hiragino Sans GB',
-          'STHeiti', 'Microsoft Sans Serif', 'WenQuanYi Micro Hei', sans-serif !important;
-      }
-      .BIBtxtFont {
-        font-family: 'qfk' !important;
-      }
-
-      &:hover {
-        background-image: url('../../assets/img/btnAc.png');
-        color: #b67150;
-      }
-    }
-
-    // 进度条
-    .BIBxian {
-      position: absolute;
-      bottom: 7%;
-      left: 50%;
-      transform: translateX(-50%);
-      width: 120px;
-      padding: 0 10px;
-      height: 2px;
-      z-index: 10;
-      & > div {
-        width: 100%;
-        height: 100%;
-        background-color: rgba(231, 214, 142, 0.6);
-        & > div {
-          width: 0%;
-          height: 100%;
-
-          background-color: #fffddc;
-        }
-      }
-    }
-    .birdBox {
-      position: absolute;
-      bottom: -122px;
-      left: 70%;
-      transform: translateX(-50%);
-      z-index: 100;
-      width: 250px;
-      height: 260px;
-      transition: all 0.5s;
-      .bird1 {
-        position: absolute;
-        top: 0;
-        left: 0;
-        pointer-events: none;
-        width: 250px;
-        height: 260px;
-        object-fit: fill !important;
-      }
-      .bird2 {
-        position: absolute;
-        bottom: 80px;
-        left: 50%;
-        transform: translateX(-50%);
-        background-image: url('../../assets/img/bird/quan.png');
-        background-size: 100% 100%;
-        z-index: 2;
-        cursor: pointer;
-        width: 90px;
-        height: 90px;
-        color: #fffddc;
-        text-align: center;
-        font-size: 16px;
-        padding-top: 18px;
-        transition: all 0.3s;
-        &:hover {
-          color: #a55b41;
-          background-image: url('../../assets/img/bird/quanAc.png');
-        }
-      }
-      .bird3 {
-        cursor: pointer;
-        position: absolute;
-        left: 50%;
-        transform: translateX(-50%);
-        top: -55px;
-        width: 33px;
-        height: 55px;
-        background-image: url('../../assets/img/bird/ji.png');
-        background-size: 100% 100%;
-        transition: all 0.3s;
-        &:hover {
-          background-image: url('../../assets/img/bird/jiAc.png');
-        }
-      }
-    }
-    #HotOpCss {
-      z-index: 1000;
-    }
-
-    // 屏幕>=1200
-    // @media screen and (min-width: 1200px) {
-    //   .BItxt > div {
-    //     font-size: 11px !important;
-    //   }
-    // }
-  }
-}
-
-.BaseImgHide {
-  opacity: 0;
-  pointer-events: none;
-}

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 168
src/components/BaseImg/index.tsx


+ 2 - 2
src/components/EndVideo/index.tsx

@@ -43,14 +43,14 @@ function EndVideo({ lastVideo, delDom, src, path, noBtn }: Props) {
         muted
         webkit-playsinline='true'
         x5-video-player-type='h5'
-        onEnded={() => history.push(path)}
+        onEnded={() => window.location.replace(path)}
       >
         <source type='video/mp4' src={src} />
         Your browser does not support the video tag.
       </video>
 
       {/* 右下角的跳过按钮 */}
-      <BtnRight imgName='skip' clickSon={() => history.push(path)} title='跳过' />
+      <BtnRight imgName='skip' clickSon={() => window.location.replace(path)} title='跳过' />
       {/* {noBtn && myData.isLdong ? null : (
       )} */}
     </div>

+ 0 - 134
src/components/FloorBtn/index.module.scss

@@ -1,134 +0,0 @@
-.FloorBtn {
-  position: absolute;
-  right: 25px;
-  bottom: 25px;
-  z-index: 10;
-  display: flex;
-  :global {
-    div {
-      background-size: 100% 100%;
-      transition: all 0.3s;
-      width: 50px;
-      height: 50px;
-      cursor: pointer;
-    }
-
-    .FloorBtn0 {
-      // margin-right: 5px;
-      background-image: url('../../assets/img/icon-game.png');
-      &:hover {
-        background-image: url('../../assets/img/icon-game1.png');
-      }
-    }
-
-    .FloorBtn1 {
-      // margin-right: 5px;
-      background-image: url('../../assets/img/icon-walk.png');
-      &:hover {
-        background-image: url('../../assets/img/icon-walk1.png');
-      }
-    }
-    .FloorBtn2 {
-      background-image: url('../../assets/img/icon-more.png');
-      &:hover {
-        background-image: url('../../assets/img/icon-more1.png');
-      }
-    }
-
-    .FloorBtn3 {
-      background-image: url('../../assets/img/icon-nonggen.png');
-      &:hover {
-        background-image: url('../../assets/img/icon-nonggen1.png');
-      }
-    }
-
-    .FloorBtn4 {
-      background-image: url('../../assets/img/icon-mol.png');
-      &:hover {
-        background-image: url('../../assets/img/icon-mol1.png');
-      }
-    }
-    .FloorBtn5 {
-      background-image: url('../../assets/img/Zguide/icon-caozuo.png');
-      &:hover {
-        background-image: url('../../assets/img/Zguide/icon-caozuo1.png');
-      }
-    }
-
-    // 新加的3个按钮
-    .leftBtn {
-      width: auto;
-      height: auto;
-      position: fixed;
-      top: 15px;
-      left: 15px;
-      cursor: default;
-      & > div {
-        width: 40px;
-        height: 40px;
-        background-size: 100% 100%;
-        transition: all 0.3s;
-        margin-bottom: 10px;
-      }
-      .shareImg {
-        background-image: url('../../assets/img/leftBtn/share.png');
-        &:hover {
-          background-image: url('../../assets/img/leftBtn/shareAc.png');
-        }
-      }
-      .msgImg {
-        background-image: url('../../assets/img/leftBtn/msg.png');
-        &:hover {
-          background-image: url('../../assets/img/leftBtn/msgAc.png');
-        }
-      }
-      .likeImg {
-        background-image: url('../../assets/img/leftBtn/like.png');
-        position: relative;
-        &:hover {
-          background-image: url('../../assets/img/leftBtn/likeAc.png');
-        }
-        .likeImg1 {
-          position: absolute;
-          bottom: -18px;
-          left: 50%;
-          transform: translateX(-50%);
-          color: #83605a;
-          text-shadow: #eed879 0.5px 0.5px;
-          font-size: 14px;
-          pointer-events: none;
-        }
-        .likeImg2 {
-          position: absolute;
-          right: -10px;
-          top: -6px;
-          font-size: 10px;
-          color: #eed879;
-          text-shadow: #83605a 0.5px 0.5px;
-        }
-      }
-      .likeImgAc {
-        background-image: url('../../assets/img/leftBtn/likeAc.png');
-      }
-    }
-
-    @media screen and (min-width: 1200px) {
-      div {
-        width: 35px;
-        height: 35px;
-      }
-      .leftBtn {
-        & > div {
-          width: 25px;
-          height: 25px;
-        }
-        .likeImg {
-          .likeImg1 {
-            font-size: 12px;
-            bottom: -15px;
-          }
-        }
-      }
-    }
-  }
-}

+ 0 - 135
src/components/FloorBtn/index.tsx

@@ -1,135 +0,0 @@
-import React, { useCallback, useEffect, useState } from 'react'
-import styles from './index.module.scss'
-import history from '@/utils/history'
-import { renClickPageFu } from '@/pages/B1more/data'
-import { locSetTimeFu, locTimeFlagFu } from '@/utils/storage'
-import { useSelector } from 'react-redux'
-import store, { RootState } from '@/store'
-import classNames from 'classnames'
-import { API_setLike } from '@/store/action/all'
-import { Toast } from 'antd-mobile'
-
-type Props = {
-  unityId?: '1' | '2'
-  gameFu?: () => void
-  plowFu?: () => void
-  unityEnd?: () => void
-  // 左上角的3个按钮是否显示,为true表示显示,默认为true
-  leftBtnShow?: boolean
-  isGuide?: string //操作指引
-}
-
-function FloorBtn({ unityId, gameFu, plowFu, unityEnd, isGuide, leftBtnShow = true }: Props) {
-  // 获取点赞数量
-  const { likeNum } = useSelector((state: RootState) => state.A0Layout)
-
-  // 进页面看下是否已经点赞过了
-  const [likeSta, setLikeSta] = useState(false)
-  useEffect(() => {
-    const likeFlag = locTimeFlagFu()
-    if (likeFlag) setLikeSta(true)
-  }, [])
-
-  // 点赞的+1动画
-  const [likeMove, setLikeMove] = useState(false)
-
-  // 点击点赞
-  const likeFu = useCallback(async () => {
-    if (!likeSta) {
-      // 今天已经赞过了
-      Toast.show({
-        content: '您今天已经赞过了!'
-      })
-      return
-    }
-
-    // 发送请求
-    const res = await API_setLike('star')
-    if (res.code === 0) {
-      // 存当天0点时间戳
-      locSetTimeFu()
-
-      // +1动画显示
-      setLikeMove(true)
-      if (likeMove) return
-
-      // 点赞图标变高亮
-      setLikeSta(false)
-      setTimeout(() => {
-        // +1动画隐藏
-        setLikeMove(false)
-        // num++
-        store.dispatch({ type: 'layout/likeNum', payload: res.data.pcsStar })
-      }, 1400)
-    }
-  }, [likeMove, likeSta])
-
-  // 点击留言板/分享
-  const openAPPpageComFu = useCallback((val: 'layout/shareShow' | 'layout/msgShow') => {
-    store.dispatch({ type: val, payload: true })
-  }, [])
-
-  return (
-    <div className={styles.FloorBtn} id='FloorBtn'>
-      {/* 操作指引 */}
-      {isGuide ? (
-        <div
-          title='操作指引'
-          className='FloorBtn5'
-          onClick={() => store.dispatch({ type: 'layout/guideVideo', payload: isGuide })}
-        ></div>
-      ) : null}
-
-      {gameFu ? <div title='游戏' className='FloorBtn0' onClick={gameFu}></div> : null}
-      {plowFu ? <div title='汉代庄园田耕记' className='FloorBtn3' onClick={plowFu}></div> : null}
-
-      <div
-        className='FloorBtn1'
-        hidden={!unityId}
-        title='漫游模式'
-        onClick={() => history.push(`/unity/${unityId}`)}
-      ></div>
-
-      {/* 陶庄园 */}
-      {unityEnd ? <div title='陶庄园' className='FloorBtn4' onClick={unityEnd}></div> : null}
-
-      {/* 更多 跳新页面 */}
-      <div
-        title='更多'
-        className='FloorBtn2'
-        onClick={() => {
-          const txt = renClickPageFu()
-          if (txt) {
-            txt === '1' ? history.replace('/more?r=ren1') : history.replace('/more?r=ren0')
-          } else history.push('/more')
-        }}
-      ></div>
-
-      {/* 新加的左上角3个按钮 */}
-      <div className='leftBtn' hidden={!leftBtnShow}>
-        <div
-          title='分享'
-          className='shareImg'
-          onClick={() => openAPPpageComFu('layout/shareShow')}
-        ></div>
-        <div
-          title='留言板'
-          className='msgImg'
-          onClick={() => openAPPpageComFu('layout/msgShow')}
-        ></div>
-        <div
-          onClick={likeFu}
-          title='点赞'
-          className={classNames('likeImg', likeSta ? '' : 'likeImgAc')}
-        >
-          <span className='likeImg1'>{likeNum}</span>
-          {likeMove ? <span className='likeImg2'>+1</span> : null}
-        </div>
-      </div>
-    </div>
-  )
-}
-
-const MemoFloorBtn = React.memo(FloorBtn)
-
-export default MemoFloorBtn

+ 0 - 161
src/components/ZHot0/index.module.scss

@@ -1,161 +0,0 @@
-.ZHot0 {
-  position: absolute;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  z-index: 9990;
-  background-size: 100% 100%;
-  transition: all 0.3s;
-  padding: 6% 12% 4% 12%;
-  background-color: rgba(0, 0, 0, 0.6);
-  :global {
-    .hot1Box {
-      width: 100%;
-      height: 100%;
-      position: relative;
-      // 主体
-      .hot1Main {
-        display: flex;
-        justify-content: space-between;
-        height: calc(100% - 55px);
-        & > div {
-          width: 48%;
-        }
-        .h1Mll {
-          overflow: hidden;
-          border: 1px solid #eacf60;
-          position: relative;
-
-          // 左右箭头
-          .h1MllIcon {
-            width: 20px;
-            position: absolute;
-            z-index: 10;
-            top: 50%;
-            transform: translateY(-50%);
-            cursor: pointer;
-            left: 5%;
-          }
-
-          .h1Mllyou {
-            left: auto;
-            right: 5%;
-          }
-
-          .h1MllCo {
-            height: 100%;
-            display: flex;
-            transition: transform 0.3s;
-          }
-
-          .h1MllRow {
-            height: 100%;
-            display: flex;
-            align-items: center;
-            padding: 10px;
-
-            .adm-image {
-              width: 100%;
-              height: 100%;
-              border: 1px solid #eacf60;
-              img {
-                width: 100%;
-                height: 100%;
-                object-fit: cover !important;
-              }
-            }
-          }
-        }
-        .h1Mrr {
-          height: 96%;
-          overflow-y: auto;
-          position: relative;
-          padding-bottom: 15px;
-          &::-webkit-scrollbar {
-            display: none;
-          }
-
-          .h1MrrTxt {
-            position: absolute;
-            top: 50%;
-            left: 0;
-            width: 100%;
-            transform: translateY(-50%);
-            max-height: 100%;
-
-            & > h1 {
-              color: #eacf60;
-              font-size: 40px;
-              font-weight: 400;
-              margin-bottom: 1%;
-            }
-            & > div {
-              color: #fffddc;
-            }
-            h3 {
-              font-size: 18px;
-              font-weight: 400;
-            }
-            h2 {
-              font-size: 20px;
-              font-weight: 400;
-            }
-            p {
-              font-size: 16px;
-            }
-          }
-        }
-      }
-
-      // 返回按钮
-      #BtnRight {
-        z-index: 10;
-        top: 0;
-        right: -40px;
-        width: 36px;
-        height: 36px;
-      }
-
-      // 底部
-      .h1Floo {
-        position: absolute;
-        bottom: 0;
-        left: 50%;
-        transform: translateX(-50%);
-        width: 80%;
-        height: 34px;
-        background-size: 100% 100%;
-        border-radius: 4px;
-        display: flex;
-        .h1FlooRow {
-          cursor: pointer;
-          flex: 1;
-          font-size: 16px;
-          height: 100%;
-          display: flex;
-          justify-content: center;
-          align-items: center;
-          color: #fffddc;
-          opacity: 0.8;
-        }
-        .h1FlooRowShow {
-          font-weight: 700;
-          opacity: 1;
-          color: #eacf60;
-          position: relative;
-        }
-        .h1FlooRowShowImg {
-          max-width: 1000px;
-          height: 180%;
-          width: auto;
-          position: absolute;
-          left: 46%;
-          top: 54%;
-          transform: translate(-50%, -50%);
-          max-height: 70px;
-        }
-      }
-    }
-  }
-}

+ 0 - 121
src/components/ZHot0/index.tsx

@@ -1,121 +0,0 @@
-import React, { useCallback, useMemo, useState } from 'react'
-import styles from './index.module.scss'
-import classNames from 'classnames'
-import LazyImg from '@/components/LazyImg'
-import { baseURL, hotInfo } from '@/utils/http'
-import BtnRight from '@/components/BtnRight'
-
-type Props = {
-  closeFu: () => void
-}
-
-function ZHot0({ closeFu }: Props) {
-  // 底部选中
-  const [flooInd, setFlooInd] = useState(0)
-
-  // 点击切换底部
-  const flooIndFu = useCallback((ind: number) => {
-    setImgAc(0)
-    const dom = document.querySelector('.h1Mrr')
-    if (dom) dom.scrollTop = 0
-    setFlooInd(ind)
-  }, [])
-
-  // 图片切换
-  const [imgAc, setImgAc] = useState(0)
-
-  const acData = useMemo(() => {
-    return hotInfo['周礼九拜'][0].data[flooInd] || []
-  }, [flooInd])
-
-  return (
-    <div
-      id='HotOpCss'
-      className={styles.ZHot0}
-      style={{
-        backgroundImage: `url(${baseURL}visit/hot1bj.png)`
-      }}
-    >
-      <div className='hot1Box'>
-        {/* 主体 */}
-        <div className='hot1Main'>
-          {/* 左边 */}
-          <div className='h1Mll'>
-            {/* 左右箭头 */}
-            <img
-              onClick={() => setImgAc(imgAc - 1)}
-              hidden={acData.imgArr.length <= 1}
-              style={{
-                opacity: imgAc === 0 ? 0.5 : 1,
-                pointerEvents: imgAc === 0 ? 'none' : 'auto'
-              }}
-              className='h1MllIcon'
-              src={`${baseURL}visit/icon-zuo-red.png`}
-              alt=''
-            />
-            <img
-              onClick={() => setImgAc(imgAc + 1)}
-              hidden={acData.imgArr.length <= 1}
-              style={{
-                opacity: imgAc === acData.imgArr.length - 1 ? 0.5 : 1,
-                pointerEvents: imgAc === acData.imgArr.length - 1 ? 'none' : 'auto'
-              }}
-              className='h1MllIcon h1Mllyou'
-              src={`${baseURL}visit/icon-you-red.png`}
-              alt=''
-            />
-
-            <div
-              className='h1MllCo'
-              style={{
-                transform: `translateX(-${(100 / acData.imgArr.length) * imgAc}%)`,
-                width: `${100 * acData.imgArr.length}%`
-              }}
-            >
-              {acData.imgArr.map((url, index) => (
-                <div
-                  className='h1MllRow'
-                  key={index}
-                  style={{ width: 100 / acData.imgArr.length + '%' }}
-                >
-                  <LazyImg src={baseURL + url} />
-                </div>
-              ))}
-            </div>
-          </div>
-          {/* 右边 */}
-          <div className='h1Mrr'>
-            <div className='h1MrrTxt'>
-              <h1>{acData.name}</h1>
-              <div dangerouslySetInnerHTML={{ __html: acData.txt }}></div>
-            </div>
-          </div>
-
-          {/* 返回按钮 */}
-          <BtnRight imgName='back' clickSon={() => closeFu()} title='返回' />
-        </div>
-
-        {/* 底部 */}
-        <div className='h1Floo' style={{ backgroundImage: `url(${baseURL}visit/h1fllo.png)` }}>
-          {hotInfo['周礼九拜'][0].data.map((item, index) => (
-            <div
-              onClick={() => flooIndFu(index)}
-              className={classNames('h1FlooRow sizeNo', flooInd === index ? 'h1FlooRowShow' : '')}
-              key={index}
-            >
-              {item.name}
-
-              {flooInd === index ? (
-                <img className='h1FlooRowShowImg' src={`${baseURL}visit/bichuyuan.png`} alt='' />
-              ) : null}
-            </div>
-          ))}
-        </div>
-      </div>
-    </div>
-  )
-}
-
-const MemoZHot0 = React.memo(ZHot0)
-
-export default MemoZHot0

+ 0 - 352
src/components/Zhot/index.module.scss

@@ -1,352 +0,0 @@
-.Zhot {
-  position: absolute;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  background-color: rgba(0, 0, 0, 0.4);
-  backdrop-filter: blur(4px);
-
-  z-index: 9990;
-  display: flex;
-  :global {
-    // 所有图片盒子
-    .ZHimgBox {
-      width: 100%;
-      height: auto;
-      // white-space: nowrap;
-      display: inline-block;
-      &::-webkit-scrollbar {
-        display: none;
-      }
-
-      .ZH2img {
-        cursor: pointer;
-        display: inline-block;
-        width: auto;
-        height: 130px;
-        margin-bottom: 10px;
-        margin-right: 10px;
-        object-fit: contain !important;
-      }
-
-      .adm-image {
-        display: inline-block;
-        width: auto;
-        margin-bottom: 10px;
-        margin-right: 10px;
-        height: 130px;
-
-        img {
-          display: inline-block;
-          width: auto;
-          // width: 100%;
-          height: 100%;
-          object-fit: fill !important;
-        }
-      }
-    }
-
-    p {
-      text-align: justify;
-    }
-    .ZHll {
-      width: 60%;
-      height: 100%;
-      padding: 3% 0 3% 4%;
-
-      .ZHLLcen {
-        width: 100%;
-        height: 100%;
-        background-size: 100% 100%;
-        background-color: rgba(242, 242, 215, 0.3);
-        padding: 12px 14px 0px;
-      }
-
-      // 标题
-      .h2Titele {
-        padding: 0 42px;
-        position: relative;
-        display: inline-block;
-        color: #eacf60;
-        font-size: 20px;
-        margin-bottom: 8px;
-        & > img {
-          position: absolute;
-          top: 53%;
-          left: 0;
-          transform: translateY(-50%);
-          width: 34px;
-          height: auto;
-        }
-        .h2TimgR {
-          left: auto;
-          right: 0;
-        }
-      }
-
-      .ZH1main {
-        width: 100%;
-        height: calc(100% - 50px);
-        display: flex;
-        align-items: center;
-        position: relative;
-        padding-bottom: 55px;
-
-        .ZH1main1 {
-          max-height: 100%;
-          overflow-y: auto;
-          &::-webkit-scrollbar {
-            display: none;
-          }
-          // 一级介绍
-          .ZH1txt {
-            font-size: 14px;
-            line-height: 24px;
-            color: #fffddc;
-            p {
-              text-indent: 2em;
-              font-family: 'Microsoft Yahei', 'PingFang SC', 'Avenir', 'Segoe UI',
-                'Hiragino Sans GB', 'STHeiti', 'Microsoft Sans Serif', 'WenQuanYi Micro Hei',
-                sans-serif !important;
-              margin-bottom: 10px;
-            }
-            h3 {
-              color: #eacf60;
-              font-family: 'Microsoft Yahei', 'PingFang SC', 'Avenir', 'Segoe UI',
-                'Hiragino Sans GB', 'STHeiti', 'Microsoft Sans Serif', 'WenQuanYi Micro Hei',
-                sans-serif !important;
-              margin-bottom: 8px;
-            }
-          }
-
-          // 二级
-          .ZH1_2 {
-            margin-top: 10px;
-            display: flex;
-            .ZH1_2ll {
-              padding-top: 5px;
-              width: 100px;
-              margin-right: 10px;
-
-              .ZH1_2llRow {
-                margin-bottom: 20px;
-                cursor: pointer;
-                color: #fffddc;
-                font-size: 14px;
-                position: relative;
-                padding-left: 24px;
-                transition: all 0.3s;
-                & > img {
-                  position: absolute;
-                  top: 0;
-                  left: 0;
-                  height: 20px;
-                  &:nth-of-type(2) {
-                    opacity: 0;
-                  }
-                }
-                // &:hover {
-                //   color: #eacf60;
-                //   & > img {
-                //     opacity: 0;
-                //     &:nth-of-type(2) {
-                //       opacity: 1;
-                //     }
-                //   }
-                // }
-              }
-              .ZH1_2llRowAc {
-                color: #eacf60;
-                & > img {
-                  opacity: 0;
-                  &:nth-of-type(2) {
-                    opacity: 1;
-                  }
-                }
-              }
-            }
-            .ZH1_2rr {
-              width: calc(100% - 110px);
-              font-size: 14px;
-              line-height: 24px;
-              color: #fffddc;
-              p {
-                text-indent: 2em;
-                font-size: 13px;
-                font-family: 'Microsoft Yahei', 'PingFang SC', 'Avenir', 'Segoe UI',
-                  'Hiragino Sans GB', 'STHeiti', 'Microsoft Sans Serif', 'WenQuanYi Micro Hei',
-                  sans-serif !important;
-                margin-bottom: 10px;
-              }
-            }
-          }
-        }
-        .ZH1main2 {
-          position: absolute;
-          bottom: 0px;
-          left: 0;
-          width: 100%;
-          height: 46px;
-          display: flex;
-          align-items: center;
-          .back1 {
-            position: relative;
-            #BtnRight {
-              top: 0;
-              left: 0;
-              bottom: 0;
-              right: 0;
-              position: relative;
-              width: 46px;
-              height: 46px;
-            }
-          }
-          // 相关文物
-          .ZH1main2rr {
-            margin-left: 10px;
-            height: 36px;
-            width: calc(100% - 60px);
-            display: flex;
-            align-items: center;
-            justify-content: space-between;
-            .ZH1main2rr1 {
-              color: #eacf60;
-              font-weight: 700;
-              width: 82px;
-            }
-            .ZH1main2rr2 {
-              width: calc(100% - 82px);
-              height: 100%;
-              overflow: auto;
-              white-space: nowrap;
-              &::-webkit-scrollbar {
-                display: none;
-              }
-              .ZH1main2rr2Row {
-                margin: 0 8px;
-                cursor: pointer;
-                width: auto;
-                height: 36px;
-                line-height: 34px;
-                padding: 0 10px;
-                color: #fffddc;
-                display: inline-block;
-                border: 1px solid #fffddc;
-                border-radius: 20px;
-                transition: all 0.3s;
-                background-color: rgba(0, 0, 0, 0.4);
-                &:nth-of-type(1) {
-                  margin-left: 0;
-                }
-                &:hover {
-                  background-color: #eacf60;
-                  border-color: transparent;
-                  color: #a55b41;
-                }
-              }
-              .ZH1main2rr2RowAc {
-                background-color: #eacf60;
-                border-color: transparent;
-                color: #a55b41;
-              }
-            }
-          }
-        }
-      }
-    }
-    .ZHrr {
-      width: 40%;
-    }
-
-    // -----------------三级信息
-    .ZH1main1Son {
-      width: 100%;
-      max-height: 100%;
-      overflow: auto;
-      &::-webkit-scrollbar {
-        display: none;
-      }
-
-      // 模型 视频
-      .H2model {
-        width: 100%;
-        height: 200px;
-        .H2modelSon {
-          iframe {
-            width: 100%;
-            height: 100%;
-          }
-        }
-
-        video {
-          object-fit: contain !important;
-          width: 100%;
-          height: 100%;
-        }
-      }
-      .ZH1txt3 {
-        p {
-          text-indent: 0em !important;
-        }
-      }
-    }
-
-    // 屏幕>=1200
-    @media screen and (min-width: 1200px) {
-      .ZHll {
-        // .h2Titele {
-        //   font-size: 24px;
-        // }
-        .ZH1main {
-          .ZH1main1 {
-            // 一级介绍
-            .ZH1txt {
-              h3 {
-                font-size: 12px;
-              }
-              p {
-                font-size: 10px;
-                line-height: 20px;
-              }
-            }
-          }
-          // 二级
-          .ZH1main1 {
-            .ZH1_2 {
-              .ZH1_2ll {
-                .ZH1_2llRow {
-                  font-size: 10px;
-                }
-              }
-              .ZH1_2rr {
-                p {
-                  font-size: 9px;
-                  line-height: 18px;
-                }
-              }
-            }
-          }
-        }
-      }
-      .ZH1main2rr1 {
-        font-size: 12px !important;
-        width: 60px !important;
-      }
-      .ZHll .ZH1main .ZH1main2 .ZH1main2rr .ZH1main2rr2 {
-        width: calc(100% - 60px);
-        height: 24px;
-        .ZH1main2rr2Row {
-          height: 24px;
-          line-height: 22px;
-          font-size: 12px;
-        }
-      }
-      #BtnRight {
-        left: 8px !important;
-        width: 38px !important;
-        height: 38px !important;
-      }
-    }
-  }
-}

+ 0 - 320
src/components/Zhot/index.tsx

@@ -1,320 +0,0 @@
-import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
-import styles from './index.module.scss'
-import { baseURL, hotInfo, isPc } from '@/utils/http'
-import { HotInvolveType, HotRowType, HotSonType } from './type'
-import BtnRight from '../BtnRight'
-import classNames from 'classnames'
-import LazyImg from '../LazyImg'
-import { useSelector } from 'react-redux'
-import { RootState } from '@/store'
-import { ImageViewer } from 'antd-mobile'
-import { Image } from 'antd'
-
-type Props = {
-  name: string
-  closeFu: () => void
-}
-
-function Zhot({ name, closeFu }: Props) {
-  // 二级的选中
-  const [acObj2, setAcObj2] = useState({} as HotSonType)
-
-  // 切换二级院落,滚动到最左边
-  useEffect(() => {
-    setTimeout(() => {
-      if (sroolRef.current) sroolRef.current.scrollLeft = 0
-    }, 100)
-  }, [acObj2])
-
-  const info = useMemo(() => {
-    let info = {} as HotRowType
-    for (const k in hotInfo) {
-      let obj = hotInfo[k as 'cheQi'].find(v => v.name === name)
-      if (obj) {
-        info = obj
-        setAcObj2(obj.data.son[0])
-      }
-    }
-    return info
-  }, [name])
-
-  // 二级相关文物---没有二级全部显示
-  const involveResArr = useMemo(() => {
-    let arr: HotInvolveType[] = []
-    if (info && info.data) {
-      arr = info.data.involve
-      if (acObj2 && acObj2.name) {
-        if (acObj2.sonInvolve) {
-          arr = arr.filter(v => acObj2.sonInvolve?.includes(v.name))
-        } else arr = []
-      }
-    }
-
-    return arr
-  }, [acObj2, info])
-
-  // 相关文物的滚动
-  const [isFlag, setIsFlag] = useState(false)
-
-  const sroolRef = useRef<HTMLDivElement>(null)
-  const mousemoveFu = useCallback(
-    (ev: any, flag?: boolean) => {
-      if (sroolRef.current) {
-        if (flag && !isFlag) {
-          const nowMove = sroolRef.current.scrollLeft
-          // 滚轮
-          let num = 50
-          if (ev.deltaY < 0) num = -num
-          sroolRef.current.scrollLeft = nowMove + num
-        } else if (isFlag) {
-          const nowMove = sroolRef.current.scrollLeft
-
-          // 鼠标按住移动
-          sroolRef.current.scrollLeft = nowMove - ev.movementX
-        }
-      }
-    },
-    [isFlag]
-  )
-
-  // 第三级选中
-  const [acObj3, setAcObj3] = useState({} as HotInvolveType)
-
-  const rootStyle = useSelector((state: RootState) => state.A0Layout.style)
-
-  const [modelSize, setModelSize] = useState({ ww: 0, hh: 0, wwB: 0, hhB: 0 })
-
-  useEffect(() => {
-    if (acObj3.name) {
-      // 模型重定义尺寸
-      const dom = document.querySelector('.H2model')
-      if (dom) {
-        setModelSize({
-          ww: Number((dom.clientWidth * rootStyle.sizeW).toFixed(2)),
-          hh: Number((dom.clientHeight * rootStyle.sizeH).toFixed(2)),
-          wwB: dom.clientWidth,
-          hhB: dom.clientHeight
-        })
-      }
-
-      setTimeout(() => {
-        // 移动到顶部
-        const sroolDom: HTMLDivElement = document.querySelector('.ZH1main1Son')!
-        if (sroolDom) sroolDom.scrollTop = 0
-      }, 100)
-    }
-  }, [acObj3.name, rootStyle.sizeH, rootStyle.sizeW])
-
-  // 查看图片
-  const [imgLook, setImgLook] = useState('')
-
-  return (
-    <div className={styles.Zhot} id='HotOpCss'>
-      {/* 移动端查看图片 */}
-      {isPc ? null : (
-        <ImageViewer
-          getContainer={document.querySelector('body')}
-          image={imgLook}
-          visible={!!imgLook}
-          onClose={() => setImgLook('')}
-        />
-      )}
-
-      {/* pc端查看图片 */}
-      {isPc && imgLook ? (
-        <Image
-          preview={{
-            visible: !!imgLook,
-            src: imgLook,
-            onVisibleChange: () => setImgLook('')
-          }}
-        />
-      ) : null}
-
-      {/* 左边主体 */}
-      <div className='ZHll'>
-        <div className='ZHLLcen' style={{ backgroundImage: `url(${baseURL + 'Zhot/bac.png'})` }}>
-          {/* 标题 */}
-          <div className='h2Titele sizeNo'>
-            <img src={`${baseURL}Zhot/img-yun1.png`} alt='' />
-            <img className='h2TimgR' src={`${baseURL}Zhot/img-yun2.png`} alt='' />
-            {acObj3.name ? acObj3.name.replaceAll('&', '') : name}
-          </div>
-
-          {info.data ? (
-            <div className='ZH1main'>
-              <div className='ZH1main1' hidden={!!acObj3.name} id='ZH1main1'>
-                {/* 一级图片 */}
-                {info.data.imgArr1 && info.data.imgArr1.length ? (
-                  <div className='ZHimgBox'>
-                    {info.data.imgArr1.map(url => (
-                      <LazyImg
-                        clickFu={() => setImgLook(baseURL + url)}
-                        src={baseURL + url}
-                        key={url}
-                      />
-                    ))}
-                  </div>
-                ) : null}
-                {/* 一级介绍 */}
-                <div className='ZH1txt' dangerouslySetInnerHTML={{ __html: info.data.txt }}></div>
-
-                {/* ----------二级----------- */}
-                {info.data.son && info.data.son.length ? (
-                  <div className='ZH1_2'>
-                    <div className='ZH1_2ll'>
-                      {info.data.son.map(row2 => (
-                        <div
-                          key={row2.name}
-                          className={classNames(
-                            'ZH1_2llRow sizeNo',
-                            acObj2.name === row2.name ? 'ZH1_2llRowAc' : ''
-                          )}
-                          onClick={() => setAcObj2(row2)}
-                        >
-                          <img src={baseURL + 'Zhot/icon2.png'} alt='' />
-                          <img src={baseURL + 'Zhot/icon2Ac.png'} alt='' />
-                          {row2.name.replaceAll('&', '')}
-                        </div>
-                      ))}
-                    </div>
-                    <div className='ZH1_2rr'>
-                      {/* 二级图片 */}
-                      {acObj2.imgArr2 && acObj2.imgArr2.length ? (
-                        <div className='ZHimgBox'>
-                          {acObj2.imgArr2.map(url => (
-                            // 懒加载有问题,用普通img
-                            // <LazyImg
-                            //   clickFu={() => setImgLook(baseURL + url)}
-                            //   src={baseURL + url}
-                            //   key={url}
-                            // />
-                            <img
-                              className='ZH2img'
-                              key={url}
-                              src={baseURL + url}
-                              alt=''
-                              onClick={() => setImgLook(baseURL + url)}
-                            />
-                          ))}
-                        </div>
-                      ) : null}
-                      <div dangerouslySetInnerHTML={{ __html: acObj2.txt }}></div>
-                    </div>
-                  </div>
-                ) : null}
-              </div>
-
-              {/* -----------三级信息------------- */}
-              {acObj3.name ? (
-                <div className='ZH1main1 ZH1main1Son'>
-                  {acObj3.type === '图片' ? (
-                    <div className='ZHimgBox'>
-                      {acObj3.urlArr.map(url => (
-                        <LazyImg
-                          clickFu={() => setImgLook(baseURL + url)}
-                          src={baseURL + url}
-                          key={url}
-                        />
-                      ))}
-                    </div>
-                  ) : null}
-
-                  {['模型', '视频'].includes(acObj3.type) ? (
-                    <div className='H2model' style={{ height: acObj3.text ? '200px' : '280px' }}>
-                      {acObj3.type === '模型' ? (
-                        <div
-                          className='H2modelSon'
-                          style={
-                            isPc && Object.keys(rootStyle).length && modelSize.ww
-                              ? {
-                                  position: 'relative',
-                                  width: modelSize.ww + 'px',
-                                  height: modelSize.hh + 'px',
-                                  transform: `translate(${-(modelSize.ww - modelSize.wwB) / 2}px, ${
-                                    -(modelSize.hh - modelSize.hhB) / 2
-                                  }px) scale(${1 / rootStyle.sizeW}, ${1 / rootStyle.sizeH})`
-                                }
-                              : { width: '100%', height: '100%' }
-                          }
-                        >
-                          <iframe
-                            title={name}
-                            src={`${baseURL}modelLoding/model.html?u=${acObj3.urlArr[0]}`}
-                            frameBorder='0'
-                          ></iframe>
-                        </div>
-                      ) : (
-                        <video
-                          src={baseURL + acObj3.urlArr[0]}
-                          controls
-                          playsInline
-                          muted
-                          webkit-playsinline='true'
-                          x5-video-player-type='h5'
-                        ></video>
-                      )}
-                    </div>
-                  ) : null}
-
-                  <div
-                    className='ZH1txt ZH1txt3'
-                    dangerouslySetInnerHTML={{ __html: acObj3.text }}
-                  ></div>
-                </div>
-              ) : null}
-
-              <div className='ZH1main2'>
-                {/* 返回按钮 */}
-                <div className='back1'>
-                  <BtnRight
-                    title='返回'
-                    clickSon={() => {
-                      acObj3.name ? setAcObj3({} as HotInvolveType) : closeFu()
-                    }}
-                    imgName='back'
-                  />
-                </div>
-
-                {/* 相关文物 */}
-                {involveResArr && involveResArr.length ? (
-                  <div className='ZH1main2rr'>
-                    <div className='ZH1main2rr1 sizeNo'>相关文物:</div>
-                    <div
-                      className='ZH1main2rr2'
-                      onMouseDown={() => setIsFlag(true)}
-                      onMouseUp={() => setIsFlag(false)}
-                      onMouseLeave={() => setIsFlag(false)}
-                      onMouseMove={e => mousemoveFu(e)}
-                      onWheel={e => mousemoveFu(e, true)}
-                      style={{ cursor: isFlag ? 'move' : 'default' }}
-                      ref={sroolRef}
-                    >
-                      {involveResArr.map(row3 => (
-                        <div
-                          onClick={() => setAcObj3(row3)}
-                          className={classNames(
-                            'ZH1main2rr2Row sizeNo',
-                            acObj3.name === row3.name ? 'ZH1main2rr2RowAc' : ''
-                          )}
-                          key={row3.name}
-                        >
-                          {row3.name.replaceAll('&', '')}
-                        </div>
-                      ))}
-                    </div>
-                  </div>
-                ) : null}
-              </div>
-            </div>
-          ) : null}
-        </div>
-      </div>
-      <div className='ZHrr' onClick={closeFu}></div>
-    </div>
-  )
-}
-
-const MemoZhot = React.memo(Zhot)
-
-export default MemoZhot

+ 0 - 77
src/components/Zhot/type.d.ts

@@ -1,77 +0,0 @@
-export type HotRowType = {
-  name: string
-  tubiao: '普通' | '文物'
-  zIndex: number
-  hoverSrc: string
-  pageType: string // 田耕特有的
-  // 当前页面的定位(如果是全景图和全景视频 ---没有)
-  locPage: {
-    top: string
-    left: string
-  }
-  // 全景视频和全景图的定位(不是全景图或者全景视频的---没有)
-  panoLoc: {
-    size: number
-    atv: number
-    ath: number
-  }
-  // 热点定位百分比(更多模块的定位--不需要在更多模块中展示的---没有)
-  locMore: {
-    top: string
-    left: string
-  }
-  data: {
-    txt: string
-    imgArr1?: string[]
-    son: HotSonType[]
-    involve: HotInvolveType[]
-  }
-}
-export type HotInvolveType = {
-  name: string
-  type: '图片' | '模型' | '视频'
-  urlArr: string[]
-  text: string
-}
-
-export type HotSonType = {
-  name: string
-  txt: string
-  imgArr2?: string[]
-  sonInvolve?: string[]
-}
-
-export type HotInfoType = {
-  cheQi: HotRowType[]
-  cheQi2: HotRowType[]
-  cheQiCove: HotRowType[]
-  yanYing1: HotRowType[]
-  yanYing2: HotRowType[]
-  yanYing3: HotRowType[]
-  yueWu: HotRowType[]
-  houCu: HotRowType[]
-  plowZhuang: HotRowType[]
-  plowCai: HotRowType[]
-  xianJu: HotRowType[]
-  xianJu2: HotRowType[]
-  周礼九拜: {
-    name: string
-    tubiao: '普通' | '文物'
-    zIndex: number
-    hoverSrc: string
-    panoLoc: {
-      size: number
-      atv: number
-      ath: number
-    }
-    locMore: {
-      top: string
-      left: string
-    }
-    data: {
-      name: string
-      txt: string
-      imgArr: string[]
-    }[]
-  }[]
-}

+ 23 - 16
src/index.tsx

@@ -27,19 +27,26 @@ const getLikeFu = async () => {
 }
 getLikeFu()
 
-root.render(
-  <ConfigProvider
-    locale={locale}
-    theme={{
-      token: {
-        colorPrimary: '#ead98f'
-      }
-    }}
-  >
-    <Provider store={store}>
-      <StyleProvider hashPriority='high' transformers={[legacyLogicalPropertiesTransformer]}>
-        <App />
-      </StyleProvider>
-    </Provider>
-  </ConfigProvider>
-)
+if (typeof window !== 'undefined') {
+
+
+  root.render(
+    <ConfigProvider
+      locale={locale}
+      theme={{
+        token: {
+          colorPrimary: '#ead98f'
+        }
+      }}
+    >
+      <Provider store={store}>
+        <StyleProvider hashPriority='high' transformers={[legacyLogicalPropertiesTransformer]}>
+          <App />
+        </StyleProvider>
+      </Provider>
+    </ConfigProvider>
+
+
+  )
+
+}

+ 5 - 0
src/pages/A0base/index.module.scss

@@ -8,6 +8,7 @@
       width: 50%;
       height: 50%;
       position: absolute;
+      z-index: 1;
       top: 50%;
       left: 50%;
       transform: translate(-5%, -65%);
@@ -107,6 +108,7 @@
       width: 60px;
       height: 120px;
       position: absolute;
+      z-index: 1;
       bottom: 5%;
       left: 2%;
       display: flex;
@@ -160,8 +162,10 @@
       width: 30px;
       height: 30px;
       position: absolute;
+      z-index: 1;
       top: 3%;
       left: 2%;
+      cursor: pointer;
       color: rgba(255, 233, 182, 1);
     }
 
@@ -170,6 +174,7 @@
       width: 50px;
       height: 50px;
       position: absolute;
+      z-index: 1;
       top: 2%;
       right: 5%;
       display: flex;

+ 5 - 5
src/pages/A0base/index.tsx

@@ -1,8 +1,7 @@
-import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
+import React, { useState } from 'react'
 import styles from './index.module.scss'
-import history from '@/utils/history'
 import { myData } from '@/utils/http'
-
+import history from '@/utils/history'
 
 
 function A0base() {
@@ -12,8 +11,9 @@ function A0base() {
   const goto = (e: React.MouseEvent, path: string) => {
     e.preventDefault()
     e.stopPropagation()
-    history.push(path)
+    window.location.replace(path)
   }
+
   return (
     <div className={styles.A0base}>
       <div className='A0Container'>
@@ -54,7 +54,7 @@ function A0base() {
         </div>
       </div>
 
-      <div className='home'>
+      <div className='home' onClick={e => goto(e, '/')}>
         <img src={require('@/assets/img/home.png')} alt='' />
       </div>
 

+ 26 - 7
src/pages/A1home/index.module.scss

@@ -2,6 +2,7 @@
   width: 100%;
   height: 100%;
   position: relative;
+  z-index: 1;
   :global {
     .loadingP {
       position: absolute;
@@ -17,6 +18,13 @@
       justify-content: center;
       flex-direction: column;
       color: rgba(166, 118, 67, 1);
+      .progress {
+        width: 200px;
+        height: 30px;
+        line-height: 30px;
+        text-align: center;
+        transform: translate(5px, 155px);
+      }
       .btn {
         width: 60px;
         height: 60px;
@@ -24,13 +32,24 @@
         background-size: 100% 100%;
         transform: translateY(155px);
         cursor: pointer;
-      }
-      .progress {
-        width: 200px;
-        height: 30px;
-        line-height: 30px;
-        text-align: center;
-        transform: translate(5px, 155px);
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        & > img {
+          width: 60%;
+          height: 60%;
+          object-fit: contain;
+          animation: yunShan 3s infinite linear;
+        }
+        .txt {
+          width: 35px;
+          height: 30px;
+          color: rgba(255, 233, 182, 1);
+          font-size: 15px;
+          line-height: 15px;
+          text-align: center;
+          animation: zhiti 2s infinite linear;
+        }
       }
     }
     .A1videoBox {

+ 28 - 15
src/pages/A1home/index.tsx

@@ -17,13 +17,13 @@ function A1home() {
       onPlay: () => { }, // 触发播放事件
       onPause: () => { }, // 触发暂停事件
       onEnded: () => {
-        history.push('/base')
+        window.location.replace('#/base')
       }, // 触发播放结束事件
       onSourceEstablished: () => {
         setVideoOk(true)
       } //有足够的数据可以播放了
     }
-    playerRef.current = F_Video('./myData/play.ts', params)
+    playerRef.current = F_Video('./myData/home.ts', params)
     const dom = document.querySelector('.A1video')!
     dom.append(playerRef.current.domElement)
   }, [])
@@ -48,23 +48,36 @@ function A1home() {
     if (progress === 100) setLoadOk(true)
   }, [progress])
 
-  window.LoadingProgress = (progress: number) => {
-    console.log('当前进度', progress)
-    if (progress >= 98) {
-      setProgress(98)
-      return
+  useEffect(() => {
+    // 1-10
+    window.unityLoading = (progress: number) => {
+      console.log('当前进度', progress * 100 + '%')
+      if (progress * 100 >= 98) {
+        setProgress(98)
+        return
+      }
+      setProgress(Number((progress * 100).toFixed(0)))
+    }
+  }, [setProgress])
+
+  // 判断是否已经加载好了iframe和视频,如果已经加载好了设置对应进度为100
+  useEffect(() => {
+    const iframe = document.getElementById('modalIframe') as HTMLIFrameElement | null
+    if (iframe && iframe.contentWindow && videoOk) {
+      setProgress(100)
     }
-    setProgress(progress)
-  }
+  }, [loadOk, videoOk])
 
   return (
     <div className={styles.A1home}>
-      <div
-        className='loadingP'
-        style={{ display: loadOk ? 'none' : 'flex' }}
-        onClick={() => window.LoadingProgress(progress + 20)}
-      >
-        <div className='btn' onClick={() => enter()}></div>
+      <div className='loadingP' style={{ display: loadOk ? 'none' : 'flex' }}>
+        <div className='btn' onClick={() => enter()}>
+          {progress !== 100 ? (
+            <img src={require('@/assets/img/home_loading.png')} alt='' draggable='false' />
+          ) : (
+            <div className="txt">点击进入</div>
+          )}
+        </div>
         <div className='progress'>加载{progress}%...</div>
       </div>
       {/* ------------微信浏览器不让视频自动播放,用ts的方式*/}

+ 66 - 42
src/pages/A2yblm/components/Detail/index.module.scss

@@ -1,55 +1,79 @@
 .detail {
-  width: 170px;
+  width: 100%;
   height: 100%;
-  display: flex;
-  flex-direction: column;
-  justify-content: center;
-  gap: 30px;
-
+  position: relative;
   :global {
-    .detail_top,
-    .detail_bottom {
-      width: 100%;
-      height: fit-content;
+    .selectContainner {
+      position: absolute;
+      z-index: 1;
+      top: 50%;
+      left: 50%;
+      transform: translate(-50%, -50%);
+      width: 170px;
+      height: 100%;
       display: flex;
-      align-items: center;
-      justify-content: space-between;
-      gap: 10px;
-      .topL {
-        width: 100px;
+      flex-direction: column;
+      justify-content: center;
+      gap: 30px;
+
+      .detail_top,
+      .detail_bottom {
+        width: 100%;
         height: fit-content;
         display: flex;
-        flex-direction: column;
+        align-items: center;
+        justify-content: space-between;
         gap: 10px;
-        .item {
+        .topL {
           width: 100px;
-          height: 20px;
-          font-size: 10px;
-          line-height: 15px;
-          text-align: right;
-          color: rgba(255, 233, 182, 1);
-          cursor: pointer;
-        }
-        .active {
-          color: rgb(255, 252, 246);
-          text-shadow: 3px 0px 10px rgba(255, 255, 255, 1);
+          height: fit-content;
+          display: flex;
+          flex-direction: column;
+          gap: 10px;
+          .item {
+            width: 100px;
+            height: 20px;
+            font-size: 10px;
+            line-height: 15px;
+            text-align: right;
+            color: rgba(255, 233, 182, 1);
+            cursor: pointer;
+            position: relative;
+            .selectedBg {
+              width: 100%;
+              height: 100%;
+              position: absolute;
+              top: 0;
+              left: 39%;
+              z-index: -1;
+              & > img {
+                width: 100%;
+                height: 100%;
+                object-fit: contain;
+              }
+            }
+          }
+          .active {
+            color: rgb(255, 252, 246);
+            text-shadow: 3px 0px 10px rgba(255, 255, 255, 1);
+          }
         }
-      }
-      .topR {
-        width: 40px;
-        height: 100%;
-        display: flex;
-        align-items: center;
-        .split {
-          width: 2px;
+        .topR {
+          width: 40px;
           height: 100%;
-          border-right: 1px dashed rgba(255, 255, 255, 1);
-        }
-        .txt {
-          width: 30px;
-          font-size: 10px;
-          text-align: right;
-          color: #fff;
+          display: flex;
+          align-items: center;
+          .split {
+            width: 2px;
+            height: 100%;
+            border-right: 1px dashed rgba(255, 255, 255, 1);
+          }
+          .txt {
+            width: 30px;
+            font-size: 10px;
+            text-align: right;
+            color: #fff;
+          }
         }
       }
     }

+ 49 - 22
src/pages/A2yblm/components/Detail/index.tsx

@@ -1,34 +1,61 @@
-import React, { useState } from "react";
+import React, { useEffect, useState } from "react";
 import styles from "./index.module.scss";
 import { myData } from "@/utils/http";
-function Detail() {
-  const [selectedIndex, setSelectedIndex] = useState(0);
+import { callIframeFu } from "@/utils/history";
+
+type DetailProps = {
+  currentTagIndex: number,
+  setCurrentTagIndex: (index: number) => void,
+  setIsShowTag: (isShow: boolean) => void
+}
+function Detail({ currentTagIndex, setCurrentTagIndex, setIsShowTag }: DetailProps) {
+
+  const handleHot = (index: number) => {
+    setCurrentTagIndex(index)
+    callIframeFu('showHotspot', index)
+  }
+
+  setTimeout(() => {
+    handleHot(currentTagIndex)
+  }, 20);
+
+  window.showTag = () => {
+    setIsShowTag(true)
+  }
+  window.hideTag = () => {
+    setIsShowTag(false)
+  }
+
   return (
     <div className={styles.detail}>
-      <div className="detail_top">
-        <div className="topL">
-          {myData.detail_modal.top.map((item, index) => (
-            <div className={`item ${selectedIndex === index ? 'active' : ''}`} onClick={() => setSelectedIndex(index)} key={index}>
+      <div className="selectContainner">
+        <div className="detail_top">
+          <div className="topL">
+            {myData.detail_modal.top.map((item, index) => (
+              <div className={`item ${currentTagIndex === index ? 'active' : ''}`} onClick={() => handleHot(index)} key={index}>
+                {item.title}
+                {currentTagIndex === index && <div className="selectedBg"><img src={require('@/assets/img/hotSelected_bg.png')} alt="" /></div>}
+              </div>
+            ))}
+          </div>
+          <div className="topR">
+            <div className="split"></div>
+            <div className="txt">碑面</div>
+          </div>
+        </div>
+        <div className="detail_bottom"> <div className="topL">
+          {myData.detail_modal.bottom.map((item, index) => (
+            <div className={`item ${currentTagIndex === index + myData.detail_modal.top.length ? 'active' : ''}`} onClick={() => handleHot(index + myData.detail_modal.top.length)} key={index}>
               {item.title}
             </div>
           ))}
         </div>
-        <div className="topR">
-          <div className="split"></div>
-          <div className="txt">碑面</div>
-        </div>
+          <div className="topR">
+            <div className="split"></div>
+            <div className="txt">碑侧</div>
+          </div></div>
       </div>
-      <div className="detail_bottom"> <div className="topL">
-        {myData.detail_modal.bottom.map((item, index) => (
-          <div className="item" key={index}>
-            {item.title}
-          </div>
-        ))}
-      </div>
-        <div className="topR">
-          <div className="split"></div>
-          <div className="txt">碑侧</div>
-        </div></div>
+
     </div>
   )
 }

+ 3 - 0
src/pages/A2yblm/components/Intro/index.module.scss

@@ -4,7 +4,10 @@
   display: flex;
   flex-direction: column;
   gap: 10px;
+  padding: 0 20px;
   padding-top: 40px;
+  background: url(../../../../assets/img/intro_bg.png) no-repeat center center;
+  background-size: 100% 100%;
   :global {
     .titleLogo {
       width: 100px;

+ 7 - 20
src/pages/A2yblm/components/Intro/index.tsx

@@ -1,5 +1,6 @@
 import React from "react";
 import styles from "./index.module.scss";
+import { myData } from "@/utils/http";
 function Intro() {
 
   return (
@@ -7,26 +8,12 @@ function Intro() {
       <div className="titleLogo">
         <img src={require("@/assets/img/titleLogo.png")} alt="" />
       </div>
-      <div className="info">
-        <div className="label">名称</div>
-        <div className="content">石碑简介石碑简介石碑简介石碑简介石碑简介石碑简介石碑简介石碑简介石碑简介石碑简介石碑简介石碑简介</div>
-      </div>
-      <div className="info">
-        <div className="label">时代</div>
-        <div className="content">简介石碑简介石碑简介石碑简介石碑简介石碑简介石碑简介</div>
-      </div>
-      <div className="info">
-        <div className="label">材质</div>
-        <div className="content">石碑简介简介石碑简介石碑简介石碑简介</div>
-      </div>
-      <div className="info">
-        <div className="label">形制</div>
-        <div className="content">石碑简介石碑简介石碑简介石碑简介石碑简介石碑简介石碑简介石碑简介石碑简介石碑简介石碑简介石碑简介</div>
-      </div>
-      <div className="info">
-        <div className="label">尺寸</div>
-        <div className="content">石碑简介石碑简介石碑简介石碑简介石碑简介石碑简介石碑简介石碑简介石碑简介石碑简介石碑简介石碑简介</div>
-      </div>
+      {myData.introInfo.map((item, index) => (
+        <div className="info" key={index}>
+          <div className="label">{item.title}</div>
+          <div className="content">{item.text}</div>
+        </div>
+      ))}
     </div>
   )
 }

+ 10 - 85
src/pages/A2yblm/components/ModalTxt/index.module.scss

@@ -1,13 +1,11 @@
 .modalTxt {
-  width: 100%;
+  width: 55%;
   height: 100%;
   position: absolute;
-
-  background-color: #ccc;
-
+  z-index: 1;
   top: 50%;
   left: 50%;
-  transform: translate(-50%, -50%);
+  transform: translate(-8%, -50%);
   display: flex;
   align-items: center;
   justify-content: end;
@@ -19,81 +17,6 @@
       flex-direction: column;
       gap: 10px;
 
-      .extra {
-        width: 110px;
-        height: 25px;
-        position: absolute;
-        bottom: 18%;
-        left: 4%;
-        display: flex;
-        align-items: center;
-        justify-content: space-between;
-        background-color: rgba(0, 0, 0, 0.7);
-        border-radius: 15px;
-        padding: 0 8px;
-        cursor: pointer;
-        .icon {
-          width: 20px;
-          height: 20px;
-          & > img {
-            height: 100%;
-            object-fit: contain;
-          }
-        }
-
-        .txt {
-          width: fit-content;
-          font-size: 9px;
-          font-weight: 500;
-          color: #fbebbd;
-        }
-      }
-      .mzm {
-        width: 100%;
-        height: 100%;
-        position: absolute;
-        z-index: 24;
-        top: 50%;
-        left: 50%;
-        transform: translate(-50%, -50%);
-        background-color: rgba(0, 0, 0, 0.7);
-        backdrop-filter: blur(3px);
-        display: flex;
-        flex-direction: column;
-        gap: 10px;
-        padding: 20px 55px;
-        .top {
-          display: flex;
-          align-items: center;
-          justify-content: space-between;
-          width: 100%;
-          height: 50px;
-          .title {
-            font-size: 14px;
-            font-weight: 500;
-            color: #fbebbd;
-          }
-          .close {
-            width: 50px;
-            height: 50px;
-            cursor: pointer;
-            & > img {
-              height: 100%;
-              object-fit: contain;
-            }
-          }
-        }
-        .content {
-          font-size: 10px;
-          line-height: 15px;
-          font-weight: lighter;
-          color: rgba(255, 255, 255, 1);
-          & > p {
-            padding-bottom: 15px;
-          }
-        }
-      }
-
       .topBar {
         width: 100%;
         height: 70px;
@@ -184,7 +107,7 @@
             font-size: 9px;
             line-height: 17px;
             font-weight: 500;
-            color: rgba(94, 52, 34, 1);
+            color: rgba(94, 52, 34, 1); // 原始颜色
             overflow: auto;
             padding-bottom: 10px;
             &::-webkit-scrollbar {
@@ -197,16 +120,15 @@
               background-color: rgba(94, 52, 34, 0.226);
               border-radius: 4px;
             }
-            &:has(> a:hover, > a.active) {
+            &:has(> a:hover) {
               color: rgba(0, 0, 0, 0.25);
             }
-            &:has(> a:hover, > a.active) > a:not(:hover):not(.active) {
+            &:has(> a:hover) > a:not(:hover) {
               color: rgba(0, 0, 0, 0.25);
             }
             & > a {
               color: rgba(94, 52, 34, 1);
               position: relative;
-
               &::after {
                 content: '';
                 position: absolute;
@@ -215,7 +137,6 @@
                 width: 100%;
                 height: 1px;
                 background-color: rgba(166, 118, 67, 1);
-                /* 使用scaleX压缩下划线,从右边开始 */
                 transform: scaleX(0.95);
                 transform-origin: right center;
               }
@@ -245,8 +166,12 @@
           font-weight: bold;
         }
         .text {
+          width: 300px;
           line-height: 15px;
           font-size: 9px;
+          & > p {
+            text-indent: 2em;
+          }
         }
       }
     }

+ 87 - 118
src/pages/A2yblm/components/ModalTxt/index.tsx

@@ -3,73 +3,26 @@ import React, { useState, useEffect, useRef } from 'react'
 import styles from './index.module.scss'
 import { myData } from '@/utils/http'
 import { Tooltip } from 'antd'
-import history, { isMobiileFu } from '@/utils/history'
+import { renderToString } from 'react-dom/server';
+import history, { callIframeFu } from '@/utils/history'
 
-function ModalTxt() {
+function ModalTxt({ setIsShowTabBar, setIsShowMzmTitle }: { setIsShowTabBar: (isShowTabBar: boolean) => void; setIsShowMzmTitle: (isShowMzmTitle: boolean) => void }) {
   const [selectedTab, setSelectedTab] = useState(0)
-  const [isOpenMzm, setIsOpenMzm] = useState(false)
-  const [modalTxtIndex, setModalTxtIndex] = useState(1)
+
   const [activeAId, setActiveAId] = useState<number | null>(null)
   const [showTooltip, setShowTooltip] = useState(-1)
 
-  // 备份
-  //   #root .ant-tooltip .tooltip_MT {
-  //   height: 100%;
-  //   font-size: 16px;
-  //   line-height: 24px;
-  //   color: #000;
-  //   display: flex;
-  //   flex-direction: column;
-  //   padding-bottom: 8px;
-  //   gap: 4px;
-  //   .top {
-  //     width: 100%;
-  //     height: 15px;
-  //     display: flex;
-  //     justify-content: space-between;
-  //     align-items: center;
-  //     .title {
-  //       width: 30px;
-  //       height: 100%;
-  //       font-size: 10px;
-  //       line-height: 15px;
-  //       color: rgba(255, 233, 182, 1);
-  //     }
-  //     .close {
-  //       width: 40px;
-  //       height: 100%;
-  //       cursor: pointer;
-  //       display: flex;
-  //       justify-content: end;
-  //       align-items: center;
-  //       & > img {
-  //         height: 90%;
-  //         object-fit: contain;
-  //       }
-  //     }
-  //   }
-  //   .content {
-  //     width: 100%;
-  //     height: calc(100% - 16px);
-  //     font-size: 7px;
-  //     line-height: 10px;
-  //     color: #fff;
-  //     font-weight: lighter;
-  //     overflow: auto;
-  //     &::-webkit-scrollbar {
-  //       width: 1px;
-  //     }
-  //     &::-webkit-scrollbar-thumb {
-  //       background: rgba(255, 233, 182, 1);
-  //     }
-  //   }
-  // }
+  useEffect(() => {
+    if (selectedTab !== 0) {
+      setIsShowMzmTitle(true)
+      setIsShowTabBar(false)
+    }
+  }, [selectedTab, setIsShowMzmTitle, setIsShowTabBar])
+
 
-  // 动态变化zIndex
   useEffect(() => {
-    setModalTxtIndex(selectedTab === 0 ? 1 : 2)
-    if (isOpenMzm) setModalTxtIndex(10)
-  }, [selectedTab, isOpenMzm])
+    localStorage.setItem('selectedBeiwen', selectedTab.toString())
+  }, [selectedTab])
 
   //动态加入a标签
   const CommentLink = ({ index, word, define }: { index: number; word: string; define: string }) => {
@@ -105,81 +58,93 @@ function ModalTxt() {
   }
 
   const CommentText = ({ str, index }: { str: string; index: number }) => {
-    // 词
-    const convertArr = myData.comment[index].words.map(item => item.name)
-    // 解释
-    const defineArr = myData.comment[index].words.map(item => item.define)
-    const parts = []
-    let remainingStr = str
+    const convertArr = myData.readDetail[index].words.map(item => item.name);
+    const defineArr = myData.readDetail[index].words.map(item => item.define);
+    const parts: React.ReactNode[] = [];
+    let remainingStr = str;
+
+    // 工具函数:过滤 <p> 标签(保留文本,移除所有 <p> 和 </p>)
+    const removePTags = (text: string) => {
+      // 匹配所有 <p...> 和 </p> 标签,替换为空(保留内部文本)
+      return text.replace(/<p[^>]*>/gi, '').replace(/<\/p>/gi, '');
+    };
+
+    // 先过滤原始字符串中的 <p> 标签
+    remainingStr = removePTags(remainingStr);
+    // 若 word/define 也带 <p>,同步过滤(按需开启)
+    // convertArr = convertArr.map(word => removePTags(word));
+    // defineArr = defineArr.map(define => removePTags(define));
 
     convertArr.forEach((word, idx) => {
-      const regex = new RegExp(word)
-      const match = remainingStr.match(regex)
+      // 注意:若 word 含特殊字符(如 . * +),需转义正则
+      const escapedWord = word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+      const regex = new RegExp(escapedWord);
+      const match = remainingStr.match(regex);
 
       if (match) {
-        const matchIndex = match.index || 0
+        const matchIndex = match.index || 0;
 
-        // 添加匹配前的文本
+        // 添加匹配前的文本(已过滤 <p>)
         if (matchIndex > 0) {
-          parts.push(remainingStr.substring(0, matchIndex))
+          parts.push(
+            <span
+              key={`text-before-${idx}`}
+              dangerouslySetInnerHTML={{ __html: remainingStr.substring(0, matchIndex) }}
+            />
+          );
         }
 
-        // 添加链接组件
-        parts.push(<CommentLink key={idx} index={idx} word={word} define={defineArr[idx]} />)
+        // 添加链接组件(若 define 带 <p>,这里也可过滤:define={removePTags(defineArr[idx])})
+        parts.push(
+          <CommentLink
+            key={idx}
+            index={idx}
+            word={word}
+            define={defineArr[idx]}
+          />
+        );
 
         // 更新剩余字符串
-        remainingStr = remainingStr.substring(matchIndex + word.length)
+        remainingStr = remainingStr.substring(matchIndex + word.length);
       }
-    })
+    });
 
-    // 添加剩余的文本
+    // 添加剩余文本(已过滤 <p>)
     if (remainingStr) {
-      parts.push(remainingStr)
+      parts.push(
+        <span
+          key="text-remaining"
+          dangerouslySetInnerHTML={{ __html: remainingStr }}
+        />
+      );
     }
 
-    return <>{parts}</>
+    return <>{parts}</>;
+  };
+
+  const handleBeie = () => {
+    window.location.replace('#/beie')
+    callIframeFu('showInscription', 0)
+  }
+
+  const handleTabClick = (tabIndex: number) => {
+    setSelectedTab(tabIndex)
+    callIframeFu('showInscription', tabIndex)
   }
 
   return (
-    <div className={styles.modalTxt} id='modalTxt' style={{ zIndex: modalTxtIndex }}>
+    <div className={styles.modalTxt} id='modalTxt'>
       <div className='modalTxtContainner'>
-        {/* 墓志铭体制之变例 */}
-        {selectedTab !== 0 && (
-          <div className='extra' onClick={() => setIsOpenMzm(true)}>
-            <div className='icon'>
-              <img src={require('@/assets/img/tip.png')} alt='' />
-            </div>
-            <div className='txt'>墓志铭体制之变例</div>
-          </div>
-        )}
 
-        {isOpenMzm && (
-          <div className='mzm'>
-            <div className='top'>
-              <div className='title'>墓志铭体制之变例</div>
-              <div className='close' onClick={() => setIsOpenMzm(false)}>
-                <img
-                  src={require('@/assets/img/closeWithTxt.png')}
-                  alt=''
-                  onClick={() => setIsOpenMzm(false)}
-                />
-              </div>
-            </div>
-            <div
-              className='content'
-              dangerouslySetInnerHTML={{ __html: myData.mzmtz.content }}
-            ></div>
-          </div>
-        )}
 
         <div className='topBar'>
           <div className='beie'>
             <img src={require('@/assets/img/beie.png')} alt='' />
-            <div className='txt' onClick={() => history.push('/beie')}>
+            <div className='txt' onClick={handleBeie}>
               碑额
             </div>
           </div>
-          <div className='tab ' onClick={() => setSelectedTab(1)}>
+          <div className='tab ' onClick={() => handleTabClick(1)}>
             <img
               src={require(`@/assets/img/btn_ModalTxt_bg${selectedTab === 1 ? '_ac' : ''}.png`)}
               alt=''
@@ -191,7 +156,7 @@ function ModalTxt() {
               造碑人与碑主
             </div>
           </div>
-          <div className='tab ' onClick={() => setSelectedTab(2)}>
+          <div className='tab ' onClick={() => handleTabClick(2)}>
             <img
               src={require(`@/assets/img/btn_ModalTxt_bg${selectedTab === 2 ? '_ac' : ''}.png`)}
               alt=''
@@ -203,7 +168,7 @@ function ModalTxt() {
               程哲生平与家族世系
             </div>
           </div>
-          <div className='tab ' onClick={() => setSelectedTab(3)}>
+          <div className='tab ' onClick={() => handleTabClick(3)}>
             <img
               src={require(`@/assets/img/btn_ModalTxt_bg${selectedTab === 3 ? '_ac' : ''}.png`)}
               alt=''
@@ -218,7 +183,7 @@ function ModalTxt() {
         </div>
 
         <div className='intro' style={{ opacity: selectedTab !== 0 ? '1' : '0' }}>
-          第一部分列造碑人与碑主。列六位造碑人(程定宗、程文静、程海珍程盖世、程进、程庆仲等)和四位碑主(程钵、程蠡、程买、程哲)。
+          {selectedTab !== 0 && myData.readDetail[selectedTab - 1].intro}
         </div>
 
         {selectedTab !== 0 && (
@@ -227,14 +192,14 @@ function ModalTxt() {
               <div className='title'>原文</div>
               <div className='txt'>
                 {CommentText({
-                  str: myData.comment[selectedTab - 1].origin,
+                  str: myData.readDetail[selectedTab - 1].origin,
                   index: selectedTab - 1
                 })}
               </div>
             </div>
             <div className='right'>
               <div className='title'>译文</div>
-              <div className='txt'>{myData.comment[selectedTab - 1].translate}</div>
+              <div className='txt'>{myData.readDetail[selectedTab - 1].translate}</div>
             </div>
           </div>
         )}
@@ -243,11 +208,15 @@ function ModalTxt() {
           <div className='content'>
             <div className='title'>碑文概述</div>
             <div className='text'>
-              程哲碑碑文,
-              <br /> 31行楷书,满行45字,
-              <br /> 字径约2厘米,带方界格,总计1404字;
-              <br /> 未刻正式碑名。 <br />
-              通篇颂德程氏家族的历史功绩。
+              <p>碑额留出高约15厘米的空白范围,仅在碑额左侧题写造碑日期。《山
+                西通志》指出:其“碑额题‘大魏天平元年岁次甲寅十一月庚辰朔三日壬午造讫’
+                岁月书额,唐贞观晋祠铭以前,此为仅见”。
+              </p>
+              <p>
+                程哲碑碑文,31行楷书,满行45字,字径约2厘米,带方界格,总计
+                1404字;未刻正式碑名。通篇颂德程氏家族的历史功绩。
+              </p>
+
             </div>
           </div>
         )}

+ 165 - 3
src/pages/A2yblm/index.module.scss

@@ -44,7 +44,7 @@
       width: 60px;
       height: 30px;
       position: absolute;
-      z-index: 10;
+      z-index: 3;
       top: 3%;
       left: 4%;
       cursor: pointer;
@@ -58,7 +58,7 @@
       width: 60px;
       height: 60px;
       position: absolute;
-      z-index: 10;
+      z-index: 3;
       bottom: 3%;
       left: 4%;
       cursor: pointer;
@@ -73,7 +73,7 @@
       width: 50px;
       height: 50px;
       position: absolute;
-      z-index: 10;
+      z-index: 3;
       top: 3%;
       right: 3%;
       cursor: pointer;
@@ -83,11 +83,88 @@
       }
     }
 
+    .extra {
+      width: 110px;
+      height: 25px;
+      position: absolute;
+      z-index: 1;
+      bottom: 18%;
+      left: 4%;
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      background-color: rgba(0, 0, 0, 0.7);
+      border-radius: 15px;
+      padding: 0 8px;
+      cursor: pointer;
+      .icon {
+        width: 20px;
+        height: 20px;
+        & > img {
+          height: 100%;
+          object-fit: contain;
+        }
+      }
+
+      .txt {
+        width: fit-content;
+        font-size: 9px;
+        font-weight: 500;
+        color: #fbebbd;
+      }
+    }
+    .mzm {
+      width: 100%;
+      height: 100%;
+      position: absolute;
+      z-index: 1100;
+      top: 50%;
+      left: 50%;
+      transform: translate(-50%, -50%);
+      background-color: rgba(0, 0, 0, 0.7);
+      backdrop-filter: blur(3px);
+      display: flex;
+      flex-direction: column;
+      gap: 10px;
+      padding: 20px 55px;
+      .top {
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        width: 100%;
+        height: 50px;
+        .title {
+          font-size: 14px;
+          font-weight: 500;
+          color: #fbebbd;
+        }
+        .close {
+          width: 50px;
+          height: 50px;
+          cursor: pointer;
+          & > img {
+            height: 100%;
+            object-fit: contain;
+          }
+        }
+      }
+      .content {
+        font-size: 10px;
+        line-height: 15px;
+        font-weight: lighter;
+        color: rgba(255, 255, 255, 1);
+        & > p {
+          padding-bottom: 15px;
+        }
+      }
+    }
+
     // sider内容
     .sider1 {
       width: 35%;
       height: 100%;
       position: absolute;
+      z-index: 1;
       top: 50%;
       left: 50%;
       transform: translate(5%, -50%);
@@ -96,6 +173,7 @@
       width: 170px;
       height: 100%;
       position: absolute;
+      z-index: 1;
       top: 50%;
       left: 50%;
       transform: translate(120%, -50%);
@@ -104,6 +182,7 @@
       width: 100%;
       height: 100%;
       position: absolute;
+      z-index: 1;
       top: 50%;
       left: 50%;
       transform: translate(-50%, -50%);
@@ -161,6 +240,27 @@
             font-weight: 500;
             color: rgba(124, 75, 54, 1);
             cursor: pointer;
+            display: flex;
+            flex-direction: column;
+
+            .bottomLine {
+              position: relative;
+              bottom: 10px;
+              width: 100%;
+              height: 20px;
+              display: flex;
+              align-items: center;
+              justify-content: center;
+              & > img {
+                width: 60%;
+                height: 100%;
+                object-fit: contain;
+              }
+            }
+            .bottomLineAc {
+              bottom: 20px;
+              height: 30px;
+            }
           }
           .tab:nth-child(1) {
             color: #fbebbd;
@@ -200,5 +300,67 @@
         transform: translate(0, -50%);
       }
     }
+
+    // 图像赏析的tag
+    .tagInfo {
+      position: absolute;
+      z-index: 1;
+      top: 50%;
+      left: 50%;
+      transform: translate(-150%, -50%);
+      width: 200px;
+      height: 150px;
+      display: flex;
+      flex-direction: column;
+      justify-content: space-between;
+      .top {
+        width: 100%;
+        height: 30px;
+        display: flex;
+        align-items: center;
+
+        .title {
+          width: fit-content;
+          max-width: 105px;
+          height: 100%;
+          line-height: 30px;
+          font-size: 16px;
+          color: rgba(124, 75, 54, 1);
+          letter-spacing: 1px;
+          display: flex;
+          align-items: center;
+          gap: 2px;
+          .dot {
+            font-size: 5px;
+          }
+        }
+        .line {
+          width: 0;
+          flex: 1;
+          height: 1px;
+          border-top: 1px dashed rgba(124, 75, 54, 1);
+        }
+        .icon {
+          width: 15px;
+          height: 15px;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          & > img {
+            width: 100%;
+            height: 100%;
+            object-fit: contain;
+          }
+        }
+      }
+      .content {
+        width: 60%;
+        height: 110px;
+        font-size: 10px;
+        line-height: 15px;
+        color: rgba(124, 75, 54, 1);
+        text-indent: 2em;
+      }
+    }
   }
 }

+ 78 - 14
src/pages/A2yblm/index.tsx

@@ -1,25 +1,48 @@
-import React, { useState } from 'react'
+import React, { useState, useEffect } from 'react'
 import styles from './index.module.scss'
-import history, { backPageFu } from '@/utils/history'
+import history, { callIframeFu } from '@/utils/history'
 import Intro from '@/pages/A2yblm/components/Intro'
 import Detail from '@/pages/A2yblm/components/Detail'
 import ModalTxt from '@/pages/A2yblm/components/ModalTxt'
+import { myData } from '@/utils/http'
 function A2yblm() {
   const [currentTab, setCurrentTab] = useState('tab1')
   const [isShowMenu, setIsShowMenu] = useState(false)
+  const [isShowTabBar, setIsShowTabBar] = useState(true)
+  const [isShowMzmTitle, setIsShowMzmTitle] = useState(false)
+  const [isOpenMzm, setIsOpenMzm] = useState(false)
+  const [currentTagIndex, setCurrentTagIndex] = useState(1);
+  const [isShowTag, setIsShowTag] = useState(false)
 
   const gotoQuanwenOrWenwu = () => {
-    if (currentTab === 'tab3') history.push('/quanwen')
-    else history.push('/wenwu')
+    if (currentTab === 'tab3') window.location.replace('#/quanwen')
+    else window.location.replace('#/wenwu')
   }
 
   const gotoBack = () => {
     if (currentTab === 'tab3') setCurrentTab('tab1')
-    else history.push('/base')
+    else window.location.replace('#/base')
   }
+
+
+  // 退出图像赏析时调用showHotspot(-1) 退出碑文解读时调用showInscription(-1)
+  useEffect(() => {
+    if (currentTab === 'tab2') setIsShowTag(true);
+    if (currentTab !== 'tab2') {
+      setCurrentTagIndex(1);
+      setIsShowTag(false)
+      callIframeFu('showHotspot', -1);
+    }
+    if (currentTab !== 'tab3') {
+      setIsShowMzmTitle(false)
+      setIsShowTabBar(true)
+      callIframeFu('showInscription', -1)
+    }
+    callIframeFu('changePanel', currentTab === 'tab1' ? 1 : currentTab === 'tab2' ? 2 : 3)
+  }, [currentTab])
   return (
     <div className={styles.A2yblm}>
-      <div className='A2_tabBar'>
+      <div className='A2_tabBar' style={{ display: isShowTabBar ? 'flex' : 'none' }}>
         <div
           className={`tab ${currentTab === 'tab1' ? 'tab_active' : ''}`}
           onClick={() => setCurrentTab('tab1')}
@@ -56,7 +79,34 @@ function A2yblm() {
         <img src={require('@/assets/img/btn_menu.png')} alt='' />
       </div>
 
+      {/* 墓志铭体制之变例 */}
+      {isShowMzmTitle && (
+        <div className='extra' onClick={() => setIsOpenMzm(true)}>
+          <div className='icon'>
+            <img src={require('@/assets/img/tip.png')} alt='' />
+          </div>
+          <div className='txt'>墓志铭体制之变例</div>
+        </div>
+      )}
 
+      {isOpenMzm && (
+        <div className='mzm'>
+          <div className='top'>
+            <div className='title'>{myData.readDetail[Number(localStorage.getItem('selectedBeiwen')) ?? 0].mzmtz.title}</div>
+            <div className='close' onClick={() => setIsOpenMzm(false)}>
+              <img
+                src={require('@/assets/img/closeWithTxt.png')}
+                alt=''
+                onClick={() => setIsOpenMzm(false)}
+              />
+            </div>
+          </div>
+          <div
+            className='content'
+            dangerouslySetInnerHTML={{ __html: myData.readDetail[Number(localStorage.getItem('selectedBeiwen')) ?? 0].mzmtz.content }}
+          ></div>
+        </div>
+      )}
 
 
       {/* sider内容 */}
@@ -67,12 +117,12 @@ function A2yblm() {
       )}
       {currentTab === 'tab2' && (
         <div className='sider2'>
-          <Detail />
+          <Detail currentTagIndex={currentTagIndex} setCurrentTagIndex={setCurrentTagIndex} setIsShowTag={setIsShowTag} />
         </div>
       )}
       {currentTab === 'tab3' && (
 
-        <ModalTxt />
+        <ModalTxt setIsShowTabBar={setIsShowTabBar} setIsShowMzmTitle={setIsShowMzmTitle} />
 
       )}
 
@@ -85,14 +135,17 @@ function A2yblm() {
             alt=''
           />
           <div className='siderContent'>
-            <div className='tab' onClick={() => history.push('/yblm')}>
-              一碑两面
+            <div className='tab' onClick={() => window.location.replace('#/yblm')}>
+              <div className="txt">一碑两面</div>
+              <div className="bottomLine bottomLineAc"><img src={require('@/assets/img/menu_item_ac.png')} alt="" /></div>
             </div>
-            <div className='tab' onClick={() => history.push('/base')}>
-              一碑万象
+            <div className='tab' onClick={() => window.location.replace('#/ybwx')}>
+              <div className="txt">一碑万象</div>
+              <div className="bottomLine"><img src={require('@/assets/img/menu_item.png')} alt="" /></div>
             </div>
-            <div className='tab' onClick={() => history.push('/base')}>
-              无尽未竟
+            <div className='tab' onClick={() => window.location.replace('#/wjwj')}>
+              <div className="txt">无尽未竟</div>
+              <div className="bottomLine"><img src={require('@/assets/img/menu_item.png')} alt="" /></div>
             </div>
             <div className='icon'>
               <div className='paint'>
@@ -111,6 +164,17 @@ function A2yblm() {
           </div>
         </div>
       </div>
+
+      {/* 图像赏析的tag */}
+      <div className="tagInfo" style={{ display: isShowTag ? 'flex' : 'none' }}>
+        <div className="top">
+          <div className="title"><div className="dot">●</div>{currentTagIndex >= myData.detail_modal.top.length ? myData.detail_modal.bottom[currentTagIndex - myData.detail_modal.top.length].title : myData.detail_modal.top[currentTagIndex].title}<div className="dot">●</div></div>
+          <div className="line"></div>
+          <div className="icon"><img src={require('@/assets/img/icon_dot2.png')} alt="" /></div>
+        </div>
+        <div className="content">{currentTagIndex >= myData.detail_modal.top.length ? myData.detail_modal.bottom[currentTagIndex - myData.detail_modal.top.length].txt : myData.detail_modal.top[currentTagIndex].txt}</div>
+
+      </div>
     </div>
   )
 }

+ 5 - 1
src/pages/A3beie/index.module.scss

@@ -2,12 +2,12 @@
   width: 100%;
   height: 100%;
   position: relative;
-  background-color: #ccc;
   :global {
     .container {
       width: 350px;
       height: 100%;
       position: absolute;
+      z-index: 1;
       top: 50%;
       left: 50%;
       transform: translate(-5%, -50%);
@@ -49,6 +49,7 @@
       width: 60px;
       height: 30px;
       position: absolute;
+      z-index: 1;
       top: 3%;
       left: 4%;
       cursor: pointer;
@@ -62,8 +63,10 @@
       width: 60px;
       height: 60px;
       position: absolute;
+      z-index: 1;
       bottom: 3%;
       left: 4%;
+      cursor: pointer;
       & > img {
         height: 100%;
         object-fit: contain;
@@ -75,6 +78,7 @@
       width: 50px;
       height: 50px;
       position: absolute;
+      z-index: 1;
       top: 3%;
       right: 3%;
       & > img {

+ 13 - 3
src/pages/A3beie/index.tsx

@@ -1,13 +1,23 @@
 import React from 'react'
 import styles from './index.module.scss'
-import { backPageFu } from '@/utils/history'
+import history, { backPageFu, callIframeFu } from '@/utils/history'
 function A3beie() {
+  const handleBack = () => {
+    backPageFu('#/yblm')
+    callIframeFu('showInscription', -1)
+  }
+
+  const gotoQuanwen = () => {
+    window.location.replace('#/quanwen')
+    callIframeFu('showInscription', 10)
+  }
+
   return (
     <div className={styles.A3beie}>
-      <div className='back' onClick={() => backPageFu('/yblm')}>
+      <div className='back' onClick={() => handleBack()}>
         <img src={require('@/assets/img/btn_back.png')} alt='' />
       </div>
-      <div className='wenwu'>
+      <div className='wenwu' onClick={() => gotoQuanwen()}>
         <img src={require('@/assets/img/A2_quanwen.png')} alt='' />
       </div>
       <div className='menu'>

+ 4 - 1
src/pages/A4quanwen/index.module.scss

@@ -2,7 +2,6 @@
   width: 100%;
   height: 100%;
   position: relative;
-  background-color: #ccc;
   display: flex;
   align-items: center;
   justify-content: end;
@@ -11,6 +10,7 @@
       width: 60px;
       height: 30px;
       position: absolute;
+      z-index: 1;
       top: 3%;
       left: 4%;
       cursor: pointer;
@@ -23,6 +23,7 @@
       width: 25px;
       height: 25px;
       position: absolute;
+      z-index: 1;
       bottom: 3%;
       left: 2%;
       cursor: pointer;
@@ -33,6 +34,8 @@
     }
 
     .txtContent {
+      position: relative;
+      z-index: 1;
       width: 50%;
       height: 100%;
       padding: 20px 30px;

+ 22 - 5
src/pages/A4quanwen/index.tsx

@@ -1,16 +1,33 @@
-import React, { useState } from "react";
+import React, { useState, useEffect } from "react";
 import styles from "./index.module.scss";
-import { backPageFu } from "@/utils/history";
+import { backPageFu, callIframeFu } from "@/utils/history";
 import { myData } from "@/utils/http";
 function A4quanwen() {
-  const [isHighlight, setIsHighlight] = useState(false)
+  const [isHighlight, setIsHighlight] = useState(true);
+  useEffect(() => {
+    callIframeFu('showInscription', 10)
+    callIframeFu('openHightlight', isHighlight ? 1 : 0)
+    // eslint-disable-next-line react-hooks/exhaustive-deps
+  }, [])
+
+  const handleHighlight = () => {
+    setIsHighlight(!isHighlight)
+    callIframeFu('openHightlight', isHighlight ? 0 : 1)
+  }
+
+  const gotoBack = () => {
+    backPageFu('#/yblm')
+    callIframeFu('openHightlight', 1)
+  }
+
+
   return (
     <div className={styles.A4quanwen}>
-      <div className='back' onClick={() => backPageFu('/yblm')}>
+      <div className='back' onClick={() => gotoBack()}>
         <img src={require('@/assets/img/btn_back.png')} alt='' />
       </div>
 
-      <div className={`highlight`} onClick={() => setIsHighlight(!isHighlight)}>
+      <div className={`highlight`} onClick={() => handleHighlight()}>
         <img src={require(`@/assets/img/${isHighlight ? 'highlight_ac.png' : 'highlight.png'}`)} alt='' />
       </div>
 

+ 5 - 3
src/pages/A5wenwu/index.module.scss

@@ -2,12 +2,12 @@
   width: 100%;
   height: 100%;
   position: relative;
-  background-color: #ccc;
   :global {
     .back {
       width: 60px;
       height: 30px;
       position: absolute;
+      z-index: 1;
       top: 3%;
       left: 4%;
       cursor: pointer;
@@ -21,14 +21,14 @@
       width: 120px;
       height: 70px;
       position: absolute;
+      z-index: 1;
       top: 50%;
       left: 50%;
-      transform: translate(100%, -50%);
+      transform: translate(120%, -50%);
       display: flex;
       align-items: center;
       justify-content: center;
       flex-direction: column;
-      cursor: pointer;
       & > img {
         width: 100%;
         object-fit: contain;
@@ -51,6 +51,7 @@
       align-items: center;
       flex-direction: column;
       position: absolute;
+      z-index: 1;
       top: 50%;
       left: 5%;
       gap: 20px;
@@ -88,6 +89,7 @@
       align-items: center;
       flex-direction: column;
       position: absolute;
+      z-index: 1;
       top: 50%;
       right: 5%;
       transform: translateY(-50%);

+ 58 - 12
src/pages/A5wenwu/index.tsx

@@ -1,37 +1,83 @@
-import React, { useState } from 'react'
+import React, { useEffect, useState } from 'react'
 import styles from './index.module.scss'
-import { backPageFu } from '@/utils/history'
+import { backPageFu, callIframeFu } from '@/utils/history'
 
 function A5wenwu() {
-  const [currentTab, setCurrentTab] = useState('tab1')
+  const [currentTab, setCurrentTab] = useState('tab0')
+  const [isShowGesture, setIsShowGesture] = useState(true)
+
+  useEffect(() => {
+    setIsShowGesture(true)
+  }, [])
+
+  const handleTabClick = (tab: string) => {
+    if (currentTab === tab) setCurrentTab('tab0')
+    else setCurrentTab(tab)
+  }
+
+  const handleSize = () => {
+    handleTabClick('tab1')
+    callIframeFu('showSize', undefined)
+  }
+
+  const handleTapian = () => {
+    handleTabClick('tab2')
+    callIframeFu('hideSize', undefined)
+    console.log('showTapian');
+  }
+
+  const handleLine = () => {
+    handleTabClick('tab3')
+    callIframeFu('hideSize', undefined)
+    console.log('showLine');
+  }
+
+  const handleZoomIn = (value: number) => {
+    callIframeFu('addModelScale', value)
+  }
+  const handleZoomOut = (value: number) => {
+    callIframeFu('addModelScale', -value)
+  }
+  const handleReset = () => {
+    callIframeFu('resetModel', undefined)
+  }
+
+  const gotoBack = () => {
+    backPageFu('#/yblm')
+    callIframeFu('hideSize', undefined)
+  }
+
+  window.hideGesture = () => {
+    setIsShowGesture(false)
+  }
   return (
     <div className={styles.A5wenwu}>
-      <div className='back' onClick={() => backPageFu('/yblm')}>
+      <div className='back' onClick={gotoBack}>
         <img src={require('@/assets/img/btn_back.png')} alt='' />
       </div>
 
-      <div className="gesture">
+      {isShowGesture && <div className="gesture">
         <img src={require('@/assets/img/A5_gesture.png')} alt="" />
         <div className="txt">单指滑动进行旋转</div>
-      </div>
+      </div>}
 
       {/* 左边 */}
       <div className='A5_tabBar'>
-        <div className={`tab`} onClick={() => setCurrentTab('tab1')}>
+        <div className={`tab`} onClick={handleSize}>
           <img
             src={require(`@/assets/img/A5_size${currentTab === 'tab1' ? 'Ac' : ''}.png`)}
             alt=''
           />
           <div className='txt'>尺寸</div>
         </div>
-        <div className={`tab`} onClick={() => setCurrentTab('tab2')}>
+        <div className={`tab`} onClick={handleTapian}>
           <img
             src={require(`@/assets/img/A5_tapian${currentTab === 'tab2' ? 'Ac' : ''}.png`)}
             alt=''
           />
           <div className='txt'>拓片</div>
         </div>
-        <div className={`tab`} onClick={() => setCurrentTab('tab3')}>
+        <div className={`tab`} onClick={handleLine}>
           <img
             src={require(`@/assets/img/A5_line${currentTab === 'tab3' ? 'Ac' : ''}.png`)}
             alt=''
@@ -42,15 +88,15 @@ function A5wenwu() {
 
       {/* 右边 */}
       <div className='A5_tabBarR'>
-        <div className={`tab`}>
+        <div className={`tab`} onClick={() => handleZoomIn(0.1)}>
           <img src={require(`@/assets/img/A5_zoomin.png`)} alt='' />
           <div className='txt'>放大</div>
         </div>
-        <div className={`tab`}>
+        <div className={`tab`} onClick={() => handleZoomOut(0.1)}>
           <img src={require(`@/assets/img/A5_zoomout.png`)} alt='' />
           <div className='txt'>缩小</div>
         </div>
-        <div className={`tab`}>
+        <div className={`tab`} onClick={handleReset}>
           <img src={require(`@/assets/img/A5_reset.png`)} alt='' />
           <div className='txt'>重置</div>
         </div>

+ 48 - 0
src/pages/A6ybwx/index.module.scss

@@ -0,0 +1,48 @@
+.A6ybwx {
+  width: 100%;
+  height: 100%;
+  position: relative;
+  z-index: 1;
+  :global {
+    .videoBox {
+      width: 100%;
+      height: 100%;
+      position: relative;
+      .back {
+        width: 60px;
+        height: 30px;
+        position: absolute;
+        z-index: 3;
+        top: 3%;
+        left: 4%;
+        cursor: pointer;
+        & > img {
+          height: 100%;
+          object-fit: contain;
+        }
+      }
+      .A6video {
+        width: 100%;
+        height: 100%;
+      }
+      .enterBtn {
+        position: absolute;
+        bottom: 0;
+        left: 50%;
+        transform: translateX(-50%);
+        width: 150px;
+        height: 35px;
+        cursor: pointer;
+      }
+      iframe {
+        position: absolute;
+        z-index: -1;
+        top: 0;
+        left: 0;
+        width: 100%;
+        height: 100%;
+        border: none;
+      }
+    }
+  }
+}

+ 58 - 0
src/pages/A6ybwx/index.tsx

@@ -0,0 +1,58 @@
+import React, { useState, useEffect, useRef } from "react";
+import styles from "./index.module.scss";
+import history from "@/utils/history";
+function A6ybwx() {
+  const [isShowBtn, setIsShowBtn] = useState(false);
+  const [isEnter, setIsEnter] = useState(false)
+  const [videoOk, setVideoOk] = useState(false)
+  const playerRef = useRef<any>(null)
+  useEffect(() => {
+    const params = {
+      objectFit: 'cover', // 视频的object-fit样式, 默认 cover
+      loop: false, // 是否循环, 默认false
+      autoplay: false, // 自动播放, 默认false
+      onPlay: () => { }, // 触发播放事件
+      onPause: () => { }, // 触发暂停事件
+      onEnded: () => {
+        setIsShowBtn(true)
+      }, // 触发播放结束事件
+      onSourceEstablished: () => {
+        setVideoOk(true)
+      } //有足够的数据可以播放了
+    }
+    playerRef.current = F_Video('./myData/ybwx.ts', params)
+    const dom = document.querySelector('.A6video')!
+    dom.append(playerRef.current.domElement)
+  }, [])
+
+  const timeRR = useRef(-1)
+  useEffect(() => {
+    if (videoOk) {
+      clearInterval(timeRR.current)
+      timeRR.current = window.setInterval(() => {
+        console.log('播放视频')
+        playerRef.current.play()
+        clearInterval(timeRR.current)
+        return
+      }, 50)
+    }
+  }, [videoOk])
+
+  return (
+    <div className={styles.A6ybwx}>
+      <div className="videoBox">
+        <div className='back' onClick={() => window.location.replace('#/base')}>
+          <img src={require('@/assets/img/btn_back.png')} alt='' />
+        </div>
+        {/* ------------微信浏览器不让视频自动播放,用ts的方式*/}
+        <div className='A6video' style={{ opacity: 1 }}></div>
+        {isShowBtn && <div className="enterBtn" onClick={() => { setIsEnter(true); setIsShowBtn(false) }}></div>}
+        <iframe style={{ zIndex: isEnter ? 2 : -1 }} title="A6ybwx" src="https://app.4dage.com/projects/Chenzhebei-ShanxiMuseum/RoomScene/index.html" />
+      </div>
+    </div>
+  )
+}
+
+const MemoA6ybwx = React.memo(A6ybwx);
+
+export default MemoA6ybwx;

+ 20 - 0
src/pages/A7wjwj/index.module.scss

@@ -0,0 +1,20 @@
+.A7Wjwj {
+  position: relative;
+  width: 100%;
+  height: 100%;
+  :global {
+    .back {
+      width: 60px;
+      height: 30px;
+      position: absolute;
+      z-index: 3;
+      top: 3%;
+      left: 4%;
+      cursor: pointer;
+      & > img {
+        height: 100%;
+        object-fit: contain;
+      }
+    }
+  }
+}

+ 26 - 0
src/pages/A7wjwj/index.tsx

@@ -0,0 +1,26 @@
+import React, { useEffect } from "react";
+import styles from "./index.module.scss";
+import history from "@/utils/history";
+function A7Wjwj() {
+  useEffect(() => {
+    const A7Back = document.getElementById('A7Back') as HTMLElement
+    const wjwjScene = document.getElementById('wjwjScene') as HTMLIFrameElement
+    wjwjScene.style.display = 'block'
+    wjwjScene.src = 'https://www.4dkankan.com/spg.html?m=SG-Oy6fyzoMQ0D&lang=zh'
+
+    A7Back.style.display = 'block'
+    A7Back.onclick = () => {
+      wjwjScene.style.display = 'none'
+      A7Back.style.display = 'none'
+      window.location.replace('#/base')
+    }
+  })
+  return (
+    <div className={styles.A7Wjwj}>
+    </div>
+  )
+}
+
+const MemoA7Wjwj = React.memo(A7Wjwj);
+
+export default MemoA7Wjwj;

+ 4 - 4
src/types/declaration.d.ts

@@ -22,11 +22,11 @@ declare const F_Video: any
 type MyDataType = {
   isLdong: boolean
   baseInfo: { title: string; text: string; path: string }[]
+  introInfo: { title: string; text: string }[]
   detail_modal: {
-    top: { title: string }[]
-    bottom: { title: string }[]
+    top: { title: string; txt: string }[]
+    bottom: { title: string; txt: string }[]
   }
   allTxt: { title: string }[]
-  mzmtz: { content: string }
-  comment: { words: { name: string; define: string }[]; origin: string; translate: string } []
+  readDetail: { words: { name: string; define: string }[]; intro: string; mzmtz: { title: string; content: string }; origin: string; translate: string }[]
 }

+ 6 - 1
src/types/function.d.ts

@@ -1,7 +1,12 @@
 // 全局方法
 declare global {
   interface Window {
-    LoadingProgress: (progress: number) =>  void
+    WjwjScene: boolean
+    unityLoading: (progress: number) =>  void
+    showTag: () => void
+    hideTag: () => void
+    changePanel: (index: number) => void
+    hideGesture: () => void
   }
 }
 

+ 30 - 6
src/utils/history.ts

@@ -1,12 +1,14 @@
-import { createHashHistory  } from 'history'
+import { createHashHistory } from 'history'
 const history = createHashHistory()
 export default history
 
 // 判断是手机端还是pc端
 export const isMobiileFu = () => {
-  if (window.navigator.userAgent.match(
-    /(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i
-  )) {
+  if (
+    window.navigator.userAgent.match(
+      /(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i
+    )
+  ) {
     return true
   } else return false
 }
@@ -24,5 +26,27 @@ history.listen((_: any, listener: any) => {
 // 点击返回
 export const backPageFu = (path: string) => {
   if (routerLength) history.go(-1)
-  else history.push(path)
-}
+  else window.location.replace(path)
+}
+
+// 调用iframe方法
+export const callIframeFu = (fuName: string, params: any) => {
+  const dom = document.getElementById('modalIframe') as HTMLIFrameElement | null;
+  const iframeWindow = dom?.contentWindow as Window & { [key: string]: (...args: any[]) => void } | undefined;
+  if (iframeWindow && typeof iframeWindow[fuName] === 'function') {
+    if (params === 0) {
+      // 直接传递 0(参数为 0 时执行)
+      iframeWindow[fuName](params);
+    } else if (params === undefined || params === null) {
+      // 参数为 undefined/null 时,使用默认空对象并调用方法
+      iframeWindow[fuName]({});
+    } else {
+      // 其他参数直接传递
+      iframeWindow[fuName](params);
+    }
+    // 修复日志显示:直接打印 params,避免 0 被 || '' 转换为空字符串
+    console.log(`执行了方法: ${fuName}(${params})`);
+  } else {
+    console.warn(`iframe 方法调用失败: 方法不存在或 iframe 未加载`);
+  }
+};

+ 1 - 4
src/utils/http.ts

@@ -1,6 +1,5 @@
-import { HotInfoType } from '@/components/Zhot/type'
 
-export const isLoc = process.env.NODE_ENV === 'development'
+export const isLoc = false
 
 export const baseURL = isLoc ? baseUrlLoc : baseUrlAtl
 
@@ -13,8 +12,6 @@ export const isPc = isPcTemp
 // 全景视频/全景图/unity场景资源地址
 export const otherUrl = otherUrlTemp
 
-// 重新梳理的热点信息
-export const hotInfo: HotInfoType = myHotInfo
 
 // 发送请求基地址
 export const apiUrl: string = apiUrlTemp

+ 31 - 0
src/utils/reactToHtml.tsx

@@ -0,0 +1,31 @@
+// 文件名:reactToHtml.tsx(必须是 tsx 后缀)
+import React, { ReactElement, useEffect } from 'react';
+import { createRoot } from 'react-dom/client';
+
+/**
+ * 极简版:仅客户端可用的 React 组件转 HTML
+ * 自动跳过服务端执行,避免 SSR 警告/错误
+ */
+export function reactToHtml(component: ReactElement): Promise<string> {
+  return new Promise((resolve, reject) => {
+    // 关键:判断是否是浏览器环境(服务端无 window/document)
+    if (typeof window === 'undefined' || typeof document === 'undefined') {
+      reject(new Error('reactToHtml 仅支持浏览器客户端执行'));
+      return;
+    }
+
+    const tempContainer = document.createElement('div');
+    const root = createRoot(tempContainer);
+
+    const RenderWrapper = () => {
+      useEffect(() => {
+        resolve(tempContainer.innerHTML);
+        root.unmount();
+        tempContainer.remove();
+      }, []);
+      return component;
+    };
+
+    root.render(<RenderWrapper />);
+  });
+}

+ 1 - 1
tsconfig.json

@@ -1,7 +1,7 @@
 {
   "extends": "./path.tsconfig.json",
   "compilerOptions": {
-    "target": "es5",
+    "target": "es2015",  
     "lib": [
       "dom",
       "dom.iterable",

+ 138 - 77
yarn.lock

@@ -1299,17 +1299,25 @@
     minimatch "^3.1.2"
     strip-json-comments "^3.1.1"
 
-"@floating-ui/core@^1.3.0":
-  version "1.3.0"
-  resolved "https://registry.npmmirror.com/@floating-ui/core/-/core-1.3.0.tgz"
-  integrity sha512-vX1WVAdPjZg9DkDkC+zEx/tKtnST6/qcNpwcjeBgco3XRNHz5PUA+ivi/yr6G3o0kMR60uKBJcfOdfzOFI7PMQ==
+"@floating-ui/core@^1.7.3":
+  version "1.7.3"
+  resolved "https://registry.npmmirror.com/@floating-ui/core/-/core-1.7.3.tgz#462d722f001e23e46d86fd2bd0d21b7693ccb8b7"
+  integrity sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==
+  dependencies:
+    "@floating-ui/utils" "^0.2.10"
 
-"@floating-ui/dom@^1.2.6":
-  version "1.3.0"
-  resolved "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.3.0.tgz"
-  integrity sha512-qIAwejE3r6NeA107u4ELDKkH8+VtgRKdXqtSPaKflL2S2V+doyN+Wt9s5oHKXPDo4E8TaVXaHT3+6BbagH31xw==
+"@floating-ui/dom@^1.4.2":
+  version "1.7.4"
+  resolved "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.7.4.tgz#ee667549998745c9c3e3e84683b909c31d6c9a77"
+  integrity sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==
   dependencies:
-    "@floating-ui/core" "^1.3.0"
+    "@floating-ui/core" "^1.7.3"
+    "@floating-ui/utils" "^0.2.10"
+
+"@floating-ui/utils@^0.2.10":
+  version "0.2.10"
+  resolved "https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.2.10.tgz#a2a1e3812d14525f725d011a73eceb41fef5bc1c"
+  integrity sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==
 
 "@humanwhocodes/config-array@^0.11.6":
   version "0.11.7"
@@ -1677,6 +1685,13 @@
   dependencies:
     "@babel/runtime" "^7.18.0"
 
+"@rc-component/mini-decimal@^1.1.0":
+  version "1.1.0"
+  resolved "https://registry.npmmirror.com/@rc-component/mini-decimal/-/mini-decimal-1.1.0.tgz#7b7a362b14a0a54cb5bc6fd2b82731f29f11d9b0"
+  integrity sha512-jS4E7T9Li2GuYwI6PyiVXmxTiM6b07rlD9Ge8uGZSCz3WlzcG5ZK7g5bbuKNeZ9pgUuPK/5guV781ujdVpm4HQ==
+  dependencies:
+    "@babel/runtime" "^7.18.0"
+
 "@rc-component/mutate-observer@^1.0.0":
   version "1.1.0"
   resolved "https://registry.npmmirror.com/@rc-component/mutate-observer/-/mutate-observer-1.1.0.tgz"
@@ -1721,7 +1736,7 @@
 
 "@react-spring/animated@~9.6.1":
   version "9.6.1"
-  resolved "https://registry.npmmirror.com/@react-spring/animated/-/animated-9.6.1.tgz"
+  resolved "https://registry.npmmirror.com/@react-spring/animated/-/animated-9.6.1.tgz#ccc626d847cbe346f5f8815d0928183c647eb425"
   integrity sha512-ls/rJBrAqiAYozjLo5EPPLLOb1LM0lNVQcXODTC1SMtS6DbuBCPaKco5svFUQFMP2dso3O+qcC4k9FsKc0KxMQ==
   dependencies:
     "@react-spring/shared" "~9.6.1"
@@ -1729,7 +1744,7 @@
 
 "@react-spring/core@~9.6.1":
   version "9.6.1"
-  resolved "https://registry.npmmirror.com/@react-spring/core/-/core-9.6.1.tgz"
+  resolved "https://registry.npmmirror.com/@react-spring/core/-/core-9.6.1.tgz#ebe07c20682b360b06af116ea24e2b609e778c10"
   integrity sha512-3HAAinAyCPessyQNNXe5W0OHzRfa8Yo5P748paPcmMowZ/4sMfaZ2ZB6e5x5khQI8NusOHj8nquoutd6FRY5WQ==
   dependencies:
     "@react-spring/animated" "~9.6.1"
@@ -1739,12 +1754,12 @@
 
 "@react-spring/rafz@~9.6.1":
   version "9.6.1"
-  resolved "https://registry.npmmirror.com/@react-spring/rafz/-/rafz-9.6.1.tgz"
+  resolved "https://registry.npmmirror.com/@react-spring/rafz/-/rafz-9.6.1.tgz#d71aafb92b78b24e4ff84639f52745afc285c38d"
   integrity sha512-v6qbgNRpztJFFfSE3e2W1Uz+g8KnIBs6SmzCzcVVF61GdGfGOuBrbjIcp+nUz301awVmREKi4eMQb2Ab2gGgyQ==
 
 "@react-spring/shared@~9.6.1":
   version "9.6.1"
-  resolved "https://registry.npmmirror.com/@react-spring/shared/-/shared-9.6.1.tgz"
+  resolved "https://registry.npmmirror.com/@react-spring/shared/-/shared-9.6.1.tgz#4e2e4296910656c02bd9fd54c559702bc836ac4e"
   integrity sha512-PBFBXabxFEuF8enNLkVqMC9h5uLRBo6GQhRMQT/nRTnemVENimgRd+0ZT4yFnAQ0AxWNiJfX3qux+bW2LbG6Bw==
   dependencies:
     "@react-spring/rafz" "~9.6.1"
@@ -1752,12 +1767,12 @@
 
 "@react-spring/types@~9.6.1":
   version "9.6.1"
-  resolved "https://registry.npmmirror.com/@react-spring/types/-/types-9.6.1.tgz"
+  resolved "https://registry.npmmirror.com/@react-spring/types/-/types-9.6.1.tgz#913d3a68c5cbc1124fdb18eff919432f7b6abdde"
   integrity sha512-POu8Mk0hIU3lRXB3bGIGe4VHIwwDsQyoD1F394OK7STTiX9w4dG3cTLljjYswkQN+hDSHRrj4O36kuVa7KPU8Q==
 
 "@react-spring/web@~9.6.1":
   version "9.6.1"
-  resolved "https://registry.npmmirror.com/@react-spring/web/-/web-9.6.1.tgz"
+  resolved "https://registry.npmmirror.com/@react-spring/web/-/web-9.6.1.tgz#3e4c03b724d2b545dc2fa2649eb6109318ab9178"
   integrity sha512-X2zR6q2Z+FjsWfGAmAXlQaoUHbPmfuCaXpuM6TcwXPpLE1ZD4A1eys/wpXboFQmDkjnrlTmKvpVna1MjWpZ5Hw==
   dependencies:
     "@react-spring/animated" "~9.6.1"
@@ -2178,10 +2193,10 @@
     jest-matcher-utils "^27.0.0"
     pretty-format "^27.0.0"
 
-"@types/js-cookie@^2.x.x":
-  version "2.2.7"
-  resolved "https://registry.npmmirror.com/@types/js-cookie/-/js-cookie-2.2.7.tgz"
-  integrity sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA==
+"@types/js-cookie@^3.0.6":
+  version "3.0.6"
+  resolved "https://registry.npmmirror.com/@types/js-cookie/-/js-cookie-3.0.6.tgz#a04ca19e877687bd449f5ad37d33b104b71fdf95"
+  integrity sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==
 
 "@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9":
   version "7.0.11"
@@ -2447,17 +2462,17 @@
     "@typescript-eslint/types" "5.41.0"
     eslint-visitor-keys "^3.3.0"
 
-"@use-gesture/core@10.2.20":
-  version "10.2.20"
-  resolved "https://registry.npmmirror.com/@use-gesture/core/-/core-10.2.20.tgz"
-  integrity sha512-4lFhHc8so4yIHkBEs641DnEsBxPyhJ5GEjB4PURFDH4p/FcZriH6w99knZgI63zN/MBFfylMyb8+PDuj6RIXKQ==
+"@use-gesture/core@10.3.0":
+  version "10.3.0"
+  resolved "https://registry.npmmirror.com/@use-gesture/core/-/core-10.3.0.tgz#9afd3777a45b2a08990a5dcfcf8d9ddd55b00db9"
+  integrity sha512-rh+6MND31zfHcy9VU3dOZCqGY511lvGcfyJenN4cWZe0u1BH6brBpBddLVXhF2r4BMqWbvxfsbL7D287thJU2A==
 
-"@use-gesture/react@10.2.20":
-  version "10.2.20"
-  resolved "https://registry.npmmirror.com/@use-gesture/react/-/react-10.2.20.tgz"
-  integrity sha512-KnJq9ZSqprWA6uNhWTUHZqTCh+rfa0j8ehTzqeBhktUPrmTj7yVOBvEQ/vSFU/7d72cGgWSsJ0f5T6GQCHXnvg==
+"@use-gesture/react@10.3.0":
+  version "10.3.0"
+  resolved "https://registry.npmmirror.com/@use-gesture/react/-/react-10.3.0.tgz#180534c821fd635c2853cbcfa813f92c94f27e3f"
+  integrity sha512-3zc+Ve99z4usVP6l9knYVbVnZgfqhKah7sIG+PS2w+vpig2v2OLct05vs+ZXMzwxdNCMka8B+8WlOo0z6Pn6DA==
   dependencies:
-    "@use-gesture/core" "10.2.20"
+    "@use-gesture/core" "10.3.0"
 
 "@webassemblyjs/ast@1.11.1":
   version "1.11.1"
@@ -2665,23 +2680,18 @@ agent-base@6:
   dependencies:
     debug "4"
 
-ahooks-v3-count@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.npmmirror.com/ahooks-v3-count/-/ahooks-v3-count-1.0.0.tgz"
-  integrity sha512-V7uUvAwnimu6eh/PED4mCDjE7tokeZQLKlxg9lCTMPhN+NjsSbtdacByVlR1oluXQzD3MOw55wylDmQo4+S9ZQ==
-
 ahooks@^3.7.6:
-  version "3.7.7"
-  resolved "https://registry.npmmirror.com/ahooks/-/ahooks-3.7.7.tgz"
-  integrity sha512-5e5WlPq81Y84UnTLOKIQeq2cJw4aa7yj8fR2Nb/oMmXPrWMjIMCbPS1o+fpxSfCaNA3AzOnnMc8AehWRZltkJQ==
+  version "3.9.6"
+  resolved "https://registry.npmmirror.com/ahooks/-/ahooks-3.9.6.tgz#c93b8f826266d07cada40439be8865d55733fb19"
+  integrity sha512-Mr7f05swd5SmKlR9SZo5U6M0LsL4ErweLzpdgXjA1JPmnZ78Vr6wzx0jUtvoxrcqGKYnX0Yjc02iEASVxHFPjQ==
   dependencies:
     "@babel/runtime" "^7.21.0"
-    "@types/js-cookie" "^2.x.x"
-    ahooks-v3-count "^1.0.0"
+    "@types/js-cookie" "^3.0.6"
     dayjs "^1.9.1"
     intersection-observer "^0.12.0"
-    js-cookie "^2.x.x"
+    js-cookie "^3.0.5"
     lodash "^4.17.21"
+    react-fast-compare "^3.2.2"
     resize-observer-polyfill "^1.5.1"
     screenfull "^5.0.0"
     tslib "^2.4.1"
@@ -2768,31 +2778,34 @@ ansi-styles@^5.0.0:
 
 antd-mobile-icons@^0.3.0:
   version "0.3.0"
-  resolved "https://registry.npmmirror.com/antd-mobile-icons/-/antd-mobile-icons-0.3.0.tgz"
+  resolved "https://registry.npmmirror.com/antd-mobile-icons/-/antd-mobile-icons-0.3.0.tgz#9b29e4588a62370909061f10ff0579aabb0b32a9"
   integrity sha512-rqINQpJWZWrva9moCd1Ye695MZYWmqLPE+bY8d2xLRy7iSQwPsinCdZYjpUPp2zL/LnKYSyXxP2ut2A+DC+whQ==
 
 antd-mobile-v5-count@^1.0.1:
   version "1.0.1"
-  resolved "https://registry.npmmirror.com/antd-mobile-v5-count/-/antd-mobile-v5-count-1.0.1.tgz"
+  resolved "https://registry.npmmirror.com/antd-mobile-v5-count/-/antd-mobile-v5-count-1.0.1.tgz#85f20c46d1635c24e856bcf5ad55e8c98e44a523"
   integrity sha512-YGsiEDCPUDz3SzfXi6gLZn/HpeSMW+jgPc4qiYUr1fSopg3hkUie2TnooJdExgfiETHefH3Ggs58He0OVfegLA==
 
 antd-mobile@^5.30.0:
-  version "5.30.0"
-  resolved "https://registry.npmmirror.com/antd-mobile/-/antd-mobile-5.30.0.tgz"
-  integrity sha512-M42VrDvFNzTr1OovLa9HezkD2oXmkDERolha9292FNNTvF1QikIcLZA/o1PDP9+0oWvuz59PW1ZfhjTNx6rUyg==
+  version "5.41.1"
+  resolved "https://registry.npmmirror.com/antd-mobile/-/antd-mobile-5.41.1.tgz#77053503436c4576b140b1170454b38efa211d48"
+  integrity sha512-fS5sTRLKHca5qryEYLGiPDLANK0rbhx8f8xk0Olu6ef00tLe0P9iqHQm0U3UtEBd8S454cilw5uv2J3I79Tbgg==
   dependencies:
-    "@floating-ui/dom" "^1.2.6"
-    "@rc-component/mini-decimal" "^1.0.1"
+    "@floating-ui/dom" "^1.4.2"
+    "@rc-component/mini-decimal" "^1.1.0"
     "@react-spring/web" "~9.6.1"
-    "@use-gesture/react" "10.2.20"
+    "@use-gesture/react" "10.3.0"
     ahooks "^3.7.6"
     antd-mobile-icons "^0.3.0"
     antd-mobile-v5-count "^1.0.1"
     classnames "^2.3.2"
     dayjs "^1.11.7"
-    lodash "^4.17.21"
-    rc-field-form "~1.27.4"
-    rc-util "^5.30.0"
+    deepmerge "^4.3.1"
+    nano-memoize "^3.0.16"
+    rc-field-form "^1.34.2"
+    rc-segmented "~2.4.1"
+    rc-util "^5.44.4"
+    react-fast-compare "^3.2.2"
     react-is "^18.2.0"
     runes2 "^1.1.2"
     staged-components "^1.1.3"
@@ -3889,11 +3902,16 @@ data-urls@^2.0.0:
     whatwg-mimetype "^2.3.0"
     whatwg-url "^8.0.0"
 
-dayjs@^1.11.1, dayjs@^1.11.7, dayjs@^1.11.9, dayjs@^1.9.1:
+dayjs@^1.11.1, dayjs@^1.11.9:
   version "1.11.13"
   resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.13.tgz"
   integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==
 
+dayjs@^1.11.7, dayjs@^1.9.1:
+  version "1.11.19"
+  resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.19.tgz#15dc98e854bb43917f12021806af897c58ae2938"
+  integrity sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==
+
 debug@2.6.9, debug@^2.6.0, debug@^2.6.9:
   version "2.6.9"
   resolved "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz"
@@ -3961,6 +3979,11 @@ deepmerge@^4.2.2:
   resolved "https://registry.npmmirror.com/deepmerge/-/deepmerge-4.2.2.tgz"
   integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
 
+deepmerge@^4.3.1:
+  version "4.3.1"
+  resolved "https://registry.npmmirror.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a"
+  integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==
+
 default-gateway@^6.0.3:
   version "6.0.3"
   resolved "https://registry.npmmirror.com/default-gateway/-/default-gateway-6.0.3.tgz"
@@ -5416,7 +5439,7 @@ internal-slot@^1.0.3:
 
 intersection-observer@^0.12.0:
   version "0.12.2"
-  resolved "https://registry.npmmirror.com/intersection-observer/-/intersection-observer-0.12.2.tgz"
+  resolved "https://registry.npmmirror.com/intersection-observer/-/intersection-observer-0.12.2.tgz#4a45349cc0cd91916682b1f44c28d7ec737dc375"
   integrity sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg==
 
 ipaddr.js@1.9.1:
@@ -6208,10 +6231,10 @@ js-base64@^3.7.5:
   resolved "https://registry.npmmirror.com/js-base64/-/js-base64-3.7.7.tgz#e51b84bf78fbf5702b9541e2cb7bfcb893b43e79"
   integrity sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==
 
-js-cookie@^2.x.x:
-  version "2.2.1"
-  resolved "https://registry.npmmirror.com/js-cookie/-/js-cookie-2.2.1.tgz"
-  integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==
+js-cookie@^3.0.5:
+  version "3.0.5"
+  resolved "https://registry.npmmirror.com/js-cookie/-/js-cookie-3.0.5.tgz#0b7e2fd0c01552c58ba86e0841f94dc2557dcdbc"
+  integrity sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==
 
 js-sdsl@^4.1.4:
   version "4.1.5"
@@ -6695,6 +6718,11 @@ mutation-observer@^1.0.3:
   resolved "https://registry.npmmirror.com/mutation-observer/-/mutation-observer-1.0.3.tgz#42e9222b101bca82e5ba9d5a7acf4a14c0f263d0"
   integrity sha512-M/O/4rF2h776hV7qGMZUH3utZLO/jK7p8rnNgGkjKUw8zCGjRQPxB8z6+5l8+VjRUQ3dNYu4vjqXYLr+U8ZVNA==
 
+nano-memoize@^3.0.16:
+  version "3.0.16"
+  resolved "https://registry.npmmirror.com/nano-memoize/-/nano-memoize-3.0.16.tgz#454100602713973ac8639bde301e255dd54920ea"
+  integrity sha512-JyK96AKVGAwVeMj3MoMhaSXaUNqgMbCRSQB3trUV8tYZfWEzqUBKdK1qJpfuNXgKeHOx1jv/IEYTM659ly7zUA==
+
 nanoid@^3.3.4:
   version "3.3.4"
   resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.4.tgz"
@@ -7893,14 +7921,14 @@ rc-dropdown@~4.1.0:
     classnames "^2.2.6"
     rc-util "^5.17.0"
 
-rc-field-form@~1.27.4:
-  version "1.27.4"
-  resolved "https://registry.npmmirror.com/rc-field-form/-/rc-field-form-1.27.4.tgz"
-  integrity sha512-PQColQnZimGKArnOh8V2907+VzDCXcqtFvHgevDLtqWc/P7YASb/FqntSmdS8q3VND5SHX3Y1vgMIzY22/f/0Q==
+rc-field-form@^1.34.2:
+  version "1.44.0"
+  resolved "https://registry.npmmirror.com/rc-field-form/-/rc-field-form-1.44.0.tgz#a66548790fbcee8c5432e9f2efcd1b46b090984b"
+  integrity sha512-el7w87fyDUsca63Y/s8qJcq9kNkf/J5h+iTdqG5WsSHLH0e6Usl7QuYSmSVzJMgtp40mOVZIY/W/QP9zwrp1FA==
   dependencies:
     "@babel/runtime" "^7.18.0"
     async-validator "^4.1.0"
-    rc-util "^5.8.0"
+    rc-util "^5.32.2"
 
 rc-field-form@~1.36.0:
   version "1.36.2"
@@ -8054,6 +8082,16 @@ rc-segmented@~2.2.0:
     rc-motion "^2.4.4"
     rc-util "^5.17.0"
 
+rc-segmented@~2.4.1:
+  version "2.4.1"
+  resolved "https://registry.npmmirror.com/rc-segmented/-/rc-segmented-2.4.1.tgz#b6bbdd6acf529c1e2ef30fb26fb3851d5966aa00"
+  integrity sha512-KUi+JJFdKnumV9iXlm+BJ00O4NdVBp2TEexLCk6bK1x/RH83TvYKQMzIz/7m3UTRPD08RM/8VG/JNjWgWbd4cw==
+  dependencies:
+    "@babel/runtime" "^7.11.1"
+    classnames "^2.2.1"
+    rc-motion "^2.4.4"
+    rc-util "^5.17.0"
+
 rc-select@~14.7.0, rc-select@~14.7.1:
   version "14.7.4"
   resolved "https://registry.npmmirror.com/rc-select/-/rc-select-14.7.4.tgz"
@@ -8169,7 +8207,7 @@ rc-upload@~4.3.0:
     classnames "^2.2.5"
     rc-util "^5.2.0"
 
-rc-util@^5.0.1, rc-util@^5.15.0, rc-util@^5.16.0, rc-util@^5.16.1, rc-util@^5.17.0, rc-util@^5.18.1, rc-util@^5.19.2, rc-util@^5.2.0, rc-util@^5.20.1, rc-util@^5.21.0, rc-util@^5.21.2, rc-util@^5.22.5, rc-util@^5.24.4, rc-util@^5.25.2, rc-util@^5.26.0, rc-util@^5.27.0, rc-util@^5.27.1, rc-util@^5.28.0, rc-util@^5.30.0, rc-util@^5.31.1, rc-util@^5.32.0, rc-util@^5.32.2, rc-util@^5.33.0, rc-util@^5.34.1, rc-util@^5.35.0, rc-util@^5.8.0:
+rc-util@^5.0.1, rc-util@^5.15.0, rc-util@^5.16.0, rc-util@^5.16.1, rc-util@^5.17.0, rc-util@^5.18.1, rc-util@^5.19.2, rc-util@^5.2.0, rc-util@^5.20.1, rc-util@^5.21.0, rc-util@^5.21.2, rc-util@^5.22.5, rc-util@^5.24.4, rc-util@^5.25.2, rc-util@^5.26.0, rc-util@^5.27.0, rc-util@^5.27.1, rc-util@^5.28.0, rc-util@^5.30.0, rc-util@^5.31.1, rc-util@^5.32.0, rc-util@^5.32.2, rc-util@^5.33.0, rc-util@^5.34.1, rc-util@^5.35.0:
   version "5.36.0"
   resolved "https://registry.npmmirror.com/rc-util/-/rc-util-5.36.0.tgz"
   integrity sha512-a4uUvT+UNHvYL+awzbN8H8zAjfduwY4KAp2wQy40wOz3NyBdo3Xhx/EAAPyDkHLoGm535jIACaMhIqExGiAjHw==
@@ -8177,6 +8215,14 @@ rc-util@^5.0.1, rc-util@^5.15.0, rc-util@^5.16.0, rc-util@^5.16.1, rc-util@^5.17
     "@babel/runtime" "^7.18.3"
     react-is "^16.12.0"
 
+rc-util@^5.44.4:
+  version "5.44.4"
+  resolved "https://registry.npmmirror.com/rc-util/-/rc-util-5.44.4.tgz#89ee9037683cca01cd60f1a6bbda761457dd6ba5"
+  integrity sha512-resueRJzmHG9Q6rI/DfK6Kdv9/Lfls05vzMs1Sk3M2P+3cJa+MakaZyWY8IPfehVuhPJFKrIY1IK4GqbiaiY5w==
+  dependencies:
+    "@babel/runtime" "^7.18.3"
+    react-is "^18.2.0"
+
 rc-virtual-list@^3.5.1, rc-virtual-list@^3.5.2:
   version "3.6.0"
   resolved "https://registry.npmmirror.com/rc-virtual-list/-/rc-virtual-list-3.6.0.tgz"
@@ -8237,18 +8283,23 @@ react-dev-utils@^12.0.1:
     text-table "^0.2.0"
 
 react-dom@^18.2.0:
-  version "18.2.0"
-  resolved "https://registry.npmmirror.com/react-dom/-/react-dom-18.2.0.tgz"
-  integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
+  version "18.3.1"
+  resolved "https://registry.npmmirror.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4"
+  integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==
   dependencies:
     loose-envify "^1.1.0"
-    scheduler "^0.23.0"
+    scheduler "^0.23.2"
 
 react-error-overlay@^6.0.11:
   version "6.0.11"
   resolved "https://registry.npmmirror.com/react-error-overlay/-/react-error-overlay-6.0.11.tgz"
   integrity sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==
 
+react-fast-compare@^3.2.2:
+  version "3.2.2"
+  resolved "https://registry.npmmirror.com/react-fast-compare/-/react-fast-compare-3.2.2.tgz#929a97a532304ce9fee4bcae44234f1ce2c21d49"
+  integrity sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==
+
 react-is@^16.12.0, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0:
   version "16.13.1"
   resolved "https://registry.npmmirror.com/react-is/-/react-is-16.13.1.tgz"
@@ -8259,11 +8310,16 @@ react-is@^17.0.1:
   resolved "https://registry.npmmirror.com/react-is/-/react-is-17.0.2.tgz"
   integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
 
-react-is@^18.0.0, react-is@^18.2.0:
+react-is@^18.0.0:
   version "18.2.0"
   resolved "https://registry.npmmirror.com/react-is/-/react-is-18.2.0.tgz"
   integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
 
+react-is@^18.2.0:
+  version "18.3.1"
+  resolved "https://registry.npmmirror.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e"
+  integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==
+
 react-redux@^8.0.4:
   version "8.0.4"
   resolved "https://registry.npmmirror.com/react-redux/-/react-redux-8.0.4.tgz"
@@ -8653,9 +8709,9 @@ run-parallel@^1.1.9:
     queue-microtask "^1.2.2"
 
 runes2@^1.1.2:
-  version "1.1.2"
-  resolved "https://registry.npmmirror.com/runes2/-/runes2-1.1.2.tgz"
-  integrity sha512-v6XIdRpUKdFLNhgF2AC9XvntZsDzxyTpVlpQ8HD592XD6vHiW8jEcHFnTV5ztUjWJC5cGOcdi9YKIwxWVh0f9w==
+  version "1.1.4"
+  resolved "https://registry.npmmirror.com/runes2/-/runes2-1.1.4.tgz#aa38d3d7946e147ac4718ed0fb19b22340ae5c66"
+  integrity sha512-LNPnEDPOOU4ehF71m5JoQyzT2yxwD6ZreFJ7MxZUAoMKNMY1XrAo60H1CUoX5ncSm0rIuKlqn9JZNRrRkNou2g==
 
 safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
   version "5.1.2"
@@ -8715,10 +8771,10 @@ saxes@^5.0.1:
   dependencies:
     xmlchars "^2.2.0"
 
-scheduler@^0.23.0:
-  version "0.23.0"
-  resolved "https://registry.npmmirror.com/scheduler/-/scheduler-0.23.0.tgz"
-  integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==
+scheduler@^0.23.2:
+  version "0.23.2"
+  resolved "https://registry.npmmirror.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3"
+  integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==
   dependencies:
     loose-envify "^1.1.0"
 
@@ -8761,7 +8817,7 @@ schema-utils@^4.0.0:
 
 screenfull@^5.0.0:
   version "5.2.0"
-  resolved "https://registry.npmmirror.com/screenfull/-/screenfull-5.2.0.tgz"
+  resolved "https://registry.npmmirror.com/screenfull/-/screenfull-5.2.0.tgz#6533d524d30621fc1283b9692146f3f13a93d1ba"
   integrity sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==
 
 scroll-into-view-if-needed@^3.0.3:
@@ -9022,7 +9078,7 @@ stackframe@^1.3.4:
 
 staged-components@^1.1.3:
   version "1.1.3"
-  resolved "https://registry.npmmirror.com/staged-components/-/staged-components-1.1.3.tgz"
+  resolved "https://registry.npmmirror.com/staged-components/-/staged-components-1.1.3.tgz#bb5a396df2d9b48fbc31841a59f53437ed8b8ac6"
   integrity sha512-9EIswzDqjwlEu+ymkV09TTlJfzSbKgEnNteUnZSTxkpMgr5Wx2CzzA9WcMFWBNCldqVPsHVnRGGrApduq2Se5A==
 
 statuses@2.0.1:
@@ -9463,11 +9519,16 @@ tslib@^1.8.1:
   resolved "https://registry.npmmirror.com/tslib/-/tslib-1.14.1.tgz"
   integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
 
-tslib@^2.0.3, tslib@^2.4.1, tslib@^2.5.0:
+tslib@^2.0.3:
   version "2.5.3"
   resolved "https://registry.npmmirror.com/tslib/-/tslib-2.5.3.tgz"
   integrity sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==
 
+tslib@^2.4.1, tslib@^2.5.0:
+  version "2.8.1"
+  resolved "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
+  integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
+
 tsutils@^3.21.0:
   version "3.21.0"
   resolved "https://registry.npmmirror.com/tsutils/-/tsutils-3.21.0.tgz"