Inga/tip button (#1043)
* added tip jar * made market actions/comments and manalink buttons IconButtons
This commit is contained in:
		
							parent
							
								
									4e5b78f4ee
								
							
						
					
					
						commit
						5ba4a9dce7
					
				|  | @ -82,3 +82,39 @@ export function Button(props: { | ||||||
|     </button> |     </button> | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | export function IconButton(props: { | ||||||
|  |   className?: string | ||||||
|  |   onClick?: MouseEventHandler<any> | undefined | ||||||
|  |   children?: ReactNode | ||||||
|  |   size?: SizeType | ||||||
|  |   type?: 'button' | 'reset' | 'submit' | ||||||
|  |   disabled?: boolean | ||||||
|  |   loading?: boolean | ||||||
|  | }) { | ||||||
|  |   const { | ||||||
|  |     children, | ||||||
|  |     className, | ||||||
|  |     onClick, | ||||||
|  |     size = 'md', | ||||||
|  |     type = 'button', | ||||||
|  |     disabled = false, | ||||||
|  |     loading, | ||||||
|  |   } = props | ||||||
|  | 
 | ||||||
|  |   return ( | ||||||
|  |     <button | ||||||
|  |       type={type} | ||||||
|  |       className={clsx( | ||||||
|  |         'inline-flex items-center justify-center transition-colors disabled:cursor-not-allowed', | ||||||
|  |         sizeClasses[size], | ||||||
|  |         'disabled:text-greyscale-2 text-greyscale-6 hover:text-indigo-600', | ||||||
|  |         className | ||||||
|  |       )} | ||||||
|  |       disabled={disabled || loading} | ||||||
|  |       onClick={onClick} | ||||||
|  |     > | ||||||
|  |       {children} | ||||||
|  |     </button> | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -19,11 +19,9 @@ import ShortToggle from '../widgets/short-toggle' | ||||||
| import { DuplicateContractButton } from '../duplicate-contract-button' | import { DuplicateContractButton } from '../duplicate-contract-button' | ||||||
| import { Row } from '../layout/row' | import { Row } from '../layout/row' | ||||||
| import { BETTORS, User } from 'common/user' | import { BETTORS, User } from 'common/user' | ||||||
| import { Button } from '../button' | import { IconButton } from '../button' | ||||||
| import { AddLiquidityButton } from './add-liquidity-button' | import { AddLiquidityButton } from './add-liquidity-button' | ||||||
| 
 | import { Tooltip } from '../tooltip' | ||||||
| export const contractDetailsButtonClassName = |  | ||||||
|   'group flex items-center rounded-md px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-100 text-gray-400 hover:text-gray-500' |  | ||||||
| 
 | 
 | ||||||
| export function ContractInfoDialog(props: { | export function ContractInfoDialog(props: { | ||||||
|   contract: Contract |   contract: Contract | ||||||
|  | @ -84,171 +82,173 @@ export function ContractInfoDialog(props: { | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <> |     <> | ||||||
|       <Button |       <Tooltip text="Market details" placement="bottom" noTap noFade> | ||||||
|         size="sm" |         <IconButton | ||||||
|         color="gray-white" |           size="2xs" | ||||||
|         className={clsx(contractDetailsButtonClassName, className)} |           className={clsx(className)} | ||||||
|         onClick={() => setOpen(true)} |           onClick={() => setOpen(true)} | ||||||
|       > |         > | ||||||
|         <DotsHorizontalIcon |           <DotsHorizontalIcon | ||||||
|           className={clsx('h-5 w-5 flex-shrink-0')} |             className={clsx('h-5 w-5 flex-shrink-0')} | ||||||
|           aria-hidden="true" |             aria-hidden="true" | ||||||
|         /> |           /> | ||||||
|       </Button> |         </IconButton> | ||||||
| 
 | 
 | ||||||
|       <Modal open={open} setOpen={setOpen}> |         <Modal open={open} setOpen={setOpen}> | ||||||
|         <Col className="gap-4 rounded bg-white p-6"> |           <Col className="gap-4 rounded bg-white p-6"> | ||||||
|           <Title className="!mt-0 !mb-0" text="This Market" /> |             <Title className="!mt-0 !mb-0" text="This Market" /> | ||||||
| 
 | 
 | ||||||
|           <table className="table-compact table-zebra table w-full text-gray-500"> |             <table className="table-compact table-zebra table w-full text-gray-500"> | ||||||
|             <tbody> |               <tbody> | ||||||
|               <tr> |  | ||||||
|                 <td>Type</td> |  | ||||||
|                 <td>{typeDisplay}</td> |  | ||||||
|               </tr> |  | ||||||
| 
 |  | ||||||
|               <tr> |  | ||||||
|                 <td>Payout</td> |  | ||||||
|                 <td className="flex gap-1"> |  | ||||||
|                   {mechanism === 'cpmm-1' ? ( |  | ||||||
|                     <> |  | ||||||
|                       Fixed{' '} |  | ||||||
|                       <InfoTooltip text="Each YES share is worth M$1 if YES wins." /> |  | ||||||
|                     </> |  | ||||||
|                   ) : ( |  | ||||||
|                     <> |  | ||||||
|                       Parimutuel{' '} |  | ||||||
|                       <InfoTooltip text="Each share is a fraction of the pool. " /> |  | ||||||
|                     </> |  | ||||||
|                   )} |  | ||||||
|                 </td> |  | ||||||
|               </tr> |  | ||||||
| 
 |  | ||||||
|               <tr> |  | ||||||
|                 <td>Market created</td> |  | ||||||
|                 <td>{formatTime(createdTime)}</td> |  | ||||||
|               </tr> |  | ||||||
| 
 |  | ||||||
|               {closeTime && ( |  | ||||||
|                 <tr> |                 <tr> | ||||||
|                   <td>Market close{closeTime > Date.now() ? 's' : 'd'}</td> |                   <td>Type</td> | ||||||
|                   <td>{formatTime(closeTime)}</td> |                   <td>{typeDisplay}</td> | ||||||
|                 </tr> |                 </tr> | ||||||
|               )} |  | ||||||
| 
 | 
 | ||||||
|               {resolutionTime && ( |  | ||||||
|                 <tr> |                 <tr> | ||||||
|                   <td>Market resolved</td> |                   <td>Payout</td> | ||||||
|                   <td>{formatTime(resolutionTime)}</td> |                   <td className="flex gap-1"> | ||||||
|                 </tr> |                     {mechanism === 'cpmm-1' ? ( | ||||||
|               )} |                       <> | ||||||
| 
 |                         Fixed{' '} | ||||||
|               <tr> |                         <InfoTooltip text="Each YES share is worth M$1 if YES wins." /> | ||||||
|                 <td> |                       </> | ||||||
|                   <span className="mr-1">Volume</span> |                     ) : ( | ||||||
|                   <InfoTooltip text="Total amount bought or sold" /> |                       <> | ||||||
|                 </td> |                         Parimutuel{' '} | ||||||
|                 <td>{formatMoney(contract.volume)}</td> |                         <InfoTooltip text="Each share is a fraction of the pool. " /> | ||||||
|               </tr> |                       </> | ||||||
| 
 |                     )} | ||||||
|               <tr> |  | ||||||
|                 <td>{capitalize(BETTORS)}</td> |  | ||||||
|                 <td>{uniqueBettorCount ?? '0'}</td> |  | ||||||
|               </tr> |  | ||||||
| 
 |  | ||||||
|               <tr> |  | ||||||
|                 <td> |  | ||||||
|                   <Row> |  | ||||||
|                     <span className="mr-1">Elasticity</span> |  | ||||||
|                     <InfoTooltip |  | ||||||
|                       text={ |  | ||||||
|                         mechanism === 'cpmm-1' |  | ||||||
|                           ? 'Probability change between a M$50 bet on YES and NO' |  | ||||||
|                           : 'Probability change from a M$100 bet' |  | ||||||
|                       } |  | ||||||
|                     /> |  | ||||||
|                   </Row> |  | ||||||
|                 </td> |  | ||||||
|                 <td>{formatPercent(elasticity)}</td> |  | ||||||
|               </tr> |  | ||||||
| 
 |  | ||||||
|               <tr> |  | ||||||
|                 <td>Liquidity subsidies</td> |  | ||||||
|                 <td> |  | ||||||
|                   {mechanism === 'cpmm-1' |  | ||||||
|                     ? formatMoney(contract.totalLiquidity) |  | ||||||
|                     : formatMoney(100)} |  | ||||||
|                 </td> |  | ||||||
|               </tr> |  | ||||||
| 
 |  | ||||||
|               <tr> |  | ||||||
|                 <td>Pool</td> |  | ||||||
|                 <td> |  | ||||||
|                   {mechanism === 'cpmm-1' && outcomeType === 'BINARY' |  | ||||||
|                     ? `${Math.round(pool.YES)} YES, ${Math.round(pool.NO)} NO` |  | ||||||
|                     : mechanism === 'cpmm-1' && outcomeType === 'PSEUDO_NUMERIC' |  | ||||||
|                     ? `${Math.round(pool.YES)} HIGHER, ${Math.round( |  | ||||||
|                         pool.NO |  | ||||||
|                       )} LOWER` |  | ||||||
|                     : contractPool(contract)} |  | ||||||
|                 </td> |  | ||||||
|               </tr> |  | ||||||
| 
 |  | ||||||
|               {/* Show a path to Firebase if user is an admin, or we're on localhost */} |  | ||||||
|               {(isAdmin || isDev) && ( |  | ||||||
|                 <tr> |  | ||||||
|                   <td>[ADMIN] Firestore</td> |  | ||||||
|                   <td> |  | ||||||
|                     <SiteLink href={firestoreConsolePath(id)}> |  | ||||||
|                       Console link |  | ||||||
|                     </SiteLink> |  | ||||||
|                   </td> |                   </td> | ||||||
|                 </tr> |                 </tr> | ||||||
|               )} |  | ||||||
|               {isAdmin && ( |  | ||||||
|                 <tr> |  | ||||||
|                   <td>[ADMIN] Featured</td> |  | ||||||
|                   <td> |  | ||||||
|                     <ShortToggle |  | ||||||
|                       on={featured} |  | ||||||
|                       setOn={setFeatured} |  | ||||||
|                       onChange={onFeaturedToggle} |  | ||||||
|                     /> |  | ||||||
|                   </td> |  | ||||||
|                 </tr> |  | ||||||
|               )} |  | ||||||
|               {user && ( |  | ||||||
|                 <tr> |  | ||||||
|                   <td>{isAdmin ? '[ADMIN]' : ''} Unlisted</td> |  | ||||||
|                   <td> |  | ||||||
|                     <ShortToggle |  | ||||||
|                       disabled={ |  | ||||||
|                         isUnlisted |  | ||||||
|                           ? !(isAdmin || (isCreator && wasUnlistedByCreator)) |  | ||||||
|                           : !(isCreator || isAdmin) |  | ||||||
|                       } |  | ||||||
|                       on={contract.visibility === 'unlisted'} |  | ||||||
|                       setOn={(b) => |  | ||||||
|                         updateContract(id, { |  | ||||||
|                           visibility: b ? 'unlisted' : 'public', |  | ||||||
|                           unlistedById: b ? user.id : '', |  | ||||||
|                         }) |  | ||||||
|                       } |  | ||||||
|                     /> |  | ||||||
|                   </td> |  | ||||||
|                 </tr> |  | ||||||
|               )} |  | ||||||
|             </tbody> |  | ||||||
|           </table> |  | ||||||
| 
 | 
 | ||||||
|           <Row className="flex-wrap"> |                 <tr> | ||||||
|             {mechanism === 'cpmm-1' && ( |                   <td>Market created</td> | ||||||
|               <AddLiquidityButton contract={contract} className="mr-2" /> |                   <td>{formatTime(createdTime)}</td> | ||||||
|             )} |                 </tr> | ||||||
|             <DuplicateContractButton contract={contract} /> | 
 | ||||||
|           </Row> |                 {closeTime && ( | ||||||
|         </Col> |                   <tr> | ||||||
|       </Modal> |                     <td>Market close{closeTime > Date.now() ? 's' : 'd'}</td> | ||||||
|  |                     <td>{formatTime(closeTime)}</td> | ||||||
|  |                   </tr> | ||||||
|  |                 )} | ||||||
|  | 
 | ||||||
|  |                 {resolutionTime && ( | ||||||
|  |                   <tr> | ||||||
|  |                     <td>Market resolved</td> | ||||||
|  |                     <td>{formatTime(resolutionTime)}</td> | ||||||
|  |                   </tr> | ||||||
|  |                 )} | ||||||
|  | 
 | ||||||
|  |                 <tr> | ||||||
|  |                   <td> | ||||||
|  |                     <span className="mr-1">Volume</span> | ||||||
|  |                     <InfoTooltip text="Total amount bought or sold" /> | ||||||
|  |                   </td> | ||||||
|  |                   <td>{formatMoney(contract.volume)}</td> | ||||||
|  |                 </tr> | ||||||
|  | 
 | ||||||
|  |                 <tr> | ||||||
|  |                   <td>{capitalize(BETTORS)}</td> | ||||||
|  |                   <td>{uniqueBettorCount ?? '0'}</td> | ||||||
|  |                 </tr> | ||||||
|  | 
 | ||||||
|  |                 <tr> | ||||||
|  |                   <td> | ||||||
|  |                     <Row> | ||||||
|  |                       <span className="mr-1">Elasticity</span> | ||||||
|  |                       <InfoTooltip | ||||||
|  |                         text={ | ||||||
|  |                           mechanism === 'cpmm-1' | ||||||
|  |                             ? 'Probability change between a M$50 bet on YES and NO' | ||||||
|  |                             : 'Probability change from a M$100 bet' | ||||||
|  |                         } | ||||||
|  |                       /> | ||||||
|  |                     </Row> | ||||||
|  |                   </td> | ||||||
|  |                   <td>{formatPercent(elasticity)}</td> | ||||||
|  |                 </tr> | ||||||
|  | 
 | ||||||
|  |                 <tr> | ||||||
|  |                   <td>Liquidity subsidies</td> | ||||||
|  |                   <td> | ||||||
|  |                     {mechanism === 'cpmm-1' | ||||||
|  |                       ? formatMoney(contract.totalLiquidity) | ||||||
|  |                       : formatMoney(100)} | ||||||
|  |                   </td> | ||||||
|  |                 </tr> | ||||||
|  | 
 | ||||||
|  |                 <tr> | ||||||
|  |                   <td>Pool</td> | ||||||
|  |                   <td> | ||||||
|  |                     {mechanism === 'cpmm-1' && outcomeType === 'BINARY' | ||||||
|  |                       ? `${Math.round(pool.YES)} YES, ${Math.round(pool.NO)} NO` | ||||||
|  |                       : mechanism === 'cpmm-1' && | ||||||
|  |                         outcomeType === 'PSEUDO_NUMERIC' | ||||||
|  |                       ? `${Math.round(pool.YES)} HIGHER, ${Math.round( | ||||||
|  |                           pool.NO | ||||||
|  |                         )} LOWER` | ||||||
|  |                       : contractPool(contract)} | ||||||
|  |                   </td> | ||||||
|  |                 </tr> | ||||||
|  | 
 | ||||||
|  |                 {/* Show a path to Firebase if user is an admin, or we're on localhost */} | ||||||
|  |                 {(isAdmin || isDev) && ( | ||||||
|  |                   <tr> | ||||||
|  |                     <td>[ADMIN] Firestore</td> | ||||||
|  |                     <td> | ||||||
|  |                       <SiteLink href={firestoreConsolePath(id)}> | ||||||
|  |                         Console link | ||||||
|  |                       </SiteLink> | ||||||
|  |                     </td> | ||||||
|  |                   </tr> | ||||||
|  |                 )} | ||||||
|  |                 {isAdmin && ( | ||||||
|  |                   <tr> | ||||||
|  |                     <td>[ADMIN] Featured</td> | ||||||
|  |                     <td> | ||||||
|  |                       <ShortToggle | ||||||
|  |                         on={featured} | ||||||
|  |                         setOn={setFeatured} | ||||||
|  |                         onChange={onFeaturedToggle} | ||||||
|  |                       /> | ||||||
|  |                     </td> | ||||||
|  |                   </tr> | ||||||
|  |                 )} | ||||||
|  |                 {user && ( | ||||||
|  |                   <tr> | ||||||
|  |                     <td>{isAdmin ? '[ADMIN]' : ''} Unlisted</td> | ||||||
|  |                     <td> | ||||||
|  |                       <ShortToggle | ||||||
|  |                         disabled={ | ||||||
|  |                           isUnlisted | ||||||
|  |                             ? !(isAdmin || (isCreator && wasUnlistedByCreator)) | ||||||
|  |                             : !(isCreator || isAdmin) | ||||||
|  |                         } | ||||||
|  |                         on={contract.visibility === 'unlisted'} | ||||||
|  |                         setOn={(b) => | ||||||
|  |                           updateContract(id, { | ||||||
|  |                             visibility: b ? 'unlisted' : 'public', | ||||||
|  |                             unlistedById: b ? user.id : '', | ||||||
|  |                           }) | ||||||
|  |                         } | ||||||
|  |                       /> | ||||||
|  |                     </td> | ||||||
|  |                   </tr> | ||||||
|  |                 )} | ||||||
|  |               </tbody> | ||||||
|  |             </table> | ||||||
|  | 
 | ||||||
|  |             <Row className="flex-wrap"> | ||||||
|  |               {mechanism === 'cpmm-1' && ( | ||||||
|  |                 <AddLiquidityButton contract={contract} className="mr-2" /> | ||||||
|  |               )} | ||||||
|  |               <DuplicateContractButton contract={contract} /> | ||||||
|  |             </Row> | ||||||
|  |           </Col> | ||||||
|  |         </Modal> | ||||||
|  |       </Tooltip> | ||||||
|     </> |     </> | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -2,7 +2,7 @@ import { ShareIcon } from '@heroicons/react/outline' | ||||||
| import { Row } from '../layout/row' | import { Row } from '../layout/row' | ||||||
| import { Contract } from 'web/lib/firebase/contracts' | import { Contract } from 'web/lib/firebase/contracts' | ||||||
| import React, { useState } from 'react' | import React, { useState } from 'react' | ||||||
| import { Button } from 'web/components/button' | import { IconButton } from 'web/components/button' | ||||||
| import { useUser } from 'web/hooks/use-user' | import { useUser } from 'web/hooks/use-user' | ||||||
| import { ShareModal } from './share-modal' | import { ShareModal } from './share-modal' | ||||||
| import { FollowMarketButton } from 'web/components/follow-market-button' | import { FollowMarketButton } from 'web/components/follow-market-button' | ||||||
|  | @ -16,15 +16,14 @@ export function ExtraContractActionsRow(props: { contract: Contract }) { | ||||||
|   const [isShareOpen, setShareOpen] = useState(false) |   const [isShareOpen, setShareOpen] = useState(false) | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <Row> |     <Row className="gap-1"> | ||||||
|       <FollowMarketButton contract={contract} user={user} /> |       <FollowMarketButton contract={contract} user={user} /> | ||||||
| 
 | 
 | ||||||
|       <LikeMarketButton contract={contract} user={user} /> |       <LikeMarketButton contract={contract} user={user} /> | ||||||
| 
 | 
 | ||||||
|       <Tooltip text="Share" placement="bottom" noTap noFade> |       <Tooltip text="Share" placement="bottom" noTap noFade> | ||||||
|         <Button |         <IconButton | ||||||
|           size="sm" |           size="2xs" | ||||||
|           color="gray-white" |  | ||||||
|           className={'flex'} |           className={'flex'} | ||||||
|           onClick={() => setShareOpen(true)} |           onClick={() => setShareOpen(true)} | ||||||
|         > |         > | ||||||
|  | @ -35,7 +34,7 @@ export function ExtraContractActionsRow(props: { contract: Contract }) { | ||||||
|             contract={contract} |             contract={contract} | ||||||
|             user={user} |             user={user} | ||||||
|           /> |           /> | ||||||
|         </Button> |         </IconButton> | ||||||
|       </Tooltip> |       </Tooltip> | ||||||
| 
 | 
 | ||||||
|       <ContractInfoDialog contract={contract} user={user} /> |       <ContractInfoDialog contract={contract} user={user} /> | ||||||
|  |  | ||||||
|  | @ -1,10 +1,9 @@ | ||||||
| import clsx from 'clsx' | import clsx from 'clsx' | ||||||
| import { HeartIcon } from '@heroicons/react/outline' |  | ||||||
| 
 |  | ||||||
| import { Button } from 'web/components/button' |  | ||||||
| import { formatMoney, shortFormatNumber } from 'common/util/format' | import { formatMoney, shortFormatNumber } from 'common/util/format' | ||||||
| import { Col } from 'web/components/layout/col' | import { Col } from 'web/components/layout/col' | ||||||
| import { Tooltip } from '../tooltip' | import { Tooltip } from '../tooltip' | ||||||
|  | import TipJar from 'web/public/custom-components/tipJar' | ||||||
|  | import { useState } from 'react' | ||||||
| 
 | 
 | ||||||
| export function TipButton(props: { | export function TipButton(props: { | ||||||
|   tipAmount: number |   tipAmount: number | ||||||
|  | @ -14,11 +13,12 @@ export function TipButton(props: { | ||||||
|   isCompact?: boolean |   isCompact?: boolean | ||||||
|   disabled?: boolean |   disabled?: boolean | ||||||
| }) { | }) { | ||||||
|   const { tipAmount, totalTipped, userTipped, isCompact, onClick, disabled } = |   const { tipAmount, totalTipped, userTipped, onClick, disabled } = props | ||||||
|     props |  | ||||||
| 
 | 
 | ||||||
|   const tipDisplay = shortFormatNumber(Math.ceil(totalTipped / 10)) |   const tipDisplay = shortFormatNumber(Math.ceil(totalTipped / 10)) | ||||||
| 
 | 
 | ||||||
|  |   const [hover, setHover] = useState(false) | ||||||
|  | 
 | ||||||
|   return ( |   return ( | ||||||
|     <Tooltip |     <Tooltip | ||||||
|       text={ |       text={ | ||||||
|  | @ -30,39 +30,40 @@ export function TipButton(props: { | ||||||
|       noTap |       noTap | ||||||
|       noFade |       noFade | ||||||
|     > |     > | ||||||
|       <Button |       <button | ||||||
|         size={'sm'} |  | ||||||
|         className={clsx( |  | ||||||
|           'max-w-xs self-center', |  | ||||||
|           isCompact && 'px-0 py-0', |  | ||||||
|           disabled && 'hover:bg-inherit' |  | ||||||
|         )} |  | ||||||
|         color={'gray-white'} |  | ||||||
|         onClick={onClick} |         onClick={onClick} | ||||||
|         disabled={disabled} |         disabled={disabled} | ||||||
|  |         className={clsx( | ||||||
|  |           'px-2 py-1 text-xs', //2xs button
 | ||||||
|  |           'text-greyscale-6 transition-transform hover:text-indigo-600 disabled:cursor-not-allowed', | ||||||
|  |           !disabled ? 'hover:rotate-12' : '' | ||||||
|  |         )} | ||||||
|  |         onMouseOver={() => setHover(true)} | ||||||
|  |         onMouseLeave={() => setHover(false)} | ||||||
|       > |       > | ||||||
|         <Col className={'relative items-center sm:flex-row'}> |         <Col className={clsx('relative', disabled ? 'opacity-30' : '')}> | ||||||
|           <HeartIcon |           <TipJar | ||||||
|             className={clsx( |             size={18} | ||||||
|               'h-5 w-5', |             color={userTipped || (hover && !disabled) ? '#4f46e5' : '#66667C'} | ||||||
|               totalTipped > 0 ? 'mr-2' : '', |             fill={userTipped ? '#4f46e5' : 'none'} | ||||||
|               userTipped ? 'fill-teal-500 text-teal-500' : '' |  | ||||||
|             )} |  | ||||||
|           /> |           /> | ||||||
|           {totalTipped > 0 && ( |           <div | ||||||
|             <div |             className={clsx( | ||||||
|               className={clsx( |               ' absolute top-[2px] text-[0.5rem]', | ||||||
|                 'bg-greyscale-5 absolute ml-3.5 mt-2 h-4 w-4 rounded-full align-middle text-white sm:mt-3 sm:h-5 sm:w-5 sm:px-1', |               userTipped ? 'text-white' : '', | ||||||
|                 tipDisplay.length > 2 |               tipDisplay.length === 1 | ||||||
|                   ? 'text-[0.4rem] sm:text-[0.5rem]' |                 ? 'left-[7px]' | ||||||
|                   : 'sm:text-2xs text-[0.5rem]' |                 : tipDisplay.length === 2 | ||||||
|               )} |                 ? 'left-[4.5px]' | ||||||
|             > |                 : tipDisplay.length > 2 | ||||||
|               {tipDisplay} |                 ? 'left-[4px] top-[2.5px] text-[0.35rem]' | ||||||
|             </div> |                 : '' | ||||||
|           )} |             )} | ||||||
|  |           > | ||||||
|  |             {totalTipped > 0 ? tipDisplay : ''} | ||||||
|  |           </div> | ||||||
|         </Col> |         </Col> | ||||||
|       </Button> |       </button> | ||||||
|     </Tooltip> |     </Tooltip> | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -24,7 +24,7 @@ import { UserLink } from 'web/components/user-link' | ||||||
| import { CommentInput } from '../comment-input' | import { CommentInput } from '../comment-input' | ||||||
| import { AwardBountyButton } from 'web/components/award-bounty-button' | import { AwardBountyButton } from 'web/components/award-bounty-button' | ||||||
| import { ReplyIcon } from '@heroicons/react/solid' | import { ReplyIcon } from '@heroicons/react/solid' | ||||||
| import { Button } from '../button' | import { IconButton } from '../button' | ||||||
| import { ReplyToggle } from '../comments/reply-toggle' | import { ReplyToggle } from '../comments/reply-toggle' | ||||||
| 
 | 
 | ||||||
| export type ReplyTo = { id: string; username: string } | export type ReplyTo = { id: string; username: string } | ||||||
|  | @ -154,36 +154,46 @@ export function ParentFeedComment(props: { | ||||||
|             numComments={numComments} |             numComments={numComments} | ||||||
|             onClick={onSeeReplyClick} |             onClick={onSeeReplyClick} | ||||||
|           /> |           /> | ||||||
|           <Row className="grow justify-end gap-2"> |           <CommentActions | ||||||
|             {onReplyClick && ( |             onReplyClick={onReplyClick} | ||||||
|               <Button |             comment={comment} | ||||||
|                 size={'sm'} |             showTip={showTip} | ||||||
|                 className={clsx( |             myTip={myTip} | ||||||
|                   'hover:bg-greyscale-2 mt-0 mb-1 max-w-xs px-0 py-0' |             totalTip={totalTip} | ||||||
|                 )} |             contract={contract} | ||||||
|                 color={'gray-white'} |           /> | ||||||
|                 onClick={() => onReplyClick(comment)} |  | ||||||
|               > |  | ||||||
|                 <ReplyIcon className="h-5 w-5" /> |  | ||||||
|               </Button> |  | ||||||
|             )} |  | ||||||
|             {showTip && ( |  | ||||||
|               <Tipper |  | ||||||
|                 comment={comment} |  | ||||||
|                 myTip={myTip ?? 0} |  | ||||||
|                 totalTip={totalTip ?? 0} |  | ||||||
|               /> |  | ||||||
|             )} |  | ||||||
|             {(contract.openCommentBounties ?? 0) > 0 && ( |  | ||||||
|               <AwardBountyButton comment={comment} contract={contract} /> |  | ||||||
|             )} |  | ||||||
|           </Row> |  | ||||||
|         </Row> |         </Row> | ||||||
|       </Col> |       </Col> | ||||||
|     </Row> |     </Row> | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | export function CommentActions(props: { | ||||||
|  |   onReplyClick?: (comment: ContractComment) => void | ||||||
|  |   comment: ContractComment | ||||||
|  |   showTip?: boolean | ||||||
|  |   myTip?: number | ||||||
|  |   totalTip?: number | ||||||
|  |   contract: Contract | ||||||
|  | }) { | ||||||
|  |   const { onReplyClick, comment, showTip, myTip, totalTip, contract } = props | ||||||
|  |   return ( | ||||||
|  |     <Row className="grow justify-end"> | ||||||
|  |       {onReplyClick && ( | ||||||
|  |         <IconButton size={'xs'} onClick={() => onReplyClick(comment)}> | ||||||
|  |           <ReplyIcon className="h-5 w-5" /> | ||||||
|  |         </IconButton> | ||||||
|  |       )} | ||||||
|  |       {showTip && ( | ||||||
|  |         <Tipper comment={comment} myTip={myTip ?? 0} totalTip={totalTip ?? 0} /> | ||||||
|  |       )} | ||||||
|  |       {(contract.openCommentBounties ?? 0) > 0 && ( | ||||||
|  |         <AwardBountyButton comment={comment} contract={contract} /> | ||||||
|  |       )} | ||||||
|  |     </Row> | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| export const FeedComment = memo(function FeedComment(props: { | export const FeedComment = memo(function FeedComment(props: { | ||||||
|   contract: Contract |   contract: Contract | ||||||
|   comment: ContractComment |   comment: ContractComment | ||||||
|  | @ -233,30 +243,14 @@ export const FeedComment = memo(function FeedComment(props: { | ||||||
|           content={content || text} |           content={content || text} | ||||||
|           smallImage |           smallImage | ||||||
|         /> |         /> | ||||||
|         <Row className="grow justify-end gap-2"> |         <CommentActions | ||||||
|           {onReplyClick && ( |           onReplyClick={onReplyClick} | ||||||
|             <Button |           comment={comment} | ||||||
|               size={'sm'} |           showTip={showTip} | ||||||
|               className={clsx( |           myTip={myTip} | ||||||
|                 'hover:bg-greyscale-2 mt-0 mb-1 max-w-xs px-0 py-0' |           totalTip={totalTip} | ||||||
|               )} |           contract={contract} | ||||||
|               color={'gray-white'} |         /> | ||||||
|               onClick={() => onReplyClick(comment)} |  | ||||||
|             > |  | ||||||
|               <ReplyIcon className="h-5 w-5" /> |  | ||||||
|             </Button> |  | ||||||
|           )} |  | ||||||
|           {showTip && ( |  | ||||||
|             <Tipper |  | ||||||
|               comment={comment} |  | ||||||
|               myTip={myTip ?? 0} |  | ||||||
|               totalTip={totalTip ?? 0} |  | ||||||
|             /> |  | ||||||
|           )} |  | ||||||
|           {(contract.openCommentBounties ?? 0) > 0 && ( |  | ||||||
|             <AwardBountyButton comment={comment} contract={contract} /> |  | ||||||
|           )} |  | ||||||
|         </Row> |  | ||||||
|       </Col> |       </Col> | ||||||
|     </Row> |     </Row> | ||||||
|   ) |   ) | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| import { Button } from 'web/components/button' | import { IconButton } from 'web/components/button' | ||||||
| import { | import { | ||||||
|   Contract, |   Contract, | ||||||
|   followContract, |   followContract, | ||||||
|  | @ -33,9 +33,8 @@ export const FollowMarketButton = (props: { | ||||||
|       noTap |       noTap | ||||||
|       noFade |       noFade | ||||||
|     > |     > | ||||||
|       <Button |       <IconButton | ||||||
|         size={'sm'} |         size="2xs" | ||||||
|         color={'gray-white'} |  | ||||||
|         onClick={async () => { |         onClick={async () => { | ||||||
|           if (!user) return firebaseLogin() |           if (!user) return firebaseLogin() | ||||||
|           if (followers?.includes(user.id)) { |           if (followers?.includes(user.id)) { | ||||||
|  | @ -65,18 +64,12 @@ export const FollowMarketButton = (props: { | ||||||
|       > |       > | ||||||
|         {watching ? ( |         {watching ? ( | ||||||
|           <Col className={'items-center gap-x-2 sm:flex-row'}> |           <Col className={'items-center gap-x-2 sm:flex-row'}> | ||||||
|             <EyeOffIcon |             <EyeOffIcon className={clsx('h-5 w-5')} aria-hidden="true" /> | ||||||
|               className={clsx('h-5 w-5 sm:h-6 sm:w-6')} |  | ||||||
|               aria-hidden="true" |  | ||||||
|             /> |  | ||||||
|             {/* Unwatch */} |             {/* Unwatch */} | ||||||
|           </Col> |           </Col> | ||||||
|         ) : ( |         ) : ( | ||||||
|           <Col className={'items-center gap-x-2 sm:flex-row'}> |           <Col className={'items-center gap-x-2 sm:flex-row'}> | ||||||
|             <EyeIcon |             <EyeIcon className={clsx('h-5 w-5')} aria-hidden="true" /> | ||||||
|               className={clsx('h-5 w-5 sm:h-6 sm:w-6')} |  | ||||||
|               aria-hidden="true" |  | ||||||
|             /> |  | ||||||
|             {/* Watch */} |             {/* Watch */} | ||||||
|           </Col> |           </Col> | ||||||
|         )} |         )} | ||||||
|  | @ -87,7 +80,7 @@ export const FollowMarketButton = (props: { | ||||||
|             followers?.includes(user?.id ?? 'nope') ? 'watched' : 'unwatched' |             followers?.includes(user?.id ?? 'nope') ? 'watched' : 'unwatched' | ||||||
|           } a question!`}
 |           } a question!`}
 | ||||||
|         /> |         /> | ||||||
|       </Button> |       </IconButton> | ||||||
|     </Tooltip> |     </Tooltip> | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -9,9 +9,9 @@ import { Col } from 'web/components/layout/col' | ||||||
| import { Row } from 'web/components/layout/row' | import { Row } from 'web/components/layout/row' | ||||||
| import { Claim, Manalink } from 'common/manalink' | import { Claim, Manalink } from 'common/manalink' | ||||||
| import { ShareIconButton } from './share-icon-button' | import { ShareIconButton } from './share-icon-button' | ||||||
| import { contractDetailsButtonClassName } from './contract/contract-info-dialog' |  | ||||||
| import { useUserById } from 'web/hooks/use-user' | import { useUserById } from 'web/hooks/use-user' | ||||||
| import getManalinkUrl from 'web/get-manalink-url' | import getManalinkUrl from 'web/get-manalink-url' | ||||||
|  | import { IconButton } from './button' | ||||||
| 
 | 
 | ||||||
| export type ManalinkInfo = { | export type ManalinkInfo = { | ||||||
|   expiresTime: number | null |   expiresTime: number | null | ||||||
|  | @ -123,7 +123,7 @@ export function ManalinkCardFromView(props: { | ||||||
|             src="/logo-white.svg" |             src="/logo-white.svg" | ||||||
|           /> |           /> | ||||||
|         </Col> |         </Col> | ||||||
|         <Row className="relative w-full gap-1 rounded-b-lg bg-white px-4 py-2 text-lg"> |         <Row className="relative w-full rounded-b-lg bg-white px-4 py-2 align-middle text-lg"> | ||||||
|           <div |           <div | ||||||
|             className={clsx( |             className={clsx( | ||||||
|               'my-auto mb-1 w-full', |               'my-auto mb-1 w-full', | ||||||
|  | @ -133,32 +133,23 @@ export function ManalinkCardFromView(props: { | ||||||
|             {formatMoney(amount)} |             {formatMoney(amount)} | ||||||
|           </div> |           </div> | ||||||
| 
 | 
 | ||||||
|           <button |           <IconButton size="2xs" onClick={() => (window.location.href = qrUrl)}> | ||||||
|             onClick={() => (window.location.href = qrUrl)} |  | ||||||
|             className={clsx(contractDetailsButtonClassName)} |  | ||||||
|           > |  | ||||||
|             <QrcodeIcon className="h-6 w-6" /> |             <QrcodeIcon className="h-6 w-6" /> | ||||||
|           </button> |           </IconButton> | ||||||
| 
 | 
 | ||||||
|           <ShareIconButton |           <ShareIconButton | ||||||
|             toastClassName={'-left-48 min-w-[250%]'} |             toastClassName={'-left-48 min-w-[250%]'} | ||||||
|             buttonClassName={'transition-colors'} |  | ||||||
|             onCopyButtonClassName={ |  | ||||||
|               'bg-gray-200 text-gray-600 transition-none hover:bg-gray-200 hover:text-gray-600' |  | ||||||
|             } |  | ||||||
|             copyPayload={getManalinkUrl(link.slug)} |             copyPayload={getManalinkUrl(link.slug)} | ||||||
|           /> |           /> | ||||||
|           <button |           <IconButton | ||||||
|  |             size="xs" | ||||||
|             onClick={() => setShowDetails(!showDetails)} |             onClick={() => setShowDetails(!showDetails)} | ||||||
|             className={clsx( |             className={clsx( | ||||||
|               contractDetailsButtonClassName, |               showDetails ? ' text-indigo-600 hover:text-indigo-700' : '' | ||||||
|               showDetails |  | ||||||
|                 ? 'bg-gray-200 text-gray-600 hover:bg-gray-200 hover:text-gray-600' |  | ||||||
|                 : '' |  | ||||||
|             )} |             )} | ||||||
|           > |           > | ||||||
|             <DotsHorizontalIcon className="h-[24px] w-5" /> |             <DotsHorizontalIcon className="h-5 w-5" /> | ||||||
|           </button> |           </IconButton> | ||||||
|         </Row> |         </Row> | ||||||
|       </Col> |       </Col> | ||||||
|       <div className="mt-2 mb-4 text-xs text-gray-500 md:text-sm"> |       <div className="mt-2 mb-4 text-xs text-gray-500 md:text-sm"> | ||||||
|  |  | ||||||
|  | @ -5,34 +5,22 @@ import clsx from 'clsx' | ||||||
| import { copyToClipboard } from 'web/lib/util/copy' | import { copyToClipboard } from 'web/lib/util/copy' | ||||||
| import { ToastClipboard } from 'web/components/toast-clipboard' | import { ToastClipboard } from 'web/components/toast-clipboard' | ||||||
| import { track } from 'web/lib/service/analytics' | import { track } from 'web/lib/service/analytics' | ||||||
| import { contractDetailsButtonClassName } from 'web/components/contract/contract-info-dialog' | import { IconButton } from './button' | ||||||
| 
 | 
 | ||||||
| export function ShareIconButton(props: { | export function ShareIconButton(props: { | ||||||
|   buttonClassName?: string |  | ||||||
|   onCopyButtonClassName?: string |  | ||||||
|   toastClassName?: string |   toastClassName?: string | ||||||
|   children?: React.ReactNode |   children?: React.ReactNode | ||||||
|   iconClassName?: string |   iconClassName?: string | ||||||
|   copyPayload: string |   copyPayload: string | ||||||
| }) { | }) { | ||||||
|   const { |   const { toastClassName, children, iconClassName, copyPayload } = props | ||||||
|     buttonClassName, |  | ||||||
|     onCopyButtonClassName, |  | ||||||
|     toastClassName, |  | ||||||
|     children, |  | ||||||
|     iconClassName, |  | ||||||
|     copyPayload, |  | ||||||
|   } = props |  | ||||||
|   const [showToast, setShowToast] = useState(false) |   const [showToast, setShowToast] = useState(false) | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <div className="relative z-10 flex-shrink-0"> |     <div className="relative z-10 flex-shrink-0"> | ||||||
|       <button |       <IconButton | ||||||
|         className={clsx( |         size="2xs" | ||||||
|           contractDetailsButtonClassName, |         className={clsx('mt-1', showToast ? 'text-indigo-600' : '')} | ||||||
|           buttonClassName, |  | ||||||
|           showToast ? onCopyButtonClassName : '' |  | ||||||
|         )} |  | ||||||
|         onClick={() => { |         onClick={() => { | ||||||
|           copyToClipboard(copyPayload) |           copyToClipboard(copyPayload) | ||||||
|           track('copy share link') |           track('copy share link') | ||||||
|  | @ -41,11 +29,11 @@ export function ShareIconButton(props: { | ||||||
|         }} |         }} | ||||||
|       > |       > | ||||||
|         <LinkIcon |         <LinkIcon | ||||||
|           className={clsx(iconClassName ? iconClassName : 'h-[24px] w-5')} |           className={clsx(iconClassName ? iconClassName : 'h-5 w-5')} | ||||||
|           aria-hidden="true" |           aria-hidden="true" | ||||||
|         /> |         /> | ||||||
|         {children} |         {children} | ||||||
|       </button> |       </IconButton> | ||||||
| 
 | 
 | ||||||
|       {showToast && <ToastClipboard className={toastClassName} />} |       {showToast && <ToastClipboard className={toastClassName} />} | ||||||
|     </div> |     </div> | ||||||
|  |  | ||||||
							
								
								
									
										23
									
								
								web/public/custom-components/tipJar.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								web/public/custom-components/tipJar.tsx
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,23 @@ | ||||||
|  | export default function TipJar({ | ||||||
|  |   size = 18, | ||||||
|  |   color = '#66667C', | ||||||
|  |   strokeWidth = 1.5, | ||||||
|  |   fill = 'none', | ||||||
|  | }) { | ||||||
|  |   return ( | ||||||
|  |     <svg | ||||||
|  |       xmlns="http://www.w3.org/2000/svg" | ||||||
|  |       viewBox="0 0 18 18" | ||||||
|  |       width={size} | ||||||
|  |       height={size} | ||||||
|  |       fill={fill} | ||||||
|  |       stroke={color} | ||||||
|  |       strokeWidth={strokeWidth} | ||||||
|  |       opacity={50} | ||||||
|  |     > | ||||||
|  |       <path d="M15.5,8.1v5.8c0,1.43-1.16,2.6-2.6,2.6H5.1c-1.44,0-2.6-1.16-2.6-2.6v-5.8c0-1.04,.89-3.25,1.5-4.1h0v-2c0-.55,.45-1,1-1H13c.55,0,1,.45,1,1v2h0c.61,.85,1.5,3.06,1.5,4.1Z" /> | ||||||
|  |       <line x1="4" y1="4" x2="9" y2="4" /> | ||||||
|  |       <line x1="11.26" y1="4" x2="14" y2="4" /> | ||||||
|  |     </svg> | ||||||
|  |   ) | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user