Merge pull request #88 from quantified-uncertainty/embed-question-page
Embed question page
This commit is contained in:
		
						commit
						8fac309bf3
					
				|  | @ -22,7 +22,7 @@ const modelToQuestion = (model: any): ReturnType<typeof prepareQuestion> => { | |||
|     title: model.name, | ||||
|     url: `https://www.getguesstimate.com/models/${model.id}`, | ||||
|     // timestamp,
 | ||||
|     description, | ||||
|     description: description || "", | ||||
|     options: [], | ||||
|     qualityindicators: { | ||||
|       numforecasts: 1, | ||||
|  | @ -90,5 +90,5 @@ export const guesstimate: Platform & { | |||
|   search, | ||||
|   version: "v1", | ||||
|   fetchQuestion, | ||||
|   calculateStars: (q) => (q.description.length > 250 ? 2 : 1), | ||||
|   calculateStars: (q) => (q.description?.length > 250 ? 2 : 1), | ||||
| }; | ||||
|  |  | |||
							
								
								
									
										4
									
								
								src/pages/questions/embed/[id].tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/pages/questions/embed/[id].tsx
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,4 @@ | |||
| export { | ||||
|   default, | ||||
|   getServerSideProps, | ||||
| } from "../../../web/questions/pages/EmbedQuestionPage"; | ||||
							
								
								
									
										16
									
								
								src/web/questions/components/PlatformLink.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/web/questions/components/PlatformLink.tsx
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,16 @@ | |||
| import { FaExternalLinkAlt } from "react-icons/fa"; | ||||
| 
 | ||||
| import { QuestionFragment } from "../../fragments.generated"; | ||||
| 
 | ||||
| export const PlatformLink: React.FC<{ question: QuestionFragment }> = ({ | ||||
|   question, | ||||
| }) => ( | ||||
|   <a | ||||
|     className="px-2 py-1 border-2 border-gray-400 rounded-lg text-black no-underline text-normal hover:bg-gray-100 flex flex-nowrap space-x-1 items-center" | ||||
|     href={question.url} | ||||
|     target="_blank" | ||||
|   > | ||||
|     <span>{question.platform.label}</span> | ||||
|     <FaExternalLinkAlt className="text-gray-400 inline sm:text-md text-md" /> | ||||
|   </a> | ||||
| ); | ||||
|  | @ -0,0 +1,19 @@ | |||
| import { QuestionWithHistoryFragment } from "../../fragments.generated"; | ||||
| import { HistoryChart } from "./HistoryChart"; | ||||
| 
 | ||||
| type Props = { | ||||
|   question: QuestionWithHistoryFragment; | ||||
| }; | ||||
| 
 | ||||
| export const QuestionChartOrVisualization: React.FC<Props> = ({ question }) => | ||||
|   question.platform.id === "guesstimate" && question.visualization ? ( | ||||
|     <a className="no-underline" href={question.url} target="_blank"> | ||||
|       <img | ||||
|         className="rounded-sm" | ||||
|         src={question.visualization} | ||||
|         alt="Guesstimate Screenshot" | ||||
|       /> | ||||
|     </a> | ||||
|   ) : question.options.length > 0 ? ( | ||||
|     <HistoryChart question={question} /> | ||||
|   ) : null; /* Don't display chart if there are no options, for now. */ | ||||
							
								
								
									
										20
									
								
								src/web/questions/components/QuestionInfoRow.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/web/questions/components/QuestionInfoRow.tsx
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,20 @@ | |||
| import { QuestionFragment } from "../../fragments.generated"; | ||||
| import { PlatformLink } from "./PlatformLink"; | ||||
| import { QuestionOptions } from "./QuestionOptions"; | ||||
| import { Stars } from "./Stars"; | ||||
| 
 | ||||
| type Props = { | ||||
|   question: QuestionFragment; | ||||
| }; | ||||
| 
 | ||||
| export const QuestionInfoRow: React.FC<Props> = ({ question }) => ( | ||||
|   <div className="flex items-center gap-2"> | ||||
|     <PlatformLink question={question} /> | ||||
|     <Stars num={question.qualityIndicators.stars} /> | ||||
|     <QuestionOptions | ||||
|       question={{ ...question }} | ||||
|       maxNumOptions={1} | ||||
|       forcePrimaryMode={true} | ||||
|     /> | ||||
|   </div> | ||||
| ); | ||||
							
								
								
									
										26
									
								
								src/web/questions/components/QuestionTitle.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/web/questions/components/QuestionTitle.tsx
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | |||
| import { QuestionFragment } from "../../fragments.generated"; | ||||
| import { getBasePath } from "../../utils"; | ||||
| 
 | ||||
| type Props = { | ||||
|   question: QuestionFragment; | ||||
|   linkToMetaforecast?: boolean; | ||||
| }; | ||||
| 
 | ||||
| export const QuestionTitle: React.FC<Props> = ({ | ||||
|   question, | ||||
|   linkToMetaforecast, | ||||
| }) => ( | ||||
|   <h1 className="sm:text-3xl text-xl"> | ||||
|     <a | ||||
|       className="text-black no-underline hover:text-gray-700" | ||||
|       href={ | ||||
|         linkToMetaforecast | ||||
|           ? getBasePath() + `/questions/${question.id}` | ||||
|           : question.url | ||||
|       } | ||||
|       target="_blank" | ||||
|     > | ||||
|       {question.title} | ||||
|     </a> | ||||
|   </h1> | ||||
| ); | ||||
							
								
								
									
										63
									
								
								src/web/questions/pages/EmbedQuestionPage.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/web/questions/pages/EmbedQuestionPage.tsx
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,63 @@ | |||
| import { GetServerSideProps, NextPage } from "next"; | ||||
| import NextError from "next/error"; | ||||
| 
 | ||||
| import { Query } from "../../common/Query"; | ||||
| import { ssrUrql } from "../../urql"; | ||||
| import { QuestionChartOrVisualization } from "../components/QuestionChartOrVisualization"; | ||||
| import { QuestionInfoRow } from "../components/QuestionInfoRow"; | ||||
| import { QuestionTitle } from "../components/QuestionTitle"; | ||||
| import { QuestionPageDocument } from "../queries.generated"; | ||||
| 
 | ||||
| interface Props { | ||||
|   id: string; | ||||
| } | ||||
| 
 | ||||
| export const getServerSideProps: GetServerSideProps<Props> = async ( | ||||
|   context | ||||
| ) => { | ||||
|   const [ssrCache, client] = ssrUrql(); | ||||
|   const id = context.query.id as string; | ||||
| 
 | ||||
|   const question = | ||||
|     (await client.query(QuestionPageDocument, { id }).toPromise()).data | ||||
|       ?.result || null; | ||||
| 
 | ||||
|   if (!question) { | ||||
|     context.res.statusCode = 404; | ||||
|   } | ||||
| 
 | ||||
|   return { | ||||
|     props: { | ||||
|       urqlState: ssrCache.extractData(), | ||||
|       id, | ||||
|     }, | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| const EmbedQuestionPage: NextPage<Props> = ({ id }) => { | ||||
|   return ( | ||||
|     <div className="bg-white min-h-screen"> | ||||
|       <Query document={QuestionPageDocument} variables={{ id }}> | ||||
|         {({ data: { result: question } }) => | ||||
|           question ? ( | ||||
|             <div className="p-4"> | ||||
|               <QuestionTitle question={question} linkToMetaforecast={true} /> | ||||
| 
 | ||||
|               <div className="mb-5 mt-5"> | ||||
|                 <QuestionInfoRow question={question} /> | ||||
|               </div> | ||||
| 
 | ||||
|               <div className="mb-10"> | ||||
|                 <QuestionChartOrVisualization question={question} /> | ||||
|               </div> | ||||
|             </div> | ||||
|           ) : ( | ||||
|             <NextError statusCode={404} /> | ||||
|           ) | ||||
|         } | ||||
|       </Query> | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default EmbedQuestionPage; | ||||
|  | @ -1,19 +1,20 @@ | |||
| import { GetServerSideProps, NextPage } from "next"; | ||||
| import NextError from "next/error"; | ||||
| import { FaExternalLinkAlt } from "react-icons/fa"; | ||||
| import ReactMarkdown from "react-markdown"; | ||||
| 
 | ||||
| import { Card } from "../../common/Card"; | ||||
| import { CopyParagraph } from "../../common/CopyParagraph"; | ||||
| import { Layout } from "../../common/Layout"; | ||||
| import { LineHeader } from "../../common/LineHeader"; | ||||
| import { Query } from "../../common/Query"; | ||||
| import { QuestionWithHistoryFragment } from "../../fragments.generated"; | ||||
| import { ssrUrql } from "../../urql"; | ||||
| import { getBasePath } from "../../utils"; | ||||
| import { CaptureQuestion } from "../components/CaptureQuestion"; | ||||
| import { HistoryChart } from "../components/HistoryChart"; | ||||
| import { IndicatorsTable } from "../components/IndicatorsTable"; | ||||
| import { QuestionOptions } from "../components/QuestionOptions"; | ||||
| import { Stars } from "../components/Stars"; | ||||
| import { QuestionChartOrVisualization } from "../components/QuestionChartOrVisualization"; | ||||
| import { QuestionInfoRow } from "../components/QuestionInfoRow"; | ||||
| import { QuestionTitle } from "../components/QuestionTitle"; | ||||
| import { QuestionPageDocument } from "../queries.generated"; | ||||
| 
 | ||||
| interface Props { | ||||
|  | @ -49,58 +50,19 @@ const Section: React.FC<{ title: string }> = ({ title, children }) => ( | |||
|   </div> | ||||
| ); | ||||
| 
 | ||||
| const PlatformLink: React.FC<{ question: QuestionWithHistoryFragment }> = ({ | ||||
|   question, | ||||
| }) => ( | ||||
|   <a | ||||
|     className="px-2 py-1 border-2 border-gray-400 rounded-lg text-black no-underline text-normal hover:bg-gray-100 flex flex-nowrap space-x-1 items-center" | ||||
|     href={question.url} | ||||
|     target="_blank" | ||||
|   > | ||||
|     <span>{question.platform.label}</span> | ||||
|     <FaExternalLinkAlt className="text-gray-400 inline sm:text-md text-md" /> | ||||
|   </a> | ||||
| ); | ||||
| 
 | ||||
| const LargeQuestionCard: React.FC<{ | ||||
|   question: QuestionWithHistoryFragment; | ||||
| }> = ({ question }) => { | ||||
|   return ( | ||||
|     <Card highlightOnHover={false} large={true}> | ||||
|       <h1 className="sm:text-3xl text-xl"> | ||||
|         <a | ||||
|           className="text-black no-underline hover:text-gray-700" | ||||
|           href={question.url} | ||||
|           target="_blank" | ||||
|         > | ||||
|           {question.title} | ||||
|         </a> | ||||
|       </h1> | ||||
|       <QuestionTitle question={question} /> | ||||
| 
 | ||||
|       <div className="flex items-center gap-2 mb-5 mt-5"> | ||||
|         <PlatformLink question={question} /> | ||||
|         <Stars num={question.qualityIndicators.stars} /> | ||||
|         <QuestionOptions | ||||
|           question={{ ...question }} | ||||
|           maxNumOptions={1} | ||||
|           forcePrimaryMode={true} | ||||
|         /> | ||||
|       <div className="mb-5 mt-5"> | ||||
|         <QuestionInfoRow question={question} /> | ||||
|       </div> | ||||
| 
 | ||||
|       <div className="mb-10"> | ||||
|         { | ||||
|           question.platform.id === "guesstimate" && question.visualization ? ( | ||||
|             <a className="no-underline" href={question.url} target="_blank"> | ||||
|               <img | ||||
|                 className="rounded-sm" | ||||
|                 src={question.visualization} | ||||
|                 alt="Guesstimate Screenshot" | ||||
|               /> | ||||
|             </a> | ||||
|           ) : question.options.length > 0 ? ( | ||||
|             <HistoryChart question={question} /> | ||||
|           ) : null /* Don't display chart if there are no options, for now. */ | ||||
|         } | ||||
|         <QuestionChartOrVisualization question={question} /> | ||||
|       </div> | ||||
| 
 | ||||
|       <div className="mx-auto max-w-prose"> | ||||
|  | @ -131,6 +93,17 @@ const QuestionScreen: React.FC<{ question: QuestionWithHistoryFragment }> = ({ | |||
|         <h1>Capture</h1> | ||||
|       </LineHeader> | ||||
|       <CaptureQuestion question={question} /> | ||||
|       <LineHeader> | ||||
|         <h1>Embed</h1> | ||||
|       </LineHeader> | ||||
|       <div className="max-w-md mx-auto"> | ||||
|         <CopyParagraph | ||||
|           text={`<iframe src="${ | ||||
|             getBasePath() + `/questions/embed/${question.id}` | ||||
|           }" height="600" width="600" frameborder="0" />`}
 | ||||
|           buttonText="Copy HTML" | ||||
|         /> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| ); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user