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 ( -
-
- Next.js logo -
    -
  1. - Get started by editing{" "} - - src/app/page.tsx - - . -
  2. -
  3. - Save and see your changes instantly. -
  4. -
+ 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 */} +
- + + + {/* 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 + } +}