noobify welcome demo (#699)
* noobify welcome * also beginning to add greyscale color scheme
This commit is contained in:
		
							parent
							
								
									87f6949d80
								
							
						
					
					
						commit
						ae2e7dfe30
					
				|  | @ -40,6 +40,7 @@ export type User = { | |||
|   referredByContractId?: string | ||||
|   referredByGroupId?: string | ||||
|   lastPingTime?: number | ||||
|   shouldShowWelcome?: boolean | ||||
| } | ||||
| 
 | ||||
| export const STARTING_BALANCE = ENV_CONFIG.startingBalance ?? 1000 | ||||
|  |  | |||
|  | @ -22,7 +22,7 @@ service cloud.firestore { | |||
|       allow read; | ||||
|       allow update: if resource.data.id == request.auth.uid | ||||
|                        && request.resource.data.diff(resource.data).affectedKeys() | ||||
|                                                                     .hasOnly(['bio', 'bannerUrl', 'website', 'twitterHandle', 'discordHandle', 'followedCategories', 'lastPingTime']); | ||||
|                                                                     .hasOnly(['bio', 'bannerUrl', 'website', 'twitterHandle', 'discordHandle', 'followedCategories', 'lastPingTime','shouldShowWelcome']); | ||||
|       // User referral rules | ||||
|       allow update: if resource.data.id == request.auth.uid | ||||
|                          && request.resource.data.diff(resource.data).affectedKeys() | ||||
|  |  | |||
|  | @ -77,6 +77,7 @@ export const createuser = newEndpoint(opts, async (req, auth) => { | |||
|     creatorVolumeCached: { daily: 0, weekly: 0, monthly: 0, allTime: 0 }, | ||||
|     followerCountCached: 0, | ||||
|     followedCategories: DEFAULT_CATEGORIES, | ||||
|     shouldShowWelcome: true, | ||||
|   } | ||||
| 
 | ||||
|   await firestore.collection('users').doc(auth.uid).create(user) | ||||
|  |  | |||
|  | @ -39,8 +39,10 @@ export function Button(props: { | |||
|         color === 'yellow' && 'bg-yellow-400 text-white hover:bg-yellow-500', | ||||
|         color === 'blue' && 'bg-blue-400 text-white hover:bg-blue-500', | ||||
|         color === 'indigo' && 'bg-indigo-500 text-white hover:bg-indigo-600', | ||||
|         color === 'gray' && 'bg-gray-100 text-gray-600 hover:bg-gray-200', | ||||
|         color === 'gray-white' && 'bg-white text-gray-500 hover:bg-gray-200', | ||||
|         color === 'gray' && | ||||
|           'bg-greyscale-1 text-greyscale-7 hover:bg-greyscale-2', | ||||
|         color === 'gray-white' && | ||||
|           'text-greyscale-6 hover:bg-greyscale-2 bg-white', | ||||
|         className | ||||
|       )} | ||||
|       disabled={disabled} | ||||
|  |  | |||
|  | @ -15,8 +15,8 @@ export function PillButton(props: { | |||
|       className={clsx( | ||||
|         'cursor-pointer select-none whitespace-nowrap rounded-full', | ||||
|         selected | ||||
|           ? ['text-white', color ?? 'bg-gray-700'] | ||||
|           : 'bg-gray-100 hover:bg-gray-200', | ||||
|           ? ['text-white', color ?? 'bg-greyscale-6'] | ||||
|           : 'bg-greyscale-2 hover:bg-greyscale-3', | ||||
|         big ? 'px-8 py-2' : 'px-3 py-1.5 text-sm' | ||||
|       )} | ||||
|       onClick={onSelect} | ||||
|  |  | |||
							
								
								
									
										173
									
								
								web/components/onboarding/welcome.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								web/components/onboarding/welcome.tsx
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,173 @@ | |||
| import { ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/solid' | ||||
| import clsx from 'clsx' | ||||
| import { useState } from 'react' | ||||
| import { useUser } from 'web/hooks/use-user' | ||||
| import { updateUser } from 'web/lib/firebase/users' | ||||
| import { Col } from '../layout/col' | ||||
| import { Modal } from '../layout/modal' | ||||
| import { Row } from '../layout/row' | ||||
| import { Title } from '../title' | ||||
| 
 | ||||
| export default function Welcome() { | ||||
|   const user = useUser() | ||||
|   const [open, setOpen] = useState(true) | ||||
|   const [page, setPage] = useState(0) | ||||
|   const TOTAL_PAGES = 4 | ||||
| 
 | ||||
|   function increasePage() { | ||||
|     if (page < TOTAL_PAGES - 1) { | ||||
|       setPage(page + 1) | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   function decreasePage() { | ||||
|     if (page > 0) { | ||||
|       setPage(page - 1) | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   async function setUserHasSeenWelcome() { | ||||
|     if (user) { | ||||
|       await updateUser(user.id, { ['shouldShowWelcome']: false }) | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   if (!user || !user.shouldShowWelcome) { | ||||
|     return <></> | ||||
|   } else | ||||
|     return ( | ||||
|       <Modal | ||||
|         open={open} | ||||
|         setOpen={(newOpen) => { | ||||
|           setUserHasSeenWelcome() | ||||
|           setOpen(newOpen) | ||||
|         }} | ||||
|       > | ||||
|         <Col className="h-[32rem] place-content-between rounded-md bg-white px-8 py-6 text-sm font-light md:h-[40rem] md:text-lg"> | ||||
|           {page === 0 && <Page0 />} | ||||
|           {page === 1 && <Page1 />} | ||||
|           {page === 2 && <Page2 />} | ||||
|           {page === 3 && <Page3 />} | ||||
|           <Col> | ||||
|             <Row className="place-content-between"> | ||||
|               <ChevronLeftIcon | ||||
|                 className={clsx( | ||||
|                   'h-10 w-10 text-gray-400 hover:text-gray-500', | ||||
|                   page === 0 ? 'disabled invisible' : '' | ||||
|                 )} | ||||
|                 onClick={decreasePage} | ||||
|               /> | ||||
|               <PageIndicator page={page} totalpages={TOTAL_PAGES} /> | ||||
|               <ChevronRightIcon | ||||
|                 className={clsx( | ||||
|                   'h-10 w-10 text-indigo-500 hover:text-indigo-600', | ||||
|                   page === TOTAL_PAGES - 1 ? 'disabled invisible' : '' | ||||
|                 )} | ||||
|                 onClick={increasePage} | ||||
|               /> | ||||
|             </Row> | ||||
|             <u | ||||
|               className="self-center text-xs text-gray-500" | ||||
|               onClick={() => { | ||||
|                 setOpen(false) | ||||
|                 setUserHasSeenWelcome() | ||||
|               }} | ||||
|             > | ||||
|               I got the gist, exit welcome | ||||
|             </u> | ||||
|           </Col> | ||||
|         </Col> | ||||
|       </Modal> | ||||
|     ) | ||||
| } | ||||
| 
 | ||||
| function PageIndicator(props: { page: number; totalpages: number }) { | ||||
|   const { page, totalpages } = props | ||||
|   return ( | ||||
|     <Row> | ||||
|       {[...Array(totalpages)].map((e, i) => ( | ||||
|         <div | ||||
|           className={clsx( | ||||
|             'mx-1.5 my-auto h-1.5 w-1.5 rounded-full', | ||||
|             i === page ? 'bg-indigo-500' : 'bg-gray-300' | ||||
|           )} | ||||
|         /> | ||||
|       ))} | ||||
|     </Row> | ||||
|   ) | ||||
| } | ||||
| 
 | ||||
| function Page0() { | ||||
|   return ( | ||||
|     <> | ||||
|       <img | ||||
|         className="h-2/3 w-2/3 place-self-center object-contain" | ||||
|         src="/welcome/manipurple.png" | ||||
|       /> | ||||
|       <Title className="text-center" text="Welcome to Manifold Markets!" /> | ||||
|       <p> | ||||
|         Manifold Markets is a place where anyone can ask a question about the | ||||
|         future. | ||||
|       </p> | ||||
|       <div className="mt-4">For example,</div> | ||||
|       <div className="mt-2 font-normal text-indigo-700"> | ||||
|         “Will Michelle Obama be the next president of the United States?” | ||||
|       </div> | ||||
|     </> | ||||
|   ) | ||||
| } | ||||
| 
 | ||||
| function Page1() { | ||||
|   return ( | ||||
|     <> | ||||
|       <p> | ||||
|         Your question becomes a prediction market that people can bet{' '} | ||||
|         <span className="font-normal text-indigo-700">mana (M$)</span> on. | ||||
|       </p> | ||||
|       <div className="mt-8 font-semibold">The core idea</div> | ||||
|       <div className="mt-2"> | ||||
|         If people have to put their mana where their mouth is, you’ll get a | ||||
|         pretty accurate answer! | ||||
|       </div> | ||||
|       <video loop autoPlay className="my-4 h-full w-full"> | ||||
|         <source src="/welcome/mana-example.mp4" type="video/mp4" /> | ||||
|         Your browser does not support video | ||||
|       </video> | ||||
|     </> | ||||
|   ) | ||||
| } | ||||
| 
 | ||||
| function Page2() { | ||||
|   return ( | ||||
|     <> | ||||
|       <p> | ||||
|         <span className="mt-4 font-normal text-indigo-700">Mana (M$)</span> is | ||||
|         the play money you bet with. You can also turn it into a real donation | ||||
|         to charity, at a 100:1 ratio. | ||||
|       </p> | ||||
|       <div className="mt-8 font-semibold">Example</div> | ||||
|       <p className="mt-2"> | ||||
|         When you donate <span className="font-semibold">M$1000</span> to | ||||
|         Givewell, Manifold sends them{' '} | ||||
|         <span className="font-semibold">$10 USD</span>. | ||||
|       </p> | ||||
|       <video loop autoPlay className="my-4 h-full w-full"> | ||||
|         <source src="/welcome/charity.mp4" type="video/mp4" /> | ||||
|         Your browser does not support video | ||||
|       </video> | ||||
|     </> | ||||
|   ) | ||||
| } | ||||
| 
 | ||||
| function Page3() { | ||||
|   return ( | ||||
|     <> | ||||
|       <img className="mx-auto object-contain" src="/welcome/treasure.png" /> | ||||
|       <Title className="mx-auto" text="Let's start predicting!" /> | ||||
|       <p className="mb-8"> | ||||
|         As a thank you for signing up, we’ve sent you{' '} | ||||
|         <span className="font-normal text-indigo-700">M$1000 Mana</span>{' '} | ||||
|       </p> | ||||
|     </> | ||||
|   ) | ||||
| } | ||||
|  | @ -5,7 +5,7 @@ export function Title(props: { text: string; className?: string }) { | |||
|   return ( | ||||
|     <h1 | ||||
|       className={clsx( | ||||
|         'my-4 inline-block text-2xl text-indigo-700 sm:my-6 sm:text-3xl', | ||||
|         'my-4 inline-block text-2xl font-normal text-indigo-700 sm:my-6 sm:text-3xl', | ||||
|         className | ||||
|       )} | ||||
|     > | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ import Script from 'next/script' | |||
| import { usePreserveScroll } from 'web/hooks/use-preserve-scroll' | ||||
| import { QueryClient, QueryClientProvider } from 'react-query' | ||||
| import { AuthProvider } from 'web/components/auth-context' | ||||
| import Welcome from 'web/components/onboarding/welcome' | ||||
| 
 | ||||
| function firstLine(msg: string) { | ||||
|   return msg.replace(/\r?\n.*/s, '') | ||||
|  | @ -78,9 +79,9 @@ function MyApp({ Component, pageProps }: AppProps) { | |||
|           content="width=device-width, initial-scale=1, maximum-scale=1" | ||||
|         /> | ||||
|       </Head> | ||||
| 
 | ||||
|       <AuthProvider> | ||||
|         <QueryClientProvider client={queryClient}> | ||||
|           <Welcome {...pageProps} /> | ||||
|           <Component {...pageProps} /> | ||||
|         </QueryClientProvider> | ||||
|       </AuthProvider> | ||||
|  |  | |||
|  | @ -242,6 +242,7 @@ export default function GroupPage(props: { | |||
|       href: groupPath(group.slug, 'about'), | ||||
|     }, | ||||
|   ] | ||||
| 
 | ||||
|   const tabIndex = tabs.map((t) => t.title).indexOf(page ?? GROUP_CHAT_SLUG) | ||||
| 
 | ||||
|   return ( | ||||
|  |  | |||
							
								
								
									
										
											BIN
										
									
								
								web/public/welcome/charity.mp4
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								web/public/welcome/charity.mp4
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								web/public/welcome/mana-example.mp4
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								web/public/welcome/mana-example.mp4
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								web/public/welcome/manipurple.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								web/public/welcome/manipurple.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 20 KiB | 
							
								
								
									
										
											BIN
										
									
								
								web/public/welcome/treasure.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								web/public/welcome/treasure.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 41 KiB | 
|  | @ -18,6 +18,15 @@ module.exports = { | |||
|       backgroundImage: { | ||||
|         'world-trading': "url('/world-trading-background.webp')", | ||||
|       }, | ||||
|       colors: { | ||||
|         'greyscale-1': '#FBFBFF', | ||||
|         'greyscale-2': '#E7E7F4', | ||||
|         'greyscale-3': '#D8D8EB', | ||||
|         'greyscale-4': '#B1B1C7', | ||||
|         'greyscale-5': '#9191A7', | ||||
|         'greyscale-6': '#66667C', | ||||
|         'greyscale-7': '#111140', | ||||
|       }, | ||||
|       typography: { | ||||
|         quoteless: { | ||||
|           css: { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user