Skip to content

Commit

Permalink
Merge pull request #1 from HohShenYien/dev
Browse files Browse the repository at this point in the history
v0.2.1
  • Loading branch information
HohShenYien authored Aug 4, 2023
2 parents 1aceda9 + 9119941 commit 60fd12e
Show file tree
Hide file tree
Showing 31 changed files with 965 additions and 295 deletions.
3 changes: 2 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
NEXT_PUBLIC_API_URL=localhost:3000/api
# Make sure to add http or axios will throw an error
NEXT_PUBLIC_API_URL=http://localhost:3000/api
122 changes: 91 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,34 @@
# Next Power Starter
<h1>Next Power Starter</h1>

<center>
<img src="https://github.com/HohShenYien/next-power-starter/assets/55322546/e21721f5-bb92-49e0-9d2d-23dc7f98f30d" alt="Next Power Starter">
</center>

<!-- toc -->
<h2>Table of Contents</h2>

- [🧐 About](#-about)
- [⚡ Features](#-features)
- [🛠 Getting Started](#-getting-started)
- [🚩 Usage](#-usage)
- [Recommended File Structure](#recommended-file-structure)
- [Env](#env)
- [Authentication](#authentication)
- [Default API routes](#default-api-routes)
- [Axios](#axios)
- [Public \& non-Public pages](#public--non-public-pages)
- [useSession](#usesession)
- [Auth configs](#auth-configs)
- [useQuery](#usequery)
- [Modal](#modal)
- [Zustand Store](#zustand-store)
- [Theming](#theming)
- [📚 Library](#-library)
- [🧾 Learn More](#-learn-more)
- [🚩 TODO](#-todo)
- [🚀 Deploy on Vercel](#-deploy-on-vercel)

<!-- tocstop -->

## 🧐 About

Expand All @@ -16,17 +40,12 @@ PS: Due to several breaking bugs in App Router, I have reverted back to **Page R

## ⚡ Features

Next Power Starter includes the following features out of the box:

- [Mantine](https://mantine.dev/): A React UI library which supports _almost_ all components you can think of. It also provides dark-mode support and utility hooks that I often find handy.

- [Tailwind CSS](https://tailwindcss.com/): Mantine sometimes lacks the granularity in designing the styles. Tailwind comes naturally as the optimal choice to fill in the gap.

- [useQuery](https://tanstack.com/query/): No more 🙅‍♂️ `fetching` in `useEffect`. Also provides caching and various other powerful features like refetch, loading state, etc.

- [Zustand](https://github.com/pmndrs/zustand): A small but powerful state management library so that we don't need to be bothered about Redux anymore.

- [TypeScript](https://www.typescriptlang.org/): This project is fully typed.
- **💃 Zero Setup**: After installation, you need 0 setup to begin using it, check out the [📚 Library](#-library) section to see what have been added.
- **🧑‍🏭 Extensible and Configurable**: Missing something? Easily add any library without needing to fear that it breaks.
- **🔏 Client-side Authentication**: Fully baked client side authentication with public and authenticated pages, sprinkle more logic if you need.
- **👾 UI Components**: [Mantine](https://mantine.dev) & [Tailwind](https://tailwindcss.com/) out of the box with more than enough components and styles ready for you.
- **🗄️ File Structure**: Stop worrying about a messy file structure with this starter.
- **Fully Typed**

## 🛠 Getting Started

Expand Down Expand Up @@ -60,34 +79,52 @@ Next Power Starter includes the following features out of the box:

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
You can start editing the page by modifying `src/pages/index.tsx`. The page auto-updates as you edit the file.

## 🚩 Usage

## Usage
### Recommended File Structure

```
-src
- components: All the general components
- configs: Constant configurations that do not need to be kept in .env
- features: Groups of related components for specific features
- layouts: Layout Component
- pages: Page Components & Routes
- stores: Zustand stores
- styles: Themes & styles files
- utils: Files that don't see to belong elsewhere
```

### Env

The .env file has one variable that you might want to update

```env
# The base API URL to make any request
NEXT_PUBLIC_API_URL=/api
NEXT_PUBLIC_API_URL=http://localhost:3000/api
```

### Authentication

Currently, **authentication API** routes are in `src/api/auth.ts` (which you should customize), and stored in Cookies (key is authToken). You can find everything related to authentication in `src/features/Auth` folder.
Currently, **authentication API** routes are in `src/features/Auth/queries.ts` (which you should customize), and relies on **http-only** cookie using server. You can find everything related to authentication in `src/features/Auth` folder.

For more information about the Authentication structure, check out my [article](https://blogs.shenyien.cyou/client-side-authentication-in-nextjs-using-cookies).

#### Default API routes

As defined in `src/api/auth.ts`, the following routes are created by default, but you should update them to match your needs
As defined in `src/features/Auth/queries.ts`, the following routes are created by default, but you should update them to match your needs.

The `login` and `logout` routes implement **http-only** cookie setting

```
/auth/login => POST Login route, accept
{
email: string,
password: string
}
returns {auth_token: string}
returns {message: string}
```

```
Expand All @@ -99,9 +136,15 @@ returns {
}
```

```
/auth/logout => Logout the current user
returns {message: string}
```

#### Axios

This project uses Axios where some interceptors have already been implemented in `src/features/Auth/AxiosProvider.tsx`. This includes basic error handling and most importantly, Authentication header will be set from the cookies.
This project uses Axios where some interceptors have already been implemented in `src/features/Auth/AxiosProvider.tsx`. This includes basic error handling and configures the `base path` for requests.

```ts
...
Expand All @@ -115,20 +158,16 @@ This project uses Axios where some interceptors have already been implemented in
...
```

#### JWT & Cookies

The JWT will be stored in cookies, using `cookies-next` library to manage. If you want to access the cookie, you can use `src/features/Auth/hooks/useAuthToken.ts` hook.

#### Public & non-Public pages

Instead of router path pattern, this project uses a less conventional `page.isPublic` component attribute. By default, every page is **public**, so to make authentication compulsory for the page, you set the `isPublic` attribute to false.

For example,

```tsx
import { NextPageWithLayout } from "@/pages/_app";
import { NextPageWithAttributes } from "@/pages/_app";

const ProtectedPage: NextPageWithLayout = () => {
const ProtectedPage: NextPageWithAttributes = () => {
...
}

Expand Down Expand Up @@ -162,10 +201,12 @@ export const loginAfterRegister = false;

### useQuery

The recommended location to keep all the API services is in `src/api/`. By keeping all the queries in the same folder, the queries will be more centralized and you'll less likely get lost in maintaing the query keys. It's also more reusable.
The recommended location to keep all the API services is in `src/features/.../queries.ts`.

You can refer to the [useQuery documentation](https://tanstack.com/query/) for more details.

Learn more about the good `use-query` patterns in this [blog series](https://tkdodo.eu/blog/effective-react-query-keys).

### Modal

To use Mantine's modal, there are two choices here. You can either use [vanilla modal](https://mantine.dev/core/modal/) with the standard `onClose` and `open` disclosures, or [Modal Manager](https://mantine.dev/others/modals/) implemented with a global context manager that is much simpler.
Expand Down Expand Up @@ -232,18 +273,37 @@ const { bears, increase } = useStore(
};
```

### Theming

This starter has filled up all Tailwind colors in Mantine's theme.

To customize Mantine's component theme globally, edit `src/styles/MantineTheme.ts`.

## 📚 Library

Next Power Starter includes the following packages out of the box:

- [Mantine](https://mantine.dev/): A React **Component library** which supports _almost_ all components you can think of. It also provides dark-mode support and utility hooks that I often find handy.

- [Tailwind CSS](https://tailwindcss.com/): Mantine sometimes lacks the granularity in designing the styles. Tailwind comes naturally as the optimal choice to fill in the gap.

- [useQuery](https://tanstack.com/query/): No more 🙅‍♂️ `fetching` in `useEffect`. Also provides caching and various other powerful features like refetch, loading state, etc.

- [Zustand](https://github.com/pmndrs/zustand): A small but powerful state management library so that we don't need to be bothered about Redux anymore.

- [TypeScript](https://www.typescriptlang.org/): This project is fully typed.

- [Zod](https://zod.dev/): Stop writing your own rules for validation, use Zod instead.

## 🧾 Learn More

To learn more about the technologies used, refer to their respective documentations from the link provided in the [features](#-getting-started).
To learn more about the technologies used, refer to their respective documentations from the link provided above.

## 🚩 TODO

- [ ] Improve documentation
- [ ] Add more
- [ ] 404 & 500 page
- [ ] Page headers

## Deploy on Vercel
## 🚀 Deploy on Vercel

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.

Expand Down
82 changes: 0 additions & 82 deletions src/api/auth.ts

This file was deleted.

58 changes: 40 additions & 18 deletions src/components/buttons/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,57 @@ import {

import { PolymorphicComponentProps } from "@mantine/utils";

type ButtonSize = "xs" | "sm" | "md" | "lg" | "xl";

type ButtonProps = PolymorphicComponentProps<"button", MantineButtonProps> & {
gray?: boolean;
size?: ButtonSize;
variant?:
| "gradient"
| "filled"
| "outline"
| "light"
| "white"
| "default"
| "subtle"
| "link";
};

const sizeToClassMapper = (size: ButtonSize) => {
switch (size) {
case "xs":
return "px-2 py-0.5 text-xs ";
case "sm":
return "px-3 py-0.5 text-sm";
case "md":
return "px-4 py-2";
case "lg":
return "text-lg py-1 px-5";
default:
return "text-xl py-1.5 px-5";
}
};

const Button = ({
children,
variant = "filled",
gray = false,
color = "indigo",
size = "md",
classNames,
...props
}: ButtonProps) => {
return (
<MantineButton
{...props}
className={clsx(props.className, "rounded-md py-2 transition-all", {
"border-gray-400 text-gray-500 hover:border-gray-500 hover:bg-gray-200/25 active:bg-gray-200/50":
gray,
"bg-indigo-500 hover:bg-indigo-600 active:bg-indigo-700":
variant == "filled",
"!bg-transparent text-indigo-500 hover:border-indigo-600 hover:text-indigo-600 active:text-indigo-700":
variant == "subtle",
"border-indigo-600 bg-transparent text-indigo-500 hover:border-indigo-600 hover:bg-indigo-500/20 active:bg-indigo-600/20":
variant == "outline",
"text-indigo-500 hover:text-indigo-600 hover:underline active:text-indigo-700":
variant == "link",
"border-none bg-transparent text-indigo-500 hover:bg-indigo-100 hover:text-indigo-600 active:bg-indigo-200":
variant == "default",
})}
variant={variant}
classNames={{ root: "!h-[unset]", label: "py-0.5" }}
color={color}
variant={variant === "link" ? "subtle" : variant}
classNames={{
root: clsx("!h-[unset]", sizeToClassMapper(size), classNames?.root, {
"!bg-transparent hover:brightness-75 transition-all":
variant === "link",
}),
label: clsx("py-0.5", classNames?.label),
...classNames,
}}
>
{children}
</MantineButton>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import React from "react";
import styles from "./NiceLink.module.scss";
import Link from "next/link";

interface NiceLinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
type NiceLinkProps = React.AnchorHTMLAttributes<HTMLAnchorElement> & {
children?: React.ReactNode;
href: string;
}
};

const NiceLink = ({ children, href, ...props }: NiceLinkProps) => {
return (
Expand Down
Loading

1 comment on commit 60fd12e

@vercel
Copy link

@vercel vercel bot commented on 60fd12e Aug 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.