Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions coding-standards.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Coding Standards

## Table of Contents

1. [Naming Convention](#naming-convention)
1. [Import](#import)

---

## Naming Convention

### Format Options[^1]

1. `camelCase` : standard `camelCase` format - no underscores are allowed between characters, and consecutive capitals are allowed (i.e. both `myID` and `myId` - are valid).
1. `PascalCase` : same as `camelCase`, except the first character must be upper-case.
1. `snake_case` : standard `snake_case` format - all characters must be lower-case, and underscores are allowed.
1. `strictCamelCase` : same as `camelCase`, but consecutive capitals are not allowed (i.e. `myId` is valid, but `myID` is not).
1. `StrictPascalCase` : same as `strictCamelCase`, except the first character must be upper-case.
1. `UPPER_CASE` : same as `snake_case`, except all characters must be upper-case.

### Format of Names

#### General

| Name Of | Format | Prefix |
| --------: | :----------- | -------------------- |
| Classe | `PascalCase` | |
| Variable | `camelCase` | |
| Function | `camelCase` | |
| File | `camelCase` | (component name)[^2] |
| Directory | `camelCase` | |
| Constant | `UPPER_CASE` | |

##### Files for React Component

1. Prefix with component name
1. Postfix with utility
1. Use **singular** form for `type` and `state` files
1. Postfix view-file with import-name of the `View` component
1. Extension should be `tsx` only when `react` element is exported
1. Example:
- `compInteractor.ts`
- `compPresenter.tsx`
- `compViewInput.tsx`
- `compState.ts`
- `compType.ts`

#### React Variables

| Name Of | Format | Prefix |
| --------: | :----------- | ------ |
| Component | `PascalCase` | |
| Type | `PascalCase` | |
| Interface | `PascalCase` | |
| State | `camelCase` | |
| Hook | `camelCase` | `use` |
| URL | `UPPER_CASE` | |

## Import

### Local

1. Import local states as `mState` and use them with dot notation
1. Import local types as `mType` and use them with dot notation
1. Import example:
- State : `import * as mState from './compState';`
- Type : `import * as mType from './compType';`
1. Usage example:
- State : `const inputValue = useAtom(mState.inputValue);`
- Type :`const inputValue : mType.InputValue = {};`

### Global

1. Import global states as `gState` and use them with dot notation
1. Import global types as `gType` and use them with dot notation
1. Import example:
- State : `import * as gState from '../../controller/data/states';`
- Type : `import * as gType from '../../controller/data/types';`
1. Usage example:
- State : `const inputValue = useAtom(gState.inputValue);`
- Type :`const inputValue : gType.InputValue = {};`

[^1]: <https://typescript-eslint.io/rules/naming-convention/#format-options>

[^2]: `( )` means "if applicable"
4 changes: 2 additions & 2 deletions components/errors/errorsViewImage.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { useAtomValue } from 'jotai';
import Image from 'next/image';
import Link from 'next/link';
import { stateErrorCode } from '../../controllers/data/states';
import * as gState from '../../controllers/data/states';
import imageSrc404 from '../../public/assets/images/404_broken_robot.png';
import imageSrc500 from '../../public/assets/images/500_faulty_dog.png';
import styles from './errors.module.scss';

const View = () => {
const errorCode = useAtomValue(stateErrorCode);
const errorCode = useAtomValue(gState.errorCode);

return (
<div className={styles.errorImage}>
Expand Down
5 changes: 2 additions & 3 deletions components/example/examplePresenter.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { placeholderUrl } from '../../controllers/apiURLs';
import { useStaticQuery } from '../../controllers/net/staticQuery';
import styles from './example.module.scss';
import { ExamplePost } from './exampleType';
import * as mType from './exampleType';
import Posts from './exampleViewPosts';

const Presenter = () => {
const query = useStaticQuery<ExamplePost[]>(placeholderUrl);
const query = useStaticQuery<mType.Post[]>(placeholderUrl);

let contents;
switch (query.status) {
Expand Down
2 changes: 1 addition & 1 deletion components/example/exampleType.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export type ExamplePost = {
export type Post = {
id: number;
title: string;
body: string;
Expand Down
4 changes: 2 additions & 2 deletions components/example/exampleViewPostSingle.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { memo } from 'react';
import styles from './example.module.scss';
import { ExamplePost } from './exampleType';
import * as mType from './exampleType';

// This uses props to get data from parent
const View = ({ post }: { post: ExamplePost }) => {
const View = ({ post }: { post: mType.Post }) => {
return <p className={styles.view}>{post.title}</p>;
};

Expand Down
6 changes: 3 additions & 3 deletions components/example/exampleViewPosts.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import styles from './example.module.scss';
import { ExamplePost } from './exampleType';
import * as mType from './exampleType';
import PostSingle from './exampleViewPostSingle';

const View = ({ data }: { data: ExamplePost[] }) => {
const dataMapper = (post: ExamplePost) => <PostSingle key={post.id} post={post} />;
const View = ({ data }: { data: mType.Post[] }) => {
const dataMapper = (post: mType.Post) => <PostSingle key={post.id} post={post} />;

return <div className={styles.view}>{data.map(dataMapper)}</div>;
};
Expand Down
4 changes: 2 additions & 2 deletions components/meta/meta.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import Head from 'next/head';
import { useGTM } from './gtm';
import { TMPropsMeta } from './metaType';
import * as mType from './metaType';

const Meta = (props: TMPropsMeta) => {
const Meta = (props: mType.Props) => {
const authorName = 'junekimdev';
const siteName = "another junekimdev's website";
const homeUrl = process.env.NEXT_PUBLIC_URL ?? 'localhost:3000';
Expand Down
2 changes: 1 addition & 1 deletion components/meta/metaType.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ReactNode } from 'react';

export type TMPropsMeta = {
export type Props = {
title: string;
desc: string;
url: string;
Expand Down
2 changes: 1 addition & 1 deletion controllers/data/states.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { atom } from 'jotai';

export const stateErrorCode = atom(500);
export const errorCode = atom(500);
2 changes: 1 addition & 1 deletion controllers/data/types.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export type TypeError = { code: number; message: string };
export type Error = { code: number; message: string };
14 changes: 7 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,25 @@
"build": "next build",
"export": "next export",
"lint": "eslint",
"inspect-lint": "eslint --inspect-config",
"lint-inspect": "eslint --inspect-config",
"start": "next start"
},
"dependencies": {
"@tanstack/react-query": "^5.65.1",
"jotai": "^2.11.2",
"@tanstack/react-query": "^5.66.0",
"jotai": "^2.11.3",
"next": "^15.1.6",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"sass": "^1.83.4",
"sass": "^1.84.0",
"sharp": "^0.33.3"
},
"devDependencies": {
"@eslint/js": "^9.19.0",
"@next/eslint-plugin-next": "^15.1.6",
"@stylistic/eslint-plugin": "^3.0.1",
"@tanstack/react-query-devtools": "^5.65.1",
"@tanstack/react-query-devtools": "^5.66.0",
"@testing-library/react": "^16.2.0",
"@types/node": "^22.12.0",
"@types/node": "^22.13.1",
"@types/react": "^19.0.8",
"@types/react-dom": "^19.0.3",
"ejs": "^3.1.9",
Expand All @@ -39,7 +39,7 @@
"jest-environment-jsdom": "^29.7.0",
"prettier": "^3.4.2",
"typescript": "^5.7.3",
"typescript-eslint": "^8.22.0"
"typescript-eslint": "^8.23.0"
},
"browserslist": {
"production": [
Expand Down
4 changes: 2 additions & 2 deletions pages/404.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { useSetAtom } from 'jotai';
import { useEffect } from 'react';
import Errors from '../components/errors';
import Meta from '../components/meta';
import { stateErrorCode } from '../controllers/data/states';
import * as gState from '../controllers/data/states';

const Error404 = () => {
const publicUrl = process.env.PUBLIC_URL || 'localhost:3000';
const setErrorCode = useSetAtom(stateErrorCode);
const setErrorCode = useSetAtom(gState.errorCode);

useEffect(() => {
setErrorCode(404);
Expand Down
4 changes: 2 additions & 2 deletions pages/_error.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { NextPageContext } from 'next';
import { useEffect } from 'react';
import Errors from '../components/errors';
import Meta from '../components/meta';
import { stateErrorCode } from '../controllers/data/states';
import * as gState from '../controllers/data/states';

const Error = ({ statusCode }: { statusCode: number }) => {
const publicUrl = process.env.PUBLIC_URL || 'localhost:3000';
const setErrorCode = useSetAtom(stateErrorCode);
const setErrorCode = useSetAtom(gState.errorCode);

useEffect(() => {
window.scrollTo(0, 0);
Expand Down
3 changes: 1 addition & 2 deletions templates/interactor.ejs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<% const camelName = name.charAt(0).toUpperCase() + name.slice(1) -%>
import { Dispatch, SetStateAction } from 'react';
import { Dispatch, MouseEvent, SetStateAction, useCallback } from 'react';

export const useLinkClick = (setState: Dispatch<SetStateAction<string>>) => {
return useCallback(
Expand Down
1 change: 0 additions & 1 deletion templates/presenter.ejs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
<% const camelName = name.charAt(0).toUpperCase() + name.slice(1) -%>
import styles from './<%=name%>.module.scss';

const Presenter = () => {
Expand Down
1 change: 0 additions & 1 deletion templates/view.ejs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
<% const camelName = name.charAt(0).toUpperCase() + name.slice(1) -%>
import { useState } from 'react';
import styles from './<%=name%>.module.scss';
import { useLinkClick } from './<%=name%>Interactor';
Expand Down
6 changes: 3 additions & 3 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "nodenext",
"target": "esnext",
"module": "esnext",
"lib": ["DOM", "ESNext", "WebWorker"],
"declaration": true,
"declarationMap": true,
Expand All @@ -18,7 +18,7 @@
"noFallthroughCasesInSwitch": true,
"skipLibCheck": true,
/* Module Resolution Options */
"moduleResolution": "nodenext",
"moduleResolution": "node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
Expand Down
Loading