Merge branch 'main' into cpmm
This commit is contained in:
commit
8df7b0fbe6
|
@ -1,14 +0,0 @@
|
|||
export function isWhitelisted(email?: string) {
|
||||
return true
|
||||
// e.g. return email.endsWith('@theoremone.co') || isAdmin(email)
|
||||
}
|
||||
|
||||
export function isAdmin(email: string) {
|
||||
const ADMINS = [
|
||||
'akrolsmir@gmail.com', // Austin
|
||||
'jahooma@gmail.com', // James
|
||||
'taowell@gmail.com', // Stephen
|
||||
'manticmarkets@gmail.com', // Manifold
|
||||
]
|
||||
return ADMINS.includes(email)
|
||||
}
|
|
@ -73,3 +73,7 @@ export type FreeResponse = {
|
|||
}
|
||||
|
||||
export type outcomeType = 'BINARY' | 'MULTI' | 'FREE_RESPONSE'
|
||||
|
||||
export const MAX_QUESTION_LENGTH = 480
|
||||
export const MAX_DESCRIPTION_LENGTH = 10000
|
||||
export const MAX_TAG_LENGTH = 60
|
||||
|
|
30
common/envs/constants.ts
Normal file
30
common/envs/constants.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
import { DEV_CONFIG } from './dev'
|
||||
import { EnvConfig, PROD_CONFIG } from './prod'
|
||||
import { THEOREMONE_CONFIG } from './theoremone'
|
||||
|
||||
const ENV = process.env.NEXT_PUBLIC_FIREBASE_ENV ?? 'PROD'
|
||||
|
||||
const CONFIGS = {
|
||||
PROD: PROD_CONFIG,
|
||||
DEV: DEV_CONFIG,
|
||||
THEOREMONE: THEOREMONE_CONFIG,
|
||||
}
|
||||
// @ts-ignore
|
||||
export const ENV_CONFIG: EnvConfig = CONFIGS[ENV]
|
||||
|
||||
export function isWhitelisted(email?: string) {
|
||||
if (!ENV_CONFIG.whitelistEmail) {
|
||||
return true
|
||||
}
|
||||
return email && (email.endsWith(ENV_CONFIG.whitelistEmail) || isAdmin(email))
|
||||
}
|
||||
|
||||
// TODO: Before open sourcing, we should turn these into env vars
|
||||
export function isAdmin(email: string) {
|
||||
return ENV_CONFIG.adminEmails.includes(email)
|
||||
}
|
||||
|
||||
export const DOMAIN = ENV_CONFIG.domain
|
||||
export const FIREBASE_CONFIG = ENV_CONFIG.firebaseConfig
|
||||
export const PROJECT_ID = ENV_CONFIG.firebaseConfig.projectId
|
||||
export const IS_PRIVATE_MANIFOLD = ENV_CONFIG.visibility === 'PRIVATE'
|
14
common/envs/dev.ts
Normal file
14
common/envs/dev.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { EnvConfig, PROD_CONFIG } from './prod'
|
||||
|
||||
export const DEV_CONFIG: EnvConfig = {
|
||||
...PROD_CONFIG,
|
||||
firebaseConfig: {
|
||||
apiKey: 'AIzaSyBoq3rzUa8Ekyo3ZaTnlycQYPRCA26VpOw',
|
||||
authDomain: 'dev-mantic-markets.firebaseapp.com',
|
||||
projectId: 'dev-mantic-markets',
|
||||
storageBucket: 'dev-mantic-markets.appspot.com',
|
||||
messagingSenderId: '134303100058',
|
||||
appId: '1:134303100058:web:27f9ea8b83347251f80323',
|
||||
measurementId: 'G-YJC9E37P37',
|
||||
},
|
||||
}
|
55
common/envs/prod.ts
Normal file
55
common/envs/prod.ts
Normal file
|
@ -0,0 +1,55 @@
|
|||
export type EnvConfig = {
|
||||
domain: string
|
||||
firebaseConfig: FirebaseConfig
|
||||
|
||||
// Access controls
|
||||
adminEmails: string[]
|
||||
whitelistEmail?: string // e.g. '@theoremone.co'. If not provided, all emails are whitelisted
|
||||
visibility: 'PRIVATE' | 'PUBLIC'
|
||||
|
||||
// Branding
|
||||
moneyMoniker: string // e.g. 'M$'
|
||||
faviconPath?: string // Should be a file in /public
|
||||
navbarLogoPath?: string
|
||||
newQuestionPlaceholders: string[]
|
||||
}
|
||||
|
||||
type FirebaseConfig = {
|
||||
apiKey: string
|
||||
authDomain: string
|
||||
projectId: string
|
||||
storageBucket: string
|
||||
messagingSenderId: string
|
||||
appId: string
|
||||
measurementId: string
|
||||
}
|
||||
|
||||
export const PROD_CONFIG: EnvConfig = {
|
||||
domain: 'manifold.markets',
|
||||
firebaseConfig: {
|
||||
apiKey: 'AIzaSyDp3J57vLeAZCzxLD-vcPaGIkAmBoGOSYw',
|
||||
authDomain: 'mantic-markets.firebaseapp.com',
|
||||
projectId: 'mantic-markets',
|
||||
storageBucket: 'mantic-markets.appspot.com',
|
||||
messagingSenderId: '128925704902',
|
||||
appId: '1:128925704902:web:f61f86944d8ffa2a642dc7',
|
||||
measurementId: 'G-SSFK1Q138D',
|
||||
},
|
||||
adminEmails: [
|
||||
'akrolsmir@gmail.com', // Austin
|
||||
'jahooma@gmail.com', // James
|
||||
'taowell@gmail.com', // Stephen
|
||||
'manticmarkets@gmail.com', // Manifold
|
||||
],
|
||||
visibility: 'PUBLIC',
|
||||
|
||||
moneyMoniker: 'M$',
|
||||
navbarLogoPath: '',
|
||||
faviconPath: '/favicon.ico',
|
||||
newQuestionPlaceholders: [
|
||||
'Will anyone I know get engaged this year?',
|
||||
'Will humans set foot on Mars by the end of 2030?',
|
||||
'Will any cryptocurrency eclipse Bitcoin by market cap this year?',
|
||||
'Will the Democrats win the 2024 presidential election?',
|
||||
],
|
||||
}
|
26
common/envs/theoremone.ts
Normal file
26
common/envs/theoremone.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import { EnvConfig, PROD_CONFIG } from './prod'
|
||||
|
||||
export const THEOREMONE_CONFIG: EnvConfig = {
|
||||
domain: 'theoremone.manifold.markets',
|
||||
firebaseConfig: {
|
||||
apiKey: 'AIzaSyBSXL6Ys7InNHnCKSy-_E_luhh4Fkj4Z6M',
|
||||
authDomain: 'theoremone-manifold.firebaseapp.com',
|
||||
projectId: 'theoremone-manifold',
|
||||
storageBucket: 'theoremone-manifold.appspot.com',
|
||||
messagingSenderId: '698012149198',
|
||||
appId: '1:698012149198:web:b342af75662831aa84b79f',
|
||||
measurementId: 'G-Y3EZ1WNT6E',
|
||||
},
|
||||
adminEmails: [...PROD_CONFIG.adminEmails, 'david.glidden@theoremone.co'],
|
||||
whitelistEmail: '@theoremone.co',
|
||||
moneyMoniker: 'T$',
|
||||
visibility: 'PRIVATE',
|
||||
faviconPath: '/theoremone/logo.ico',
|
||||
navbarLogoPath: '/theoremone/TheoremOne-Logo.svg',
|
||||
newQuestionPlaceholders: [
|
||||
'Will we have at least 5 new team members by the end of this quarter?',
|
||||
'Will we meet or exceed our goals this sprint?',
|
||||
'Will we sign on 3 or more new clients this month?',
|
||||
'Will Paul shave his beard by the end of the month?',
|
||||
],
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
import { ENV_CONFIG } from '../envs/constants'
|
||||
|
||||
const formatter = new Intl.NumberFormat('en-US', {
|
||||
style: 'currency',
|
||||
currency: 'USD',
|
||||
|
@ -7,7 +9,9 @@ const formatter = new Intl.NumberFormat('en-US', {
|
|||
|
||||
export function formatMoney(amount: number) {
|
||||
const newAmount = Math.round(amount) === 0 ? 0 : amount // handle -0 case
|
||||
return 'M$ ' + formatter.format(newAmount).replace('$', '')
|
||||
return (
|
||||
ENV_CONFIG.moneyMoniker + ' ' + formatter.format(newAmount).replace('$', '')
|
||||
)
|
||||
}
|
||||
|
||||
export function formatWithCommas(amount: number) {
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import { MAX_TAG_LENGTH } from '../contract'
|
||||
|
||||
export function parseTags(text: string) {
|
||||
const regex = /(?:^|\s)(?:[#][a-z0-9_]+)/gi
|
||||
const matches = (text.match(regex) || []).map((match) =>
|
||||
match.trim().substring(1)
|
||||
match.trim().substring(1).substring(0, MAX_TAG_LENGTH)
|
||||
)
|
||||
const tagSet = new Set()
|
||||
const uniqueTags: string[] = []
|
||||
|
|
|
@ -242,6 +242,10 @@
|
|||
"arrayConfig": "CONTAINS",
|
||||
"queryScope": "COLLECTION"
|
||||
},
|
||||
{
|
||||
"order": "ASCENDING",
|
||||
"queryScope": "COLLECTION_GROUP"
|
||||
},
|
||||
{
|
||||
"order": "DESCENDING",
|
||||
"queryScope": "COLLECTION_GROUP"
|
||||
|
|
|
@ -44,6 +44,8 @@ export const backupDb = functions.pubsub
|
|||
'users',
|
||||
'bets',
|
||||
'comments',
|
||||
'followers',
|
||||
'answers',
|
||||
],
|
||||
})
|
||||
.then((responses) => {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import * as functions from 'firebase-functions'
|
||||
import * as admin from 'firebase-admin'
|
||||
import * as _ from 'lodash'
|
||||
|
||||
import { chargeUser, getUser } from './utils'
|
||||
import {
|
||||
|
@ -9,6 +10,9 @@ import {
|
|||
DPM,
|
||||
FreeResponse,
|
||||
FullContract,
|
||||
MAX_DESCRIPTION_LENGTH,
|
||||
MAX_QUESTION_LENGTH,
|
||||
MAX_TAG_LENGTH,
|
||||
outcomeType,
|
||||
} from '../../common/contract'
|
||||
import { slugify } from '../../common/util/slugify'
|
||||
|
@ -44,10 +48,19 @@ export const createContract = functions
|
|||
const creator = await getUser(userId)
|
||||
if (!creator) return { status: 'error', message: 'User not found' }
|
||||
|
||||
const { question, description, initialProb, ante, closeTime, tags } = data
|
||||
let { question, description, initialProb, ante, closeTime, tags } = data
|
||||
|
||||
if (!question)
|
||||
return { status: 'error', message: 'Missing question field' }
|
||||
if (!question || typeof question != 'string')
|
||||
return { status: 'error', message: 'Missing or invalid question field' }
|
||||
question = question.slice(0, MAX_QUESTION_LENGTH)
|
||||
|
||||
if (typeof description !== 'string')
|
||||
return { status: 'error', message: 'Invalid description field' }
|
||||
description = description.slice(0, MAX_DESCRIPTION_LENGTH)
|
||||
|
||||
if (tags !== undefined && !_.isArray(tags))
|
||||
return { status: 'error', message: 'Invalid tags field' }
|
||||
tags = tags?.map((tag) => tag.toString().slice(0, MAX_TAG_LENGTH))
|
||||
|
||||
let outcomeType = data.outcomeType ?? 'BINARY'
|
||||
if (!['BINARY', 'MULTI', 'FREE_RESPONSE'].includes(outcomeType))
|
||||
|
|
|
@ -14,7 +14,7 @@ import {
|
|||
cleanUsername,
|
||||
} from '../../common/util/clean-username'
|
||||
import { sendWelcomeEmail } from './emails'
|
||||
import { isWhitelisted } from '../../common/access'
|
||||
import { isWhitelisted } from '../../common/envs/constants'
|
||||
|
||||
export const createUser = functions
|
||||
.runWith({ minInstances: 1 })
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import * as _ from 'lodash'
|
||||
|
||||
import { DOMAIN, PROJECT_ID } from '../../common/envs/constants'
|
||||
import { Answer } from '../../common/answer'
|
||||
import { Bet } from '../../common/bet'
|
||||
import { getProbability } from '../../common/calculate'
|
||||
|
@ -9,7 +10,7 @@ import { CREATOR_FEE } from '../../common/fees'
|
|||
import { PrivateUser, User } from '../../common/user'
|
||||
import { formatMoney, formatPercent } from '../../common/util/format'
|
||||
import { sendTemplateEmail, sendTextEmail } from './send-email'
|
||||
import { getPrivateUser, getUser, isProd } from './utils'
|
||||
import { getPrivateUser, getUser } from './utils'
|
||||
|
||||
export const sendMarketResolutionEmail = async (
|
||||
userId: string,
|
||||
|
@ -49,7 +50,7 @@ export const sendMarketResolutionEmail = async (
|
|||
outcome,
|
||||
investment: `${Math.round(investment)}`,
|
||||
payout: `${Math.round(payout)}`,
|
||||
url: `https://manifold.markets/${creator.username}/${contract.slug}`,
|
||||
url: `https://${DOMAIN}/${creator.username}/${contract.slug}`,
|
||||
}
|
||||
|
||||
// Modify template here:
|
||||
|
@ -118,7 +119,7 @@ Or come chat with us on Discord: https://discord.gg/eHQBNBqXuh
|
|||
|
||||
Best,
|
||||
Austin from Manifold
|
||||
https://manifold.markets/`
|
||||
https://${DOMAIN}/`
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -139,7 +140,7 @@ export const sendMarketCloseEmail = async (
|
|||
|
||||
const { question, pool: pools, slug } = contract
|
||||
const pool = formatMoney(_.sum(_.values(pools)))
|
||||
const url = `https://manifold.markets/${username}/${slug}`
|
||||
const url = `https://${DOMAIN}/${username}/${slug}`
|
||||
|
||||
await sendTemplateEmail(
|
||||
privateUser.email,
|
||||
|
@ -173,11 +174,9 @@ export const sendNewCommentEmail = async (
|
|||
return
|
||||
|
||||
const { question, creatorUsername, slug } = contract
|
||||
const marketUrl = `https://manifold.markets/${creatorUsername}/${slug}`
|
||||
const marketUrl = `https://${DOMAIN}/${creatorUsername}/${slug}`
|
||||
|
||||
const unsubscribeUrl = `https://us-central1-${
|
||||
isProd ? 'mantic-markets' : 'dev-mantic-markets'
|
||||
}.cloudfunctions.net/unsubscribe?id=${userId}&type=market-comment`
|
||||
const unsubscribeUrl = `https://us-central1-${PROJECT_ID}.cloudfunctions.net/unsubscribe?id=${userId}&type=market-comment`
|
||||
|
||||
const { name: commentorName, avatarUrl: commentorAvatarUrl } = commentCreator
|
||||
const { text } = comment
|
||||
|
@ -252,10 +251,8 @@ export const sendNewAnswerEmail = async (
|
|||
const { question, creatorUsername, slug } = contract
|
||||
const { name, avatarUrl, text } = answer
|
||||
|
||||
const marketUrl = `https://manifold.markets/${creatorUsername}/${slug}`
|
||||
const unsubscribeUrl = `https://us-central1-${
|
||||
isProd ? 'mantic-markets' : 'dev-mantic-markets'
|
||||
}.cloudfunctions.net/unsubscribe?id=${userId}&type=market-answer`
|
||||
const marketUrl = `https://${DOMAIN}/${creatorUsername}/${slug}`
|
||||
const unsubscribeUrl = `https://us-central1-${PROJECT_ID}.cloudfunctions.net/unsubscribe?id=${userId}&type=market-answer`
|
||||
|
||||
const subject = `New answer on ${question}`
|
||||
const from = `${name} <info@manifold.markets>`
|
||||
|
|
105
functions/src/scripts/pay-out-contract-again.ts
Normal file
105
functions/src/scripts/pay-out-contract-again.ts
Normal file
|
@ -0,0 +1,105 @@
|
|||
import * as admin from 'firebase-admin'
|
||||
import * as _ from 'lodash'
|
||||
|
||||
import { initAdmin } from './script-init'
|
||||
initAdmin('james')
|
||||
|
||||
import { Bet } from '../../../common/bet'
|
||||
import { Contract } from '../../../common/contract'
|
||||
import {
|
||||
getLoanPayouts,
|
||||
getPayouts,
|
||||
getPayoutsMultiOutcome,
|
||||
} from '../../../common/payouts'
|
||||
import { filterDefined } from '../../../common/util/array'
|
||||
import { payUser } from '../utils'
|
||||
|
||||
type DocRef = admin.firestore.DocumentReference
|
||||
|
||||
const firestore = admin.firestore()
|
||||
|
||||
async function checkIfPayOutAgain(contractRef: DocRef, contract: Contract) {
|
||||
const bets = await contractRef
|
||||
.collection('bets')
|
||||
.get()
|
||||
.then((snap) => snap.docs.map((bet) => bet.data() as Bet))
|
||||
|
||||
const openBets = bets.filter((b) => !b.isSold && !b.sale)
|
||||
const loanedBets = openBets.filter((bet) => bet.loanAmount)
|
||||
|
||||
if (loanedBets.length && contract.resolution) {
|
||||
const { resolution, outcomeType, resolutions, resolutionProbability } =
|
||||
contract
|
||||
const payouts =
|
||||
outcomeType === 'FREE_RESPONSE' && resolutions
|
||||
? getPayoutsMultiOutcome(resolutions, contract, openBets)
|
||||
: getPayouts(resolution, contract, openBets, resolutionProbability)
|
||||
|
||||
const loanPayouts = getLoanPayouts(openBets)
|
||||
const groups = _.groupBy(
|
||||
[...payouts, ...loanPayouts],
|
||||
(payout) => payout.userId
|
||||
)
|
||||
const userPayouts = _.mapValues(groups, (group) =>
|
||||
_.sumBy(group, (g) => g.payout)
|
||||
)
|
||||
|
||||
const entries = Object.entries(userPayouts)
|
||||
const firstNegative = entries.findIndex(([_, payout]) => payout < 0)
|
||||
const toBePaidOut = firstNegative === -1 ? [] : entries.slice(firstNegative)
|
||||
|
||||
if (toBePaidOut.length) {
|
||||
console.log(
|
||||
'to be paid out',
|
||||
toBePaidOut.length,
|
||||
'already paid out',
|
||||
entries.length - toBePaidOut.length
|
||||
)
|
||||
const positivePayouts = toBePaidOut.filter(([_, payout]) => payout > 0)
|
||||
if (positivePayouts.length)
|
||||
return { contract, toBePaidOut: positivePayouts }
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
async function payOutContractAgain() {
|
||||
console.log('Recalculating contract info')
|
||||
|
||||
const snapshot = await firestore.collection('contracts').get()
|
||||
|
||||
const [startTime, endTime] = [
|
||||
new Date('2022-03-02'),
|
||||
new Date('2022-03-07'),
|
||||
].map((date) => date.getTime())
|
||||
|
||||
const contracts = snapshot.docs
|
||||
.map((doc) => doc.data() as Contract)
|
||||
.filter((contract) => {
|
||||
const { resolutionTime } = contract
|
||||
return (
|
||||
resolutionTime && resolutionTime > startTime && resolutionTime < endTime
|
||||
)
|
||||
})
|
||||
|
||||
console.log('Loaded', contracts.length, 'contracts')
|
||||
|
||||
const toPayOutAgain = filterDefined(
|
||||
await Promise.all(
|
||||
contracts.map(async (contract) => {
|
||||
const contractRef = firestore.doc(`contracts/${contract.id}`)
|
||||
|
||||
return await checkIfPayOutAgain(contractRef, contract)
|
||||
})
|
||||
)
|
||||
)
|
||||
|
||||
const flattened = _.flatten(toPayOutAgain.map((d) => d.toBePaidOut))
|
||||
|
||||
for (const [userId, payout] of flattened) {
|
||||
console.log('Paying out', userId, payout)
|
||||
// await payUser(userId, payout)
|
||||
}
|
||||
}
|
||||
|
||||
if (require.main === module) payOutContractAgain().then(() => process.exit())
|
|
@ -7,8 +7,18 @@ import { PrivateUser } from '../../common/user'
|
|||
export const unsubscribe = functions
|
||||
.runWith({ minInstances: 1 })
|
||||
.https.onRequest(async (req, res) => {
|
||||
const { id, type } = req.query as { id: string; type: string }
|
||||
if (!id || !type) return
|
||||
let { id, type } = req.query as { id: string; type: string }
|
||||
if (!id || !type) {
|
||||
res.status(400).send('Empty id or type parameter.')
|
||||
return
|
||||
}
|
||||
|
||||
if (type === 'market-resolved') type = 'market-resolve'
|
||||
|
||||
if (!['market-resolve', 'market-comment', 'market-answer'].includes(type)) {
|
||||
res.status(400).send('Invalid type parameter.')
|
||||
return
|
||||
}
|
||||
|
||||
const user = await getUser(id)
|
||||
|
||||
|
|
|
@ -4,5 +4,6 @@ module.exports = {
|
|||
rules: {
|
||||
// Add or disable rules here.
|
||||
'@next/next/no-img-element': 'off',
|
||||
'@next/next/no-typos': 'off',
|
||||
},
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// From https://tailwindui.com/components/application-ui/lists/feeds
|
||||
import { Fragment, useState } from 'react'
|
||||
import _ from 'lodash'
|
||||
import * as _ from 'lodash'
|
||||
import {
|
||||
BanIcon,
|
||||
CheckIcon,
|
||||
|
@ -43,7 +43,11 @@ import { parseTags } from '../../common/util/parse'
|
|||
import { Avatar } from './avatar'
|
||||
import { useAdmin } from '../hooks/use-admin'
|
||||
import { FreeResponse, FullContract } from '../../common/contract'
|
||||
import { getCpmmLiquidity } from '../../common/calculate-cpmm'
|
||||
import { Answer } from '../../common/answer'
|
||||
|
||||
const canAddComment = (createdTime: number, isSelf: boolean) => {
|
||||
return isSelf && Date.now() - createdTime < 60 * 60 * 1000
|
||||
}
|
||||
|
||||
function FeedComment(props: {
|
||||
activityItem: any
|
||||
|
@ -95,11 +99,13 @@ function Timestamp(props: { time: number }) {
|
|||
|
||||
function FeedBet(props: { activityItem: any; feedType: FeedType }) {
|
||||
const { activityItem, feedType } = props
|
||||
const { id, contractId, amount, outcome, createdTime } = activityItem
|
||||
const { id, contractId, amount, outcome, createdTime, contract } =
|
||||
activityItem
|
||||
const user = useUser()
|
||||
const isSelf = user?.id == activityItem.userId
|
||||
// The creator can comment if the bet was posted in the last hour
|
||||
const canComment = isSelf && Date.now() - createdTime < 60 * 60 * 1000
|
||||
const isCreator = contract.creatorId == activityItem.userId
|
||||
// You can comment if your bet was posted in the last hour
|
||||
const canComment = canAddComment(createdTime, isSelf)
|
||||
|
||||
const [comment, setComment] = useState('')
|
||||
async function submitComment() {
|
||||
|
@ -110,11 +116,19 @@ function FeedBet(props: { activityItem: any; feedType: FeedType }) {
|
|||
const bought = amount >= 0 ? 'bought' : 'sold'
|
||||
const money = formatMoney(Math.abs(amount))
|
||||
|
||||
const answer =
|
||||
feedType !== 'multi' &&
|
||||
(contract.answers?.find((answer: Answer) => answer?.id === outcome) as
|
||||
| Answer
|
||||
| undefined)
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
{isSelf ? (
|
||||
<Avatar avatarUrl={user?.avatarUrl} />
|
||||
) : isCreator ? (
|
||||
<Avatar avatarUrl={contract.creatorAvatarUrl} />
|
||||
) : (
|
||||
<div className="relative px-1">
|
||||
<div className="flex h-8 w-8 items-center justify-center rounded-full bg-gray-200">
|
||||
|
@ -123,10 +137,20 @@ function FeedBet(props: { activityItem: any; feedType: FeedType }) {
|
|||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="min-w-0 flex-1 py-1.5">
|
||||
<div className={clsx('min-w-0 flex-1 pb-1.5', !answer && 'pt-1.5')}>
|
||||
{answer && (
|
||||
<div className="text-neutral mb-2" style={{ fontSize: 15 }}>
|
||||
{answer.text}
|
||||
</div>
|
||||
)}
|
||||
<div className="text-sm text-gray-500">
|
||||
<span>{isSelf ? 'You' : 'A trader'}</span> {bought} {money}
|
||||
<MaybeOutcomeLabel outcome={outcome} feedType={feedType} />
|
||||
<span>
|
||||
{isSelf ? 'You' : isCreator ? contract.creatorName : 'A trader'}
|
||||
</span>{' '}
|
||||
{bought} {money}
|
||||
{!answer && (
|
||||
<MaybeOutcomeLabel outcome={outcome} feedType={feedType} />
|
||||
)}
|
||||
<Timestamp time={createdTime} />
|
||||
{canComment && (
|
||||
// Allow user to comment in an textarea if they are the creator
|
||||
|
@ -356,9 +380,9 @@ function FeedQuestion(props: {
|
|||
{!showDescription && (
|
||||
<SiteLink
|
||||
href={contractPath(contract)}
|
||||
className="self-end sm:self-start text-sm relative top-4"
|
||||
className="relative top-4 self-end text-sm sm:self-start"
|
||||
>
|
||||
<div className="text-gray-500 pb-1.5">See more...</div>
|
||||
<div className="pb-1.5 text-gray-500">See more...</div>
|
||||
</SiteLink>
|
||||
)}
|
||||
</Col>
|
||||
|
@ -499,7 +523,7 @@ function FeedClose(props: { contract: Contract }) {
|
|||
)
|
||||
}
|
||||
|
||||
function toFeedBet(bet: Bet) {
|
||||
function toFeedBet(bet: Bet, contract: Contract) {
|
||||
return {
|
||||
id: bet.id,
|
||||
contractId: bet.contractId,
|
||||
|
@ -509,6 +533,7 @@ function toFeedBet(bet: Bet) {
|
|||
outcome: bet.outcome,
|
||||
createdTime: bet.createdTime,
|
||||
date: fromNow(bet.createdTime),
|
||||
contract,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -538,12 +563,13 @@ const DAY_IN_MS = 24 * 60 * 60 * 1000
|
|||
// Group together bets that are:
|
||||
// - Within `windowMs` of the first in the group
|
||||
// - Do not have a comment
|
||||
// - Were not created by this user
|
||||
// - Were not created by this user or the contract creator
|
||||
// Return a list of ActivityItems
|
||||
function groupBets(
|
||||
bets: Bet[],
|
||||
comments: Comment[],
|
||||
windowMs: number,
|
||||
contract: Contract,
|
||||
userId?: string
|
||||
) {
|
||||
const commentsMap = mapCommentsByBetId(comments)
|
||||
|
@ -553,25 +579,25 @@ function groupBets(
|
|||
// Turn the current group into an ActivityItem
|
||||
function pushGroup() {
|
||||
if (group.length == 1) {
|
||||
items.push(toActivityItem(group[0]))
|
||||
items.push(toActivityItem(group[0], false))
|
||||
} else if (group.length > 1) {
|
||||
items.push({ type: 'betgroup', bets: [...group], id: group[0].id })
|
||||
}
|
||||
group = []
|
||||
}
|
||||
|
||||
function toActivityItem(bet: Bet) {
|
||||
function toActivityItem(bet: Bet, isPublic: boolean) {
|
||||
const comment = commentsMap[bet.id]
|
||||
return comment ? toFeedComment(bet, comment) : toFeedBet(bet)
|
||||
return comment ? toFeedComment(bet, comment) : toFeedBet(bet, contract)
|
||||
}
|
||||
|
||||
for (const bet of bets) {
|
||||
const isCreator = userId === bet.userId
|
||||
const isCreator = userId === bet.userId || contract.creatorId === bet.userId
|
||||
|
||||
if (commentsMap[bet.id] || isCreator) {
|
||||
pushGroup()
|
||||
// Create a single item for this
|
||||
items.push(toActivityItem(bet))
|
||||
items.push(toActivityItem(bet, true))
|
||||
} else {
|
||||
if (
|
||||
group.length > 0 &&
|
||||
|
@ -791,6 +817,8 @@ export function ContractFeed(props: {
|
|||
const [expanded, setExpanded] = useState(false)
|
||||
const user = useUser()
|
||||
|
||||
const comments = useComments(id) ?? props.comments
|
||||
|
||||
let bets = useBets(contract.id) ?? props.bets
|
||||
bets = isBinary
|
||||
? bets.filter((bet) => !bet.isAnte)
|
||||
|
@ -798,15 +826,21 @@ export function ContractFeed(props: {
|
|||
|
||||
if (feedType === 'multi') {
|
||||
bets = bets.filter((bet) => bet.outcome === outcome)
|
||||
} else if (outcomeType === 'FREE_RESPONSE') {
|
||||
// Keep bets on comments or your bets where you can comment.
|
||||
const commentBetIds = new Set(comments.map((comment) => comment.betId))
|
||||
bets = bets.filter(
|
||||
(bet) =>
|
||||
commentBetIds.has(bet.id) ||
|
||||
canAddComment(bet.createdTime, user?.id === bet.userId)
|
||||
)
|
||||
}
|
||||
|
||||
const comments = useComments(id) ?? props.comments
|
||||
|
||||
const groupWindow = feedType == 'activity' ? 10 * DAY_IN_MS : DAY_IN_MS
|
||||
|
||||
const allItems: ActivityItem[] = [
|
||||
{ type: 'start', id: '0' },
|
||||
...groupBets(bets, comments, groupWindow, user?.id),
|
||||
...groupBets(bets, comments, groupWindow, contract, user?.id),
|
||||
]
|
||||
if (contract.closeTime && contract.closeTime <= Date.now()) {
|
||||
allItems.push({ type: 'close', id: `${contract.closeTime}` })
|
||||
|
@ -847,16 +881,27 @@ export function ContractActivityFeed(props: {
|
|||
comments: Comment[]
|
||||
betRowClassName?: string
|
||||
}) {
|
||||
const { contract, betRowClassName, bets, comments } = props
|
||||
const { contract, betRowClassName, comments } = props
|
||||
|
||||
const user = useUser()
|
||||
|
||||
bets.sort((b1, b2) => b1.createdTime - b2.createdTime)
|
||||
let bets = props.bets.sort((b1, b2) => b1.createdTime - b2.createdTime)
|
||||
comments.sort((c1, c2) => c1.createdTime - c2.createdTime)
|
||||
|
||||
if (contract.outcomeType === 'FREE_RESPONSE') {
|
||||
// Keep bets on comments, and the last non-comment bet.
|
||||
const commentBetIds = new Set(comments.map((comment) => comment.betId))
|
||||
const [commentBets, nonCommentBets] = _.partition(bets, (bet) =>
|
||||
commentBetIds.has(bet.id)
|
||||
)
|
||||
bets = [...commentBets, ...nonCommentBets.slice(-1)].sort(
|
||||
(b1, b2) => b1.createdTime - b2.createdTime
|
||||
)
|
||||
}
|
||||
|
||||
const allItems: ActivityItem[] = [
|
||||
{ type: 'start', id: '0' },
|
||||
...groupBets(bets, comments, DAY_IN_MS, user?.id),
|
||||
...groupBets(bets, comments, DAY_IN_MS, contract, user?.id),
|
||||
]
|
||||
if (contract.closeTime && contract.closeTime <= Date.now()) {
|
||||
allItems.push({ type: 'close', id: `${contract.closeTime}` })
|
||||
|
|
|
@ -5,10 +5,11 @@ import { Spacer } from './layout/spacer'
|
|||
import { NewContract } from '../pages/create'
|
||||
import { firebaseLogin, User } from '../lib/firebase/users'
|
||||
import { ContractsGrid } from './contracts-list'
|
||||
import { Contract } from '../../common/contract'
|
||||
import { Contract, MAX_QUESTION_LENGTH } from '../../common/contract'
|
||||
import { Col } from './layout/col'
|
||||
import clsx from 'clsx'
|
||||
import { Row } from './layout/row'
|
||||
import { ENV_CONFIG } from '../../common/envs/constants'
|
||||
|
||||
export function FeedPromo(props: { hotContracts: Contract[] }) {
|
||||
const { hotContracts } = props
|
||||
|
@ -72,16 +73,10 @@ export default function FeedCreate(props: {
|
|||
const [isExpanded, setIsExpanded] = useState(false)
|
||||
const inputRef = useRef<HTMLTextAreaElement | null>()
|
||||
|
||||
const placeholders = [
|
||||
'Will anyone I know get engaged this year?',
|
||||
'Will humans set foot on Mars by the end of 2030?',
|
||||
'Will any cryptocurrency eclipse Bitcoin by market cap this year?',
|
||||
'Will the Democrats win the 2024 presidential election?',
|
||||
]
|
||||
const placeholders = ENV_CONFIG.newQuestionPlaceholders
|
||||
// Rotate through a new placeholder each day
|
||||
// Easter egg idea: click your own name to shuffle the placeholder
|
||||
// const daysSinceEpoch = Math.floor(Date.now() / 1000 / 60 / 60 / 24)
|
||||
|
||||
const [randIndex] = useState(
|
||||
Math.floor(Math.random() * 1e10) % placeholders.length
|
||||
)
|
||||
|
@ -90,7 +85,7 @@ export default function FeedCreate(props: {
|
|||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
'mt-2 w-full rounded bg-white p-4 shadow-md cursor-text',
|
||||
'mt-2 w-full cursor-text rounded bg-white p-4 shadow-md',
|
||||
isExpanded ? 'ring-2 ring-indigo-300' : '',
|
||||
className
|
||||
)}
|
||||
|
@ -126,6 +121,7 @@ export default function FeedCreate(props: {
|
|||
placeholder={placeholder}
|
||||
value={question}
|
||||
rows={question.length > 68 ? 4 : 2}
|
||||
maxLength={MAX_QUESTION_LENGTH}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onChange={(e) => setQuestion(e.target.value.replace('\n', ''))}
|
||||
onFocus={() => setIsExpanded(true)}
|
||||
|
|
|
@ -2,6 +2,7 @@ import Link from 'next/link'
|
|||
import clsx from 'clsx'
|
||||
|
||||
import { useUser } from '../hooks/use-user'
|
||||
import { ENV_CONFIG } from '../../common/envs/constants'
|
||||
|
||||
export function ManifoldLogo(props: {
|
||||
className?: string
|
||||
|
@ -20,24 +21,30 @@ export function ManifoldLogo(props: {
|
|||
width={45}
|
||||
height={45}
|
||||
/>
|
||||
<div
|
||||
className={clsx(
|
||||
'font-major-mono mt-1 text-lg lowercase sm:hidden',
|
||||
darkBackground && 'text-white'
|
||||
)}
|
||||
>
|
||||
Manifold
|
||||
<br />
|
||||
Markets
|
||||
</div>
|
||||
<div
|
||||
className={clsx(
|
||||
'font-major-mono mt-1 hidden lowercase sm:flex sm:text-2xl md:whitespace-nowrap',
|
||||
darkBackground && 'text-white'
|
||||
)}
|
||||
>
|
||||
Manifold Markets
|
||||
</div>
|
||||
{ENV_CONFIG.navbarLogoPath ? (
|
||||
<img src={ENV_CONFIG.navbarLogoPath} width={245} height={45} />
|
||||
) : (
|
||||
<>
|
||||
<div
|
||||
className={clsx(
|
||||
'font-major-mono mt-1 text-lg lowercase sm:hidden',
|
||||
darkBackground && 'text-white'
|
||||
)}
|
||||
>
|
||||
Manifold
|
||||
<br />
|
||||
Markets
|
||||
</div>
|
||||
<div
|
||||
className={clsx(
|
||||
'font-major-mono mt-1 hidden lowercase sm:flex sm:text-2xl md:whitespace-nowrap',
|
||||
darkBackground && 'text-white'
|
||||
)}
|
||||
>
|
||||
Manifold Markets
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</a>
|
||||
</Link>
|
||||
)
|
||||
|
|
|
@ -3,6 +3,7 @@ import { formatMoney } from '../../common/util/format'
|
|||
import { Avatar } from './avatar'
|
||||
import { Col } from './layout/col'
|
||||
import { MenuButton } from './menu'
|
||||
import { IS_PRIVATE_MANIFOLD } from '../../common/envs/constants'
|
||||
|
||||
export function ProfileMenu(props: { user: User | undefined }) {
|
||||
const { user } = props
|
||||
|
@ -54,22 +55,32 @@ function getNavigationOptions(
|
|||
name: 'Your trades',
|
||||
href: '/trades',
|
||||
},
|
||||
{
|
||||
name: 'Add funds',
|
||||
href: '/add-funds',
|
||||
},
|
||||
{
|
||||
name: 'Leaderboards',
|
||||
href: '/leaderboards',
|
||||
},
|
||||
{
|
||||
name: 'Discord',
|
||||
href: 'https://discord.gg/eHQBNBqXuh',
|
||||
},
|
||||
{
|
||||
name: 'About',
|
||||
href: '/about',
|
||||
},
|
||||
// Disable irrelevant menu options for teams.
|
||||
...(IS_PRIVATE_MANIFOLD
|
||||
? [
|
||||
{
|
||||
name: 'Leaderboards',
|
||||
href: '/leaderboards',
|
||||
},
|
||||
]
|
||||
: [
|
||||
{
|
||||
name: 'Add funds',
|
||||
href: '/add-funds',
|
||||
},
|
||||
{
|
||||
name: 'Leaderboards',
|
||||
href: '/leaderboards',
|
||||
},
|
||||
{
|
||||
name: 'Discord',
|
||||
href: 'https://discord.gg/eHQBNBqXuh',
|
||||
},
|
||||
{
|
||||
name: 'About',
|
||||
href: '/about',
|
||||
},
|
||||
]),
|
||||
{
|
||||
name: 'Sign out',
|
||||
href: '#',
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { isAdmin } from '../../common/access'
|
||||
import { isAdmin } from '../../common/envs/constants'
|
||||
import { usePrivateUser, useUser } from './use-user'
|
||||
|
||||
export const useAdmin = () => {
|
||||
|
|
|
@ -29,7 +29,7 @@ export const useContractWithPreload = (
|
|||
useEffect(() => {
|
||||
if (contractId) return listenForContract(contractId, setContract)
|
||||
|
||||
if (contractId !== null)
|
||||
if (contractId !== null && slug)
|
||||
getContractFromSlug(slug).then((c) => setContractId(c?.id || null))
|
||||
}, [contractId, slug])
|
||||
|
||||
|
|
|
@ -25,6 +25,22 @@ export const getAllContractInfo = async () => {
|
|||
return { contracts, recentComments, folds }
|
||||
}
|
||||
|
||||
const defaultSkippedTags = [
|
||||
'meta',
|
||||
'test',
|
||||
'trolling',
|
||||
'spam',
|
||||
'transaction',
|
||||
'personal',
|
||||
]
|
||||
const includedWithDefaultFeed = (contract: Contract) => {
|
||||
const { tags } = contract
|
||||
|
||||
if (tags.length === 0) return false
|
||||
if (tags.some((tag) => defaultSkippedTags.includes(tag))) return false
|
||||
return true
|
||||
}
|
||||
|
||||
export const useFilterYourContracts = (
|
||||
user: User | undefined | null,
|
||||
folds: Fold[],
|
||||
|
@ -54,8 +70,9 @@ export const useFilterYourContracts = (
|
|||
// Show no contracts before your info is loaded.
|
||||
let yourContracts: Contract[] = []
|
||||
if (yourBetContracts && followedFoldIds) {
|
||||
// Show all contracts if no folds are followed.
|
||||
if (followedFoldIds.length === 0) yourContracts = contracts
|
||||
// Show default contracts if no folds are followed.
|
||||
if (followedFoldIds.length === 0)
|
||||
yourContracts = contracts.filter(includedWithDefaultFeed)
|
||||
else
|
||||
yourContracts = contracts.filter(
|
||||
(contract) =>
|
||||
|
|
39
web/hooks/use-propz.ts
Normal file
39
web/hooks/use-propz.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
import _ from 'lodash'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useState, useEffect } from 'react'
|
||||
import { IS_PRIVATE_MANIFOLD } from '../../common/envs/constants'
|
||||
|
||||
type PropzProps = {
|
||||
// Params from the router query
|
||||
params: any
|
||||
}
|
||||
|
||||
// getStaticPropz should exactly match getStaticProps
|
||||
// This allows us to client-side render the page for authenticated users.
|
||||
// TODO: Could cache the result using stale-while-revalidate: https://swr.vercel.app/
|
||||
export function usePropz(
|
||||
initialProps: Object,
|
||||
getStaticPropz: (props: PropzProps) => Promise<any>
|
||||
) {
|
||||
// If props were successfully server-side generated, just use those
|
||||
if (!_.isEmpty(initialProps)) {
|
||||
return initialProps
|
||||
}
|
||||
|
||||
// Otherwise, get params from router
|
||||
const router = useRouter()
|
||||
const params = router.query
|
||||
|
||||
const [propz, setPropz] = useState<any>(undefined)
|
||||
useEffect(() => {
|
||||
if (router.isReady) {
|
||||
getStaticPropz({ params }).then((result) => setPropz(result.props))
|
||||
}
|
||||
}, [params])
|
||||
return propz
|
||||
}
|
||||
|
||||
// Conditionally disable SSG for private Manifold instances
|
||||
export function fromPropz(getStaticPropz: (props: PropzProps) => Promise<any>) {
|
||||
return IS_PRIVATE_MANIFOLD ? async () => ({ props: {} }) : getStaticPropz
|
||||
}
|
|
@ -1,42 +1,8 @@
|
|||
import { getFirestore } from '@firebase/firestore'
|
||||
import { initializeApp, getApps, getApp } from 'firebase/app'
|
||||
import { FIREBASE_CONFIG } from '../../../common/envs/constants'
|
||||
|
||||
// Used to decide which Stripe instance to point to
|
||||
export const isProd = process.env.NEXT_PUBLIC_FIREBASE_ENV !== 'DEV'
|
||||
|
||||
const FIREBASE_CONFIGS = {
|
||||
PROD: {
|
||||
apiKey: 'AIzaSyDp3J57vLeAZCzxLD-vcPaGIkAmBoGOSYw',
|
||||
authDomain: 'mantic-markets.firebaseapp.com',
|
||||
projectId: 'mantic-markets',
|
||||
storageBucket: 'mantic-markets.appspot.com',
|
||||
messagingSenderId: '128925704902',
|
||||
appId: '1:128925704902:web:f61f86944d8ffa2a642dc7',
|
||||
measurementId: 'G-SSFK1Q138D',
|
||||
},
|
||||
DEV: {
|
||||
apiKey: 'AIzaSyBoq3rzUa8Ekyo3ZaTnlycQYPRCA26VpOw',
|
||||
authDomain: 'dev-mantic-markets.firebaseapp.com',
|
||||
projectId: 'dev-mantic-markets',
|
||||
storageBucket: 'dev-mantic-markets.appspot.com',
|
||||
messagingSenderId: '134303100058',
|
||||
appId: '1:134303100058:web:27f9ea8b83347251f80323',
|
||||
measurementId: 'G-YJC9E37P37',
|
||||
},
|
||||
THEOREMONE: {
|
||||
apiKey: 'AIzaSyBSXL6Ys7InNHnCKSy-_E_luhh4Fkj4Z6M',
|
||||
authDomain: 'theoremone-manifold.firebaseapp.com',
|
||||
projectId: 'theoremone-manifold',
|
||||
storageBucket: 'theoremone-manifold.appspot.com',
|
||||
messagingSenderId: '698012149198',
|
||||
appId: '1:698012149198:web:b342af75662831aa84b79f',
|
||||
measurementId: 'G-Y3EZ1WNT6E',
|
||||
},
|
||||
}
|
||||
const ENV = process.env.NEXT_PUBLIC_FIREBASE_ENV ?? 'PROD'
|
||||
// @ts-ignore
|
||||
const firebaseConfig = FIREBASE_CONFIGS[ENV]
|
||||
// Initialize Firebase
|
||||
export const app = getApps().length ? getApp() : initializeApp(firebaseConfig)
|
||||
export const app = getApps().length ? getApp() : initializeApp(FIREBASE_CONFIG)
|
||||
|
||||
export const db = getFirestore(app)
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
import { isProd } from '../firebase/init'
|
||||
import { PROJECT_ID } from '../../../common/envs/constants'
|
||||
|
||||
export const checkoutURL = (
|
||||
userId: string,
|
||||
manticDollarQuantity: number,
|
||||
referer = ''
|
||||
) => {
|
||||
const endpoint = isProd
|
||||
? 'https://us-central1-mantic-markets.cloudfunctions.net/createCheckoutSession'
|
||||
: 'https://us-central1-dev-mantic-markets.cloudfunctions.net/createCheckoutSession'
|
||||
const endpoint = `https://us-central1-${PROJECT_ID}.cloudfunctions.net/createCheckoutSession`
|
||||
|
||||
return `${endpoint}?userId=${userId}&manticDollarQuantity=${manticDollarQuantity}&referer=${encodeURIComponent(
|
||||
referer
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
"scripts": {
|
||||
"dev": "concurrently -n NEXT,TS -c magenta,cyan \"next dev -p 3000\" \"yarn ts --watch\"",
|
||||
"devdev": "NEXT_PUBLIC_FIREBASE_ENV=DEV concurrently -n NEXT,TS -c magenta,cyan \"FIREBASE_ENV=DEV next dev -p 3000\" \"FIREBASE_ENV=DEV yarn ts --watch\"",
|
||||
"dev:dev": "yarn devdev",
|
||||
"dev:the": "NEXT_PUBLIC_FIREBASE_ENV=THEOREMONE concurrently -n NEXT,TS -c magenta,cyan \"FIREBASE_ENV=THEOREMONE next dev -p 3000\" \"FIREBASE_ENV=THEOREMONE yarn ts --watch\"",
|
||||
"ts": "tsc --noEmit --incremental --preserveWatchOutput --pretty",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
import { useEffect } from 'gridjs'
|
||||
import { IS_PRIVATE_MANIFOLD } from '../../common/envs/constants'
|
||||
import { Page } from '../components/page'
|
||||
import { Title } from '../components/title'
|
||||
|
||||
export default function Custom404() {
|
||||
if (IS_PRIVATE_MANIFOLD) {
|
||||
// Since private Manifolds are client-side rendered, they'll blink the 404
|
||||
// So we just show a blank page here:
|
||||
return <Page></Page>
|
||||
}
|
||||
return (
|
||||
<Page>
|
||||
<div className="flex h-full flex-col items-center justify-center">
|
||||
|
|
|
@ -29,8 +29,10 @@ import { useFoldsWithTags } from '../../hooks/use-fold'
|
|||
import { listAllAnswers } from '../../lib/firebase/answers'
|
||||
import { Answer } from '../../../common/answer'
|
||||
import { AnswersPanel } from '../../components/answers/answers-panel'
|
||||
import { fromPropz, usePropz } from '../../hooks/use-propz'
|
||||
|
||||
export async function getStaticProps(props: {
|
||||
export const getStaticProps = fromPropz(getStaticPropz)
|
||||
export async function getStaticPropz(props: {
|
||||
params: { username: string; contractSlug: string }
|
||||
}) {
|
||||
const { username, contractSlug } = props.params
|
||||
|
@ -77,6 +79,15 @@ export default function ContractPage(props: {
|
|||
slug: string
|
||||
folds: Fold[]
|
||||
}) {
|
||||
props = usePropz(props, getStaticPropz) ?? {
|
||||
contract: null,
|
||||
username: '',
|
||||
comments: [],
|
||||
answers: [],
|
||||
bets: [],
|
||||
slug: '',
|
||||
folds: [],
|
||||
}
|
||||
const user = useUser()
|
||||
|
||||
const contract = useContractWithPreload(props.slug, props.contract)
|
||||
|
@ -143,7 +154,7 @@ export default function ContractPage(props: {
|
|||
<>
|
||||
<div className="md:ml-6" />
|
||||
|
||||
<Col className="md:w-[310px] flex-shrink-0">
|
||||
<Col className="flex-shrink-0 md:w-[310px]">
|
||||
{allowTrade && (
|
||||
<BetPanel className="hidden lg:flex" contract={contract} />
|
||||
)}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import { Html, Head, Main, NextScript } from 'next/document'
|
||||
import { ENV_CONFIG } from '../../common/envs/constants'
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<Html data-theme="mantic" className="min-h-screen">
|
||||
<Head>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<link rel="icon" href={ENV_CONFIG.faviconPath} />
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
import dayjs from 'dayjs'
|
||||
import _ from 'lodash'
|
||||
import { IS_PRIVATE_MANIFOLD } from '../../common/envs/constants'
|
||||
import { DailyCountChart } from '../components/analytics/charts'
|
||||
import { Col } from '../components/layout/col'
|
||||
import { Spacer } from '../components/layout/spacer'
|
||||
import { Page } from '../components/page'
|
||||
import { Title } from '../components/title'
|
||||
import { fromPropz, usePropz } from '../hooks/use-propz'
|
||||
import { getDailyBets } from '../lib/firebase/bets'
|
||||
import { getDailyComments } from '../lib/firebase/comments'
|
||||
import { getDailyContracts } from '../lib/firebase/contracts'
|
||||
|
||||
export async function getStaticProps() {
|
||||
export const getStaticProps = fromPropz(getStaticPropz)
|
||||
export async function getStaticPropz() {
|
||||
const numberOfDays = 80
|
||||
const today = dayjs(dayjs().format('YYYY-MM-DD'))
|
||||
const startDate = today.subtract(numberOfDays, 'day')
|
||||
|
@ -54,11 +57,18 @@ export default function Analytics(props: {
|
|||
dailyContractCounts: number[]
|
||||
dailyCommentCounts: number[]
|
||||
}) {
|
||||
props = usePropz(props, getStaticPropz) ?? {
|
||||
startDate: 0,
|
||||
dailyActiveUsers: [],
|
||||
dailyBetCounts: [],
|
||||
dailyContractCounts: [],
|
||||
dailyCommentCounts: [],
|
||||
}
|
||||
return (
|
||||
<Page>
|
||||
<CustomAnalytics {...props} />
|
||||
<Spacer h={8} />
|
||||
<FirebaseAnalytics />
|
||||
{!IS_PRIVATE_MANIFOLD && <FirebaseAnalytics />}
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ import { ProbabilitySelector } from '../components/probability-selector'
|
|||
import { parseWordsAsTags } from '../../common/util/parse'
|
||||
import { TagsList } from '../components/tags-list'
|
||||
import { Row } from '../components/layout/row'
|
||||
import { outcomeType } from '../../common/contract'
|
||||
import { MAX_DESCRIPTION_LENGTH, outcomeType } from '../../common/contract'
|
||||
|
||||
export default function Create() {
|
||||
const [question, setQuestion] = useState('')
|
||||
|
@ -186,6 +186,7 @@ export function NewContract(props: { question: string; tag?: string }) {
|
|||
<Textarea
|
||||
className="textarea textarea-bordered w-full"
|
||||
rows={3}
|
||||
maxLength={MAX_DESCRIPTION_LENGTH}
|
||||
placeholder={descriptionPlaceholder}
|
||||
value={description}
|
||||
disabled={isSubmitting}
|
||||
|
|
|
@ -38,12 +38,14 @@ import FeedCreate from '../../../components/feed-create'
|
|||
import { SEO } from '../../../components/SEO'
|
||||
import { useTaggedContracts } from '../../../hooks/use-contracts'
|
||||
import { Linkify } from '../../../components/linkify'
|
||||
import { fromPropz, usePropz } from '../../../hooks/use-propz'
|
||||
import { filterDefined } from '../../../../common/util/array'
|
||||
import { useRecentBets } from '../../../hooks/use-bets'
|
||||
import { useRecentComments } from '../../../hooks/use-comments'
|
||||
import { LoadingIndicator } from '../../../components/loading-indicator'
|
||||
|
||||
export async function getStaticProps(props: { params: { slugs: string[] } }) {
|
||||
export const getStaticProps = fromPropz(getStaticPropz)
|
||||
export async function getStaticPropz(props: { params: { slugs: string[] } }) {
|
||||
const { slugs } = props.params
|
||||
|
||||
const fold = await getFoldBySlug(slugs[0])
|
||||
|
@ -116,13 +118,25 @@ export default function FoldPage(props: {
|
|||
creatorScores: { [userId: string]: number }
|
||||
topCreators: User[]
|
||||
}) {
|
||||
props = usePropz(props, getStaticPropz) ?? {
|
||||
fold: null,
|
||||
curator: null,
|
||||
contracts: [],
|
||||
activeContracts: [],
|
||||
activeContractBets: [],
|
||||
activeContractComments: [],
|
||||
traderScores: {},
|
||||
topTraders: [],
|
||||
creatorScores: {},
|
||||
topCreators: [],
|
||||
}
|
||||
const { curator, traderScores, topTraders, creatorScores, topCreators } =
|
||||
props
|
||||
|
||||
const router = useRouter()
|
||||
const { slugs } = router.query as { slugs: string[] }
|
||||
|
||||
const page = (slugs[1] ?? 'activity') as typeof foldSubpages[number]
|
||||
const page = (slugs?.[1] ?? 'activity') as typeof foldSubpages[number]
|
||||
|
||||
const fold = useFold(props.fold?.id) ?? props.fold
|
||||
|
||||
|
|
|
@ -59,7 +59,24 @@ export default function Folds(props: {
|
|||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
}, [curatorsDict])
|
||||
|
||||
const [query, setQuery] = useState('')
|
||||
// Copied from contracts-list.tsx; extract if we copy this again
|
||||
const queryWords = query.toLowerCase().split(' ')
|
||||
function check(corpus: String) {
|
||||
return queryWords.every((word) => corpus.toLowerCase().includes(word))
|
||||
}
|
||||
|
||||
const matches = folds.filter(
|
||||
(f) =>
|
||||
check(f.name) ||
|
||||
check(f.about || '') ||
|
||||
check(curatorsDict[f.curatorId].username) ||
|
||||
check(f.lowercaseTags.map((tag) => `#${tag}`).join(' '))
|
||||
)
|
||||
// Not strictly necessary, but makes the "hold delete" experience less laggy
|
||||
const debouncedQuery = _.debounce(setQuery, 50)
|
||||
|
||||
return (
|
||||
<Page>
|
||||
|
@ -76,10 +93,17 @@ export default function Folds(props: {
|
|||
markets. Follow a community to personalize your feed and receive
|
||||
relevant updates.
|
||||
</div>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
onChange={(e) => debouncedQuery(e.target.value)}
|
||||
placeholder="Search communities"
|
||||
className="input input-bordered mb-4 w-full"
|
||||
/>
|
||||
</Col>
|
||||
|
||||
<Col className="gap-4">
|
||||
{folds.map((fold) => (
|
||||
{matches.map((fold) => (
|
||||
<FoldCard
|
||||
key={fold.id}
|
||||
fold={fold}
|
||||
|
|
|
@ -22,11 +22,14 @@ import {
|
|||
useFilterYourContracts,
|
||||
useFindActiveContracts,
|
||||
} from '../hooks/use-find-active-contracts'
|
||||
import { fromPropz, usePropz } from '../hooks/use-propz'
|
||||
import { useGetRecentBets, useRecentBets } from '../hooks/use-bets'
|
||||
import { useActiveContracts } from '../hooks/use-contracts'
|
||||
import { useRecentComments } from '../hooks/use-comments'
|
||||
import { IS_PRIVATE_MANIFOLD } from '../../common/envs/constants'
|
||||
|
||||
export async function getStaticProps() {
|
||||
export const getStaticProps = fromPropz(getStaticPropz)
|
||||
export async function getStaticPropz() {
|
||||
const contractInfo = await getAllContractInfo()
|
||||
|
||||
return {
|
||||
|
@ -40,6 +43,11 @@ const Home = (props: {
|
|||
folds: Fold[]
|
||||
recentComments: Comment[]
|
||||
}) => {
|
||||
props = usePropz(props, getStaticPropz) ?? {
|
||||
contracts: [],
|
||||
folds: [],
|
||||
recentComments: [],
|
||||
}
|
||||
const { folds } = props
|
||||
const user = useUser()
|
||||
|
||||
|
@ -76,13 +84,14 @@ const Home = (props: {
|
|||
<FeedCreate user={user ?? undefined} />
|
||||
<Spacer h={6} />
|
||||
|
||||
{initialFollowedFoldSlugs !== undefined &&
|
||||
initialFollowedFoldSlugs.length === 0 && (
|
||||
{/* {initialFollowedFoldSlugs !== undefined &&
|
||||
initialFollowedFoldSlugs.length === 0 &&
|
||||
!IS_PRIVATE_MANIFOLD && (
|
||||
<FastFoldFollowing
|
||||
user={user}
|
||||
followedFoldSlugs={initialFollowedFoldSlugs}
|
||||
/>
|
||||
)}
|
||||
)} */}
|
||||
|
||||
<Spacer h={5} />
|
||||
|
||||
|
|
|
@ -5,8 +5,10 @@ import { Leaderboard } from '../components/leaderboard'
|
|||
import { Page } from '../components/page'
|
||||
import { getTopCreators, getTopTraders, User } from '../lib/firebase/users'
|
||||
import { formatMoney } from '../../common/util/format'
|
||||
import { fromPropz, usePropz } from '../hooks/use-propz'
|
||||
|
||||
export async function getStaticProps() {
|
||||
export const getStaticProps = fromPropz(getStaticPropz)
|
||||
export async function getStaticPropz() {
|
||||
const [topTraders, topCreators] = await Promise.all([
|
||||
getTopTraders().catch((_) => {}),
|
||||
getTopCreators().catch((_) => {}),
|
||||
|
@ -26,6 +28,10 @@ export default function Leaderboards(props: {
|
|||
topTraders: User[]
|
||||
topCreators: User[]
|
||||
}) {
|
||||
props = usePropz(props, getStaticPropz) ?? {
|
||||
topTraders: [],
|
||||
topCreators: [],
|
||||
}
|
||||
const { topTraders, topCreators } = props
|
||||
|
||||
return (
|
||||
|
|
5
web/public/theoremone/Th1-Icon-Round.svg
Normal file
5
web/public/theoremone/Th1-Icon-Round.svg
Normal file
|
@ -0,0 +1,5 @@
|
|||
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="512" height="512" rx="256" fill="#031323"/>
|
||||
<path d="M99.1324 181.341C97.0441 181.341 96 181.761 96 184.701V220.193C96 221.873 97.253 222.713 98.506 222.713C99.9678 222.713 101.638 221.663 101.638 219.983C101.638 206.962 112.706 189.741 131.501 189.741H150.713V269.126C150.713 298.107 149.878 313.018 149.46 318.899C148.416 331.289 142.987 336.33 126.489 336.33C123.983 336.33 122.73 338.01 122.73 339.48C122.73 340.74 123.774 342 125.863 342H200.624C202.712 342 203.756 340.74 203.756 339.48C203.756 338.01 202.503 336.33 199.788 336.33C184.544 336.33 178.07 331.499 176.608 318.899C175.982 313.018 175.355 297.687 175.355 269.336V189.741H219.209C231.321 189.741 232.783 195.201 232.783 217.043V284.457C232.783 298.527 231.948 314.488 231.53 320.369C230.486 332.759 227.145 336.54 215.45 336.54C212.944 336.54 211.691 338.01 211.691 339.48C211.691 340.74 212.736 342 214.824 342H272.67C274.758 342 275.802 340.74 275.802 339.48C275.802 338.01 274.549 336.54 272.043 336.54C259.722 336.54 258.469 332.969 256.799 320.369C255.963 314.488 255.754 298.527 255.754 284.457V248.125C270.581 236.364 278.935 228.593 288.332 228.593C298.773 228.593 305.247 235.524 305.247 279.626C305.247 328.979 301.488 336.54 289.167 336.54C286.661 336.54 285.408 338.01 285.408 339.48C285.408 340.74 286.452 342 288.541 342H345.133C347.222 342 348.266 340.74 348.266 339.48C348.266 338.01 347.013 336.54 344.507 336.54C333.23 336.54 329.262 332.969 329.262 320.369V245.394C329.262 227.333 319.03 213.893 301.697 213.893C286.661 213.893 275.802 222.713 262.437 234.054L255.754 239.724V175.25C255.754 171.26 254.084 170 251.578 170C245.104 170 243.434 181.341 218.583 181.341H99.1324Z" fill="white"/>
|
||||
<path d="M393.238 181.551C393.238 180.291 392.82 179.871 391.567 179.871C388.017 179.871 370.266 183.861 354.187 187.641C352.516 188.061 351.889 189.111 351.889 190.161C351.889 191.421 352.725 192.471 353.978 192.471H370.893C375.905 192.471 376.74 194.151 376.74 199.402V229.643C376.74 236.784 376.531 244.344 375.696 247.284C374.025 253.375 364.21 255.685 356.275 255.685C354.395 255.685 353.56 256.735 353.56 257.785C353.56 258.835 354.186 260.095 355.648 260.095H413.703C415.165 260.095 416 259.255 416 257.785C416 256.525 414.956 255.685 413.703 255.685C405.559 255.685 396.161 253.585 394.282 247.284C393.446 244.344 393.238 236.784 393.238 229.643V181.551Z" fill="white"/>
|
||||
</svg>
|
After Width: | Height: | Size: 2.4 KiB |
5
web/public/theoremone/Th1-Icon-Square.svg
Normal file
5
web/public/theoremone/Th1-Icon-Square.svg
Normal file
|
@ -0,0 +1,5 @@
|
|||
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="512" height="512" fill="#031323"/>
|
||||
<path d="M99.1324 181.341C97.0441 181.341 96 181.761 96 184.701V220.193C96 221.873 97.253 222.713 98.506 222.713C99.9678 222.713 101.638 221.663 101.638 219.983C101.638 206.962 112.706 189.741 131.501 189.741H150.713V269.126C150.713 298.107 149.878 313.018 149.46 318.899C148.416 331.289 142.987 336.33 126.489 336.33C123.983 336.33 122.73 338.01 122.73 339.48C122.73 340.74 123.774 342 125.863 342H200.624C202.712 342 203.756 340.74 203.756 339.48C203.756 338.01 202.503 336.33 199.788 336.33C184.544 336.33 178.07 331.499 176.608 318.899C175.982 313.018 175.355 297.687 175.355 269.336V189.741H219.209C231.321 189.741 232.783 195.201 232.783 217.043V284.457C232.783 298.527 231.948 314.488 231.53 320.369C230.486 332.759 227.145 336.54 215.45 336.54C212.944 336.54 211.691 338.01 211.691 339.48C211.691 340.74 212.736 342 214.824 342H272.67C274.758 342 275.802 340.74 275.802 339.48C275.802 338.01 274.549 336.54 272.043 336.54C259.722 336.54 258.469 332.969 256.799 320.369C255.963 314.488 255.754 298.527 255.754 284.457V248.125C270.581 236.364 278.935 228.593 288.332 228.593C298.773 228.593 305.247 235.524 305.247 279.626C305.247 328.979 301.488 336.54 289.167 336.54C286.661 336.54 285.408 338.01 285.408 339.48C285.408 340.74 286.452 342 288.541 342H345.133C347.222 342 348.266 340.74 348.266 339.48C348.266 338.01 347.013 336.54 344.507 336.54C333.23 336.54 329.262 332.969 329.262 320.369V245.394C329.262 227.333 319.03 213.893 301.697 213.893C286.661 213.893 275.802 222.713 262.437 234.054L255.754 239.724V175.25C255.754 171.26 254.084 170 251.578 170C245.104 170 243.434 181.341 218.583 181.341H99.1324Z" fill="white"/>
|
||||
<path d="M393.238 181.551C393.238 180.291 392.82 179.871 391.567 179.871C388.017 179.871 370.266 183.861 354.187 187.641C352.516 188.061 351.889 189.111 351.889 190.161C351.889 191.421 352.725 192.471 353.978 192.471H370.893C375.905 192.471 376.74 194.151 376.74 199.402V229.643C376.74 236.784 376.531 244.344 375.696 247.284C374.025 253.375 364.21 255.685 356.275 255.685C354.395 255.685 353.56 256.735 353.56 257.785C353.56 258.835 354.186 260.095 355.648 260.095H413.703C415.165 260.095 416 259.255 416 257.785C416 256.525 414.956 255.685 413.703 255.685C405.559 255.685 396.161 253.585 394.282 247.284C393.446 244.344 393.238 236.784 393.238 229.643V181.551Z" fill="white"/>
|
||||
</svg>
|
After Width: | Height: | Size: 2.4 KiB |
12
web/public/theoremone/TheoremOne-Logo-White.svg
Normal file
12
web/public/theoremone/TheoremOne-Logo-White.svg
Normal file
|
@ -0,0 +1,12 @@
|
|||
<svg width="1080" height="130" viewBox="0 0 1080 130" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2.34908 8.44198C0.783027 8.44198 0 8.75465 0 10.9433V37.3636C0 38.6142 0.939632 39.2396 1.87926 39.2396C2.9755 39.2396 4.22834 38.4579 4.22834 37.2072C4.22834 27.5146 12.5284 14.6953 26.6229 14.6953H41.0306V73.7891C41.0306 95.3631 40.4042 106.463 40.091 110.84C39.3079 120.064 35.2362 123.816 22.8644 123.816C20.9851 123.816 20.0455 125.066 20.0455 126.161C20.0455 127.099 20.8285 128.037 22.3946 128.037H78.4593C80.0253 128.037 80.8084 127.099 80.8084 126.161C80.8084 125.066 79.8687 123.816 77.8329 123.816C66.4007 123.816 61.5459 120.22 60.4497 110.84C59.9799 106.463 59.51 95.0504 59.51 73.9455V14.6953H92.3972C101.48 14.6953 102.577 18.76 102.577 35.0186V85.2015C102.577 95.6758 101.95 107.557 101.637 111.934C100.854 121.158 98.3482 123.972 89.5783 123.972C87.699 123.972 86.7594 125.066 86.7594 126.161C86.7594 127.099 87.5424 128.037 89.1085 128.037H132.488C134.054 128.037 134.837 127.099 134.837 126.161C134.837 125.066 133.898 123.972 132.018 123.972C122.779 123.972 121.839 121.314 120.586 111.934C119.96 107.557 119.803 95.6758 119.803 85.2015V58.1559C130.922 49.4012 137.186 43.6169 144.234 43.6169C152.064 43.6169 156.919 48.7759 156.919 81.6058C156.919 118.344 154.1 123.972 144.86 123.972C142.981 123.972 142.041 125.066 142.041 126.161C142.041 127.099 142.824 128.037 144.39 128.037H186.83C188.396 128.037 189.179 127.099 189.179 126.161C189.179 125.066 188.24 123.972 186.36 123.972C177.904 123.972 174.928 121.314 174.928 111.934V56.1235C174.928 42.6789 167.255 32.6736 154.256 32.6736C142.981 32.6736 134.837 39.2396 124.814 47.6816L119.803 51.9025V3.90833C119.803 0.938004 118.55 0 116.671 0C111.816 0 110.563 8.44198 91.9273 8.44198H2.34908Z" fill="white"/>
|
||||
<path d="M265.658 102.867C265.658 101.773 265.345 100.991 264.405 100.991C263.778 100.991 263.152 101.304 262.682 102.242C256.888 114.279 249.527 117.562 238.878 117.562C221.652 117.562 210.846 100.522 210.846 70.8188H256.105C262.839 70.8188 265.658 68.7865 265.658 63.1585C265.658 39.7086 248.588 32.6736 235.59 32.6736C206.774 32.6736 192.523 55.0292 192.523 83.9508C192.523 114.592 208.967 129.6 232.301 129.6C256.261 129.6 265.658 112.56 265.658 102.867ZM232.457 37.6762C241.541 37.6762 246.082 44.5549 246.082 58.9375C246.082 62.3768 245.142 64.4092 239.974 64.7218L211.159 66.7542C213.038 51.4335 219.303 37.6762 232.457 37.6762Z" fill="white"/>
|
||||
<path d="M312.332 129.6C338.016 129.6 356.965 114.279 356.965 78.3228C356.965 49.7139 342.4 32.6736 317.657 32.6736C291.974 32.6736 273.181 48.9322 273.181 84.8888C273.181 113.498 287.589 129.6 312.332 129.6ZM316.561 124.128C299.491 124.128 292.287 104.899 292.287 79.2608C292.287 55.6545 298.238 37.9889 314.368 37.9889C331.125 37.9889 337.702 58.1559 337.702 83.7945C337.702 107.401 332.848 124.128 316.561 124.128Z" fill="white"/>
|
||||
<path d="M393.96 59.2502C393.96 46.1182 392.864 34.5496 386.913 34.5496C384.407 34.5496 366.085 37.2072 359.664 38.9269C357.941 39.3959 357.315 40.3339 357.315 41.1156C357.315 42.0536 358.098 42.8352 359.664 42.8352H363.422C376.421 42.8352 377.36 58.9375 377.36 78.4791V85.2015C377.36 95.6758 376.734 106.463 376.421 110.84C375.638 120.064 372.505 123.972 364.362 123.972C362.483 123.972 361.543 125.066 361.543 126.161C361.543 127.099 362.326 128.037 363.892 128.037H412.753C414.319 128.037 415.102 127.099 415.102 126.161C415.102 125.066 414.162 123.972 412.283 123.972C399.442 123.972 395.683 120.22 394.43 110.84C393.96 106.463 393.49 99.7404 393.49 80.8241C393.49 62.3768 400.851 46.8999 409.621 46.8999C416.355 46.8999 416.511 54.0912 416.511 56.9052C421.21 56.9052 430.606 54.8729 430.606 45.3366C430.606 36.5819 425.125 32.6736 417.138 32.6736C408.681 32.6736 398.972 37.6762 393.96 59.2502Z" fill="white"/>
|
||||
<path d="M502.126 102.867C502.126 101.773 501.812 100.991 500.873 100.991C500.246 100.991 499.62 101.304 499.15 102.242C493.356 114.279 485.995 117.562 475.346 117.562C458.12 117.562 447.314 100.522 447.314 70.8188H492.573C499.307 70.8188 502.126 68.7865 502.126 63.1585C502.126 39.7086 485.056 32.6736 472.057 32.6736C443.242 32.6736 428.991 55.0292 428.991 83.9508C428.991 114.592 445.435 129.6 468.769 129.6C492.729 129.6 502.126 112.56 502.126 102.867ZM468.925 37.6762C478.008 37.6762 482.55 44.5549 482.55 58.9375C482.55 62.3768 481.61 64.4092 476.442 64.7218L447.627 66.7542C449.506 51.4335 455.771 37.6762 468.925 37.6762Z" fill="white"/>
|
||||
<path d="M590.927 52.0589C589.518 40.8029 582.784 32.6736 571.195 32.6736C559.919 32.6736 553.655 39.2396 543.632 47.6816L538.934 51.5899C539.091 48.3069 539.091 44.0859 539.091 42.2099C539.091 36.7382 536.585 34.5496 533.14 34.5496C527.658 34.5496 505.107 38.1452 505.107 41.2719C505.107 42.0536 505.577 42.8352 507.143 42.8352H511.528C521.551 42.8352 521.707 58.1559 521.707 77.6975V85.2015C521.707 115.843 521.707 123.816 508.709 123.972C506.83 123.972 505.89 125.066 505.89 126.161C505.89 127.099 506.673 128.037 508.239 128.037H551.306C552.872 128.037 553.655 127.099 553.655 126.161C553.655 125.066 552.715 123.972 550.679 123.972C540.97 123.972 540.657 120.533 539.404 111.153C538.777 106.775 538.464 95.6758 538.464 85.2015V78.4791C538.464 70.9752 538.464 63.3148 538.621 58.1559C549.74 49.4012 554.908 44.2422 561.485 44.2422C568.689 44.2422 573.231 48.7759 573.231 81.6058C573.231 118.344 570.412 123.972 561.172 123.972C559.293 123.972 558.353 125.066 558.353 126.161C558.353 127.099 559.136 128.037 560.702 128.037H603.142C604.708 128.037 605.491 127.099 605.491 126.161C605.491 125.066 604.552 123.972 602.672 123.972C594.216 123.972 591.24 121.314 591.24 111.934V58.1559C602.359 49.4012 607.527 44.2422 614.105 44.2422C621.308 44.2422 625.85 48.7759 625.85 81.6058C625.85 118.344 623.031 123.972 613.791 123.972C611.912 123.972 610.973 125.066 610.973 126.161C610.973 127.099 611.756 128.037 613.322 128.037H655.762C657.328 128.037 658.111 127.099 658.111 126.161C658.111 125.066 657.171 123.972 655.292 123.972C646.835 123.972 643.86 121.314 643.86 111.934V56.1235C643.86 42.6789 636.812 32.6736 623.814 32.6736C612.539 32.6736 606.431 39.3959 596.252 47.6816L590.927 52.0589Z" fill="white"/>
|
||||
<path d="M659.855 68.0048C659.855 107.244 682.093 129.6 717.33 129.6C752.409 129.6 774.647 107.401 774.647 68.0048C774.647 28.6089 752.409 6.25332 717.33 6.25332C682.093 6.25332 659.855 29.2343 659.855 68.0048ZM716.547 12.194C744.109 12.194 752.722 39.2396 752.722 69.2555C752.722 97.3954 744.266 123.659 716.86 123.659C689.767 123.659 681.31 95.8321 681.31 66.7542C681.31 39.3959 689.454 12.194 716.547 12.194Z" fill="white"/>
|
||||
<path d="M808.856 51.5899C809.012 48.3069 809.012 44.0859 809.012 42.2099C809.012 36.7382 806.507 34.5496 803.061 34.5496C797.58 34.5496 777.729 38.1452 777.729 41.2719C777.729 42.0536 778.199 42.8352 779.765 42.8352H781.45C791.473 42.8352 791.629 58.1559 791.629 77.6975V85.2015C791.629 115.843 791.629 123.816 778.631 123.972C776.752 123.972 775.812 125.066 775.812 126.161C775.812 127.099 776.595 128.037 778.161 128.037H821.228C822.794 128.037 823.577 127.099 823.577 126.161C823.577 125.066 822.637 123.972 820.601 123.972C810.892 123.972 810.578 120.533 809.326 111.153C808.699 106.775 808.386 95.6758 808.386 85.2015V78.4791C808.386 70.9752 808.386 63.3148 808.543 58.1559C819.662 49.4012 825.926 43.6169 832.973 43.6169C840.803 43.6169 845.658 48.7759 845.658 81.6058C845.658 118.344 842.839 123.972 833.599 123.972C831.72 123.972 830.781 125.066 830.781 126.161C830.781 127.099 831.564 128.037 833.13 128.037H875.57C877.136 128.037 877.919 127.099 877.919 126.161C877.919 125.066 876.979 123.972 875.1 123.972C866.643 123.972 863.668 121.314 863.668 111.934V56.1235C863.668 42.6789 855.994 32.6736 842.996 32.6736C831.72 32.6736 823.577 39.2396 813.554 47.6816L808.856 51.5899Z" fill="white"/>
|
||||
<path d="M950.4 102.867C950.4 101.773 950.087 100.991 949.147 100.991C948.521 100.991 947.894 101.304 947.425 102.242C941.63 114.279 934.27 117.562 923.621 117.562C906.394 117.562 895.588 100.522 895.588 70.8188H940.847C947.581 70.8188 950.4 68.7865 950.4 63.1585C950.4 39.7086 933.33 32.6736 920.332 32.6736C891.516 32.6736 877.265 55.0292 877.265 83.9508C877.265 114.592 893.709 129.6 917.043 129.6C941.004 129.6 950.4 112.56 950.4 102.867ZM917.2 37.6762C926.283 37.6762 930.824 44.5549 930.824 58.9375C930.824 62.3768 929.885 64.4092 924.717 64.7218L895.901 66.7542C897.781 51.4335 904.045 37.6762 917.2 37.6762Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1063.8 48.6H999V113.4H1063.8V48.6ZM982.8 32.4V129.6H1080V32.4H982.8Z" fill="white"/>
|
||||
</svg>
|
After Width: | Height: | Size: 8.4 KiB |
12
web/public/theoremone/TheoremOne-Logo.svg
Normal file
12
web/public/theoremone/TheoremOne-Logo.svg
Normal file
|
@ -0,0 +1,12 @@
|
|||
<svg width="1080" height="130" viewBox="0 0 1080 130" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2.34908 8.44198C0.783027 8.44198 0 8.75465 0 10.9433V37.3636C0 38.6142 0.939632 39.2396 1.87926 39.2396C2.9755 39.2396 4.22834 38.4579 4.22834 37.2072C4.22834 27.5146 12.5284 14.6953 26.6229 14.6953H41.0306V73.7891C41.0306 95.3631 40.4042 106.463 40.091 110.84C39.3079 120.064 35.2362 123.816 22.8644 123.816C20.9851 123.816 20.0455 125.066 20.0455 126.161C20.0455 127.099 20.8285 128.037 22.3946 128.037H78.4593C80.0253 128.037 80.8084 127.099 80.8084 126.161C80.8084 125.066 79.8687 123.816 77.8329 123.816C66.4007 123.816 61.5459 120.22 60.4497 110.84C59.9799 106.463 59.51 95.0504 59.51 73.9455V14.6953H92.3972C101.48 14.6953 102.577 18.76 102.577 35.0186V85.2015C102.577 95.6758 101.95 107.557 101.637 111.934C100.854 121.158 98.3482 123.972 89.5783 123.972C87.699 123.972 86.7594 125.066 86.7594 126.161C86.7594 127.099 87.5424 128.037 89.1085 128.037H132.488C134.054 128.037 134.837 127.099 134.837 126.161C134.837 125.066 133.898 123.972 132.018 123.972C122.779 123.972 121.839 121.314 120.586 111.934C119.96 107.557 119.803 95.6758 119.803 85.2015V58.1559C130.922 49.4012 137.186 43.6169 144.234 43.6169C152.064 43.6169 156.919 48.7759 156.919 81.6058C156.919 118.344 154.1 123.972 144.86 123.972C142.981 123.972 142.041 125.066 142.041 126.161C142.041 127.099 142.824 128.037 144.39 128.037H186.83C188.396 128.037 189.179 127.099 189.179 126.161C189.179 125.066 188.24 123.972 186.36 123.972C177.904 123.972 174.928 121.314 174.928 111.934V56.1235C174.928 42.6789 167.255 32.6736 154.256 32.6736C142.981 32.6736 134.837 39.2396 124.814 47.6816L119.803 51.9025V3.90833C119.803 0.938004 118.55 0 116.671 0C111.816 0 110.563 8.44198 91.9273 8.44198H2.34908Z" fill="#031323"/>
|
||||
<path d="M265.658 102.867C265.658 101.773 265.345 100.991 264.405 100.991C263.778 100.991 263.152 101.304 262.682 102.242C256.888 114.279 249.527 117.562 238.878 117.562C221.652 117.562 210.846 100.522 210.846 70.8188H256.105C262.839 70.8188 265.658 68.7865 265.658 63.1585C265.658 39.7086 248.588 32.6736 235.59 32.6736C206.774 32.6736 192.523 55.0292 192.523 83.9508C192.523 114.592 208.967 129.6 232.301 129.6C256.261 129.6 265.658 112.56 265.658 102.867ZM232.457 37.6762C241.541 37.6762 246.082 44.5549 246.082 58.9375C246.082 62.3768 245.142 64.4092 239.974 64.7218L211.159 66.7542C213.038 51.4335 219.303 37.6762 232.457 37.6762Z" fill="#031323"/>
|
||||
<path d="M312.332 129.6C338.016 129.6 356.965 114.279 356.965 78.3228C356.965 49.7139 342.4 32.6736 317.657 32.6736C291.974 32.6736 273.181 48.9322 273.181 84.8888C273.181 113.498 287.589 129.6 312.332 129.6ZM316.561 124.128C299.491 124.128 292.287 104.899 292.287 79.2608C292.287 55.6545 298.238 37.9889 314.368 37.9889C331.125 37.9889 337.702 58.1559 337.702 83.7945C337.702 107.401 332.848 124.128 316.561 124.128Z" fill="#031323"/>
|
||||
<path d="M393.96 59.2502C393.96 46.1182 392.864 34.5496 386.913 34.5496C384.407 34.5496 366.085 37.2072 359.664 38.9269C357.941 39.3959 357.315 40.3339 357.315 41.1156C357.315 42.0536 358.098 42.8352 359.664 42.8352H363.422C376.421 42.8352 377.36 58.9375 377.36 78.4791V85.2015C377.36 95.6758 376.734 106.463 376.421 110.84C375.638 120.064 372.505 123.972 364.362 123.972C362.483 123.972 361.543 125.066 361.543 126.161C361.543 127.099 362.326 128.037 363.892 128.037H412.753C414.319 128.037 415.102 127.099 415.102 126.161C415.102 125.066 414.162 123.972 412.283 123.972C399.442 123.972 395.683 120.22 394.43 110.84C393.96 106.463 393.49 99.7404 393.49 80.8241C393.49 62.3768 400.851 46.8999 409.621 46.8999C416.355 46.8999 416.511 54.0912 416.511 56.9052C421.21 56.9052 430.606 54.8729 430.606 45.3366C430.606 36.5819 425.125 32.6736 417.138 32.6736C408.681 32.6736 398.972 37.6762 393.96 59.2502Z" fill="#031323"/>
|
||||
<path d="M502.126 102.867C502.126 101.773 501.812 100.991 500.873 100.991C500.246 100.991 499.62 101.304 499.15 102.242C493.356 114.279 485.995 117.562 475.346 117.562C458.12 117.562 447.314 100.522 447.314 70.8188H492.573C499.307 70.8188 502.126 68.7865 502.126 63.1585C502.126 39.7086 485.056 32.6736 472.057 32.6736C443.242 32.6736 428.991 55.0292 428.991 83.9508C428.991 114.592 445.435 129.6 468.769 129.6C492.729 129.6 502.126 112.56 502.126 102.867ZM468.925 37.6762C478.008 37.6762 482.55 44.5549 482.55 58.9375C482.55 62.3768 481.61 64.4092 476.442 64.7218L447.627 66.7542C449.506 51.4335 455.771 37.6762 468.925 37.6762Z" fill="#031323"/>
|
||||
<path d="M590.927 52.0589C589.518 40.8029 582.784 32.6736 571.195 32.6736C559.919 32.6736 553.655 39.2396 543.632 47.6816L538.934 51.5899C539.091 48.3069 539.091 44.0859 539.091 42.2099C539.091 36.7382 536.585 34.5496 533.14 34.5496C527.658 34.5496 505.107 38.1452 505.107 41.2719C505.107 42.0536 505.577 42.8352 507.143 42.8352H511.528C521.551 42.8352 521.707 58.1559 521.707 77.6975V85.2015C521.707 115.843 521.707 123.816 508.709 123.972C506.83 123.972 505.89 125.066 505.89 126.161C505.89 127.099 506.673 128.037 508.239 128.037H551.306C552.872 128.037 553.655 127.099 553.655 126.161C553.655 125.066 552.715 123.972 550.679 123.972C540.97 123.972 540.657 120.533 539.404 111.153C538.777 106.775 538.464 95.6758 538.464 85.2015V78.4791C538.464 70.9752 538.464 63.3148 538.621 58.1559C549.74 49.4012 554.908 44.2422 561.485 44.2422C568.689 44.2422 573.231 48.7759 573.231 81.6058C573.231 118.344 570.412 123.972 561.172 123.972C559.293 123.972 558.353 125.066 558.353 126.161C558.353 127.099 559.136 128.037 560.702 128.037H603.142C604.708 128.037 605.491 127.099 605.491 126.161C605.491 125.066 604.552 123.972 602.672 123.972C594.216 123.972 591.24 121.314 591.24 111.934V58.1559C602.359 49.4012 607.527 44.2422 614.105 44.2422C621.308 44.2422 625.85 48.7759 625.85 81.6058C625.85 118.344 623.031 123.972 613.791 123.972C611.912 123.972 610.973 125.066 610.973 126.161C610.973 127.099 611.756 128.037 613.322 128.037H655.762C657.328 128.037 658.111 127.099 658.111 126.161C658.111 125.066 657.171 123.972 655.292 123.972C646.835 123.972 643.86 121.314 643.86 111.934V56.1235C643.86 42.6789 636.812 32.6736 623.814 32.6736C612.539 32.6736 606.431 39.3959 596.252 47.6816L590.927 52.0589Z" fill="#031323"/>
|
||||
<path d="M659.855 68.0048C659.855 107.244 682.093 129.6 717.33 129.6C752.409 129.6 774.647 107.401 774.647 68.0048C774.647 28.6089 752.409 6.25332 717.33 6.25332C682.093 6.25332 659.855 29.2343 659.855 68.0048ZM716.547 12.194C744.109 12.194 752.722 39.2396 752.722 69.2555C752.722 97.3954 744.266 123.659 716.86 123.659C689.767 123.659 681.31 95.8321 681.31 66.7542C681.31 39.3959 689.454 12.194 716.547 12.194Z" fill="#031323"/>
|
||||
<path d="M808.856 51.5899C809.012 48.3069 809.012 44.0859 809.012 42.2099C809.012 36.7382 806.507 34.5496 803.061 34.5496C797.58 34.5496 777.729 38.1452 777.729 41.2719C777.729 42.0536 778.199 42.8352 779.765 42.8352H781.45C791.473 42.8352 791.629 58.1559 791.629 77.6975V85.2015C791.629 115.843 791.629 123.816 778.631 123.972C776.752 123.972 775.812 125.066 775.812 126.161C775.812 127.099 776.595 128.037 778.161 128.037H821.228C822.794 128.037 823.577 127.099 823.577 126.161C823.577 125.066 822.637 123.972 820.601 123.972C810.892 123.972 810.578 120.533 809.326 111.153C808.699 106.775 808.386 95.6758 808.386 85.2015V78.4791C808.386 70.9752 808.386 63.3148 808.543 58.1559C819.662 49.4012 825.926 43.6169 832.973 43.6169C840.803 43.6169 845.658 48.7759 845.658 81.6058C845.658 118.344 842.839 123.972 833.599 123.972C831.72 123.972 830.781 125.066 830.781 126.161C830.781 127.099 831.564 128.037 833.13 128.037H875.57C877.136 128.037 877.919 127.099 877.919 126.161C877.919 125.066 876.979 123.972 875.1 123.972C866.643 123.972 863.668 121.314 863.668 111.934V56.1235C863.668 42.6789 855.994 32.6736 842.996 32.6736C831.72 32.6736 823.577 39.2396 813.554 47.6816L808.856 51.5899Z" fill="#031323"/>
|
||||
<path d="M950.4 102.867C950.4 101.773 950.087 100.991 949.147 100.991C948.521 100.991 947.894 101.304 947.425 102.242C941.63 114.279 934.27 117.562 923.621 117.562C906.394 117.562 895.588 100.522 895.588 70.8188H940.847C947.581 70.8188 950.4 68.7865 950.4 63.1585C950.4 39.7086 933.33 32.6736 920.332 32.6736C891.516 32.6736 877.265 55.0292 877.265 83.9508C877.265 114.592 893.709 129.6 917.043 129.6C941.004 129.6 950.4 112.56 950.4 102.867ZM917.2 37.6762C926.283 37.6762 930.824 44.5549 930.824 58.9375C930.824 62.3768 929.885 64.4092 924.717 64.7218L895.901 66.7542C897.781 51.4335 904.045 37.6762 917.2 37.6762Z" fill="#031323"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1063.8 48.6H999V113.4H1063.8V48.6ZM982.8 32.4V129.6H1080V32.4H982.8Z" fill="#031323"/>
|
||||
</svg>
|
After Width: | Height: | Size: 8.4 KiB |
BIN
web/public/theoremone/logo.ico
Normal file
BIN
web/public/theoremone/logo.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
Loading…
Reference in New Issue
Block a user