Add sort by tag
This commit is contained in:
parent
f1977f26ea
commit
96d5ea0437
|
@ -16,6 +16,7 @@ import { UserLink } from './user-page'
|
||||||
import { Linkify } from './linkify'
|
import { Linkify } from './linkify'
|
||||||
import { Col } from './layout/col'
|
import { Col } from './layout/col'
|
||||||
import { SiteLink } from './site-link'
|
import { SiteLink } from './site-link'
|
||||||
|
import { parseTags } from '../lib/util/parse'
|
||||||
|
|
||||||
export function ContractDetails(props: { contract: Contract }) {
|
export function ContractDetails(props: { contract: Contract }) {
|
||||||
const { contract } = props
|
const { contract } = props
|
||||||
|
@ -162,9 +163,64 @@ export function CreatorContractsGrid(props: { contracts: Contract[] }) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function TagContractsGrid(props: { contracts: Contract[] }) {
|
||||||
|
const { contracts } = props
|
||||||
|
|
||||||
|
const contractTags = _.flatMap(contracts, (contract) =>
|
||||||
|
parseTags(contract.question + ' ' + contract.description).map((tag) => ({
|
||||||
|
tag,
|
||||||
|
contract,
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
const groupedByTag = _.groupBy(contractTags, ({ tag }) => tag)
|
||||||
|
const byTag = _.mapValues(groupedByTag, (contractTags) =>
|
||||||
|
contractTags.map(({ contract }) => contract)
|
||||||
|
)
|
||||||
|
const tags = _.sortBy(Object.keys(byTag), (tag) =>
|
||||||
|
_.sumBy(byTag[tag], (contract) => -1 * compute(contract).truePool)
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Col className="gap-6">
|
||||||
|
{tags.map((tag) => {
|
||||||
|
return (
|
||||||
|
<Col className="gap-4">
|
||||||
|
<SiteLink className="text-lg" href={`/tag/${tag}`}>
|
||||||
|
#{tag}
|
||||||
|
</SiteLink>
|
||||||
|
|
||||||
|
<ul role="list" className="grid grid-cols-1 gap-4 lg:grid-cols-2">
|
||||||
|
{byTag[tag]
|
||||||
|
.slice(0, MAX_GROUPED_CONTRACTS_DISPLAYED)
|
||||||
|
.map((contract) => (
|
||||||
|
<ContractCard contract={contract} key={contract.id} />
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{byTag[tag].length > MAX_GROUPED_CONTRACTS_DISPLAYED ? (
|
||||||
|
<Link href={`/tag/${tag}`}>
|
||||||
|
<a
|
||||||
|
className={clsx(
|
||||||
|
'self-end hover:underline hover:decoration-indigo-400 hover:decoration-2'
|
||||||
|
)}
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
See all
|
||||||
|
</a>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<div />
|
||||||
|
)}
|
||||||
|
</Col>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</Col>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const MAX_CONTRACTS_DISPLAYED = 99
|
const MAX_CONTRACTS_DISPLAYED = 99
|
||||||
|
|
||||||
type Sort = 'creator' | 'createdTime' | 'pool' | 'resolved' | 'all'
|
type Sort = 'creator' | 'tag' | 'createdTime' | 'pool' | 'resolved' | 'all'
|
||||||
export function SearchableGrid(props: {
|
export function SearchableGrid(props: {
|
||||||
contracts: Contract[]
|
contracts: Contract[]
|
||||||
defaultSort?: Sort
|
defaultSort?: Sort
|
||||||
|
@ -189,7 +245,7 @@ export function SearchableGrid(props: {
|
||||||
|
|
||||||
if (sort === 'createdTime' || sort === 'resolved' || sort === 'all') {
|
if (sort === 'createdTime' || sort === 'resolved' || sort === 'all') {
|
||||||
matches.sort((a, b) => b.createdTime - a.createdTime)
|
matches.sort((a, b) => b.createdTime - a.createdTime)
|
||||||
} else if (sort === 'pool' || sort === 'creator') {
|
} else if (sort === 'pool' || sort === 'creator' || sort === 'tag') {
|
||||||
matches.sort((a, b) => compute(b).truePool - compute(a).truePool)
|
matches.sort((a, b) => compute(b).truePool - compute(a).truePool)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,13 +280,16 @@ export function SearchableGrid(props: {
|
||||||
) : (
|
) : (
|
||||||
<option value="creator">By creator</option>
|
<option value="creator">By creator</option>
|
||||||
)}
|
)}
|
||||||
|
<option value="tag">By tag</option>
|
||||||
<option value="pool">Most traded</option>
|
<option value="pool">Most traded</option>
|
||||||
<option value="createdTime">Newest first</option>
|
<option value="createdTime">Newest first</option>
|
||||||
<option value="resolved">Resolved</option>
|
<option value="resolved">Resolved</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{!byOneCreator && (sort === 'creator' || sort === 'resolved') ? (
|
{sort === 'tag' ? (
|
||||||
|
<TagContractsGrid contracts={matches} />
|
||||||
|
) : !byOneCreator && (sort === 'creator' || sort === 'resolved') ? (
|
||||||
<CreatorContractsGrid contracts={matches} />
|
<CreatorContractsGrid contracts={matches} />
|
||||||
) : (
|
) : (
|
||||||
<ContractsGrid contracts={matches} />
|
<ContractsGrid contracts={matches} />
|
||||||
|
|
8
web/lib/util/parse.ts
Normal file
8
web/lib/util/parse.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
export function parseTags(text: string) {
|
||||||
|
const regex = /(?:^|\s)(?:[#][a-z0-9_]+)/gi
|
||||||
|
const matches = text.match(regex) || []
|
||||||
|
return matches.map((match) => {
|
||||||
|
const tag = match.trim().substring(1)
|
||||||
|
return tag
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user