diff --git a/src/website/packages/fakeyou.com/src/components/entities/EntityInput/EntityInput.scss b/src/website/packages/fakeyou.com/src/components/entities/EntityInput/EntityInput.scss
index 81894f5e18..afa4186211 100644
--- a/src/website/packages/fakeyou.com/src/components/entities/EntityInput/EntityInput.scss
+++ b/src/website/packages/fakeyou.com/src/components/entities/EntityInput/EntityInput.scss
@@ -82,25 +82,25 @@
pointer-events: none;
}
- .fy-entity-input-progress-indicator {
- align-items: center;
- display: flex;
- flex-direction: column;
- position: relative;
+ // .fy-entity-input-progress-indicator {
+ // align-items: center;
+ // display: flex;
+ // flex-direction: column;
+ // position: relative;
- .fy-entity-input-progress-number {
- position: absolute;
- text-align: center;
- font-size: 0.625rem;
- line-height: 0.625rem;
- height: 0.625rem;
- top: 50%;
- transform: translateY(-50%);
- left: 0;
- right: 0;
- bottom: 0;
- }
- }
+ // .fy-entity-input-progress-number {
+ // position: absolute;
+ // text-align: center;
+ // font-size: 0.625rem;
+ // line-height: 0.625rem;
+ // height: 0.625rem;
+ // top: 50%;
+ // transform: translateY(-50%);
+ // left: 0;
+ // right: 0;
+ // bottom: 0;
+ // }
+ // }
}
.fy-entity-input-landscape {
diff --git a/src/website/packages/fakeyou.com/src/components/entities/EntityInput/EntityInput.tsx b/src/website/packages/fakeyou.com/src/components/entities/EntityInput/EntityInput.tsx
index 14e5ea5cb7..e0cecc58be 100644
--- a/src/website/packages/fakeyou.com/src/components/entities/EntityInput/EntityInput.tsx
+++ b/src/website/packages/fakeyou.com/src/components/entities/EntityInput/EntityInput.tsx
@@ -91,23 +91,17 @@ const MediaBusy = ({ uploaderBusy, uploadProgress }: SlideProps) => {
return (
{uploaderBusy ? (
- <>
- Uploading
-
-
- {uploadProgress}%
-
-
-
- >
+
) : (
)}
@@ -370,6 +364,7 @@ export default function EntityInput({
onSelect,
queryUser,
render: EntityInputEmpty,
+ selectToken,
showWebcam,
type,
...sharedProps,
diff --git a/src/website/packages/fakeyou.com/src/components/entities/EntityInput/EntityInputEmpty.tsx b/src/website/packages/fakeyou.com/src/components/entities/EntityInput/EntityInputEmpty.tsx
index 6199669653..20f74efda7 100644
--- a/src/website/packages/fakeyou.com/src/components/entities/EntityInput/EntityInputEmpty.tsx
+++ b/src/website/packages/fakeyou.com/src/components/entities/EntityInput/EntityInputEmpty.tsx
@@ -36,6 +36,7 @@ interface EmptySlideProps extends SlideProps {
accept: AcceptTypes | AcceptTypes[];
inputProps?: any;
queryUser?: string;
+ selectToken: (token: string) => void;
showWebcam: boolean;
type: EntityModeProp;
}
@@ -44,6 +45,7 @@ export default function EntityInputEmpty({
accept,
inputProps,
queryUser,
+ selectToken,
showWebcam,
type,
...rest
@@ -80,6 +82,7 @@ export default function EntityInputEmpty({
open({
component: CameraCapture,
padding: false,
+ props: { selectToken },
width: "square",
});
diff --git a/src/website/packages/fakeyou.com/src/components/layout/InferenceJobsList/JobItem.tsx b/src/website/packages/fakeyou.com/src/components/layout/InferenceJobsList/JobItem.tsx
index b6d9cd9d8f..1c94a612f3 100644
--- a/src/website/packages/fakeyou.com/src/components/layout/InferenceJobsList/JobItem.tsx
+++ b/src/website/packages/fakeyou.com/src/components/layout/InferenceJobsList/JobItem.tsx
@@ -136,9 +136,7 @@ export default function JobItem({
});
const headingBounce = useSpring(makeBounce(8));
const subtitleBounce = useSpring(makeBounce(6, 30));
- const percentFade = useSpring({
- opacity: jobIsAlive ? 1 : 0,
- });
+
const subtitle = maybeFailureCategory
? `${failures(maybeFailureCategory)}`
: t(`subtitles.${jobStatus}`);
@@ -188,16 +186,15 @@ export default function JobItem({
return (
<>
-
-
- {progressPercentage}%
-
-
-
+
diff --git a/src/website/packages/fakeyou.com/src/components/modals/CameraCapture/CameraCapture.scss b/src/website/packages/fakeyou.com/src/components/modals/CameraCapture/CameraCapture.scss
index adcd21e7ab..f58e12ad76 100644
--- a/src/website/packages/fakeyou.com/src/components/modals/CameraCapture/CameraCapture.scss
+++ b/src/website/packages/fakeyou.com/src/components/modals/CameraCapture/CameraCapture.scss
@@ -2,12 +2,39 @@
@import "scss/site-refresh.scss";
.fy-camera-capture-modal {
- width: 100%;
- height: 100%;
+ // background: red;
+ width: 75vh;
+ height: 75vh;
position: relative;
+ .fy-camera-capture-close {
+ @include video-tint;
+ border: none;
+ position: absolute;
+ right: 1rem;
+ top: 1rem;
+
+ &:hover {
+ background-color: rgba($secondary-very-dark, 0.45);
+ }
+ }
+
+ .fy-camera-capture-slide {
+ position: absolute;
+ width: 100%;
+ }
+
+ .fy-camera-capture-centered {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100%;
+ }
+
.fy-camera-capture-display {
+ // background: red;
+ width: 100%;
height: 100%;
margin: auto;
}
@@ -41,19 +68,74 @@
svg {
display: block;
- // background: rgba(#00f, 0.25);
height: 2rem;
width: 2rem;
margin-bottom: 0.25rem;
+ &.fy-camera-capture-btn-record {
+ circle {
+ stroke: $primary;
+ }
+ rect {
+ fill: $primary;
+ }
+ &:hover {
+ circle {
+ stroke: $primary-light;
+ }
+ rect {
+ fill: $primary-light;
+ }
+ }
+ }
+
+ &.fy-camera-capture-btn-stop {
+ circle {
+ stroke: $secondary-lightest;
+ }
+ rect {
+ fill: $secondary-lightest;
+ }
+ &:hover {
+ circle {
+ stroke: #fff;
+ }
+ rect {
+ fill: #fff;
+ }
+ }
+ }
+
+ circle,
+ rect {
+ transition: all 0.25s ease-in-out;
+ }
+
circle {
fill: none;
- stroke: $primary;
stroke-width: 2px;
}
- rect {
- fill: $primary;
- }
+ }
+ }
+
+ .fy-camera-capture-preview {
+ width: 100%;
+ position: absolute;
+ }
+
+ .fy-camera-capture-float-button {
+ position: absolute;
+ top: 1rem;
+
+ &:first-of-type {
+ left: 1rem;
+ }
+
+ &:last-of-type {
+ margin: auto;
+ width: fit-content;
+ left: 0;
+ right: 0;
}
}
}
diff --git a/src/website/packages/fakeyou.com/src/components/modals/CameraCapture/CameraCapture.tsx b/src/website/packages/fakeyou.com/src/components/modals/CameraCapture/CameraCapture.tsx
index e22dd3d3c3..0772e4ee55 100644
--- a/src/website/packages/fakeyou.com/src/components/modals/CameraCapture/CameraCapture.tsx
+++ b/src/website/packages/fakeyou.com/src/components/modals/CameraCapture/CameraCapture.tsx
@@ -1,55 +1,57 @@
-import React, { useCallback, useRef, useState } from "react";
+import React, { useCallback, useEffect, useRef, useState } from "react";
import Webcam from "react-webcam";
-import { a, useSpring } from "@react-spring/web";
-// import { MediaRecorder, IMediaRecorder } from "extendable-media-recorder";
+import { a, TransitionFn, useSpring, useTransition } from "@react-spring/web";
+import { WorkIndicator } from "components/svg";
+import { useInterval, useMediaUploader } from "hooks";
+import { UploaderResponse } from "components/entities/EntityTypes";
+import { Button, ModalUtilities, Spinner } from "components/common";
+import { faClose } from "@fortawesome/pro-solid-svg-icons";
+import CapturePreview from "./CapturePreview";
import "./CameraCapture.scss";
-import { ModalUtilities } from "components/common";
+interface CameraCaptureProps extends ModalUtilities {
+ selectToken: (token: string) => void;
+}
-// interface Props {
-// value?: any;
-// }
-
-export default function CameraCapture({ handleClose }: ModalUtilities) {
+export default function CameraCapture({
+ handleClose,
+ selectToken,
+}: CameraCaptureProps) {
const webcamRef = useRef(null);
const mediaRecorderRef = useRef(null);
const [capturing, capturingSet] = useState(false);
- const [recordedChunks, setRecordedChunks] = useState([]);
+ const [recordedChunks, recordedChunksSet] = useState([]);
+ const [counter, counterSet] = useState(0);
+ const [blob, blobSet] = useState(null);
+ const [cameraStarted, cameraStartedSet] = useState(false);
+
+ const hours = Math.floor(counter / 3600);
+ const minutes = Math.floor((counter - hours * 3600) / 60);
+ const seconds = counter - hours * 3600 - minutes * 60;
+
+ const timeString =
+ hours.toString().padStart(2, "0") +
+ ":" +
+ minutes.toString().padStart(2, "0") +
+ ":" +
+ seconds.toString().padStart(2, "0");
const handleDataAvailable = useCallback(
({ data }) => {
if (data.size > 0) {
- setRecordedChunks(prev => prev.concat(data));
+ recordedChunksSet(prev => prev.concat(data));
}
},
- [setRecordedChunks]
+ [recordedChunksSet]
);
- const handleDownload = React.useCallback(() => {
- if (recordedChunks.length) {
- const blob = new Blob(recordedChunks, {
- type: "video/webm",
- });
- const url = URL.createObjectURL(blob);
- const a = document.createElement("a");
- document.body.appendChild(a);
- // a.style = "display: none";
- a.href = url;
- a.download = "react-webcam-stream-capture.webm";
- a.click();
- window.URL.revokeObjectURL(url);
- setRecordedChunks([]);
- }
- }, [recordedChunks]);
-
const mainToggleClick = () => {
if (!capturing) {
capturingSet(true);
if (webcamRef.current && webcamRef.current.stream) {
- console.log("🧢", webcamRef.current.stream);
mediaRecorderRef.current = new MediaRecorder(webcamRef.current.stream, {
- mimeType: "video/webm",
+ mimeType: "video/mp4",
});
mediaRecorderRef.current.addEventListener(
@@ -73,67 +75,181 @@ export default function CameraCapture({ handleClose }: ModalUtilities) {
xy: capturing ? 9 : 8,
});
+ const resetCapture = () => {
+ cameraStartedSet(false);
+ blobSet(null);
+ recordedChunksSet([]);
+ counterSet(0);
+ };
+
+ const {
+ busy: uploaderBusy,
+ createUpload,
+ error: uploaderError,
+ uploadProgress,
+ } = useMediaUploader({
+ onSuccess: (res: UploaderResponse) => {
+ handleClose();
+ selectToken(res.media_file_token);
+ },
+ });
+
+ const index = uploaderError
+ ? 3
+ : uploaderBusy
+ ? 2
+ : blob && !capturing
+ ? 1
+ : 0;
+
+ const upload = () => {
+ if (blob) {
+ const file = new File([blob], "test-upload.mp4", { type: "video/mp4" });
+ createUpload(file);
+ }
+ };
+
+ const transitions: TransitionFn<
+ number,
+ { opacity: number; transform: string }
+ > = useTransition(index, {
+ config: { mass: 1, tension: 80, friction: 10 },
+ from: { opacity: 0, transform: `translateX(${5}rem)` },
+ enter: { opacity: 1, transform: `translateX(0)` },
+ leave: { opacity: 0, transform: `translateX(${5}rem)` },
+ });
+
+ useInterval({
+ eventProps: { capturing, counter },
+ interval: 1000,
+ locked: !capturing,
+ onTick: () => {
+ if (capturing) {
+ counterSet(currentCounter => currentCounter + 1);
+ }
+ },
+ });
+
+ useEffect(() => {
+ if (!blob && !capturing && recordedChunks.length) {
+ blobSet(
+ new Blob(recordedChunks, {
+ type: "video/mp4",
+ })
+ );
+ }
+ }, [blob, capturing, recordedChunks]);
+
return (
-
handleClose(),
+ square: true,
}}
/>
-
-
+ ) : (
+
+
+
+ )}
+ ,
+
+ ,
+
+
-
- Record
-
- {recordedChunks.length > 0 && (
-
- )}
-
- {/* {capturing ? (
-
- ) : (
-
- )}
- {recordedChunks.length > 0 && (
-
- )}*/}
+ ,
+
+ error
+ ,
+ ][i];
+ })}
);
}
diff --git a/src/website/packages/fakeyou.com/src/components/modals/CameraCapture/CapturePreview.tsx b/src/website/packages/fakeyou.com/src/components/modals/CameraCapture/CapturePreview.tsx
new file mode 100644
index 0000000000..b0ea6bb6a3
--- /dev/null
+++ b/src/website/packages/fakeyou.com/src/components/modals/CameraCapture/CapturePreview.tsx
@@ -0,0 +1,46 @@
+import React from "react";
+import { a, SpringValues } from "@react-spring/web";
+import { Button } from "components/common";
+
+interface CapturePreviewProps {
+ blob: Blob | null;
+ resetCapture: () => void;
+ style: SpringValues;
+ upload: () => void;
+}
+
+export default function CapturePreview({
+ blob,
+ resetCapture,
+ style,
+ upload,
+}: CapturePreviewProps) {
+ if (blob) {
+ const url = URL.createObjectURL(blob);
+
+ return (
+
+
+
+ );
+ } else return null;
+}
diff --git a/src/website/packages/fakeyou.com/src/components/providers/ModalProvider/ModalLayer.scss b/src/website/packages/fakeyou.com/src/components/providers/ModalProvider/ModalLayer.scss
index 9eaf911443..f5232fe497 100644
--- a/src/website/packages/fakeyou.com/src/components/providers/ModalProvider/ModalLayer.scss
+++ b/src/website/packages/fakeyou.com/src/components/providers/ModalProvider/ModalLayer.scss
@@ -40,8 +40,8 @@
}
.fy-modal-body-square {
- width: 75vh;
- height: 75vh;
+ // width: 75vh;
+ // height: 75vh;
}
.fy-modal-body-wide,
@@ -56,7 +56,11 @@
box-shadow: 0px 9px 33px 1px rgba(19, 19, 27, 0.8);
-webkit-box-shadow: 0px 9px 33px 1px rgba(19, 19, 27, 0.8);
-moz-box-shadow: 0px 9px 33px 1px rgba(19, 19, 27, 0.8);
+ }
+ .fy-modal-body-wide,
+ .fy-modal-body-narrow,
+ .fy-modal-body-small {
padding: 1rem;
@include breakpoint($under992) {
diff --git a/src/website/packages/fakeyou.com/src/components/svg/WorkIndicator/WorkIndicator.scss b/src/website/packages/fakeyou.com/src/components/svg/WorkIndicator/WorkIndicator.scss
index 856ce02626..121b3baac5 100644
--- a/src/website/packages/fakeyou.com/src/components/svg/WorkIndicator/WorkIndicator.scss
+++ b/src/website/packages/fakeyou.com/src/components/svg/WorkIndicator/WorkIndicator.scss
@@ -1,17 +1,29 @@
@import "scss/colours.scss";
@import "scss/site-refresh.scss";
+.work-indicator-label {
+ align-items: center;
+ display: flex;
+ flex-direction: column;
+ position: relative;
+}
+
.work-indicator {
@include medium-svg;
- // height: 2.25rem;
- // width: 2.25rem;
- // fill: none;
+ position: relative;
- // circle, line, polyline {
- // stroke-width: 4px;
- // stroke-linecap: round;
- // stroke: #fff;
- // }
+ .work-indicator-progress {
+ text-align: center;
+ position: absolute;
+ font-size: 0.625rem;
+ line-height: 0.625rem;
+ height: 0.625rem;
+ top: 50%;
+ transform: translateY(-50%);
+ left: 0;
+ right: 0;
+ bottom: 0;
+ }
polyline {
transform: translate(6px, 6px);
diff --git a/src/website/packages/fakeyou.com/src/components/svg/WorkIndicator/WorkIndicator.tsx b/src/website/packages/fakeyou.com/src/components/svg/WorkIndicator/WorkIndicator.tsx
index 38f7d09239..20e11bf39b 100644
--- a/src/website/packages/fakeyou.com/src/components/svg/WorkIndicator/WorkIndicator.tsx
+++ b/src/website/packages/fakeyou.com/src/components/svg/WorkIndicator/WorkIndicator.tsx
@@ -1,37 +1,71 @@
import React from "react";
+import { a, useSpring } from "@react-spring/web";
import { AniX, Check, DashedCircle } from "components/svg";
import { circle } from "../sharedSVGProps";
import "./WorkIndicator.scss";
-interface Props {
+interface WorkIndicatorProps {
+ className?: string;
failure: boolean;
max?: number;
progressPercentage: number;
stage: number;
+ showPercentage?: boolean;
success: boolean;
}
-export default function WorkIndicator({
+interface WorkIndicatorWrapperProps extends WorkIndicatorProps {
+ label?: string;
+}
+
+const WorkIndicatorSpinner = ({
+ className,
failure = false,
max,
progressPercentage,
stage = 0,
+ showPercentage,
success = false,
...rest
-}: Props) {
+}: WorkIndicatorProps) => {
+ const style = useSpring({
+ opacity: showPercentage ? 1 : 0,
+ });
+
return (
-
-
-
-
-
-
+
+
+ {progressPercentage}%
+
+
+
+
+
+
+
+
+ );
+};
+
+export default function WorkIndicator({
+ label,
+ ...rest
+}: WorkIndicatorWrapperProps) {
+ return label ? (
+
+ {label}
+
+
+ ) : (
+
);
}
diff --git a/src/website/packages/fakeyou.com/src/hooks/useMediaUploader/useMediaUploader.tsx b/src/website/packages/fakeyou.com/src/hooks/useMediaUploader/useMediaUploader.tsx
index 82dfbf5ba1..f3905a8a86 100644
--- a/src/website/packages/fakeyou.com/src/hooks/useMediaUploader/useMediaUploader.tsx
+++ b/src/website/packages/fakeyou.com/src/hooks/useMediaUploader/useMediaUploader.tsx
@@ -98,6 +98,7 @@ export default function useMediaUploader({ autoUpload, onSuccess = n }: Props) {
return {
busy: status === FetchStatus.in_progress,
clear,
+ createUpload,
engineSubtype,
engineSubtypeChange,
error: status === FetchStatus.error,