pnpm dlx shadcn@latest init
Use the following for downloading the components.
pnpm dlx shadcn@latest add button
It is used for making a reusable component for adding new Tailwind Utilities. We will need it.
Tailwind Utilities
pnpm i clsx tailwind-merge
import clsx, { type ClassValue } from "clsx"; import { twMerge } from "tailwind-merge"; // this function is for reusable components, e.g buttons export function cn(...inputs: ClassValue[]): any { return twMerge(clsx(inputs)); }
You will get it automatically by installing the shadcn.
shadcn
Optional
pnpm i geist
import type { Metadata } from "next"; import "./globals.css"; import { GeistSans } from "geist/font/sans"; import { GeistMono } from "geist/font/mono"; export const metadata: Metadata = { title: "Create Next App", description: "Generated by create next app", }; export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { return ( <html lang="en" className={`${GeistSans.variable} ${GeistMono.variable}`}> <body className="px-4">{children}</body> </html> ); }
... theme: { extend: { fontFamily: { sans: ["var(--font-geist-sans)"], mono: ["var(--font-geist-mono)"], }, }, }, ...
pnpm i next-themes
import type { Metadata } from "next"; import "./globals.css"; import { ThemeProvider } from "next-themes"; export const metadata: Metadata = { title: "Create Next App", description: "Generated by create next app", }; export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { return ( <html lang="en" suppressHydrationWarning> <body> <ThemeProvider attribute="class" disableTransitionOnChange> {children} </ThemeProvider> </body> </html> ); }
import type { Config } from "tailwindcss"; const config: Config = { content: [ "./src/pages/**/*.{js,ts,jsx,tsx,mdx}", "./src/components/**/*.{js,ts,jsx,tsx,mdx}", "./src/app/**/*.{js,ts,jsx,tsx,mdx}", "./src/**/*.{js,ts,jsx,tsx,mdx}", ], darkMode: "class", theme: { extend: {}, }, plugins: [], }; export default config;
:root { --background: 255 255 255; --foreground: 0 0 0; } html.dark { --background: 0 0 0; --foreground: 255 255 255; } body { background-color: rgb(var(--background)); color: rgba(var(--foreground)); }
"use client"; import React from "react"; import { useTheme } from "next-themes"; export default function ThemeButton() { const { setTheme, resolvedTheme } = useTheme(); return ( <div className="fixed bottom-4 right-4"> {resolvedTheme === "dark" ? ( <button onClick={() => setTheme("light")} className="focus:border-wrapper flex h-8 w-8 items-center justify-center rounded-md" > <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M8.76536 2.78058V1.08058C8.76536 0.930293 8.82507 0.786159 8.93134 0.679889C9.03761 0.573618 9.18174 0.513916 9.33203 0.513916C9.48232 0.513916 9.62645 0.573618 9.73273 0.679889C9.839 0.786159 9.8987 0.930293 9.8987 1.08058V2.78058C9.8987 2.93087 9.839 3.07501 9.73273 3.18128C9.62645 3.28755 9.48232 3.34725 9.33203 3.34725C9.18174 3.34725 9.03761 3.28755 8.93134 3.18128C8.82507 3.07501 8.76536 2.93087 8.76536 2.78058ZM13.8654 9.01392C13.8654 9.91052 13.5995 10.787 13.1014 11.5325C12.6032 12.278 11.8952 12.8591 11.0669 13.2022C10.2385 13.5453 9.327 13.6351 8.44762 13.4601C7.56824 13.2852 6.76048 12.8535 6.12648 12.2195C5.49248 11.5855 5.06072 10.7777 4.8858 9.89833C4.71089 9.01894 4.80066 8.10744 5.14378 7.27908C5.48689 6.45073 6.06794 5.74272 6.81345 5.24459C7.55895 4.74646 8.43542 4.48058 9.33203 4.48058C10.5339 4.4819 11.6863 4.95993 12.5361 5.80981C13.386 6.6597 13.8641 7.812 13.8654 9.01392ZM12.732 9.01392C12.732 8.34146 12.5326 7.6841 12.159 7.12498C11.7854 6.56585 11.2544 6.13006 10.6332 5.87273C10.0119 5.61539 9.32826 5.54806 8.66872 5.67925C8.00919 5.81044 7.40337 6.13425 6.92787 6.60975C6.45237 7.08525 6.12855 7.69107 5.99736 8.35061C5.86617 9.01014 5.9335 9.69377 6.19084 10.315C6.44818 10.9363 6.88397 11.4673 7.44309 11.8409C8.00222 12.2145 8.65957 12.4139 9.33203 12.4139C10.2335 12.413 11.0977 12.0545 11.7352 11.417C12.3726 10.7796 12.7311 9.91536 12.732 9.01392ZM4.39778 4.8815C4.50411 4.98783 4.64832 5.04756 4.7987 5.04756C4.94907 5.04756 5.09328 4.98783 5.19961 4.8815C5.30594 4.77517 5.36568 4.63096 5.36568 4.48058C5.36568 4.33021 5.30594 4.186 5.19961 4.07967L4.06628 2.94633C3.95995 2.84 3.81574 2.78027 3.66536 2.78027C3.51499 2.78027 3.37078 2.84 3.26445 2.94633C3.15812 3.05266 3.09838 3.19688 3.09838 3.34725C3.09838 3.49762 3.15812 3.64184 3.26445 3.74817L4.39778 4.8815ZM4.39778 13.1463L3.26445 14.2797C3.15812 14.386 3.09838 14.5302 3.09838 14.6806C3.09838 14.831 3.15812 14.9752 3.26445 15.0815C3.37078 15.1878 3.51499 15.2476 3.66536 15.2476C3.81574 15.2476 3.95995 15.1878 4.06628 15.0815L5.19961 13.9482C5.25226 13.8955 5.29403 13.833 5.32252 13.7642C5.35101 13.6954 5.36568 13.6217 5.36568 13.5472C5.36568 13.4728 5.35101 13.3991 5.32252 13.3303C5.29403 13.2615 5.25226 13.199 5.19961 13.1463C5.14697 13.0937 5.08446 13.0519 5.01567 13.0234C4.94688 12.9949 4.87315 12.9803 4.7987 12.9803C4.72424 12.9803 4.65051 12.9949 4.58172 13.0234C4.51293 13.0519 4.45043 13.0937 4.39778 13.1463ZM13.8654 5.04725C13.9398 5.04731 14.0135 5.0327 14.0823 5.00426C14.1511 4.97582 14.2136 4.93411 14.2663 4.8815L15.3996 3.74817C15.5059 3.64184 15.5657 3.49762 15.5657 3.34725C15.5657 3.19688 15.5059 3.05266 15.3996 2.94633C15.2933 2.84 15.1491 2.78027 14.9987 2.78027C14.8483 2.78027 14.7041 2.84 14.5978 2.94633L13.4644 4.07967C13.3851 4.15892 13.3311 4.25993 13.3092 4.36991C13.2873 4.47989 13.2985 4.5939 13.3414 4.6975C13.3843 4.8011 13.457 4.88963 13.5503 4.95189C13.6436 5.01415 13.7532 5.04734 13.8654 5.04725ZM14.2663 13.1463C14.16 13.04 14.0157 12.9803 13.8654 12.9803C13.715 12.9803 13.5708 13.04 13.4644 13.1463C13.3581 13.2527 13.2984 13.3969 13.2984 13.5472C13.2984 13.6976 13.3581 13.8418 13.4644 13.9482L14.5978 15.0815C14.6504 15.1341 14.7129 15.1759 14.7817 15.2044C14.8505 15.2329 14.9242 15.2476 14.9987 15.2476C15.0732 15.2476 15.1469 15.2329 15.2157 15.2044C15.2845 15.1759 15.347 15.1341 15.3996 15.0815C15.4523 15.0289 15.494 14.9663 15.5225 14.8976C15.551 14.8288 15.5657 14.755 15.5657 14.6806C15.5657 14.6061 15.551 14.5324 15.5225 14.4636C15.494 14.3948 15.4523 14.3323 15.3996 14.2797L14.2663 13.1463ZM3.66536 9.01392C3.66536 8.86363 3.60566 8.71949 3.49939 8.61322C3.39312 8.50695 3.24899 8.44725 3.0987 8.44725H1.3987C1.24841 8.44725 1.10427 8.50695 0.998004 8.61322C0.891733 8.71949 0.832031 8.86363 0.832031 9.01392C0.832031 9.16421 0.891733 9.30834 0.998004 9.41461C1.10427 9.52088 1.24841 9.58058 1.3987 9.58058H3.0987C3.24899 9.58058 3.39312 9.52088 3.49939 9.41461C3.60566 9.30834 3.66536 9.16421 3.66536 9.01392ZM9.33203 14.6806C9.18174 14.6806 9.03761 14.7403 8.93134 14.8466C8.82507 14.9528 8.76536 15.097 8.76536 15.2472V16.9472C8.76536 17.0975 8.82507 17.2417 8.93134 17.3479C9.03761 17.4542 9.18174 17.5139 9.33203 17.5139C9.48232 17.5139 9.62645 17.4542 9.73273 17.3479C9.839 17.2417 9.8987 17.0975 9.8987 16.9472V15.2472C9.8987 15.097 9.839 14.9528 9.73273 14.8466C9.62645 14.7403 9.48232 14.6806 9.33203 14.6806ZM17.2654 8.44725H15.5654C15.4151 8.44725 15.2709 8.50695 15.1647 8.61322C15.0584 8.71949 14.9987 8.86363 14.9987 9.01392C14.9987 9.16421 15.0584 9.30834 15.1647 9.41461C15.2709 9.52088 15.4151 9.58058 15.5654 9.58058H17.2654C17.4157 9.58058 17.5598 9.52088 17.6661 9.41461C17.7723 9.30834 17.832 9.16421 17.832 9.01392C17.832 8.86363 17.7723 8.71949 17.6661 8.61322C17.5598 8.50695 17.4157 8.44725 17.2654 8.44725Z" fill="currentColor" /> </svg> </button> ) : resolvedTheme === "light" ? ( <button onClick={() => setTheme("dark")} className="focus:border-wrapper flex h-8 w-8 items-center justify-center rounded-md" > <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M17.3094 10.6972C17.2238 10.6115 17.1165 10.5507 16.999 10.5213C16.8815 10.4919 16.7583 10.4951 16.6424 10.5305C15.3708 10.9149 14.0186 10.9471 12.7301 10.6237C11.4416 10.3003 10.2649 9.63339 9.32553 8.694C8.38614 7.75461 7.71921 6.57795 7.3958 5.28942C7.07239 4.00088 7.10463 2.64875 7.48907 1.37709C7.52475 1.26121 7.52816 1.13781 7.49895 1.02013C7.46973 0.902463 7.409 0.794982 7.32326 0.70925C7.23753 0.623518 7.13005 0.562779 7.01238 0.533565C6.89471 0.504351 6.7713 0.507768 6.65543 0.543448C4.8973 1.08202 3.35382 2.16137 2.24463 3.62792C1.27462 4.91577 0.682934 6.4486 0.536055 8.0542C0.389176 9.65979 0.692921 11.2745 1.41317 12.717C2.13341 14.1595 3.24162 15.3726 4.61328 16.2199C5.98495 17.0673 7.56573 17.5154 9.17802 17.5139C11.059 17.5196 12.8899 16.9081 14.3899 15.7732C15.8565 14.664 16.9358 13.1206 17.4744 11.3624C17.5097 11.247 17.513 11.1241 17.4839 11.007C17.4548 10.8898 17.3945 10.7828 17.3094 10.6972ZM13.588 14.7078C12.1754 15.7718 10.4261 16.2897 8.66196 16.1661C6.89785 16.0426 5.23774 15.286 3.98722 14.0356C2.73671 12.7852 1.97996 11.1251 1.8563 9.36103C1.73263 7.59693 2.25036 5.84754 3.31419 4.43488C4.00729 3.5196 4.90333 2.77765 5.93183 2.26742C5.87324 2.67859 5.84371 3.09338 5.84346 3.50871C5.84589 5.80735 6.7601 8.01116 8.38549 9.63655C10.0109 11.2619 12.2147 12.1761 14.5133 12.1786C14.9295 12.1784 15.3451 12.1489 15.7571 12.0902C15.2464 13.1189 14.5039 14.0149 13.588 14.7078Z" fill="currentColor" /> </svg> </button> ) : null} </div> ); }
export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { return ( <html lang="en" suppressHydrationWarning className={`${GeistSans.variable} ${GeistMono.variable}`} > <body> <ThemeProvider attribute="class" disableTransitionOnChange> {children} <ThemeButton /> </ThemeProvider> </body> </html> ); }
pnpm i zustand
import { create } from "zustand"; interface useSidebarTypes { currentHeading: string | null; setCurrentHeading: (a: string | null) => void; } export const useSidebar = create<useSidebarTypes>((set) => ({ currentHeading: null, setCurrentHeading: (value) => set({ currentHeading: value }), }));
pnpm i next-nprogress-bar
"use client"; import React, { type ReactNode } from "react"; import { AppProgressBar as ProgressBar } from "next-nprogress-bar"; const ProgressBarProvider = ({ children }: { children: ReactNode }) => { return ( <> {children} <ProgressBar height="2px" color="hsl(var(--primary))" options={{ showSpinner: false }} shallowRouting /> </> ); }; export default ProgressBarProvider;
import type { Metadata } from "next"; import "./globals.css"; import ProgressBarProvider from "@/providers/ProgressBar"; export const metadata: Metadata = { title: "Create Next App", description: "Generated by create next app", }; export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { return ( <html lang="en"> <body className="px-4"> <ProgressBarProvider>{children}</ProgressBarProvider> </body> </html> ); }
pnpm i prettier prettier-plugin-tailwindcss
touch .prettierrc .prettierignore
{ "plugins": ["prettier-plugin-tailwindcss"], "trailingComma": "es5", "tabWidth": 2, "semi": true, "singleQuote": false, "bracketSpacing": true, "bracketSameLine": false, "singleAttributePerLine": false }
/src/docs
pnpm i class-variance-authority