Skip to content

Latest commit

 

History

History
331 lines (246 loc) · 11.5 KB

styleguide.md

File metadata and controls

331 lines (246 loc) · 11.5 KB

Conventions used throughout the project

Table of content:


Style Guide

Introduction This style guide contains information about file, class and variable naming conventions, code practices, file structure and rules about the usage of TS types.


Naming Conventions:

The following naming conventions were agreed upon in the set-up phase of the project and should always be followed.

Folder

Folder names should be in camelCase.

Files

.ts files that

  • Exports a single class should be in PascalCase
  • Exports a single interface should be in PascalCase and begin with an uppercase "I".
    • Ex. interface called IPoint should be in a file called IPoint.ts to indicate that it exports an interface.
  • Does not export a single class or interface should be in camelCase

.svelte files that

  • Is a component should be in PascalCase
  • Is a route should be in camelCase

.json files should be in PascalCase

Classes and Interfaces

Class names should be in PascalCase Interface names should be in PascalCase and begin with an uppercase "I" to indicate that it is an interface.

Variables

  • Variable names should be in camelCase.
  • Private properties should begin with _ (underscore) or #:
    • _ (underscore) represents a variable using the native TypeScript access modifier private, which is a compile-time construct that prevents private properties from being accessed outside of the class. After compilation the private property is simply removed.
    • # represents a JavaScript private field and is a runtime feature that enforces privacy, making the field inaccessible outside the class even during runtime.
  • Variable names should be written in full.
    • siteCtx should be siteContext
    • testBtn should be testButton

Functions & Methods

Functions and members should be in camelCase.

HTML & CSS

  • CSS classes and id's should be in kebab-case
  • CSS variables loaded using the GlobalCssSchemesLoader should be in kebab-case with an initial --
    • Example: --test-css-variable-name

Good Code Practices:

  • Use const instead of let whenever possible.
  • Use async/await instead of Promises whenever possible.
  • Use explicit types as it makes the code more readable and makes it easier to identify type related errors.
  • Use private properties to encapsulate implementation details that are not relevant to other components.
  • If a function cant be described based on its name it is too big and should be split.

File structure specifics:

  • Group related files in the same directory.

TypeScript Type Practices:

  • Mark function parameters and object properties as optional (?) if they can be omitted.
  • Mark properties as readonly if it should not be changed after being created.
  • Always explicitely specify types as TypeScript might not always be able to infer it.
  • Use null and undefined carefully.
  • DO NOT use the any type as it omits all type checking. In extreme cases one can use the unknown type if necessary.
  • DO NOT use @ts-ignore or @ts-expect-error as they disable TypeScript checks

For a more in-depth and complete style one can visit the Google TypeScript Style Guide.


Comment Practices:

Use JSDoc comments for classes, methods and functions. JSDoc comments are useful as they can provide a lot of information. An example of a JSDoc comment can be seen in the following code block:

/**
 * Function for concatenating two strings.
 *
 * @param a - The first input string
 * @param b - The second input string
 * @returns The concatenation of `a` and `b`
 */
function concat(a: string, b: string): string {
  return a + b;
}

For more information on JSDoc comments, visit @use JSDoc

Comment writing guidelines:

  1. Avoid obvious comments i.e. code that is self-explanatory.
  2. Write comments for complex code that explains what it does.

Folder Structure:

The following folder structure is meant to be a guideline of where one should put specific files and folders.

.
├── examples
│   └── <-- Working examples of projects -->
├── presentation
│   └── <-- Example pictures of the application -->
├── src
│   ├── lib
│   │   ├── interfaces
│   │   │   └── <-- Folders and typescript files for interfaces -->
│   │   ├── classes
│   │   │   └── <-- Folders and typescript files for object classes -->
│   │   ├── globalState
│   │   │   └── <-- Folders and files related to the global state of the application -->
│   │   └── components
│   │       ├── <-- Folders and files for Svelte components -->
│   │       └── samplesImplementations
│   │           └── <-- An example of how one would implement and use a specific component -->
│   │
│   ├── routes
│   │   └── <-- Files for routing and global layout -->
│   └── tests
│       └── <-- Unit test files here.
                Folder structure should copy the project structure starting from src,
                and put tests in their corresponing folders ->
