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 = () => { | ||||
|   return ( | ||||
|     <Layout page="about"> | ||||
|       <Card highlightOnHover={false}> | ||||
|         <div className="p-4"> | ||||
|           <ReactMarkdown remarkPlugins={[gfm]} children={readmeMarkdownText} /> | ||||
|         </div> | ||||
|       <Card highlightOnHover={false} large={true}> | ||||
|         <ReactMarkdown | ||||
|           remarkPlugins={[gfm]} | ||||
|           children={readmeMarkdownText} | ||||
|           className="max-w-prose mx-auto" | ||||
|         /> | ||||
|       </Card> | ||||
|     </Layout> | ||||
|   ); | ||||
|  |  | |||
|  | @ -4,17 +4,22 @@ const CardTitle: React.FC = ({ children }) => ( | |||
| 
 | ||||
| interface Props { | ||||
|   highlightOnHover?: boolean; | ||||
|   large?: boolean; | ||||
| } | ||||
| 
 | ||||
| type CardType = React.FC<Props> & { | ||||
|   Title: typeof CardTitle; | ||||
| }; | ||||
| 
 | ||||
| export const Card: CardType = ({ children, highlightOnHover = true }) => ( | ||||
| export const Card: CardType = ({ | ||||
|   children, | ||||
|   large = false, | ||||
|   highlightOnHover = true, | ||||
| }) => ( | ||||
|   <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" : "" | ||||
|     }`}
 | ||||
|     } ${large ? "p-5 sm:p-10" : "px-4 py-3"}`}
 | ||||
|   > | ||||
|     {children} | ||||
|   </div> | ||||
|  |  | |||
|  | @ -151,7 +151,7 @@ export const Layout: React.FC<Props> = ({ page, children }) => { | |||
|         </nav> | ||||
|         <main> | ||||
|           <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} | ||||
|             </div> | ||||
|           </ErrorBoundary> | ||||
|  |  | |||
|  | @ -143,94 +143,88 @@ export const HistoryChart: React.FC<Props> = ({ question }) => { | |||
|   })); | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="flex justify-center items-center w-full"> | ||||
|       <div className="w-10/12"> | ||||
|         <VictoryChart | ||||
|           domainPadding={20} | ||||
|           padding={padding} | ||||
|           theme={VictoryTheme.material} | ||||
|           height={height} | ||||
|           width={width} | ||||
|           containerComponent={ | ||||
|             <VictoryVoronoiContainer | ||||
|               labels={({ datum }) => `Not shown`} | ||||
|               labelComponent={ | ||||
|                 <VictoryTooltip | ||||
|                   pointerLength={0} | ||||
|                   dy={-12} | ||||
|                   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
 | ||||
|     <VictoryChart | ||||
|       domainPadding={20} | ||||
|       padding={padding} | ||||
|       theme={VictoryTheme.material} | ||||
|       height={height} | ||||
|       width={width} | ||||
|       containerComponent={ | ||||
|         <VictoryVoronoiContainer | ||||
|           labels={({ datum }) => `Not shown`} | ||||
|           labelComponent={ | ||||
|             <VictoryTooltip | ||||
|               pointerLength={0} | ||||
|               dy={-12} | ||||
|               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} | ||||
|             /> | ||||
|           } | ||||
|           domain={{ | ||||
|             y: [0, domainMax], | ||||
|           }} | ||||
|         > | ||||
|           <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} | ||||
|           /> | ||||
|           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
 | ||||
|           } | ||||
|         /> | ||||
|       } | ||||
|       domain={{ | ||||
|         y: [0, domainMax], | ||||
|       }} | ||||
|     > | ||||
|       <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 | ||||
|             .slice(0, 5) | ||||
|             .map((dataset, i) => getVictoryGroup(dataset, i))} | ||||
|           <VictoryAxis | ||||
|             // tickValues specifies both the number of ticks and where
 | ||||
|             // they are placed on the axis
 | ||||
|             // tickValues={dataAsXy.map((datum) => datum.x)}
 | ||||
|             // tickFormat={dataAsXy.map((datum) => datum.x)}
 | ||||
|             tickCount={7} | ||||
|             style={{ | ||||
|               grid: { stroke: null, strokeWidth: 0.5 }, | ||||
|             }} | ||||
|             //axisLabelComponent={
 | ||||
|             //  <VictoryLabel dy={40} style={{ fontSize: 10, fill: "gray" }} />
 | ||||
|             //}
 | ||||
|             // label="Date (dd/mm/yy)"
 | ||||
|             tickLabelComponent={ | ||||
|               <VictoryLabel | ||||
|                 dy={10} | ||||
|                 angle={-30} | ||||
|                 style={{ fontSize: 15, fill: "gray" }} | ||||
|               /> | ||||
|             } | ||||
|       {dataSets.slice(0, 5).map((dataset, i) => getVictoryGroup(dataset, i))} | ||||
|       <VictoryAxis | ||||
|         // tickValues specifies both the number of ticks and where
 | ||||
