This commit is contained in:
parent
b586d52f72
commit
9cd5c158e7
|
@ -2,12 +2,13 @@
|
||||||
"typescript.tsdk": "node_modules/typescript/lib",
|
"typescript.tsdk": "node_modules/typescript/lib",
|
||||||
"eslint.format.enable": true,
|
"eslint.format.enable": true,
|
||||||
"eslint.codeActionsOnSave.mode": "all",
|
"eslint.codeActionsOnSave.mode": "all",
|
||||||
|
"css.lint.validProperties": ["composes"],
|
||||||
"css.format.spaceAroundSelectorSeparator": true,
|
"css.format.spaceAroundSelectorSeparator": true,
|
||||||
"[css]": {
|
"[css]": {
|
||||||
"editor.suggest.insertMode": "replace",
|
"editor.suggest.insertMode": "replace",
|
||||||
"gitlens.codeLens.scopes": ["document"],
|
"gitlens.codeLens.scopes": ["document"],
|
||||||
"editor.formatOnSave": true,
|
"editor.formatOnSave": true,
|
||||||
"editor.defaultFormatter": "vscode.css-language-features"
|
"editor.defaultFormatter": "vscode.css-language-features",
|
||||||
},
|
},
|
||||||
"[javascript]": {
|
"[javascript]": {
|
||||||
"editor.formatOnSave": false,
|
"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
|
nextProps: WordCloudWordsProps
|
||||||
) => {
|
) => {
|
||||||
if (
|
if (
|
||||||
prevProps.tooltipLeft !== nextProps.tooltipLeft ||
|
// if width changes, rerender, else don't rerender for a tooltip change
|
||||||
|
prevProps.width === nextProps.width &&
|
||||||
|
(prevProps.tooltipLeft !== nextProps.tooltipLeft ||
|
||||||
prevProps.tooltipTop !== nextProps.tooltipTop ||
|
prevProps.tooltipTop !== nextProps.tooltipTop ||
|
||||||
nextProps.tooltipLeft === undefined ||
|
nextProps.tooltipLeft === undefined ||
|
||||||
nextProps.tooltipTop === undefined
|
nextProps.tooltipTop === undefined)
|
||||||
) {
|
) {
|
||||||
return true; // do not re-render
|
return true; // do not re-render
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,9 +21,9 @@
|
||||||
"@visx/group": "^2.10.0",
|
"@visx/group": "^2.10.0",
|
||||||
"@visx/scale": "^2.2.2",
|
"@visx/scale": "^2.2.2",
|
||||||
"@visx/shape": "^2.10.0",
|
"@visx/shape": "^2.10.0",
|
||||||
|
"@visx/text": "^2.10.0",
|
||||||
"@visx/tooltip": "^2.10.0",
|
"@visx/tooltip": "^2.10.0",
|
||||||
"@visx/wordcloud": "^2.10.0",
|
"@visx/wordcloud": "^2.10.0",
|
||||||
"@visx/text": "^2.10.0",
|
|
||||||
"next": "12.1.6",
|
"next": "12.1.6",
|
||||||
"react": "18.1.0",
|
"react": "18.1.0",
|
||||||
"react-dom": "18.1.0"
|
"react-dom": "18.1.0"
|
||||||
|
|
|
@ -73,7 +73,11 @@ h2 {
|
||||||
color: var(--primary-heading);
|
color: var(--primary-heading);
|
||||||
}
|
}
|
||||||
|
|
||||||
h3,
|
h3 {
|
||||||
|
color: var(--secondary-heading);
|
||||||
|
font-size: calc(45rem / 16);
|
||||||
|
}
|
||||||
|
|
||||||
h4,
|
h4,
|
||||||
h5,
|
h5,
|
||||||
h6 {
|
h6 {
|
||||||
|
@ -89,6 +93,10 @@ a:hover {
|
||||||
color: var(--link-hover);
|
color: var(--link-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: calc(28rem / 16);
|
||||||
|
}
|
||||||
|
|
||||||
@media only screen and (prefers-color-scheme: dark) {
|
@media only screen and (prefers-color-scheme: dark) {
|
||||||
body {
|
body {
|
||||||
--primary-background: var(--dark--primary-background);
|
--primary-background: var(--dark--primary-background);
|
||||||
|
|
|
@ -1,9 +1,20 @@
|
||||||
import type { AppProps } from "next/app";
|
import type { AppProps } from "next/app";
|
||||||
|
import Head from "next/head";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import "./_app.css";
|
import "./_app.css";
|
||||||
import "./font.css";
|
import "./font.css";
|
||||||
|
|
||||||
export default function App({ Component, pageProps }: AppProps): JSX.Element {
|
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 (
|
return (
|
||||||
<p>
|
<p>
|
||||||
Click <Link href="/playground">here</Link> to visit the playground
|
Click <Link href="/playground">here</Link> to visit the playground
|
||||||
|
<br />
|
||||||
|
Click <Link href="/samplePage">here</Link> to visit a sample page
|
||||||
</p>
|
</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…
Reference in New Issue