├── static
└── tests
    └── <-- End-to-end test files here.
            Folder structure should copy the project structure starting from src,
            and put tests in their corresponing folders -->

Tests writing guidelines:

  • There should be a one to one relation between files tested and test files.
  • When writing end-to-end tests the test names should explain the test.
  • When writing unit tests, the describe and it functions should be used in a way such that they form a sentence.

An example of a unit test:

describe('Circle class', => {
  describe('area is calculated when', => {
    it('sets the radius', => { ... });
    it('sets the diameter', => { ... });
    it('sets the circumference', => { ... });
  });
});

Using the CSS Schemes Loader

The CSS loader was created to support dynamic loading of color schemes and userdefined colorschemes.

General JSON Structure

The different media schemes are stored using a JSON file. The root of this file contains a default mediascheme and a list of mediaschemes:

const MediaSchemes = z
  .object({
    default: RequiredMediaScheme.required(),
    schemes: z.array(MediaScheme),
  })
  .strict();
  1. Default scheme: Requires all defined CSS variables to have a default fallback value to prevent the situation where an elements does not have styling. This scheme automatically also functions as the "light mode" styling.
  2. List of mediaschemes: Contains specifications of some CSS variables that overwrites the standard values in case the mediafeature matches the browser. Example: A mediascheme has mediafeature "prefers-color-scheme: dark". This feature is matched when the browser is set to dark mode.

Supporting New CSS Media Features

To add support for additional mediafeatures one has to add a new mediafeature object to the schemes array located in the root of the JSON file.

The MediaScheme definition looks like the following:

const MediaScheme = z
  .object({
    mediaFeature: z.string(),
    color: ColorVariables.partial().optional(),
    fontSize: FontSizeVariables.partial().optional(),
    border: BorderVariables.partial().optional(),
  })
  .strict();

As seen in the above definition of MediaScheme one is not required to specify any color, fontSize or border, meaning that one only has to specify the variables specifically needed for that scheme.

An example of a new media scheme can be seen below:

{
  "mediaFeature": "prefers-reduced-motion",
  "color": {},
  "fontSize": {},
  "border": {}
}

A list of media features can be seen on the MDN Web Docs: Using media queries.

Adding CSS Variables

The allowed CSS variables are listed in the CSSVariables.ts file. To add support for new CSS variables these have to be added to the corresponding list.

Example Of Adding A New CSS Variable

The process of adding new CSS variables are the following:

  1. Add the name and type of the variable to the correct scheme in the CSSVariables.ts file. Example: Adding a color called --css-color-name of the type ColorAttribute.
export const ColorVariables = z.object({
  ...
	"--css-color-name": ColorAttribute,
}).strict();
  1. Add a default value in the default scheme in the JSON file.
"color": {
  ...
	"--navigationbar-text-color": ["display-p3", 1, 1, 1],
}
  1. (Optional) Further specify the CSS variable in other media schemes e.g. add a darkmode version.

Specifying A CSS Color Attribute

The color attribute is based on the CSS color() function. The color function takes four parameters and a fifth optional parameter. The syntax is defined as following:

color(colorspace value-one value-two value-three / optional-alpha-value);

The colorspace value should be one of the colorspaces listed in the SupportedGamuts enum in the ColorAttribute.ts file and the four numerical values should be within the range 0-1.

Now that the implementation specifics have been discussed we can take a look at how one would define a color in the JSON file. An example of ColorAttribute is seen in the following:

"--console-scrollbar-thumb-color": [
  "display-p3",
  0.22745098039,
  0.27450980392,
  0.30588235294
],

For more information on the color() function see MDN Web Docs: color()

Using CSS Variables

The specified CSS variables are extremely easy to apply in the GUI as they are simply added as CSS properties in the root file.

Examples of applying the CSS variable --background-color are:

.side-panel {
  ...
  background-color: var(--background-color);
}
<div style="background-color: var(--background-color);">...</div>

A more advanced implementation switching between two CSS variables:

<script>
  let buttonActive: string = "var(--button-active)";
  let buttonInActive: string = "var(--button-inactive)";
</script>
<button
  style="background-color: { currentTab == thisTab
  ? buttonActive
  : buttonInActive}"
></button>