Merge remote-tracking branch 'origin/main' into shahanneda/header
continuous-integration/drone/push Build is failing
Details
continuous-integration/drone/push Build is failing
Details
This commit is contained in:
commit
41e0ee0e87
|
@ -0,0 +1,59 @@
|
|||
.aboutWrapper {
|
||||
position: relative;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.about {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding: calc(45rem / 16);
|
||||
}
|
||||
|
||||
.about h1 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.about h4 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.about aside {
|
||||
flex: 1;
|
||||
margin-right: calc(40rem / 16);
|
||||
}
|
||||
|
||||
.about aside h1 {
|
||||
color: var(--secondary-accent)
|
||||
}
|
||||
|
||||
.about aside p {
|
||||
color: var(--primary-accent-lighter)
|
||||
}
|
||||
|
||||
.about article {
|
||||
flex: 3;
|
||||
}
|
||||
|
||||
.about article p {
|
||||
color: var(--primary-text);
|
||||
}
|
||||
|
||||
.angle {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: calc(70rem / 16);
|
||||
height: calc(70rem / 16);
|
||||
}
|
||||
|
||||
.anglePath {
|
||||
stroke: var(--primary-accent-light)
|
||||
}
|
||||
|
||||
.left.angle {
|
||||
transform: rotate(180deg);
|
||||
top: unset;
|
||||
left: unset;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
import React from "react";
|
||||
|
||||
import styles from "./About.module.css";
|
||||
|
||||
export function About() {
|
||||
return (
|
||||
<div className={styles.aboutWrapper}>
|
||||
<AngleDecoration isBottom={false} />
|
||||
<section className={styles.about}>
|
||||
<aside>
|
||||
<h1>About the Programs</h1>
|
||||
<p>Getting an overview of the CS programs in UW</p>
|
||||
</aside>
|
||||
<article>
|
||||
<h4>Computer Science</h4>
|
||||
<p>
|
||||
Offered from the Faculty of Mathematics as most commonly a co-op
|
||||
program, students usually attend 8 school and 6 co-op terms in their
|
||||
degree. However, CS is very flexible, as many students historically
|
||||
have dropped co-ops, taking terms off, and messing with their
|
||||
schedule to fit their desires.
|
||||
</p>
|
||||
<h4>Computing and Financial Management</h4>
|
||||
<p>
|
||||
Computing and Financial Management (CFM) combines the core CS
|
||||
courses with electives from areas such as accounting, economics, and
|
||||
financial management. This is a joint offer from the Faculty of
|
||||
Mathematics and the School of Accounting and Finance, and has the
|
||||
same schedule (and flexibility) as CS.
|
||||
</p>
|
||||
<h4>CS/BBA</h4>
|
||||
<p>
|
||||
Joint with Wilfrid Laurier University, the Business Administration
|
||||
and Computer Science Double Degree (CS/BBA) is an exclusive offering
|
||||
that allows students to get experience in CS as well as many
|
||||
subfields of business. There are 10 school terms and either 4 or 5
|
||||
co-op terms in the usual schedule, so it’s a bit more work than CS
|
||||
or CFM.
|
||||
</p>
|
||||
</article>
|
||||
</section>
|
||||
<AngleDecoration isBottom={true} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface AngleDecorationProps {
|
||||
isBottom: boolean;
|
||||
}
|
||||
|
||||
function AngleDecoration({ isBottom }: AngleDecorationProps) {
|
||||
return (
|
||||
<svg
|
||||
viewBox="0 0 100 100"
|
||||
className={isBottom ? `${styles.left} ${styles.angle}` : styles.angle}
|
||||
>
|
||||
<path
|
||||
d="M100,2 L2,2 L2,100"
|
||||
fill="none"
|
||||
strokeWidth="10"
|
||||
className={styles.anglePath}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
.boxplot {
|
||||
fill: var(--primary-accent-light);
|
||||
}
|
||||
|
||||
.boxplot:hover {
|
||||
fill: var(--primary-accent);
|
||||
filter: drop-shadow(0 0 calc(4rem / 16) var(--primary-accent));
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
font-family: "Inconsolata", monospace;
|
||||
top: 0;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
background-color: var(--label);
|
||||
color: var(--primary-background);
|
||||
pointer-events: none;
|
||||
padding: calc(10rem / 16);
|
||||
border-radius: calc(10rem / 16);
|
||||
}
|
||||
|
||||
.tooltip .category {
|
||||
margin: calc(10rem / 16) 0 0 0;
|
||||
font-size: calc(16rem / 16);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.tooltip .toolTipData {
|
||||
margin-top: calc(5rem / 16);
|
||||
margin-bottom: calc(10rem / 16);
|
||||
font-size: calc(16rem / 16);
|
||||
}
|
||||
|
||||
.tooltip .toolTipData p {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: calc(16rem / 16);
|
||||
}
|
|
@ -0,0 +1,361 @@
|
|||
import { AxisLeft, AxisBottom } from "@visx/axis";
|
||||
import { GridRows, GridColumns } from "@visx/grid";
|
||||
import { Group } from "@visx/group";
|
||||
import { Stats } from "@visx/mock-data/lib/generators/genStats";
|
||||
import { Point } from "@visx/point";
|
||||
import { scaleBand, scaleLinear } from "@visx/scale";
|
||||
import { Line } from "@visx/shape";
|
||||
import { BoxPlot as VisxBoxPlot } from "@visx/stats";
|
||||
import { withTooltip, Tooltip } from "@visx/tooltip";
|
||||
import { WithTooltipProvidedProps } from "@visx/tooltip/lib/enhancers/withTooltip";
|
||||
import React from "react";
|
||||
import { Color } from "utils/Color";
|
||||
|
||||
import styles from "./Boxplot.module.css";
|
||||
|
||||
const DEFAULT_LABEL_SIZE = 16;
|
||||
const TICK_LABEL_FONT_WEIGHT = 800;
|
||||
|
||||
interface BoxPlotData {
|
||||
category: string;
|
||||
min: number;
|
||||
median: number;
|
||||
max: number;
|
||||
firstQuartile: number;
|
||||
thirdQuartile: number;
|
||||
outliers?: number[];
|
||||
}
|
||||
|
||||
type TooltipData = Omit<BoxPlotData, "outliers">;
|
||||
|
||||
export type StatsPlotProps = {
|
||||
data: BoxPlotData[];
|
||||
/** Width of the entire graph, in pixels, greater than 10. */
|
||||
width: number;
|
||||
/** Height of the entire graph, in pixels. */
|
||||
height: number;
|
||||
/** Distance between the edge of the graph and the area where the bars are drawn, in pixels. */
|
||||
margin: {
|
||||
top: number;
|
||||
left: number;
|
||||
};
|
||||
/** Width of the lines in the graph, in px. */
|
||||
strokeWidth?: number;
|
||||
/** Length of the dashes and the gaps in the graph, in px. */
|
||||
strokeDashArray?: string;
|
||||
/** Number of ticks for the value (y-)axis */
|
||||
numTicksLeftAxis?: number;
|
||||
/** Distance between the boxplot and the top of the grid, in px. */
|
||||
plotTopOffset?: number;
|
||||
/** Distance between the left axis labels and the start of the lines of the graph, in px. */
|
||||
valueAxisLeftOffset?: number;
|
||||
/** Distance between the top and the first label of the y axis, in px. */
|
||||
valueAxisLabelTopOffset?: number;
|
||||
/** Distance between the left and the labels of the y axis, in px. */
|
||||
valueAxisLabelLeftOffset?: number;
|
||||
/** Distance between the left and the start of the first label of the x axis, in px. */
|
||||
categoryAxisLabelLeftOffset?: number;
|
||||
/** Distance between the top and the column lines of the grid of the graph, in px. */
|
||||
gridColumnTopOffset?: number;
|
||||
/** Distance between the top of the point in the boxplot and the start of the tooltip box, in px. */
|
||||
toolTipTopOffset?: number;
|
||||
/** Distance between the left of the point in the boxplot and the start of the tooltip box, in px. */
|
||||
toolTipLeftOffset?: number;
|
||||
/** Font size of the category (x-)axis labels */
|
||||
categoryAxisLabelSize?: number;
|
||||
/** Font size of the value (y-)axis labels */
|
||||
valueAxisLabelSize?: number;
|
||||
/** Font size of the text in the tool tip box */
|
||||
toolTipFontSize?: number;
|
||||
/** Factor multiplied with the compressed width to determine the box width, in px. */
|
||||
boxPlotWidthFactor?: number;
|
||||
/** Factor multiplied with the compressed width to determine the distance between boxes, in px. */
|
||||
boxPlotLeftOffset?: number;
|
||||
};
|
||||
|
||||
export const BoxPlot = withTooltip<StatsPlotProps, TooltipData>(
|
||||
({
|
||||
width,
|
||||
height,
|
||||
data,
|
||||
margin,
|
||||
tooltipOpen,
|
||||
tooltipLeft,
|
||||
tooltipTop,
|
||||
tooltipData,
|
||||
showTooltip,
|
||||
hideTooltip,
|
||||
strokeWidth = 2.5,
|
||||
strokeDashArray = "10,4",
|
||||
numTicksLeftAxis = 6,
|
||||
plotTopOffset = 10,
|
||||
valueAxisLeftOffset = 40,
|
||||
gridColumnTopOffset = -20,
|
||||
valueAxisLabelTopOffset = 5,
|
||||
valueAxisLabelLeftOffset = 10,
|
||||
categoryAxisLabelLeftOffset = 30,
|
||||
toolTipTopOffset = 20,
|
||||
toolTipLeftOffset = 5,
|
||||
categoryAxisLabelSize = DEFAULT_LABEL_SIZE,
|
||||
valueAxisLabelSize = DEFAULT_LABEL_SIZE,
|
||||
boxPlotWidthFactor = 0.4,
|
||||
boxPlotLeftOffset = 0.3,
|
||||
}: StatsPlotProps & WithTooltipProvidedProps<TooltipData>) => {
|
||||
// bounds
|
||||
const xMax = width;
|
||||
const yMax = height - 120;
|
||||
// formatting data
|
||||
const plotData: Stats[] = data.map((d) => {
|
||||
return {
|
||||
boxPlot: {
|
||||
...d,
|
||||
x: d.category,
|
||||
outliers: [],
|
||||
},
|
||||
binData: [],
|
||||
};
|
||||
});
|
||||
|
||||
// accessors
|
||||
const getX = (d: Stats) => d.boxPlot.x;
|
||||
const getMin = (d: Stats) => d.boxPlot.min;
|
||||
const getMax = (d: Stats) => d.boxPlot.max;
|
||||
const getMedian = (d: Stats) => d.boxPlot.median;
|
||||
const getFirstQuartile = (d: Stats) => d.boxPlot.firstQuartile;
|
||||
const getThirdQuartile = (d: Stats) => d.boxPlot.thirdQuartile;
|
||||
|
||||
// scales
|
||||
const xScale = scaleBand<string>({
|
||||
range: [18, xMax - 80], // scaling is needed due to the left offset
|
||||
round: true,
|
||||
domain: plotData.map(getX),
|
||||
padding: 0.3,
|
||||
});
|
||||
|
||||
const values = plotData.reduce((allValues, { boxPlot }) => {
|
||||
allValues.push(boxPlot.min, boxPlot.max);
|
||||
return allValues;
|
||||
}, [] as number[]);
|
||||
const minYValue = Math.min(...values);
|
||||
const maxYValue = Math.max(...values);
|
||||
|
||||
const yScale = scaleLinear<number>({
|
||||
range: [yMax, 0],
|
||||
round: true,
|
||||
domain: [minYValue, maxYValue],
|
||||
});
|
||||
|
||||
const constrainedWidth = Math.min(200, xScale.bandwidth());
|
||||
|
||||
return width < 10 ? null : (
|
||||
<div>
|
||||
<svg width={width} height={height}>
|
||||
<Group top={margin.top} left={margin.left}>
|
||||
<GridRows
|
||||
top={plotTopOffset}
|
||||
left={valueAxisLeftOffset}
|
||||
scale={yScale}
|
||||
width={xMax}
|
||||
numTicks={numTicksLeftAxis}
|
||||
stroke={Color.tertiaryBackground}
|
||||
strokeWidth={strokeWidth}
|
||||
strokeDasharray={strokeDashArray}
|
||||
/>
|
||||
<GridColumns
|
||||
scale={xScale}
|
||||
height={yMax + plotTopOffset - gridColumnTopOffset}
|
||||
top={gridColumnTopOffset}
|
||||
left={valueAxisLeftOffset}
|
||||
stroke={Color.tertiaryBackground}
|
||||
strokeWidth={strokeWidth}
|
||||
strokeDasharray={strokeDashArray}
|
||||
/>
|
||||
<Line
|
||||
fill={Color.tertiaryBackground}
|
||||
to={new Point({ x: valueAxisLeftOffset, y: gridColumnTopOffset })}
|
||||
from={
|
||||
new Point({ x: valueAxisLeftOffset, y: yMax + plotTopOffset })
|
||||
}
|
||||
stroke={Color.tertiaryBackground}
|
||||
strokeWidth={strokeWidth}
|
||||
strokeDasharray={strokeDashArray}
|
||||
/>
|
||||
<Line
|
||||
fill={Color.tertiaryBackground}
|
||||
to={
|
||||
new Point({
|
||||
x: xMax - margin.left - strokeWidth,
|
||||
y: gridColumnTopOffset,
|
||||
})
|
||||
}
|
||||
from={
|
||||
new Point({
|
||||
x: xMax - margin.left - strokeWidth,
|
||||
y: yMax + plotTopOffset,
|
||||
})
|
||||
}
|
||||
stroke={Color.tertiaryBackground}
|
||||
strokeWidth={strokeWidth}
|
||||
strokeDasharray={strokeDashArray}
|
||||
/>
|
||||
<AxisBottom
|
||||
top={yMax + plotTopOffset - gridColumnTopOffset}
|
||||
left={categoryAxisLabelLeftOffset}
|
||||
scale={xScale}
|
||||
hideAxisLine
|
||||
hideTicks
|
||||
labelProps={{
|
||||
fontSize: `${categoryAxisLabelSize / 16}rem`,
|
||||
}}
|
||||
tickLabelProps={() => {
|
||||
return {
|
||||
fill: Color.label,
|
||||
fontWeight: TICK_LABEL_FONT_WEIGHT,
|
||||
};
|
||||
}}
|
||||
/>
|
||||
<AxisLeft
|
||||
scale={yScale}
|
||||
top={plotTopOffset + valueAxisLabelTopOffset}
|
||||
left={valueAxisLabelLeftOffset}
|
||||
numTicks={numTicksLeftAxis}
|
||||
hideAxisLine
|
||||
labelProps={{
|
||||
fontSize: `${valueAxisLabelSize / 16}rem`,
|
||||
}}
|
||||
tickLabelProps={() => {
|
||||
return {
|
||||
fill: Color.label,
|
||||
fontWeight: TICK_LABEL_FONT_WEIGHT,
|
||||
};
|
||||
}}
|
||||
/>
|
||||
<Group top={plotTopOffset}>
|
||||
{plotData.map((d: Stats, i) => (
|
||||
<Group key={i}>
|
||||
<VisxBoxPlot
|
||||
className={styles.boxplot}
|
||||
min={getMin(d)}
|
||||
max={getMax(d)}
|
||||
left={
|
||||
xScale(getX(d))! +
|
||||
boxPlotLeftOffset * constrainedWidth +
|
||||
valueAxisLeftOffset
|
||||
}
|
||||
firstQuartile={getFirstQuartile(d)}
|
||||
thirdQuartile={getThirdQuartile(d)}
|
||||
median={getMedian(d)}
|
||||
boxWidth={constrainedWidth * boxPlotWidthFactor}
|
||||
rx={0}
|
||||
ry={0}
|
||||
stroke={Color.label}
|
||||
strokeWidth={strokeWidth}
|
||||
valueScale={yScale}
|
||||
minProps={{
|
||||
onMouseOver: () => {
|
||||
showTooltip({
|
||||
tooltipTop:
|
||||
(yScale(getMin(d)) ?? 0) + toolTipTopOffset,
|
||||
tooltipLeft:
|
||||
xScale(getX(d))! +
|
||||
constrainedWidth +
|
||||
toolTipLeftOffset,
|
||||
tooltipData: {
|
||||
...d.boxPlot,
|
||||
category: getX(d),
|
||||
},
|
||||
});
|
||||
},
|
||||
onMouseLeave: () => {
|
||||
hideTooltip();
|
||||
},
|
||||
}}
|
||||
maxProps={{
|
||||
onMouseOver: () => {
|
||||
showTooltip({
|
||||
tooltipTop:
|
||||
(yScale(getMax(d)) ?? 0) + toolTipTopOffset,
|
||||
tooltipLeft:
|
||||
xScale(getX(d))! +
|
||||
constrainedWidth +
|
||||
toolTipLeftOffset,
|
||||
tooltipData: {
|
||||
...d.boxPlot,
|
||||
category: getX(d),
|
||||
},
|
||||
});
|
||||
},
|
||||
onMouseLeave: () => {
|
||||
hideTooltip();
|
||||
},
|
||||
}}
|
||||
boxProps={{
|
||||
onMouseOver: () => {
|
||||
showTooltip({
|
||||
tooltipTop:
|
||||
(yScale(getMedian(d)) ?? 0) + toolTipTopOffset,
|
||||
tooltipLeft:
|
||||
xScale(getX(d))! +
|
||||
constrainedWidth +
|
||||
toolTipLeftOffset,
|
||||
tooltipData: {
|
||||
...d.boxPlot,
|
||||
category: getX(d),
|
||||
},
|
||||
});
|
||||
},
|
||||
strokeWidth: 0,
|
||||
onMouseLeave: () => {
|
||||
hideTooltip();
|
||||
},
|
||||
}}
|
||||
medianProps={{
|
||||
style: {
|
||||
stroke: Color.label,
|
||||
},
|
||||
onMouseOver: () => {
|
||||
showTooltip({
|
||||
tooltipTop:
|
||||
(yScale(getMedian(d)) ?? 0) + toolTipTopOffset,
|
||||
tooltipLeft:
|
||||
xScale(getX(d))! +
|
||||
constrainedWidth +
|
||||
toolTipLeftOffset,
|
||||
tooltipData: {
|
||||
...d.boxPlot,
|
||||
category: getX(d),
|
||||
},
|
||||
});
|
||||
},
|
||||
onMouseLeave: () => {
|
||||
hideTooltip();
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Group>
|
||||
))}
|
||||
</Group>
|
||||
</Group>
|
||||
</svg>
|
||||
|
||||
{tooltipOpen && tooltipData && (
|
||||
<Tooltip
|
||||
top={tooltipTop}
|
||||
left={tooltipLeft}
|
||||
className={styles.tooltip}
|
||||
unstyled
|
||||
>
|
||||
<p className={styles.category}>{tooltipData.category}</p>
|
||||
<div className={styles.toolTipData}>
|
||||
<p>max: {tooltipData.max}</p>
|
||||
<p>third quartile: {tooltipData.thirdQuartile}</p>
|
||||
<p>median: {tooltipData.median}</p>
|
||||
<p>first quartile: {tooltipData.firstQuartile}</p>
|
||||
<p>min: {tooltipData.min}</p>
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
|
@ -0,0 +1,7 @@
|
|||
.textbox {
|
||||
width: 80%;
|
||||
padding: calc(80rem / 16);
|
||||
background-color: var(--secondary-background);
|
||||
border-radius: calc(20rem / 16);
|
||||
margin: 0 auto;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
import React, { ReactNode } from "react";
|
||||
|
||||
import styles from "./CenterWrapper.module.css";
|
||||
|
||||
export interface TextboxProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export function CenterWrapper({ children }: TextboxProps) {
|
||||
return <section className={styles.textbox}>{children}</section>;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
.piePath {
|
||||
fill: var(--tertiary-background);
|
||||
}
|
||||
|
||||
.labelPath {
|
||||
fill-opacity: 0;
|
||||
}
|
||||
|
||||
.pieText,
|
||||
.labelText {
|
||||
fill: var(--label);
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.pieText {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.group:hover > .piePath {
|
||||
fill: var(--primary-accent);
|
||||
filter: drop-shadow(0px 0px calc(6rem / 16) var(--primary-accent));
|
||||
}
|
||||
|
||||
.group:hover .pieText {
|
||||
display: inline;
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
import { Group } from "@visx/group";
|
||||
import Pie, { ProvidedProps } from "@visx/shape/lib/shapes/Pie";
|
||||
import { Text } from "@visx/text";
|
||||
import React from "react";
|
||||
|
||||
import styles from "./PieChart.module.css";
|
||||
|
||||
interface PieChartProps {
|
||||
data: PieChartData[];
|
||||
/** Width of the entire graph, including labels, in pixels. */
|
||||
width: number;
|
||||
/** Width of the outer ring of labels, in pixels. Label text may be cut off if specified value is too small. */
|
||||
labelWidth: number;
|
||||
/** Distance between pie slices, in pixels. */
|
||||
padRadius?: number;
|
||||
/** Distance of gap in center of pie graph, in pixels. */
|
||||
innerRadius?: number;
|
||||
/** Font size of text inside the pie, in pixels. */
|
||||
pieTextSize?: number;
|
||||
/** X-axis offset of the pie text, in pixels. */
|
||||
pieTextXOffset?: number;
|
||||
/** Y-axis offset of the pie text, in pixels. */
|
||||
pieTextYOffset?: number;
|
||||
/** Accessor function to get value to display as pie text from datum. */
|
||||
getPieDisplayValueFromDatum?: (datum: PieChartData) => string;
|
||||
/** Font size of labels outside the pie, in pixels. */
|
||||
labelTextSize?: number;
|
||||
/** X-axis offset of the label text, in pixels. */
|
||||
labelTextXOffset?: number;
|
||||
/** Y-axis offset of the label text, in pixels. */
|
||||
labelTextYOffset?: number;
|
||||
/** Accessor function to get value to display as label text from datum. */
|
||||
getLabelDisplayValueFromDatum?: (datum: PieChartData) => string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
interface PieChartData {
|
||||
category: string;
|
||||
value: number;
|
||||
}
|
||||
|
||||
export function PieChart({
|
||||
data,
|
||||
width,
|
||||
labelWidth,
|
||||
padRadius = width * 0.35,
|
||||
innerRadius = width * 0.015,
|
||||
pieTextSize = 40,
|
||||
pieTextXOffset = 0,
|
||||
pieTextYOffset = 10,
|
||||
getPieDisplayValueFromDatum = (datum: PieChartData) => `${datum.value}%`,
|
||||
labelTextSize = 40,
|
||||
labelTextXOffset = 0,
|
||||
labelTextYOffset = 0,
|
||||
getLabelDisplayValueFromDatum = (datum: PieChartData) => `${datum.category}`,
|
||||
className,
|
||||
}: PieChartProps) {
|
||||
const pieWidth = width * 0.5 - labelWidth;
|
||||
return (
|
||||
<svg className={className} width={width} height={width}>
|
||||
<Group top={width * 0.5} left={width * 0.5}>
|
||||
<Pie
|
||||
data={data}
|
||||
pieValue={(d: PieChartData) => d.value}
|
||||
cornerRadius={10}
|
||||
padAngle={0.075}
|
||||
padRadius={padRadius}
|
||||
innerRadius={innerRadius}
|
||||
outerRadius={pieWidth}
|
||||
>
|
||||
{(pie) => (
|
||||
<PieSlice
|
||||
{...pie}
|
||||
pieTextSize={pieTextSize}
|
||||
pieTextXOffset={pieTextXOffset}
|
||||
pieTextYOffset={pieTextYOffset}
|
||||
getPieDisplayValueFromDatum={getPieDisplayValueFromDatum}
|
||||
/>
|
||||
)}
|
||||
</Pie>
|
||||
<Pie
|
||||
data={data}
|
||||
pieValue={(d: PieChartData) => d.value}
|
||||
innerRadius={pieWidth}
|
||||
outerRadius={width * 0.5}
|
||||
>
|
||||
{(pie) => (
|
||||
<PieSliceLabel
|
||||
{...pie}
|
||||
labelTextSize={labelTextSize}
|
||||
labelTextXOffset={labelTextXOffset}
|
||||
labelTextYOffset={labelTextYOffset}
|
||||
getLabelDisplayValueFromDatum={getLabelDisplayValueFromDatum}
|
||||
/>
|
||||
)}
|
||||
</Pie>
|
||||
</Group>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
type PieSliceProps<PieChartData> = ProvidedProps<PieChartData> & {
|
||||
pieTextSize: number;
|
||||
pieTextXOffset: number;
|
||||
pieTextYOffset: number;
|
||||
getPieDisplayValueFromDatum: (datum: PieChartData) => string;
|
||||
};
|
||||
|
||||
export function PieSlice({
|
||||
path,
|
||||
arcs,
|
||||
pieTextSize,
|
||||
pieTextXOffset,
|
||||
pieTextYOffset,
|
||||
getPieDisplayValueFromDatum,
|
||||
}: PieSliceProps<PieChartData>) {
|
||||
return (
|
||||
<>
|
||||
{arcs.map((arc) => {
|
||||
const [centroidX, centroidY] = path.centroid(arc);
|
||||
const pathArc = path(arc) as string;
|
||||
|
||||
return (
|
||||
<Group className={styles.group} key={`arc-${arc.data.category}`}>
|
||||
<path className={styles.piePath} d={pathArc} />
|
||||
<Text
|
||||
className={styles.pieText}
|
||||
x={centroidX + pieTextXOffset}
|
||||
y={centroidY + pieTextYOffset}
|
||||
textAnchor="middle"
|
||||
fontSize={pieTextSize}
|
||||
>
|
||||
{`${getPieDisplayValueFromDatum(arc.data)}`}
|
||||
</Text>
|
||||
</Group>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
type PieSliceLabelProps<PieChartData> = ProvidedProps<PieChartData> & {
|
||||
labelTextSize: number;
|
||||
labelTextXOffset: number;
|
||||
labelTextYOffset: number;
|
||||
getLabelDisplayValueFromDatum: (datum: PieChartData) => string;
|
||||
};
|
||||
|
||||
export function PieSliceLabel({
|
||||
path,
|
||||
arcs,
|
||||
labelTextSize,
|
||||
labelTextXOffset,
|
||||
labelTextYOffset,
|
||||
getLabelDisplayValueFromDatum,
|
||||
}: PieSliceLabelProps<PieChartData>) {
|
||||
return (
|
||||
<>
|
||||
{arcs.map((arc) => {
|
||||
const [centroidX, centroidY] = path.centroid(arc);
|
||||
const pathArc = path(arc) as string;
|
||||
|
||||
return (
|
||||
<Group className={styles.group} key={`arc-${arc.data.category}`}>
|
||||
<path className={styles.labelPath} d={pathArc} />
|
||||
<Text
|
||||
className={styles.labelText}
|
||||
x={centroidX + labelTextXOffset}
|
||||
y={centroidY + labelTextYOffset}
|
||||
textAnchor="middle"
|
||||
fontSize={labelTextSize}
|
||||
>
|
||||
{`${getLabelDisplayValueFromDatum(arc.data)}`}
|
||||
</Text>
|
||||
</Group>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -1,14 +1,12 @@
|
|||
.sections {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 50%;
|
||||
gap: 15px;
|
||||
margin: 0 50px;
|
||||
gap: calc(15rem / 16);
|
||||
}
|
||||
|
||||
.sections h1 {
|
||||
flex: 3;
|
||||
text-align: left;
|
||||
text-align: right;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
@ -17,7 +15,7 @@
|
|||
background-color: var(--label);
|
||||
height: calc(1rem / 16);
|
||||
width: 100%;
|
||||
margin-top: calc(24rem / 16);
|
||||
margin-top: calc(30rem / 16);
|
||||
}
|
||||
|
||||
.nav {
|
||||
|
@ -26,27 +24,37 @@
|
|||
flex-direction: column;
|
||||
}
|
||||
|
||||
.navItem {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
.nav ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.nav li {
|
||||
margin: calc(20rem / 16);
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.navItem:first-child {
|
||||
margin-top: calc(10rem / 16);
|
||||
.nav li:first-child {
|
||||
margin-top: calc(18rem / 16);
|
||||
}
|
||||
|
||||
.nav h4 {
|
||||
.nav li .linkNumber {
|
||||
color: var(--secondary-accent);
|
||||
margin: 0 calc(14rem / 16) 0 0;
|
||||
margin: 0;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.nav a {
|
||||
.nav li a {
|
||||
font-size: calc(24rem / 16);
|
||||
color: var(--primary-text);
|
||||
}
|
||||
|
||||
.nav a:hover {
|
||||
color: var(--primary-accent-light);
|
||||
.nav li a:hover .linkName {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.nav li .linkName {
|
||||
margin: 0;
|
||||
display: inline;
|
||||
}
|
|
@ -8,23 +8,37 @@ interface SectionsData {
|
|||
}
|
||||
|
||||
interface SectionsProps {
|
||||
/* Whether to display the "Sections" title and separator that appears on the left. */
|
||||
showHeader?: boolean;
|
||||
data: SectionsData[];
|
||||
}
|
||||
|
||||
export default function Sections({ data }: SectionsProps) {
|
||||
export function Sections({ data, showHeader = true }: SectionsProps) {
|
||||
return (
|
||||
<section className={styles.sections}>
|
||||
{/* <h1>Sections</h1> */}
|
||||
{/* <div className={styles.separator} /> */}
|
||||
{showHeader ? (
|
||||
<>
|
||||
<h1>Sections</h1>
|
||||
<div className={styles.separator} />
|
||||
</>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
<nav className={styles.nav}>
|
||||
{data.map((datum, index) => {
|
||||
return (
|
||||
<div key={`${datum.name}-${index}`} className={styles.navItem}>
|
||||
<h4>{String(index).padStart(2, "0")}</h4>
|
||||
<a href={datum.url}>{datum.name}</a>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<ul>
|
||||
{data.map((datum, index) => {
|
||||
return (
|
||||
<li key={`${datum.name}-${index}`}>
|
||||
<a href={datum.url}>
|
||||
<span className={styles.linkNumber}>
|
||||
{String(index).padStart(2, "0")}{" "}
|
||||
</span>
|
||||
<span className={styles.linkName}>{datum.name}</span>
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</nav>
|
||||
</section>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
.wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.line {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
border-radius: calc(10rem / 16);
|
||||
background-color: var(--secondary-accent);
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.timelineSections {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
gap: calc(20rem / 16);
|
||||
}
|
||||
|
||||
.timelineSection {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.time {
|
||||
margin: 0;
|
||||
text-align: right;
|
||||
font-size: calc(30rem / 16);
|
||||
font-weight: 700;
|
||||
color: var(--secondary-accent);
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.circle {
|
||||
background-color: var(--secondary-accent);
|
||||
box-shadow: calc(0rem / 16) calc(0rem / 16) calc(30rem / 16) var(--secondary-accent);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.innerCircle {
|
||||
background-color: var(--label);
|
||||
display: none;
|
||||
}
|
||||
|
||||
.text {
|
||||
height: fit-content;
|
||||
margin: 0;
|
||||
padding: calc(15rem / 16);
|
||||
border-radius: calc(10rem / 16);
|
||||
font-size: calc(20rem / 16);
|
||||
font-weight: 700;
|
||||
color: var(--label);
|
||||
border: calc(2rem / 16) solid var(--card-background);
|
||||
background-color: var(--card-background);
|
||||
word-wrap: break-word;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.timelineSection:hover .time {
|
||||
color: var(--secondary-accent-light);
|
||||
}
|
||||
|
||||
.timelineSection:hover .innerCircle {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.timelineSection:hover .text {
|
||||
border: calc(2rem / 16) solid var(--secondary-accent-light);
|
||||
box-shadow: calc(0rem / 16) calc(0rem / 16) calc(20rem / 16) var(--secondary-accent);
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
import React from "react";
|
||||
|
||||
import styles from "./Timeline.module.css";
|
||||
|
||||
interface TimelineData {
|
||||
time: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
interface TimelineProps {
|
||||
data: TimelineData[];
|
||||
/** Whether the time is transformed to uppercase. */
|
||||
isTimeUppercase?: boolean;
|
||||
/** Width of the middle timeline line, in pixels */
|
||||
lineWidth?: number;
|
||||
/** Width of the outer circles on the timeline, in pixels. */
|
||||
outerCircleWidth?: number;
|
||||
/** Width of the inner circles on the timeline, in pixels. */
|
||||
innerCircleWidth?: number;
|
||||
/** Width of time label, in pixels. */
|
||||
timeWidth?: number;
|
||||
/** Width of text label, in pixels. */
|
||||
textWidth?: number;
|
||||
/** Distance between the time label AND the text label to middle line, in pixels. */
|
||||
gap?: number;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function Timeline({
|
||||
data,
|
||||
isTimeUppercase = true,
|
||||
lineWidth = 5,
|
||||
outerCircleWidth = 30,
|
||||
innerCircleWidth = 15,
|
||||
timeWidth = 200,
|
||||
textWidth = 300,
|
||||
gap = 50,
|
||||
className,
|
||||
}: TimelineProps) {
|
||||
const largerMiddleElement =
|
||||
outerCircleWidth > lineWidth ? outerCircleWidth : lineWidth;
|
||||
const width = timeWidth + gap + largerMiddleElement + gap + textWidth;
|
||||
if (innerCircleWidth > outerCircleWidth) {
|
||||
throw new Error(
|
||||
`<Timeline /> - innerCircleWidth (${innerCircleWidth}) is larger than outerCircleWidth (${outerCircleWidth})`
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
className ? `${className} ${styles.wrapper}` : `${styles.wrapper}`
|
||||
}
|
||||
style={{ width: width }}
|
||||
>
|
||||
<div
|
||||
className={styles.line}
|
||||
style={{
|
||||
width: lineWidth,
|
||||
left: width / 2 - lineWidth / 2,
|
||||
}}
|
||||
/>
|
||||
<div className={styles.timelineSections}>
|
||||
{data.map((datum) => (
|
||||
<TimelineSection
|
||||
key={datum.time}
|
||||
datum={datum}
|
||||
width={width}
|
||||
isTimeUppercase={isTimeUppercase}
|
||||
outerCircleWidth={outerCircleWidth}
|
||||
innerCircleWidth={innerCircleWidth}
|
||||
timeWidth={timeWidth}
|
||||
textWidth={textWidth}
|
||||
gap={gap}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface TimelineSectionProps {
|
||||
datum: TimelineData;
|
||||
width: number;
|
||||
isTimeUppercase: boolean;
|
||||
outerCircleWidth: number;
|
||||
innerCircleWidth: number;
|
||||
timeWidth: number;
|
||||
textWidth: number;
|
||||
gap: number;
|
||||
}
|
||||
|
||||
function TimelineSection({
|
||||
datum,
|
||||
width,
|
||||
isTimeUppercase,
|
||||
outerCircleWidth,
|
||||
innerCircleWidth,
|
||||
timeWidth,
|
||||
textWidth,
|
||||
gap,
|
||||
}: TimelineSectionProps) {
|
||||
return (
|
||||
<div className={styles.timelineSection} style={{ gap: gap }}>
|
||||
<div
|
||||
className={styles.time}
|
||||
style={{
|
||||
width: timeWidth,
|
||||
marginLeft: (width - 2 * gap - outerCircleWidth) / 2 - timeWidth,
|
||||
}}
|
||||
>
|
||||
{isTimeUppercase ? datum.time.toUpperCase() : datum.time}
|
||||
</div>
|
||||
<div
|
||||
className={styles.circle}
|
||||
style={{
|
||||
width: outerCircleWidth,
|
||||
height: outerCircleWidth,
|
||||
borderRadius: outerCircleWidth,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={styles.innerCircle}
|
||||
style={{
|
||||
width: innerCircleWidth,
|
||||
height: innerCircleWidth,
|
||||
borderRadius: innerCircleWidth,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={styles.text}
|
||||
style={{
|
||||
width: textWidth,
|
||||
marginRight: (width - 2 * gap - outerCircleWidth) / 2 - textWidth,
|
||||
}}
|
||||
>
|
||||
{datum.text}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -36,6 +36,21 @@ export const mockCategoricalData = [
|
|||
},
|
||||
];
|
||||
|
||||
export const mockPieData = [
|
||||
{
|
||||
category: "Nightingale",
|
||||
value: 42,
|
||||
},
|
||||
{
|
||||
category: "Quail",
|
||||
value: 48,
|
||||
},
|
||||
{
|
||||
category: "Cuckoo",
|
||||
value: 10,
|
||||
},
|
||||
];
|
||||
|
||||
export const moreMockCategoricalData = [
|
||||
{ key: "Python", value: 29.53 },
|
||||
{ key: "Java", value: 17.06 },
|
||||
|
@ -65,6 +80,75 @@ export const moreMockCategoricalData = [
|
|||
{ key: "Dart", value: 2.21 },
|
||||
];
|
||||
|
||||
export const mockTimelineData = [
|
||||
{
|
||||
time: "Fall 2020",
|
||||
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
|
||||
},
|
||||
{
|
||||
time: "Winter 2021",
|
||||
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad",
|
||||
},
|
||||
{
|
||||
time: "Spring 2021",
|
||||
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor i",
|
||||
},
|
||||
{
|
||||
time: "Fall 2021",
|
||||
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proid",
|
||||
},
|
||||
{
|
||||
time: "Winter 2022",
|
||||
text: "Lorem ipsum dolor sit amet, consectetur adipi",
|
||||
},
|
||||
{
|
||||
time: "Spring 2022",
|
||||
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut en",
|
||||
},
|
||||
];
|
||||
|
||||
export const mockBoxPlotData = [
|
||||
{
|
||||
category: "1A",
|
||||
min: 20,
|
||||
firstQuartile: 25,
|
||||
median: 30,
|
||||
thirdQuartile: 80,
|
||||
max: 100,
|
||||
outliers: [],
|
||||
},
|
||||
{
|
||||
category: "1B",
|
||||
min: 0,
|
||||
firstQuartile: 20,
|
||||
median: 30,
|
||||
thirdQuartile: 50,
|
||||
max: 100,
|
||||
outliers: [],
|
||||
},
|
||||
{
|
||||
category: "2A",
|
||||
min: 25,
|
||||
firstQuartile: 35,
|
||||
median: 50,
|
||||
thirdQuartile: 90,
|
||||
max: 100,
|
||||
outliers: [],
|
||||
},
|
||||
];
|
||||
|
||||
export const mockQuoteData = [
|
||||
"The quick brown fox jumps over the lazy dog.",
|
||||
"Sphinx of black quartz, judge my vow!",
|
||||
"Pack my box with five dozen liquor jugs.",
|
||||
];
|
||||
|
||||
export const mockQuoteDataLong = [
|
||||
"Here, have some quotes of varying lengths, and see how they look.",
|
||||
"Hello, world!",
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla in enim neque. Sed sit amet convallis tellus. Integer condimentum a felis id gravida. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nullam metus libero, sagittis in consectetur in, scelerisque sed sapien. Nullam ut feugiat sapien. Praesent dictum ac ipsum ac lacinia.",
|
||||
];
|
||||
|
||||
export const mockQuoteData = [
|
||||
"The quick brown fox jumps over the lazy dog.",
|
||||
"Sphinx of black quartz, judge my vow!",
|
||||
|
|
|
@ -5,15 +5,16 @@
|
|||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "cs-2022-class-profile",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@visx/axis": "^2.10.0",
|
||||
"@visx/event": "^2.6.0",
|
||||
"@visx/grid": "^2.10.0",
|
||||
"@visx/group": "^2.10.0",
|
||||
"@visx/mock-data": "^2.1.2",
|
||||
"@visx/scale": "^2.2.2",
|
||||
"@visx/shape": "^2.10.0",
|
||||
"@visx/stats": "^2.10.0",
|
||||
"@visx/text": "^2.10.0",
|
||||
"@visx/tooltip": "^2.10.0",
|
||||
"@visx/wordcloud": "^2.10.0",
|
||||
|
@ -608,6 +609,11 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-1.0.9.tgz",
|
||||
"integrity": "sha512-NaIeSIBiFgSC6IGUBjZWcscUJEq7vpVu7KthHN8eieTV9d9MqkSOZLH4chq1PmcKy06PNe3axLeKmRIyxJ+PZQ=="
|
||||
},
|
||||
"node_modules/@types/d3-random": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-2.2.1.tgz",
|
||||
"integrity": "sha512-5vvxn6//poNeOxt1ZwC7QU//dG9QqABjy1T7fP/xmFHY95GnaOw3yABf29hiu5SR1Oo34XcpyHFbzod+vemQjA=="
|
||||
},
|
||||
"node_modules/@types/d3-scale": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-3.3.2.tgz",
|
||||
|
@ -967,6 +973,15 @@
|
|||
"react": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@visx/mock-data": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@visx/mock-data/-/mock-data-2.1.2.tgz",
|
||||
"integrity": "sha512-6xUVP56tiPwVi3BxvoXPQzDYWG6iX2nnOlsHEYsHgK8gHq1r7AhjQtdbQUX7QF0QkmkJM0cW8TBjZ2e+dItB8Q==",
|
||||
"dependencies": {
|
||||
"@types/d3-random": "^2.2.0",
|
||||
"d3-random": "^2.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@visx/point": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/point/-/point-2.6.0.tgz",
|
||||
|
@ -1007,6 +1022,23 @@
|
|||
"react": "^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@visx/stats": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/stats/-/stats-2.10.0.tgz",
|
||||
"integrity": "sha512-4p8rQamOc1IC3IkqTHgfMHbSXvRl9DMWFCglJy+DmbH6Wx1TaWt2nj/N0Ttp350UTRzBy4o5ou/D4Gts8LZHuA==",
|
||||
"dependencies": {
|
||||
"@types/d3-shape": "^1.3.2",
|
||||
"@types/react": "*",
|
||||
"@visx/group": "2.10.0",
|
||||
"@visx/scale": "2.2.2",
|
||||
"classnames": "^2.3.1",
|
||||
"d3-shape": "^1.2.0",
|
||||
"prop-types": "^15.5.10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@visx/text": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/text/-/text-2.10.0.tgz",
|
||||
|
@ -1392,6 +1424,7 @@
|
|||
"version": "3.22.7",
|
||||
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.22.7.tgz",
|
||||
"integrity": "sha512-wTriFxiZI+C8msGeh7fJcbC/a0V8fdInN1oS2eK79DMBGs8iIJiXhtFJCiT3rBa8w6zroHWW3p8ArlujZ/Mz+w==",
|
||||
"deprecated": "core-js-pure@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js-pure.",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"funding": {
|
||||
|
@ -1535,6 +1568,11 @@
|
|||
"resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz",
|
||||
"integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg=="
|
||||
},
|
||||
"node_modules/d3-random": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/d3-random/-/d3-random-2.2.2.tgz",
|
||||
"integrity": "sha512-0D9P8TRj6qDAtHhRQn6EfdOtHMfsUWanl3yb/84C4DqpZ+VsgfI5iTVRNRbELCfNvRfpMr8OrqqUTQ6ANGCijw=="
|
||||
},
|
||||
"node_modules/d3-scale": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.3.0.tgz",
|
||||
|
@ -4790,6 +4828,11 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-1.0.9.tgz",
|
||||
"integrity": "sha512-NaIeSIBiFgSC6IGUBjZWcscUJEq7vpVu7KthHN8eieTV9d9MqkSOZLH4chq1PmcKy06PNe3axLeKmRIyxJ+PZQ=="
|
||||
},
|
||||
"@types/d3-random": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-2.2.1.tgz",
|
||||
"integrity": "sha512-5vvxn6//poNeOxt1ZwC7QU//dG9QqABjy1T7fP/xmFHY95GnaOw3yABf29hiu5SR1Oo34XcpyHFbzod+vemQjA=="
|
||||
},
|
||||
"@types/d3-scale": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-3.3.2.tgz",
|
||||
|
@ -5043,6 +5086,15 @@
|
|||
"prop-types": "^15.6.2"
|
||||
}
|
||||
},
|
||||
"@visx/mock-data": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@visx/mock-data/-/mock-data-2.1.2.tgz",
|
||||
"integrity": "sha512-6xUVP56tiPwVi3BxvoXPQzDYWG6iX2nnOlsHEYsHgK8gHq1r7AhjQtdbQUX7QF0QkmkJM0cW8TBjZ2e+dItB8Q==",
|
||||
"requires": {
|
||||
"@types/d3-random": "^2.2.0",
|
||||
"d3-random": "^2.2.2"
|
||||
}
|
||||
},
|
||||
"@visx/point": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/point/-/point-2.6.0.tgz",
|
||||
|
@ -5080,6 +5132,20 @@
|
|||
"prop-types": "^15.5.10"
|
||||
}
|
||||
},
|
||||
"@visx/stats": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/stats/-/stats-2.10.0.tgz",
|
||||
"integrity": "sha512-4p8rQamOc1IC3IkqTHgfMHbSXvRl9DMWFCglJy+DmbH6Wx1TaWt2nj/N0Ttp350UTRzBy4o5ou/D4Gts8LZHuA==",
|
||||
"requires": {
|
||||
"@types/d3-shape": "^1.3.2",
|
||||
"@types/react": "*",
|
||||
"@visx/group": "2.10.0",
|
||||
"@visx/scale": "2.2.2",
|
||||
"classnames": "^2.3.1",
|
||||
"d3-shape": "^1.2.0",
|
||||
"prop-types": "^15.5.10"
|
||||
}
|
||||
},
|
||||
"@visx/text": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/text/-/text-2.10.0.tgz",
|
||||
|
@ -5443,6 +5509,11 @@
|
|||
"resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz",
|
||||
"integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg=="
|
||||
},
|
||||
"d3-random": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/d3-random/-/d3-random-2.2.2.tgz",
|
||||
"integrity": "sha512-0D9P8TRj6qDAtHhRQn6EfdOtHMfsUWanl3yb/84C4DqpZ+VsgfI5iTVRNRbELCfNvRfpMr8OrqqUTQ6ANGCijw=="
|
||||
},
|
||||
"d3-scale": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.3.0.tgz",
|
||||
|
|
|
@ -19,8 +19,10 @@
|
|||
"@visx/event": "^2.6.0",
|
||||
"@visx/grid": "^2.10.0",
|
||||
"@visx/group": "^2.10.0",
|
||||
"@visx/mock-data": "^2.1.2",
|
||||
"@visx/scale": "^2.2.2",
|
||||
"@visx/shape": "^2.10.0",
|
||||
"@visx/stats": "^2.10.0",
|
||||
"@visx/text": "^2.10.0",
|
||||
"@visx/tooltip": "^2.10.0",
|
||||
"@visx/wordcloud": "^2.10.0",
|
||||
|
|
|
@ -24,7 +24,6 @@ body {
|
|||
--light--secondary-accent-light: #FEA0C8;
|
||||
--light--primary-heading: #D02B53;
|
||||
--light--primary-text: #483B35;
|
||||
--light--secondary-text: var(--pink);
|
||||
--light--link: var(--orange);
|
||||
--light--link-hover: #FFBC9F;
|
||||
--light--card-background: #FFFFFF;
|
||||
|
@ -69,22 +68,52 @@ body {
|
|||
color: var(--primary-text);
|
||||
font-family: "Inconsolata", monospace;
|
||||
margin: 0;
|
||||
|
||||
/* Font styling for body */
|
||||
font-size: calc(18rem / 16);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
h1,
|
||||
/* Page titles (e.g. Demographics) */
|
||||
h1 {
|
||||
font-size: calc(48rem / 16);
|
||||
font-weight: 700;
|
||||
color: var(--primary-accent-light);
|
||||
margin-top: calc(32rem / 16);
|
||||
margin-bottom: calc(16rem / 16);
|
||||
}
|
||||
|
||||
/* Major section headings (e.g. About the Programs) */
|
||||
h2 {
|
||||
font-size: calc(36rem / 16);
|
||||
font-weight: 700;
|
||||
color: var(--primary-heading);
|
||||
margin-top: calc(32rem / 16);
|
||||
margin-bottom: calc(16rem / 16);
|
||||
}
|
||||
|
||||
/* Minor section headings & questions (e.g. What Program Are You In?) */
|
||||
h3 {
|
||||
font-size: calc(32rem / 16);
|
||||
font-weight: 700;
|
||||
color: var(--secondary-heading);
|
||||
font-size: calc(45rem / 16);
|
||||
margin-top: calc(24rem / 16);
|
||||
margin-bottom: calc(16rem / 16);
|
||||
}
|
||||
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
/* Titles within paragraphs (e.g. About the Programs -> Computer Science)*/
|
||||
h4 {
|
||||
font-size: calc(24rem / 16);
|
||||
font-weight: 700;
|
||||
color: var(--secondary-heading);
|
||||
margin-top: calc(24rem / 16);
|
||||
margin-bottom: calc(8rem / 16);
|
||||
}
|
||||
|
||||
p {
|
||||
color: var(--primary-text);
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
a {
|
||||
|
|
|
@ -1,16 +1,24 @@
|
|||
import { BarGraphHorizontal, BarGraphVertical } from "components/BarGraph";
|
||||
import { BoxPlot } from "components/Boxplot";
|
||||
import {
|
||||
mockCategoricalData,
|
||||
moreMockCategoricalData,
|
||||
mockBoxPlotData,
|
||||
mockQuoteData,
|
||||
mockQuoteDataLong,
|
||||
mockPieData,
|
||||
mockTimelineData,
|
||||
} from "data/mocks";
|
||||
import { sectionsData } from "data/routes";
|
||||
import React from "react";
|
||||
|
||||
import { About } from "@/components/About";
|
||||
import { PieChart } from "@/components/PieChart";
|
||||
import { QuotationCarousel } from "@/components/QuotationCarousel";
|
||||
import Sections from "@/components/Sections";
|
||||
import { Sections } from "@/components/Sections";
|
||||
import { Timeline } from "@/components/Timeline";
|
||||
|
||||
import { CenterWrapper } from "../components/CenterWrapper";
|
||||
import { ColorPalette } from "../components/ColorPalette";
|
||||
import { WordCloud } from "../components/WordCloud";
|
||||
|
||||
|
@ -21,8 +29,26 @@ export default function Home() {
|
|||
<div className={styles.page}>
|
||||
<h1>Playground</h1>
|
||||
<p>Show off your components here!</p>
|
||||
|
||||
<ColorPalette />
|
||||
|
||||
<h2>
|
||||
<code>Text Styles</code>
|
||||
</h2>
|
||||
<h1>h1 h1 h1 h1 h1 h1 h1 h1 h1 h1 h1 h1 h1 h1 h1 h1 h1 h1</h1>
|
||||
<h2>h2 h2 h2 h2 h2 h2 h2 h2 h2 h2 h2 h2 h2 h2 h2 h2 h2 h2</h2>
|
||||
<h3>h3 h3 h3 h3 h3 h3 h3 h3 h3 h3 h3 h3 h3 h3 h3 h3 h3 h3</h3>
|
||||
<h4>h4 h4 h4 h4 h4 h4 h4 h4 h4 h4 h4 h4 h4 h4 h4 h4 h4 h4</h4>
|
||||
<p>p p p p p p p p p p p p p p p p p p p p p p p p p p p p</p>
|
||||
<a href="#">a a a a a a a a a a a a a a a a a a a a a a a a a a a a</a>
|
||||
|
||||
<h2>
|
||||
<code>{"<PieChart />"}</code>
|
||||
</h2>
|
||||
<div style={{ padding: "30px" }}>
|
||||
<PieChart data={mockPieData} width={800} labelWidth={215} />
|
||||
</div>
|
||||
|
||||
<h2>
|
||||
<code>{"<BarGraphHorizontal />"}</code>
|
||||
</h2>
|
||||
|
@ -32,7 +58,7 @@ export default function Home() {
|
|||
width={800}
|
||||
height={500}
|
||||
margin={{
|
||||
top: 20,
|
||||
top: 25,
|
||||
bottom: 40,
|
||||
left: 150,
|
||||
right: 20,
|
||||
|
@ -69,6 +95,79 @@ export default function Home() {
|
|||
}))}
|
||||
/>
|
||||
|
||||
<h2>
|
||||
<code>{"<Timeline />"}</code>
|
||||
</h2>
|
||||
<Timeline data={mockTimelineData} />
|
||||
|
||||
<h2>
|
||||
<code>{"<Textbox />"}</code>
|
||||
</h2>
|
||||
<CenterWrapper>
|
||||
<h1>Preface</h1>
|
||||
<p>
|
||||
The CS Class Profile consists of data relevant to CS, CFM, and CS/BBA
|
||||
students. These were combined with the knowledge that students in
|
||||
these programs tend to have similar experiences, as many of the same
|
||||
CS required courses are shared. In the standard co-op offering, CS and
|
||||
CFM take 4 years and 2 semesters to complete, while CS/BBA can take up
|
||||
to a full 5 years.
|
||||
</p>
|
||||
<p>
|
||||
Computer Science (and the others) is known to be a very prestigious
|
||||
program, and is very well known in Canada as well as across the world.
|
||||
For prospective students or anyone who is interested in learning more
|
||||
about what the students are like, this CS Class Profile will attempt
|
||||
to answer some of your questions, and you may even learn a thing or
|
||||
two you didn’t expect!
|
||||
</p>
|
||||
<p>
|
||||
The survey questions were approved by the Institutional Analysis &
|
||||
Planning, where all University of Waterloo stakeholders that are
|
||||
interested in conducting a non-academic research survey involving a
|
||||
large portion of the UWaterloo population are reviewed and approved.
|
||||
The entirety of the survey creation and data processing was done by
|
||||
the UW Computer Science Club, so please check us out if you enjoy what
|
||||
you see!
|
||||
</p>
|
||||
</CenterWrapper>
|
||||
|
||||
<h2>
|
||||
<code>{"<Sections />"}</code>
|
||||
</h2>
|
||||
<Sections data={sectionsData} />
|
||||
|
||||
<h2>
|
||||
<code>{"<About />"}</code>
|
||||
</h2>
|
||||
<About />
|
||||
|
||||
<h2>
|
||||
<code>{"<BoxPlot />"}</code>
|
||||
</h2>
|
||||
<BoxPlot
|
||||
width={600}
|
||||
height={400}
|
||||
data={mockBoxPlotData}
|
||||
margin={{
|
||||
top: 20,
|
||||
left: 20,
|
||||
}}
|
||||
/>
|
||||
|
||||
<h2>
|
||||
<code>{"<QuotationCarousel />"}</code>
|
||||
</h2>
|
||||
<div className={styles.quotationCarouselDemo}>
|
||||
<QuotationCarousel data={mockQuoteData} circleDiameter={0} />
|
||||
<QuotationCarousel
|
||||
data={mockQuoteDataLong}
|
||||
width={800}
|
||||
height={160}
|
||||
circleDiameter={180}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<h2>
|
||||
<code>{"<QuotationCarousel />"}</code>
|
||||
</h2>
|
||||
|
|
|
@ -5,7 +5,6 @@ import { useWindowDimensions } from "utils/getWindowDimensions";
|
|||
import { useIsMobile } from "utils/isMobile";
|
||||
|
||||
import { ComponentWrapper } from "@/components/ComponentWrapper";
|
||||
import { Header } from "@/components/Header";
|
||||
|
||||
import { WordCloud } from "../components/WordCloud";
|
||||
|
||||
|
@ -17,7 +16,6 @@ export default function SamplePage() {
|
|||
|
||||
return (
|
||||
<div className={styles.page}>
|
||||
<Header />
|
||||
<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."
|
||||
|
|
Loading…
Reference in New Issue