diff --git a/.prettierrc.json b/.prettierrc.json index 49955e2e..ada37bd3 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1,4 +1,5 @@ { + "endOfLine": "lf", "semi": false, "singleQuote": true, "trailingComma": "none" diff --git a/.storybook/theme.tsx b/.storybook/theme.tsx index a18a70fd..ec3204ea 100644 --- a/.storybook/theme.tsx +++ b/.storybook/theme.tsx @@ -43,7 +43,8 @@ const LIGHT_THEME = ` --toast-text: #ffffff; --modal: #ffffff; --dimmer: #ffffffdd; - --clear-divider: #A09BA8; + --text-area-border: #67637033; + --clear-divider: #a09ba8; --navbar-icons: #000; /* shadows */ @@ -56,7 +57,19 @@ const LIGHT_THEME = ` --shadow-color-3: 0px 16px 32px 0px rgba(0, 0, 0, 0.24); /* svgs */ - --brightness: brightness(0.1); /* black svgs */ + --brightness: brightness(0.1); + /* black svgs */ + --notification-onboarding-bell: url(../../assets/bell-onboarding-light.png); + + /* Navbar2 */ + --navbar-menu-enabled: #a09ba8; + --navbar-menu-hover: #000; + --navbar-item-text-enabled: #716b7c; + --navbar-item-text-hover: #000; + --navbar-item-border-enabled: #cfcdd4; + --navbar-item-border-hover: #000; + --usermenu-item-text-enabled: #43404a; + --usermenu-item-border-enabled: #43404a; } ` @@ -86,7 +99,7 @@ const DARK_THEME = ` /* ui */ --divider: #67637033; - --dropdown: #676370; + --dropdown: #716b7c; --dropdown-hover: #24212933; --popup: #676370; --popup-text: #ffffff; @@ -98,8 +111,8 @@ const DARK_THEME = ` --toast-text: #ffffff; --modal: #242129; --dimmer: #000000dd; - --cloud-sky: #716B7C; - --clear-divider: #A09BA8; + --text-area-border: #676370; + --clear-divider: #a09ba8; --navbar-icons: #fff; /* shadows */ @@ -112,7 +125,20 @@ const DARK_THEME = ` --shadow-color-3: 0px 16px 32px 0px rgba(0, 0, 0, 0.32); /* svgs */ - --brightness: brightness(100); /* black svgs */ + --brightness: brightness(100); + /* black svgs */ + + --notification-onboarding-bell: url(../../assets/bell-onboarding-dark.png); + + /* Navbar2 */ + --navbar-menu-enabled: #ecebed; + --navbar-menu-hover: #fff; + --navbar-item-text-enabled: #cfcdd4; + --navbar-item-text-hover: #fff; + --navbar-item-border-enabled: #716b7c; + --navbar-item-border-hover: #cfcdd4; + --usermenu-item-text-enabled: #cfcdd4; + --usermenu-item-border-enabled: #cfcdd4; } ` diff --git a/src/assets/icon-arrow-right.png b/src/assets/icon-arrow-right.png new file mode 100644 index 00000000..c5a2fbd2 Binary files /dev/null and b/src/assets/icon-arrow-right.png differ diff --git a/src/assets/link-external-icon.svg b/src/assets/link-external-icon.svg new file mode 100644 index 00000000..ff36ff07 --- /dev/null +++ b/src/assets/link-external-icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/man-default.png b/src/assets/man-default.png new file mode 100644 index 00000000..b8d25f81 Binary files /dev/null and b/src/assets/man-default.png differ diff --git a/src/assets/navbar-avatar-create.png b/src/assets/navbar-avatar-create.png new file mode 100644 index 00000000..b940b6ad Binary files /dev/null and b/src/assets/navbar-avatar-create.png differ diff --git a/src/assets/navbar-avatar-discover.png b/src/assets/navbar-avatar-discover.png new file mode 100644 index 00000000..4400f452 Binary files /dev/null and b/src/assets/navbar-avatar-discover.png differ diff --git a/src/assets/navbar-avatar-learn.png b/src/assets/navbar-avatar-learn.png new file mode 100644 index 00000000..b1e653b0 Binary files /dev/null and b/src/assets/navbar-avatar-learn.png differ diff --git a/src/assets/navbar-avatar-marketplace.png b/src/assets/navbar-avatar-marketplace.png new file mode 100644 index 00000000..0e3eea8b Binary files /dev/null and b/src/assets/navbar-avatar-marketplace.png differ diff --git a/src/assets/navbar-avatar-profile.png b/src/assets/navbar-avatar-profile.png new file mode 100644 index 00000000..83e8e7ce Binary files /dev/null and b/src/assets/navbar-avatar-profile.png differ diff --git a/src/assets/navbar-avatar-vote.png b/src/assets/navbar-avatar-vote.png new file mode 100644 index 00000000..46bb721b Binary files /dev/null and b/src/assets/navbar-avatar-vote.png differ diff --git a/src/components/Back/Back.tsx b/src/components/Back/Back.tsx index 30e40791..029116d5 100644 --- a/src/components/Back/Back.tsx +++ b/src/components/Back/Back.tsx @@ -4,7 +4,7 @@ import './Back.css' export type BackProps = { className?: string absolute?: boolean - onClick?: () => void + onClick?: (e: React.MouseEvent) => void } export class Back extends React.PureComponent { diff --git a/src/components/Icons/ArrowIcon.tsx b/src/components/Icons/ArrowIcon.tsx new file mode 100644 index 00000000..55176990 --- /dev/null +++ b/src/components/Icons/ArrowIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react' +import classNames from 'classnames' + +import './styles.css' + +const ArrowIcon = () => ( +
+ + + +
+) + +export default ArrowIcon diff --git a/src/components/Icons/ChevronIcon.tsx b/src/components/Icons/ChevronIcon.tsx new file mode 100644 index 00000000..439eda32 --- /dev/null +++ b/src/components/Icons/ChevronIcon.tsx @@ -0,0 +1,31 @@ +import React from 'react' +import classNames from 'classnames' + +import './styles.css' + +const ChevronIcon = ({ down = false }: { down?: boolean }) => ( +
+ + + + + + +
+) + +export default ChevronIcon diff --git a/src/components/Icons/ExternalIcon.tsx b/src/components/Icons/ExternalIcon.tsx new file mode 100644 index 00000000..fb2f9b1a --- /dev/null +++ b/src/components/Icons/ExternalIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react' +import classNames from 'classnames' + +import './styles.css' + +const ExternalIcon = () => ( +
+ + + +
+) + +export default ExternalIcon diff --git a/src/components/Icons/Notifications/ManaMainnet.tsx b/src/components/Icons/Notifications/ManaMainnet.tsx index 3dd6b110..8a405345 100644 --- a/src/components/Icons/Notifications/ManaMainnet.tsx +++ b/src/components/Icons/Notifications/ManaMainnet.tsx @@ -5,7 +5,7 @@ const ManaMainnet = (props: React.SVGAttributes) => { ( ) diff --git a/src/components/Icons/Notifications/NotificationBellActive.tsx b/src/components/Icons/Notifications/NotificationBellActive.tsx index e90afd0a..6e1fac11 100644 --- a/src/components/Icons/Notifications/NotificationBellActive.tsx +++ b/src/components/Icons/Notifications/NotificationBellActive.tsx @@ -5,7 +5,7 @@ const NotificationBellActive = () => ( ) diff --git a/src/components/Icons/styles.css b/src/components/Icons/styles.css index c1f17b37..1b316ce1 100644 --- a/src/components/Icons/styles.css +++ b/src/components/Icons/styles.css @@ -2,3 +2,16 @@ width: 24px; height: 24px; } + +.dui-icon-container.centered { + width: 24px; + height: 24px; + display: flex; + justify-content: center; + align-items: center; +} + +.iconContainer.rotate-180 svg, +.dui-icon-container.rotate-180 svg { + transform: rotateZ(180deg); +} diff --git a/src/components/Navbar/Navbar.stories.tsx b/src/components/Navbar/Navbar.stories.tsx index 344657f0..98093d50 100644 --- a/src/components/Navbar/Navbar.stories.tsx +++ b/src/components/Navbar/Navbar.stories.tsx @@ -7,6 +7,7 @@ import { Hero } from '../Hero/Hero' import { Parallax } from '../Parallax/Parallax' import { UserMenu } from '../UserMenu/UserMenu' import { avatar } from '../../data/avatar' +import { i18n as i18nUserMenu } from '../UserMenu/UserMenu.i18n' import { Navbar } from './Navbar' import './Navbar.stories.css' @@ -218,7 +219,9 @@ storiesOf('Navbar', module) address="0x68FFc53C43C65C8Dd778969320e21B85b10363cE" mana={200000} onClickAccount={() => console.log('Clicked on account menu')} - rightMenu={} + rightMenu={ + + } /> ) diff --git a/src/components/Navbar2/MainMenu/MainMenu.css b/src/components/Navbar2/MainMenu/MainMenu.css new file mode 100644 index 00000000..a73e7823 --- /dev/null +++ b/src/components/Navbar2/MainMenu/MainMenu.css @@ -0,0 +1,24 @@ +.dui-navbar2__menu.dui-navbar2__menu-desktop { + display: flex; + height: 100%; +} + +.dui-navbar2__menu.dui-navbar2__menu-mobile { + position: fixed; + display: none; + flex-direction: column; + align-items: flex-start; + justify-content: flex-start; + background-color: var(--background); + width: 100vw; + height: 100vh; + top: -150vh; + left: 0; + transition: top 200ms ease-in-out; +} + +@media (max-width: 991px) { + .dui-navbar2__menu.dui-navbar2__menu-mobile { + display: flex; + } +} diff --git a/src/components/Navbar2/MainMenu/MainMenu.tsx b/src/components/Navbar2/MainMenu/MainMenu.tsx new file mode 100644 index 00000000..34a9d599 --- /dev/null +++ b/src/components/Navbar2/MainMenu/MainMenu.tsx @@ -0,0 +1,47 @@ +import React from 'react' +import classNames from 'classnames' + +import { MenuItem } from '../MenuItem/MenuItem' +import { Navbar2Pages } from '../Navbar2.types' +import { MainMenuProps } from './MainMenu.types' + +import './MainMenu.css' + +export const MainMenu = (props: MainMenuProps) => { + const { i18n, ...menuItemProps } = props + return ( +
+ + + + + +
+ ) +} diff --git a/src/components/Navbar2/MainMenu/MainMenu.types.ts b/src/components/Navbar2/MainMenu/MainMenu.types.ts new file mode 100644 index 00000000..a384258c --- /dev/null +++ b/src/components/Navbar2/MainMenu/MainMenu.types.ts @@ -0,0 +1,12 @@ +import { Navbar2MenuI18nProps, Navbar2Pages } from '../Navbar2.types' + +export type MainMenuProps = { + activePage: Navbar2Pages | string + onToggleShowSubMenu: ( + e: React.MouseEvent, + show: boolean, + section?: Navbar2Pages + ) => void + i18n: Navbar2MenuI18nProps + isMobile?: boolean +} diff --git a/src/components/Navbar2/MenuItem/MenuItem.css b/src/components/Navbar2/MenuItem/MenuItem.css new file mode 100644 index 00000000..e962b999 --- /dev/null +++ b/src/components/Navbar2/MenuItem/MenuItem.css @@ -0,0 +1,32 @@ +.dui-menu-item .dui-icon-container.centered { + margin-top: 4px; + margin-left: 4px; +} + +.dui-menu-item .dui-icon-container.centered svg path:nth-child(2) { + fill: var(--navbar-item-text-enabled); +} + +.dui-menu-item.active .dui-icon-container.centered svg path:nth-child(2), +.dui-menu-item:hover .dui-icon-container.centered svg path:nth-child(2) { + fill: var(--text); +} + +@media (max-width: 991px) { + .item.dui-menu-item.mobile { + cursor: pointer; + padding: 40px 0 23.66px; + display: flex; + align-items: center; + border-bottom-color: var(--navbar-menu-hover); + color: var(--navbar-menu-hover); + font-size: 20px; + font-style: normal; + font-weight: 400; + line-height: 18px; + border-bottom-style: solid; + width: calc(100% - 50px); + margin: 0 25px; + justify-content: space-between; + } +} diff --git a/src/components/Navbar2/MenuItem/MenuItem.tsx b/src/components/Navbar2/MenuItem/MenuItem.tsx new file mode 100644 index 00000000..9dda1d75 --- /dev/null +++ b/src/components/Navbar2/MenuItem/MenuItem.tsx @@ -0,0 +1,33 @@ +import React from 'react' +import Menu from 'semantic-ui-react/dist/commonjs/collections/Menu' +import classNames from 'classnames' + +import ArrowIcon from '../../Icons/ArrowIcon' +import ChevronIcon from '../../Icons/ChevronIcon' +import { MenuItemProps } from './MenuItem.types' + +import './MenuItem.css' + +export const MenuItem = (props: MenuItemProps) => { + const { activePage, section, title, onToggleShowSubMenu, isMobile } = props + + return ( + + !isMobile && onToggleShowSubMenu(e, true, section) + } + onMouseLeave={(e: React.MouseEvent) => + !isMobile && onToggleShowSubMenu(e, false, section) + } + onClick={(e: React.MouseEvent) => { + isMobile && onToggleShowSubMenu(e, true, section) + }} + className={classNames('dui-menu-item', section, isMobile && 'mobile')} + > + {title} + {!isMobile && } + {isMobile && } + + ) +} diff --git a/src/components/Navbar2/MenuItem/MenuItem.types.ts b/src/components/Navbar2/MenuItem/MenuItem.types.ts new file mode 100644 index 00000000..0d215dc4 --- /dev/null +++ b/src/components/Navbar2/MenuItem/MenuItem.types.ts @@ -0,0 +1,13 @@ +import { Navbar2Pages } from '../Navbar2.types' + +export type MenuItemProps = { + activePage: Navbar2Pages | string + section: Navbar2Pages + title: React.ReactNode + onToggleShowSubMenu: ( + e: React.MouseEvent, + show: boolean, + section?: Navbar2Pages + ) => void + isMobile?: boolean +} diff --git a/src/components/Navbar2/Navbar2.css b/src/components/Navbar2/Navbar2.css new file mode 100644 index 00000000..e00e72e7 --- /dev/null +++ b/src/components/Navbar2/Navbar2.css @@ -0,0 +1,579 @@ +.dui-navbar2 { + position: relative; + height: var(--navbar-height); + margin-bottom: var(--navbar-margin-bottom); + border-bottom: 1px solid var(--divider); + width: 100%; + box-sizing: content-box; + z-index: 20; + margin-bottom: 0px; + border-bottom: none; +} + +.dui-navbar2.open { + z-index: var(--z-index-navbar); +} + +.dui-navbar2.open .ui.container.dui-navbar2-container { + z-index: calc(var(--z-index-navbar) + 10); +} + +.dui-navbar2 .dui-navbar2-menu { + position: relative; + height: 100%; + display: flex; + justify-content: space-between; + width: 100%; + align-items: center; +} + +.dui-navbar2 .dui-navbar2-wrapper { + display: flex; + align-items: center; + height: 100%; +} + +.dui-navbar2 > .ui.container.dui-navbar2-container { + position: relative; + display: flex; + flex-flow: row nowrap; + align-items: center; + justify-content: space-between; + height: 100%; + background-color: var(--background); + transition: background-color 0.25s ease; + z-index: 21; + width: 100%; + padding: 0 24px; + box-sizing: border-box; +} + +.dui-navbar2-logo { + cursor: pointer; + width: 36px; + height: 36px; + margin-top: 2px; +} + +.dcl.account-wrapper, +.dcl.new-account-wrapper { + display: flex; + flex-flow: row nowrap; + align-items: center; +} + +.dcl.account-wrapper.clickable, +.dcl.new-account-wrapper.clickable { + cursor: pointer; +} + +.dcl.new-account-wrapper .dcl.mana { + display: inline-block; + margin: 0px 0px 0px 0px; + color: var(--text); + font-size: 13px; + line-height: 18px; + font-weight: 700; +} + +.dcl.account-wrapper .dcl.mana { + display: inline-block; + margin: 0px 20px 0px 0px; + color: var(--text); + font-size: 13px; + line-height: 18px; +} + +.dcl.account-wrapper .dcl.mana .symbol .ethereum, +.dcl.new-account-wrapper .dcl.mana .symbol .ethereum { + font-size: 14px; +} + +.dcl.account-wrapper .dcl.blockie, +.dcl.newaccount-wrapper .dcl.blockie { + width: 32px; + height: 32px; + margin-top: -0.2em; +} + +.dui-navbar2-account { + display: flex; + flex-flow: row nowrap; + align-items: center; +} + +.dui-navbar2-account .dui-navbar2-wrapper.secondary.dui-navbar2-account-menu { + margin: 0px 24px 0px 0px; +} + +.dui-navbar2-account .dui-navbar2-wrapper.dui-navbar2-account-menu .item .icon { + margin: 0em; +} + +.dui-navbar2 .dui-navbar2-wrapper.secondary { + margin: 0px; +} + +.dui-navbar2 .dui-navbar2-wrapper .item:not(.mobile) { + font-weight: normal; + color: var(--navbar-item-text-enabled); + border-radius: 6px; + text-transform: capitalize; + font-family: var(--font-family); + margin-left: 24px; + padding: 0px; + font-size: 16px; + line-height: 18px; + z-index: 2; + height: 100%; + display: flex; + align-items: center; +} + +.dui-navbar2 .dui-navbar2-wrapper .item.disabled { + color: var(--secondary-text) !important; + opacity: 0.5; +} + +.dui-navbar2 .dui-navbar2-wrapper .item:hover, +.dui-navbar2 .dui-navbar2-wrapper .item .item:has(+ .item.submenu), +.dui-navbar2 .dui-navbar2-wrapper .item.active, +.dui-navbar2 .dui-navbar2-wrapper .item.active .item { + color: var(--text); + background: transparent; + cursor: pointer; +} + +.dui-navbar2 .dui-navbar2-wrapper .item > .item { + z-index: 1; +} + +.dui-navbar2 .dui-navbar2-wrapper .item.active, +.dui-navbar2 .dui-navbar2-wrapper .item.active .item { + font-weight: bold; +} + +.dcl.active-page { + color: var(--text); + display: inline-block; + text-transform: uppercase; + cursor: pointer; + margin: 0px; +} + +.dcl.active-page::after { + content: ' '; + width: 12px; + height: 7px; + background-size: contain; + background-repeat: no-repeat; + display: inline-block; + margin-left: 8px; + filter: var(--brightness); + background-image: url('../../assets/arrow-down.svg'); + transition: transform 0.25s ease; +} + +.dcl.active-page.caret-down::after { + transform: rotateZ(0deg) translateY(-1px); +} + +.dcl.active-page.caret-up::after { + transform: rotateZ(180deg) translateY(1px); +} + +.dui-navbar2 .children-wrapper { + position: absolute; + top: 0px; + left: 0px; + right: 0px; +} + +.dui-navbar2 .mobile-menu { + position: relative; + display: none; + padding-top: 0px; + transition: opacity 0.25s ease, transform 0.25s ease, box-shadow 0.25s ease; + opacity: 0; + transform: translateY(-16px); + box-shadow: 0 0px 0px 0 rgba(0, 0, 0, 0); +} + +.dui-navbar2 .dui-navbar2-wrapper .item > a.item { + margin-left: 0; + margin-right: 0; +} + +.dui-navbar2.marketplace .dui-submenu-container.marketplace-selected, +.dui-navbar2.explore .dui-submenu-container.explore-selected, +.dui-navbar2.learn .dui-submenu-container.learn-selected, +.dui-navbar2.governance .dui-submenu-container.governance-selected { + height: 390px; + opacity: 1; + background-color: var(--background); +} + +.dui-navbar2.create .dui-submenu-container.create-selected { + height: 430px; + opacity: 1; + background-color: var(--background); +} + +.dui-navbar2 .item.submenu { + background-size: 100% 100%; + background-position: 0px 0px, 0px 0px; + position: fixed; + top: -1000px; + z-index: 0; + left: 0; + padding-left: 370px; + width: calc(100% - 370px); + max-width: 100%; + height: 328px; + min-height: 390px; + box-shadow: none; + background-repeat: no-repeat; + display: flex; + align-items: center; + + transition: top 200ms ease-in-out 1ms, box-shadow 200ms ease-in-out 200ms, + height 200ms ease 100ms, left 200ms ease-in-out 1ms; +} + +.dui-navbar2:not(.unselected) + .dui-submenu-container.marketplace-selected + .item.submenu.marketplace-submenu, +.dui-navbar2:not(.unselected) + .dui-submenu-container.create-selected + .item.submenu.create-submenu, +.dui-navbar2:not(.unselected) + .dui-submenu-container.explore-selected + .item.submenu.explore-submenu, +.dui-navbar2:not(.unselected) + .dui-submenu-container.learn-selected + .item.submenu.learn-submenu, +.dui-navbar2:not(.unselected) + .dui-submenu-container.governance-selected + .item.submenu.governance-submenu { + opacity: 1; + z-index: 10; + top: var(--navbar-height); + box-shadow: var(--shadow-2); +} + +.dui-navbar2 .item.submenu::after { + content: ''; + position: absolute; + width: 370px; + height: 100%; + top: 0; + background-repeat: no-repeat; + background-position: bottom center; + left: 0; + background-size: auto 90%; +} + +.dui-navbar2 .item.submenu.marketplace-submenu::after { + background-image: url('../../assets/navbar-avatar-marketplace.png'); +} + +.dui-navbar2 .item.submenu.create-submenu::after { + background-image: url('../../assets/navbar-avatar-create.png'); +} + +.dui-navbar2 .item.submenu.explore-submenu::after { + background-image: url('../../assets/navbar-avatar-discover.png'); +} + +.dui-navbar2 .item.submenu.learn-submenu::after { + background-image: url('../../assets/navbar-avatar-learn.png'); +} + +.dui-navbar2 .item.submenu.governance-submenu::after { + background-image: url('../../assets/navbar-avatar-vote.png'); +} + +.dui-navbar2 .item.submenu.marketplace-submenu { + background-image: radial-gradient( + 350px 200px at 400px 120%, + #691fa933 0%, + transparent 150% + ), + radial-gradient(350px 200px at 1280px 120%, #691fa933 0%, #073aff00 100%); + height: 390px; +} + +.dui-navbar2 .item.submenu.create-submenu { + background-image: radial-gradient( + 350px 200px at 400px 120%, + #ff743933 0%, + transparent 150% + ), + radial-gradient(350px 200px at 1280px 120%, #ff743933 0%, #073aff00 100%); + height: 430px; +} + +.dui-navbar2 .item.submenu.explore-submenu { + background-image: radial-gradient( + 350px 200px at 400px 120%, + #3dd0ff33 0%, + transparent 150% + ), + radial-gradient(350px 200px at 1280px 120%, #3dd0ff33 0%, #073aff00 100%); + height: 390px; +} + +.dui-navbar2 .item.submenu.learn-submenu { + background-image: radial-gradient( + 350px 200px at 400px 120%, + #a6746433 0%, + transparent 150% + ), + radial-gradient(350px 200px at 1280px 120%, #a6746433 0%, #073aff00 100%); + height: 390px; +} + +.dui-navbar2 .item.submenu.governance-submenu { + background-image: radial-gradient( + 350px 200px at 400px 120%, + #ff3dec33 0%, + transparent 150% + ), + radial-gradient(350px 200px at 1280px 120%, #ff3dec33 0%, #073aff00 100%); + height: 390px; +} + +.dui-navbar2 .item.submenu .submenu-column__wrapper { + width: 100%; + display: flex; + align-items: flex-start; + height: fit-content; +} + +.dui-navbar2 .submenu .ui.vertical.menu { + background: transparent; + box-shadow: var(--shadow-2); +} + +.dui-navbar2 .submenu .item { + font-weight: normal; + color: var(--text); + border-radius: 0; + text-transform: uppercase; + font-family: var(--font-family); + margin-left: 0; + margin-right: 0; + font-size: 13px; + line-height: 1.4285em; + display: flex; + align-items: center; + border-bottom: 1px solid var(--dropdown-hover); + padding: 12px 16px; +} + +.dui-navbar2 .dui-navbar2-wrapper .item .submenu .item:last-child { + border-bottom: none; +} + +.dui-navbar2 .dui-navbar2-wrapper .item .submenu .item:hover { + background-color: var(--dropdown-hover); +} + +.dui-navbar2 .dui-navbar2-toggle { + display: none; + height: 9px; + width: 32px; + position: relative; +} + +.dui-navbar2 .dui-navbar2-toggle { + transition: all 200ms ease-in-out; +} + +.dui-navbar2 .dui-navbar2-toggle span { + transition: top 200ms ease-in-out, left 200ms ease-in-out, + width 200ms ease-in-out, transform 200ms ease-in-out; + height: 2px; + width: 100%; + background-color: var(--usermenu-item-text-enabled); + position: absolute; +} + +.dui-navbar2 .dui-navbar2-toggle span:nth-of-type(1) { + top: 0; + left: 0; +} + +.dui-navbar2 .dui-navbar2-toggle span:nth-of-type(2) { + top: 100%; + left: 0; +} + +.dui-navbar2 + .dui-navbar2-wrapper + .menu-item.item:hover + .icon-container.centered + svg + path:nth-child(2) { + fill: var(--text); +} + +@media (max-width: 1280px) { + .dui-navbar2 .item.submenu { + padding-left: 48px; + padding-right: 48px; + width: calc(100% - 92px); + } + + .dui-navbar2 .item.submenu.marketplace-submenu::after, + .dui-navbar2 .item.submenu.create-submenu::after, + .dui-navbar2 .item.submenu.explore-submenu::after, + .dui-navbar2 .item.submenu.learn-submenu::after, + .dui-navbar2 .item.submenu.governance-submenu::after { + background-image: none; + } + + .dui-navbar2 .item.submenu .submenu-column__wrapper { + flex-flow: row wrap; + } +} + +@media (max-width: 1199px) { + .dui-navbar2 > .ui.container.dui-navbar2-container { + width: 100%; + padding: 0 24px; + box-sizing: border-box; + margin: 0; + } +} + +@media (max-width: 991px) { + .dui-navbar2 > .ui.container.dui-navbar2-container { + margin: 0 !important; + } + + .dui-navbar2 .dui-navbar2-toggle { + display: flex; + cursor: pointer; + } + + .dui-navbar2 .dui-navbar2-toggle.open { + position: relative; + height: 24px; + width: 24px; + } + + .dui-navbar2 .dui-navbar2-toggle.open span:nth-of-type(1) { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%) rotate(45deg); + width: 33.94px; + } + + .dui-navbar2 .dui-navbar2-toggle.open span:nth-of-type(2) { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%) rotate(-45deg); + width: 33.94px; + } + + .dui-navbar2 .item.submenu { + transition: top 0ms ease-in-out 0ms, box-shadow 200ms ease-in-out 200ms, + height 200ms ease 100ms, left 200ms ease-in-out 1ms; + } + + .dui-navbar2 .item.submenu.marketplace-submenu, + .dui-navbar2 .item.submenu.create-submenu, + .dui-navbar2 .item.submenu.explore-submenu, + .dui-navbar2 .item.submenu.learn-submenu, + .dui-navbar2 .item.submenu.governance-submenu { + background-image: none; + background-color: var(--background); + left: 150%; + } + + .dui-navbar2-menu .dui-navbar2-logo { + position: absolute; + left: 50%; + transform: translateX(-50%); + } + + .dui-navbar2.dui-navbar2__mobile-open .dui-submenu-container.mobile, + .dui-navbar2:not(.unselected) .dui-submenu-container.mobile { + z-index: 20; + } + + .dui-navbar2.dui-navbar2__mobile-open.unselected + .dui-submenu-container.marketplace-selected + .item.submenu.marketplace-submenu, + .dui-navbar2.dui-navbar2__mobile-open.unselected + .dui-submenu-container.explore-selected + .item.submenu.explore-submenu, + .dui-navbar2.dui-navbar2__mobile-open.unselected + .dui-submenu-container.learn-selected + .item.submenu.learn-submenu, + .dui-navbar2.dui-navbar2__mobile-open.unselected + .dui-submenu-container.governance-selected + .item.submenu.governance-submenu, + .dui-navbar2.dui-navbar2__mobile-open.unselected + .dui-submenu-container.create-selected + .item.submenu.create-submenu { + left: 150%; + top: var(--navbar-height); + } + + .dui-navbar2.dui-navbar2__mobile-open + .dui-submenu-container.marketplace-selected + .item.submenu.marketplace-submenu, + .dui-navbar2.dui-navbar2__mobile-open + .dui-submenu-container.explore-selected + .item.submenu.explore-submenu, + .dui-navbar2.dui-navbar2__mobile-open + .dui-submenu-container.learn-selected + .item.submenu.learn-submenu, + .dui-navbar2.dui-navbar2__mobile-open + .dui-submenu-container.governance-selected + .item.submenu.governance-submenu, + .dui-navbar2.dui-navbar2__mobile-open + .dui-submenu-container.create-selected + .item.submenu.create-submenu { + background-color: var(--background); + height: 100vh; + width: calc(100% - 50px); + padding: 0; + margin: 0 25px; + align-items: flex-start; + box-shadow: none; + top: var(--navbar-height); + left: 0; + } + + .dui-navbar2 .item.submenu .submenu-column__wrapper { + flex-direction: column; + } + + .dui-navbar2 .item.submenu .submenu-column__wrapper .dcl.back { + border: none; + padding-left: 30px; + padding-top: 5px; + background-position-x: 2px; + background-position-y: 9px; + margin-left: 0; + } + + .dui-navbar2 .item.submenu::after { + display: none; + } + + .dui-navbar2.dui-navbar2__mobile-open + .dui-navbar2__menu.dui-navbar2__menu-mobile { + top: 56px; + } + + .dui-navbar2.dui-navbar2__mobile-open .item.submenu .dui-submenu-item h1, + .dui-navbar2.dui-navbar2__mobile-open .item.submenu .dui-submenu-item p { + color: var(--navbar-menu-hover); + } +} diff --git a/src/components/Navbar2/Navbar2.defaults.ts b/src/components/Navbar2/Navbar2.defaults.ts new file mode 100644 index 00000000..76165421 --- /dev/null +++ b/src/components/Navbar2/Navbar2.defaults.ts @@ -0,0 +1,211 @@ +import { config } from '../../config' +import { Navbar2SubmenuProps, Navbar2MenuI18nProps } from './Navbar2.types' + +export const navbarMainTitlesI18N = { + marketplace: 'marketplace', + create: 'create', + explore: 'explore', + learn: 'learn', + governance: 'governance' +} as Navbar2MenuI18nProps + +export const navbarSubmenu = { + marketplace: { + column1: [ + { + title: 'Overview', + description: "See what's trending & new", + url: config.get('MARKETPLACE_URL'), + eventTrackingName: 'marketplace_overview' + }, + { + title: 'NAMEs', + description: 'Claim a NAME, get a whole World', + url: config.get('MARKETPLACE_NAMES_URL'), + eventTrackingName: 'marketplace_names' + } + ], + column2: [ + { + title: 'Wearables', + description: 'Customize your digital identity', + url: config.get('MARKETPLACE_WEARABLES_URL'), + eventTrackingName: 'marketplace_wearables' + }, + { + title: 'LAND', + description: 'Buy or Rent parcels on the Genesis City map', + url: config.get('MARKETPLACE_LANDS_URL'), + eventTrackingName: 'marketplace_lands' + } + ], + column3: [ + { + title: 'Emotes', + description: 'Animate your avatar', + url: config.get('MARKETPLACE_EMOTES_URL'), + eventTrackingName: 'marketplace_emotes' + }, + { + title: 'My Assets', + description: 'Manage your assets, listings, bids, &and more', + url: config.get('MARKETPLACE_MY_ASSETS_URL'), + eventTrackingName: 'marketplace_my_assets' + } + ] + }, + create: { + column1Title: 'PUBLISH', + column1: [ + { + title: 'Wearables & Emotes', + description: 'Publish & manage Marketplace collections', + url: config.get('BUILDER_WEARABLE_EMOTES_URL'), + eventTrackingName: 'builder_wearables_emotes' + }, + { + title: 'Scenes', + description: 'Create & publish scenes to LAND or Worlds', + url: config.get('BUILDER_SCENES_URL'), + eventTrackingName: 'builder_scenes' + } + ], + column2Title: 'MANAGE', + column2: [ + { + title: 'My NAMEs', + description: 'Create & manage NAMEs', + url: config.get('BUILDER_NAMES_URL'), + eventTrackingName: 'builder_names' + }, + { + title: 'My Worlds', + description: 'Manage Worlds & Worlds storage', + url: config.get('BUILDER_WORLDS_URL'), + eventTrackingName: 'builder_worlds' + }, + { + title: 'My LAND', + description: 'Manage parcel permissions & more', + url: config.get('BUILDER_LAND_URL'), + eventTrackingName: 'builder_land' + } + ], + column3Title: 'HIRE', + column3: [ + { + title: 'Decentraland Studios', + description: 'Hire pros to transform your ideas to reality', + url: config.get('STUDIOS_URL'), + eventTrackingName: 'studios', + isExternal: true + } + ] + }, + explore: { + column1: [ + { + title: 'Events', + description: 'Find an event to jump into', + url: config.get('EVENTS_URL'), + eventTrackingName: 'events' + }, + { + title: 'My Events', + description: 'See saved events & events you’re hosting', + url: config.get('EVENTS_MY_EVENTS_URL'), + eventTrackingName: 'events_my_events' + } + ], + column2: [ + { + title: 'Places', + description: 'Browse locations in Genesis City & Worlds', + url: config.get('PLACES_URL'), + eventTrackingName: 'places' + }, + { + title: 'My Favorite Places', + description: 'See your saved locations', + url: config.get('PLACES_MY_FAVORITE_URL'), + eventTrackingName: 'places_my_favorite' + } + ] + }, + learn: { + column1: [ + { + title: 'About Decentraland', + description: 'FAQs, Whitepaper, & DAO docs', + url: config.get('DOCS_ABOUT_URL'), + eventTrackingName: 'docs_about' + }, + { + title: 'Creator Docs', + description: 'Make Wearables, Emotes, scenes, games, & more', + url: config.get('DOCS_CREATORS_URL'), + eventTrackingName: 'docs_creators' + } + ], + column2: [ + { + title: 'Blog', + description: 'News, Community Highlights, & more', + url: config.get('BLOG_URL'), + eventTrackingName: 'blog', + isExternal: true + }, + { + title: 'Open Protocol Docs', + description: 'See how Decentraland works & contribute', + url: config.get('DOCS_CONTRIBUTOR_URL'), + eventTrackingName: 'docs_contributor' + } + ] + }, + governance: { + column1: [ + { + title: 'Overview', + description: 'The latest in Decentraland governance', + url: config.get('GOVERNANCE_URL'), + eventTrackingName: 'governance_overview' + }, + { + title: 'DAO Transparency', + description: 'Treasury, Activity Dashboards, & more', + url: config.get('GOVERNANCE_TRANSPARENCY_URL'), + eventTrackingName: 'governance_transparency' + } + ], + column2: [ + { + title: 'Proposals', + description: 'Vote on active proposals', + url: config.get('GOVERNANCE_PROPOSALS_URL'), + eventTrackingName: 'governance_proposals' + }, + { + title: 'DAO Grants', + description: 'Community grants overview, highlights, & resources', + url: config.get('DAO_GRANTS_URL'), + eventTrackingName: 'dao_grants', + isExternal: true + } + ], + column3: [ + { + title: 'Active Grants', + description: 'Browse grant-funded community projects', + url: config.get('GOVERNANCE_PROJECTS_URL'), + eventTrackingName: 'governance_active_grants' + }, + { + title: 'DAO Docs', + description: 'Learn about the DAO & how to participate', + url: config.get('DOCS_DAO_URL'), + eventTrackingName: 'docs_dao' + } + ] + } +} as Navbar2SubmenuProps diff --git a/src/components/Navbar2/Navbar2.stories.css b/src/components/Navbar2/Navbar2.stories.css new file mode 100644 index 00000000..80ca19f1 --- /dev/null +++ b/src/components/Navbar2/Navbar2.stories.css @@ -0,0 +1,64 @@ +.dui-navbar2-story-container { + position: absolute; + overflow: hidden; + width: 100%; + height: 100vh; + left: 0; + top: 0; +} + +.dui-navbar2-story-container .color-layer { + width: 100%; + height: 100%; + background-image: linear-gradient(to bottom, #060d2b, #132d7d 52%, #9763c1); + position: absolute; +} + +.dui-navbar2-story-container .over-gradient .ui.header { + color: white; +} + +.dui-navbar2-story-container .homepage-pyramid { + background: url('../../assets/pyramid.svg'); + background-size: contain; + background-repeat: no-repeat; +} + +.dui-navbar2-story-container .homepage-pyramid.small { + width: 400px; + height: 400px; + margin-left: -100px; + margin-top: 250px; + filter: var(--pyramid-small-brightness); +} + +.dui-navbar2-story-container .homepage-pyramid.large { + width: 1000px; + height: 1000px; + margin-top: -200px; + margin-left: 300px; + filter: var(--pyramid-large-brightness); +} + +.dui-navbar2-story-container .dcl.dui-navbar2 .dcl.hero { + background-color: #f2f2f5; +} + +.dui-navbar2-story-container .background { + background-image: url(../../assets/background.png); + + background-repeat: no-repeat; + background-size: cover; + background-position: 50%; + position: absolute; + top: 0px; + left: 0px; + right: 0px; + bottom: 0px; +} + +@media (max-width: 768px) { + .dui-navbar2-story-container { + width: 100%; + } +} diff --git a/src/components/Navbar2/Navbar2.stories.tsx b/src/components/Navbar2/Navbar2.stories.tsx new file mode 100644 index 00000000..eb783aa1 --- /dev/null +++ b/src/components/Navbar2/Navbar2.stories.tsx @@ -0,0 +1,186 @@ +import * as React from 'react' +import { storiesOf } from '@storybook/react' +import { avatar } from '../../data/avatar' + +import { Navbar2 } from './Navbar2' +import { Navbar2Pages } from './Navbar2.types' +import { Network } from '@dcl/schemas/dist/dapps/network' +import { Rarity } from '@dcl/schemas/dist/dapps/rarity' +import { NFTCategory } from '@dcl/schemas/dist/dapps/nft-category' +import { NotificationActiveTab } from '../Notifications/types' + +import './Navbar2.stories.css' + +storiesOf('Navbar2', module) + .add('Marketplace', () => { + return ( +
+ +
+ ) + }) + .add('Sign In', () => { + return ( +
+ console.log('Clicked on sign in')} + /> +
+ ) + }) + .add('Signed in', () => { + return ( +
+ console.log('Clicked on sign in')} + /> +
+ ) + }) + .add('Signed in', () => { + return ( +
+ console.log('Clicked on sign in')} + /> +
+ ) + }) + .add('With Balance', () => { + return ( +
+ console.log('Clicked on sign in', e)} + /> +
+ ) + }) + .add('Width Activity pending', () => { + return ( +
+ console.log('Clicked on sign in ', e)} + manaBalances={{ [Network.ETHEREUM]: 1000, [Network.MATIC]: 2500 }} + onClickBalance={(e, network) => + console.log('Clicked on balance ', e, network) + } + onClickActivity={(e) => console.log('Clicked on activity ', e)} + hasActivity + /> +
+ ) + }) + .add('With Notification', () => { + return ( +
+ console.log('Clicked on sign in ', e)} + manaBalances={{ [Network.ETHEREUM]: 1000, [Network.MATIC]: 2500 }} + onClickBalance={(e, network) => + console.log('Clicked on balance ', e, network) + } + onClickActivity={(e) => console.log('Clicked on activity ', e)} + hasActivity + notifications={{ + isOnboarding: false, + isOpen: false, + isLoading: false, + items: [ + { + id: 'A', + read: true, + type: 'item_sold', + address: '0xA', + timestamp: 1680108689 * 1000, + metadata: { + link: 'https://market.decentraland.org/contracts/0x4c290f486bae507719c562b6b524bdb71a2570c9/tokens/1020', + image: + 'https://peer.decentraland.org/lambdas/collections/contents/urn:decentraland:ethereum:collections-v1:atari_launch:atari_green_upper_body/thumbnail', + rarity: 'epic' as Rarity, + seller: '0x8bc619e7f9ca9949b8440245fd9d8c4c002edf02', + nftName: 'Green Atari Tee', + network: 'ethereum', + category: 'wearable' as NFTCategory + }, + created_at: '2023-11-29T12:51:00.600Z', + updated_at: '2023-11-30T12:51:00.600Z' + } + ], + locale: 'en', + activeTab: NotificationActiveTab.NEWEST, + onBegin: console.log, + onChangeTab: console.log, + onClick: console.log, + onClose: console.log + }} + /> +
+ ) + }) + .add('With Notification pending', () => { + return ( +
+ console.log('Clicked on sign in ', e)} + manaBalances={{ [Network.ETHEREUM]: 1000, [Network.MATIC]: 2500 }} + onClickBalance={(e, network) => + console.log('Clicked on balance ', e, network) + } + onClickActivity={(e) => console.log('Clicked on activity ', e)} + hasActivity + notifications={{ + isOnboarding: false, + isOpen: false, + isLoading: false, + items: [ + { + id: 'A', + read: false, + type: 'item_sold', + address: '0xA', + timestamp: 1680108689 * 1000, + metadata: { + link: 'https://market.decentraland.org/contracts/0x4c290f486bae507719c562b6b524bdb71a2570c9/tokens/1020', + image: + 'https://peer.decentraland.org/lambdas/collections/contents/urn:decentraland:ethereum:collections-v1:atari_launch:atari_green_upper_body/thumbnail', + rarity: 'epic' as Rarity, + seller: '0x8bc619e7f9ca9949b8440245fd9d8c4c002edf02', + nftName: 'Green Atari Tee', + network: 'ethereum', + category: 'wearable' as NFTCategory + }, + created_at: '2023-11-29T12:51:00.600Z', + updated_at: '2023-11-29T12:51:00.600Z' + } + ], + locale: 'en', + activeTab: NotificationActiveTab.NEWEST, + onBegin: console.log, + onChangeTab: console.log, + onClick: console.log, + onClose: console.log + }} + /> +
+ ) + }) diff --git a/src/components/Navbar2/Navbar2.tsx b/src/components/Navbar2/Navbar2.tsx new file mode 100644 index 00000000..35972005 --- /dev/null +++ b/src/components/Navbar2/Navbar2.tsx @@ -0,0 +1,132 @@ +import React, { useState, useCallback } from 'react' +import classNames from 'classnames' + +import { Container } from '../Container/Container' +import { Logo } from '../Logo/Logo' +import { Desktop, TabletAndBelow, useTabletAndBelowMediaQuery } from '../Media' +import { UserMenu } from '../UserMenu/UserMenu' +import { Navbar2Pages, Navbar2Props } from './Navbar2.types' +import { SubMenu } from './SubMenu/SubMenu' +import { MainMenu } from './MainMenu/MainMenu' +import { + navbarMainTitlesI18N as i18nNavbarTitlesDefault, + navbarSubmenu +} from './Navbar2.defaults' +import { i18n as i18nUserMenuDefault } from '../UserMenu/UserMenu.i18n' + +import './Navbar2.css' + +export const Navbar2 = React.memo((props: Navbar2Props) => { + const { + activePage, + className, + isSignedIn, + i18nNavbar = i18nNavbarTitlesDefault, + i18nUserMenu = i18nUserMenuDefault, + submenuItems = navbarSubmenu, + onClickMenuItem, + ...userMenuProps + } = props + const [toggle, setToggle] = useState(false) + const [selectedMenu, setSelectedMenu] = useState() + const [menuMobileOpen, setMenuMobileOpen] = useState(false) + + const isTabletAndBelow = useTabletAndBelowMediaQuery() + + const handleToggle = useCallback( + (e: React.MouseEvent, show: boolean, section: Navbar2Pages) => { + setToggle(show) + show && setSelectedMenu(section) + }, + [setToggle, setSelectedMenu] + ) + + const handleMobileToggle = useCallback( + (e: React.MouseEvent, show: boolean) => { + !show && setToggle(false) + setMenuMobileOpen(show) + }, + [setToggle, setMenuMobileOpen] + ) + + const handleClickMenu = useCallback( + ( + event: React.MouseEvent, + eventTracking: string + ) => { + onClickMenuItem && onClickMenuItem(event, eventTracking) + }, + [onClickMenuItem] + ) + + return ( +
+ +
+
+ +
handleMobileToggle(e, !menuMobileOpen)} + > + + +
+
+ + + + + + +
+ + + + + +
+ +
+
+
+ + + + + +
+ ) +}) diff --git a/src/components/Navbar2/Navbar2.types.ts b/src/components/Navbar2/Navbar2.types.ts new file mode 100644 index 00000000..530193b9 --- /dev/null +++ b/src/components/Navbar2/Navbar2.types.ts @@ -0,0 +1,54 @@ +import { UserMenuI18N, UserMenuProps } from '../UserMenu/UserMenu.types' + +export enum Navbar2Pages { + MARKETPLACE = 'marketplace', + CREATE = 'create', + EXPLORE = 'explore', + LEARN = 'learn', + GOVERNANCE = 'governance' +} + +export type Navbar2MenuI18nProps = Record + +export type Navbar2SubMenuItemsProps = { + column1Title?: string + column1: { + title: string + description: string + url: string + eventTrackingName: string + isExternal?: boolean + }[] + column2Title?: string + column2: { + title: string + description: string + url: string + eventTrackingName: string + isExternal?: boolean + }[] + column3Title?: string + column3?: { + title: string + description: string + url: string + eventTrackingName: string + isExternal?: boolean + }[] +} + +export type Navbar2SubmenuProps = { + marketplace: Navbar2SubMenuItemsProps + create: Navbar2SubMenuItemsProps + explore: Navbar2SubMenuItemsProps + learn: Navbar2SubMenuItemsProps + governance: Navbar2SubMenuItemsProps +} + +export type Navbar2Props = Omit & { + i18nNavbar?: Navbar2MenuI18nProps + submenuItems?: Navbar2SubmenuProps + i18nUserMenu?: UserMenuI18N + activePage: Navbar2Pages | string + className?: string +} diff --git a/src/components/Navbar2/SubMenu/SubMenu.css b/src/components/Navbar2/SubMenu/SubMenu.css new file mode 100644 index 00000000..bc51e870 --- /dev/null +++ b/src/components/Navbar2/SubMenu/SubMenu.css @@ -0,0 +1,14 @@ +.dui-submenu-container { + background-color: transparent; + height: 0; + opacity: 0; + transition: height 200ms ease-in-out 1ms, opacity 100ms ease-in-out 50ms, + background-color 100ms ease-in-out 0ms; +} + +@media (max-width: 991px) { + .dui-submenu-container.mobile { + position: absolute; + z-index: 0; + } +} diff --git a/src/components/Navbar2/SubMenu/SubMenu.tsx b/src/components/Navbar2/SubMenu/SubMenu.tsx new file mode 100644 index 00000000..bbc0d5ee --- /dev/null +++ b/src/components/Navbar2/SubMenu/SubMenu.tsx @@ -0,0 +1,100 @@ +import React from 'react' +import classNames from 'classnames' +import Menu from 'semantic-ui-react/dist/commonjs/collections/Menu' + +import { Back } from '../../Back/Back' +import { Navbar2Pages } from '../Navbar2.types' +import { SubMenuProps } from './SubMenu.types' +import { SubMenuColumn } from '../SubMenuColumn/SubMenuColumn' +import { SubMenuItem } from '../SubMenuItem/SubMenuItem' + +import './SubMenu.css' + +export const SubMenu = (props: SubMenuProps) => { + const { + selectedMenu, + onToggleShowSubMenu, + onClickMenuOption, + isMobile, + submenus + } = props + + return ( +
+ {Object.keys(submenus).map((key) => { + const section = key as Navbar2Pages + const submenu = submenus[section] + return ( + + !isMobile && onToggleShowSubMenu(e, true, section) + } + onMouseLeave={(e: React.MouseEvent) => + !isMobile && onToggleShowSubMenu(e, false, section) + } + > +
+ {isMobile && ( + onToggleShowSubMenu(e, false, section)} + > + Back + + )} + + {submenu.column1.map((item, index) => ( + + ))} + + + {submenu.column2.map((item, index) => ( + + ))} + + {!!submenu.column3 && ( + + {submenu.column3.map((item, index) => ( + + ))} + + )} +
+
+ ) + })} +
+ ) +} diff --git a/src/components/Navbar2/SubMenu/SubMenu.types.ts b/src/components/Navbar2/SubMenu/SubMenu.types.ts new file mode 100644 index 00000000..1fc882c3 --- /dev/null +++ b/src/components/Navbar2/SubMenu/SubMenu.types.ts @@ -0,0 +1,16 @@ +import { Navbar2SubmenuProps, Navbar2Pages } from '../Navbar2.types' + +export type SubMenuProps = { + selectedMenu: Navbar2Pages | boolean + submenus: Navbar2SubmenuProps + onToggleShowSubMenu: ( + e: React.MouseEvent, + show: boolean, + section?: Navbar2Pages + ) => void + onClickMenuOption?: ( + event: React.MouseEvent, + eventTracking: string + ) => void + isMobile?: boolean +} diff --git a/src/components/Navbar2/SubMenuColumn/SubMenuColumn.css b/src/components/Navbar2/SubMenuColumn/SubMenuColumn.css new file mode 100644 index 00000000..a29e4989 --- /dev/null +++ b/src/components/Navbar2/SubMenuColumn/SubMenuColumn.css @@ -0,0 +1,44 @@ +.dui-submenu-column { + display: flex; + flex-flow: column nowrap; + justify-content: center; + height: 100%; + flex-wrap: nowrap; + margin-right: 56px; + flex: 1; + max-width: 350px; +} + +.dui-submenu-column:not(.dui-submenu-column-title) > h1 { + display: none; +} + +.dui-submenu-column.dui-submenu-column-title > h1 { + color: val(--navbar-menu-enabled); + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 18px; + margin: 0; +} + +@media (max-width: 991px) { + .dui-submenu-column { + width: 100%; + max-width: 100%; + } + + .dui-navbar2 + .item.submenu + .submenu-column__wrapper + .dui-submenu-column:nth-child(2) { + margin-top: 37px; + } + + .dui-navbar2.dui-navbar2__mobile-open + .item.submenu + .dui-submenu-column.dui-submenu-column-title + > h1 { + margin: 20px 0 0; + } +} diff --git a/src/components/Navbar2/SubMenuColumn/SubMenuColumn.tsx b/src/components/Navbar2/SubMenuColumn/SubMenuColumn.tsx new file mode 100644 index 00000000..3bc32bc6 --- /dev/null +++ b/src/components/Navbar2/SubMenuColumn/SubMenuColumn.tsx @@ -0,0 +1,22 @@ +import React from 'react' +import classNames from 'classnames' + +import { SubMenuColumnProps } from './SubMenuColumn.types' + +import './SubMenuColumn.css' + +export const SubMenuColumn = (props: SubMenuColumnProps) => { + const { children, title, className } = props + return ( +
+ {!!title &&

{title}

} + {children} +
+ ) +} diff --git a/src/components/Navbar2/SubMenuColumn/SubMenuColumn.types.ts b/src/components/Navbar2/SubMenuColumn/SubMenuColumn.types.ts new file mode 100644 index 00000000..e1f6ded4 --- /dev/null +++ b/src/components/Navbar2/SubMenuColumn/SubMenuColumn.types.ts @@ -0,0 +1,6 @@ +export type SubMenuColumnProps = { + children: React.ReactNode + title?: string + isExternal?: boolean + className?: string +} diff --git a/src/components/Navbar2/SubMenuItem/SubMenuItem.css b/src/components/Navbar2/SubMenuItem/SubMenuItem.css new file mode 100644 index 00000000..db44f435 --- /dev/null +++ b/src/components/Navbar2/SubMenuItem/SubMenuItem.css @@ -0,0 +1,75 @@ +.dui-submenu-item a { + width: 100%; +} + +.dui-submenu-item.dui-submenu-item-external { + position: relative; + padding-right: 20px; + width: calc(100% - 20px); +} + +.dui-submenu-item.dui-submenu-item-external .dui-icon-container { + position: absolute; + top: 50%; + right: 0; + width: 14px; + height: 15px; + transform: translateY(-50%); +} + +.dui-submenu-item.dui-submenu-item-external .dui-icon-container svg path { + fill: var(--navbar-item-text-enabled); +} + +.dui-submenu-item.dui-submenu-item-external:hover .dui-icon-container svg path { + fill: var(--navbar-item-text-hover); +} + +.dui-submenu-item { + display: flex; + padding: 0; + width: 100%; + border-bottom-color: var(--navbar-item-border-enabled); + border-bottom-style: solid; + margin-bottom: 6px; + padding-bottom: 16px; + height: 60px; +} + +.dui-submenu-item:hover { + border-bottom-color: var(--navbar-item-border-hover); +} + +.dui-submenu-item:not(:first-child) { + margin-top: 32px; +} + +.dui-submenu-item h1, +.dui-submenu-item p { + color: var(--navbar-item-text-enabled); +} + +.dui-submenu-item:hover h1, +.dui-submenu-item:hover p { + color: var(--navbar-item-text-hover); +} + +.dui-submenu-item h1 { + font-size: 18px; + font-weight: 600; + line-height: 18px; + margin-bottom: 6px; +} + +.dui-submenu-item p { + font-size: 14px; + font-weight: 400; + line-height: 18px; +} + +@media (max-width: 991px) { + .dui-submenu-item { + margin-top: 32px; + border-bottom-color: var(--navbar-menu-hover); + } +} diff --git a/src/components/Navbar2/SubMenuItem/SubMenuItem.tsx b/src/components/Navbar2/SubMenuItem/SubMenuItem.tsx new file mode 100644 index 00000000..0f3439ab --- /dev/null +++ b/src/components/Navbar2/SubMenuItem/SubMenuItem.tsx @@ -0,0 +1,34 @@ +import React from 'react' + +import classNames from 'classnames' +import { SubMenuItemProps } from './SubMenuItem.types' +import ExternalIcon from '../../Icons/ExternalIcon' + +import './SubMenuItem.css' + +export const SubMenuItem = (props: SubMenuItemProps) => { + const { + title, + description, + href, + isExternal, + className, + eventTrackingName, + onClickMenuOption + } = props + return ( + + ) +} diff --git a/src/components/Navbar2/SubMenuItem/SubMenuItem.types.ts b/src/components/Navbar2/SubMenuItem/SubMenuItem.types.ts new file mode 100644 index 00000000..7a5da992 --- /dev/null +++ b/src/components/Navbar2/SubMenuItem/SubMenuItem.types.ts @@ -0,0 +1,12 @@ +export type SubMenuItemProps = { + title: string + description: string + href: string + eventTrackingName: string + isExternal?: boolean + className?: string + onClickMenuOption?: ( + event: React.MouseEvent, + eventTrackingName: string + ) => void +} diff --git a/src/components/Notifications/Notifications.css b/src/components/Notifications/Notifications.css index 47ae9c16..75358f22 100644 --- a/src/components/Notifications/Notifications.css +++ b/src/components/Notifications/Notifications.css @@ -28,4 +28,5 @@ position: relative; top: -24px; left: 19px; + cursor: pointer; } diff --git a/src/components/Notifications/Notifications.stories.tsx b/src/components/Notifications/Notifications.stories.tsx index 59011a1d..acdec482 100644 --- a/src/components/Notifications/Notifications.stories.tsx +++ b/src/components/Notifications/Notifications.stories.tsx @@ -320,6 +320,174 @@ storiesOf('Notifications Toggle', module) created_at: '2023-11-29T12:51:00.600Z', updated_at: '2023-11-29T12:51:00.600Z' }, + { + id: 'A', + read: true, + type: 'item_sold', + address: '0xA', + timestamp: new Date( + new Date().setHours(new Date().getHours() - 19) + ).getTime(), + metadata: { + link: 'https://market.decentraland.org/contracts/0xa8ee490e4c4da48cc1653502c1a77479d4d818de/tokens/590', + image: + 'https://peer.decentraland.org/lambdas/collections/contents/urn:decentraland:ethereum:collections-v1:binance_us_collection:binance_us_upper_body/thumbnail', + rarity: 'epic' as Rarity, + seller: '0x6b347a82fcac4e6a38d1fc40e3631bd8f9495e9f', + nftName: 'Exclusive Binance Hoodie', + network: 'ethereum', + category: 'wearable' as NFTCategory + }, + created_at: '2023-11-29T12:51:00.600Z', + updated_at: '2023-11-29T12:51:00.600Z' + }, + { + id: 'A', + read: true, + type: 'item_sold', + address: '0xA', + timestamp: new Date( + new Date().setHours(new Date().getHours() - 19) + ).getTime(), + metadata: { + link: 'https://market.decentraland.org/contracts/0xa8ee490e4c4da48cc1653502c1a77479d4d818de/tokens/590', + image: + 'https://peer.decentraland.org/lambdas/collections/contents/urn:decentraland:ethereum:collections-v1:binance_us_collection:binance_us_upper_body/thumbnail', + rarity: 'epic' as Rarity, + seller: '0x6b347a82fcac4e6a38d1fc40e3631bd8f9495e9f', + nftName: 'Exclusive Binance Hoodie', + network: 'ethereum', + category: 'wearable' as NFTCategory + }, + created_at: '2023-11-29T12:51:00.600Z', + updated_at: '2023-11-29T12:51:00.600Z' + }, + { + id: 'A', + read: true, + type: 'item_sold', + address: '0xA', + timestamp: new Date( + new Date().setHours(new Date().getHours() - 19) + ).getTime(), + metadata: { + link: 'https://market.decentraland.org/contracts/0xa8ee490e4c4da48cc1653502c1a77479d4d818de/tokens/590', + image: + 'https://peer.decentraland.org/lambdas/collections/contents/urn:decentraland:ethereum:collections-v1:binance_us_collection:binance_us_upper_body/thumbnail', + rarity: 'epic' as Rarity, + seller: '0x6b347a82fcac4e6a38d1fc40e3631bd8f9495e9f', + nftName: 'Exclusive Binance Hoodie', + network: 'ethereum', + category: 'wearable' as NFTCategory + }, + created_at: '2023-11-29T12:51:00.600Z', + updated_at: '2023-11-29T12:51:00.600Z' + }, + { + id: 'A', + read: true, + type: 'item_sold', + address: '0xA', + timestamp: new Date( + new Date().setHours(new Date().getHours() - 19) + ).getTime(), + metadata: { + link: 'https://market.decentraland.org/contracts/0xa8ee490e4c4da48cc1653502c1a77479d4d818de/tokens/590', + image: + 'https://peer.decentraland.org/lambdas/collections/contents/urn:decentraland:ethereum:collections-v1:binance_us_collection:binance_us_upper_body/thumbnail', + rarity: 'epic' as Rarity, + seller: '0x6b347a82fcac4e6a38d1fc40e3631bd8f9495e9f', + nftName: 'Exclusive Binance Hoodie', + network: 'ethereum', + category: 'wearable' as NFTCategory + }, + created_at: '2023-11-29T12:51:00.600Z', + updated_at: '2023-11-29T12:51:00.600Z' + }, + { + id: 'A', + read: true, + type: 'item_sold', + address: '0xA', + timestamp: new Date( + new Date().setHours(new Date().getHours() - 19) + ).getTime(), + metadata: { + link: 'https://market.decentraland.org/contracts/0xa8ee490e4c4da48cc1653502c1a77479d4d818de/tokens/590', + image: + 'https://peer.decentraland.org/lambdas/collections/contents/urn:decentraland:ethereum:collections-v1:binance_us_collection:binance_us_upper_body/thumbnail', + rarity: 'epic' as Rarity, + seller: '0x6b347a82fcac4e6a38d1fc40e3631bd8f9495e9f', + nftName: 'Exclusive Binance Hoodie', + network: 'ethereum', + category: 'wearable' as NFTCategory + }, + created_at: '2023-11-29T12:51:00.600Z', + updated_at: '2023-11-29T12:51:00.600Z' + }, + { + id: 'A', + read: true, + type: 'item_sold', + address: '0xA', + timestamp: new Date( + new Date().setHours(new Date().getHours() - 19) + ).getTime(), + metadata: { + link: 'https://market.decentraland.org/contracts/0xa8ee490e4c4da48cc1653502c1a77479d4d818de/tokens/590', + image: + 'https://peer.decentraland.org/lambdas/collections/contents/urn:decentraland:ethereum:collections-v1:binance_us_collection:binance_us_upper_body/thumbnail', + rarity: 'epic' as Rarity, + seller: '0x6b347a82fcac4e6a38d1fc40e3631bd8f9495e9f', + nftName: 'Exclusive Binance Hoodie', + network: 'ethereum', + category: 'wearable' as NFTCategory + }, + created_at: '2023-11-29T12:51:00.600Z', + updated_at: '2023-11-29T12:51:00.600Z' + }, + { + id: 'A', + read: true, + type: 'item_sold', + address: '0xA', + timestamp: new Date( + new Date().setHours(new Date().getHours() - 19) + ).getTime(), + metadata: { + link: 'https://market.decentraland.org/contracts/0xa8ee490e4c4da48cc1653502c1a77479d4d818de/tokens/590', + image: + 'https://peer.decentraland.org/lambdas/collections/contents/urn:decentraland:ethereum:collections-v1:binance_us_collection:binance_us_upper_body/thumbnail', + rarity: 'epic' as Rarity, + seller: '0x6b347a82fcac4e6a38d1fc40e3631bd8f9495e9f', + nftName: 'Exclusive Binance Hoodie', + network: 'ethereum', + category: 'wearable' as NFTCategory + }, + created_at: '2023-11-29T12:51:00.600Z', + updated_at: '2023-11-29T12:51:00.600Z' + }, + { + id: 'A', + read: true, + type: 'item_sold', + address: '0xA', + timestamp: new Date( + new Date().setHours(new Date().getHours() - 19) + ).getTime(), + metadata: { + link: 'https://market.decentraland.org/contracts/0xa8ee490e4c4da48cc1653502c1a77479d4d818de/tokens/590', + image: + 'https://peer.decentraland.org/lambdas/collections/contents/urn:decentraland:ethereum:collections-v1:binance_us_collection:binance_us_upper_body/thumbnail', + rarity: 'epic' as Rarity, + seller: '0x6b347a82fcac4e6a38d1fc40e3631bd8f9495e9f', + nftName: 'Exclusive Binance Hoodie', + network: 'ethereum', + category: 'wearable' as NFTCategory + }, + created_at: '2023-11-29T12:51:00.600Z', + updated_at: '2023-11-29T12:51:00.600Z' + }, { id: 'AC', read: true, diff --git a/src/components/UserMenu/ManaBalances/ManaBalances.tsx b/src/components/UserMenu/ManaBalances/ManaBalances.tsx new file mode 100644 index 00000000..48ca9be8 --- /dev/null +++ b/src/components/UserMenu/ManaBalances/ManaBalances.tsx @@ -0,0 +1,30 @@ +import React from 'react' + +import { Network } from '@dcl/schemas' +import classNames from 'classnames' + +import { ManaBalancesProps } from './ManaBalances.types' +import { Mana } from '../../Mana/Mana' +import { config } from '../../../config' + +export const ManaBalances = (props: ManaBalancesProps) => { + const { manaBalances, onClickBalance } = props + + return ( + + {manaBalances && + Object.keys(manaBalances).map((network) => ( + + {Number(manaBalances[network].toFixed(2)).toLocaleString()} + + ))} + + ) +} diff --git a/src/components/UserMenu/ManaBalances/ManaBalances.types.ts b/src/components/UserMenu/ManaBalances/ManaBalances.types.ts new file mode 100644 index 00000000..19933b07 --- /dev/null +++ b/src/components/UserMenu/ManaBalances/ManaBalances.types.ts @@ -0,0 +1,10 @@ +import * as React from 'react' +import { Network } from '@dcl/schemas/dist/dapps/network' + +export type ManaBalancesProps = { + manaBalances?: Partial> + onClickBalance?: ( + event: React.MouseEvent, + network: Network + ) => void +} diff --git a/src/components/UserMenu/UserMenu.css b/src/components/UserMenu/UserMenu.css index 1f7eb5f4..340b068e 100644 --- a/src/components/UserMenu/UserMenu.css +++ b/src/components/UserMenu/UserMenu.css @@ -5,237 +5,13 @@ outline: none; } -.dcl.user-menu .toggle, -.dcl.user-menu .toggle .avatar-face { - width: 42px; - height: 42px; +.dcl .user-menu__jump-in { + padding: 5px 32px; + margin-left: 24px; } -.dcl.user-menu .menu .avatar-face { - background: rgba(var(--dark-raw), 0.3); -} - -.dcl.user-menu .toggle { - cursor: pointer; -} - -.dcl.user-menu .ui.button { - font-size: 12px; - line-height: 18px; - padding: 9px 14px; - min-width: 0; -} - -.dcl.user-menu .menu { - position: absolute; - top: 56px; - right: 0; - z-index: 1; - background: var(--dropdown); - box-shadow: var(--shadow-2); - border-radius: 6px; - display: inline-block; - transition: transform 200ms ease-in-out, opacity 200ms ease-in-out; - opacity: 0; - user-select: none; - pointer-events: none; - transform: translate(0, -4px); - min-width: 180px; - overflow: hidden; -} - -.dcl.user-menu .menu.clickable { - pointer-events: auto; -} - -.dcl.user-menu .menu.open { - opacity: 1; - transform: translate(0, 0); -} - -.dcl.user-menu .info { - color: var(--text); - display: flex; - align-items: center; - border-bottom: 1px solid var(--dropdown-hover); - padding: 12px 16px; -} - -.dcl.user-menu .info.clickable { - cursor: pointer; -} - -.dcl.user-menu .info.clickable:hover { - background-color: var(--dropdown-hover); -} - -.dcl.user-menu .image { - margin-right: 10px; -} - -.dcl.user-menu .name { - font-weight: 500; - font-size: 16px; - line-height: 20px; - letter-spacing: -0.19px; -} - -.dcl.user-menu .email { - font-size: 14px; - line-height: 18px; -} - -.dcl.user-menu .actions { - list-style-type: none; - padding: 0; - margin: 0; - font-size: 14px; -} - -.dcl.user-menu .actions li, -.dcl.user-menu .actions .item { - cursor: pointer; - padding: 12px 16px; - display: flex; - align-items: center; -} - -.dcl.user-menu .actions li:hover, -.dcl.user-menu .actions .item:hover { - background-color: var(--dropdown-hover); -} - -.dcl.user-menu .actions li img { - margin-right: 12px; - display: block; - filter: var(--brightness); -} - -.dcl.user-menu .actions .sign-out-icon { - width: 12px; - height: 12px; - filter: var(--brightness); - background: url(../../assets/signout.svg); - background-position: center; - background-repeat: no-repeat; - margin-right: 12px; -} - -.dcl.user-menu .toggle { - width: 46px; - height: 46px; -} - -.dcl.user-menu-wrapper .activity-bell.item { - margin-right: 24px; -} - -.dcl.user-menu-wrapper .activity-bell.item .bell { - color: var(--text); - position: relative; - cursor: pointer; -} - -.dcl.user-menu-wrapper .activity-bell.item.active .bell { - color: var(--primary); -} - -.dcl.user-menu-wrapper .activity-bell.item .bell.pending:after { - content: ''; - width: 5px; - height: 5px; - background-color: var(--primary); - position: absolute; - border-radius: 100%; - top: -5px; - right: -5px; -} - -.dcl.user-menu .menu .item, -.dcl.user-menu .menu a { - color: var(--text); - font-weight: normal; -} - -.dcl.user-menu .menu li .icon, -.dcl.user-menu .menu .item .icon, -.dcl.user-menu .menu li .WalletIcon, -.dcl.user-menu .menu .item .WalletIcon { - font-size: 13px; - height: 18px; - margin-right: 10px; -} - -.dcl.user-menu .menu li .WalletIcon svg, -.dcl.user-menu .menu .item .WalletIcon svg { - height: 100%; - width: 1.18em; -} - -.dcl.user-menu .dcl.mana .symbol { - font-weight: bold; - color: var(--primary); -} - -.dcl.user-menu-wrapper .dcl.mana { - cursor: pointer; -} - -@media (max-width: 768px) { - .dcl.navbar .dcl.account-wrapper { - flex-direction: column; - align-items: flex-start; - } - - .dcl.navbar .dcl.account-wrapper .dcl.mana + .dcl.mana { - padding: 0; - } - - .dcl.navbar:has(.dcl.mobile-user-balances-wrapper) { - height: calc(var(--navbar-height) + 16px); - } - - .dcl.navbar:has(.dcl.mobile-user-balances-wrapper) > .ui.container { - align-items: flex-start; - padding-top: 8px; - } - - .dcl.navbar:has(.dcl.mobile-user-balances-wrapper) .dcl.account-wrapper { - flex-direction: row; - } - - .dcl.navbar:has(.dcl.mobile-user-balances-wrapper) - .dcl.account-wrapper - .dcl.mana { - margin-right: 8px; - padding: 0; - } - - .dcl.navbar:has(.dcl.mobile-user-balances-wrapper) - .dcl.user-menu - .dcl.account-wrapper { +@media (max-width: 991px) { + .dcl .user-menu__jump-in { display: none; } - - .dcl.navbar:has(.dcl.mobile-user-balances-wrapper) - .dcl.account-wrapper - .dcl.mana:last-of-type { - margin-right: 0; - } - - .dcl.navbar .dcl.mobile-user-balances-wrapper { - position: absolute; - top: 38px; - width: 240px; - } - - .dcl.user-menu .toggle { - width: 36px; - height: 36px; - } - - .dcl.user-menu .toggle .avatar-face { - width: 36px; - height: 36px; - } } diff --git a/src/components/UserMenu/UserMenu.i18n.ts b/src/components/UserMenu/UserMenu.i18n.ts new file mode 100644 index 00000000..4c043c02 --- /dev/null +++ b/src/components/UserMenu/UserMenu.i18n.ts @@ -0,0 +1,16 @@ +import { UserMenuI18N } from './UserMenu.types' + +export const i18n = { + activity: 'Activity', + myAssets: 'My Assets', + settings: 'Account Settings', + myLists: 'My Lists', + account: 'Account', + profile: 'Profile', + viewProfile: 'View Profile', + signIn: 'Sign In', + signOut: 'Sign out', + guest: 'Guest', + wallet: 'Manage Wallet', + jumpIn: 'Jump In' +} as UserMenuI18N diff --git a/src/components/UserMenu/UserMenu.stories.css b/src/components/UserMenu/UserMenu.stories.css new file mode 100644 index 00000000..b85cba0d --- /dev/null +++ b/src/components/UserMenu/UserMenu.stories.css @@ -0,0 +1,14 @@ +.usermenu-story-container { + position: absolute; + top: 100px; + right: 100px; + height: 100vh; + width: 100%; +} + +@media (max-width: 991px) { + .usermenu-story-container { + left: 0; + right: 0; + } +} diff --git a/src/components/UserMenu/UserMenu.stories.tsx b/src/components/UserMenu/UserMenu.stories.tsx index a7ccc94c..0c1918c5 100644 --- a/src/components/UserMenu/UserMenu.stories.tsx +++ b/src/components/UserMenu/UserMenu.stories.tsx @@ -1,90 +1,155 @@ import * as React from 'react' -import { Network } from '@dcl/schemas/dist/dapps/network' -import MenuItem from 'semantic-ui-react/dist/commonjs/collections/Menu/MenuItem' -import Icon from 'semantic-ui-react/dist/commonjs/elements/Icon/Icon' import { storiesOf } from '@storybook/react' -import { UserMenu } from './UserMenu' +import { Network } from '@dcl/schemas/dist/dapps/network' +import { NFTCategory } from '@dcl/schemas/dist/dapps/nft-category' +import { Rarity } from '@dcl/schemas/dist/dapps/rarity' + import { avatar } from '../../data/avatar' +import { NotificationActiveTab } from '../Notifications/types' +import { UserMenu } from './UserMenu' +import { i18n } from './UserMenu.i18n' + +import './UserMenu.stories.css' storiesOf('UserMenu', module) - .add('Signed out', () => ) - .add('Signed in', () => ) - .add('Guest', () => ) - .add('Clickable profile', () => ( - undefined} /> + .add('Signed out', () => ( +
+ +
)) - .add('Sign Out', () => ( - undefined} /> + .add('Signed in', () => ( +
+ +
)) - .add('Settings', () => ( - undefined} - onClickSettings={() => undefined} - /> + .add('Guest', () => ( +
+ , + trackId: string + ) => console.log(event, trackId)} + onClickBalance={( + event: React.MouseEvent, + network: Network + ) => console.log(event, network)} + /> +
)) - .add('Extra actions', () => ( - undefined} - menuItems={ - <> - - -  Friends - - - } - /> + .add('Clickable profile', () => ( +
+ undefined} + /> +
)) .add('Mana', () => ( - +
+ +
)) .add('Mana L2', () => ( - +
+ +
+ )) + .add('Has activity', () => ( +
+ undefined} + onClickActivity={() => undefined} + manaBalances={{ [Network.ETHEREUM]: 1000, [Network.MATIC]: 2500 }} + hasActivity + /> +
)) - .add('Activity', () => ( - undefined} - onClickActivity={() => undefined} - manaBalances={{ [Network.ETHEREUM]: 1000, [Network.MATIC]: 2500 }} - menuItems={ - <> - - -  Friends - - - } - /> + .add('Notification', () => ( +
+ undefined} + onClickActivity={() => undefined} + manaBalances={{ [Network.ETHEREUM]: 1000, [Network.MATIC]: 2500 }} + hasActivity + notifications={{ + isOnboarding: false, + isOpen: false, + isLoading: false, + items: [], + locale: 'en', + activeTab: NotificationActiveTab.NEWEST, + onBegin: console.log, + onChangeTab: console.log, + onClick: console.log, + onClose: console.log + }} + /> +
)) - .add('Activity pending', () => ( - undefined} - onClickActivity={() => undefined} - manaBalances={{ [Network.ETHEREUM]: 1000, [Network.MATIC]: 2500 }} - hasActivity - menuItems={ - <> - - -  Friends - - - } - /> + .add('Notification pending', () => ( +
+ undefined} + onClickActivity={() => undefined} + manaBalances={{ [Network.ETHEREUM]: 1000, [Network.MATIC]: 2500 }} + hasActivity + notifications={{ + isOnboarding: false, + isOpen: false, + isLoading: false, + items: [ + { + id: 'A', + read: false, + type: 'item_sold', + address: '0xA', + timestamp: 1680108689 * 1000, + metadata: { + link: 'https://market.decentraland.org/contracts/0x4c290f486bae507719c562b6b524bdb71a2570c9/tokens/1020', + image: + 'https://peer.decentraland.org/lambdas/collections/contents/urn:decentraland:ethereum:collections-v1:atari_launch:atari_green_upper_body/thumbnail', + rarity: 'epic' as Rarity, + seller: '0x8bc619e7f9ca9949b8440245fd9d8c4c002edf02', + nftName: 'Green Atari Tee', + network: 'ethereum', + category: 'wearable' as NFTCategory + }, + created_at: '2023-11-29T12:51:00.600Z', + updated_at: '2023-11-29T12:51:00.600Z' + } + ], + locale: 'en', + activeTab: NotificationActiveTab.NEWEST, + onBegin: console.log, + onChangeTab: console.log, + onClick: console.log, + onClose: console.log + }} + /> +
)) diff --git a/src/components/UserMenu/UserMenu.tsx b/src/components/UserMenu/UserMenu.tsx index 53b0a3ce..81eb3c58 100644 --- a/src/components/UserMenu/UserMenu.tsx +++ b/src/components/UserMenu/UserMenu.tsx @@ -1,227 +1,115 @@ -import * as React from 'react' -import { Network } from '@dcl/schemas/dist/dapps/network' -import { Avatar } from '@dcl/schemas/dist/platform/profile/avatar' -import Menu from 'semantic-ui-react/dist/commonjs/collections/Menu' -import Icon from 'semantic-ui-react/dist/commonjs/elements/Icon' -import { AvatarFace } from '../AvatarFace/AvatarFace' -import { Mobile } from '../Media' -import { Mana } from '../Mana/Mana' +import React, { useState, useCallback } from 'react' +import { v4 as uuidv4 } from 'uuid' +import classNames from 'classnames' + +import { UserMenuSignedIn } from './UserMenuSignedIn/UserMenuSignedIn' +import { i18n as i18nUserMenu } from './UserMenu.i18n' +import { UserMenuProps, UserMenuEventId } from './UserMenu.types' import { Button } from '../Button/Button' import { Column } from '../Column/Column' import { config } from '../../config' import { Row } from '../Row/Row' -import { WalletIcon } from '../WalletIcon/WalletIcon' -import './UserMenu.css' - -export type UserMenuI18N = { - signIn: React.ReactNode - signOut: React.ReactNode - guest: React.ReactNode - settings: React.ReactNode - wallet: React.ReactNode - profile: React.ReactNode - account: React.ReactNode -} - -export type UserMenuProps = { - isSignedIn: boolean - isSigningIn: boolean - isActivity: boolean - hasActivity: boolean - address?: string - manaBalances?: Partial> - avatar?: Avatar - menuItems?: React.ReactNode - i18n: UserMenuI18N - onSignOut: () => void - onSignIn: () => void - onClickProfile: () => void - onClickActivity: () => void - onClickSettings: () => void - onClickBalance: (network: Network) => void -} - -export type UserMenuState = { - isOpen: boolean - isClickable: boolean -} - -export class UserMenu extends React.Component { - static defaultProps: Partial = { - manaBalances: {}, - i18n: { - signIn: 'Sign In', - signOut: 'Sign Out', - guest: 'Guest', - settings: 'Settings', - wallet: 'Wallet', - profile: 'Profile', - account: 'Account' - } - } - - state: UserMenuState = { - isOpen: false, - isClickable: false - } - - mounted = false - - ref: HTMLElement | null = null - - handleClose = (): void => { - this.toggle(false) - } - - handleToggle = (): void => { - this.toggle(!this.state.isOpen) - } - toggle(value: boolean): void { - this.setState({ isOpen: value }) - setTimeout(() => { - if (this.mounted) { - this.setState({ isClickable: value }) - } - }, 250) - } - - componentDidMount(): void { - this.mounted = true - } - - componentWillUnmount(): void { - this.mounted = false - } - - renderManaBalances = (): React.ReactNode => { - const { manaBalances, onClickBalance } = this.props - - return ( - - {Object.keys(manaBalances).map((network) => ( - - {Number(manaBalances[network].toFixed(2)).toLocaleString()} - - ))} - - ) - } - - render(): JSX.Element { - const { - avatar, - manaBalances, - isSignedIn, - isSigningIn, - isActivity, - hasActivity, - onSignOut, - onSignIn, - onClickProfile, - onClickActivity, - onClickSettings, - i18n, - menuItems - } = this.props - - const { isOpen, isClickable } = this.state - - const name = avatar ? avatar.name : null - - const isSomeBalanceTooHigh = Object.values(manaBalances).some( - (balance) => Number(balance.toFixed(2)).toLocaleString().length > 5 - ) +import './UserMenu.css' - return ( - - - { + const { + isSignedIn, + isSigningIn, + manaBalances, + i18n = i18nUserMenu, + onClickSignIn, + onClickBalance, + onClickOpen, + onClickJumpIn, + onClickMenuItem, + ...signInProps + } = props + + const [isOpen, setIsOpen] = useState(false) + const [trackingId, setTrackingId] = useState(null) + const handleToggle = useCallback( + (event: React.MouseEvent) => { + const trackId = uuidv4() + setIsOpen((prev) => { + if (!prev) { + setTrackingId(trackId) + } + if (!prev && onClickOpen) { + onClickOpen(event, trackId) + } + return !prev + }) + }, + [setIsOpen, onClickOpen] + ) + + const handleClose = useCallback(() => { + setIsOpen(false) + }, [setIsOpen]) + + const handleClickJumpIn = useCallback( + (event: React.MouseEvent) => { + onClickMenuItem && + onClickMenuItem(event, UserMenuEventId.JUMP_IN, trackingId) + + setTimeout( + () => { + onClickJumpIn + ? onClickJumpIn(event) + : window.open(config.get('EXPLORER_URL'), '_blank', 'noopener') + }, + onClickMenuItem ? 300 : 0 + ) + }, + [onClickJumpIn, onClickMenuItem, trackingId] + ) + + const handleClickSignIn = useCallback( + (event: React.MouseEvent) => { + onClickMenuItem && + onClickMenuItem(event, UserMenuEventId.SIGN_IN, trackingId) + + onClickSignIn(event) + }, + [onClickSignIn, onClickMenuItem, trackingId] + ) + + return ( + + +
+ {isSignedIn && ( + + )} + {!isSignedIn && ( + + )} + - )} -
-
- {isSignedIn && isSomeBalanceTooHigh && ( - - - {this.renderManaBalances()} - - - )} -
- ) - } -} + {i18n.jumpIn} + + +
+
+ ) +}) diff --git a/src/components/UserMenu/UserMenu.types.ts b/src/components/UserMenu/UserMenu.types.ts new file mode 100644 index 00000000..6728536c --- /dev/null +++ b/src/components/UserMenu/UserMenu.types.ts @@ -0,0 +1,43 @@ +import * as React from 'react' +import { UserMenuSignedInProps } from './UserMenuSignedIn/UserMenuSignedIn.types' + +export type UserMenuProps = Omit< + UserMenuSignedInProps, + 'isOpen' | 'isClickable' | 'trackingId' | 'onClickToggle' +> & { + isSignedIn?: boolean + isSigningIn?: boolean + isActivity?: boolean + i18n?: UserMenuI18N + onClickSignIn?: (event: React.MouseEvent) => void + onClickOpen?: ( + event: React.MouseEvent, + trackingId: string + ) => void + onClickJumpIn?: (event: React.MouseEvent) => void +} + +export type UserMenuI18N = Record< + | 'myAssets' + | 'settings' + | 'account' + | 'viewProfile' + | 'signIn' + | 'signOut' + | 'guest' + | 'wallet' + | 'jumpIn', + string +> + +export enum UserMenuEventId { + ACTIVITY = 'activity', + MY_ASSETS = 'my_assets', + SETTINGS = 'settings', + PROFILE = 'profile', + SIGN_IN = 'sign_in', + SIGN_OUT = 'sign_out', + GUEST = 'guest', + WALLET = 'wallet', + JUMP_IN = 'jump_in' +} diff --git a/src/components/UserMenu/UserMenuSignedIn/UserMenuSignedIn.css b/src/components/UserMenu/UserMenuSignedIn/UserMenuSignedIn.css new file mode 100644 index 00000000..85b22272 --- /dev/null +++ b/src/components/UserMenu/UserMenuSignedIn/UserMenuSignedIn.css @@ -0,0 +1,295 @@ +.dui-user-menu-signed-in { + display: flex; + position: relative; + text-align: left; + outline: none; + justify-content: flex-end; +} + +.dui-user-menu-signed-in .toggle, +.dui-user-menu-signed-in .toggle .avatar-face { + width: 42px; + height: 42px; +} + +.dui-user-menu-signed-in .menu-wrapper .avatar-face { + background: rgba(var(--dark-raw), 0.3); +} + +.dui-user-menu-signed-in .toggle { + cursor: pointer; +} + +.dui-user-menu-signed-in .ui.button { + font-size: 12px; + line-height: 18px; + padding: 9px 14px; + min-width: 0; +} + +.dui-user-menu-signed-in .menu-wrapper .avatar-face { + background: rgba(var(--dark-raw), 0.3); +} + +.dui-user-menu-signed-in .ui.button { + font-size: 12px; + line-height: 18px; + padding: 9px 14px; + min-width: 0; +} + +.dui-user-menu-signed-in .menu-wrapper { + position: fixed; + top: 64px; + right: 0; + z-index: 1; + background-color: var(--background); + box-shadow: var(--shadow-2); + border-radius: 6px; + display: inline-block; + transition: transform 200ms ease-in-out, opacity 200ms ease-in-out; + opacity: 0; + user-select: none; + pointer-events: none; + transform: translate(0, -4px); + min-width: 180px; + overflow: hidden; + width: 561px; + display: flex; + align-items: flex-end; + justify-content: space-between; + height: 607px; +} + +.dui-user-menu-signed-in .menu-wrapper .menu-wearable-preview { + height: 110%; + margin-left: -100px; + margin-bottom: -100px; +} + +.dui-user-menu-signed-in .menu-wrapper .menu-wearable-preview.default-avatar { + margin-left: -50px; +} + +.dui-user-menu-signed-in + .menu-wrapper + .menu-wearable-preview.default-avatar + img { + height: 100%; +} + +.dui-user-menu-signed-in .menu-wrapper .menu-wearable-preview .WearablePreview { + background: var(--background); +} + +.dui-user-menu-signed-in .menu-wrapper.open { + opacity: 1; + transform: translate(0, 0); + pointer-events: auto; +} + +.dui-user-menu-signed-in .menu-info { + color: var(--text); + display: flex; + align-items: center; + border: none; + padding: 64px 0 47px; + color: var(--usermenu-item-text-enabled); + font-size: 32px; + font-style: normal; + font-weight: 700; + line-height: 18px; +} + +.dui-user-menu-signed-in .menu-info span { + margin-left: 12px; + color: var(--navbar-menu-enabled); + font-size: 20px; + font-style: normal; + font-weight: 400; + line-height: 18px; +} + +.dui-user-menu-signed-in .menu-actions__wrapper { + height: 607px; + display: flex; + flex-direction: column; + justify-content: flex-start; +} + +.dui-user-menu-signed-in .menu-actions { + list-style-type: none; + padding: 0; + margin: 0 55px 0 0; + font-size: 14px; + width: 276px; + height: 100%; +} + +.dui-user-menu-signed-in .menu-actions li, +.dui-user-menu-signed-in .menu-actions .item { + cursor: pointer; + padding: 40px 0 23.66px; + display: flex; + align-items: center; + border-bottom-color: var(--usermenu-item-border-enabled); + color: var(--usermenu-item-text-enabled); + font-size: 20px; + font-style: normal; + font-weight: 400; + line-height: 18px; + border-bottom-style: solid; + justify-content: space-between; +} + +.dui-user-menu-signed-in .menu-option__sign-out { + color: var(--usermenu-item-text-enabled); + font-size: 20px; + font-style: normal; + font-weight: 600; + height: 24px; + line-height: 18px; + margin: 0 55px 48px 0; + display: flex; + justify-content: flex-end; + align-items: center; + cursor: pointer; +} + +.dui-user-menu-signed-in .menu-option__sign-out .iconContainer { + margin-left: 10px; + height: 18px; + width: 18px; +} + +.dui-user-menu-signed-in .menu-option__sign-out .iconContainer svg { + height: 20px; + width: 20px; +} + +.dui-user-menu-signed-in .menu-option__sign-out .iconContainer svg g rect { + fill: var(--usermenu-item-text-enabled); +} + +.dui-user-menu-signed-in .menu-actions li:hover, +.dui-user-menu-signed-in .menu-actions .item:hover, +.dui-user-menu-signed-in .menu-option__sign-out:hover { + color: var(--navbar-item-text-hover); +} + +.dui-user-menu-signed-in + .menu-option__sign-out:hover + .iconContainer + svg + g + rect { + fill: var(--navbar-item-text-hover); +} + +.dui-user-menu-signed-in .menu-actions li img { + margin-right: 12px; + display: block; + filter: var(--brightness); +} + +.dui-user-menu-signed-in .toggle { + width: 46px; + height: 46px; +} + +.dui-user-menu-signed-in .menu-wrapper .item, +.dui-user-menu-signed-in .menu-wrapper a { + color: var(--text); + font-weight: normal; +} + +.dui-user-menu-signed-in .menu-actions li .dui-icon-container { + display: none; +} + +@media (max-width: 991px) { + .dui-user-menu-signed-in .activity-icon { + display: none; + } + + .dui-user-menu-signed-in .dcl.account-wrapper { + display: none; + } + + .dui-user-menu-signed-in .dcl.notifications { + margin-right: 14px; + } + + .dui-user-menu-signed-in .menu-wrapper { + width: 100vw; + height: calc(100vh - 56px); + flex-direction: column-reverse; + align-items: flex-start; + left: 0; + right: 0; + position: fixed; + box-shadow: none; + } + + .dui-user-menu-signed-in .menu-actions__wrapper { + margin-left: 25px; + margin-right: 22px; + width: calc(100% - 25px - 22px); + height: auto; + } + + .dui-user-menu-signed-in .menu-actions { + margin: 0; + width: 100%; + } + + .dui-user-menu-signed-in .menu-wrapper .menu-wearable-preview { + margin-left: -60px; + margin-bottom: -200px; + } + + .dui-user-menu-signed-in .menu-wrapper .menu-wearable-preview.default-avatar { + margin-left: -30px; + height: 400px; + margin-bottom: -100px; + } + + .dui-user-menu-signed-in + .menu-wrapper + .menu-wearable-preview.default-avatar + img { + height: 400px; + } + + .dui-user-menu-signed-in .menu-option__sign-out { + position: absolute; + right: 0; + bottom: 0; + } + + .dui-user-menu-signed-in .menu-actions li { + position: relative; + } + + .dui-user-menu-signed-in .menu-actions li .dui-icon-container { + display: flex; + } + + .dui-user-menu-signed-in + .menu-actions + li + .dui-icon-container.centered + svg + path { + fill: var(--usermenu-item-text-enabled); + } + + .dui-user-menu-signed-in + .menu-actions + li:hover + .dui-icon-container.centered + svg + path { + fill: var(--navbar-item-text-hover); + } +} diff --git a/src/components/UserMenu/UserMenuSignedIn/UserMenuSignedIn.stories.tsx b/src/components/UserMenu/UserMenuSignedIn/UserMenuSignedIn.stories.tsx new file mode 100644 index 00000000..98183d5a --- /dev/null +++ b/src/components/UserMenu/UserMenuSignedIn/UserMenuSignedIn.stories.tsx @@ -0,0 +1,117 @@ +import * as React from 'react' +import { storiesOf } from '@storybook/react' +import { Network } from '@dcl/schemas/dist/dapps/network' +import { Rarity } from '@dcl/schemas/dist/dapps/rarity' +import { NFTCategory } from '@dcl/schemas/dist/dapps/nft-category' + +import { UserMenuSignedIn } from './UserMenuSignedIn' +import { NotificationActiveTab } from '../../Notifications/types' +import { avatar } from '../../../data/avatar' + +import '../UserMenu.stories.css' +import { i18n } from '../UserMenu.i18n' + +storiesOf('UserMenuSignedIn', module) + .add('Guest', () => ( +
+ +
+ )) + .add('Without profile', () => ( +
+ +
+ )) + .add('Signed in', () => ( +
+ +
+ )) + .add('Complete', () => ( +
+ +
+ )) diff --git a/src/components/UserMenu/UserMenuSignedIn/UserMenuSignedIn.tsx b/src/components/UserMenu/UserMenuSignedIn/UserMenuSignedIn.tsx new file mode 100644 index 00000000..2954cb05 --- /dev/null +++ b/src/components/UserMenu/UserMenuSignedIn/UserMenuSignedIn.tsx @@ -0,0 +1,223 @@ +import React, { useCallback, useMemo } from 'react' +import classNames from 'classnames' + +import { ManaBalances } from '../ManaBalances/ManaBalances' +import { UserMenuSignedInProps } from './UserMenuSignedIn.types' +import { AvatarFace } from '../../AvatarFace/AvatarFace' +import { Button } from '../../Button/Button' +import ActivityIcon from '../../Icons/ActivityIcon' +import LogoutIcon from '../../Icons/LogoutIcon' +import Notifications from '../../Notifications/Notifications' +import ArrowIcon from '../../Icons/ArrowIcon' +import { config } from '../../../config' +import mansDefault from '../../../assets/man-default.png' +import { UserMenuEventId } from '../UserMenu.types' + +import '../UserMenu.css' +import './UserMenuSignedIn.css' + +export const UserMenuSignedIn = (props: UserMenuSignedInProps) => { + const { + manaBalances, + avatar, + address, + hasActivity, + isOpen, + trackingId, + notifications, + i18n, + onClickAccountSettings, + onClickActivity, + onClickBalance, + onClickMenuItem, + onClickMyAssets, + onClickProfile, + onClickSignOut, + onClickToggle, + onClickWallet + } = props + + const handleClickActivity = useCallback( + (event: React.MouseEvent) => { + onClickMenuItem && + onClickMenuItem(event, UserMenuEventId.ACTIVITY, trackingId) + setTimeout( + () => { + onClickActivity + ? onClickActivity(event) + : window.open( + `${config.get('MARKETPLACE_URL')}/activity`, + '_blank', + 'noopener' + ) + }, + onClickActivity ? 300 : 0 + ) + }, + [onClickActivity, onClickMenuItem, trackingId] + ) + + const handleClickMyAssets = useCallback( + (event: React.MouseEvent) => { + onClickMenuItem && + onClickMenuItem(event, UserMenuEventId.MY_ASSETS, trackingId) + + setTimeout( + () => { + onClickMyAssets + ? onClickMyAssets(event) + : window.open( + `${config.get('MARKETPLACE_MY_ASSETS_URL')}`, + '_blank', + 'noopener' + ) + }, + onClickMenuItem ? 300 : 0 + ) + }, + [onClickMyAssets, onClickMenuItem, trackingId] + ) + + const handleClickAccountSettings = useCallback( + (event: React.MouseEvent) => { + onClickMenuItem && + onClickMenuItem(event, UserMenuEventId.SETTINGS, trackingId) + + setTimeout( + () => { + onClickAccountSettings + ? onClickAccountSettings(event) + : window.open( + `${config.get('MARKETPLACE_SETTINGS_URL')}`, + '_blank', + 'noopener' + ) + }, + onClickMenuItem ? 300 : 0 + ) + }, + [onClickAccountSettings, onClickMenuItem, trackingId] + ) + + const handleClickProfile = useCallback( + (event: React.MouseEvent) => { + onClickMenuItem && + onClickMenuItem(event, UserMenuEventId.PROFILE, trackingId) + + setTimeout( + () => { + onClickProfile + ? onClickProfile(event) + : window.open(config.get('PROFILE_URL'), '_blank', 'noopener') + }, + onClickMenuItem ? 300 : 0 + ) + }, + [onClickProfile, onClickMenuItem, trackingId] + ) + + const handleClickWallet = useCallback( + (event: React.MouseEvent) => { + onClickMenuItem && + onClickMenuItem(event, UserMenuEventId.WALLET, trackingId) + + setTimeout( + () => { + onClickWallet + ? onClickWallet(event) + : window.open(config.get('ACCOUNT_URL'), '_blank', 'noopener') + }, + onClickMenuItem ? 300 : 0 + ) + }, + [onClickWallet, onClickMenuItem, trackingId] + ) + + const handleClickSignOut = useCallback( + (event: React.MouseEvent) => { + onClickMenuItem && + onClickMenuItem(event, UserMenuEventId.SIGN_OUT, trackingId) + onClickSignOut(event, trackingId) + }, + [onClickSignOut, onClickMenuItem, trackingId] + ) + + const handleClickToggle = useCallback( + (event: React.MouseEvent) => { + onClickToggle(event) + }, + [onClickToggle] + ) + + const userAddress = useMemo( + () => avatar?.ethAddress || address, + [avatar, address] + ) + + return ( +
+ {notifications && } + + +
+ +
+
+
+ +
+
+
+ {avatar?.name || i18n.guest}{' '} + {!avatar?.hasClaimedName && userAddress && ( + #{userAddress.substring(userAddress.length - 4)} + )} +
+
    +
    +
  • + {i18n.viewProfile} + +
  • +
    +
    +
  • + {i18n.myAssets} + +
  • +
    +
    +
  • + {i18n.wallet} + +
  • +
    +
    +
  • + {i18n.settings} + +
  • +
    +
+
+ {i18n.signOut} + +
+
+
+
+ ) +} diff --git a/src/components/UserMenu/UserMenuSignedIn/UserMenuSignedIn.types.ts b/src/components/UserMenu/UserMenuSignedIn/UserMenuSignedIn.types.ts new file mode 100644 index 00000000..dfcf643f --- /dev/null +++ b/src/components/UserMenu/UserMenuSignedIn/UserMenuSignedIn.types.ts @@ -0,0 +1,31 @@ +import { Avatar } from '@dcl/schemas/dist/platform/profile/avatar' +import { NotificationsProps } from '../../Notifications/Notifications' +import { ManaBalancesProps } from '../ManaBalances/ManaBalances.types' +import { UserMenuI18N } from '../UserMenu.types' + +export type UserMenuSignedInProps = ManaBalancesProps & { + avatar?: Avatar + address?: string + isOpen?: boolean + trackingId?: string | null + hasActivity?: boolean + notifications?: NotificationsProps + i18n: UserMenuI18N + onClickAccountSettings?: ( + event: React.MouseEvent + ) => void + onClickActivity?: (event: React.MouseEvent) => void + onClickMyAssets?: (event: React.MouseEvent) => void + onClickProfile?: (event: React.MouseEvent) => void + onClickSignOut?: ( + event: React.MouseEvent, + trackingId: string + ) => void + onClickToggle?: (event: React.MouseEvent) => void + onClickWallet?: (event: React.MouseEvent) => void + onClickMenuItem?: ( + event: React.MouseEvent, + id: string, + trackingId?: string + ) => void +} diff --git a/src/config/env/dev.json b/src/config/env/dev.json index 82dbad2d..5183ecae 100644 --- a/src/config/env/dev.json +++ b/src/config/env/dev.json @@ -3,9 +3,33 @@ "ACCOUNT_URL": "https://decentraland.zone/account", "PROFILE_URL": "https://decentraland.zone/profile", "MARKETPLACE_URL": "https://decentraland.zone/marketplace", + "MARKETPLACE_NAMES_URL": "https://decentraland.zone/marketplace/browse?assetType=nft§ion=ens&vendor=decentraland&page=1&sortBy=newest&onlyOnSale=true", + "MARKETPLACE_WEARABLES_URL": "https://decentraland.zone/marketplace/browse?section=wearables&vendor=decentraland&page=1&sortBy=newest&status=on_sale", + "MARKETPLACE_LANDS_URL": "https://decentraland.zone/marketplace/lands", + "MARKETPLACE_EMOTES_URL": "https://decentraland.zone/marketplace/browse?assetType=item§ion=emotes&vendor=decentraland&page=1&sortBy=newest&status=on_sale", + "MARKETPLACE_MY_ASSETS_URL": "https://decentraland.zone/marketplace/account?assetType=nft§ion=wearables&vendor=decentraland&page=1&sortBy=newest&onlyOnSale=false", + "MARKETPLACE_SETTINGS_URL": "https://decentraland.zone/marketplace/settings", "BUILDER_URL": "https://decentraland.zone/builder", + "BUILDER_WEARABLE_EMOTES_URL": "https://decentraland.zone/builder/collections", + "BUILDER_SCENES_URL": "https://decentraland.zone/builder/scenes", + "BUILDER_NAMES_URL": "https://decentraland.zone/builder/names", + "BUILDER_WORLDS_URL": "https://decentraland.zone/builder/worlds?tab=dcl", + "BUILDER_LAND_URL": "https://decentraland.zone/builder/land", "DAO_URL": "https://decentraland.zone/dao", + "DAO_GRANTS_URL": "https://decentraland.zone/dao/grants/", "GOVERNANCE_URL": "https://decentraland.zone/governance", + "GOVERNANCE_TRANSPARENCY_URL": "https://decentraland.zone/governance/transparency/", + "GOVERNANCE_PROPOSALS_URL": "https://decentraland.zone/governance/proposals/", + "GOVERNANCE_PROJECTS_URL": "https://decentraland.zone/governance/projects/", "EVENTS_URL": "https://decentraland.zone/events", - "PLACES_URL": "https://decentraland.zone/places" + "EVENTS_MY_EVENTS": "https://decentraland.zone/events/me/", + "PLACES_URL": "https://decentraland.zone/places", + "PLACES_MY_FAVORITE_URL": "https://decentraland.zone/places/favorites/", + "EXPLORER_URL": "https://play.decentraland.zone", + "STUDIOS_URL": "https://studios.decentraland.org/", + "DOCS_ABOUT_URL": "https://docs.decentraland.org/player/", + "DOCS_CREATORS_URL": "https://docs.decentraland.org/creator/", + "DOCS_CONTRIBUTOR_URL": "https://docs.decentraland.org/contributor/", + "DOCS_DAO_URL": "https://docs.decentraland.org/player/general/dao/overview/what-is-the-dao/", + "BLOG_URL": "https://decentraland.zone/blog/" } diff --git a/src/config/env/prod.json b/src/config/env/prod.json index c6784579..f65a8073 100644 --- a/src/config/env/prod.json +++ b/src/config/env/prod.json @@ -3,9 +3,33 @@ "ACCOUNT_URL": "https://decentraland.org/account", "PROFILE_URL": "https://decentraland.org/profile", "MARKETPLACE_URL": "https://decentraland.org/marketplace", + "MARKETPLACE_NAMES_URL": "https://decentraland.org/marketplace/browse?assetType=nft§ion=ens&vendor=decentraland&page=1&sortBy=newest&onlyOnSale=true", + "MARKETPLACE_WEARABLES_URL": "https://decentraland.org/marketplace/browse?section=wearables&vendor=decentraland&page=1&sortBy=newest&status=on_sale", + "MARKETPLACE_LANDS_URL": "https://decentraland.org/marketplace/lands", + "MARKETPLACE_EMOTES_URL": "https://decentraland.org/marketplace/browse?assetType=item§ion=emotes&vendor=decentraland&page=1&sortBy=newest&status=on_sale", + "MARKETPLACE_MY_ASSETS_URL": "https://decentraland.org/marketplace/account?assetType=nft§ion=wearables&vendor=decentraland&page=1&sortBy=newest&onlyOnSale=false", + "MARKETPLACE_SETTINGS_URL": "https://decentraland.org/marketplace/settings", "BUILDER_URL": "https://decentraland.org/builder", + "BUILDER_WEARABLE_EMOTES_URL": "https://decentraland.org/builder/collections", + "BUILDER_SCENES_URL": "https://decentraland.org/builder/scenes", + "BUILDER_NAMES_URL": "https://decentraland.org/builder/names", + "BUILDER_WORLDS_URL": "https://decentraland.org/builder/worlds?tab=dcl", + "BUILDER_LAND_URL": "https://decentraland.org/builder/land", "DAO_URL": "https://decentraland.org/dao", + "DAO_GRANTS_URL": "https://decentraland.org/dao/grants/", "GOVERNANCE_URL": "https://decentraland.org/governance", + "GOVERNANCE_TRANSPARENCY_URL": "https://decentraland.org/governance/transparency/", + "GOVERNANCE_PROPOSALS_URL": "https://decentraland.org/governance/proposals/", + "GOVERNANCE_PROJECTS_URL": "https://decentraland.org/governance/projects/", "EVENTS_URL": "https://decentraland.org/events", - "PLACES_URL": "https://decentraland.org/places" + "EVENTS_MY_EVENTS": "https://decentraland.org/events/me/", + "PLACES_URL": "https://decentraland.org/places", + "PLACES_MY_FAVORITE_URL": "https://decentraland.org/places/favorites/", + "EXPLORER_URL": "https://play.decentraland.org", + "STUDIOS_URL": "https://studios.decentraland.org/", + "DOCS_ABOUT_URL": "https://docs.decentraland.org/player/", + "DOCS_CREATORS_URL": "https://docs.decentraland.org/creator/", + "DOCS_CONTRIBUTOR_URL": "https://docs.decentraland.org/contributor/", + "DOCS_DAO_URL": "https://docs.decentraland.org/player/general/dao/overview/what-is-the-dao/", + "BLOG_URL": "https://decentraland.org/blog/" } diff --git a/src/config/env/stg.json b/src/config/env/stg.json index 1bc85cad..82f778be 100644 --- a/src/config/env/stg.json +++ b/src/config/env/stg.json @@ -3,9 +3,33 @@ "ACCOUNT_URL": "https://decentraland.today/account", "PROFILE_URL": "https://decentraland.today/profile", "MARKETPLACE_URL": "https://decentraland.today/marketplace", + "MARKETPLACE_NAMES_URL": "https://decentraland.today/marketplace/browse?assetType=nft§ion=ens&vendor=decentraland&page=1&sortBy=newest&onlyOnSale=true", + "MARKETPLACE_WEARABLES_URL": "https://decentraland.today/marketplace/browse?section=wearables&vendor=decentraland&page=1&sortBy=newest&status=on_sale", + "MARKETPLACE_LANDS_URL": "https://decentraland.today/marketplace/lands", + "MARKETPLACE_EMOTES_URL": "https://decentraland.today/marketplace/browse?assetType=item§ion=emotes&vendor=decentraland&page=1&sortBy=newest&status=on_sale", + "MARKETPLACE_MY_ASSETS_URL": "https://decentraland.today/marketplace/account?assetType=nft§ion=wearables&vendor=decentraland&page=1&sortBy=newest&onlyOnSale=false", + "MARKETPLACE_SETTINGS_URL": "https://decentraland.zone/marketplace/settings", "BUILDER_URL": "https://decentraland.today/builder", + "BUILDER_WEARABLE_EMOTES_URL": "https://decentraland.today/builder/collections", + "BUILDER_SCENES_URL": "https://decentraland.today/builder/scenes", + "BUILDER_NAMES_URL": "https://decentraland.today/builder/names", + "BUILDER_WORLDS_URL": "https://decentraland.today/builder/worlds?tab=dcl", + "BUILDER_LAND_URL": "https://decentraland.today/builder/land", "DAO_URL": "https://decentraland.today/dao", - "GOVERNANCE_URL": "https://decentraland.today/governance", - "EVENTS_URL": "https://decentraland.today/events", - "PLACES_URL": "https://decentraland.today/places" + "DAO_GRANTS_URL": "https://decentraland.today/dao/grants/", + "GOVERNANCE_URL": "https://decentraland.zone/governance", + "GOVERNANCE_TRANSPARENCY_URL": "https://decentraland.zone/governance/transparency/", + "GOVERNANCE_PROPOSALS_URL": "https://decentraland.zone/governance/proposals/", + "GOVERNANCE_PROJECTS_URL": "https://decentraland.zone/governance/projects/", + "EVENTS_URL": "https://decentraland.zone/events", + "EVENTS_MY_EVENTS": "https://decentraland.zone/events/me/", + "PLACES_URL": "https://decentraland.zone/places", + "PLACES_MY_FAVORITE_URL": "https://decentraland.zone/places/favorites/", + "EXPLORER_URL": "https://play.decentraland.today", + "STUDIOS_URL": "https://studios.decentraland.org/", + "DOCS_ABOUT_URL": "https://docs.decentraland.org/player/", + "DOCS_CREATORS_URL": "https://docs.decentraland.org/creator/", + "DOCS_CONTRIBUTOR_URL": "https://docs.decentraland.org/contributor/", + "DOCS_DAO_URL": "https://docs.decentraland.org/player/general/dao/overview/what-is-the-dao/", + "BLOG_URL": "https://decentraland.today/blog/" } diff --git a/src/data/avatar.ts b/src/data/avatar.ts index 5d4111db..5713cb3e 100644 --- a/src/data/avatar.ts +++ b/src/data/avatar.ts @@ -1,35 +1,97 @@ import { Avatar } from '@dcl/schemas/dist/platform/profile/avatar' export const avatar: Avatar = { - userId: '0xb6e9c0a25aa6b10fa4fe0aa8d1097d2a6136bf98', - email: '', - name: 'AFIP', hasClaimedName: true, description: 'I see you', + tutorialStep: 256, + name: 'AFIP', + userId: '0xb6e9c0a25aa6b10fa4fe0aa8d1097d2a6136bf98', + email: '', ethAddress: '0xb6e9c0a25aa6b10fa4fe0aa8d1097d2a6136bf98', - version: 12, + version: 96, avatar: { - bodyShape: 'urn:decentraland:off-chain:base-avatars:BaseFemale', + bodyShape: 'urn:decentraland:off-chain:base-avatars:BaseMale', + wearables: [ + 'urn:decentraland:off-chain:base-avatars:eyes_00', + 'urn:decentraland:off-chain:base-avatars:eyebrows_00', + 'urn:decentraland:off-chain:base-avatars:mouth_00', + 'urn:decentraland:off-chain:base-avatars:beard', + 'urn:decentraland:matic:collections-v2:0xc714bac4b6af6c7407dd4f6587ed332aa21fad84:6:631873750011343120187508166102022593913370572403294667525865865247', + 'urn:decentraland:matic:collections-v2:0x21aa54b72247e8b02a8eb7669a68698930c00c90:1:105312291668557186697918027683670432318895095400549111254310977603', + 'urn:decentraland:matic:collections-v2:0x21aa54b72247e8b02a8eb7669a68698930c00c90:0:68', + 'urn:decentraland:matic:collections-v2:0xd6a09edae4b93db8f2ddb1911db01193692514ca:0:5', + 'urn:decentraland:matic:collections-v2:0x39056796acd7c31647a701fa13c5bb382f9de29b:0:3' + ], + forceRender: [], + emotes: [ + { + slot: 0, + urn: 'money' + }, + { + urn: 'urn:decentraland:matic:collections-v2:0x8ac9d70106cc01e4aa74b1a79d4be1e87f58c59d:30:3159368750056715600937540830510112969566852862016473337629329326100', + slot: 1 + }, + { + urn: 'urn:decentraland:matic:collections-v2:0xc9cd5a0523caa50cff6237c5ab95fd2a18352315:0:5', + slot: 2 + }, + { + urn: 'urn:decentraland:matic:collections-v2:0xf6360585d9e581e0ac0c4cd7ac90f03b1a45fcd1:0:24', + slot: 3 + }, + { + urn: 'urn:decentraland:matic:collections-v2:0xded1e53d7a43ac1844b66c0ca0f02627eb42e16d:8:842498333348457493583344221469363458551160763204392890034487820835', + slot: 4 + }, + { + urn: 'urn:decentraland:matic:collections-v2:0xbada8a315e84e4d78e3b6914003647226d9b4001:11:1158435208354129053677098304520374755507846049406040223797420757090', + slot: 5 + }, + { + urn: 'urn:decentraland:matic:collections-v2:0xef832a5183bf2e4099efed4c6ec981b7b41aa545:0:2', + slot: 6 + }, + { + slot: 7, + urn: 'kiss' + }, + { + slot: 8, + urn: 'headexplode' + }, + { + slot: 9, + urn: 'dab' + } + ], snapshots: { + body: 'https://peer-ec1.decentraland.org/content/contents/bafkreiauffcs7vadf4q4jzcemlo3k6gxyvx4inbi65wxtk4hcdsriagsze', face256: - 'https://peer-ec1.decentraland.org/content/contents/QmcDmQ7WbDFU65idd4PEwEKBM1bgQi88Y6CByCWFMN8raV', - body: 'https://peer-ec1.decentraland.org/content/contents/QmaE1YgiBJAbEqCkBtmDe8fTMzqBUgvUCY6HifrjV1WAnY' + 'https://peer-ec1.decentraland.org/content/contents/bafkreigvrqs6ej4ktzz6awmvnxrkh4znvybf5xziv27t34ls6easvvoa5m' }, - eyes: { color: { r: 0.37109375, g: 0.22265625, b: 0.1953125 } }, - hair: { color: { r: 0.109375, g: 0.109375, b: 0.109375 } }, - skin: { color: { r: 0.80078125, g: 0.609375, b: 0.46484375 } }, - wearables: [ - 'urn:decentraland:off-chain:base-avatars:f_mouth_04', - 'urn:decentraland:off-chain:base-avatars:f_eyes_00', - 'urn:decentraland:off-chain:base-avatars:f_eyebrows_00', - 'urn:decentraland:off-chain:base-avatars:hair_undere', - 'urn:decentraland:off-chain:base-avatars:black_sun_glasses', - 'urn:decentraland:off-chain:base-avatars:elegant_blue_trousers', - 'urn:decentraland:off-chain:base-avatars:classic_shoes', - 'urn:decentraland:matic:collections-v2:0x93d2c265957cd7924260193c288a8ecfc785c0d1:1', - 'urn:decentraland:matic:collections-v2:0x50f4d59172ec5edc54b7fd05350372d00b154ccf:0' - ] + eyes: { + color: { + r: 0.125, + g: 0.703125, + b: 0.96484375 + } + }, + hair: { + color: { + r: 0.109375, + g: 0.109375, + b: 0.109375 + } + }, + skin: { + color: { + r: 0.80078125, + g: 0.609375, + b: 0.46484375 + } + } }, - tutorialStep: 256, - interests: [] + interests: [], + hasConnectedWeb3: true } diff --git a/src/modules.d.ts b/src/modules.d.ts index f1f9fa48..6b5933f8 100644 --- a/src/modules.d.ts +++ b/src/modules.d.ts @@ -5,3 +5,8 @@ declare module '*.svg' { const content: string export default content } + +declare module '*.png' { + const content: string + export default content +} diff --git a/src/themes/alternative/dark-theme.css b/src/themes/alternative/dark-theme.css index 790ee631..6e0deee1 100644 --- a/src/themes/alternative/dark-theme.css +++ b/src/themes/alternative/dark-theme.css @@ -53,4 +53,14 @@ /* black svgs */ --notification-onboarding-bell: url(../../assets/bell-onboarding-dark.png); + + /* Navbar2 */ + --navbar-menu-enabled: #ecebed; + --navbar-menu-hover: #fff; + --navbar-item-text-enabled: #cfcdd4; + --navbar-item-text-hover: #fff; + --navbar-item-border-enabled: #716b7c; + --navbar-item-border-hover: #cfcdd4; + --usermenu-item-text-enabled: #cfcdd4; + --usermenu-item-border-enabled: #cfcdd4; } diff --git a/src/themes/alternative/light-theme.css b/src/themes/alternative/light-theme.css index 428c0ddb..03a2ebe0 100644 --- a/src/themes/alternative/light-theme.css +++ b/src/themes/alternative/light-theme.css @@ -52,4 +52,14 @@ --brightness: brightness(0.1); /* black svgs */ --notification-onboarding-bell: url(../../assets/bell-onboarding-light.png); + + /* Navbar2 */ + --navbar-menu-enabled: #a09ba8; + --navbar-menu-hover: #000; + --navbar-item-text-enabled: #716b7c; + --navbar-item-text-hover: #000; + --navbar-item-border-enabled: #cfcdd4; + --navbar-item-border-hover: #000; + --usermenu-item-text-enabled: #43404a; + --usermenu-item-border-enabled: #43404a; }