Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OV-29: Add Video Items Menu #48

Merged
merged 36 commits into from
Aug 30, 2024
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
aae16c7
OV-29: + routing to video editor view
lfelix3011 Aug 21, 2024
e2ec702
OV-29: + script to use lint fix
lfelix3011 Aug 21, 2024
b0e6fbf
OV-29: + use of new components of chackra ui
lfelix3011 Aug 21, 2024
8f5e21b
OV-29: + simple menu for vidao editor
lfelix3011 Aug 21, 2024
3dd913d
OV-29: + mock components for the menu body
lfelix3011 Aug 21, 2024
d318403
OV-29: + simple menu body for video editor
lfelix3011 Aug 21, 2024
cbe63e4
OV-29: + creating video editor component to use menu and menu body
lfelix3011 Aug 21, 2024
f4bf456
Merge branch 'next' of https://github.com/BinaryStudioAcademy/bsa-202…
lfelix3011 Aug 21, 2024
23f8426
OV-29: + components to create icon from svg
lfelix3011 Aug 22, 2024
b6ea3d8
OV-29: + new mock for header component
lfelix3011 Aug 22, 2024
1d4db78
OV-29: * script for lint
lfelix3011 Aug 22, 2024
fd6cf4f
OV-29: + menu-item types on it on folder
lfelix3011 Aug 22, 2024
394b92f
OV-29: * styles for menu component
lfelix3011 Aug 22, 2024
a0e0f82
OV-29: * styles for menu-body component
lfelix3011 Aug 22, 2024
da525ad
OV-29: * header can be string o other component for video-editor
lfelix3011 Aug 22, 2024
b702100
OV-29: + utilities methods to validate array and obj
lfelix3011 Aug 22, 2024
dd6dde1
OV-29: * show and remove active element of meu
lfelix3011 Aug 22, 2024
5bbe156
OV-29: * prettier adjusments
lfelix3011 Aug 22, 2024
61fd859
OV-29: * use of icons of FontAwsome as suggested
lfelix3011 Aug 23, 2024
a24b6c7
OV-29: * better strcuture for helpers methods
lfelix3011 Aug 23, 2024
6ac97d0
OV-29: * change of properties type name
lfelix3011 Aug 23, 2024
155e002
OV-29: * use h3 styles variant of heading
lfelix3011 Aug 23, 2024
d989e6c
OV-29: * use of icons of FontAwsome as suggested
lfelix3011 Aug 23, 2024
0705414
Merge branch 'next' of https://github.com/BinaryStudioAcademy/bsa-202…
lfelix3011 Aug 23, 2024
634bdfb
OV-29: + new video editor route
lfelix3011 Aug 23, 2024
80b0bcf
OV-29: * remove as suggested in review all helpers of null and undefi…
lfelix3011 Aug 23, 2024
090e086
OV-29: * add a separted folder for icons
lfelix3011 Aug 23, 2024
e9de78c
OV-29: * use of prettier
lfelix3011 Aug 23, 2024
2b3dbd3
OV-29: * abstract uses of icons
lfelix3011 Aug 27, 2024
30c8d15
OV-29: - Remove rout of video editor
lfelix3011 Aug 27, 2024
055b4f3
OV-29: * changes of properties names suggested on review of PR
lfelix3011 Aug 27, 2024
3be1022
OV-29: * changes of properties names suggested on review of PR
lfelix3011 Aug 27, 2024
9b2447b
OV-29: * changes of prettier
lfelix3011 Aug 27, 2024
29deaab
Merge branch 'next' of https://github.com/BinaryStudioAcademy/bsa-202…
lfelix3011 Aug 27, 2024
6f90893
OV-29: - inncesary using as icon
lfelix3011 Aug 27, 2024
e30edef
Merge branch 'next' of https://github.com/BinaryStudioAcademy/bsa-202…
lfelix3011 Aug 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import {
Icon,
IconButton,
Input,
InputGroup,
InputRightElement,
ViewIcon,
ViewOffIcon,
} from '~/bundles/common/components/components.js';
import { useCallback, useState } from '~/bundles/common/hooks/hooks.js';
import { IconMap } from '~/bundles/common/icons/icons.js';

