diff --git a/src/components/landing-page/create-production.tsx b/src/components/landing-page/create-production.tsx index ee49e021..d1c6f8d4 100644 --- a/src/components/landing-page/create-production.tsx +++ b/src/components/landing-page/create-production.tsx @@ -176,7 +176,7 @@ export const CreateProduction = () => { Create Production diff --git a/src/components/landing-page/form-elements.tsx b/src/components/landing-page/form-elements.tsx index ce96f7e9..be589e38 100644 --- a/src/components/landing-page/form-elements.tsx +++ b/src/components/landing-page/form-elements.tsx @@ -61,7 +61,7 @@ export const ActionButton = styled.button` box-shadow: inset 0.1rem 0.1rem 0 rgba(0, 0, 0, 0.2); } - &.submit { + &.with-loader { position: relative; color: rgba(255, 255, 255, 0); } diff --git a/src/components/loader/loader.tsx b/src/components/loader/loader.tsx index 6a3c235c..d49d042b 100644 --- a/src/components/loader/loader.tsx +++ b/src/components/loader/loader.tsx @@ -2,23 +2,23 @@ import styled from "@emotion/styled"; import { FC, useEffect, useState } from "react"; const Loading = styled.div` - border: 4px solid rgba(0, 0, 0, 0.1); - border-top: 4px solid #333; + border: 0.4rem solid rgba(0, 0, 0, 0.1); + border-top: 0.4rem solid #333; border-radius: 50%; - width: 30px; - height: 30px; + width: 3rem; + height: 3rem; animation: spin 1s linear infinite; margin: auto; &.create-production { position: absolute; - top: 5px; - left: 60px; + top: 0.5rem; + left: 6rem; } &.join-production { - border: 4px solid rgba(201, 201, 201, 0.1); - border-top: 4px solid #e2e2e2; + border: 0.4rem solid rgba(201, 201, 201, 0.1); + border-top: 0.4rem solid #e2e2e2; } @keyframes spin { diff --git a/src/components/production-line/long-press-to-talk-button.tsx b/src/components/production-line/long-press-to-talk-button.tsx new file mode 100644 index 00000000..5526d010 --- /dev/null +++ b/src/components/production-line/long-press-to-talk-button.tsx @@ -0,0 +1,86 @@ +import { useEffect, useState } from "react"; +import styled from "@emotion/styled"; +import { ActionButton } from "../landing-page/form-elements"; +import { isMobile } from "../../bowser"; + +type TLongPressToTalkButton = { + setMicMute: (input: boolean) => void; +}; + +const Button = styled(ActionButton)` + position: relative; + + &.active-btn { + color: rgba(255, 255, 255, 0); + animation: pulse 0.7s ease-in-out infinite alternate; + } + + &.mobile { + user-select: none; + } + + @keyframes pulse { + 0% { + background: #4ada1e; + } + 100% { + background: rgba(255, 255, 255, 0.78); + } + } +`; + +export const LongPressToTalkButton = ({ + setMicMute, +}: TLongPressToTalkButton) => { + const [isToggled, setIsToggled] = useState(false); + const [longPressTimeout, setLongPressTimeout] = + useState>(); + + useEffect(() => { + return () => { + if (longPressTimeout) { + clearTimeout(longPressTimeout); + } + }; + }, [longPressTimeout]); + + const toggleMuteAfterTimeout = (e: React.PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + e.currentTarget.setPointerCapture(e.pointerId); + + let timeoutId: NodeJS.Timeout; + + switch (e.type) { + case "pointerdown": + timeoutId = setTimeout(() => { + setMicMute(false); + setIsToggled(true); + }, 300); + setLongPressTimeout(timeoutId); + break; + case "pointerup": + setIsToggled(false); + setMicMute(true); + clearTimeout(longPressTimeout); + break; + default: + console.error(`Invalid event type received: ${e.type}`); + } + }; + + return ( + + ); +}; diff --git a/src/components/production-line/production-line.tsx b/src/components/production-line/production-line.tsx index 11c512c6..4c7800c0 100644 --- a/src/components/production-line/production-line.tsx +++ b/src/components/production-line/production-line.tsx @@ -14,8 +14,9 @@ import { DisplayContainer, FlexContainer } from "../generic-components.ts"; import { useHeartbeat } from "./use-heartbeat.ts"; import { JoinProduction } from "../landing-page/join-production.tsx"; import { useDeviceLabels } from "./use-device-labels.ts"; -import { useLineHotkeys } from "./use-line-hotkeys.ts"; import { isMobile } from "../../bowser.ts"; +import { useLineHotkeys } from "./use-line-hotkeys.ts"; +import { LongPressToTalkButton } from "./long-press-to-talk-button.tsx"; import { useLinePolling } from "./use-line-polling.ts"; import { useFetchProduction } from "../landing-page/use-fetch-production.ts"; import { useIsLoading } from "./use-is-loading.ts"; @@ -134,6 +135,7 @@ export const ProductionLine: FC = () => { }); // TODO detect if browser back button is pressed and run exit(); + return ( <> @@ -190,6 +192,9 @@ export const ProductionLine: FC = () => { {isInputMuted ? "Muted" : "Unmuted"} + setIsInputMuted(input)} + /> )}