) => {
)
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={
- <>
-
- >
- }
- />
+ .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={
- <>
-
- >
- }
- />
+ .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={
- <>
-
- >
- }
- />
+ .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 && (
+
+ )}
+
+
+
+
+ )
+})
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.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;
}