Support hashtags in the question

This commit is contained in:
Austin Chen 2021-12-19 01:08:12 -08:00
parent f1a96b5320
commit a760940ae6
4 changed files with 51 additions and 46 deletions

View File

@ -1,4 +1,4 @@
import { Fragment, useState } from 'react'
import { useState } from 'react'
import {
compute,
Contract,
@ -13,7 +13,7 @@ import router from 'next/router'
import { useUser } from '../hooks/use-user'
import { Row } from './layout/row'
import dayjs from 'dayjs'
import Link from 'next/link'
import { Linkify } from './Linkify'
function ContractDescription(props: {
contract: Contract
@ -33,46 +33,6 @@ function ContractDescription(props: {
setDescription(editStatement())
}
// Return a JSX span, linkifying @username, #hashtags, and https://...
function Linkify(props: { text: string }) {
const { text } = props
const regex = /(?:^|\s)(?:[@#][a-z0-9_]+|https?:\/\/\S+)/gi
const matches = text.match(regex) || []
const links = matches.map((match) => {
// Matches are in the form: " @username" or "https://example.com"
const whitespace = match.match(/^\s/)
const symbol = match.trim().substring(0, 1)
const tag = match.trim().substring(1)
const href =
{
'@': `/${tag}`,
'#': `/tag/${tag}`,
}[symbol] ?? match
return (
<>
{whitespace}
<Link href={href}>
<a className="text-indigo-700 hover:underline hover:decoration-2">
{symbol}
{tag}
</a>
</Link>
</>
)
})
return (
<span>
{text.split(regex).map((part, i) => (
<Fragment key={i}>
{part}
{links[i]}
</Fragment>
))}
</span>
)
}
return (
<div className="whitespace-pre-line">
<Linkify text={contract.description} />
@ -146,7 +106,7 @@ export const ContractOverview = (props: {
<Col className="justify-between md:flex-row">
<Col>
<div className="text-3xl text-indigo-700 mb-4">
{contract.question}
<Linkify text={contract.question} />
</div>
<ContractDetails contract={contract} />

View File

@ -13,6 +13,7 @@ import {
import { formatMoney } from '../lib/util/format'
import { User } from '../lib/firebase/users'
import { UserLink } from './user-page'
import { Linkify } from './Linkify'
export function ContractDetails(props: { contract: Contract }) {
const { contract } = props
@ -59,7 +60,7 @@ function ContractCard(props: { contract: Contract }) {
<div className="card-body p-6">
<Row className="justify-between gap-4 mb-2">
<p className="font-medium text-indigo-700">
{contract.question}
<Linkify text={contract.question} />
</p>
<div className={clsx('text-4xl', resolutionColor)}>
{resolutionText || (

View File

@ -0,0 +1,42 @@
import Link from 'next/link'
import { Fragment } from 'react'
// Return a JSX span, linkifying @username, #hashtags, and https://...
export function Linkify(props: { text: string }) {
const { text } = props
const regex = /(?:^|\s)(?:[@#][a-z0-9_]+|https?:\/\/\S+)/gi
const matches = text.match(regex) || []
const links = matches.map((match) => {
// Matches are in the form: " @username" or "https://example.com"
const whitespace = match.match(/^\s/)
const symbol = match.trim().substring(0, 1)
const tag = match.trim().substring(1)
const href =
{
'@': `/${tag}`,
'#': `/tag/${tag}`,
}[symbol] ?? match
return (
<>
{whitespace}
<Link href={href}>
<a className="text-indigo-700 hover:underline hover:decoration-2">
{symbol}
{tag}
</a>
</Link>
</>
)
})
return (
<span>
{text.split(regex).map((part, i) => (
<Fragment key={i}>
{part}
{links[i]}
</Fragment>
))}
</span>
)
}

View File

@ -12,8 +12,10 @@ export default function TagPage() {
let contracts = useContracts()
if (tag && contracts !== 'loading') {
contracts = contracts.filter((contract) =>
contract.description.toLowerCase().includes(`#${tag.toLowerCase()}`)
contracts = contracts.filter(
(contract) =>
contract.description.toLowerCase().includes(`#${tag.toLowerCase()}`) ||
contract.question.toLowerCase().includes(`#${tag.toLowerCase()}`)
)
}