feat: css improvements

This commit is contained in:
Vyacheslav Matyukhin 2022-04-30 00:44:13 +04:00
parent 9507579a7a
commit 12a236186f
No known key found for this signature in database
GPG Key ID: 3D2A774C5489F96C
6 changed files with 189 additions and 188 deletions

View File

@ -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>
); );

View File

@ -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>

View File

@ -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>

View File

@ -143,94 +143,88 @@ export const HistoryChart: React.FC<Props> = ({ question }) => {
})); }));
return ( return (
<div className="flex justify-center items-center w-full"> <VictoryChart
<div className="w-10/12"> domainPadding={20}
<VictoryChart padding={padding}
domainPadding={20} theme={VictoryTheme.material}
padding={padding} height={height}
theme={VictoryTheme.material} width={width}
height={height} containerComponent={
width={width} <VictoryVoronoiContainer
containerComponent={ labels={({ datum }) => `Not shown`}
<VictoryVoronoiContainer labelComponent={
labels={({ datum }) => `Not shown`} <VictoryTooltip
labelComponent={ pointerLength={0}
<VictoryTooltip dy={-12}
pointerLength={0} text={({ datum }) =>
dy={-12} `${datum.name}: ${Math.round(datum.y * 100)}%`
text={({ datum }) =>
`${datum.name}: ${Math.round(datum.y * 100)}%`
}
style={{
fontSize: 15,
fill: "black",
strokeWidth: 0.05,
}}
flyoutStyle={{
stroke: "black",
fill: "white",
}}
cornerRadius={0}
flyoutPadding={7}
/>
}
voronoiBlacklist={
["line-0", "line-1", "line-2", "line-3", "line-4"]
//Array.from(Array(5).keys()).map((x, i) => `line${i}`)
// see: https://github.com/FormidableLabs/victory/issues/545
} }
style={{
fontSize: 15,
fill: "black",
strokeWidth: 0.05,
}}
flyoutStyle={{
stroke: "black",
fill: "white",
}}
cornerRadius={0}
flyoutPadding={7}
/> />
} }
domain={{ voronoiBlacklist={
y: [0, domainMax], ["line-0", "line-1", "line-2", "line-3", "line-4"]
}} //Array.from(Array(5).keys()).map((x, i) => `line${i}`)
> // see: https://github.com/FormidableLabs/victory/issues/545
<VictoryLegend }
x={width - labelLegendStart - letterLength * longestNameLength} />
y={height / 2 - 18 - (dataSetsLength - 1) * 13} }
orientation="vertical" domain={{
gutter={20} y: [0, domainMax],
style={{ border: { stroke: "white" }, labels: { fontSize: 15 } }} }}
data={legendData} >
/> <VictoryLegend
x={width - labelLegendStart - letterLength * longestNameLength}
y={height / 2 - 18 - (dataSetsLength - 1) * 13}
orientation="vertical"
gutter={20}
style={{ border: { stroke: "white" }, labels: { fontSize: 15 } }}
data={legendData}
/>
{dataSets {dataSets.slice(0, 5).map((dataset, i) => getVictoryGroup(dataset, i))}
.slice(0, 5) <VictoryAxis
.map((dataset, i) => getVictoryGroup(dataset, i))} // tickValues specifies both the number of ticks and where
<VictoryAxis // they are placed on the axis
// tickValues specifies both the number of ticks and where // tickValues={dataAsXy.map((datum) => datum.x)}
// they are placed on the axis // tickFormat={dataAsXy.map((datum) => datum.x)}
// tickValues={dataAsXy.map((datum) => datum.x)} tickCount={7}
// tickFormat={dataAsXy.map((datum) => datum.x)} style={{
tickCount={7} grid: { stroke: null, strokeWidth: 0.5 },
style={{ }}
grid: { stroke: null, strokeWidth: 0.5 }, //axisLabelComponent={
}} // <VictoryLabel dy={40} style={{ fontSize: 10, fill: "gray" }} />
//axisLabelComponent={ //}
// <VictoryLabel dy={40} style={{ fontSize: 10, fill: "gray" }} /> // label="Date (dd/mm/yy)"
//} tickLabelComponent={
// label="Date (dd/mm/yy)" <VictoryLabel
tickLabelComponent={ dy={10}
<VictoryLabel angle={-30}
dy={10} style={{ fontSize: 15, fill: "gray" }}
angle={-30}
style={{ fontSize: 15, fill: "gray" }}
/>
}
/> />
<VictoryAxis }
dependentAxis />
// tickFormat specifies how ticks should be displayed <VictoryAxis
tickFormat={(x) => `${x * 100}%`} dependentAxis
style={{ // tickFormat specifies how ticks should be displayed
grid: { stroke: "#D3D3D3", strokeWidth: 0.5 }, tickFormat={(x) => `${x * 100}%`}
}} style={{
tickLabelComponent={ grid: { stroke: "#D3D3D3", strokeWidth: 0.5 },
<VictoryLabel dy={0} style={{ fontSize: 15, fill: "gray" }} /> }}
} tickLabelComponent={
/> <VictoryLabel dy={0} style={{ fontSize: 15, fill: "gray" }} />
</VictoryChart> }
</div> />
</div> </VictoryChart>
); );
}; };

View 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>
);

View File

@ -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>
<HistoryChart question={question} /> <div className="max-w-3xl">
<HistoryChart question={question} />
<h2 className="pt-10 text-xl place-self-center w-full text-center text-gray-900">
Question description
</h2>
<ReactMarkdown
linkTarget="_blank"
className="font-normal text-gray-900 w-9/12"
>
{question.description.replaceAll("---", "")}
</ReactMarkdown>
<h2 className="pt-2 text-xl place-self-center w-full text-center text-gray-900">
Indicators
</h2>
<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>
<Section title="Question description">
<ReactMarkdown
linkTarget="_blank"
className="font-normal text-gray-900 max-w-prose"
>
{question.description.replaceAll("---", "")}
</ReactMarkdown>
</Section>
<Section title="Indicators">
<IndicatorsTable question={question} />
</Section>
</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">