+ ;
+};
\ No newline at end of file
diff --git a/packages/fakeyou.com/src/components/common/ImageInput/index.tsx b/packages/fakeyou.com/src/components/common/ImageInput/index.tsx
new file mode 100644
index 0000000000..4bcb609d53
--- /dev/null
+++ b/packages/fakeyou.com/src/components/common/ImageInput/index.tsx
@@ -0,0 +1 @@
+export { default } from './ImageInput';
diff --git a/packages/fakeyou.com/src/components/common/index.tsx b/packages/fakeyou.com/src/components/common/index.tsx
new file mode 100644
index 0000000000..5e570e82e2
--- /dev/null
+++ b/packages/fakeyou.com/src/components/common/index.tsx
@@ -0,0 +1,15 @@
+import AudioInput from './AudioInput';
+import ImageInput from './ImageInput';
+import FileActions from './FileActions';
+import FileDetails from './FileDetails';
+import FileWrapper from './FileWrapper';
+import FileLabel from './FileLabel';
+
+export {
+ AudioInput,
+ ImageInput,
+ FileActions,
+ FileDetails,
+ FileWrapper,
+ FileLabel
+};
\ No newline at end of file
diff --git a/packages/fakeyou.com/src/components/layout/PageHeader/PageHeader.tsx b/packages/fakeyou.com/src/components/layout/PageHeader/PageHeader.tsx
new file mode 100644
index 0000000000..e0c8b6e0e4
--- /dev/null
+++ b/packages/fakeyou.com/src/components/layout/PageHeader/PageHeader.tsx
@@ -0,0 +1,33 @@
+import React from "react";
+
+interface Props {
+ childProps?: any;
+ titleIcon?: JSX.Element;
+ titleComponent?: React.ComponentType;
+ title?: string;
+ subText: string;
+ showButtons: boolean;
+ actionButtons?: JSX.Element;
+}
+
+
+export default function PageHeader({ actionButtons, childProps, showButtons, subText, titleComponent: Title, title, titleIcon }: Props) {
+ return
+
+
+ { Title ? :
+ { titleIcon }
+ { title }
+
}
+
{ subText }
+ { showButtons && (
+
+ { actionButtons }
+
+ )}
+
+
+
;
+};
+
+// export default PageHeader;
diff --git a/packages/fakeyou.com/src/components/layout/PageHeader/index.js b/packages/fakeyou.com/src/components/layout/PageHeader/index.js
new file mode 100644
index 0000000000..58edd62eef
--- /dev/null
+++ b/packages/fakeyou.com/src/components/layout/PageHeader/index.js
@@ -0,0 +1 @@
+export { default } from './PageHeader';
\ No newline at end of file
diff --git a/packages/fakeyou.com/src/components/layout/index.tsx b/packages/fakeyou.com/src/components/layout/index.tsx
new file mode 100644
index 0000000000..110b9fc1d6
--- /dev/null
+++ b/packages/fakeyou.com/src/components/layout/index.tsx
@@ -0,0 +1,5 @@
+import PageHeader from './PageHeader';
+
+export {
+ PageHeader,
+};
\ No newline at end of file
diff --git a/packages/fakeyou.com/src/hooks/index.tsx b/packages/fakeyou.com/src/hooks/index.tsx
new file mode 100644
index 0000000000..bf9bef4f63
--- /dev/null
+++ b/packages/fakeyou.com/src/hooks/index.tsx
@@ -0,0 +1,5 @@
+import useFile from './useFile';
+import useId from './useId';
+import useIdempotency from './useIdempotency';
+
+export { useFile, useId, useIdempotency };
\ No newline at end of file
diff --git a/packages/fakeyou.com/src/hooks/useFile/index.tsx b/packages/fakeyou.com/src/hooks/useFile/index.tsx
new file mode 100644
index 0000000000..e10364a878
--- /dev/null
+++ b/packages/fakeyou.com/src/hooks/useFile/index.tsx
@@ -0,0 +1 @@
+export { default } from "./useFile";
\ No newline at end of file
diff --git a/packages/fakeyou.com/src/hooks/useFile/useFile.tsx b/packages/fakeyou.com/src/hooks/useFile/useFile.tsx
new file mode 100644
index 0000000000..f75d512939
--- /dev/null
+++ b/packages/fakeyou.com/src/hooks/useFile/useFile.tsx
@@ -0,0 +1,53 @@
+import { useRef, useState } from 'react';
+
+const n = (o: any) => o;
+
+interface Props {
+ debug?: any;
+ onChange?: (file: any) => void;
+ onClear?: (x?: any) => void;
+ onSubmit?: (file: any) => boolean;
+}
+
+export default function useFile({ debug, onChange = n, onClear = n, onSubmit = n }: Props) {
+ const [file, fileSet] = useState(undefined);
+ const [blob, blobSet] = useState();
+ const [working, workingSet] = useState(false);
+ const [success, successSet] = useState(false);
+ const inputRef = useRef(null);
+
+ const submit = async () => {
+ if (file === undefined) { return false; }
+ const onUploadResult = await onSubmit(file);
+ workingSet(true);
+ if (onUploadResult) { successSet(true); }
+ successSet(false);
+ };
+ const fileChange = (inputFile?: any) => {
+ onChange(file);
+ fileSet(inputFile || null);
+ blobSet(inputFile ? URL.createObjectURL(inputFile) : "");
+ successSet(false);
+ };
+ const inputChange = ({ target = {} }: { target: any }) => {
+ fileChange(target.value);
+ };
+ const clear = () => {
+ if (inputRef?.current?.value) inputRef.current.value = '';
+ fileChange();
+ onClear();
+ };
+
+ return {
+ blob,
+ clear,
+ file,
+ inputProps: {
+ onChange: inputChange,
+ inputRef
+ },
+ submit,
+ success,
+ working,
+ };
+};
\ No newline at end of file
diff --git a/packages/fakeyou.com/src/hooks/useId/index.tsx b/packages/fakeyou.com/src/hooks/useId/index.tsx
new file mode 100644
index 0000000000..bf8a1630ed
--- /dev/null
+++ b/packages/fakeyou.com/src/hooks/useId/index.tsx
@@ -0,0 +1 @@
+export { default } from './useId';
diff --git a/packages/fakeyou.com/src/hooks/useId/useId.tsx b/packages/fakeyou.com/src/hooks/useId/useId.tsx
new file mode 100644
index 0000000000..57852ce56f
--- /dev/null
+++ b/packages/fakeyou.com/src/hooks/useId/useId.tsx
@@ -0,0 +1,15 @@
+import { useEffect, useState } from 'react';
+
+const S4 = () => (((1+Math.random())*0x10000)|0).toString(16).substring(1);
+
+export default function useId() {
+ const [id,idSet] = useState();
+
+ useEffect(() => {
+ if (!id) idSet(S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
+ },[id]);
+
+ return id;
+};
+
+// based on https://stackoverflow.com/questions/6860853/generate-random-string-for-div-id/6860916#6860916
\ No newline at end of file
diff --git a/packages/fakeyou.com/src/hooks/useIdempotency/index.tsx b/packages/fakeyou.com/src/hooks/useIdempotency/index.tsx
new file mode 100644
index 0000000000..fe06c4c25a
--- /dev/null
+++ b/packages/fakeyou.com/src/hooks/useIdempotency/index.tsx
@@ -0,0 +1 @@
+export { default } from './useIdempotency';
diff --git a/packages/fakeyou.com/src/hooks/useIdempotency/useIdempotency.tsx b/packages/fakeyou.com/src/hooks/useIdempotency/useIdempotency.tsx
new file mode 100644
index 0000000000..0f264b57a0
--- /dev/null
+++ b/packages/fakeyou.com/src/hooks/useIdempotency/useIdempotency.tsx
@@ -0,0 +1,7 @@
+import { useState } from 'react';
+import { v4 as uuidv4 } from "uuid";
+
+export default function useIdempotency() {
+ const [token, set] = useState(uuidv4());
+ return { reset: () => set(uuidv4()), set, token };
+};
\ No newline at end of file
diff --git a/packages/fakeyou.com/src/v2/view/PageContainer.tsx b/packages/fakeyou.com/src/v2/view/PageContainer.tsx
index 5210ac206b..10dc7ec360 100644
--- a/packages/fakeyou.com/src/v2/view/PageContainer.tsx
+++ b/packages/fakeyou.com/src/v2/view/PageContainer.tsx
@@ -6,6 +6,7 @@ import { LoginPage } from "./pages/login/LoginPage";
import { ModerationFc } from "./pages/moderation/moderation_main/ModerationFc";
import { ModerationIpBanListFc } from "./pages/moderation/moderation_ip_ban_list/ModerationIpBanListFc";
import { ModerationViewIpBanFc } from "./pages/moderation/moderation_view_ip_ban/ModerationViewIpBanFc";
+import { LipsyncEditor } from "./pages/lipsync";
import { FooterNav } from "./nav/FooterNav";
import { TopNav } from "./nav/TopNav";
import { ProfileEditFc } from "./pages/profile/profile_edit/ProfileEditFc";
@@ -429,6 +430,10 @@ class PageContainer extends React.Component {
+
+
+
+
;
+
+const Title = ({ ...rest }) => {
+ const { audioFile, imageFile } = rest;
+
+ return
+
+ Generate a lipsync
+
+
+
+
+ Image
+
+
+
+ Audio
+
+
+
+
+};
+
+export default function LipsyncEditor({ ...rest }) {
+ const audioProps = useFile({ debug: 'audio useFile' });
+ const imageProps = useFile({});
+
+ const subText = "Select an image with a clear face, or one of our existing templates, then choose either text to speech or uploaded audio(eg. music). Then you can generate a beautifully lipsynced video.";
+ const headerProps = {
+ childProps: { audioFile: !audioProps.file, imageFile: !imageProps.file },
+ titleComponent: Title,
+ subText,
+ showButtons: false
+ };
+
+ return
+
+
+
+
+
Image
+
+
+
Audio
+
+
+
+
+
+
+
+
+
+
;
+};
\ No newline at end of file
diff --git a/packages/fakeyou.com/src/v2/view/pages/lipsync/LipsyncEditor/index.tsx b/packages/fakeyou.com/src/v2/view/pages/lipsync/LipsyncEditor/index.tsx
new file mode 100644
index 0000000000..02f8db5b47
--- /dev/null
+++ b/packages/fakeyou.com/src/v2/view/pages/lipsync/LipsyncEditor/index.tsx
@@ -0,0 +1 @@
+export { default } from './LipsyncEditor';
\ No newline at end of file
diff --git a/packages/fakeyou.com/src/v2/view/pages/lipsync/index.tsx b/packages/fakeyou.com/src/v2/view/pages/lipsync/index.tsx
new file mode 100644
index 0000000000..e9598cfc23
--- /dev/null
+++ b/packages/fakeyou.com/src/v2/view/pages/lipsync/index.tsx
@@ -0,0 +1,3 @@
+import LipsyncEditor from './LipsyncEditor';
+
+export { LipsyncEditor };
\ No newline at end of file