6.0 KiB
Pages
All pages are a separate React component in our repository, under the pages folder. This is a special directory used by Next.js which maps a React component exported from this directory to a page on a url.
The React components exported by these files are wrapped by the App
component. This lets us reuse code in between pages which makes it a good place to render the navbar, footer, background shapes, and the general CSS layout of a page.
Title
We use a custom Title
component to set the title on our pages. This is a very simple component and is just a wrapper around the Next.js Head
component. It also automatically prefixes each title with "CSC - University of Waterloo". Look at the code for more details.
Example 1
import { Title } from "@/components/Title"
function FooPage() {
return (
<>
<Title>Title in the tab</Title>
<div>Content of the page</div>
</>
)
}
// The page's content will be "Content of the page"
// The title of the page (as shown at the top of the browser in the tab) is "CSC - University of Waterloo - Title in the tab"
Example 2
You can also pass in an array of strings, and the Title
component will automatically join them with " - ".
import { Title } from "@/components/Title"
function FooPage() {
return (
<>
<Title>{["Foo", "Bar", "Baz"]}</Title>
<div>Content of the page</div>
</>
)
}
// The page's content will be "Content of the page"
// The title of the page (as shown at the top of the browser in the tab) is "CSC - University of Waterloo - Foo - Bar - Baz"
Layout
Most pages are wrapped with the DefaultLayout
component which limits the page width and adds the necessary margins and paddings. However, some pages need to override these default styles to accomodate for their specific design. For example:
- The home page is wider than all the other pages.
- The about us needs the entire screen width to properly render the bubbles.

We have an opt-in model for using a custom layout for pages. This is enabled by the static Layout
function on a React component for a page.
Example
function PageXYZ() {
return <p>I am a page</p>
}
// If we want this page to use a custom layout, we can add a static `Layout` function to it.
PageXYZ.Layout = function PageXYZLayout(props: { children: React.ReactNode }) {
return <div className={styles.customLayoutStyles}>{props.children}</div>;
}
It is extremely important to return props.children
as part of the JSX because this contains the entire page. If you fail to return it, the page will not show up.
Note that this functionality is not a part of Next.js. We take advantage of static properties in the _app.tsx file to implement this.
Shapes Background
Just like the static Layout
function, we use another static function on React pages called getShapesConfig
. Most pages use the default config which positions shapes randomly on the page. Some pages require a little artistic nudge or even hardcoding the shapes to appear in certain locations.
Pages like the home page can use the getShapesConfig
function to customize what shapes they want the page to render.
Example 1
import { GetShapesConfig } from "@/components/ShapesBackground";
PageXYZ.getShapesConfig = (() => {
// I ONLY LIKE DOTS AND WAVES!!!!
return {
dots: [
{
// These map to CSS properties. You don't have to use all of them. Use the ones that you want.
top: "calc(0.06 * (580rem / 0.65) / 16)",
right: "90vw",
width: "calc(168rem / 16)",
height: "calc(204rem / 16)",
filter: "var(--teal)",
opacity: "25%",
}
],
waves: [
{
top: "calc(0.5 * (580rem / 0.65) / 16)",
left: "24vw",
width: "calc(116rem / 16)",
height: "calc(58rem / 16)",
filter: "var(--teal)",
},
]
}
}) as GetShapesConfig
Note that background shapes are not rendered into html files during build time because it is impossible to know the window dimensions. This means that you can safely use window.innerWidth
and window.innerHeight
as well use the width and height of the shapes container inside the getShapesConfig
function to change the shapes based on size of the screen.
Example 2
import { GetShapesConfig } from "@/components/ShapesBackground";
PageXYZ.getShapesConfig = ((containerWidth, containerHeight) => {
// I like dots on desktops
if (window.innerWidth >= 768) {
return {
dots: [
{
// These map to CSS properties. You don't have to use all of them. Use the ones that you want.
top: "calc(0.06 * (580rem / 0.65) / 16)",
right: "90vw",
width: "calc(168rem / 16)",
height: "calc(204rem / 16)",
filter: "var(--teal)",
opacity: "25%",
}
],
}
}
// but waves on phones and tables
else {
return {
waves: [
{
top: "calc(0.5 * (580rem / 0.65) / 16)",
left: "24vw",
width: "calc(116rem / 16)",
height: "calc(58rem / 16)",
filter: "var(--teal)",
},
]
}
}
}) as GetShapesConfig
As with the Layout
function, this is not a part of Next.js. We take advantage of static properties in the _app.tsx file to implement this.