Skip to content

Latest commit

 

History

History
348 lines (258 loc) · 13 KB

File metadata and controls

348 lines (258 loc) · 13 KB

Design Guidelines

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

  • 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 import statements must use relative file paths.

Repository Architecture

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/
│   └── ...
└── ...

Posts

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.

Team

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

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: The Layout component houses the layout for each page. Every page must use the Layout component

Pages

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 team
    • index.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 themselves
    • index.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.

Public

All assets are registered in the public/ directory. Put all svg, img, favicon, etc here.

Utils

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.

Scripts

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.

Styles

The styles/ directory is the home for all the stylsheets. These style sheets MUST follow CSS Modules.

Component Design

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.

Adding a new component

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/ labeled ComponentName/
  • Turn <ComponentName>.tsx into ComponentName/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
└── ...

Writing a component module

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 interface with clearly-defined field types
  • This interface must appear directly above the exported compoennt.
  • The name of this interface must 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(
    ...
  );
}

Styling

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.

Module Based Styling

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.

Hooks and Utilities

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.

Assets

All assets must go inside the public/ directory.

As much as possible, use .svg files 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.

Appendix

Example: Post

Below is an example post for xplr. We will utilize gray-matter to hold our metadata.

Notice that:

  • slug is 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 names
  • title is 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)

Example: Team Member

Below is an example team member for xplr. We will utilize gray-matter to hold our metadata.

Notice that:

  • name must be capitalized and identical to author metadata on a post and the file name is the name but in kebab-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...