diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..03d9549
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/kdot.iml b/.idea/kdot.iml
new file mode 100644
index 0000000..24643cc
--- /dev/null
+++ b/.idea/kdot.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..8f54556
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 06ba3d6..bcd13dc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,6 +8,8 @@
"name": "kdot",
"version": "0.1.0",
"dependencies": {
+ "gray-matter": "^4.0.3",
+ "lucide-react": "^0.511.0",
"next": "15.3.2",
"react": "^19.0.0",
"react-dom": "^19.0.0"
@@ -3073,6 +3075,19 @@
"url": "https://opencollective.com/eslint"
}
},
+ "node_modules/esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "license": "BSD-2-Clause",
+ "bin": {
+ "esparse": "bin/esparse.js",
+ "esvalidate": "bin/esvalidate.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/esquery": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
@@ -3119,6 +3134,18 @@
"node": ">=0.10.0"
}
},
+ "node_modules/extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+ "license": "MIT",
+ "dependencies": {
+ "is-extendable": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -3441,6 +3468,43 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/gray-matter": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz",
+ "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==",
+ "license": "MIT",
+ "dependencies": {
+ "js-yaml": "^3.13.1",
+ "kind-of": "^6.0.2",
+ "section-matter": "^1.0.0",
+ "strip-bom-string": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6.0"
+ }
+ },
+ "node_modules/gray-matter/node_modules/argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "license": "MIT",
+ "dependencies": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "node_modules/gray-matter/node_modules/js-yaml": {
+ "version": "3.14.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+ "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
"node_modules/has-bigints": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz",
@@ -3739,6 +3803,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -4104,6 +4177,15 @@
"json-buffer": "3.0.1"
}
},
+ "node_modules/kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/language-subtag-registry": {
"version": "0.3.23",
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz",
@@ -4413,6 +4495,15 @@
"loose-envify": "cli.js"
}
},
+ "node_modules/lucide-react": {
+ "version": "0.511.0",
+ "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.511.0.tgz",
+ "integrity": "sha512-VK5a2ydJ7xm8GvBeKLS9mu1pVK6ucef9780JVUjw6bAjJL/QXnd4Y0p7SPeOUMC27YhzNCZvm5d/QX0Tp3rc0w==",
+ "license": "ISC",
+ "peerDependencies": {
+ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
"node_modules/magic-string": {
"version": "0.30.17",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
@@ -5200,6 +5291,19 @@
"integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==",
"license": "MIT"
},
+ "node_modules/section-matter": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
+ "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==",
+ "license": "MIT",
+ "dependencies": {
+ "extend-shallow": "^2.0.1",
+ "kind-of": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
@@ -5422,6 +5526,12 @@
"node": ">=0.10.0"
}
},
+ "node_modules/sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+ "license": "BSD-3-Clause"
+ },
"node_modules/stable-hash": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz",
@@ -5560,6 +5670,15 @@
"node": ">=4"
}
},
+ "node_modules/strip-bom-string": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz",
+ "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
diff --git a/package.json b/package.json
index ea9f114..1f7e760 100644
--- a/package.json
+++ b/package.json
@@ -9,19 +9,21 @@
"lint": "next lint"
},
"dependencies": {
+ "gray-matter": "^4.0.3",
+ "lucide-react": "^0.511.0",
+ "next": "15.3.2",
"react": "^19.0.0",
- "react-dom": "^19.0.0",
- "next": "15.3.2"
+ "react-dom": "^19.0.0"
},
"devDependencies": {
- "typescript": "^5",
+ "@eslint/eslintrc": "^3",
+ "@tailwindcss/postcss": "^4",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
- "@tailwindcss/postcss": "^4",
- "tailwindcss": "^4",
"eslint": "^9",
"eslint-config-next": "15.3.2",
- "@eslint/eslintrc": "^3"
+ "tailwindcss": "^4",
+ "typescript": "^5"
}
}
diff --git a/posts/dna.md b/posts/dna.md
new file mode 100644
index 0000000..a5b1a21
--- /dev/null
+++ b/posts/dna.md
@@ -0,0 +1,17 @@
+---
+title: "DNA"
+date: "2024-01-15"
+excerpt: "Analysis of Kendrick's exploration of identity and heritage"
+---
+
+# DNA - The Foundation of Identity
+
+"DNA" serves as a powerful opening statement about Kendrick Lamar's genetic and cultural inheritance. The track explores themes of identity, heritage, and the complex relationship between nature and nurture.
+
+## Key Themes
+
+- **Identity Formation**: How our DNA shapes who we are
+- **Cultural Heritage**: The weight of ancestral history
+- **Resilience**: Strength passed down through generations
+
+The aggressive production mirrors the intensity of Kendrick's delivery, creating a sonic representation of the fire that runs through his veins.
diff --git a/src/app/api/post/[slug].ts b/src/app/api/post/[slug].ts
new file mode 100644
index 0000000..eda7a59
--- /dev/null
+++ b/src/app/api/post/[slug].ts
@@ -0,0 +1,3 @@
+export async function GET(slug: string) {
+
+}
\ No newline at end of file
diff --git a/src/app/api/posts/route.ts b/src/app/api/posts/route.ts
new file mode 100644
index 0000000..93090cf
--- /dev/null
+++ b/src/app/api/posts/route.ts
@@ -0,0 +1,46 @@
+import { NextResponse } from "next/server"
+import fs from "fs"
+import path from "path"
+import matter from "gray-matter"
+
+export interface Post {
+ slug: string
+ title: string
+ date: string
+ excerpt?: string
+}
+
+export async function GET() {
+ try {
+ const postsDirectory = path.join(process.cwd(), "posts")
+ console.log(postsDirectory)
+
+ // Check if posts directory exists
+ if (!fs.existsSync(postsDirectory)) {
+ return NextResponse.json([])
+ }
+
+ const fileNames = fs.readdirSync(postsDirectory)
+ const posts = fileNames
+ .filter((name) => name.endsWith(".md") || name.endsWith(".mdx"))
+ .map((fileName) => {
+ const slug = fileName.replace(/\.(md|mdx)$/, "")
+ const fullPath = path.join(postsDirectory, fileName)
+ const fileContents = fs.readFileSync(fullPath, "utf8")
+ const { data } = matter(fileContents)
+
+ return {
+ slug,
+ title: data.title || slug,
+ date: data.date || "",
+ excerpt: data.excerpt || "",
+ }
+ })
+ .sort((a, b) => (a.date > b.date ? -1 : 1))
+
+ return NextResponse.json(posts)
+ } catch (error) {
+ console.error("Error reading posts:", error)
+ return NextResponse.json([])
+ }
+}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index f7fa87e..00f3737 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -1,22 +1,5 @@
-import type { Metadata } from "next";
-import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
-const geistSans = Geist({
- variable: "--font-geist-sans",
- subsets: ["latin"],
-});
-
-const geistMono = Geist_Mono({
- variable: "--font-geist-mono",
- subsets: ["latin"],
-});
-
-export const metadata: Metadata = {
- title: "Create Next App",
- description: "Generated by create next app",
-};
-
export default function RootLayout({
children,
}: Readonly<{
@@ -24,9 +7,7 @@ export default function RootLayout({
}>) {
return (
-
+
{children}
diff --git a/src/app/page.tsx b/src/app/page.tsx
index e68abe6..df6f5b3 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,103 +1,155 @@
-import Image from "next/image";
+"use client"
+
+import { useEffect, useState } from "react"
+import { ChevronDown } from "lucide-react"
+import Navbar from "@/components/navbar";
export default function Home() {
- return (
-
-
-
-
- -
- Get started by editing{" "}
-
- src/app/page.tsx
-
- .
-
- -
- Save and see your changes instantly.
-
-
+ const [scrollY, setScrollY] = useState(0)
+ const [titleOpacity, setTitleOpacity] = useState(0)
-
-
{
+ const handleScroll = () => {
+ const currentScrollY = window.scrollY
+ setScrollY(currentScrollY)
+
+ // Calculate title opacity based on scroll position
+ const opacity = Math.min(currentScrollY / 400, 1)
+ setTitleOpacity(opacity)
+ }
+
+ window.addEventListener("scroll", handleScroll, { passive: true })
+ return () => window.removeEventListener("scroll", handleScroll)
+ }, [])
+
+ const scrollToContent = () => {
+ window.scrollTo({
+ top: window.innerHeight,
+ behavior: "smooth",
+ })
+ }
+
+ return (
+
+
+
+ {/* Parallax Hero Section */}
+
+ {/* Parallax Background */}
+
+
+ {/* Dark Overlay */}
+
+
+ {/* Content Overlay */}
+
+
+
DAMN.
+
by Kendrick Lamar
+
+
+ {/* Scroll Indicator */}
+
-
-
+
+
+ {/* Title Reveal Section */}
+
+
+
+ {/* Main Title with Fade-in Effect */}
+
+
DAMN.
+
+
KENDRICK LAMAR
+
+ An exploration of duality, spirituality, and the human condition through one of hip-hop's most
+ critically acclaimed albums.
+
+
+
+
+ {/* Album Details */}
+
+
+
RELEASED
+
April 14, 2017
+
+
+
LABEL
+
Top Dawg Entertainment
+
+
+
GENRE
+
Hip Hop, Conscious Rap
+
+
+
+ {/* Quote Section */}
+
+
+ "Is it wickedness? Is it weakness? You decide. Are we gonna live or die?"
+
+
— Kendrick Lamar, FEAR.
+
+
+
+
+
+ {/* Additional Content Section */}
+
+
+
+
ABOUT THE ALBUM
+
+
+
+
+ DAMN. is the fourth studio album by American rapper Kendrick Lamar. The album explores themes of
+ loyalty, faith, and the duality of human nature through introspective lyrics and innovative
+ production.
+
+
+ Featuring collaborations with Rihanna, Zacari, and U2, the album received widespread critical acclaim
+ and won the Pulitzer Prize for Music, making Lamar the first non-classical or jazz artist to receive
+ the honor.
+
+
+
+
+
+
ACCOLADES
+
+ - • Pulitzer Prize for Music (2018)
+ - • Grammy Award for Best Rap Album
+ - • #1 on Billboard 200
+ - • Triple Platinum Certification
+
+
+
+
+
+
+
- );
-}
+ )
+}
\ No newline at end of file
diff --git a/src/app/posts/[slug]/page.tsx b/src/app/posts/[slug]/page.tsx
new file mode 100644
index 0000000..d36925a
--- /dev/null
+++ b/src/app/posts/[slug]/page.tsx
@@ -0,0 +1,49 @@
+import { getPost } from "@/lib/posts"
+import { notFound } from "next/navigation"
+import Link from "next/link"
+import { ArrowLeft } from "lucide-react"
+
+interface PostPageProps {
+ params: Promise<{ slug: string }>
+}
+
+export default async function PostPage({ params }: PostPageProps) {
+ const { slug } = await params
+ const post = await getPost(slug)
+
+ if (!post) {
+ notFound()
+ }
+
+ return (
+
+
+
+ {/* Back button */}
+
+
+
Back to Home
+
+
+ {/* Post header */}
+
+ {post.title}
+ {post.date && }
+ {post.excerpt && {post.excerpt}
}
+
+
+ {/* Post content */}
+
+ ") }}
+ />
+
+
+
+
+ )
+}
diff --git a/src/components/navbar.tsx b/src/components/navbar.tsx
new file mode 100644
index 0000000..16187c2
--- /dev/null
+++ b/src/components/navbar.tsx
@@ -0,0 +1,60 @@
+"use client"
+
+import Link from "next/link"
+import { useEffect, useState } from "react"
+
+interface Post {
+ slug: string
+ title: string
+ date: string
+ excerpt?: string
+}
+
+export default function Navbar() {
+ const [posts, setPosts] = useState([])
+
+ useEffect(() => {
+ fetch("/api/posts")
+ .then((res) => res.json())
+ .then((data) => setPosts(data))
+ .catch((err) => console.error("Error fetching posts:", err))
+ }, [])
+
+ console.log(posts)
+
+ return (
+
+ )
+}
\ No newline at end of file
diff --git a/src/lib/posts.ts b/src/lib/posts.ts
new file mode 100644
index 0000000..10cc913
--- /dev/null
+++ b/src/lib/posts.ts
@@ -0,0 +1,45 @@
+import fs from "fs"
+import path from "path"
+import matter from "gray-matter"
+
+export interface Post {
+ slug: string
+ title: string
+ date: string
+ excerpt?: string
+ content: string
+}
+
+const postsDirectory = path.join(process.cwd(), "posts")
+
+export async function getPost(slug: string): Promise {
+ try {
+ const fullPath = path.join(postsDirectory, `${slug}.md`)
+
+ // Try .md first, then .mdx
+ let fileContents: string
+ if (fs.existsSync(fullPath)) {
+ fileContents = fs.readFileSync(fullPath, "utf8")
+ } else {
+ const mdxPath = path.join(postsDirectory, `${slug}.mdx`)
+ if (fs.existsSync(mdxPath)) {
+ fileContents = fs.readFileSync(mdxPath, "utf8")
+ } else {
+ return null
+ }
+ }
+
+ const { data, content } = matter(fileContents)
+
+ return {
+ slug,
+ title: data.title || slug,
+ date: data.date || "",
+ excerpt: data.excerpt || "",
+ content,
+ }
+ } catch (error) {
+ console.error("Error reading post:", error)
+ return null
+ }
+}