Merge branch 'main' into group-adding-removing

This commit is contained in:
Ian Philips 2022-07-22 11:27:26 -06:00 committed by GitHub
commit 7d39f27786
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 166 additions and 14 deletions

View File

@ -20,6 +20,7 @@ import { Text } from '@tiptap/extension-text'
// other tiptap extensions
import { Image } from '@tiptap/extension-image'
import { Link } from '@tiptap/extension-link'
import Iframe from './tiptap-iframe'
export function parseTags(text: string) {
const regex = /(?:^|\s)(?:[#][a-z0-9_]+)/gi
@ -80,6 +81,7 @@ export const exhibitExts = [
Image,
Link,
Iframe,
]
// export const exhibitExts = [StarterKit as unknown as Extension, Image]

View File

@ -0,0 +1,92 @@
// Adopted from https://github.com/ueberdosis/tiptap/blob/main/demos/src/Experiments/Embeds/Vue/iframe.ts
import { Node } from '@tiptap/core'
export interface IframeOptions {
allowFullscreen: boolean
HTMLAttributes: {
[key: string]: any
}
}
declare module '@tiptap/core' {
interface Commands<ReturnType> {
iframe: {
setIframe: (options: { src: string }) => ReturnType
}
}
}
// These classes style the outer wrapper and the inner iframe;
// Adopted from css in https://github.com/ueberdosis/tiptap/blob/main/demos/src/Experiments/Embeds/Vue/index.vue
const wrapperClasses = 'relative h-auto w-full overflow-hidden'
const iframeClasses = 'absolute top-0 left-0 h-full w-full'
export default Node.create<IframeOptions>({
name: 'iframe',
group: 'block',
atom: true,
addOptions() {
return {
allowFullscreen: true,
HTMLAttributes: {
class: 'iframe-wrapper' + ' ' + wrapperClasses,
// Tailwind JIT doesn't seem to pick up `pb-[20rem]`, so we hack this in:
style: 'padding-bottom: 20rem;',
},
}
},
addAttributes() {
return {
src: {
default: null,
},
frameborder: {
default: 0,
},
allowfullscreen: {
default: this.options.allowFullscreen,
parseHTML: () => this.options.allowFullscreen,
},
}
},
parseHTML() {
return [{ tag: 'iframe' }]
},
renderHTML({ HTMLAttributes }) {
return [
'div',
this.options.HTMLAttributes,
[
'iframe',
{
...HTMLAttributes,
class: HTMLAttributes.class + ' ' + iframeClasses,
},
],
]
},
addCommands() {
return {
setIframe:
(options: { src: string }) =>
({ tr, dispatch }) => {
const { selection } = tr
const node = this.type.create(options)
if (dispatch) {
tr.replaceRangeWith(selection.from, selection.to, node)
}
return true
},
}
},
})

View File

@ -17,6 +17,7 @@ initAdmin()
const adminFirestore = admin.firestore()
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const addGroupIdToContracts = async () => {
const groups = await getValues<Group>(adminFirestore.collection('groups'))
const contracts = await getValues<Contract>(

View File

@ -39,11 +39,12 @@ const indexPrefix = ENV === 'DEV' ? 'dev-' : ''
const sortIndexes = [
{ label: 'Newest', value: indexPrefix + 'contracts-newest' },
{ label: 'Oldest', value: indexPrefix + 'contracts-oldest' },
// { label: 'Oldest', value: indexPrefix + 'contracts-oldest' },
{ label: 'Most popular', value: indexPrefix + 'contracts-score' },
{ label: 'Most traded', value: indexPrefix + 'contracts-most-traded' },
{ label: '24h volume', value: indexPrefix + 'contracts-24-hour-vol' },
{ label: 'Last updated', value: indexPrefix + 'contracts-last-updated' },
{ label: 'Subsidy', value: indexPrefix + 'contracts-liquidity' },
{ label: 'Close date', value: indexPrefix + 'contracts-close-date' },
{ label: 'Resolve date', value: indexPrefix + 'contracts-resolve-date' },
]

View File

@ -49,7 +49,7 @@ export function ContractLeaderboard(props: {
return users && users.length > 0 ? (
<Leaderboard
title="🏅 Top bettors"
title="🏅 Top traders"
users={users || []}
columns={[
{

View File

@ -19,6 +19,7 @@ import { useMutation } from 'react-query'
import { exhibitExts } from 'common/util/parse'
import { FileUploadButton } from './file-upload-button'
import { linkClass } from './site-link'
import Iframe from 'common/util/tiptap-iframe'
const proseClass = clsx(
'prose prose-p:my-0 prose-li:my-0 prose-blockquote:not-italic max-w-none prose-quoteless leading-relaxed',
@ -56,6 +57,7 @@ export function useTextEditor(props: {
class: clsx('no-underline !text-indigo-700', linkClass),
},
}),
Iframe,
],
content: defaultValue,
})
@ -69,12 +71,20 @@ export function useTextEditor(props: {
(file) => file.type.startsWith('image')
)
if (!imageFiles.length) {
return // if no files pasted, use default paste handler
if (imageFiles.length) {
event.preventDefault()
upload.mutate(imageFiles)
}
event.preventDefault()
upload.mutate(imageFiles)
// If the pasted content is iframe code, directly inject it
const text = event.clipboardData?.getData('text/plain').trim() ?? ''
const isValidIframe = /^<iframe.*<\/iframe>$/.test(text)
if (isValidIframe) {
editor.chain().insertContent(text).run()
return true // Prevent the code from getting pasted as text
}
return // Otherwise, use default paste handler
},
},
})

View File

@ -1,6 +1,9 @@
import { sortBy, sumBy, uniqBy } from 'lodash'
import clsx from 'clsx'
import React, { useEffect, useRef, useState } from 'react'
import Image from 'next/image'
import Confetti from 'react-confetti'
import { Col } from 'web/components/layout/col'
import { Row } from 'web/components/layout/row'
import { Page } from 'web/components/page'
@ -16,11 +19,11 @@ import { useRouter } from 'next/router'
import Custom404 from '../404'
import { useCharityTxns } from 'web/hooks/use-charity-txns'
import { useWindowSize } from 'web/hooks/use-window-size'
import Confetti from 'react-confetti'
import { Donation } from 'web/components/charity/feed-items'
import Image from 'next/image'
import { manaToUSD } from 'common/util/format'
import { manaToUSD } from 'common/util/format'>>>>>>> main
import { track } from 'web/lib/service/analytics'
import { SEO } from 'web/components/SEO'
export default function CharityPageWrapper() {
const router = useRouter()
@ -63,6 +66,11 @@ function CharityPage(props: { charity: Charity }) {
/>
}
>
<SEO
title={name}
description={description}
url="/groups"
/>
{showConfetti && (
<Confetti
width={width ? width : 500}

View File

@ -23,6 +23,7 @@ import { searchInAny } from 'common/util/parse'
import { getUser } from 'web/lib/firebase/users'
import { SiteLink } from 'web/components/site-link'
import { User } from 'common/user'
import { SEO } from 'web/components/SEO'
export async function getStaticProps() {
const txns = await getAllCharityTxns()
@ -114,6 +115,11 @@ export default function Charity(props: {
return (
<Page>
<SEO
title="Manifold for Charity"
description="Donate your prediction market earnings to charity on Manifold."
url="/charity"
/>
<Col className="w-full rounded px-4 py-6 sm:px-8 xl:w-[125%]">
<Col className="">
<Title className="!mt-0" text="Manifold for Charity" />
@ -128,6 +134,9 @@ export default function Charity(props: {
</SiteLink>
!
</span> */}
<span className="text-gray-600">
Convert your M$ earnings into real charitable donations.
</span>
<DonatedStats
stats={[
{

View File

@ -30,6 +30,7 @@ import { TextEditor, useTextEditor } from 'web/components/editor'
import { Checkbox } from 'web/components/checkbox'
import { redirectIfLoggedOut } from 'web/lib/firebase/server-auth'
import { Title } from 'web/components/title'
import { SEO } from 'web/components/SEO'
export const getServerSideProps = redirectIfLoggedOut('/')
@ -63,6 +64,11 @@ export default function Create() {
return (
<Page>
<SEO
title="Create a market"
description="Create a play-money prediction market on any question."
url="/create"
/>
<div className="mx-auto w-full max-w-2xl">
<div className="rounded-lg px-6 py-4 sm:py-0">
<Title className="!mt-0" text="Create a market" />

View File

@ -492,7 +492,7 @@ function GroupLeaderboards(props: {
<SortedLeaderboard
users={members}
scoreFunction={(user) => traderScores[user.id] ?? 0}
title="🏅 Top bettors"
title="🏅 Top traders"
header="Profit"
maxToShow={maxToShow}
/>
@ -508,7 +508,7 @@ function GroupLeaderboards(props: {
<>
<Leaderboard
className="max-w-xl"
title="🏅 Top bettors"
title="🏅 Top traders"
users={topTraders}
columns={[
{

View File

@ -18,6 +18,7 @@ import { Avatar } from 'web/components/avatar'
import { JoinOrLeaveGroupButton } from 'web/components/groups/groups-button'
import { UserLink } from 'web/components/user-page'
import { searchInAny } from 'common/util/parse'
import { SEO } from 'web/components/SEO'
export async function getStaticProps() {
const groups = await listAllGroups().catch((_) => [])
@ -100,6 +101,11 @@ export default function Groups(props: {
return (
<Page>
<SEO
title="Groups"
description="Manifold Groups are communities centered around a collection of prediction markets. Discuss and compete on questions with your friends."
url="/groups"
/>
<Col className="items-center">
<Col className="w-full max-w-2xl px-4 sm:px-2">
<Row className="items-center justify-between">

View File

@ -5,6 +5,7 @@ import { Col } from 'web/components/layout/col'
import { ManifoldLogo } from 'web/components/nav/manifold-logo'
import { redirectIfLoggedIn } from 'web/lib/firebase/server-auth'
import { useSaveReferral } from 'web/hooks/use-save-referral'
import { SEO } from 'web/components/SEO'
export const getServerSideProps = redirectIfLoggedIn('/home', async (_) => {
// These hardcoded markets will be shown in the frontpage for signed-out users:
@ -30,6 +31,11 @@ export default function Home(props: { hotContracts: Contract[] }) {
return (
<Page>
<SEO
title="Manifold Markets"
description="Create a play-money prediction market on any topic you care about
and bet with your friends on what will happen!"
/>
<div className="px-4 pt-2 md:mt-0 lg:hidden">
<ManifoldLogo />
</div>

View File

@ -13,6 +13,7 @@ import { useEffect, useState } from 'react'
import { Title } from 'web/components/title'
import { Tabs } from 'web/components/layout/tabs'
import { useTracking } from 'web/hooks/use-tracking'
import { SEO } from 'web/components/SEO'
export async function getStaticProps() {
const props = await fetchProps()
@ -78,7 +79,7 @@ export default function Leaderboards(_props: {
<>
<Col className="mx-4 items-center gap-10 lg:flex-row">
<Leaderboard
title="🏅 Top bettors"
title="🏅 Top traders"
users={topTraders}
columns={[
{
@ -123,6 +124,11 @@ export default function Leaderboards(_props: {
return (
<Page>
<SEO
title="Leaderboards"
description="Manifold's leaderboards show the top traders and market creators."
url="/leaderboards"
/>
<Title text={'Leaderboards'} className={'hidden md:block'} />
<Tabs
currentPageForAnalytics={'leaderboards'}

View File

@ -8,7 +8,7 @@ export default function Markets() {
<Page>
<SEO
title="Explore"
description="Discover what's new, trending, or soon-to-close. Or search among our hundreds of markets."
description="Discover what's new, trending, or soon-to-close. Or search thousands of prediction markets."
url="/markets"
/>
<ContractSearch />

View File

@ -391,7 +391,7 @@ function IncomeNotificationItem(props: {
reasonText = !simple
? `Bonus for ${
parseInt(sourceText) / UNIQUE_BETTOR_BONUS_AMOUNT
} unique bettors`
} unique traders`
: 'bonus on'
} else if (sourceType === 'tip') {
reasonText = !simple ? `tipped you` : `in tips on`

View File

@ -21,7 +21,12 @@ export default function ReferralsPage() {
return (
<Page>
<SEO title="Referrals" description="" url="/add-funds" />
<SEO
title="Referrals"
description={`Manifold's referral program. Invite new users to Manifold and get M${REFERRAL_AMOUNT} if they
sign up!`}
url="/referrals"
/>
<Col className="items-center">
<Col className="h-full rounded bg-white p-4 py-8 sm:p-8 sm:shadow-md">