25ee793208
* Factor out section header * Remove daily balance change * Remove dead code * Layout, add streak * Fix visibility observer to work on server * Tweak * Search perserved by url * Add pill query param * Add search page * Extract component for ProbChangeRow * Explore groups page * Add search row * Add trending groups section * Add unfollow option for group * Experimental home: accommodate old saved sections. * Tweaks to search layout * Rearrange layout * Daily movers page * Add streak grayed out indicator * Use firebase query instead of algolia search for groups * Replace trending group card with pills * Hide streak if you turned off that notification * Listen for group updates * Better UI for adding / removing groups * Toast feedback for join/leave group. Customize button moved to bottom. * Remove Home title * Refactor arrange home * Add new for you section * Add prefetch * Move home out of experimental! * Remove unused import * Show non-public markets from group
102 lines
2.7 KiB
TypeScript
102 lines
2.7 KiB
TypeScript
import clsx from 'clsx'
|
|
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd'
|
|
import { MenuIcon } from '@heroicons/react/solid'
|
|
|
|
import { Col } from 'web/components/layout/col'
|
|
import { Row } from 'web/components/layout/row'
|
|
import { Subtitle } from 'web/components/subtitle'
|
|
import { keyBy } from 'lodash'
|
|
|
|
export function ArrangeHome(props: {
|
|
sections: { label: string; id: string }[]
|
|
setSectionIds: (sections: string[]) => void
|
|
}) {
|
|
const { sections, setSectionIds } = props
|
|
|
|
const sectionsById = keyBy(sections, 'id')
|
|
|
|
return (
|
|
<DragDropContext
|
|
onDragEnd={(e) => {
|
|
const { destination, source, draggableId } = e
|
|
if (!destination) return
|
|
|
|
const section = sectionsById[draggableId]
|
|
|
|
const newSectionIds = sections.map((section) => section.id)
|
|
|
|
newSectionIds.splice(source.index, 1)
|
|
newSectionIds.splice(destination.index, 0, section.id)
|
|
|
|
setSectionIds(newSectionIds)
|
|
}}
|
|
>
|
|
<Row className="relative max-w-md gap-4">
|
|
<DraggableList items={sections} title="Sections" />
|
|
</Row>
|
|
</DragDropContext>
|
|
)
|
|
}
|
|
|
|
function DraggableList(props: {
|
|
title: string
|
|
items: { id: string; label: string }[]
|
|
}) {
|
|
const { title, items } = props
|
|
return (
|
|
<Droppable droppableId={title.toLowerCase()}>
|
|
{(provided) => (
|
|
<Col
|
|
{...provided.droppableProps}
|
|
ref={provided.innerRef}
|
|
className={clsx('flex-1 items-stretch gap-1 rounded bg-gray-100 p-4')}
|
|
>
|
|
<Subtitle text={title} className="mx-2 !mt-0 !mb-4" />
|
|
{items.map((item, index) => (
|
|
<Draggable key={item.id} draggableId={item.id} index={index}>
|
|
{(provided, snapshot) => (
|
|
<div
|
|
ref={provided.innerRef}
|
|
{...provided.draggableProps}
|
|
{...provided.dragHandleProps}
|
|
style={provided.draggableProps.style}
|
|
>
|
|
<SectionItem
|
|
className={clsx(
|
|
snapshot.isDragging && 'z-[9000] bg-gray-200'
|
|
)}
|
|
item={item}
|
|
/>
|
|
</div>
|
|
)}
|
|
</Draggable>
|
|
))}
|
|
{provided.placeholder}
|
|
</Col>
|
|
)}
|
|
</Droppable>
|
|
)
|
|
}
|
|
|
|
const SectionItem = (props: {
|
|
item: { id: string; label: string }
|
|
className?: string
|
|
}) => {
|
|
const { item, className } = props
|
|
|
|
return (
|
|
<div
|
|
className={clsx(
|
|
className,
|
|
'flex flex-row items-center gap-4 rounded bg-gray-50 p-2'
|
|
)}
|
|
>
|
|
<MenuIcon
|
|
className="h-5 w-5 flex-shrink-0 text-gray-500"
|
|
aria-hidden="true"
|
|
/>{' '}
|
|
{item.label}
|
|
</div>
|
|
)
|
|
}
|