Create common card component (#1012)
* Create common card component * lint
This commit is contained in:
		
							parent
							
								
									7ce09ae39d
								
							
						
					
					
						commit
						94624c5387
					
				
							
								
								
									
										16
									
								
								web/components/card.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								web/components/card.tsx
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,16 @@ | ||||||
|  | import clsx from 'clsx' | ||||||
|  | 
 | ||||||
|  | export function Card(props: JSX.IntrinsicElements['div']) { | ||||||
|  |   const { children, className, ...rest } = props | ||||||
|  |   return ( | ||||||
|  |     <div | ||||||
|  |       className={clsx( | ||||||
|  |         'cursor-pointer rounded-lg border-2 bg-white transition-shadow hover:shadow-md focus:shadow-md', | ||||||
|  |         className | ||||||
|  |       )} | ||||||
|  |       {...rest} | ||||||
|  |     > | ||||||
|  |       {children} | ||||||
|  |     </div> | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  | @ -6,6 +6,8 @@ import { Charity } from 'common/charity' | ||||||
| import { useCharityTxns } from 'web/hooks/use-charity-txns' | import { useCharityTxns } from 'web/hooks/use-charity-txns' | ||||||
| import { manaToUSD } from '../../../common/util/format' | import { manaToUSD } from '../../../common/util/format' | ||||||
| import { Row } from '../layout/row' | import { Row } from '../layout/row' | ||||||
|  | import { Col } from '../layout/col' | ||||||
|  | import { Card } from '../card' | ||||||
| 
 | 
 | ||||||
| export function CharityCard(props: { charity: Charity; match?: number }) { | export function CharityCard(props: { charity: Charity; match?: number }) { | ||||||
|   const { charity } = props |   const { charity } = props | ||||||
|  | @ -15,43 +17,44 @@ export function CharityCard(props: { charity: Charity; match?: number }) { | ||||||
|   const raised = sumBy(txns, (txn) => txn.amount) |   const raised = sumBy(txns, (txn) => txn.amount) | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <Link href={`/charity/${slug}`} passHref> |     <Link href={`/charity/${slug}`}> | ||||||
|       <div className="card card-compact transition:shadow flex-1 cursor-pointer border-2 bg-white hover:shadow-md"> |       <a className="flex-1"> | ||||||
|         <Row className="mt-6 mb-2"> |         <Card className="!rounded-2xl"> | ||||||
|           {tags?.includes('Featured') && <FeaturedBadge />} |           <Row className="mt-6 mb-2"> | ||||||
|         </Row> |             {tags?.includes('Featured') && <FeaturedBadge />} | ||||||
|         <div className="px-8"> |           </Row> | ||||||
|           <figure className="relative h-32"> |           <div className="px-8"> | ||||||
|             {photo ? ( |             <figure className="relative h-32"> | ||||||
|               <Image src={photo} alt="" layout="fill" objectFit="contain" /> |               {photo ? ( | ||||||
|             ) : ( |                 <Image src={photo} alt="" layout="fill" objectFit="contain" /> | ||||||
|               <div className="h-full w-full bg-gradient-to-r from-slate-300 to-indigo-200" /> |               ) : ( | ||||||
|             )} |                 <div className="h-full w-full bg-gradient-to-r from-slate-300 to-indigo-200" /> | ||||||
|           </figure> |               )} | ||||||
|         </div> |             </figure> | ||||||
|         <div className="card-body"> |           </div> | ||||||
|           {/* <h3 className="card-title line-clamp-3">{name}</h3> */} |           <Col className="p-8"> | ||||||
|           <div className="line-clamp-4 text-sm">{preview}</div> |             <div className="line-clamp-4 text-sm">{preview}</div> | ||||||
|           {raised > 0 && ( |             {raised > 0 && ( | ||||||
|             <> |               <> | ||||||
|               <Row className="mt-4 flex-1 items-end justify-center gap-6 text-gray-900"> |                 <Row className="mt-4 flex-1 items-end justify-center gap-6 text-gray-900"> | ||||||
|                 <Row className="items-baseline gap-1"> |                   <Row className="items-baseline gap-1"> | ||||||
|                   <span className="text-3xl font-semibold"> |                     <span className="text-3xl font-semibold"> | ||||||
|                     {formatUsd(raised)} |                       {formatUsd(raised)} | ||||||
|                   </span> |                     </span> | ||||||
|                   raised |                     raised | ||||||
|                 </Row> |                   </Row> | ||||||
|                 {/* {match && ( |                   {/* {match && ( | ||||||
|                   <Col className="text-gray-500"> |                   <Col className="text-gray-500"> | ||||||
|                     <span className="text-xl">+{formatUsd(match)}</span> |                     <span className="text-xl">+{formatUsd(match)}</span> | ||||||
|                     <span className="">match</span> |                     <span className="">match</span> | ||||||
|                   </Col> |                   </Col> | ||||||
|                 )} */} |                 )} */} | ||||||
|               </Row> |                 </Row> | ||||||
|             </> |               </> | ||||||
|           )} |             )} | ||||||
|         </div> |           </Col> | ||||||
|       </div> |         </Card> | ||||||
|  |       </a> | ||||||
|     </Link> |     </Link> | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -8,6 +8,7 @@ import { | ||||||
|   BinaryContract, |   BinaryContract, | ||||||
|   Contract, |   Contract, | ||||||
|   CPMMBinaryContract, |   CPMMBinaryContract, | ||||||
|  |   CPMMContract, | ||||||
|   FreeResponseContract, |   FreeResponseContract, | ||||||
|   MultipleChoiceContract, |   MultipleChoiceContract, | ||||||
|   NumericContract, |   NumericContract, | ||||||
|  | @ -35,6 +36,7 @@ import { getMappedValue } from 'common/pseudo-numeric' | ||||||
| import { Tooltip } from '../tooltip' | import { Tooltip } from '../tooltip' | ||||||
| import { SiteLink } from '../site-link' | import { SiteLink } from '../site-link' | ||||||
| import { ProbChange } from './prob-change-table' | import { ProbChange } from './prob-change-table' | ||||||
|  | import { Card } from '../card' | ||||||
| 
 | 
 | ||||||
| export function ContractCard(props: { | export function ContractCard(props: { | ||||||
|   contract: Contract |   contract: Contract | ||||||
|  | @ -75,12 +77,7 @@ export function ContractCard(props: { | ||||||
|     !hideQuickBet |     !hideQuickBet | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <Row |     <Card className={clsx('group relative flex gap-3', className)}> | ||||||
|       className={clsx( |  | ||||||
|         'group  relative gap-3 rounded-lg bg-white shadow-md hover:cursor-pointer hover:bg-gray-100', |  | ||||||
|         className |  | ||||||
|       )} |  | ||||||
|     > |  | ||||||
|       <Col className="relative flex-1 gap-3 py-4 pb-12  pl-6"> |       <Col className="relative flex-1 gap-3 py-4 pb-12  pl-6"> | ||||||
|         <AvatarDetails |         <AvatarDetails | ||||||
|           contract={contract} |           contract={contract} | ||||||
|  | @ -195,7 +192,7 @@ export function ContractCard(props: { | ||||||
|           /> |           /> | ||||||
|         </Link> |         </Link> | ||||||
|       )} |       )} | ||||||
|     </Row> |     </Card> | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -391,7 +388,7 @@ export function PseudoNumericResolutionOrExpectation(props: { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function ContractCardProbChange(props: { | export function ContractCardProbChange(props: { | ||||||
|   contract: CPMMBinaryContract |   contract: CPMMContract | ||||||
|   noLinkAvatar?: boolean |   noLinkAvatar?: boolean | ||||||
|   className?: string |   className?: string | ||||||
| }) { | }) { | ||||||
|  | @ -399,12 +396,7 @@ export function ContractCardProbChange(props: { | ||||||
|   const contract = useContractWithPreload(props.contract) as CPMMBinaryContract |   const contract = useContractWithPreload(props.contract) as CPMMBinaryContract | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <Col |     <Card className={clsx(className, 'mb-4')}> | ||||||
|       className={clsx( |  | ||||||
|         className, |  | ||||||
|         'mb-4 rounded-lg bg-white shadow hover:bg-gray-100 hover:shadow-lg' |  | ||||||
|       )} |  | ||||||
|     > |  | ||||||
|       <AvatarDetails |       <AvatarDetails | ||||||
|         contract={contract} |         contract={contract} | ||||||
|         className={'px-6 pt-4'} |         className={'px-6 pt-4'} | ||||||
|  | @ -419,6 +411,6 @@ export function ContractCardProbChange(props: { | ||||||
|         </SiteLink> |         </SiteLink> | ||||||
|         <ProbChange className="py-2 pr-4" contract={contract} /> |         <ProbChange className="py-2 pr-4" contract={contract} /> | ||||||
|       </Row> |       </Row> | ||||||
|     </Col> |     </Card> | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,13 +1,10 @@ | ||||||
| import { sortBy } from 'lodash' |  | ||||||
| import clsx from 'clsx' | import clsx from 'clsx' | ||||||
| import { contractPath } from 'web/lib/firebase/contracts' |  | ||||||
| import { CPMMContract } from 'common/contract' | import { CPMMContract } from 'common/contract' | ||||||
| import { formatPercent } from 'common/util/format' | import { formatPercent } from 'common/util/format' | ||||||
| import { SiteLink } from '../site-link' | import { sortBy } from 'lodash' | ||||||
| import { Col } from '../layout/col' | import { Col } from '../layout/col' | ||||||
| import { Row } from '../layout/row' |  | ||||||
| import { LoadingIndicator } from '../loading-indicator' | import { LoadingIndicator } from '../loading-indicator' | ||||||
| import { useContractWithPreload } from 'web/hooks/use-contract' | import { ContractCardProbChange } from './contract-card' | ||||||
| 
 | 
 | ||||||
| export function ProbChangeTable(props: { | export function ProbChangeTable(props: { | ||||||
|   changes: CPMMContract[] | undefined |   changes: CPMMContract[] | undefined | ||||||
|  | @ -39,46 +36,21 @@ export function ProbChangeTable(props: { | ||||||
|   if (rows === 0) return <div className="px-4 text-gray-500">None</div> |   if (rows === 0) return <div className="px-4 text-gray-500">None</div> | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <Col className="mb-4 w-full divide-x-2 divide-y rounded-lg bg-white shadow-md md:flex-row md:divide-y-0"> |     <Col className="mb-4 w-full gap-4 rounded-lg md:flex-row"> | ||||||
|       <Col className="flex-1 divide-y"> |       <Col className="flex-1 gap-4"> | ||||||
|         {filteredPositiveChanges.map((contract) => ( |         {filteredPositiveChanges.map((contract) => ( | ||||||
|           <ProbChangeRow key={contract.id} contract={contract} /> |           <ContractCardProbChange key={contract.id} contract={contract} /> | ||||||
|         ))} |         ))} | ||||||
|       </Col> |       </Col> | ||||||
|       <Col className="flex-1 divide-y"> |       <Col className="flex-1 gap-4"> | ||||||
|         {filteredNegativeChanges.map((contract) => ( |         {filteredNegativeChanges.map((contract) => ( | ||||||
|           <ProbChangeRow key={contract.id} contract={contract} /> |           <ContractCardProbChange key={contract.id} contract={contract} /> | ||||||
|         ))} |         ))} | ||||||
|       </Col> |       </Col> | ||||||
|     </Col> |     </Col> | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function ProbChangeRow(props: { |  | ||||||
|   contract: CPMMContract |  | ||||||
|   className?: string |  | ||||||
| }) { |  | ||||||
|   const { className } = props |  | ||||||
|   const contract = |  | ||||||
|     (useContractWithPreload(props.contract) as CPMMContract) ?? props.contract |  | ||||||
|   return ( |  | ||||||
|     <Row |  | ||||||
|       className={clsx( |  | ||||||
|         'items-center justify-between gap-4 hover:bg-gray-100', |  | ||||||
|         className |  | ||||||
|       )} |  | ||||||
|     > |  | ||||||
|       <SiteLink |  | ||||||
|         className="p-4 pr-0 font-semibold text-indigo-700" |  | ||||||
|         href={contractPath(contract)} |  | ||||||
|       > |  | ||||||
|         <span className="line-clamp-2">{contract.question}</span> |  | ||||||
|       </SiteLink> |  | ||||||
|       <ProbChange className="py-2 pr-4 text-xl" contract={contract} /> |  | ||||||
|     </Row> |  | ||||||
|   ) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export function ProbChange(props: { | export function ProbChange(props: { | ||||||
|   contract: CPMMContract |   contract: CPMMContract | ||||||
|   className?: string |   className?: string | ||||||
|  |  | ||||||
|  | @ -7,8 +7,8 @@ import { useUserById } from 'web/hooks/use-user' | ||||||
| import { postPath } from 'web/lib/firebase/posts' | import { postPath } from 'web/lib/firebase/posts' | ||||||
| import { fromNow } from 'web/lib/util/time' | import { fromNow } from 'web/lib/util/time' | ||||||
| import { Avatar } from './avatar' | import { Avatar } from './avatar' | ||||||
|  | import { Card } from './card' | ||||||
| import { CardHighlightOptions } from './contract/contracts-grid' | import { CardHighlightOptions } from './contract/contracts-grid' | ||||||
| import { Row } from './layout/row' |  | ||||||
| import { UserLink } from './user-link' | import { UserLink } from './user-link' | ||||||
| 
 | 
 | ||||||
| export function PostCard(props: { | export function PostCard(props: { | ||||||
|  | @ -26,9 +26,9 @@ export function PostCard(props: { | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <div className="relative py-1"> |     <div className="relative py-1"> | ||||||
|       <Row |       <Card | ||||||
|         className={clsx( |         className={clsx( | ||||||
|           'relative  gap-3  rounded-lg bg-white py-2 px-3 shadow-md hover:cursor-pointer hover:bg-gray-100', |           'relative flex gap-3 py-2 px-3', | ||||||
|           itemIds?.includes(post.id) && highlightClassName |           itemIds?.includes(post.id) && highlightClassName | ||||||
|         )} |         )} | ||||||
|       > |       > | ||||||
|  | @ -58,7 +58,7 @@ export function PostCard(props: { | ||||||
|             Post |             Post | ||||||
|           </span> |           </span> | ||||||
|         </div> |         </div> | ||||||
|       </Row> |       </Card> | ||||||
|       {onPostClick ? ( |       {onPostClick ? ( | ||||||
|         <a |         <a | ||||||
|           className="absolute top-0 left-0 right-0 bottom-0" |           className="absolute top-0 left-0 right-0 bottom-0" | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user