type Properties = {
label: string;
Expand Down Expand Up @@ -37,7 +37,14 @@ const PasswordInput: React.FC<Properties> = ({ label, name, hasError }) => {
aria-label={
isPasswordVisible ? 'Hide password' : 'Show password'
}
icon={isPasswordVisible ? <ViewIcon /> : <ViewOffIcon />}
as={Icon}
icon={
isPasswordVisible ? (
<Icon as={IconMap.VIEW} />
) : (
<Icon as={IconMap.VIEW_OFF} />
)
}
onClick={handlePasswordIconClick}
variant="ghostIcon"
/>
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/bundles/common/components/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,26 @@ export { Overlay } from './overlay/overlay.js';
export { Player } from './player/player.js';
export { RouterProvider } from './router-provider/router-provider.js';
export { VideoModal } from './video-modal/video-modal.js';
export { DownloadIcon } from '@chakra-ui/icons';
export { ViewIcon, ViewOffIcon } from '@chakra-ui/icons';
export {
Box,
Center,
Circle,
CloseButton,
Collapse,
ChakraProvider as ComponentsProvider,
Flex,
FormControl,
FormErrorMessage,
Heading,
Icon,
IconButton,
InputGroup,
InputRightElement,
SimpleGrid,
Text,
VStack,
} from '@chakra-ui/react';
export { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
export { FormikProvider as FormProvider } from 'formik';
export { Provider as StoreProvider } from 'react-redux';
export { Outlet as RouterOutlet } from 'react-router-dom';
1 change: 1 addition & 0 deletions frontend/src/bundles/common/enums/app-route.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const AppRoute = {
SIGN_IN: '/sign-in',
SIGN_UP: '/sign-up',
STUDIO: '/studio',
VIDEO_EDITOR: '/video-editor',
ANY: '*',
} as const;

Expand Down
21 changes: 21 additions & 0 deletions frontend/src/bundles/common/icons/icons-map.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { DownloadIcon, ViewIcon, ViewOffIcon } from '@chakra-ui/icons';
import {
faCircleUser,
faCloudArrowUp,
faFont,
faT,
faTableColumns,
} from '@fortawesome/free-solid-svg-icons';

const IconMap = {
DOWNLOAD: DownloadIcon,
VIEW: ViewIcon,
VIEW_OFF: ViewOffIcon,
AVATAR: faCircleUser,
UPLOAD: faCloudArrowUp,
TEMPLATE: faTableColumns,
SCRIPT: faFont,
TEXT: faT,
} as const;

export { IconMap };
1 change: 1 addition & 0 deletions frontend/src/bundles/common/icons/icons.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { IconMap } from './icons-map.js';
5 changes: 3 additions & 2 deletions frontend/src/bundles/studio/pages/studio.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import {
Button,
DownloadIcon,
Header,
Icon,
IconButton,
} from '~/bundles/common/components/components.js';
import { IconMap } from '~/bundles/common/icons/icons.js';

const Studio: React.FC = () => {
return (
Expand All @@ -20,7 +21,7 @@ const Studio: React.FC = () => {
<IconButton
variant="primaryOutlined"
aria-label="Download"
icon={<DownloadIcon />}
icon={<Icon as={IconMap.DOWNLOAD} />}
/>
}
/>
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/bundles/video-editor/components/components.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { Menu } from './menu/menu.js';
export { MenuBody } from './menu-body/menu-body.js';
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import {
Box,
CloseButton,
Flex,
Heading,
VStack,
} from '~/bundles/common/components/components.js';

type Properties = {
title: string | React.ReactNode;
children: React.ReactNode;
isOpen: boolean;
onClose: () => void;
};

const MenuBody: React.FC<Properties> = ({
title,
children,
isOpen,
onClose,
}) => {
return (
<>
{isOpen && (
<Box
sx={{
position: 'fixed',
top: '50%',
transform: 'translateY(-50%)',
left: '100px',
height: '72vh',
width: '335px',
p: 2,
zIndex: 1000,
borderRadius: '8px',
boxShadow: 'lg',
bg: 'background.900',
color: 'white',
}}
>
<Flex justifyContent="space-between" alignItems="center">
<Heading as="h3">{title}</Heading>
<CloseButton onClick={onClose} color="background.600" />
</Flex>
<VStack mt={4} spacing={4} align="start">
{children}
</VStack>
</Box>
)}
</>
);
};

export { MenuBody };
89 changes: 89 additions & 0 deletions frontend/src/bundles/video-editor/components/menu/menu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { Box, Flex, VStack } from '~/bundles/common/components/components.js';
import { useCallback } from '~/bundles/common/hooks/hooks.js';

import { type MenuItem } from '../../types/types.js';

type Properties = {
items: MenuItem[];
activeIndex: number | null;
setActiveIndex: (index: number) => void;
};

const Menu: React.FC<Properties> = ({ items, activeIndex, setActiveIndex }) => {
const handleClick = useCallback(
(index: number) => {
return () => {
if (!items || items.length === 0 || index >= items.length) {
return;
}

const item = items[index];
if (!item) {
return;
}

setActiveIndex(index);
item.onClick();
};
},
[setActiveIndex, items],
);
return (
<Box
sx={{
position: 'fixed',
left: 0,
top: '50%',
transform: 'translateY(-50%)',
h: 'auto',
w: '84px',
bg: 'background.900',
color: 'white',
borderTopRightRadius: 'xl',
borderBottomRightRadius: 'xl',
}}
>
<VStack spacing={1} align="stretch" p={2} w="100%">
{items.map((item, index) => (
<Flex
key={index}
onClick={handleClick(index)}
sx={{
flexDirection: 'column',
alignItems: 'center',
p: 2,
w: '66px',
gap: 1,
cursor: 'pointer',
borderRadius: '8px',
bg:
activeIndex === index
? 'background.600'
: 'transparent',
_hover: {
bg: 'background.600',
},
}}
>
<Box
sx={{
fontSize: 'xl',
}}
>
{item.icon}
</Box>
<Box
sx={{
fontSize: '12px',
}}
>
{item.label}
</Box>
</Flex>
))}
</VStack>
</Box>
);
};

export { Menu };
31 changes: 31 additions & 0 deletions frontend/src/bundles/video-editor/components/mock/menu-mock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {
Flex,
FontAwesomeIcon,
Icon,
} from '~/bundles/common/components/components.js';
import { IconMap } from '~/bundles/common/icons/icons.js';

const TemplatesContent: React.FC = () => (
<div>This is the Templates content.</div>
);
const AvatarsContent: React.FC = () => <div>This is the Avatars content.</div>;
const ScriptHeader: React.FC = () => (
<Flex justifyContent={'space-between'} w={'280px'}>
<div>Script</div>
<div>
<Icon as={FontAwesomeIcon} icon={IconMap.UPLOAD} />
</div>
</Flex>
);
const ScriptContent: React.FC = () => <div>This is the Script content.</div>;
const TextContent: React.FC = () => <div>This is the Text content.</div>;
const AssetsContent: React.FC = () => <div>This is the Assets content.</div>;

export {
AssetsContent,
AvatarsContent,
ScriptContent,
ScriptHeader,
TemplatesContent,
TextContent,
};
89 changes: 89 additions & 0 deletions frontend/src/bundles/video-editor/pages/video-editor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import {
FontAwesomeIcon,
Icon,
} from '~/bundles/common/components/components.js';
import { useCallback, useState } from '~/bundles/common/hooks/hooks.js';
import { IconMap } from '~/bundles/common/icons/icons.js';

import { Menu, MenuBody } from '../components/components.js';
import {
AssetsContent,
AvatarsContent,
ScriptContent,
ScriptHeader,
TemplatesContent,
TextContent,
} from '../components/mock/menu-mock.js';
import { type MenuItem } from '../types/menu-item.type.js';

const VideoEditor: React.FC = () => {
const [activeIndex, setActiveIndex] = useState<number | null>(null);
const [activeContent, setActiveContent] = useState<React.ReactNode | null>(
null,
);
const [activeTitle, setActiveTitle] = useState<string | React.ReactNode>(
Copy link
Collaborator

@Sanchousina Sanchousina Aug 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the states are related data, like here title and content, wouldn't it be better to store it as an object?

'',
);
const [isOpen, setIsOpen] = useState(false);

const handleMenuClick = (
header: string | React.ReactNode,
content: React.ReactNode,
): void => {
setActiveContent(content);
setActiveTitle(header);
setIsOpen(true);
};

const resetActiveItem = useCallback((): void => {
setIsOpen(false);
setActiveIndex(null);
}, []);

const menuItems: MenuItem[] = [
{
label: 'Templates',
icon: <Icon as={FontAwesomeIcon} icon={IconMap.TEMPLATE} />,
onClick: () => handleMenuClick('Templates', <TemplatesContent />),
},
{
label: 'Avatars',
icon: <Icon as={FontAwesomeIcon} icon={IconMap.AVATAR} />,
onClick: () => handleMenuClick('Avatars', <AvatarsContent />),
},
{
label: 'Script',
icon: <Icon as={FontAwesomeIcon} icon={IconMap.SCRIPT} />,
onClick: () => handleMenuClick(<ScriptHeader />, <ScriptContent />),
},
{
label: 'Text',
icon: <Icon as={FontAwesomeIcon} icon={IconMap.TEXT} />,
onClick: () => handleMenuClick('Text', <TextContent />),
},
{
label: 'Assets',
icon: <Icon as={FontAwesomeIcon} icon={IconMap.UPLOAD} />,
onClick: () => handleMenuClick('Assets', <AssetsContent />),
},
];

return (
<>
<Menu
items={menuItems}
activeIndex={activeIndex}
setActiveIndex={setActiveIndex}
/>
<MenuBody
title={activeTitle}
isOpen={isOpen}
onClose={resetActiveItem}
>
{activeContent}
</MenuBody>
</>
);
};

export { VideoEditor };
7 changes: 7 additions & 0 deletions frontend/src/bundles/video-editor/types/menu-item.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
type MenuItem = {
label: string;
icon: React.ReactNode;
onClick: () => void;
};

export { type MenuItem };
1 change: 1 addition & 0 deletions frontend/src/bundles/video-editor/types/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { type MenuItem } from './menu-item.type.js';
Loading
Loading