dfe6a7e193
* refactor: optimize message feed rendering and state management - Removed unnecessary initialization state in VirtualMessageFeed. - Updated message data subscription to only track visible messages, improving performance. - Simplified props in Layout component for VirtualMessageFeed and Send components. * refactor: 针对低性能设备进行更多优化,包括消息隔离等 - Added a script to suppress ResizeObserver errors in index.html. - Introduced memoized selectors for efficient message retrieval in message selectors. - Optimized message insertion logic in message slices to reduce unnecessary sorting. - Improved memoization in Message component for better rendering performance. - Enhanced MessageInput to reset editor state on chat changes. - Updated VirtualMessageFeed to manage visible messages more efficiently and reduce initial load for better performance on low-end devices. * chore: bump version to v0.9.50
231 lines
7.6 KiB
HTML
231 lines
7.6 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta
|
|
name="viewport"
|
|
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
|
|
/>
|
|
<meta name="theme-color" content="#527ff1" />
|
|
<meta name="description" content="Your private chat APP" />
|
|
|
|
<!-- Suppress ResizeObserver errors - must be first script -->
|
|
<script>
|
|
// Suppress benign ResizeObserver errors from virtualized lists
|
|
// This is a known browser issue and doesn't affect functionality
|
|
// Reference: https://github.com/WICG/resize-observer/issues/38
|
|
|
|
(function() {
|
|
function isResizeObserverError(message) {
|
|
return message && (
|
|
message.includes('ResizeObserver loop') ||
|
|
message.includes('ResizeObserver loop completed') ||
|
|
message.includes('ResizeObserver loop limit exceeded')
|
|
);
|
|
}
|
|
|
|
// Intercept window.onerror
|
|
const originalOnError = window.onerror;
|
|
window.onerror = function(message, source, lineno, colno, error) {
|
|
if (typeof message === 'string' && isResizeObserverError(message)) {
|
|
return true; // Suppress ResizeObserver errors
|
|
}
|
|
if (originalOnError) {
|
|
return originalOnError.apply(this, arguments);
|
|
}
|
|
return false;
|
|
};
|
|
|
|
// Intercept error events (capture phase to catch early)
|
|
window.addEventListener('error', function(e) {
|
|
if (e.message && isResizeObserverError(e.message)) {
|
|
e.stopImmediatePropagation();
|
|
e.preventDefault();
|
|
return true;
|
|
}
|
|
}, true);
|
|
|
|
// Intercept console.error
|
|
const originalConsoleError = console.error;
|
|
console.error = function() {
|
|
const args = Array.from(arguments);
|
|
if (args.length > 0 && typeof args[0] === 'string' && isResizeObserverError(args[0])) {
|
|
return; // Suppress
|
|
}
|
|
originalConsoleError.apply(console, args);
|
|
};
|
|
})();
|
|
</script>
|
|
|
|
<link rel="apple-touch-icon" href="%PUBLIC_URL%/apple-touch-icon.png" />
|
|
<!-- splash -->
|
|
<link
|
|
href="%PUBLIC_URL%/splash/iphone5_splash.png"
|
|
media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2)"
|
|
rel="apple-touch-startup-image"
|
|
/>
|
|
<link
|
|
href="%PUBLIC_URL%/splash/iphone6_splash.png"
|
|
media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2)"
|
|
rel="apple-touch-startup-image"
|
|
/>
|
|
<link
|
|
href="%PUBLIC_URL%/splash/iphoneplus_splash.png"
|
|
media="(device-width: 621px) and (device-height: 1104px) and (-webkit-device-pixel-ratio: 3)"
|
|
rel="apple-touch-startup-image"
|
|
/>
|
|
<link
|
|
href="%PUBLIC_URL%/splash/iphonex_splash.png"
|
|
media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3)"
|
|
rel="apple-touch-startup-image"
|
|
/>
|
|
<link
|
|
href="%PUBLIC_URL%/splash/iphonexr_splash.png"
|
|
media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2)"
|
|
rel="apple-touch-startup-image"
|
|
/>
|
|
<link
|
|
href="%PUBLIC_URL%/splash/iphonexsmax_splash.png"
|
|
media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3)"
|
|
rel="apple-touch-startup-image"
|
|
/>
|
|
<link
|
|
href="%PUBLIC_URL%/splash/ipad_splash.png"
|
|
media="(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2)"
|
|
rel="apple-touch-startup-image"
|
|
/>
|
|
<link
|
|
href="%PUBLIC_URL%/splash/ipadpro1_splash.png"
|
|
media="(device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2)"
|
|
rel="apple-touch-startup-image"
|
|
/>
|
|
<link
|
|
href="%PUBLIC_URL%/splash/ipadpro3_splash.png"
|
|
media="(device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2)"
|
|
rel="apple-touch-startup-image"
|
|
/>
|
|
<link
|
|
href="%PUBLIC_URL%/splash/ipadpro2_splash.png"
|
|
media="(device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2)"
|
|
rel="apple-touch-startup-image"
|
|
/>
|
|
|
|
<!-- /splash -->
|
|
<!--
|
|
manifest.json provides metadata used when your web app is installed on a
|
|
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
|
-->
|
|
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
|
<!-- <link rel="manifest" id="my-manifest-placeholder"> -->
|
|
<!--
|
|
Notice the use of %PUBLIC_URL% in the tags above.
|
|
It will be replaced with the URL of the `public` folder during the build.
|
|
Only files inside the `public` folder can be referenced from the HTML.
|
|
|
|
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
|
work correctly both with client-side routing and a non-root public URL.
|
|
Learn how to configure a non-root public URL by running `npm run build`.
|
|
-->
|
|
<title>VoceChat WebAPP</title>
|
|
<!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.0/styles/github.min.css"> -->
|
|
<style>
|
|
html {
|
|
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
|
|
Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif !important;
|
|
}
|
|
</style>
|
|
</head>
|
|
<style>
|
|
#root-modal,
|
|
#modal-modal {
|
|
pointer-events: none;
|
|
position: fixed;
|
|
z-index: 999;
|
|
left: 0;
|
|
top: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
#root-modal > .wrapper,
|
|
#modal-modal > .wrapper {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
|
|
#root-modal.mask > .wrapper,
|
|
#modal-modal.mask > .wrapper {
|
|
background-color: rgba(2, 2, 2, 0.4);
|
|
pointer-events: all;
|
|
width: 100vw;
|
|
height: 100dvh;
|
|
}
|
|
</style>
|
|
<style>
|
|
/* reset */
|
|
body {
|
|
overflow: hidden;
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
/* iOS safari */
|
|
@supports (-webkit-touch-callout: none) {
|
|
body {
|
|
height: -webkit-fill-available;
|
|
}
|
|
.h-screen {
|
|
height: -webkit-fill-available !important ;
|
|
overflow: auto;
|
|
}
|
|
}
|
|
/* iframe 样式覆盖 */
|
|
body.iframe {
|
|
position: fixed;
|
|
top: 0;
|
|
}
|
|
body.iframe .guest-container {
|
|
padding: 0;
|
|
}
|
|
body.iframe .guest-container .left-container,
|
|
body.iframe .guest-container .right-container {
|
|
border-radius: 0;
|
|
}
|
|
/* electron */
|
|
body.electron .guest-container {
|
|
padding: 0;
|
|
}
|
|
body.electron .guest-container .left-container,
|
|
body.electron .guest-container .right-container {
|
|
border-radius: 0;
|
|
}
|
|
</style>
|
|
|
|
<body>
|
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
<div id="root"></div>
|
|
<div id="root-modal"></div>
|
|
<div id="modal-modal"></div>
|
|
<!--
|
|
This HTML file is a template.
|
|
If you open it directly in the browser, you will see an empty page.
|
|
|
|
You can add webfonts, meta tags, or analytics to this file.
|
|
The build step will place the bundled scripts into the <body> tag.
|
|
|
|
To begin the development, run `npm start` or `yarn start`.
|
|
To create a production bundle, use `npm run build` or `yarn build`.
|
|
-->
|
|
</body>
|
|
<script>
|
|
// electron
|
|
if (navigator.userAgent.indexOf("Electron/") > -1) {
|
|
document.body.classList.add("electron");
|
|
}
|
|
if (window.location !== window.parent.location) {
|
|
// The page is in an iframe
|
|
document.body.classList.add("iframe");
|
|
}
|
|
</script>
|
|
</html>
|