diff --git a/frontend/webapp/app/globals.css b/frontend/webapp/app/globals.css index 27185356f..6bbdf7e7c 100644 --- a/frontend/webapp/app/globals.css +++ b/frontend/webapp/app/globals.css @@ -1,4 +1,4 @@ /* Preload key fonts in your global CSS */ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap'); -@import url('https://fonts.googleapis.com/css2?family=Kode+Mono:wght@400;700&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=Kode+Mono:wght@100;200;300;400;500;600;700&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Inter+Tight:wght@400;700&display=swap'); diff --git a/frontend/webapp/components/setup/headers/header/index.tsx b/frontend/webapp/components/setup/headers/header/index.tsx index 29bd04789..722a27586 100644 --- a/frontend/webapp/components/setup/headers/header/index.tsx +++ b/frontend/webapp/components/setup/headers/header/index.tsx @@ -1,12 +1,11 @@ -import { Button, Text } from '@/reuseable-components'; -import theme from '@/styles/theme'; import Image from 'next/image'; import React from 'react'; import styled from 'styled-components'; +import { NavigationButtons, Text } from '@/reuseable-components'; interface SetupHeaderProps { - onBack?: () => void; - onNext?: () => void; + onBack: () => void; + onNext: () => void; } const HeaderContainer = styled.div` @@ -21,24 +20,12 @@ const HeaderContainer = styled.div` const Title = styled(Text)``; -const HeaderButton = styled(Button)` - display: flex; - align-items: center; - gap: 8px; -`; - const Logo = styled.div` display: flex; align-items: center; font-size: 1.2em; `; -const NavigationButtons = styled.div` - display: flex; - gap: 8px; - align-items: center; -`; - export const SetupHeader: React.FC = ({ onBack, onNext }) => { return ( @@ -51,40 +38,22 @@ export const SetupHeader: React.FC = ({ onBack, onNext }) => { /> START WITH ODIGOS - - - back - - BACK - - - - - NEXT - - next - - + ); }; diff --git a/frontend/webapp/containers/main/destinations/choose-destination/index.tsx b/frontend/webapp/containers/main/destinations/choose-destination/index.tsx index adcd566bf..c2fc0be52 100644 --- a/frontend/webapp/containers/main/destinations/choose-destination/index.tsx +++ b/frontend/webapp/containers/main/destinations/choose-destination/index.tsx @@ -1,5 +1,11 @@ import React, { useEffect, useState } from 'react'; -import { Button, SectionTitle, Text } from '@/reuseable-components'; +import { + Button, + Modal, + NavigationButtons, + SectionTitle, + Text, +} from '@/reuseable-components'; import styled from 'styled-components'; import Image from 'next/image'; import theme from '@/styles/theme'; @@ -21,6 +27,14 @@ const AddDestinationButton = styled(Button)` export function ChooseDestinationContainer() { const { data, loading, error } = useQuery(GET_DESTINATION_TYPE); + const [isModalOpen, setModalOpen] = useState(false); + + const handleOpenModal = () => setModalOpen(true); + const handleCloseModal = () => setModalOpen(false); + const handleSubmit = () => { + console.log('Action submitted'); + setModalOpen(false); + }; useEffect(() => { if (error) { @@ -36,7 +50,10 @@ export function ChooseDestinationContainer() { description="Add backend destinations where collected data will be sent and configure their settings." /> - + handleOpenModal()} + > back + {}, + // variant: 'secondary', + // }, + { + label: 'NEXT', + iconSrc: '/icons/common/arrow-black.svg', + onClick: () => {}, + variant: 'primary', + }, + ]} + /> + } + header={{ + title: 'Modal Title', + }} + onClose={handleCloseModal} + > +

This is the modal content.

