From e8ae9a73940e92a502e20c457339f2a1c757924b Mon Sep 17 00:00:00 2001 From: Pico2x Date: Tue, 13 Sep 2022 17:09:49 +0100 Subject: [PATCH] Move tabs to sidebar --- web/components/nav/group-nav-bar.tsx | 94 ++++++++++++++ web/components/nav/group-sidebar.tsx | 87 +++++++++++++ web/components/nav/nav-bar.tsx | 33 ++--- web/components/nav/sidebar.tsx | 82 ++++++++----- web/lib/icons/corner-down-right-icon.tsx | 19 +++ web/pages/group/[...slugs]/index.tsx | 149 ++++++++++++++--------- 6 files changed, 362 insertions(+), 102 deletions(-) create mode 100644 web/components/nav/group-nav-bar.tsx create mode 100644 web/components/nav/group-sidebar.tsx create mode 100644 web/lib/icons/corner-down-right-icon.tsx diff --git a/web/components/nav/group-nav-bar.tsx b/web/components/nav/group-nav-bar.tsx new file mode 100644 index 00000000..041d006b --- /dev/null +++ b/web/components/nav/group-nav-bar.tsx @@ -0,0 +1,94 @@ +import { BookOpenIcon, HomeIcon } from '@heroicons/react/outline' +import { Item } from './sidebar' + +import clsx from 'clsx' +import { trackCallback } from 'web/lib/service/analytics' +import TrophyIcon from 'web/lib/icons/trophy-icon' +import { useUser } from 'web/hooks/use-user' +import NotificationsIcon from '../notifications-icon' +import router from 'next/router' +import { userProfileItem } from './nav-bar' + +const mobileGroupNavigation = [ + { name: 'About', key: 'about', icon: BookOpenIcon }, + { name: 'Markets', key: 'markets', icon: HomeIcon }, + { name: 'Leaderboard', key: 'leaderboards', icon: TrophyIcon }, +] + +const mobileGeneralNavigation = [ + { + name: 'Notifications', + key: 'notifications', + icon: NotificationsIcon, + href: '/notifications', + }, +] + +export function GroupNavBar(props: { + currentPage: string + onClick: (key: string) => void +}) { + const { currentPage } = props + const user = useUser() + + return ( + + ) +} + +function NavBarItem(props: { + item: Item + currentPage: string + onClick: (key: string) => void +}) { + const { item, currentPage } = props + const track = trackCallback( + `group navbar: ${item.trackingEventName ?? item.name}` + ) + + return ( + + ) +} diff --git a/web/components/nav/group-sidebar.tsx b/web/components/nav/group-sidebar.tsx new file mode 100644 index 00000000..33784194 --- /dev/null +++ b/web/components/nav/group-sidebar.tsx @@ -0,0 +1,87 @@ +import { HomeIcon, BookOpenIcon } from '@heroicons/react/outline' +import clsx from 'clsx' +import { useUser } from 'web/hooks/use-user' +import { ManifoldLogo } from './manifold-logo' +import { ProfileSummary } from './profile-menu' +import React from 'react' +import TrophyIcon from 'web/lib/icons/trophy-icon' +import { SignInButton } from '../sign-in-button' +import CornerDownRightIcon from 'web/lib/icons/corner-down-right-icon' +import NotificationsIcon from '../notifications-icon' +import { SidebarItem } from './sidebar' +import { buildArray } from 'common/util/array' +import { User } from 'common/user' + +const groupNavigation = [ + { name: 'About', key: 'about', icon: BookOpenIcon }, + { name: 'Markets', key: 'markets', icon: HomeIcon }, + { name: 'Leaderboard', key: 'leaderboards', icon: TrophyIcon }, +] + +const generalNavigation = (user?: User | null) => + buildArray( + user && { + name: 'Notifications', + href: `/notifications`, + key: 'notifications', + icon: NotificationsIcon, + } + ) + +export default function GroupSidebar(props: { + groupName: string + className?: string + onClick: (key: string) => void + joinOrAddQuestionsButton: React.ReactNode + currentKey: string +}) { + const { className, groupName, currentKey } = props + + const user = useUser() + + return ( + + ) +} diff --git a/web/components/nav/nav-bar.tsx b/web/components/nav/nav-bar.tsx index 242d6ff5..14e7d1b0 100644 --- a/web/components/nav/nav-bar.tsx +++ b/web/components/nav/nav-bar.tsx @@ -17,6 +17,7 @@ import { useRouter } from 'next/router' import NotificationsIcon from 'web/components/notifications-icon' import { useIsIframe } from 'web/hooks/use-is-iframe' import { trackCallback } from 'web/lib/service/analytics' +import { User } from 'common/user' function getNavigation() { return [ @@ -34,6 +35,21 @@ const signedOutNavigation = [ { name: 'Explore', href: '/home', icon: SearchIcon }, ] +export const userProfileItem = (user: User) => ({ + name: formatMoney(user.balance), + trackingEventName: 'profile', + href: `/${user.username}?tab=trades`, + icon: () => ( + + ), +}) + // From https://codepen.io/chris__sev/pen/QWGvYbL export function BottomNavBar() { const [sidebarOpen, setSidebarOpen] = useState(false) @@ -61,20 +77,7 @@ export function BottomNavBar() { ( - - ), - }} + item={userProfileItem(user)} /> )}
+ ( + return buildArray( CHALLENGES_ENABLED && { name: 'Challenges', href: '/challenges' }, [ { name: 'Groups', href: '/groups' }, @@ -156,39 +156,59 @@ function getMoreMobileNav() { export type Item = { name: string trackingEventName?: string - href: string + href?: string + key?: string icon?: React.ComponentType<{ className?: string }> } -function SidebarItem(props: { item: Item; currentPage: string }) { - const { item, currentPage } = props - return ( - - - {item.icon && ( - - +export function SidebarItem(props: { + item: Item + currentPage: string + onClick?: (key: string) => void +}) { + const { item, currentPage, onClick } = props + const isCurrentPage = + item.href != null ? item.href === currentPage : item.key === currentPage + + const sidebarItem = ( + + {item.icon && ( + ) + + if (item.href) { + return ( + + {sidebarItem} + + ) + } else { + return onClick ? ( + + ) : ( + <> + ) + } } function SidebarButton(props: { diff --git a/web/lib/icons/corner-down-right-icon.tsx b/web/lib/icons/corner-down-right-icon.tsx new file mode 100644 index 00000000..37d61afa --- /dev/null +++ b/web/lib/icons/corner-down-right-icon.tsx @@ -0,0 +1,19 @@ +export default function CornerDownRightIcon(props: { className?: string }) { + return ( + + + + + ) +} diff --git a/web/pages/group/[...slugs]/index.tsx b/web/pages/group/[...slugs]/index.tsx index f5d68e57..71330ce9 100644 --- a/web/pages/group/[...slugs]/index.tsx +++ b/web/pages/group/[...slugs]/index.tsx @@ -1,10 +1,9 @@ import React, { useState } from 'react' import Link from 'next/link' import { useRouter } from 'next/router' -import { toast } from 'react-hot-toast' +import { toast, Toaster } from 'react-hot-toast' import { Group, GROUP_CHAT_SLUG } from 'common/group' -import { Page } from 'web/components/page' import { Contract, listContractsByGroupSlug } from 'web/lib/firebase/contracts' import { addContractToGroup, @@ -30,7 +29,6 @@ import Custom404 from '../../404' import { SEO } from 'web/components/SEO' import { Linkify } from 'web/components/linkify' import { fromPropz, usePropz } from 'web/hooks/use-propz' -import { Tabs } from 'web/components/layout/tabs' import { LoadingIndicator } from 'web/components/loading-indicator' import { Modal } from 'web/components/layout/modal' import { ChoicesToggleGroup } from 'web/components/choices-toggle-group' @@ -51,6 +49,9 @@ import { Spacer } from 'web/components/layout/spacer' import { usePost } from 'web/hooks/use-post' import { useAdmin } from 'web/hooks/use-admin' import { track } from '@amplitude/analytics-browser' +import GroupSidebar from 'web/components/nav/group-sidebar' +import { GroupNavBar } from 'web/components/nav/group-nav-bar' +import { ArrowLeftIcon } from '@heroicons/react/solid' export const getStaticProps = fromPropz(getStaticPropz) export async function getStaticPropz(props: { params: { slugs: string[] } }) { @@ -144,6 +145,7 @@ export default function GroupPage(props: { const user = useUser() const isAdmin = useAdmin() const memberIds = useMemberIds(group?.id ?? null) ?? props.memberIds + const [sidebarIndex, setSidebarIndex] = useState(0) useSaveReferral(user, { defaultReferrerUsername: creator.username, @@ -157,7 +159,7 @@ export default function GroupPage(props: { const isMember = user && memberIds.includes(user.id) const maxLeaderboardSize = 50 - const leaderboard = ( + const leaderboardPage = (
) - const aboutTab = ( + const aboutPage = ( {(group.aboutPostId != null || isCreator || isAdmin) && ( ) - const questionsTab = ( - + const questionsPage = ( + <> + {/* align the divs to the right */} +
+
+ +
+
+ + ) - const tabs = [ + const sidebarPages = [ { badge: `${contractsCount}`, title: 'Markets', - content: questionsTab, + content: questionsPage, href: groupPath(group.slug, 'markets'), + key: 'markets', }, { title: 'Leaderboards', - content: leaderboard, + content: leaderboardPage, href: groupPath(group.slug, 'leaderboards'), + key: 'leaderboards', }, { title: 'About', - content: aboutTab, + content: aboutPage, href: groupPath(group.slug, 'about'), + key: 'about', }, ] - const tabIndex = tabs - .map((t) => t.title.toLowerCase()) - .indexOf(page ?? 'markets') + const pageContent = sidebarPages[sidebarIndex].content + const onSidebarClick = (key: string) => { + const index = sidebarPages.findIndex((t) => t.key === key) + setSidebarIndex(index) + } + + const joinOrAddQuestionsButton = ( + + ) return ( - - - - -
-
+ <> +
+
+
+ + + + +
+
+

{group.name} -

-
- -
+
-
- -
- - - 0 ? tabIndex : 0} - tabs={tabs} - /> - +
+ +
+
+ + + + +
{pageContent}
+
+ +
+ ) } @@ -271,10 +305,11 @@ function JoinOrAddQuestionsButtons(props: { group: Group user: User | null | undefined isMember: boolean + className?: string }) { const { group, user, isMember } = props return user && isMember ? ( - + ) : group.anyoneCanJoin ? ( @@ -433,9 +468,9 @@ function AddContractButton(props: { group: Group; user: User }) { return ( <> -
+