├── .env.example ├── .eslintrc.js ├── .github ├── FUNDING.yml ├── issue-branch.yml ├── pull_request_template.md └── workflows │ ├── create-branch.yml │ ├── issue-autolink.yml │ ├── lint.yml │ └── release-please.yml ├── .gitignore ├── .husky ├── commit-msg ├── post-merge └── pre-commit ├── .npmrc ├── .nvmrc ├── .prettierignore ├── .prettierrc.js ├── .vscode ├── css.code-snippets ├── extensions.json ├── settings.json └── typescriptreact.code-snippets ├── CHANGELOG.md ├── README.md ├── commitlint.config.js ├── jest.config.js ├── jest.setup.js ├── next-env.d.ts ├── next-sitemap.config.js ├── next.config.js ├── package.json ├── pnpm-lock.yaml ├── postcss.config.js ├── public ├── favicon.ico ├── favicon │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── apple-touch-icon.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon.ico │ └── site.webmanifest ├── fonts │ └── inter-var-latin.woff2 ├── images │ ├── new-tab.png │ └── og.jpg └── svg │ ├── Logo.svg │ └── Vercel.svg ├── src ├── __mocks__ │ └── svg.tsx ├── __tests__ │ └── pages │ │ └── HomePage.test.tsx ├── app │ ├── api │ │ └── hello │ │ │ └── route.ts │ ├── components │ │ ├── layout.tsx │ │ └── page.tsx │ ├── error.tsx │ ├── layout.tsx │ ├── not-found.tsx │ └── page.tsx ├── components │ ├── NextImage.tsx │ ├── Skeleton.tsx │ ├── buttons │ │ ├── Button.tsx │ │ ├── IconButton.tsx │ │ └── TextButton.tsx │ └── links │ │ ├── ArrowLink.tsx │ │ ├── ButtonLink.tsx │ │ ├── IconLink.tsx │ │ ├── PrimaryLink.tsx │ │ ├── UnderlineLink.tsx │ │ └── UnstyledLink.tsx ├── constant │ ├── config.ts │ └── env.ts ├── lib │ ├── __tests__ │ │ └── og.test.ts │ ├── env.ts │ ├── helper.ts │ ├── logger.ts │ ├── og.ts │ └── utils.ts └── styles │ ├── colors.css │ └── globals.css ├── tailwind.config.ts ├── tsconfig.json └── vercel.json /.env.example: -------------------------------------------------------------------------------- 1 | # !STARTERCONF Duplicate this to .env.local 2 | 3 | # DEVELOPMENT TOOLS 4 | # Ideally, don't add them to production deployment envs 5 | # !STARTERCONF Change to true if you want to log data 6 | NEXT_PUBLIC_SHOW_LOGGER="false" -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es2021: true, 5 | node: true, 6 | }, 7 | plugins: ['@typescript-eslint', 'simple-import-sort', 'unused-imports'], 8 | extends: [ 9 | 'eslint:recommended', 10 | 'next', 11 | 'next/core-web-vitals', 12 | 'plugin:@typescript-eslint/recommended', 13 | 'prettier', 14 | ], 15 | rules: { 16 | 'no-unused-vars': 'off', 17 | 'no-console': 'warn', 18 | '@typescript-eslint/explicit-module-boundary-types': 'off', 19 | 'react/no-unescaped-entities': 'off', 20 | 21 | 'react/display-name': 'off', 22 | 'react/jsx-curly-brace-presence': [ 23 | 'warn', 24 | { props: 'never', children: 'never' }, 25 | ], 26 | 27 | //#region //*=========== Unused Import =========== 28 | '@typescript-eslint/no-unused-vars': 'off', 29 | 'unused-imports/no-unused-imports': 'warn', 30 | 'unused-imports/no-unused-vars': [ 31 | 'warn', 32 | { 33 | vars: 'all', 34 | varsIgnorePattern: '^_', 35 | args: 'after-used', 36 | argsIgnorePattern: '^_', 37 | }, 38 | ], 39 | //#endregion //*======== Unused Import =========== 40 | 41 | //#region //*=========== Import Sort =========== 42 | 'simple-import-sort/exports': 'warn', 43 | 'simple-import-sort/imports': [ 44 | 'warn', 45 | { 46 | groups: [ 47 | // ext library & side effect imports 48 | ['^@?\\w', '^\\u0000'], 49 | // {s}css files 50 | ['^.+\\.s?css$'], 51 | // Lib and hooks 52 | ['^@/lib', '^@/hooks'], 53 | // static data 54 | ['^@/data'], 55 | // components 56 | ['^@/components', '^@/container'], 57 | // zustand store 58 | ['^@/store'], 59 | // Other imports 60 | ['^@/'], 61 | // relative paths up until 3 level 62 | [ 63 | '^\\./?$', 64 | '^\\.(?!/?$)', 65 | '^\\.\\./?$', 66 | '^\\.\\.(?!/?$)', 67 | '^\\.\\./\\.\\./?$', 68 | '^\\.\\./\\.\\.(?!/?$)', 69 | '^\\.\\./\\.\\./\\.\\./?$', 70 | '^\\.\\./\\.\\./\\.\\.(?!/?$)', 71 | ], 72 | ['^@/types'], 73 | // other that didnt fit in 74 | ['^'], 75 | ], 76 | }, 77 | ], 78 | //#endregion //*======== Import Sort =========== 79 | }, 80 | globals: { 81 | React: true, 82 | JSX: true, 83 | }, 84 | }; 85 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # !STARTERCONF You can delete this file :) Your support is much appreciated! 2 | # These are supported funding model platforms 3 | 4 | github: theodorusclarence 5 | patreon: # Replace with a single Patreon username 6 | open_collective: # Replace with a single Open Collective username 7 | ko_fi: # Replace with a single Ko-fi username 8 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 9 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 10 | liberapay: # Replace with a single Liberapay username 11 | issuehunt: # Replace with a single IssueHunt username 12 | otechie: # Replace with a single Otechie username 13 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 14 | custom: ['https://saweria.co/theodorusclarence'] 15 | -------------------------------------------------------------------------------- /.github/issue-branch.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/robvanderleek/create-issue-branch#option-2-configure-github-action 2 | 3 | # ex: i4-lower_camel_upper 4 | branchName: 'i${issue.number}-${issue.title,}' 5 | branches: 6 | - label: epic 7 | skip: true 8 | - label: debt 9 | skip: true 10 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Description & Technical Solution 2 | 3 | Describe problems, if any, clearly and concisely. 4 | Summarize the impact to the system. 5 | Please also include relevant motivation and context. 6 | Please include a summary of the technical solution and how it solves the problem. 7 | 8 | # Checklist 9 | 10 | - [ ] I have commented my code, particularly in hard-to-understand areas. 11 | - [ ] Already rebased against main branch. 12 | 13 | # Screenshots 14 | 15 | Provide screenshots or videos of the changes made if any. 16 | -------------------------------------------------------------------------------- /.github/workflows/create-branch.yml: -------------------------------------------------------------------------------- 1 | name: Create Branch from Issue 2 | 3 | on: 4 | issues: 5 | types: [assigned] 6 | 7 | jobs: 8 | create_issue_branch_job: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Create Issue Branch 12 | uses: robvanderleek/create-issue-branch@main 13 | env: 14 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 15 | -------------------------------------------------------------------------------- /.github/workflows/issue-autolink.yml: -------------------------------------------------------------------------------- 1 | name: 'Issue Autolink' 2 | on: 3 | pull_request: 4 | types: [opened] 5 | 6 | jobs: 7 | issue-links: 8 | runs-on: ubuntu-latest 9 | permissions: 10 | pull-requests: write 11 | steps: 12 | - uses: tkt-actions/add-issue-links@v1.8.1 13 | with: 14 | repo-token: '${{ secrets.GITHUB_TOKEN }}' 15 | branch-prefix: 'i' 16 | resolve: 'true' 17 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Code Check 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: {} 7 | 8 | concurrency: 9 | group: ${{ github.job }}-${{ github.ref }} 10 | cancel-in-progress: true 11 | 12 | jobs: 13 | lint: 14 | name: ⬣ ESLint, ʦ TypeScript, 💅 Prettier, and 🃏 Test 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: ⬇️ Checkout repo 18 | uses: actions/checkout@v4 19 | 20 | - name: 🤌 Setup pnpm 21 | uses: pnpm/action-setup@v4 22 | with: 23 | version: 9 24 | 25 | - name: ⎔ Setup node 26 | uses: actions/setup-node@v4 27 | with: 28 | node-version: 20 29 | cache: 'pnpm' 30 | 31 | - name: 📥 Download deps 32 | run: pnpm install --frozen-lockfile 33 | 34 | - name: 🔬 Lint 35 | run: pnpm run lint:strict 36 | 37 | - name: 🔎 Type check 38 | run: pnpm run typecheck 39 | 40 | - name: 💅 Prettier check 41 | run: pnpm run format:check 42 | 43 | - name: 🃏 Run jest 44 | run: pnpm run test 45 | -------------------------------------------------------------------------------- /.github/workflows/release-please.yml: -------------------------------------------------------------------------------- 1 | name: release-please 2 | on: 3 | # !STARTERCONF Choose your preferred event 4 | # !Option 1: Manual Trigger from GitHub 5 | workflow_dispatch: 6 | # !Option 2: Release on every push on main branch 7 | # push: 8 | # branches: 9 | # - main 10 | jobs: 11 | release-please: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: google-github-actions/release-please-action@v3 15 | with: 16 | release-type: node 17 | package-name: release-please-action 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | .pnpm-debug.log* 27 | 28 | # local env files 29 | .env 30 | .env*.local 31 | 32 | # vercel 33 | .vercel 34 | 35 | # typescript 36 | *.tsbuildinfo 37 | next-env.d.ts 38 | 39 | # next-sitemap 40 | robots.txt 41 | sitemap.xml 42 | sitemap-*.xml -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx --no-install commitlint --edit "$1" 5 | -------------------------------------------------------------------------------- /.husky/post-merge: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | pnpm install 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx lint-staged -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | enable-pre-post-scripts=true -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v20.10.0 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | .next 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | .pnpm-debug.log* 28 | 29 | # local env files 30 | .env.local 31 | .env.development.local 32 | .env.test.local 33 | .env.production.local 34 | 35 | # vercel 36 | .vercel 37 | 38 | # changelog 39 | CHANGELOG.md 40 | 41 | pnpm-lock.yaml 42 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | arrowParens: 'always', 3 | singleQuote: true, 4 | jsxSingleQuote: true, 5 | tabWidth: 2, 6 | semi: true, 7 | }; 8 | -------------------------------------------------------------------------------- /.vscode/css.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "Region CSS": { 3 | "prefix": "regc", 4 | "body": [ 5 | "/* #region /**=========== ${1} =========== */", 6 | "$0", 7 | "/* #endregion /**======== ${1} =========== */" 8 | ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | // Tailwind CSS Intellisense 4 | "bradlc.vscode-tailwindcss", 5 | "esbenp.prettier-vscode", 6 | "dbaeumer.vscode-eslint", 7 | "aaron-bond.better-comments" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "css.validate": false, 3 | "editor.formatOnSave": true, 4 | "editor.tabSize": 2, 5 | "editor.codeActionsOnSave": { 6 | "source.fixAll": "explicit" 7 | }, 8 | "[css]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, 9 | // Tailwind CSS Autocomplete, add more if used in projects 10 | "tailwindCSS.classAttributes": [ 11 | "class", 12 | "className", 13 | "classNames", 14 | "containerClassName" 15 | ], 16 | "typescript.preferences.importModuleSpecifier": "non-relative" 17 | } 18 | -------------------------------------------------------------------------------- /.vscode/typescriptreact.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | //#region //*=========== React =========== 3 | "import React": { 4 | "prefix": "ir", 5 | "body": ["import * as React from 'react';"] 6 | }, 7 | "React.useState": { 8 | "prefix": "us", 9 | "body": [ 10 | "const [${1}, set${1/(^[a-zA-Z])(.*)/${1:/upcase}${2}/}] = React.useState<$3>(${2:initial${1/(^[a-zA-Z])(.*)/${1:/upcase}${2}/}})$0" 11 | ] 12 | }, 13 | "React.useEffect": { 14 | "prefix": "uf", 15 | "body": ["React.useEffect(() => {", " $0", "}, []);"] 16 | }, 17 | "React.useReducer": { 18 | "prefix": "ur", 19 | "body": [ 20 | "const [state, dispatch] = React.useReducer(${0:someReducer}, {", 21 | " ", 22 | "})" 23 | ] 24 | }, 25 | "React.useRef": { 26 | "prefix": "urf", 27 | "body": ["const ${1:someRef} = React.useRef($0)"] 28 | }, 29 | "React Functional Component": { 30 | "prefix": "rc", 31 | "body": [ 32 | "import * as React from 'react';\n", 33 | "export default function ${1:${TM_FILENAME_BASE}}() {", 34 | " return (", 35 | "
Next.js + Tailwind CSS + TypeScript starter packed with useful development features.
6 |Made by Theodorus Clarence
7 | 8 | [](https://github.com/theodorusclarence/ts-nextjs-tailwind-starter/stargazers) 9 | [](https://depfu.com/github/theodorusclarence/ts-nextjs-tailwind-starter?project_id=30160) 10 | [](https://shields.io/) 11 | 12 |66 | You can change primary color to any Tailwind CSS colors. See 67 | globals.css to change your color. 68 |
69 |132 | No style applied, differentiate internal and outside links, give 133 | custom cursor for outside links. 134 |
135 |145 | Add styling on top of UnstyledLink, giving a primary color to 146 | the link. 147 |
148 |158 | Add styling on top of UnstyledLink, giving a dotted and animated 159 | underline. 160 |
161 |171 | Useful for indicating navigation, I use this quite a lot, so why 172 | not build a component with some whimsy touch? 173 |
174 |199 | Button styled link with 3 variants. 200 |
201 |236 | Ordinary button with style. 237 |
238 |381 | Button with a text style 382 |
383 |391 | Button with only icon inside 392 |
393 |404 | Styled 404 page with some animation. 405 |
406 |413 | Next Image with default props and skeleton animation 414 |
415 |427 | Skeleton with shimmer effect 428 |
429 |36 | A starter for Next.js, Tailwind CSS, and TypeScript with Absolute 37 | Import, Seo, Link component, pre-configured with Husky{' '} 38 |
39 |
40 |