Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
{
"i18n-ally.localesPaths": ["src/locales"]
}
2 changes: 1 addition & 1 deletion README.md
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
![Logo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/th5xamgrr6se0x5ro4g6.png)
![Logo](./public/images/hammercode.png)

# Hammercode Web

Expand Down
1 change: 1 addition & 0 deletions next.config.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,6 +4,7 @@ const withNextIntl = createNextIntlPlugin("./src/lib/i18n.ts");

/** @type{import('next').NextConfig} */
const nextConfig ={
pageExtensions: ["js", "jsx", "mdx", "ts", "tsx"],
images:{
remotePatterns: [
{
Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -41,17 +41,22 @@
"motion": "^12.7.4",
"next": "15.3.2",
"next-intl": "^4.1.0",
"next-mdx-remote": "^5.0.0",
"next-themes": "^0.3.0",
"prettier-plugin-tailwindcss": "^0.6.11",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-hook-form": "^7.56.2",
"rehype-pretty-code": "^0.14.1",
"remark-gfm": "^4.0.1",
"shiki": "^3.7.0",
"tailwind-merge": "^3.3.0",
"tailwindcss-animate": "^1.0.7",
"zod": "^3.24.4"
},
"devDependencies":{
"@tailwindcss/postcss": "^4.1.4",
"@tailwindcss/typography": "^0.5.16",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.4.8",
"@testing-library/react": "^16.0.0",
Expand Down
Binary file addedpublic/assets/contents/welcome.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file addedpublic/assets/images/hammercode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file addedpublic/images/hammercode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
30 changes: 30 additions & 0 deletions src/app/[locale]/blogs/[slug]/page.tsx
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
import{getBlogBySlug } from "@/lib/mdx"
import BlogDetailPage from "@/features/blog/BlogDetailPage"

interface BlogPostPageProps{
params: Promise<{
slug: string;
}>
}

export async function generateMetadata({params }: BlogPostPageProps){
const{slug } = await params;
const post = await getBlogBySlug(slug);

if (!post){
return{
title: "Blog Post Not Found",
description: "The blog post you are looking for does not exist.",
};
}

return{
title: post.metadata.title,
description: post.metadata.description,
};
}

export default async function BlogPostPage({params }: BlogPostPageProps){
const{slug } = await params;
return <BlogDetailPage slug={slug} />
}
20 changes: 20 additions & 0 deletions src/app/[locale]/blogs/page.tsx
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
import{BlogPage } from "@/features/blog"

interface BlogsPageProps{
searchParams: Promise<{
category?: string;
}>
}

export function generateMetadata(){
return{
title: "Blogs",
description: "Read our latest blog posts and articles.",
};
}

export default async function BlogsPage({searchParams }: BlogsPageProps){
const{category } = await searchParams;

return <BlogPage category={category} />
}
1 change: 1 addition & 0 deletions src/app/[locale]/globals.css
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
@import "tailwindcss"
@plugin "@tailwindcss/typography"

@custom-variant dark (&:is(.dark *));

Expand Down
101 changes: 101 additions & 0 deletions src/app/api/posts/[slug]/route.ts
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
import{NextResponse } from "next/server"

// Mock data - same as in the main API route
const mockPosts = [
{
id: "1",
title: "Building Modern Web Apps with API",
description: "Learn how to build modern web applications using APIs and dynamic content.",
content: `
<h2>Introduction</h2>
<p>This post comes from a custom API endpoint. It demonstrates how you can combine static MDX content with dynamic API content.</p>

<h3>Key Benefits</h3>
<ul>
<li>Dynamic content management</li>
<li>Real-time updates</li>
<li>Flexible data sources</li>
<li>Content versioning</li>
</ul>

<h3>Implementation</h3>
<p>The API endpoint provides structured data that gets seamlessly integrated with your static MDX files.</p>

<blockquote>
<p>This approach gives you the flexibility to manage content through both static files and dynamic APIs.</p>
</blockquote>
`,
date: "2024-01-20T10:00:00Z",
publishedAt: "2024-01-20T10:00:00Z",
author:{
name: "API Author",
},
tags: ["api", "web development", "next.js"],
slug: "building-modern-web-apps-api",
},
{
id: "2",
title: "Content Management with APIs",
description: "Understanding how to manage content through API endpoints.",
content: `
<h2>API-First Content Strategy</h2>
<p>An API-first approach to content management provides several advantages:</p>

<h3>Advantages</h3>
<ol>
<li><strong>Scalability:</strong> Easy to scale content across multiple platforms</li>
<li><strong>Flexibility:</strong> Content can be updated without redeployment</li>
<li><strong>Integration:</strong> Easy integration with headless CMS systems</li>
</ol>

<h3>Use Cases</h3>
<p>Perfect for:</p>
<ul>
<li>News and blog platforms</li>
<li>E-commerce product catalogs</li>
<li>Documentation sites</li>
<li>Multi-language content</li>
</ul>

<p>This post demonstrates how API content can be seamlessly integrated with your static MDX content.</p>
`,
date: "2024-01-18T14:30:00Z",
publishedAt: "2024-01-18T14:30:00Z",
author:{
name: "Content Manager",
},
tags: ["cms", "api", "content management"],
slug: "content-management-apis",
},
];

export async function GET(request: Request,{params }:{params: Promise<{slug: string }>}){
try{
const{slug } = await params;
const post = mockPosts.find((p) => p.slug === slug);

if (!post){
return NextResponse.json(
{
success: false,
message: "Post not found",
},
{status: 404 }
);
}

return NextResponse.json({
post,
success: true,
});
} catch (error){
return NextResponse.json(
{
success: false,
message: "Failed to fetch post",
error,
},
{status: 500 }
);
}
}
137 changes: 137 additions & 0 deletions src/app/api/posts/route.ts
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
import{NextResponse } from "next/server"

// Mock data - replace with your actual data source
const mockPosts = [
{
id: "1",
title: "Building Modern Web Apps with API",
description: "Learn how to build modern web applications using APIs and dynamic content.",
content: `
<h2>Introduction</h2>
<p>This post comes from a custom API endpoint. It demonstrates how you can combine static MDX content with dynamic API content.</p>

<h3>Key Benefits</h3>
<ul>
<li>Dynamic content management</li>
<li>Real-time updates</li>
<li>Flexible data sources</li>
<li>Content versioning</li>
</ul>

<h3>Implementation</h3>
<p>The API endpoint provides structured data that gets seamlessly integrated with your static MDX files.</p>

<blockquote>
<p>This approach gives you the flexibility to manage content through both static files and dynamic APIs.</p>
</blockquote>
`,
date: "2024-01-20T10:00:00Z",
publishedAt: "2024-01-20T10:00:00Z",
author:{
name: "API Author",
},
tags: ["api", "web development", "next.js"],
slug: "building-modern-web-apps-api",
},
{
id: "2",
title: "Content Management with APIs",
description: "Understanding how to manage content through API endpoints.",
content: `
<h2>API-First Content Strategy</h2>
<p>An API-first approach to content management provides several advantages:</p>

<h3>Advantages</h3>
<ol>
<li><strong>Scalability:</strong> Easy to scale content across multiple platforms</li>
<li><strong>Flexibility:</strong> Content can be updated without redeployment</li>
<li><strong>Integration:</strong> Easy integration with headless CMS systems</li>
</ol>

<h3>Use Cases</h3>
<p>Perfect for:</p>
<ul>
<li>News and blog platforms</li>
<li>E-commerce product catalogs</li>
<li>Documentation sites</li>
<li>Multi-language content</li>
</ul>

<p>This post demonstrates how API content can be seamlessly integrated with your static MDX content.</p>
`,
date: "2024-01-18T14:30:00Z",
publishedAt: "2024-01-18T14:30:00Z",
author:{
name: "Content Manager",
},
tags: ["cms", "api", "content management"],
slug: "content-management-apis",
},
];

export async function GET(){
try{
return NextResponse.json({
posts: mockPosts,
success: true,
});
} catch (error){
return NextResponse.json(
{
posts: [],
success: false,
message: "Failed to fetch posts",
error,
},
{status: 500 }
);
}
}

export async function POST(request: Request){
try{
const body = await request.json();

if (!body.title || !body.content){
return NextResponse.json(
{
success: false,
message: "Title and content are required",
},
{status: 400 }
);
}

const newPost ={
id: Date.now().toString(),
title: body.title,
description: body.description || body.content.substring(0, 150) + "...",
content: body.content,
date: new Date().toISOString(),
publishedAt: new Date().toISOString(),
author:{
name: body.author || "Anonymous",
},
tags: body.tags || [],
slug: body.title
.toLowerCase()
.replace(/\s+/g, "-")
.replace(/[^a-z0-9-]/g, ""),
};

return NextResponse.json({
post: newPost,
success: true,
message: "Post created successfully",
});
} catch (error){
return NextResponse.json(
{
success: false,
message: "Failed to create post",
error,
},
{status: 500 }
);
}
}
4 changes: 4 additions & 0 deletions src/components/layout/Navbar/constant.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,6 +13,10 @@ export const LINKS = [
},
{
id: "4",
href: "/blogs",
},
{
id: "5",
href: "/support-us",
},
];
34 changes: 34 additions & 0 deletions src/content/welcome-to-hammercode.mdx
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
---
title: "Selamat Datang di Hammercode!"
description: "Perkenalan dan langkah awal bersama komunitas teknologi Hammercode"
date: "2025-12-12"
author: "Hammercode Team"
category: "announcement"
tags: ["hammercode", "komunitas", "teknologi", "perkenalan"]
images: "/assets/contents/welcome.png"
published: true
---

![Hammercode Banner](/assets/images/hammercode.png)

Halo dan selamat datang di blog pertama Hammercode!

Kami adalah komunitas teknologi berbasis di Palu, Indonesia, yang berfokus pada pembelajaran, kolaborasi, dan pengembangan proyek teknologi bersama. Blog ini akan menjadi pusat informasi, tutorial, pengumuman acara, dan dokumentasi perjalanan komunitas kita.

## Apa yang Akan Kamu Temukan di Sini?

Di blog ini, kamu akan menemukan:

- Tutorial dan tips seputar pengembangan perangkat lunak
- Insight dari proyek-proyek open source yang kami kembangkan
- Cerita dari anggota komunitas
- Dokumentasi event, workshop, dan meetup Hammercode

## Bergabung dengan Hammercode

Mau terlibat lebih jauh? Berikut langkah mudah untuk bergabung:

1. **Gabung Discord**: Tempat diskusi utama komunitas
2. **Ikuti Instagram & GitHub**: Untuk update event dan proyek
3. **Kontribusi Proyek**: Cek repositori dan mulai kontribusi
4. **Datang ke Meetup**: Kami rutin mengadakan pertemuan offline
Loading