Move tabs to sidebar (#873)
* Move tabs to sidebar * Address all feedback Fix icon names Extract navbar component into a separate function Rm arrow and indentation Move group name under logo Fix visual sidebar stretchy thing Fix visual bug * Extra nits
This commit is contained in:
parent
256fd89fd2
commit
456aed467c
|
@ -389,9 +389,7 @@ function ContractSearchControls(props: {
|
|||
}
|
||||
|
||||
return (
|
||||
<Col
|
||||
className={clsx('bg-base-200 sticky top-0 z-20 gap-3 pb-3', className)}
|
||||
>
|
||||
<Col className={clsx('bg-base-200 top-0 z-20 gap-3 pb-3', className)}>
|
||||
<Row className="gap-1 sm:gap-2">
|
||||
<input
|
||||
type="text"
|
||||
|
|
|
@ -81,7 +81,7 @@ export function SelectMarketsModal(props: {
|
|||
</div>
|
||||
)}
|
||||
|
||||
<div className="overflow-y-auto sm:px-8">
|
||||
<div className="overflow-y-auto px-2 sm:px-8">
|
||||
<ContractSearch
|
||||
hideOrderSelector
|
||||
onContractClick={addContract}
|
||||
|
@ -96,7 +96,7 @@ export function SelectMarketsModal(props: {
|
|||
'!bg-indigo-100 outline outline-2 outline-indigo-300',
|
||||
}}
|
||||
additionalFilter={{}} /* hide pills */
|
||||
headerClassName="bg-white"
|
||||
headerClassName="bg-white sticky"
|
||||
{...contractSearchOptions}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -110,6 +110,7 @@ export function CreatorContractsList(props: {
|
|||
|
||||
return (
|
||||
<ContractSearch
|
||||
headerClassName="sticky"
|
||||
user={user}
|
||||
defaultSort="newest"
|
||||
defaultFilter="all"
|
||||
|
|
94
web/components/nav/group-nav-bar.tsx
Normal file
94
web/components/nav/group-nav-bar.tsx
Normal file
|
@ -0,0 +1,94 @@
|
|||
import { ClipboardIcon, 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: ClipboardIcon },
|
||||
{ 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 (
|
||||
<nav className="fixed inset-x-0 bottom-0 z-20 flex justify-between border-t-2 bg-white text-xs text-gray-700 lg:hidden">
|
||||
{mobileGroupNavigation.map((item) => (
|
||||
<NavBarItem
|
||||
key={item.name}
|
||||
item={item}
|
||||
currentPage={currentPage}
|
||||
onClick={props.onClick}
|
||||
/>
|
||||
))}
|
||||
|
||||
{mobileGeneralNavigation.map((item) => (
|
||||
<NavBarItem
|
||||
key={item.name}
|
||||
item={item}
|
||||
currentPage={currentPage}
|
||||
onClick={() => {
|
||||
router.push(item.href)
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
{user && (
|
||||
<NavBarItem
|
||||
key={'profile'}
|
||||
currentPage={currentPage}
|
||||
onClick={() => {
|
||||
router.push(`/${user.username}?tab=trades`)
|
||||
}}
|
||||
item={userProfileItem(user)}
|
||||
/>
|
||||
)}
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
|
||||
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 (
|
||||
<button onClick={() => props.onClick(item.key ?? '#')}>
|
||||
<a
|
||||
className={clsx(
|
||||
'block w-full py-1 px-3 text-center hover:bg-indigo-200 hover:text-indigo-700',
|
||||
currentPage === item.key && 'bg-gray-200 text-indigo-700'
|
||||
)}
|
||||
onClick={track}
|
||||
>
|
||||
{item.icon && <item.icon className="my-1 mx-auto h-6 w-6" />}
|
||||
{item.name}
|
||||
</a>
|
||||
</button>
|
||||
)
|
||||
}
|
90
web/components/nav/group-sidebar.tsx
Normal file
90
web/components/nav/group-sidebar.tsx
Normal file
|
@ -0,0 +1,90 @@
|
|||
import { ClipboardIcon, HomeIcon } 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'
|
||||
import { Row } from '../layout/row'
|
||||
import { Col } from '../layout/col'
|
||||
|
||||
const groupNavigation = [
|
||||
{ name: 'Markets', key: 'markets', icon: HomeIcon },
|
||||
{ name: 'About', key: 'about', icon: ClipboardIcon },
|
||||
{ name: 'Leaderboard', key: 'leaderboards', icon: TrophyIcon },
|
||||
]
|
||||
|
||||
const generalNavigation = (user?: User | null) =>
|
||||
buildArray(
|
||||
user && {
|
||||
name: 'Notifications',
|
||||
href: `/notifications`,
|
||||
key: 'notifications',
|
||||
icon: NotificationsIcon,
|
||||
}
|
||||
)
|
||||
|
||||
export 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 (
|
||||
<nav
|
||||
aria-label="Group Sidebar"
|
||||
className={clsx('flex max-h-[100vh] flex-col', className)}
|
||||
>
|
||||
<ManifoldLogo className="pt-6" twoLine />
|
||||
<Row className="pl-2">
|
||||
<Col className="flex justify-center">
|
||||
<CornerDownRightIcon className=" h-6 w-6 text-indigo-700" />
|
||||
</Col>
|
||||
<Col>
|
||||
<div className={' text-2xl text-indigo-700 sm:mb-1 sm:mt-3'}>
|
||||
{groupName}
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<div className=" min-h-0 shrink flex-col items-stretch gap-1 pt-6 lg:flex ">
|
||||
{user ? (
|
||||
<ProfileSummary user={user} />
|
||||
) : (
|
||||
<SignInButton className="mb-4" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Desktop navigation */}
|
||||
{groupNavigation.map((item) => (
|
||||
<SidebarItem
|
||||
key={item.key}
|
||||
item={item}
|
||||
currentPage={currentKey}
|
||||
onClick={props.onClick}
|
||||
/>
|
||||
))}
|
||||
{generalNavigation(user).map((item) => (
|
||||
<SidebarItem
|
||||
key={item.key}
|
||||
item={item}
|
||||
currentPage={currentKey}
|
||||
onClick={props.onClick}
|
||||
/>
|
||||
))}
|
||||
|
||||
{props.joinOrAddQuestionsButton}
|
||||
</nav>
|
||||
)
|
||||
}
|
|
@ -17,6 +17,8 @@ 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'
|
||||
|
||||
import { PAST_BETS } from 'common/user'
|
||||
|
||||
function getNavigation() {
|
||||
|
@ -35,6 +37,21 @@ const signedOutNavigation = [
|
|||
{ name: 'Explore', href: '/home', icon: SearchIcon },
|
||||
]
|
||||
|
||||
export const userProfileItem = (user: User) => ({
|
||||
name: formatMoney(user.balance),
|
||||
trackingEventName: 'profile',
|
||||
href: `/${user.username}?tab=${PAST_BETS}`,
|
||||
icon: () => (
|
||||
<Avatar
|
||||
className="mx-auto my-1"
|
||||
size="xs"
|
||||
username={user.username}
|
||||
avatarUrl={user.avatarUrl}
|
||||
noLink
|
||||
/>
|
||||
),
|
||||
})
|
||||
|
||||
// From https://codepen.io/chris__sev/pen/QWGvYbL
|
||||
export function BottomNavBar() {
|
||||
const [sidebarOpen, setSidebarOpen] = useState(false)
|
||||
|
@ -62,20 +79,7 @@ export function BottomNavBar() {
|
|||
<NavBarItem
|
||||
key={'profile'}
|
||||
currentPage={currentPage}
|
||||
item={{
|
||||
name: formatMoney(user.balance),
|
||||
trackingEventName: 'profile',
|
||||
href: `/${user.username}?tab=${PAST_BETS}`,
|
||||
icon: () => (
|
||||
<Avatar
|
||||
className="mx-auto my-1"
|
||||
size="xs"
|
||||
username={user.username}
|
||||
avatarUrl={user.avatarUrl}
|
||||
noLink
|
||||
/>
|
||||
),
|
||||
}}
|
||||
item={userProfileItem(user)}
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
|
@ -99,7 +103,7 @@ function NavBarItem(props: { item: Item; currentPage: string }) {
|
|||
const track = trackCallback(`navbar: ${item.trackingEventName ?? item.name}`)
|
||||
|
||||
return (
|
||||
<Link href={item.href}>
|
||||
<Link href={item.href ?? '#'}>
|
||||
<a
|
||||
className={clsx(
|
||||
'block w-full py-1 px-3 text-center hover:bg-indigo-200 hover:text-indigo-700',
|
||||
|
|
|
@ -13,7 +13,7 @@ import Router, { useRouter } from 'next/router'
|
|||
import { useUser } from 'web/hooks/use-user'
|
||||
import { firebaseLogout, User } from 'web/lib/firebase/users'
|
||||
import { ManifoldLogo } from './manifold-logo'
|
||||
import { MenuButton } from './menu'
|
||||
import { MenuButton, MenuItem } from './menu'
|
||||
import { ProfileSummary } from './profile-menu'
|
||||
import NotificationsIcon from 'web/components/notifications-icon'
|
||||
import React from 'react'
|
||||
|
@ -139,7 +139,7 @@ function getMoreMobileNav() {
|
|||
}
|
||||
if (IS_PRIVATE_MANIFOLD) return [signOut]
|
||||
|
||||
return buildArray<Item>(
|
||||
return buildArray<MenuItem>(
|
||||
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 (
|
||||
<Link href={item.href} key={item.name}>
|
||||
<a
|
||||
onClick={trackCallback('sidebar: ' + item.name)}
|
||||
className={clsx(
|
||||
item.href == currentPage
|
||||
? 'bg-gray-200 text-gray-900'
|
||||
: 'text-gray-600 hover:bg-gray-100',
|
||||
'group flex items-center rounded-md px-3 py-2 text-sm font-medium'
|
||||
)}
|
||||
aria-current={item.href == currentPage ? 'page' : undefined}
|
||||
>
|
||||
{item.icon && (
|
||||
<item.icon
|
||||
className={clsx(
|
||||
item.href == currentPage
|
||||
? 'text-gray-500'
|
||||
: 'text-gray-400 group-hover:text-gray-500',
|
||||
'-ml-1 mr-3 h-6 w-6 flex-shrink-0'
|
||||
)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
)}
|
||||
<span className="truncate">{item.name}</span>
|
||||
</a>
|
||||
</Link>
|
||||
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 = (
|
||||
<a
|
||||
onClick={trackCallback('sidebar: ' + item.name)}
|
||||
className={clsx(
|
||||
isCurrentPage
|
||||
? 'bg-gray-200 text-gray-900'
|
||||
: 'text-gray-600 hover:bg-gray-100',
|
||||
'group flex items-center rounded-md px-3 py-2 text-sm font-medium'
|
||||
)}
|
||||
aria-current={item.href == currentPage ? 'page' : undefined}
|
||||
>
|
||||
{item.icon && (
|
||||
<item.icon
|
||||
className={clsx(
|
||||
isCurrentPage
|
||||
? 'text-gray-500'
|
||||
: 'text-gray-400 group-hover:text-gray-500',
|
||||
'-ml-1 mr-3 h-6 w-6 flex-shrink-0'
|
||||
)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
)}
|
||||
<span className="truncate">{item.name}</span>
|
||||
</a>
|
||||
)
|
||||
|
||||
if (item.href) {
|
||||
return (
|
||||
<Link href={item.href} key={item.name}>
|
||||
{sidebarItem}
|
||||
</Link>
|
||||
)
|
||||
} else {
|
||||
return onClick ? (
|
||||
<button onClick={() => onClick(item.key ?? '#')}>{sidebarItem}</button>
|
||||
) : (
|
||||
<> </>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function SidebarButton(props: {
|
||||
|
|
19
web/lib/icons/corner-down-right-icon.tsx
Normal file
19
web/lib/icons/corner-down-right-icon.tsx
Normal file
|
@ -0,0 +1,19 @@
|
|||
export default function CornerDownRightIcon(props: { className?: string }) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
className={props.className}
|
||||
>
|
||||
<polyline points="15 10 20 15 15 20"></polyline>
|
||||
<path d="M4 4v7a4 4 0 0 0 4 4h12"></path>
|
||||
</svg>
|
||||
)
|
||||
}
|
|
@ -114,6 +114,7 @@ function SearchSection(props: {
|
|||
}
|
||||
noControls
|
||||
maxResults={6}
|
||||
headerClassName="sticky"
|
||||
persistPrefix={`experimental-home-${sort}`}
|
||||
/>
|
||||
</Col>
|
||||
|
@ -135,6 +136,7 @@ function GroupSection(props: {
|
|||
additionalFilter={{ groupSlug: group.slug }}
|
||||
noControls
|
||||
maxResults={6}
|
||||
headerClassName="sticky"
|
||||
persistPrefix={`experimental-home-${group.slug}`}
|
||||
/>
|
||||
</Col>
|
||||
|
|
|
@ -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,7 @@ 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 { ChoicesToggleGroup } from 'web/components/choices-toggle-group'
|
||||
import { ContractSearch } from 'web/components/contract-search'
|
||||
import { JoinOrLeaveGroupButton } from 'web/components/groups/groups-button'
|
||||
|
@ -49,6 +48,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 { GroupNavBar } from 'web/components/nav/group-nav-bar'
|
||||
import { ArrowLeftIcon } from '@heroicons/react/solid'
|
||||
import { GroupSidebar } from 'web/components/nav/group-sidebar'
|
||||
import { SelectMarketsModal } from 'web/components/contract-select-modal'
|
||||
import { BETTORS } from 'common/user'
|
||||
|
||||
|
@ -138,6 +140,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,
|
||||
|
@ -151,7 +154,7 @@ export default function GroupPage(props: {
|
|||
const isMember = user && memberIds.includes(user.id)
|
||||
const maxLeaderboardSize = 50
|
||||
|
||||
const leaderboard = (
|
||||
const leaderboardPage = (
|
||||
<Col>
|
||||
<div className="mt-4 flex flex-col gap-8 px-4 md:flex-row">
|
||||
<GroupLeaderboard
|
||||
|
@ -170,7 +173,7 @@ export default function GroupPage(props: {
|
|||
</Col>
|
||||
)
|
||||
|
||||
const aboutTab = (
|
||||
const aboutPage = (
|
||||
<Col>
|
||||
{(group.aboutPostId != null || isCreator || isAdmin) && (
|
||||
<GroupAboutPost
|
||||
|
@ -190,73 +193,118 @@ export default function GroupPage(props: {
|
|||
</Col>
|
||||
)
|
||||
|
||||
const questionsTab = (
|
||||
<ContractSearch
|
||||
user={user}
|
||||
defaultSort={'newest'}
|
||||
defaultFilter={suggestedFilter}
|
||||
additionalFilter={{ groupSlug: group.slug }}
|
||||
persistPrefix={`group-${group.slug}`}
|
||||
/>
|
||||
const questionsPage = (
|
||||
<>
|
||||
{/* align the divs to the right */}
|
||||
<div className={' flex justify-end px-2 pb-2 sm:hidden'}>
|
||||
<div>
|
||||
<JoinOrAddQuestionsButtons
|
||||
group={group}
|
||||
user={user}
|
||||
isMember={!!isMember}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<ContractSearch
|
||||
headerClassName="md:sticky"
|
||||
user={user}
|
||||
defaultSort={'newest'}
|
||||
defaultFilter={suggestedFilter}
|
||||
additionalFilter={{ groupSlug: group.slug }}
|
||||
persistPrefix={`group-${group.slug}`}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
|
||||
const tabs = [
|
||||
const sidebarPages = [
|
||||
{
|
||||
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 = (
|
||||
<JoinOrAddQuestionsButtons
|
||||
group={group}
|
||||
user={user}
|
||||
isMember={!!isMember}
|
||||
/>
|
||||
)
|
||||
|
||||
return (
|
||||
<Page>
|
||||
<SEO
|
||||
title={group.name}
|
||||
description={`Created by ${creator.name}. ${group.about}`}
|
||||
url={groupPath(group.slug)}
|
||||
/>
|
||||
<Col className="relative px-3">
|
||||
<Row className={'items-center justify-between gap-4'}>
|
||||
<div className={'sm:mb-1'}>
|
||||
<div
|
||||
className={'line-clamp-1 my-2 text-2xl text-indigo-700 sm:my-3'}
|
||||
>
|
||||
{group.name}
|
||||
</div>
|
||||
<div className={'hidden sm:block'}>
|
||||
<Linkify text={group.about} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-2">
|
||||
<JoinOrAddQuestionsButtons
|
||||
group={group}
|
||||
user={user}
|
||||
isMember={!!isMember}
|
||||
/>
|
||||
</div>
|
||||
</Row>
|
||||
</Col>
|
||||
<Tabs
|
||||
currentPageForAnalytics={groupPath(group.slug)}
|
||||
className={'mx-2 mb-0 sm:mb-2'}
|
||||
defaultIndex={tabIndex > 0 ? tabIndex : 0}
|
||||
tabs={tabs}
|
||||
/>
|
||||
</Page>
|
||||
<>
|
||||
<TopGroupNavBar group={group} />
|
||||
<div>
|
||||
<div
|
||||
className={
|
||||
'mx-auto w-full pb-[58px] lg:grid lg:grid-cols-12 lg:gap-x-2 lg:pb-0 xl:max-w-7xl xl:gap-x-8'
|
||||
}
|
||||
>
|
||||
<Toaster />
|
||||
<GroupSidebar
|
||||
groupName={group.name}
|
||||
className="sticky top-0 hidden divide-gray-300 self-start pl-2 lg:col-span-2 lg:flex"
|
||||
onClick={onSidebarClick}
|
||||
joinOrAddQuestionsButton={joinOrAddQuestionsButton}
|
||||
currentKey={sidebarPages[sidebarIndex].key}
|
||||
/>
|
||||
|
||||
<SEO
|
||||
title={group.name}
|
||||
description={`Created by ${creator.name}. ${group.about}`}
|
||||
url={groupPath(group.slug)}
|
||||
/>
|
||||
<main className={'px-2 pt-1 lg:col-span-8 lg:pt-6 xl:col-span-8'}>
|
||||
{pageContent}
|
||||
</main>
|
||||
</div>
|
||||
<GroupNavBar
|
||||
currentPage={sidebarPages[sidebarIndex].key}
|
||||
onClick={onSidebarClick}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export function TopGroupNavBar(props: { group: Group }) {
|
||||
return (
|
||||
<header className="sticky top-0 z-50 w-full pb-2 md:hidden lg:col-span-12">
|
||||
<div className="flex items-center border-b border-gray-200 bg-white px-4">
|
||||
<div className="flex-shrink-0">
|
||||
<Link href="/">
|
||||
<a className="text-indigo-700 hover:text-gray-500 ">
|
||||
<ArrowLeftIcon className="h-5 w-5" aria-hidden="true" />
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="ml-3">
|
||||
<h1 className="text-lg font-medium text-indigo-700">
|
||||
{props.group.name}
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -264,10 +312,11 @@ function JoinOrAddQuestionsButtons(props: {
|
|||
group: Group
|
||||
user: User | null | undefined
|
||||
isMember: boolean
|
||||
className?: string
|
||||
}) {
|
||||
const { group, user, isMember } = props
|
||||
return user && isMember ? (
|
||||
<Row className={'mt-0 justify-end'}>
|
||||
<Row className={'w-full self-start pt-4'}>
|
||||
<AddContractButton group={group} user={user} />
|
||||
</Row>
|
||||
) : group.anyoneCanJoin ? (
|
||||
|
@ -411,9 +460,9 @@ function AddContractButton(props: { group: Group; user: User }) {
|
|||
|
||||
return (
|
||||
<>
|
||||
<div className={'flex justify-center'}>
|
||||
<div className={'flex w-full justify-center'}>
|
||||
<Button
|
||||
className="whitespace-nowrap"
|
||||
className="w-full whitespace-nowrap"
|
||||
size="md"
|
||||
color="indigo"
|
||||
onClick={() => setOpen(true)}
|
||||
|
@ -468,7 +517,9 @@ function JoinGroupButton(props: {
|
|||
<div>
|
||||
<button
|
||||
onClick={follow}
|
||||
className={'btn-md btn-outline btn whitespace-nowrap normal-case'}
|
||||
className={
|
||||
'btn-md btn-outline btn w-full whitespace-nowrap normal-case'
|
||||
}
|
||||
>
|
||||
Follow
|
||||
</button>
|
||||
|
|
|
@ -26,6 +26,7 @@ const Home = () => {
|
|||
user={user}
|
||||
persistPrefix="home-search"
|
||||
useQueryUrlParam={true}
|
||||
headerClassName="sticky"
|
||||
/>
|
||||
</Col>
|
||||
<button
|
||||
|
|
Loading…
Reference in New Issue
Block a user