feat: embed question pages
This commit is contained in:
parent
19779bca02
commit
addf87b22a
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