diff --git a/dashboard/15-final/app/layout.tsx b/dashboard/15-final/app/layout.tsx
index ef077d2..139fcc0 100644
--- a/dashboard/15-final/app/layout.tsx
+++ b/dashboard/15-final/app/layout.tsx
@@ -16,7 +16,7 @@ export default function RootLayout({
}) {
return (
-
{children}
+ {children}
)
}
diff --git a/dashboard/15-final/app/login/page.tsx b/dashboard/15-final/app/login/page.tsx
index e65cbe6..522ecd1 100644
--- a/dashboard/15-final/app/login/page.tsx
+++ b/dashboard/15-final/app/login/page.tsx
@@ -1,7 +1,9 @@
+import LoginForm from "@/app/ui/login-form";
+
export default function Page() {
return (
-
-
Replace with login-form.tsx
-
- )
+
+
+
+ );
}
diff --git a/dashboard/15-final/app/page.tsx b/dashboard/15-final/app/page.tsx
index 5de4f25..76bab6f 100644
--- a/dashboard/15-final/app/page.tsx
+++ b/dashboard/15-final/app/page.tsx
@@ -1,11 +1,9 @@
+import Hero from "@/app/ui/hero";
+
export default function Page() {
return (
-
-
- Landing page. Login button should be in content to avoid root layouts
- and route groups complexity.
-
-
-
- )
+
+
+
+ );
}
diff --git a/dashboard/15-final/app/ui/background-blur.tsx b/dashboard/15-final/app/ui/background-blur.tsx
new file mode 100644
index 0000000..64c23d5
--- /dev/null
+++ b/dashboard/15-final/app/ui/background-blur.tsx
@@ -0,0 +1,8 @@
+export default function BackgroundBlur() {
+ return (
+
+ );
+}
diff --git a/dashboard/15-final/app/ui/hero.tsx b/dashboard/15-final/app/ui/hero.tsx
new file mode 100644
index 0000000..06f8a30
--- /dev/null
+++ b/dashboard/15-final/app/ui/hero.tsx
@@ -0,0 +1,30 @@
+import BackgroundBlur from "@/app/ui/background-blur";
+
+export default function Hero() {
+ return (
+ <>
+
+
+
+ Next.js Dashboard
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut vulputate
+ dapibus consectetur. Duis quis eros euismod.
+
+
+
+
+
+
+
+

+
+ >
+ );
+}
diff --git a/dashboard/15-final/app/ui/login-form.tsx b/dashboard/15-final/app/ui/login-form.tsx
new file mode 100644
index 0000000..1ca08a6
--- /dev/null
+++ b/dashboard/15-final/app/ui/login-form.tsx
@@ -0,0 +1,71 @@
+"use client";
+
+import BackgroundBlur from "@/app/ui/background-blur";
+import React, { useState } from "react";
+
+// This component contains basic logic for a React Form.
+// We'll be updating it in Chapter 8 - Adding Authentication.
+
+export default function LoginForm() {
+ const [email, setEmail] = useState("");
+ const [password, setPassword] = useState("");
+
+ const handleSubmit = (e: { preventDefault: () => void }) => {
+ e.preventDefault();
+ console.log(`Email: ${email}, Password: ${password}`);
+ };
+
+ return (
+
+
+
+
+
+
+ Log in to your dashboard
+
+
+
+ );
+}
diff --git a/dashboard/15-final/package-lock.json b/dashboard/15-final/package-lock.json
index 6caf7d0..e4182fa 100644
--- a/dashboard/15-final/package-lock.json
+++ b/dashboard/15-final/package-lock.json
@@ -20,6 +20,10 @@
"react-dom": "18.2.0",
"tailwindcss": "3.3.3",
"typescript": "5.2.2"
+ },
+ "devDependencies": {
+ "prettier": "^3.0.3",
+ "prettier-plugin-tailwindcss": "^0.5.3"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@@ -3122,6 +3126,93 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/prettier": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz",
+ "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==",
+ "dev": true,
+ "bin": {
+ "prettier": "bin/prettier.cjs"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
+ "node_modules/prettier-plugin-tailwindcss": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.5.3.tgz",
+ "integrity": "sha512-M5K80V21yM+CTm/FEFYRv9/9LyInYbCSXpIoPAKMm8zy89IOwdiA2e4JVbcO7tvRtAQWz32zdj7/WKcsmFyAVg==",
+ "dev": true,
+ "engines": {
+ "node": ">=14.21.3"
+ },
+ "peerDependencies": {
+ "@ianvs/prettier-plugin-sort-imports": "*",
+ "@prettier/plugin-pug": "*",
+ "@shopify/prettier-plugin-liquid": "*",
+ "@shufo/prettier-plugin-blade": "*",
+ "@trivago/prettier-plugin-sort-imports": "*",
+ "prettier": "^3.0",
+ "prettier-plugin-astro": "*",
+ "prettier-plugin-css-order": "*",
+ "prettier-plugin-import-sort": "*",
+ "prettier-plugin-jsdoc": "*",
+ "prettier-plugin-organize-attributes": "*",
+ "prettier-plugin-organize-imports": "*",
+ "prettier-plugin-style-order": "*",
+ "prettier-plugin-svelte": "*"
+ },
+ "peerDependenciesMeta": {
+ "@ianvs/prettier-plugin-sort-imports": {
+ "optional": true
+ },
+ "@prettier/plugin-pug": {
+ "optional": true
+ },
+ "@shopify/prettier-plugin-liquid": {
+ "optional": true
+ },
+ "@shufo/prettier-plugin-blade": {
+ "optional": true
+ },
+ "@trivago/prettier-plugin-sort-imports": {
+ "optional": true
+ },
+ "prettier-plugin-astro": {
+ "optional": true
+ },
+ "prettier-plugin-css-order": {
+ "optional": true
+ },
+ "prettier-plugin-import-sort": {
+ "optional": true
+ },
+ "prettier-plugin-jsdoc": {
+ "optional": true
+ },
+ "prettier-plugin-marko": {
+ "optional": true
+ },
+ "prettier-plugin-organize-attributes": {
+ "optional": true
+ },
+ "prettier-plugin-organize-imports": {
+ "optional": true
+ },
+ "prettier-plugin-style-order": {
+ "optional": true
+ },
+ "prettier-plugin-svelte": {
+ "optional": true
+ },
+ "prettier-plugin-twig-melody": {
+ "optional": true
+ }
+ }
+ },
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@@ -6111,6 +6202,19 @@
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="
},
+ "prettier": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz",
+ "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==",
+ "dev": true
+ },
+ "prettier-plugin-tailwindcss": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.5.3.tgz",
+ "integrity": "sha512-M5K80V21yM+CTm/FEFYRv9/9LyInYbCSXpIoPAKMm8zy89IOwdiA2e4JVbcO7tvRtAQWz32zdj7/WKcsmFyAVg==",
+ "dev": true,
+ "requires": {}
+ },
"prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
diff --git a/dashboard/15-final/package.json b/dashboard/15-final/package.json
index aa074b9..48cd717 100644
--- a/dashboard/15-final/package.json
+++ b/dashboard/15-final/package.json
@@ -21,5 +21,9 @@
"react-dom": "18.2.0",
"tailwindcss": "3.3.3",
"typescript": "5.2.2"
+ },
+ "devDependencies": {
+ "prettier": "^3.0.3",
+ "prettier-plugin-tailwindcss": "^0.5.3"
}
}
diff --git a/dashboard/15-final/prettier.config.js b/dashboard/15-final/prettier.config.js
new file mode 100644
index 0000000..d573118
--- /dev/null
+++ b/dashboard/15-final/prettier.config.js
@@ -0,0 +1,3 @@
+module.exports = {
+ plugins: ["prettier-plugin-tailwindcss"],
+};