|         // they are placed on the axis
 | ||||
|         // tickValues={dataAsXy.map((datum) => datum.x)}
 | ||||
|         // tickFormat={dataAsXy.map((datum) => datum.x)}
 | ||||
|         tickCount={7} | ||||
|         style={{ | ||||
|           grid: { stroke: null, strokeWidth: 0.5 }, | ||||
|         }} | ||||
|         //axisLabelComponent={
 | ||||
|         //  <VictoryLabel dy={40} style={{ fontSize: 10, fill: "gray" }} />
 | ||||
|         //}
 | ||||
|         // label="Date (dd/mm/yy)"
 | ||||
|         tickLabelComponent={ | ||||
|           <VictoryLabel | ||||
|             dy={10} | ||||
|             angle={-30} | ||||
|             style={{ fontSize: 15, fill: "gray" }} | ||||
|           /> | ||||
|           <VictoryAxis | ||||
|             dependentAxis | ||||
|             // tickFormat specifies how ticks should be displayed
 | ||||
|             tickFormat={(x) => `${x * 100}%`} | ||||
|             style={{ | ||||
|               grid: { stroke: "#D3D3D3", strokeWidth: 0.5 }, | ||||
|             }} | ||||
|             tickLabelComponent={ | ||||
|               <VictoryLabel dy={0} style={{ fontSize: 15, fill: "gray" }} /> | ||||
|             } | ||||
|           /> | ||||
|         </VictoryChart> | ||||
|       </div> | ||||
|     </div> | ||||
|         } | ||||
|       /> | ||||
|       <VictoryAxis | ||||
|         dependentAxis | ||||
|         // tickFormat specifies how ticks should be displayed
 | ||||
|         tickFormat={(x) => `${x * 100}%`} | ||||
|         style={{ | ||||
|           grid: { stroke: "#D3D3D3", strokeWidth: 0.5 }, | ||||
|         }} | ||||
|         tickLabelComponent={ | ||||
|           <VictoryLabel dy={0} style={{ fontSize: 15, fill: "gray" }} /> | ||||
|         } | ||||
|       /> | ||||
|     </VictoryChart> | ||||
|   ); | ||||
| }; | ||||
|  |  | |||
							
								
								
									
										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 { Card } from "../../display/Card"; | ||||
| import { DisplayOneQuestionForCapture } from "../../display/DisplayOneQuestionForCapture"; | ||||
| import { | ||||
|     formatIndicatorValue, qualityIndicatorLabels, UsedIndicatorName | ||||
| } from "../../display/DisplayQuestion/QuestionFooter"; | ||||
| import { Layout } from "../../display/Layout"; | ||||
| import { LineHeader } from "../../display/LineHeader"; | ||||
| import { Stars } from "../../display/Stars"; | ||||
| import { QuestionWithHistoryFragment } from "../../fragments.generated"; | ||||
| import { ssrUrql } from "../../urql"; | ||||
| import { HistoryChart } from "../components/HistoryChart"; | ||||
| import { IndicatorsTable } from "../components/IndicatorsTable"; | ||||
| import { QuestionPageDocument } from "../queries.generated"; | ||||
| 
 | ||||
| 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<{ | ||||
|   question: QuestionWithHistoryFragment; | ||||
| }> = ({ question }) => ( | ||||
|   <div className="grid grid-cols-1 space-y-4 place-items-center"> | ||||
|     <h1 className="text-4xl place-self-center w-full text-center mt-10 pl-5 pr-5"> | ||||
|   <div className="flex flex-col space-y-8 items-center pt-5"> | ||||
|     <h1 className="sm:text-4xl text-2xl text-center"> | ||||
|       <a | ||||
|         className="text-black no-underline hover:text-gray-600" | ||||
|         href={question.url} | ||||
|  | @ -56,106 +60,33 @@ const QuestionCardContents: React.FC<{ | |||
|         <FaExternalLinkAlt className="text-gray-400 inline" size="24" /> | ||||
|       </a> | ||||
|     </h1> | ||||
|     <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 className="max-w-3xl"> | ||||
|       <HistoryChart question={question} /> | ||||
|     </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> | ||||
| ); | ||||
| 
 | ||||
| const QuestionPage: NextPage<Props> = ({ id }) => { | ||||
|   return ( | ||||
|     <Layout page="question"> | ||||
|       <div className="max-w-4xl mx-auto mb-5"> | ||||
|       <div className="max-w-4xl mx-auto"> | ||||
|         <Query document={QuestionPageDocument} variables={{ id }}> | ||||
|           {({ data }) => ( | ||||
|             <div className="space-y-8"> | ||||
|               <Card highlightOnHover={false}> | ||||
|               <Card highlightOnHover={false} large={true}> | ||||
|                 <QuestionCardContents question={data.result} /> | ||||
|               </Card> | ||||
|               <div className="space-y-4"> | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user