diff --git a/frontend/src/bundles/auth/components/common/form-header/form-header.module.css b/frontend/src/bundles/auth/components/common/form-header/form-header.module.css new file mode 100644 index 000000000..c4f581cf5 --- /dev/null +++ b/frontend/src/bundles/auth/components/common/form-header/form-header.module.css @@ -0,0 +1,14 @@ +.logo { + margin-bottom: 50px; +} + +.heading { + color: white; + margin-bottom: 6px; + font-size: 30px; +} + +.text { + margin-bottom: 24px; + font-size: 14px; +} diff --git a/frontend/src/bundles/common/components/components.ts b/frontend/src/bundles/common/components/components.ts index 8a84da077..627bb0220 100644 --- a/frontend/src/bundles/common/components/components.ts +++ b/frontend/src/bundles/common/components/components.ts @@ -44,6 +44,7 @@ export { Input as LibraryInput, Link as LibraryLink, Modal as LibraryModal, + ListItem, Menu, MenuButton, MenuItem, @@ -67,6 +68,7 @@ export { Tabs, Text, Tooltip, + UnorderedList, VStack, } from '@chakra-ui/react'; export { Player as LibraryPlayer } from '@remotion/player'; diff --git a/frontend/src/bundles/common/components/header/header.module.css b/frontend/src/bundles/common/components/header/header.module.css new file mode 100644 index 000000000..7319f2acb --- /dev/null +++ b/frontend/src/bundles/common/components/header/header.module.css @@ -0,0 +1,19 @@ +.header { + height: 75px; + position: sticky; + top: 0; + left: 0; + width: 100%; + background-color: var(--chakra-colors-background-900); + box-shadow: var(--chakra-shadows-md); + z-index: 100; + padding: var(--chakra-space-4); + align-items: center; + justify-content: space-between; +} + +.logoText { + font-size: var(--chakra-fontSizes-xl); + font-weight: var(--chakra-fontWeights-lighter); + color: var(--chakra-colors-white); +} diff --git a/frontend/src/bundles/common/components/sidebar/sidebar.module.css b/frontend/src/bundles/common/components/sidebar/sidebar.module.css new file mode 100644 index 000000000..3b7d97da8 --- /dev/null +++ b/frontend/src/bundles/common/components/sidebar/sidebar.module.css @@ -0,0 +1,38 @@ +.sidebarContainer { + background-color: var(--chakra-colors-background-900); + height: calc(100vh - 75px); + position: fixed; + display: flex; + flex-direction: column; + justify-content: space-between; + padding: 10px; + padding-bottom: 20px; +} + +.userBox { + margin-bottom: 30px; +} + +.contentBox { + flex: 1; +} + +.sidebarItem { + width: 100%; + height: 50px; + display: flex; + align-items: center; + gap: 10px; + font-size: 1rem; + font-weight: bold; + border-radius: 10px; + padding: 10px; +} + +.itemJustifyCenter { + justify-content: center; +} + +.itemJustifyStart { + justify-content: flex-start; +} diff --git a/frontend/src/bundles/common/components/upload-video/components/video-player/components/control/libs/hooks/hooks.ts b/frontend/src/bundles/common/components/upload-video/components/video-player/components/control/libs/hooks/hooks.ts new file mode 100644 index 000000000..fac0b689c --- /dev/null +++ b/frontend/src/bundles/common/components/upload-video/components/video-player/components/control/libs/hooks/hooks.ts @@ -0,0 +1 @@ +export { useAnimationFrame } from './use-animation-frame.js'; diff --git a/frontend/src/bundles/common/components/upload-video/components/video-player/components/control/libs/hooks/use-animation-frame.ts b/frontend/src/bundles/common/components/upload-video/components/video-player/components/control/libs/hooks/use-animation-frame.ts new file mode 100644 index 000000000..fef569486 --- /dev/null +++ b/frontend/src/bundles/common/components/upload-video/components/video-player/components/control/libs/hooks/use-animation-frame.ts @@ -0,0 +1,29 @@ +import { + useCallback, + useEffect, + useRef, +} from '~/bundles/common/hooks/hooks.js'; + +const useAnimationFrame = ( + nextAnimationFrameHandler: () => void, + shouldAnimate = true, +): void => { + const frame = useRef(0); + + const animate = useCallback((): void => { + nextAnimationFrameHandler(); + frame.current = requestAnimationFrame(animate); + }, [nextAnimationFrameHandler]); + + useEffect(() => { + if (shouldAnimate) { + frame.current = requestAnimationFrame(animate); + } else { + cancelAnimationFrame(frame.current); + } + + return (): void => cancelAnimationFrame(frame.current); + }, [animate, shouldAnimate]); +}; + +export { useAnimationFrame }; diff --git a/frontend/src/bundles/common/components/video-modal/video-modal.module.css b/frontend/src/bundles/common/components/video-modal/video-modal.module.css new file mode 100644 index 000000000..ae2b90bc1 --- /dev/null +++ b/frontend/src/bundles/common/components/video-modal/video-modal.module.css @@ -0,0 +1,108 @@ +.previewContainer { + display: flex; + flex-direction: column; + align-items: center; +} + +.previewBox { + height: 444px; + border-width: 1px; + border-color: var(--chakra-colors-gray-300); + border-radius: var(--chakra-radii-md); + justify-content: center; + align-items: center; + margin-bottom: var(--chakra-space-4); +} + +.previewInnerBox { + display: flex; + flex-direction: column; + align-items: center; + color: var(--chakra-colors-gray-400); +} + +.previewIcon { + padding: 5px; + height: 16px; +} + +.previewText { + color: var(--chakra-colors-gray-400); +} + +.previewButtonContainer { + display: flex; + justify-content: center; + gap: var(--chakra-space-4); +} + +.previewButton { + background-color: var(--chakra-colors-brand-secondary-300); + color: white; +} + +.previewButton:hover { + background-color: var(--chakra-colors-brand-secondary-600); +} + +.scriptFormContainer { + width: 256px; + margin-top: 20px; +} + +.scriptFormTextareaTopic { + height: 84px; +} + +.scriptFormTextareaAdditionalInfo { + height: 64px; +} + +.scriptPlaceholderContainer { + width: 100%; + padding: 40px; + gap: 10px; +} + +.scriptPlaceholderIcon { + color: var(--chakra-colors-brand-secondary-300); + opacity: 0.5; + font-size: 2rem; +} + +.scriptPlaceholderText { + color: var(--chakra-colors-gray-400); + width: 40%; + min-width: 175px; + text-align: center; + font-style: italic; +} +.scriptViewHeading { + color: var(--chakra-colors-typography-900); + padding: 33px 0px 20px; +} + +.scriptViewTabList { + width: max-content; + background-color: var(--chakra-colors-gray-100); + border-width: 1px; + border-radius: var(--chakra-radii-md); + padding: var(--chakra-space-1); + gap: 10px; +} + +.scriptViewTab { + border-radius: var(--chakra-radii-md); + padding-left: var(--chakra-space-4); + padding-right: var(--chakra-space-4); + padding-top: var(--chakra-space-1); + padding-bottom: var(--chakra-space-1); +} + +.scriptViewTabPanel { + padding: 0; +} + +.scriptViewHStack { + justify-content: space-between; +} diff --git a/frontend/src/bundles/common/enums/app-route.enum.ts b/frontend/src/bundles/common/enums/app-route.enum.ts index 21140bf1e..d6526128a 100644 --- a/frontend/src/bundles/common/enums/app-route.enum.ts +++ b/frontend/src/bundles/common/enums/app-route.enum.ts @@ -5,6 +5,7 @@ const AppRoute = { STUDIO: '/studio', MY_AVATAR: '/my-avatar', ANY: '*', + CREATE_AVATAR: '/create-avatar', } as const; export { AppRoute }; diff --git a/frontend/src/bundles/common/icons/icon-name.ts b/frontend/src/bundles/common/icons/icon-name.ts index d7129229a..c0a541f54 100644 --- a/frontend/src/bundles/common/icons/icon-name.ts +++ b/frontend/src/bundles/common/icons/icon-name.ts @@ -2,6 +2,7 @@ import { AddIcon, ArrowLeftIcon, ArrowRightIcon, + CheckCircleIcon, CloseIcon, DownloadIcon, ViewIcon, @@ -58,6 +59,7 @@ const IconName = { TEXT: T, ADD: AddIcon, CLOSE: CloseIcon, + CHECK_CIRCLE: CheckCircleIcon, OPEN_AI: OpenAi, LOGO: Logo, LOGO_TEXT: LogoText, diff --git a/frontend/src/bundles/create-avatar/components/components.ts b/frontend/src/bundles/create-avatar/components/components.ts new file mode 100644 index 000000000..db0a242a4 --- /dev/null +++ b/frontend/src/bundles/create-avatar/components/components.ts @@ -0,0 +1 @@ +export { Instruction } from './instruction/instruction.js'; diff --git a/frontend/src/bundles/create-avatar/components/instruction-list/instruction-list.tsx b/frontend/src/bundles/create-avatar/components/instruction-list/instruction-list.tsx new file mode 100644 index 000000000..e44f88cf3 --- /dev/null +++ b/frontend/src/bundles/create-avatar/components/instruction-list/instruction-list.tsx @@ -0,0 +1,44 @@ +import { + Box, + Flex, + Icon, + ListItem, + Text, + UnorderedList, +} from '~/bundles/common/components/components.js'; +import { IconName } from '~/bundles/common/icons/icons.js'; + +import styles from './styles.module.css'; + +interface InstructionListProperties { + color: string; + listItems: string[]; + title: string; +} + +const InstructionList: React.FC = ({ + color, + listItems, + title, +}) => ( + + + + + {title} + + + + {listItems.map((item, index) => ( + {item} + ))} + + +); + +export { InstructionList }; diff --git a/frontend/src/bundles/create-avatar/components/instruction-list/styles.module.css b/frontend/src/bundles/create-avatar/components/instruction-list/styles.module.css new file mode 100644 index 000000000..fef68f410 --- /dev/null +++ b/frontend/src/bundles/create-avatar/components/instruction-list/styles.module.css @@ -0,0 +1,4 @@ +.icon { + border-radius: 50%; + background-color: white; +} diff --git a/frontend/src/bundles/create-avatar/components/instruction/instruction.tsx b/frontend/src/bundles/create-avatar/components/instruction/instruction.tsx new file mode 100644 index 000000000..bd8675bd8 --- /dev/null +++ b/frontend/src/bundles/create-avatar/components/instruction/instruction.tsx @@ -0,0 +1,45 @@ +import { Button, Flex } from '~/bundles/common/components/components.js'; + +import { InstructionList } from '../instruction-list/instruction-list.js'; +import styles from './styles.module.css'; + +const screenshotListItems = [ + 'At least 5 minutes of footage', + 'High resolution camera', + 'Well-lit quiet environment', + 'Keep your head centered in the frame', + 'Ensure face visibility; do not cover your mouth', + 'Use a tripod or stabilize your phone to avoid shaking', +]; + +const avoidListItems = [ + 'Stitches or cuts of your footage', + 'Talking without pauses', + 'Fast head movements', + 'Loud background noise like music', + 'Shadows or overexposure on your face', + 'Diverting your gaze or looking around', + 'Hand gestures above the chest or pointing gestures', +]; + +const Instruction: React.FC = () => { + return ( + + + + + +