+
); diff --git a/frontend/webapp/public/icons/common/x.svg b/frontend/webapp/public/icons/common/x.svg new file mode 100644 index 000000000..26ea41f62 --- /dev/null +++ b/frontend/webapp/public/icons/common/x.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/webapp/reuseable-components/index.ts b/frontend/webapp/reuseable-components/index.ts index 4090df8fb..4cf8e0bd3 100644 --- a/frontend/webapp/reuseable-components/index.ts +++ b/frontend/webapp/reuseable-components/index.ts @@ -8,3 +8,5 @@ export * from './divider'; export * from './counter'; export * from './toggle'; export * from './checkbox'; +export * from './modal'; +export * from './navigation-buttons'; diff --git a/frontend/webapp/reuseable-components/modal/index.tsx b/frontend/webapp/reuseable-components/modal/index.tsx new file mode 100644 index 000000000..68d08a1cd --- /dev/null +++ b/frontend/webapp/reuseable-components/modal/index.tsx @@ -0,0 +1,129 @@ +import React from 'react'; +import Image from 'next/image'; +import { Text } from '../text'; +import ReactDOM from 'react-dom'; +import styled from 'styled-components'; +import { Button } from '../button'; + +interface ModalProps { + isOpen: boolean; + header: { + title: string; + }; + actionComponent?: React.ReactNode; + onClose: () => void; + children: React.ReactNode; +} + +const Overlay = styled.div` + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(17, 17, 17, 0.8); + backdrop-filter: blur(1px); + display: flex; + justify-content: center; + align-items: center; + z-index: 1000; +`; + +const ModalWrapper = styled.div` + background: ${({ theme }) => theme.colors.translucent_bg}; + border-radius: 40px; + border: ${({ theme }) => `1px solid ${theme.colors.border}`}; + width: 1080px; + box-shadow: 0px 1px 1px 0px rgba(17, 17, 17, 0.8), + 0px 2px 2px 0px rgba(17, 17, 17, 0.8), 0px 5px 5px 0px rgba(17, 17, 17, 0.8), + 0px 10px 10px 0px rgba(17, 17, 17, 0.8), + 0px 0px 8px 0px rgba(17, 17, 17, 0.8); +`; + +const ModalHeader = styled.div` + display: flex; + justify-content: space-between; + align-items: center; + height: 80px; + border-bottom: 1px solid ${({ theme }) => theme.colors.border}; + padding: 0 24px; +`; + +const ModalCloseButton = styled.div` + cursor: pointer; + display: flex; + align-items: center; + gap: 8px; +`; + +const HeaderActionsWrapper = styled.div` + display: flex; + align-items: center; + gap: 8px; +`; + +const ModalContent = styled.div` + padding: 1rem; +`; + +const ModalTitleContainer = styled.div` + position: absolute; + left: 50%; + transform: translateX(-50%); + display: flex; + align-items: center; + justify-content: center; + width: 100%; + pointer-events: none; +`; + +const ModalTitle = styled(Text)` + text-transform: uppercase; + font-family: ${({ theme }) => theme.font_family.secondary}; + pointer-events: auto; +`; + +const CancelText = styled(Text)` + text-transform: uppercase; + font-weight: 600; + font-size: 14px; + font-family: ${({ theme }) => theme.font_family.secondary}; + text-decoration: underline; + cursor: pointer; +`; + +const Modal: React.FC = ({ + isOpen, + header, + onClose, + children, + actionComponent, +}) => { + if (!isOpen) return null; + + return ReactDOM.createPortal( + + + + + close + {'Cancel'} + + + {header.title} + + {actionComponent} + + {children} + + , + document.body + ); +}; + +export { Modal }; diff --git a/frontend/webapp/reuseable-components/navigation-buttons/index.tsx b/frontend/webapp/reuseable-components/navigation-buttons/index.tsx new file mode 100644 index 000000000..f1b366150 --- /dev/null +++ b/frontend/webapp/reuseable-components/navigation-buttons/index.tsx @@ -0,0 +1,93 @@ +import React from 'react'; +import Image from 'next/image'; +import { Text } from '../text'; +import { Button } from '../button'; +import theme from '@/styles/theme'; +import styled from 'styled-components'; + +interface NavigationButtonProps { + label: string; + iconSrc?: string; + onClick: () => void; + variant?: 'primary' | 'secondary'; + disabled?: boolean; +} + +interface NavigationButtonsProps { + buttons: NavigationButtonProps[]; +} + +const ButtonsContainer = styled.div` + display: flex; + gap: 8px; + align-items: center; +`; + +const StyledButton = styled(Button)` + display: flex; + align-items: center; + gap: 8px; +`; + +const ButtonText = styled(Text)` + text-decoration: underline; +`; + +export const NavigationButtons: React.FC = ({ + buttons, +}) => { + function renderBackButton({ + button, + index, + }: { + button: NavigationButtonProps; + index: number; + }) { + return ( + buttons.length > 0 && + buttons[0].label === 'BACK' && + button.iconSrc && + index === 0 + ); + } + return ( + + {buttons.map((button, index) => ( + + {renderBackButton({ button, index }) && ( + {button.label} + )} + + {button.label} + + {button.iconSrc && !renderBackButton({ button, index }) && ( + {button.label} + )} + + ))} + + ); +}; diff --git a/frontend/webapp/reuseable-components/text/index.tsx b/frontend/webapp/reuseable-components/text/index.tsx index 61c582f40..393e02dcc 100644 --- a/frontend/webapp/reuseable-components/text/index.tsx +++ b/frontend/webapp/reuseable-components/text/index.tsx @@ -14,23 +14,20 @@ interface TextProps { const TextWrapper = styled.div<{ color?: string; - size: number; - weight: number; - align: 'left' | 'center' | 'right'; + size?: number; + weight?: number; + align?: 'left' | 'center' | 'right'; family?: 'primary' | 'secondary'; - opacity: number; + opacity?: number; decoration?: string; }>` color: ${({ color, theme }) => color || theme.colors.text}; - font-size: ${({ size }) => size}px; - font-weight: ${({ weight }) => weight}; - text-align: ${({ align }) => align}; - opacity: ${({ opacity }) => opacity}; - text-decoration: ${({ decoration }) => decoration}; + font-size: ${({ size }) => (size !== undefined ? size : 16)}px; + font-weight: ${({ weight }) => (weight !== undefined ? weight : 300)}; + text-align: ${({ align }) => align || 'left'}; + opacity: ${({ opacity }) => (opacity !== undefined ? opacity : 1)}; + text-decoration: ${({ decoration }) => decoration || 'none'}; font-family: ${({ theme, family }) => { - if (family === 'primary') { - return theme.font_family.primary; - } if (family === 'secondary') { return theme.font_family.secondary; } @@ -38,29 +35,8 @@ const TextWrapper = styled.div<{ }}; `; -const Text: React.FC = ({ - children, - color, - size = 16, - weight = 300, - align = 'left', - family = 'primary', - opacity = 1, - decoration, -}) => { - return ( - - {children} - - ); +const Text: React.FC = ({ children, ...props }) => { + return {children}; }; export { Text }; diff --git a/frontend/webapp/styles/theme.ts b/frontend/webapp/styles/theme.ts index ce5ce7c11..533cd3401 100644 --- a/frontend/webapp/styles/theme.ts +++ b/frontend/webapp/styles/theme.ts @@ -7,6 +7,7 @@ const colors = { dark_grey: '#151515', text: '#F9F9F9', border: 'rgba(249, 249, 249, 0.08)', + translucent_bg: 'rgba(249, 249, 249, 0.04)', }; const text = {