diff --git a/apps/warp-protocol-landing/src/dropdown-menu/DropdownMenu.module.sass b/apps/warp-protocol-landing/src/dropdown-menu/DropdownMenu.module.sass new file mode 100644 index 00000000..79430d73 --- /dev/null +++ b/apps/warp-protocol-landing/src/dropdown-menu/DropdownMenu.module.sass @@ -0,0 +1,15 @@ +.root + position: relative + +.menu + > * + padding: 0 !important + + > * + margin: 0 !important + height: 50px + padding: 0 16px + display: flex + align-items: center + justify-content: space-between + width: 100% diff --git a/apps/warp-protocol-landing/src/dropdown-menu/DropdownMenu.tsx b/apps/warp-protocol-landing/src/dropdown-menu/DropdownMenu.tsx new file mode 100644 index 00000000..8e2e6d69 --- /dev/null +++ b/apps/warp-protocol-landing/src/dropdown-menu/DropdownMenu.tsx @@ -0,0 +1,80 @@ +import { ClickAwayListener, Portal } from '@mui/material'; +import { UIElementProps } from '@terra-money/apps/components'; +import classNames from 'classnames'; +import { MenuContext, MenuProvider } from '../menu-button'; +import { Menu } from '../menu'; +import { cloneElement, CSSProperties, useContext, useEffect, useMemo, useRef, useState } from 'react'; +import styles from './DropdownMenu.module.sass'; + +export type DropdownMenuProps = UIElementProps & { + action?: JSX.Element; + menuClass?: string; + open?: boolean; + menuStyle?: React.CSSProperties; +}; + +export function DropdownMenuInner(props: DropdownMenuProps) { + const { className, children, action, menuClass, menuStyle, open, style } = props; + const { open: dropdownOpen, setOpen: setDropdownOpen } = useContext(MenuContext); + const containerRef = useRef(null); + + const [menuEl, setMenuEl] = useState(null); + const menuHeight = useMemo(() => menuEl?.clientHeight ?? 0, [menuEl]); + + const containerTop = containerRef.current?.getBoundingClientRect().top ?? 0; + const containerLeft = containerRef.current?.getBoundingClientRect().left ?? 0; + + const coords: CSSProperties = { + top: containerTop + 52, + left: containerLeft, + }; + + const outOfViewport = (menuEl?.getBoundingClientRect().bottom ?? 0) > window.innerHeight; + + if (outOfViewport) { + const padding = 8; + coords.top = containerTop - (menuHeight + padding); + } + + useEffect(() => { + setDropdownOpen(Boolean(open)); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [open]); + + return ( + { + setDropdownOpen(false); + }} + > +
+ {action && + cloneElement(action, { + onClick: () => { + setDropdownOpen((open) => !open); + action.props.onClick?.(); + }, + })} + {dropdownOpen && ( + + setMenuEl(el)} + > + {children} + + + )} +
+
+ ); +} + +export const DropdownMenu = (props: DropdownMenuProps) => { + return ( + + + + ); +}; diff --git a/apps/warp-protocol-landing/src/link/Link.module.sass b/apps/warp-protocol-landing/src/link/Link.module.sass new file mode 100644 index 00000000..d4046944 --- /dev/null +++ b/apps/warp-protocol-landing/src/link/Link.module.sass @@ -0,0 +1,10 @@ +.root + cursor: pointer + color: var(--color-light-green) + font-size: 14px + font-weight: 400 + line-height: 20px + min-width: unset + width: fit-content + block-size: fit-content + padding: 0 diff --git a/apps/warp-protocol-landing/src/link/Link.tsx b/apps/warp-protocol-landing/src/link/Link.tsx new file mode 100644 index 00000000..47fc57c7 --- /dev/null +++ b/apps/warp-protocol-landing/src/link/Link.tsx @@ -0,0 +1,29 @@ +import classNames from 'classnames'; +import { PropsWithChildren, useCallback } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { Button } from '../button'; +import styles from './Link.module.sass'; + +type LinkProps = PropsWithChildren & { + className?: string; + to?: string | -1; + onClick?: () => void; +}; + +export const Link = ({ to, children, className, onClick }: LinkProps) => { + const navigate = useNavigate(); + + const handleClick = useCallback(() => { + if (to) { + navigate(to as string); + } else { + onClick?.(); + } + }, [navigate, to, onClick]); + + return ( + + ); +}; diff --git a/apps/warp-protocol-landing/src/link/index.ts b/apps/warp-protocol-landing/src/link/index.ts new file mode 100644 index 00000000..3db78f51 --- /dev/null +++ b/apps/warp-protocol-landing/src/link/index.ts @@ -0,0 +1 @@ +export * from './Link'; diff --git a/apps/warp-protocol-landing/src/menu-button/MenuAction.tsx b/apps/warp-protocol-landing/src/menu-button/MenuAction.tsx new file mode 100644 index 00000000..efd54870 --- /dev/null +++ b/apps/warp-protocol-landing/src/menu-button/MenuAction.tsx @@ -0,0 +1,28 @@ +import { UIElementProps } from '@terra-money/apps/components'; +import { MenuItem } from '../menu'; +import { useContext } from 'react'; +import { MenuContext } from './MenuContext'; + +export type MenuActionProps = UIElementProps & { onClick?: () => void; subMenu?: boolean; onMouseEnter?: () => void }; + +export const MenuAction = (props: MenuActionProps) => { + const { setOpen } = useContext(MenuContext); + const { onClick, children, subMenu, className, onMouseEnter } = props; + + return ( + { + if (!subMenu) { + setOpen(false); + } + + onClick?.(); + }} + > + {children} + + ); +}; diff --git a/apps/warp-protocol-landing/src/menu-button/MenuButton.module.sass b/apps/warp-protocol-landing/src/menu-button/MenuButton.module.sass new file mode 100644 index 00000000..8cc826e2 --- /dev/null +++ b/apps/warp-protocol-landing/src/menu-button/MenuButton.module.sass @@ -0,0 +1,13 @@ +.action_btn + margin-right: 8px + //width: 44px + height: 44px + margin-left: auto + min-width: 0 + padding: 0 + border-radius: 16px + // width: 40px + // background-color: var(--menu-button-background-color) + +.btn_active + background: var(--widget-background-color) !important diff --git a/apps/warp-protocol-landing/src/menu-button/MenuButton.tsx b/apps/warp-protocol-landing/src/menu-button/MenuButton.tsx new file mode 100644 index 00000000..05b38375 --- /dev/null +++ b/apps/warp-protocol-landing/src/menu-button/MenuButton.tsx @@ -0,0 +1,72 @@ +import classNames from 'classnames'; +import MoreVertIcon from '@mui/icons-material/MoreVert'; +import { useContext, useRef, useState } from 'react'; +import { ClickAwayListener, Portal } from '@mui/material'; +import styles from './MenuButton.module.sass'; +import { UIElementProps } from '@terra-money/apps/components'; +import { MenuContext, MenuProvider } from './MenuContext'; +import { Button } from '../button'; +import { Menu } from '../menu'; + +export type MenuButtonProps = UIElementProps & {}; + +const MenuButtonInner = (props: MenuButtonProps) => { + const { className, children } = props; + const [menuHeight, setMenuHeight] = useState(200); + const { open, setOpen } = useContext(MenuContext); + const actionContainer = useRef(null); + + const menuRef = useRef(null); + + const clipToViewportHeight = (top: number) => { + const offset = menuHeight + 40; + + if (top + offset > window.innerHeight) { + return window.innerHeight - offset; + } + + return top; + }; + + return ( + setOpen(false)}> +
+
+
+ ); +}; + +export const MenuButton = (props: MenuButtonProps) => { + return ( + + + + ); +}; diff --git a/apps/warp-protocol-landing/src/menu-button/MenuContext.tsx b/apps/warp-protocol-landing/src/menu-button/MenuContext.tsx new file mode 100644 index 00000000..cf30d9c6 --- /dev/null +++ b/apps/warp-protocol-landing/src/menu-button/MenuContext.tsx @@ -0,0 +1,36 @@ +import { UIElementProps } from '@terra-money/apps/components'; +import { createContext, useCallback, useContext, useMemo, useState } from 'react'; + +type MenuContextValue = { + open: boolean; + setOpen: React.Dispatch>; +}; + +export const MenuContext = createContext({ + setOpen: () => false, + open: false, +}); + +export const MenuProvider = ({ children }: UIElementProps) => { + const [open, setOpen] = useState(false); + + const context = useContext(MenuContext); + + const bindedSetOpen: React.Dispatch> = useCallback( + (action) => { + // is submenu + if (context.open && open) { + context.setOpen(false); + } + + setOpen(action); + }, + [setOpen, context, open] + ); + + const value = useMemo(() => { + return { open, setOpen: bindedSetOpen }; + }, [open, bindedSetOpen]); + + return {children}; +}; diff --git a/apps/warp-protocol-landing/src/menu-button/index.ts b/apps/warp-protocol-landing/src/menu-button/index.ts new file mode 100644 index 00000000..d74dafa5 --- /dev/null +++ b/apps/warp-protocol-landing/src/menu-button/index.ts @@ -0,0 +1,2 @@ +export * from './MenuButton'; +export * from './MenuContext'; diff --git a/apps/warp-protocol-landing/src/menu/Menu.module.sass b/apps/warp-protocol-landing/src/menu/Menu.module.sass new file mode 100644 index 00000000..147ec535 --- /dev/null +++ b/apps/warp-protocol-landing/src/menu/Menu.module.sass @@ -0,0 +1,40 @@ +.menu + position: absolute + width: 200px + left: 80px + z-index: 1000 + border-radius: 6px + box-sizing: border-box + +.menu_content + padding: 24px + border: 1px solid var(--background-color) + background: var(--widget-background-color) + border-radius: 6px + +.menu_item + cursor: pointer + font-weight: 500 + font-size: 14px + color: var(--text-color-primary) + + &:not(&:last-child) + margin-bottom: 24px + + &:hover + color: #DFE1EE + +.chevron + width: 24px + height: 24px + margin-left: 4px + margin-right: 4px + path + fill-opacity: 0.6 + fill: #F6F7FA !important + +.submenu + width: 100% + display: flex + align-items: center + justify-content: space-between diff --git a/apps/warp-protocol-landing/src/menu/Menu.tsx b/apps/warp-protocol-landing/src/menu/Menu.tsx new file mode 100644 index 00000000..1b9d7fe3 --- /dev/null +++ b/apps/warp-protocol-landing/src/menu/Menu.tsx @@ -0,0 +1,32 @@ +import { UIElementProps } from '@terra-money/apps/components'; +import classNames from 'classnames'; +import { forwardRef, Ref } from 'react'; +import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight'; +import styles from './Menu.module.sass'; + +export const Menu = forwardRef((props: UIElementProps, ref: Ref) => { + const { children, style, className } = props; + + return ( +
+
{children}
+
+ ); +}); + +type MenuItemProps = UIElementProps & { onClick?: () => void; subMenu?: boolean; onMouseEnter?: () => void }; + +export const MenuItem = (props: MenuItemProps) => { + const { children, subMenu, onMouseEnter, ...remainingProps } = props; + + return ( +
+ {children} + {subMenu && } +
+ ); +}; diff --git a/apps/warp-protocol-landing/src/menu/index.ts b/apps/warp-protocol-landing/src/menu/index.ts new file mode 100644 index 00000000..629d3d0a --- /dev/null +++ b/apps/warp-protocol-landing/src/menu/index.ts @@ -0,0 +1 @@ +export * from './Menu'; diff --git a/apps/warp-protocol-landing/src/pages/home/features/DesktopFeatures.module.sass b/apps/warp-protocol-landing/src/pages/home/features/DesktopFeatures.module.sass index 9b05b220..bf733290 100644 --- a/apps/warp-protocol-landing/src/pages/home/features/DesktopFeatures.module.sass +++ b/apps/warp-protocol-landing/src/pages/home/features/DesktopFeatures.module.sass @@ -51,6 +51,9 @@ > .description line-height: 20px + display: flex + flex-direction: column + align-items: flex-end .slide height: 100% @@ -64,7 +67,6 @@ height: 1000px left: 35% - -@media (max-width: 768px) +@media (max-width: 768px) .slide - z-index: 0 !important \ No newline at end of file + z-index: 0 !important diff --git a/apps/warp-protocol-landing/src/pages/home/features/DesktopFeatures.tsx b/apps/warp-protocol-landing/src/pages/home/features/DesktopFeatures.tsx index 6f87fbd3..01392006 100644 --- a/apps/warp-protocol-landing/src/pages/home/features/DesktopFeatures.tsx +++ b/apps/warp-protocol-landing/src/pages/home/features/DesktopFeatures.tsx @@ -3,46 +3,62 @@ import classNames from 'classnames'; import { UIElementProps } from '@terra-money/apps/components'; import React, { forwardRef, useState } from 'react'; import styles from './DesktopFeatures.module.sass'; +import { Link } from '../../../link'; type Feature = { id: number; imageUrl: string; heading: string; description: string; - footer: string; + footer: string | JSX.Element; }; const features: Feature[] = [ { id: 0, - imageUrl: 'images/DashboardSlide.png', - heading: 'Asynchronous', - description: 'On-chain programming', + imageUrl: 'images/QuerySlide.png', + heading: 'Generic', + description: 'Logic composition', footer: - 'Bringing the async keyword to the world of smart contracts. Execute whatever, whenever.', + 'Define logic using executable payloads, contract queries, and custom messages to create attractive, automated platform features and experiences.', }, { id: 1, - imageUrl: 'images/QuerySlide.png', - heading: 'Generic way of', - description: 'Composing logic', + imageUrl: 'images/ConditionSlide.png', + heading: 'Define execution with', + description: 'Custom conditions', footer: - 'Define logic as you would in a programming language by supplying executable payloads. Arbitrary messages and contract queries.', + 'Create jobs based on any available on-chain data using boolean logic and math operators. No smart contract changes necessary.', }, { id: 2, - imageUrl: 'images/ConditionSlide.png', - heading: 'Define execution with', - description: 'Arbitrary condition', - footer: 'Complete boolean logic support.', + imageUrl: 'images/DashboardSlide.png', + heading: 'Create customizable', + description: 'Recurring jobs', + footer: + 'Compose jobs made up of multiple transactions organized in an atomic list-form. These can be simple in nature, such as sending a transaction, or complex and recursive, whereby a job message is made up of multiple transactions.', }, { - id: 4, + id: 3, imageUrl: 'images/SdkSlide2.png', - heading: 'For builders', - description: 'Warp SDK', - footer: - 'Build entire keeper bots and interact with warp contracts with ease.', + heading: 'Start building with', + description: 'Seamless integration', + footer: ( + <> + + Using Warp's advanced SDK, developers can experiment and seamlessly + integrate Warp functionality right into their front or backend in just + a few minutes. + + { + window.open('https://github.com/terra-money/warp-sdk'); + }} + > + Warp SDK + + + ), }, ]; diff --git a/apps/warp-protocol-landing/src/pages/home/features/MobileFeatures.module.sass b/apps/warp-protocol-landing/src/pages/home/features/MobileFeatures.module.sass index fd178382..1e6ad844 100644 --- a/apps/warp-protocol-landing/src/pages/home/features/MobileFeatures.module.sass +++ b/apps/warp-protocol-landing/src/pages/home/features/MobileFeatures.module.sass @@ -52,7 +52,10 @@ > .description line-height: 20px - height: 60px + height: 100px + display: flex + flex-direction: column + align-items: flex-end .slide height: auto diff --git a/apps/warp-protocol-landing/src/pages/home/features/MobileFeatures.tsx b/apps/warp-protocol-landing/src/pages/home/features/MobileFeatures.tsx index cfc27a9d..f7567361 100644 --- a/apps/warp-protocol-landing/src/pages/home/features/MobileFeatures.tsx +++ b/apps/warp-protocol-landing/src/pages/home/features/MobileFeatures.tsx @@ -3,46 +3,62 @@ import classNames from 'classnames'; import { UIElementProps } from '@terra-money/apps/components'; import React, { forwardRef, useState } from 'react'; import styles from './MobileFeatures.module.sass'; +import { Link } from '../../../link'; type Feature = { id: number; imageUrl: string; heading: string; description: string; - footer: string; + footer: string | JSX.Element; }; const features: Feature[] = [ { id: 0, - imageUrl: 'images/DashboardSlide.png', - heading: 'Asynchronous', - description: 'On-chain programming', + imageUrl: 'images/QuerySlide.png', + heading: 'Generic', + description: 'Logic composition', footer: - 'Bringing the async keyword to the world of smart contracts. Execute whatever, whenever.', + 'Define logic using executable payloads, contract queries, and custom messages to create attractive, automated platform features and experiences.', }, { id: 1, - imageUrl: 'images/QuerySlide.png', - heading: 'Generic way of', - description: 'Composing logic', + imageUrl: 'images/ConditionSlide.png', + heading: 'Define execution with', + description: 'Custom conditions', footer: - 'Define logic as you would in a programming language by supplying executable payloads. Arbitrary messages and contract queries.', + 'Create jobs based on any available on-chain data using boolean logic and math operators. No smart contract changes necessary.', }, { id: 2, - imageUrl: 'images/ConditionSlide.png', - heading: 'Define execution with', - description: 'Arbitrary condition', - footer: 'Complete boolean logic support.', + imageUrl: 'images/DashboardSlide.png', + heading: 'Create customizable', + description: 'Recurring jobs', + footer: + 'Compose jobs made up of multiple transactions organized in an atomic list-form. These can be simple in nature, such as sending a transaction, or complex and recursive, whereby a job message is made up of multiple transactions.', }, { - id: 4, + id: 3, imageUrl: 'images/SdkSlide2.png', - heading: 'For builders', - description: 'Warp SDK', - footer: - 'Build entire keeper bots and interact with warp contracts with ease.', + heading: 'Start building with', + description: 'Seamless integration', + footer: ( + <> + + Using Warp's advanced SDK, developers can experiment and seamlessly + integrate Warp functionality right into their front or backend in just + a few minutes. + + { + window.open('https://github.com/terra-money/warp-sdk'); + }} + > + Warp SDK + + + ), }, ]; diff --git a/apps/warp-protocol-landing/src/top-bar/DesktopTopBar.module.sass b/apps/warp-protocol-landing/src/top-bar/DesktopTopBar.module.sass index f165cd2e..0187cded 100644 --- a/apps/warp-protocol-landing/src/top-bar/DesktopTopBar.module.sass +++ b/apps/warp-protocol-landing/src/top-bar/DesktopTopBar.module.sass @@ -4,8 +4,19 @@ padding: 32px 64px .btn_gray + min-width: 0 + padding: 0 color: rgba(223, 226, 225, 0.4) !important + &:not(&:last-child) + margin-right: 20px !important + + &:not(&:first-child) + margin-left: 20px !important + +.menu + width: 120px + .left margin-right: auto diff --git a/apps/warp-protocol-landing/src/top-bar/DesktopTopBar.tsx b/apps/warp-protocol-landing/src/top-bar/DesktopTopBar.tsx index 4df2a7ea..f1ba7905 100644 --- a/apps/warp-protocol-landing/src/top-bar/DesktopTopBar.tsx +++ b/apps/warp-protocol-landing/src/top-bar/DesktopTopBar.tsx @@ -4,19 +4,30 @@ import styles from './DesktopTopBar.module.sass'; import { Button } from '../button/Button'; import classNames from 'classnames'; import { forwardRef } from 'react'; +import { DropdownMenu } from 'dropdown-menu/DropdownMenu'; +import { MenuAction } from 'menu-button/MenuAction'; type DesktopTopBarProps = UIElementProps & { onHomeClick: () => void; onDocsClick: () => void; onFeaturesClick: () => void; onWebAppClick: () => void; + onTelegramClick: () => void; + onDiscordClick: () => void; }; export const DesktopTopBar = forwardRef< HTMLDivElement | null, DesktopTopBarProps >((props, ref) => { - const { onHomeClick, onFeaturesClick, onDocsClick, onWebAppClick } = props; + const { + onHomeClick, + onFeaturesClick, + onDocsClick, + onWebAppClick, + onTelegramClick, + onDiscordClick, + } = props; return (
@@ -50,6 +61,22 @@ export const DesktopTopBar = forwardRef< > Features + + Community + + } + > + Telegram + Discord +