This repository is written entirely in Next.js, using TypeScript for components and Sass for stylesheets.
The purpose of this document is to provide information and guidelines for designing and writing code for this website in order to ensure consistency and clarity for all contributors, present and future.
As much as possible, the guidelines in this document are enforced by ESLint (for .ts. and .tsx files) and StyleLint (for .scss files).
As such, whenever you commit code, we recommend you run yarn lint to ensure that you're adhering to these guidelines.
- General Syntax and Format
- Repository Architecture
- Component Design
- Styling
- Utilities
- Assets
- Appendix
- All lines must end in a semicolon.
- Indentation uses two spaces.
- Component and interface names, imported assets, static functions, and static variables must be in PascalCase.
- Non-static functions, non-static variables, interface fields, and style classes must be in camelCase.
- For multiline blocks, opening braces/brackets must be on the same line as the preceding code, while closing braces/brackets must be on their own line.
- For interfaces, JSON files, etc. the last field must have a trailing comma in order to have clean file diffs.
- Local
importstatements must use relative file paths.
The respository architecture we utilize for xplr makes all types of files first class citizens.
Usually, in a React project, you would have a src/ which branches into directories like
assets/, components/, and styles/. One of the downsides to such a nested structure is
that files are easily lost and duplication happens more frequently.
xplr is organized with different files segmented into first class directories.
root
├── _posts/
│ ├── [title-of-post].md
│ └── ...
├── _team/
│ ├── [bryan-pan].md
│ └── ...
├── components/
│ ├── Layout.tsx
│ └── ...
├── pages/
│ ├── api/
│ │ └── search.ts
│ ├── team/
│ │ ├── index.tsx
│ │ └── [person].tsx
│ ├── posts/
│ │ ├── index.tsx
│ │ └── [slug].tsx
│ ├── _app.tsx
| └── index.tsx
├── public/
│ └── ...
├── utils/
│ └── ...
├── styles/
│ └── ...
└── ...
All posts go inside the _posts/ directory. Posts must be named in
kebab-case. To see an example post check out this section
of the Appendix.
All team member info go inside the _team/ directory. Files must be named in
kebab-case. To see an example team member file check out
this section of the Appendix.
Components are resuable and/or abstracted React Components used in our pages. Whether you are creating
a Layout to ensure consistency across webpages, or creating a
NavBar, they belong within the components/ page.
For example, we use Layout.tsx to define the generic page layout for all
of our pages. This ensures consitency across pages and reduces future work in respect to creating
pages.
Notable components:
Layout.tsx: TheLayoutcomponent houses the layout for each page. Every page must use theLayoutcomponent
All pages are registered in the pages/ directory. The pages/ directory holds
all of the pages of our website. Routing in Next.js is as easy as
creating a file in pages/ that corresponds to the desired pathname.
For example, if I want to create a team page where the pathname to visit this page lies at /team.
I would go into pages/ and create the file team.tsx.
Notice how the pathname is identical to the file name!
path.tsx➡️/path
Notable pages:
team/: This directory is dedicated to highlighting our teamindex.tsx: A list of our amazing team![person].tsx: A dynamic route for each team member and holds all the posts that team member made to the repository
posts/: This directory is dedicated to hosting the individual posts themselvesindex.tsx: A list of all of our recent posts, with the ability to filter and search[slug].tsx: A dynamic route for the post itself
index.tsx: This component is the root route (i.e./). This route will have a nice splash page for people coming on the site with a search bar. It will also feature a short description of the site, inspo posts, and team members.
All assets are registered in the public/ directory. Put all svg, img, favicon, etc here.
All utility functions are registered in the utils/ directory. The utils/ directory
hosts all hooks, utility funcitons, and componentless objects. Utilities should be
organized by topic, NOT by the originating Component. Generally, components tend to
share actions and in those cases, it's better to quickly look up existing utilities
by their topic than by Component name.
The scripts/ directory stores any development or build time scripts. Anything that a user doesn't
interact with goes in this folder. Generally, if the script you are writing is for the benefit of a
developer as opposed to a user it belongs in this directory.
The styles/ directory is the home for all the stylsheets. These style sheets MUST follow
CSS Modules.
Components are the core of what makes React great! In Next.js it might be confusing that the
components are not tightly bound to the pages themselves. However, the distinction between a Component
and a Page allows us to separate our concerns and allow us to quickly debug and even create new pages.
All React component modules are to be created under the components/ directory, with a filename <ComponentName>.tsx.
If the component you are trying to create requires a little more complexity, it might be a good idea to create subcomponents
To accomplish this:
- Create a directory within
components/labeledComponentName/ - Turn
<ComponentName>.tsxintoComponentName/index.tsx- All your previous imports will still function properly
import ComponentName from '../components/ComponentName';
- Create all the sub-components you need in
ComponentName/to complete development
Suppose you are making a new component for a header named Header which consists of a logo and a series of navigation links, which you want to use as sub-components named Logo and NavLink, respectively. In such a case, your file tree may look something like this:
components
├── Header
│ ├── index.tsx
│ ├── Logo.tsx
│ └── NavLinks.tsx
├── Layout.tsx
└── ...
For this website, we are using functional components and not class-based components.
This is because functional components allow us to use React Hooks, which allow greater flexibility and control over having to rely on rigid lifecycle methods such as componentDidUpdate and componentWillMount.
- Component properties must have a corresponding
interfacewith clearly-defined field types - This
interfacemust appear directly above the exported compoennt. - The name of this
interfacemust be<ComponentName>Props. - Try to avoid optional properties (using the syntax
<propertyName>?: <type>)
Refrain from adding extra functions to a component module outside of the component function itself. If you want to include simple, brief functions within a component module, add them to the component function as named lambda expressions, like so:
const someFunction = (arg1: <type>, arg2: <type>, ...): <return type> => {
...
};This is primarily useful for functions that use JSX code.
For larger, more complex functions that don't use JSX code, create a utility module! See Hooks and Utilites below for more information.
The general structure of a component module:
import React from 'react';
interface ComponentNameProps {
someField: number;
anotherField?: string;
...
}
export default function ComponentName(props: ComponentNameProps) {
...
return(
...
);
}Styles for a component should be placed in styles/. The stylesheet's file name, like the component's name, should be <ComponentName>.module.scss.
If your component consists of multiple sub-components, you must use one single stylesheet for all these sub-components and the top-level component. In this case, the stylesheet's file name will match the name of the top-level component.
As mentioned in General Syntax and Format above, class and identifier names must be in camelCase. All rules within a style must end with a semicolon.
Do not use
!important.
Nine times out of ten, any problems solved by adding this to a rule can be solved by rearranging some
code. If you absolutely need to use !important, make sure you include a comment in your PR
explaining why.
Next.js enforces module based styling. This means your files must be named with the .module.scss
file extension AND they must be imported as the following:
import styles from '../styles/[MyComponent].module.scss';
<div className={styles.container}/>Module-based styling puts your styles in a local scope. Imagine if you had two different css files
where you declared the CSS class .container. Collisions are inevitable, especially when working
with team members on a big project. CSS modules lets you program without having to worry about
collisions!
To read more about CSS Modules check out this doc.
If you make any functions or interfaces which are not directly linked to or are too large to be a
lambda function member of a specific component, such as a utility function for performing a useful
calculation or a custom React Hook, these must go inside the utils/ directory.
To maintain structure, we recommend you adhere to the following file organization guidelines:
- Complex functions used in a specific component should go inside a file named
<utilityName>.ts. - General, non-specific utilites should go inside a file named
misc.ts. - Custom React Hooks should go inside a file named
hooks.ts.
All assets must go inside the public/ directory.
As much as possible, use
.svgfiles if you can.
To use an asset inside a component, you must import it like so (file path is just an example):
import <AssetName> from '../public/<asset>.<ext>';Remember from General Syntax and Format above that imported asset names must be in PascalCase.
Below is an example post for xplr. We will utilize gray-matter to hold our metadata.
Notice that:
slugis the url path of the post and is identical to the file name (this will help) against duplicate path names as we cannot have identical file namestitleis identical to the post title
File: _posts/next-js.md
---
title: Next.js: The future of JavaScript Frameworks
description: Next.js is a powerful JavaScript framework that takes everything we already love about React and brings it up to eleven.
author: Bryan Pan
tags: javascript web-dev tooling
slug: next-js
---
# Next.js: The Future of JavaScript Frameworks
Intro text blah blah...
## Why is Next.js interesting?
It's great...
## How can we use Next.js?
Everything...
## Resources and Examples
- [2021 deds site](https://tinycl.com/deds)Below is an example team member for xplr. We will utilize gray-matter to hold our metadata.
Notice that:
namemust be capitalized and identical toauthormetadata on a post and the file name is thenamebut inkebab-case
File: _team/bryan-pan.md
---
name: Bryan Pan
year: 2022
major: Computer Science
---
[!A beautiful image of Bryan Pan](_team/assets/bryan-pan.png)
# Bryan Pan
Little blurb about me and what I like...