├── .eslintrc.json
├── .gitignore
├── README.md
├── app
├── (custom)
│ ├── layout.js
│ └── newsletter
│ │ └── page.js
├── (primary)
│ ├── dashboard
│ │ ├── account
│ │ │ └── page.js
│ │ ├── analytics
│ │ │ └── page.js
│ │ ├── layout.js
│ │ └── settings
│ │ │ ├── @notifications
│ │ │ ├── page.js
│ │ │ └── users
│ │ │ │ └── page.js
│ │ │ ├── @revenue
│ │ │ ├── default.js
│ │ │ ├── loading.js
│ │ │ └── page.js
│ │ │ ├── default.js
│ │ │ ├── error.js
│ │ │ ├── layout.js
│ │ │ ├── loading.js
│ │ │ └── page.js
│ ├── layout.js
│ └── page.js
├── favicon.ico
├── globals.css
└── layout.js
├── components
├── DashboardNavLink.js
├── Footer.js
├── Header.js
├── HeaderNavLink.js
├── NewsletterFooter.js
└── SearchField.js
├── jsconfig.json
├── next.config.js
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
├── next.svg
└── vercel.svg
└── tailwind.config.js
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/.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 |
27 | # local env files
28 | .env*.local
29 |
30 | # vercel
31 | .vercel
32 |
33 | # typescript
34 | *.tsbuildinfo
35 | next-env.d.ts
36 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2 |
3 | ## Getting Started
4 |
5 | First, run the development server:
6 |
7 | ```bash
8 | npm run dev
9 | # or
10 | yarn dev
11 | # or
12 | pnpm dev
13 | ```
14 |
15 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
16 |
17 | You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file.
18 |
19 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
20 |
21 | ## Learn More
22 |
23 | To learn more about Next.js, take a look at the following resources:
24 |
25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
27 |
28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
29 |
30 | ## Deploy on Vercel
31 |
32 | 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.
33 |
34 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
35 |
--------------------------------------------------------------------------------
/app/(custom)/layout.js:
--------------------------------------------------------------------------------
1 | import NewsletterFooter from '@/components/NewsletterFooter';
2 |
3 | export default function CustomLayout({ children }) {
4 | return (
5 |
6 |
7 | {children}
8 |
9 |
10 |
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/app/(custom)/newsletter/page.js:
--------------------------------------------------------------------------------
1 | export const NewsletterPage = () => {
2 | return (
3 |
4 |
5 | Get our Weekly Developer's Tips via Email
6 |
7 |
8 |
14 |
20 |
21 |
22 | );
23 | };
24 |
25 | export default NewsletterPage;
26 |
--------------------------------------------------------------------------------
/app/(primary)/dashboard/account/page.js:
--------------------------------------------------------------------------------
1 | const AccountPage = () => {
2 | return Account screen
;
3 | };
4 |
5 | export default AccountPage;
6 |
--------------------------------------------------------------------------------
/app/(primary)/dashboard/analytics/page.js:
--------------------------------------------------------------------------------
1 | const Page = () => {
2 | return Analytics here...
;
3 | };
4 |
5 | export default Page;
6 |
--------------------------------------------------------------------------------
/app/(primary)/dashboard/layout.js:
--------------------------------------------------------------------------------
1 | import DashboardNavLink from '@/components/DashboardNavLink';
2 |
3 | const DashboardLayout = ({ children }) => {
4 | return (
5 |
6 |
32 |
33 | {children}
34 |
35 |
36 | );
37 | };
38 |
39 | export default DashboardLayout;
40 |
--------------------------------------------------------------------------------
/app/(primary)/dashboard/settings/@notifications/page.js:
--------------------------------------------------------------------------------
1 | export default async function Notifications() {
2 | await new Promise((resolve) => setTimeout(resolve, 3000));
3 | return Notifications
;
4 | }
5 |
--------------------------------------------------------------------------------
/app/(primary)/dashboard/settings/@notifications/users/page.js:
--------------------------------------------------------------------------------
1 | export default async function Users() {
2 | await new Promise((resolve) => setTimeout(resolve, 3000));
3 | return users notifications
;
4 | }
5 |
--------------------------------------------------------------------------------
/app/(primary)/dashboard/settings/@revenue/default.js:
--------------------------------------------------------------------------------
1 | export default function RevenueDefault() {
2 | return Revenue default page
;
3 | }
4 |
--------------------------------------------------------------------------------
/app/(primary)/dashboard/settings/@revenue/loading.js:
--------------------------------------------------------------------------------
1 | export default function LoadingRevenue() {
2 | return Loading revenue...
;
3 | }
4 |
--------------------------------------------------------------------------------
/app/(primary)/dashboard/settings/@revenue/page.js:
--------------------------------------------------------------------------------
1 | export default async function Revenue() {
2 | await new Promise((resolve) => setTimeout(resolve, 5000));
3 | // throw new Error();
4 | return Revenue metrics
;
5 | }
6 |
--------------------------------------------------------------------------------
/app/(primary)/dashboard/settings/default.js:
--------------------------------------------------------------------------------
1 | export default function SettingsDefault() {
2 | return Settings default page
;
3 | }
4 |
--------------------------------------------------------------------------------
/app/(primary)/dashboard/settings/error.js:
--------------------------------------------------------------------------------
1 | 'use client'; // Error components must be Client Components
2 |
3 | export default function Error() {
4 | return (
5 |
6 |
Something went wrong!
7 |
8 | );
9 | }
10 |
--------------------------------------------------------------------------------
/app/(primary)/dashboard/settings/layout.js:
--------------------------------------------------------------------------------
1 | const SettingsPageLayout = ({ children, notifications, revenue }) => {
2 | return (
3 | <>
4 | {children}
5 |
6 |
7 | {notifications}
8 |
9 |
10 |
11 | {revenue}
12 |
13 |
14 | >
15 | );
16 | };
17 |
18 | export default SettingsPageLayout;
19 |
--------------------------------------------------------------------------------
/app/(primary)/dashboard/settings/loading.js:
--------------------------------------------------------------------------------
1 | export default function Loading() {
2 | return Loading...
;
3 | }
4 |
--------------------------------------------------------------------------------
/app/(primary)/dashboard/settings/page.js:
--------------------------------------------------------------------------------
1 | const SettingsPage = async () => {
2 | await new Promise((resolve) => setTimeout(resolve, 2000));
3 | return Settings page
;
4 | };
5 |
6 | export default SettingsPage;
7 |
--------------------------------------------------------------------------------
/app/(primary)/layout.js:
--------------------------------------------------------------------------------
1 | import Header from '@/components/Header';
2 | import Footer from '@/components/Footer';
3 |
4 | export default function MainLayout({ children }) {
5 | return (
6 |
7 |
8 |
9 | {children}
10 |
11 |
12 |
13 | );
14 | }
15 |
--------------------------------------------------------------------------------
/app/(primary)/page.js:
--------------------------------------------------------------------------------
1 | const Home = () => {
2 | return (
3 |
4 |
5 | Demo project
6 |
7 |
8 | Nested layouts in Next.js
9 |
10 |
11 | );
12 | };
13 |
14 | export default Home;
15 |
--------------------------------------------------------------------------------
/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Ibaslogic/nextjs-nested-layout-app-dir/fca22424b8804c8dd3716dfe35c81c703d5b88ab/app/favicon.ico
--------------------------------------------------------------------------------
/app/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | :root {
6 | --foreground-rgb: #464646;
7 | }
8 |
9 | body {
10 | color: rgb(var(--foreground-rgb));
11 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI',
12 | sans-serif;
13 | }
14 |
15 | @layer base {
16 | h2 {
17 | @apply text-base font-semibold mb-3;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/layout.js:
--------------------------------------------------------------------------------
1 | import './globals.css';
2 |
3 | export const metadata = {
4 | title: 'Create Next App',
5 | description: 'Generated by create next app',
6 | };
7 |
8 | export default function RootLayout({ children }) {
9 | return (
10 |
11 | {children}
12 |
13 | );
14 | }
15 |
--------------------------------------------------------------------------------
/components/DashboardNavLink.js:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import Link from 'next/link';
4 | import { usePathname } from 'next/navigation';
5 |
6 | const DashboardNavLink = ({ href, children }) => {
7 | const pathname = usePathname();
8 | const active = href === pathname;
9 |
10 | return (
11 |
17 | {children}
18 |
19 | );
20 | };
21 |
22 | export default DashboardNavLink;
23 |
--------------------------------------------------------------------------------
/components/Footer.js:
--------------------------------------------------------------------------------
1 | const Footer = () => {
2 | return (
3 |
6 | );
7 | };
8 |
9 | export default Footer;
10 |
--------------------------------------------------------------------------------
/components/Header.js:
--------------------------------------------------------------------------------
1 | import Image from 'next/image';
2 | import Link from 'next/link';
3 | import HeaderNavLink from './HeaderNavLink';
4 | import SearchField from './SearchField';
5 |
6 | const menuItems = [
7 | { label: `Home`, url: `/` },
8 | { label: `Dashboard`, url: `/dashboard/analytics` },
9 | { label: `Newsletter`, url: `/newsletter` },
10 | ];
11 |
12 | const Header = () => {
13 | return (
14 |
15 |
16 |
17 |
24 |
25 |
34 |
35 |
36 |
37 |
38 | );
39 | };
40 |
41 | export default Header;
42 |
--------------------------------------------------------------------------------
/components/HeaderNavLink.js:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import Link from 'next/link';
4 | import { usePathname } from 'next/navigation';
5 |
6 | const HeaderNavLink = ({ href, children }) => {
7 | const pathname = usePathname();
8 | const active = href === pathname;
9 |
10 | return (
11 |
21 | {children}
22 |
23 | );
24 | };
25 |
26 | export default HeaderNavLink;
27 |
--------------------------------------------------------------------------------
/components/NewsletterFooter.js:
--------------------------------------------------------------------------------
1 | import Image from 'next/image';
2 | import Link from 'next/link';
3 |
4 | const NewsletterFooter = () => {
5 | return (
6 |
22 | );
23 | };
24 |
25 | export default NewsletterFooter;
26 |
--------------------------------------------------------------------------------
/components/SearchField.js:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { useState } from 'react';
4 |
5 | const SearchField = () => {
6 | const [search, setSearch] = useState('');
7 |
8 | return (
9 | setSearch(e.target.value)}
13 | className="block w-full border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:border-gray-500"
14 | placeholder="Search..."
15 | />
16 | );
17 | };
18 |
19 | export default SearchField;
20 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "paths": {
4 | "@/*": ["./*"]
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {};
3 |
4 | module.exports = nextConfig;
5 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nextjs-layout-app-dir",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "autoprefixer": "10.4.14",
13 | "eslint": "8.40.0",
14 | "eslint-config-next": "13.4.1",
15 | "next": "^14.1.0",
16 | "postcss": "8.4.23",
17 | "react": "18.2.0",
18 | "react-dom": "18.2.0",
19 | "tailwindcss": "3.3.2"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | './pages/**/*.{js,ts,jsx,tsx,mdx}',
5 | './components/**/*.{js,ts,jsx,tsx,mdx}',
6 | './app/**/*.{js,ts,jsx,tsx,mdx}',
7 | ],
8 | theme: {
9 | extend: {
10 | backgroundImage: {
11 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
12 | 'gradient-conic':
13 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
14 | },
15 | },
16 | },
17 | plugins: [],
18 | }
19 |
--------------------------------------------------------------------------------