fix: 修复移动端输入框被键盘遮挡的问题
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
/.pnp
|
/.pnp
|
||||||
.pnp.js
|
.pnp.js
|
||||||
.pnpm-store
|
.pnpm-store
|
||||||
|
.omc
|
||||||
|
|
||||||
# testing
|
# testing
|
||||||
/coverage
|
/coverage
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "vocechat-web",
|
"name": "vocechat-web",
|
||||||
"version": "0.9.78",
|
"version": "0.9.79",
|
||||||
"homepage": "https://voce.chat",
|
"homepage": "https://voce.chat",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@metamask/onboarding": "^1.0.1",
|
"@metamask/onboarding": "^1.0.1",
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
|
const isIOS = () =>
|
||||||
|
/iPad|iPhone|iPod/.test(navigator.userAgent) ||
|
||||||
|
(navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listens to the VisualViewport API and writes the visible height as a CSS
|
||||||
|
* custom property (`--vh-visible`) on `document.documentElement`.
|
||||||
|
*
|
||||||
|
* On Android mobile browsers the virtual keyboard shrinks the visual viewport
|
||||||
|
* while `100vh` still refers to the full layout viewport, which causes
|
||||||
|
* bottom-pinned elements (like the chat input) to be hidden behind the
|
||||||
|
* keyboard or the browser chrome.
|
||||||
|
*
|
||||||
|
* iOS Safari handles this natively via scroll-into-view behaviour and
|
||||||
|
* `-webkit-fill-available`, so we skip it there to avoid the container
|
||||||
|
* being over-shrunk when the keyboard opens.
|
||||||
|
*/
|
||||||
|
export default function useVirtualKeyboard() {
|
||||||
|
useEffect(() => {
|
||||||
|
if (isIOS()) return;
|
||||||
|
|
||||||
|
const vv = window.visualViewport;
|
||||||
|
|
||||||
|
function update() {
|
||||||
|
const height = vv ? vv.height : window.innerHeight;
|
||||||
|
document.documentElement.style.setProperty("--vh-visible", `${height}px`);
|
||||||
|
}
|
||||||
|
|
||||||
|
update();
|
||||||
|
|
||||||
|
if (vv) {
|
||||||
|
vv.addEventListener("resize", update);
|
||||||
|
vv.addEventListener("scroll", update);
|
||||||
|
} else {
|
||||||
|
window.addEventListener("resize", update);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (vv) {
|
||||||
|
vv.removeEventListener("resize", update);
|
||||||
|
vv.removeEventListener("scroll", update);
|
||||||
|
} else {
|
||||||
|
window.removeEventListener("resize", update);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
@@ -8,6 +8,8 @@ import ChannelModal from "@/components/ChannelModal";
|
|||||||
import ErrorCatcher from "@/components/ErrorCatcher";
|
import ErrorCatcher from "@/components/ErrorCatcher";
|
||||||
import Server from "@/components/Server";
|
import Server from "@/components/Server";
|
||||||
import UsersModal from "@/components/UsersModal";
|
import UsersModal from "@/components/UsersModal";
|
||||||
|
import useVirtualKeyboard from "@/hooks/useVirtualKeyboard";
|
||||||
|
import { isIOS } from "@/utils";
|
||||||
import ChannelChat from "./ChannelChat";
|
import ChannelChat from "./ChannelChat";
|
||||||
import DMChat from "./DMChat";
|
import DMChat from "./DMChat";
|
||||||
import GuestBlankPlaceholder from "./GuestBlankPlaceholder";
|
import GuestBlankPlaceholder from "./GuestBlankPlaceholder";
|
||||||
@@ -19,6 +21,7 @@ import VoiceFullscreen from "./VoiceFullscreen";
|
|||||||
import { shallowEqual } from "react-redux";
|
import { shallowEqual } from "react-redux";
|
||||||
|
|
||||||
function ChatPage() {
|
function ChatPage() {
|
||||||
|
useVirtualKeyboard();
|
||||||
const isHomePath = useMatch(`/`);
|
const isHomePath = useMatch(`/`);
|
||||||
const isChatHomePath = useMatch(`/chat`);
|
const isChatHomePath = useMatch(`/chat`);
|
||||||
const [sessionListVisible, setSessionListVisible] = useState(false);
|
const [sessionListVisible, setSessionListVisible] = useState(false);
|
||||||
@@ -65,6 +68,8 @@ function ChatPage() {
|
|||||||
const contextId = (+channel_id || callingTo) ?? 0;
|
const contextId = (+channel_id || callingTo) ?? 0;
|
||||||
console.log("fffff", channel_id, user_id, aside, channelChatVisible);
|
console.log("fffff", channel_id, user_id, aside, channelChatVisible);
|
||||||
|
|
||||||
|
const mobileHeight = isIOS() ? "h-screen" : "h-[var(--vh-visible,100vh)]";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ErrorCatcher>
|
<ErrorCatcher>
|
||||||
{channelModalVisible && (
|
{channelModalVisible && (
|
||||||
@@ -73,7 +78,7 @@ function ChatPage() {
|
|||||||
{usersModalVisible && <UsersModal closeModal={toggleUsersModalVisible} />}
|
{usersModalVisible && <UsersModal closeModal={toggleUsersModalVisible} />}
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
`flex h-screen md:h-full md:pt-2 md:pb-2.5 md:pr-1`,
|
`flex ${mobileHeight} md:h-full md:pt-2 md:pb-2.5 md:pr-1`,
|
||||||
isGuest ? "guest-container md:px-1" : "md:pr-12"
|
isGuest ? "guest-container md:px-1" : "md:pr-12"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -85,7 +90,7 @@ function ChatPage() {
|
|||||||
)}
|
)}
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"left-container flex-col md:rounded-l-2xl w-full h-screen md:h-full md:max-w-[250px] md:min-w-[268px] shadow-[rgb(0_0_0_/_10%)_-1px_0px_0px_inset] bg-white dark:!bg-gray-800",
|
`left-container flex-col md:rounded-l-2xl w-full ${mobileHeight} md:h-full md:max-w-[250px] md:min-w-[268px] shadow-[rgb(0_0_0_/_10%)_-1px_0px_0px_inset] bg-white dark:!bg-gray-800`,
|
||||||
isMainPath ? "flex" : "hidden md:flex"
|
isMainPath ? "flex" : "hidden md:flex"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import Tooltip from "@/components/Tooltip";
|
|||||||
import UnreadTabTip from "@/components/UnreadTabTip";
|
import UnreadTabTip from "@/components/UnreadTabTip";
|
||||||
import Voice from "@/components/Voice";
|
import Voice from "@/components/Voice";
|
||||||
import usePreload from "@/hooks/usePreload";
|
import usePreload from "@/hooks/usePreload";
|
||||||
|
import useVirtualKeyboard from "@/hooks/useVirtualKeyboard";
|
||||||
|
import { isIOS } from "@/utils";
|
||||||
import FavIcon from "@/assets/icons/bookmark.svg";
|
import FavIcon from "@/assets/icons/bookmark.svg";
|
||||||
import ChatIcon from "@/assets/icons/chat.svg";
|
import ChatIcon from "@/assets/icons/chat.svg";
|
||||||
import FolderIcon from "@/assets/icons/folder.svg";
|
import FolderIcon from "@/assets/icons/folder.svg";
|
||||||
@@ -23,6 +25,7 @@ import User from "./User";
|
|||||||
import StreamStatus from "@/components/StreamStatus";
|
import StreamStatus from "@/components/StreamStatus";
|
||||||
|
|
||||||
function HomePage() {
|
function HomePage() {
|
||||||
|
useVirtualKeyboard();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const isHomePath = useMatch(`/`);
|
const isHomePath = useMatch(`/`);
|
||||||
@@ -66,7 +69,9 @@ function HomePage() {
|
|||||||
<Manifest />
|
<Manifest />
|
||||||
{!guest && <Notification />}
|
{!guest && <Notification />}
|
||||||
<div
|
<div
|
||||||
className={`vocechat-container flex w-screen h-screen bg-neutral-100 dark:bg-neutral-900`}
|
className={`vocechat-container flex w-screen ${
|
||||||
|
isIOS() ? "h-screen" : "h-[var(--vh-visible,100vh)]"
|
||||||
|
} bg-neutral-100 dark:bg-neutral-900`}
|
||||||
>
|
>
|
||||||
{!guest && (
|
{!guest && (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -61,6 +61,10 @@ export function getMessageFromPlateValues(values: ParagraphInput[]): MessageWith
|
|||||||
export const isMobile = () =>
|
export const isMobile = () =>
|
||||||
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
||||||
|
|
||||||
|
export const isIOS = () =>
|
||||||
|
/iPad|iPhone|iPod/.test(navigator.userAgent) ||
|
||||||
|
(navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1);
|
||||||
|
|
||||||
export const getLocalAuthData = () => {
|
export const getLocalAuthData = () => {
|
||||||
return {
|
return {
|
||||||
token: localStorage.getItem(KEY_TOKEN) || "",
|
token: localStorage.getItem(KEY_TOKEN) || "",
|
||||||
|
|||||||
Reference in New Issue
Block a user