Sample page and graph wrappers (#32)

histogram-component
Shahan Nedadahandeh 5 months ago
parent b586d52f72
commit 9cd5c158e7
  1. 3
      .vscode/settings.json
  2. 59
      components/ComponentWrapper.module.css
  3. 42
      components/ComponentWrapper.tsx
  4. 10
      components/WordCloud.tsx
  5. 2
      package.json
  6. 10
      pages/_app.css
  7. 13
      pages/_app.tsx
  8. 2
      pages/index.tsx
  9. 5
      pages/samplePage.module.css
  10. 127
      pages/samplePage.tsx
  11. 35
      utils/getWindowDimensions.ts
  12. 3
      utils/isMobile.ts

@ -2,12 +2,13 @@
"typescript.tsdk": "node_modules/typescript/lib",
"eslint.format.enable": true,
"eslint.codeActionsOnSave.mode": "all",
"css.lint.validProperties": ["composes"],
"css.format.spaceAroundSelectorSeparator": true,
"[css]": {
"editor.suggest.insertMode": "replace",
"gitlens.codeLens.scopes": ["document"],
"editor.formatOnSave": true,
"editor.defaultFormatter": "vscode.css-language-features"
"editor.defaultFormatter": "vscode.css-language-features",
},
"[javascript]": {
"editor.formatOnSave": false,

@ -0,0 +1,59 @@
.sideWrapperCommon {
background-color: var(--secondary-background);
display: flex;
padding: calc(40rem / 16) calc(50rem / 16);
margin: calc(65rem / 16) 0;
width: 90%;
}
.wrapperRight {
composes: sideWrapperCommon;
align-self: end;
margin-right: 0;
padding-right: 0;
border-radius: calc(200rem / 16) 0 0 calc(200rem / 16);
flex-direction: row-reverse;
padding-right: calc(50rem / 16);
}
.wrapperLeft {
composes: sideWrapperCommon;
align-self: start;
margin-left: 0;
padding-left: 0;
border-radius: 0 calc(200rem / 16) calc(200rem / 16) 0;
flex-direction: row;
padding-left: calc(50rem / 16);
}
.noBackground {
background: none;
align-self: center;
}
.wrapperCenter {
flex-direction: column;
text-align: center;
gap: calc(25rem / 16);
/* to match the 65px margin with the left/right variant:
add 45px bottom margin, since internal wrapper contributes 20px for the center component
0px top margin, since h3 contributes 45px and internal wrapper contributes 20px for the center component
*/
margin: 0 0 calc(45rem / 16) 0;
padding: 0 15%;
}
@media screen and (max-width: 768px) {
.sideWrapperCommon {
margin: auto;
flex-direction: column;
text-align: center;
padding: 0;
border-radius: 0;
width: 100%;
}
}
.internalWrapper {
padding: calc(20rem / 16);
}

@ -0,0 +1,42 @@
import React from "react";
import styles from "./ComponentWrapper.module.css";
type AlignOption = "left" | "center" | "right";
type ComponentWrapperProps = {
children: React.ReactNode;
heading: string;
bodyText: string;
align?: AlignOption;
noBackground?: boolean;
};
export function ComponentWrapper({
heading,
bodyText,
children,
align = "left",
noBackground = false,
}: ComponentWrapperProps) {
const alignClasses: { [key in AlignOption]: string } = {
left: styles.wrapperLeft,
center: styles.wrapperCenter,
right: styles.wrapperRight,
};
return (
<div
className={`
${alignClasses[align]}
${noBackground ? styles.noBackground : ""}
`}
>
<div className={styles.internalWrapper}>
<h3>{heading}</h3>
<p>{bodyText}</p>
</div>
<div className={styles.internalWrapper}>{children}</div>
</div>
);
}

@ -197,10 +197,12 @@ const shouldNotRerender = (
nextProps: WordCloudWordsProps
) => {
if (
prevProps.tooltipLeft !== nextProps.tooltipLeft ||
prevProps.tooltipTop !== nextProps.tooltipTop ||
nextProps.tooltipLeft === undefined ||
nextProps.tooltipTop === undefined
// if width changes, rerender, else don't rerender for a tooltip change
prevProps.width === nextProps.width &&
(prevProps.tooltipLeft !== nextProps.tooltipLeft ||
prevProps.tooltipTop !== nextProps.tooltipTop ||
nextProps.tooltipLeft === undefined ||
nextProps.tooltipTop === undefined)
) {
return true; // do not re-render
}

@ -21,9 +21,9 @@
"@visx/group": "^2.10.0",
"@visx/scale": "^2.2.2",
"@visx/shape": "^2.10.0",
"@visx/text": "^2.10.0",
"@visx/tooltip": "^2.10.0",
"@visx/wordcloud": "^2.10.0",
"@visx/text": "^2.10.0",
"next": "12.1.6",
"react": "18.1.0",
"react-dom": "18.1.0"

@ -73,7 +73,11 @@ h2 {
color: var(--primary-heading);
}
h3,
h3 {
color: var(--secondary-heading);
font-size: calc(45rem / 16);
}
h4,
h5,
h6 {
@ -89,6 +93,10 @@ a:hover {
color: var(--link-hover);
}
p {
font-size: calc(28rem / 16);
}
@media only screen and (prefers-color-scheme: dark) {
body {
--primary-background: var(--dark--primary-background);

@ -1,9 +1,20 @@
import type { AppProps } from "next/app";
import Head from "next/head";
import React from "react";
import "./_app.css";
import "./font.css";
export default function App({ Component, pageProps }: AppProps): JSX.Element {
return <Component {...pageProps} />;
return (
<>
<Head>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0,user-scalable=0"
/>
</Head>
<Component {...pageProps} />
</>
);
}

@ -5,6 +5,8 @@ export default function Home() {
return (
<p>
Click <Link href="/playground">here</Link> to visit the playground
<br />
Click <Link href="/samplePage">here</Link> to visit a sample page
</p>
);
}

@ -0,0 +1,5 @@
.page {
display: flex;
flex-direction: column;
justify-content: center;
}

@ -0,0 +1,127 @@
import { BarGraphHorizontal, BarGraphVertical } from "components/BarGraph";
import { mockCategoricalData, moreMockCategoricalData } from "data/mocks";
import React from "react";
import { useWindowDimensions } from "utils/getWindowDimensions";
import { useIsMobile } from "utils/isMobile";
import { ComponentWrapper } from "@/components/ComponentWrapper";
import { WordCloud } from "../components/WordCloud";
import styles from "./samplePage.module.css";
export default function SamplePage() {
const { width } = useWindowDimensions();
const isMobile = useIsMobile();
return (
<div className={styles.page}>
<ComponentWrapper
heading="What program are you in?"
bodyText="There are a total of 106 respondents of the CS Class Profile. Interestingly, there are a huge number of students that are just in CS, partially due to the overwhelming number of people in CS as seen in the total demographics."
>
<BarGraphVertical
data={mockCategoricalData}
// For components that are in the side wrappers, it looks better if they fill a certain amount of width, so we can make the width dynamic like this
width={isMobile ? width / 1.25 : width / 2}
height={500}
margin={{
top: 20,
bottom: 80,
left: 60,
right: 20,
}}
/>
</ComponentWrapper>
<ComponentWrapper
heading="What program are you in?"
bodyText="There are a total of 106 respondents of the CS Class Profile. Interestingly, there are a huge number of students that are just in CS, partially due to the overwhelming number of people in CS as seen in the total demographics."
align="center"
>
<WordCloud
data={moreMockCategoricalData.map((word) => ({
text: word.key,
value: word.value,
}))}
// For components that we don't want to match the width necessarily we can provide direct values
width={isMobile ? width / 1.5 : 800}
height={500}
/>
</ComponentWrapper>
<ComponentWrapper
heading="What program are you in?"
bodyText="There are a total of 106 respondents of the CS Class Profile. Interestingly, there are a huge number of students that are just in CS, partially due to the overwhelming number of people in CS as seen in the total demographics."
align="right"
>
<BarGraphHorizontal
className={styles.barGraphDemo}
data={mockCategoricalData}
width={isMobile ? width / 1.45 : width / 2}
height={500}
margin={{
top: 20,
bottom: 40,
left: 150,
right: 20,
}}
/>
</ComponentWrapper>
<ComponentWrapper
heading="What program are you in?"
bodyText="There are a total of 106 respondents of the CS Class Profile. Interestingly, there are a huge number of students that are just in CS, partially due to the overwhelming number of people in CS as seen in the total demographics."
align="left"
noBackground
>
<BarGraphHorizontal
className={styles.barGrapDemo}
data={mockCategoricalData}
width={isMobile ? width / 1.45 : width / 2}
height={500}
margin={{
top: 20,
bottom: 40,
left: 150,
right: 20,
}}
/>
</ComponentWrapper>
<ComponentWrapper
heading="What program are you in?"
bodyText="There are a total of 106 respondents of the CS Class Profile. Interestingly, there are a huge number of students that are just in CS, partially due to the overwhelming number of people in CS as seen in the total demographics."
>
<BarGraphHorizontal
className={styles.barGraphDemo}
data={mockCategoricalData}
width={isMobile ? width / 1.45 : width / 2}
height={500}
margin={{
top: 20,
bottom: 40,
left: 150,
right: 20,
}}
/>
</ComponentWrapper>
<ComponentWrapper
heading="What program are you in?"
bodyText="There are a total of 106 respondents of the CS Class Profile. Interestingly, there are a huge number of students that are just in CS, partially due to the overwhelming number of people in CS as seen in the total demographics."
align="left"
noBackground
>
<WordCloud
data={moreMockCategoricalData.map((word) => ({
text: word.key,
value: word.value,
}))}
width={isMobile ? width / 1.5 : width / 2}
height={500}
/>
</ComponentWrapper>
</div>
);
}

@ -0,0 +1,35 @@
// Attribution: https://stackoverflow.com/questions/36862334/get-viewport-window-height-in-reactjs
import { useState, useEffect } from "react";
type WindowDimensions = {
width: number;
height: number;
};
const getWindowDimensions = (): WindowDimensions => {
const { innerWidth, innerHeight } = window;
return {
width: innerWidth,
height: innerHeight,
};
};
export const useWindowDimensions = (): WindowDimensions => {
const [windowDimensions, setWindowDimensions] = useState<WindowDimensions>({
width: 0,
height: 0,
});
const handleResize = () => {
setWindowDimensions(getWindowDimensions());
};
useEffect(() => {
handleResize();
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
return windowDimensions;
};

@ -0,0 +1,3 @@
import { useWindowDimensions } from "./getWindowDimensions";
export const useIsMobile = () => useWindowDimensions().width <= 768;
Loading…
Cancel
Save