feat: css improvements
This commit is contained in:
parent
9507579a7a
commit
12a236186f
|
@ -31,10 +31,12 @@ Also note that, whatever other redeeming features they might have, prediction ma
|
||||||
const AboutPage: NextPage = () => {
|
const AboutPage: NextPage = () => {
|
||||||
return (
|
return (
|
||||||
<Layout page="about">
|
<Layout page="about">
|
||||||
<Card highlightOnHover={false}>
|
<Card highlightOnHover={false} large={true}>
|
||||||
<div className="p-4">
|
<ReactMarkdown
|
||||||
<ReactMarkdown remarkPlugins={[gfm]} children={readmeMarkdownText} />
|
remarkPlugins={[gfm]}
|
||||||
</div>
|
children={readmeMarkdownText}
|
||||||
|
className="max-w-prose mx-auto"
|
||||||
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,17 +4,22 @@ const CardTitle: React.FC = ({ children }) => (
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
highlightOnHover?: boolean;
|
highlightOnHover?: boolean;
|
||||||
|
large?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
type CardType = React.FC<Props> & {
|
type CardType = React.FC<Props> & {
|
||||||
Title: typeof CardTitle;
|
Title: typeof CardTitle;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Card: CardType = ({ children, highlightOnHover = true }) => (
|
export const Card: CardType = ({
|
||||||
|
children,
|
||||||
|
large = false,
|
||||||
|
highlightOnHover = true,
|
||||||
|
}) => (
|
||||||
<div
|
<div
|
||||||
className={`h-full px-4 py-3 bg-white rounded-md shadow ${
|
className={`h-full bg-white rounded-md shadow ${
|
||||||
highlightOnHover ? "hover:bg-gray-100" : ""
|
highlightOnHover ? "hover:bg-gray-100" : ""
|
||||||
}`}
|
} ${large ? "p-5 sm:p-10" : "px-4 py-3"}`}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -151,7 +151,7 @@ export const Layout: React.FC<Props> = ({ page, children }) => {
|
||||||
</nav>
|
</nav>
|
||||||
<main>
|
<main>
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<div className="container max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pt-5">
|
<div className="container max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pt-5 mb-10">
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
|
|
|
@ -143,8 +143,6 @@ export const HistoryChart: React.FC<Props> = ({ question }) => {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex justify-center items-center w-full">
|
|
||||||
<div className="w-10/12">
|
|
||||||
<VictoryChart
|
<VictoryChart
|
||||||
domainPadding={20}
|
domainPadding={20}
|
||||||
padding={padding}
|
padding={padding}
|
||||||
|
@ -194,9 +192,7 @@ export const HistoryChart: React.FC<Props> = ({ question }) => {
|
||||||
data={legendData}
|
data={legendData}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{dataSets
|
{dataSets.slice(0, 5).map((dataset, i) => getVictoryGroup(dataset, i))}
|
||||||
.slice(0, 5)
|
|
||||||
.map((dataset, i) => getVictoryGroup(dataset, i))}
|
|
||||||
<VictoryAxis
|
<VictoryAxis
|
||||||
// tickValues specifies both the number of ticks and where
|
// tickValues specifies both the number of ticks and where
|
||||||
// they are placed on the axis
|
// they are placed on the axis
|
||||||
|
@ -230,7 +226,5 @@ export const HistoryChart: React.FC<Props> = ({ question }) => {
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</VictoryChart>
|
</VictoryChart>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
69
src/web/questions/components/IndicatorsTable.tsx
Normal file
69
src/web/questions/components/IndicatorsTable.tsx
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
import {
|
||||||
|
formatIndicatorValue, qualityIndicatorLabels, UsedIndicatorName
|
||||||
|
} from "../../display/DisplayQuestion/QuestionFooter";
|
||||||
|
import { Stars } from "../../display/Stars";
|
||||||
|
import { QuestionFragment } from "../../fragments.generated";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
question: QuestionFragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TableRow: React.FC<{ title: string }> = ({ title, children }) => (
|
||||||
|
<tr className="border-b">
|
||||||
|
<th
|
||||||
|
scope="row"
|
||||||
|
className="px-6 py-4 font-medium text-gray-900 whitespace-nowrap"
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</th>
|
||||||
|
<td className="px-6 py-4">{children}</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const IndicatorsTable: React.FC<Props> = ({ question }) => (
|
||||||
|
<div className="relative overflow-x-auto shadow-md sm:rounded-lg">
|
||||||
|
<table className="w-full text-sm text-left text-gray-500">
|
||||||
|
<thead className="text-xs text-gray-700 uppercase bg-gray-100">
|
||||||
|
<tr>
|
||||||
|
<th scope="col" className="px-6 py-3">
|
||||||
|
Indicator
|
||||||
|
</th>
|
||||||
|
<th scope="col" className="px-6 py-3">
|
||||||
|
Value
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<TableRow title="Stars">
|
||||||
|
<Stars num={question.qualityIndicators.stars} />
|
||||||
|
</TableRow>
|
||||||
|
<TableRow title="Platform">{question.platform.label}</TableRow>
|
||||||
|
{question.qualityIndicators.numForecasts ? (
|
||||||
|
<TableRow title="Number of forecasts">
|
||||||
|
{question.qualityIndicators.numForecasts}
|
||||||
|
</TableRow>
|
||||||
|
) : null}
|
||||||
|
{Object.keys(question.qualityIndicators)
|
||||||
|
.filter(
|
||||||
|
(indicator) =>
|
||||||
|
question.qualityIndicators[indicator] != null &&
|
||||||
|
!!qualityIndicatorLabels[indicator]
|
||||||
|
)
|
||||||
|
.map((indicator: UsedIndicatorName) => {
|
||||||
|
return (
|
||||||
|
<TableRow
|
||||||
|
title={qualityIndicatorLabels[indicator]}
|
||||||
|
key={indicator}
|
||||||
|
>
|
||||||
|
{formatIndicatorValue(
|
||||||
|
question.qualityIndicators[indicator],
|
||||||
|
indicator,
|
||||||
|
question.platform.id
|
||||||
|
)}
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
);
|
|
@ -5,15 +5,12 @@ import ReactMarkdown from "react-markdown";
|
||||||
import { Query } from "../../common/Query";
|
import { Query } from "../../common/Query";
|
||||||
import { Card } from "../../display/Card";
|
import { Card } from "../../display/Card";
|
||||||
import { DisplayOneQuestionForCapture } from "../../display/DisplayOneQuestionForCapture";
|
import { DisplayOneQuestionForCapture } from "../../display/DisplayOneQuestionForCapture";
|
||||||
import {
|
|
||||||
formatIndicatorValue, qualityIndicatorLabels, UsedIndicatorName
|
|
||||||
} from "../../display/DisplayQuestion/QuestionFooter";
|
|
||||||
import { Layout } from "../../display/Layout";
|
import { Layout } from "../../display/Layout";
|
||||||
import { LineHeader } from "../../display/LineHeader";
|
import { LineHeader } from "../../display/LineHeader";
|
||||||
import { Stars } from "../../display/Stars";
|
|
||||||
import { QuestionWithHistoryFragment } from "../../fragments.generated";
|
import { QuestionWithHistoryFragment } from "../../fragments.generated";
|
||||||
import { ssrUrql } from "../../urql";
|
import { ssrUrql } from "../../urql";
|
||||||
import { HistoryChart } from "../components/HistoryChart";
|
import { HistoryChart } from "../components/HistoryChart";
|
||||||
|
import { IndicatorsTable } from "../components/IndicatorsTable";
|
||||||
import { QuestionPageDocument } from "../queries.generated";
|
import { QuestionPageDocument } from "../queries.generated";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
@ -42,11 +39,18 @@ export const getServerSideProps: GetServerSideProps<Props> = async (
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Section: React.FC<{ title: string }> = ({ title, children }) => (
|
||||||
|
<div className="space-y-4 flex flex-col items-center">
|
||||||
|
<h2 className="text-xl text-gray-900">{title}</h2>
|
||||||
|
<div>{children}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
const QuestionCardContents: React.FC<{
|
const QuestionCardContents: React.FC<{
|
||||||
question: QuestionWithHistoryFragment;
|
question: QuestionWithHistoryFragment;
|
||||||
}> = ({ question }) => (
|
}> = ({ question }) => (
|
||||||
<div className="grid grid-cols-1 space-y-4 place-items-center">
|
<div className="flex flex-col space-y-8 items-center pt-5">
|
||||||
<h1 className="text-4xl place-self-center w-full text-center mt-10 pl-5 pr-5">
|
<h1 className="sm:text-4xl text-2xl text-center">
|
||||||
<a
|
<a
|
||||||
className="text-black no-underline hover:text-gray-600"
|
className="text-black no-underline hover:text-gray-600"
|
||||||
href={question.url}
|
href={question.url}
|
||||||
|
@ -56,106 +60,33 @@ const QuestionCardContents: React.FC<{
|
||||||
<FaExternalLinkAlt className="text-gray-400 inline" size="24" />
|
<FaExternalLinkAlt className="text-gray-400 inline" size="24" />
|
||||||
</a>
|
</a>
|
||||||
</h1>
|
</h1>
|
||||||
|
<div className="max-w-3xl">
|
||||||
<HistoryChart question={question} />
|
<HistoryChart question={question} />
|
||||||
|
</div>
|
||||||
|
|
||||||
<h2 className="pt-10 text-xl place-self-center w-full text-center text-gray-900">
|
<Section title="Question description">
|
||||||
Question description
|
|
||||||
</h2>
|
|
||||||
<ReactMarkdown
|
<ReactMarkdown
|
||||||
linkTarget="_blank"
|
linkTarget="_blank"
|
||||||
className="font-normal text-gray-900 w-9/12"
|
className="font-normal text-gray-900 max-w-prose"
|
||||||
>
|
>
|
||||||
{question.description.replaceAll("---", "")}
|
{question.description.replaceAll("---", "")}
|
||||||
</ReactMarkdown>
|
</ReactMarkdown>
|
||||||
|
</Section>
|
||||||
|
|
||||||
<h2 className="pt-2 text-xl place-self-center w-full text-center text-gray-900">
|
<Section title="Indicators">
|
||||||
Indicators
|
<IndicatorsTable question={question} />
|
||||||
</h2>
|
</Section>
|
||||||
<div className="relative overflow-x-auto shadow-md sm:rounded-lg">
|
|
||||||
<table className="w-full text-sm text-left text-gray-500">
|
|
||||||
<thead className="text-xs text-gray-700 uppercase bg-gray-100">
|
|
||||||
<tr>
|
|
||||||
<th scope="col" className="px-6 py-3">
|
|
||||||
Indicator
|
|
||||||
</th>
|
|
||||||
<th scope="col" className="px-6 py-3">
|
|
||||||
Value
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr className="border-b">
|
|
||||||
<th
|
|
||||||
scope="row"
|
|
||||||
className="px-6 py-4 font-medium text-gray-900 whitespace-nowrap"
|
|
||||||
>
|
|
||||||
Stars
|
|
||||||
</th>
|
|
||||||
<td className="px-6 py-4">
|
|
||||||
<Stars num={question.qualityIndicators.stars} />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr className="border-b">
|
|
||||||
<th
|
|
||||||
scope="row"
|
|
||||||
className="px-6 py-4 font-medium text-gray-900 whitespace-nowrap"
|
|
||||||
>
|
|
||||||
Platform
|
|
||||||
</th>
|
|
||||||
<td className="px-6 py-4">{question.platform.label}</td>
|
|
||||||
</tr>
|
|
||||||
{question.qualityIndicators.numForecasts ? (
|
|
||||||
<tr className="border-b">
|
|
||||||
<th
|
|
||||||
scope="row"
|
|
||||||
className="px-6 py-4 font-medium text-gray-900 whitespace-nowrap"
|
|
||||||
>
|
|
||||||
Number of forecasts
|
|
||||||
</th>
|
|
||||||
<td className="px-6 py-4">
|
|
||||||
{question.qualityIndicators.numForecasts}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
) : null}
|
|
||||||
{Object.keys(question.qualityIndicators)
|
|
||||||
.filter(
|
|
||||||
(indicator) =>
|
|
||||||
question.qualityIndicators[indicator] != null &&
|
|
||||||
!!qualityIndicatorLabels[indicator]
|
|
||||||
)
|
|
||||||
.map((indicator: UsedIndicatorName) => {
|
|
||||||
return (
|
|
||||||
<tr className="bg-white border-b" key={indicator}>
|
|
||||||
<th
|
|
||||||
scope="row"
|
|
||||||
className="px-6 py-4 font-medium text-gray-900 whitespace-nowrap"
|
|
||||||
>
|
|
||||||
{qualityIndicatorLabels[indicator]}
|
|
||||||
</th>
|
|
||||||
<td className="px-6 py-4">
|
|
||||||
{formatIndicatorValue(
|
|
||||||
question.qualityIndicators[indicator],
|
|
||||||
indicator,
|
|
||||||
question.platform.id
|
|
||||||
)}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
const QuestionPage: NextPage<Props> = ({ id }) => {
|
const QuestionPage: NextPage<Props> = ({ id }) => {
|
||||||
return (
|
return (
|
||||||
<Layout page="question">
|
<Layout page="question">
|
||||||
<div className="max-w-4xl mx-auto mb-5">
|
<div className="max-w-4xl mx-auto">
|
||||||
<Query document={QuestionPageDocument} variables={{ id }}>
|
<Query document={QuestionPageDocument} variables={{ id }}>
|
||||||
{({ data }) => (
|
{({ data }) => (
|
||||||
<div className="space-y-8">
|
<div className="space-y-8">
|
||||||
<Card highlightOnHover={false}>
|
<Card highlightOnHover={false} large={true}>
|
||||||
<QuestionCardContents question={data.result} />
|
<QuestionCardContents question={data.result} />
|
||||||
</Card>
|
</Card>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
|
|
Loading…
Reference in New Issue
Block a user