diff --git a/app/blog/page.tsx b/app/blog/page.tsx index 32597eb..3c48bc3 100644 --- a/app/blog/page.tsx +++ b/app/blog/page.tsx @@ -2,14 +2,18 @@ import { BlogContent } from "@/components/blog-content"; import { getBlogPageData } from "@/data/blog"; type BlogPageProps = { - searchParams?: Promise<{ page?: string }>; + searchParams?: Promise<{ page?: string | string[]; category?: string | string[] }>; }; export default async function BlogPage({ searchParams }: BlogPageProps) { const resolved = searchParams ? await searchParams : undefined; - const page = Number(resolved?.page ?? "1"); + const pageParam = Array.isArray(resolved?.page) ? resolved?.page[0] : resolved?.page; + const categoryParam = Array.isArray(resolved?.category) + ? resolved?.category[0] + : resolved?.category; + const page = Number(pageParam ?? "1"); const currentPage = Number.isFinite(page) && page > 0 ? Math.floor(page) : 1; - const data = await getBlogPageData(currentPage, 12); + const data = await getBlogPageData(currentPage, 12, categoryParam); return ; } diff --git a/components/blog-content.tsx b/components/blog-content.tsx index 80a44fc..b2a5813 100644 --- a/components/blog-content.tsx +++ b/components/blog-content.tsx @@ -16,8 +16,30 @@ type BlogContentProps = { data: BlogPageData; }; -function pageHref(page: number) { - return page <= 1 ? "/blog" : `/blog?page=${page}`; +function pageHref(page: number, category: string) { + const params = new URLSearchParams(); + + if (page > 1) { + params.set("page", String(page)); + } + + if (category !== "All") { + params.set("category", category); + } + + const query = params.toString(); + return query ? `/blog?${query}` : "/blog"; +} + +function categoryHref(category: string) { + if (category === "All") { + return "/blog"; + } + + const params = new URLSearchParams(); + params.set("category", category); + + return `/blog?${params.toString()}`; } export function BlogContent({ data }: BlogContentProps) { @@ -45,14 +67,15 @@ export function BlogContent({ data }: BlogContentProps) { Kategoriler
- {data.categories.map((category, index) => ( - - {category} - + {data.categories.map((category) => ( + + + {category} + + ))}
@@ -114,7 +137,9 @@ export function BlogContent({ data }: BlogContentProps) { ) : ( - Henüz blog yazısı bulunmuyor. + {data.selectedCategory === "All" + ? "Henüz blog yazısı bulunmuyor." + : `"${data.selectedCategory}" kategorisinde henüz blog yazısı bulunmuyor.`} )} @@ -123,14 +148,17 @@ export function BlogContent({ data }: BlogContentProps) { {pageNumbers.map((page) => ( - + {page} @@ -138,7 +166,7 @@ export function BlogContent({ data }: BlogContentProps) { = data.totalPages} /> diff --git a/content/blog/conventional-commits-nedir.md b/content/blog/conventional-commits-nedir.md index ab46b50..f76a299 100644 --- a/content/blog/conventional-commits-nedir.md +++ b/content/blog/conventional-commits-nedir.md @@ -4,7 +4,7 @@ category: "Yazilim" date: "2026-02-01" readTime: "8 min read" author: "Poyraz Avsever" -excerpt: "Bu yazida temel kavramlari, pratik ornekleri ve uygulayabileceginiz ipuclarini sade bir dille bulabilirsiniz." +excerpt: "Yazılım geliştirme sürecinde yalnızca kod yazmıyoruz; aynı zamanda takım iletişimini ve proje geçmişini...." coverImage: "https://miro.medium.com/v2/resize:fit:1400/format:webp/1*WQOgajPE2m4aYuVC3SZoFQ.jpeg" --- diff --git a/content/blog/frontend-testing-jest-cypress.md b/content/blog/frontend-testing-jest-cypress.md index 0e83fd6..480e466 100644 --- a/content/blog/frontend-testing-jest-cypress.md +++ b/content/blog/frontend-testing-jest-cypress.md @@ -4,7 +4,7 @@ category: "Testing" date: "2026-02-22" readTime: "9 min read" author: "Poyraz Avsever" -excerpt: "Bu yazida temel kavramlari, pratik ornekleri ve uygulayabileceginiz ipuclarini sade bir dille bulabilirsiniz." +excerpt: "Frontend tarafında kaliteyi korumanın en sağlam yolu testtir. Bu yazıda, farklı amaçlara hizmet eden..." coverImage: "https://miro.medium.com/v2/resize:fit:1400/format:webp/0*uNpkjRqVlaB2WbDl.png" --- diff --git a/content/blog/jsxden-tsxe-gecis.md b/content/blog/jsxden-tsxe-gecis.md index a89af8b..f0c84ea 100644 --- a/content/blog/jsxden-tsxe-gecis.md +++ b/content/blog/jsxden-tsxe-gecis.md @@ -4,7 +4,7 @@ category: "TypeScript" date: "2026-02-18" readTime: "8 min read" author: "Poyraz Avsever" -excerpt: "Bu yazida temel kavramlari, pratik ornekleri ve uygulayabileceginiz ipuclarini sade bir dille bulabilirsiniz." +excerpt: "JavaScript'ten TypeScript'e geçiş, özellikle React projelerinde kod kalitesini gözle görülür şekilde artırıyor..." coverImage: "https://miro.medium.com/v2/resize:fit:1400/format:webp/0*yRK5eL_pqabAhrn7" --- diff --git a/content/blog/kullanici-arastirmasi-ve-persona.md b/content/blog/kullanici-arastirmasi-ve-persona.md index 5efada7..3fe990c 100644 --- a/content/blog/kullanici-arastirmasi-ve-persona.md +++ b/content/blog/kullanici-arastirmasi-ve-persona.md @@ -4,7 +4,7 @@ category: "UX" date: "2026-02-05" readTime: "6 min read" author: "Poyraz Avsever" -excerpt: "Bu yazida temel kavramlari, pratik ornekleri ve uygulayabileceginiz ipuclarini sade bir dille bulabilirsiniz." +excerpt: "Tasarım dünyasında, ürünlerimizin kullanıcılarımızın ihtiyaçlarını en iyi şekilde karşılamasını istemek..." coverImage: "https://miro.medium.com/v2/resize:fit:1400/format:webp/0*BEVhh2Et54wytkaA.jpg" --- diff --git a/content/blog/svelte-ilk-adimlar-react-vue-karsilastirma.md b/content/blog/svelte-ilk-adimlar-react-vue-karsilastirma.md index dd13949..3715674 100644 --- a/content/blog/svelte-ilk-adimlar-react-vue-karsilastirma.md +++ b/content/blog/svelte-ilk-adimlar-react-vue-karsilastirma.md @@ -4,7 +4,7 @@ category: "Frontend" date: "2026-02-14" readTime: "11 min read" author: "Poyraz Avsever" -excerpt: "Bu yazida temel kavramlari, pratik ornekleri ve uygulayabileceginiz ipuclarini sade bir dille bulabilirsiniz." +excerpt: "Frontend dünyasında React, Vue ve Angular gibi güçlü seçenekler var. Son yıllarda bu listeye güçlü bir alternatif..." coverImage: "https://miro.medium.com/v2/resize:fit:1400/format:webp/0*Dx04pr9plejiCcWI.png" --- diff --git a/content/blog/tailwind-css-ile-hizli-tasarim.md b/content/blog/tailwind-css-ile-hizli-tasarim.md index 53f89aa..f487b17 100644 --- a/content/blog/tailwind-css-ile-hizli-tasarim.md +++ b/content/blog/tailwind-css-ile-hizli-tasarim.md @@ -4,7 +4,7 @@ category: "Frontend" date: "2026-02-10" readTime: "10 min read" author: "Poyraz Avsever" -excerpt: "Bu yazida temel kavramlari, pratik ornekleri ve uygulayabileceginiz ipuclarini sade bir dille bulabilirsiniz." +excerpt: "Tailwind CSS, son dönemde front-end geliştiriciler arasında çok popüler hale geldi. Klasik CSS..." coverImage: "/news/performance.svg" --- diff --git a/content/blog/ux-tasarimi-ve-insan-psikolojisi.md b/content/blog/ux-tasarimi-ve-insan-psikolojisi.md index 31398cb..e761478 100644 --- a/content/blog/ux-tasarimi-ve-insan-psikolojisi.md +++ b/content/blog/ux-tasarimi-ve-insan-psikolojisi.md @@ -4,7 +4,7 @@ category: "UX" date: "2026-02-26" readTime: "12 min read" author: "Poyraz Avsever" -excerpt: "Bu yazida temel kavramlari, pratik ornekleri ve uygulayabileceginiz ipuclarini sade bir dille bulabilirsiniz." +excerpt: "UX (Kullanıcı Deneyimi) tasarımı, teknolojiyle etkileşime geçen herkesin deneyimini iyileştirmeye..." coverImage: "https://miro.medium.com/v2/resize:fit:1400/format:webp/0*5OUFz00g3w5ee2lV.jpg" --- diff --git a/data/blog.ts b/data/blog.ts index ba3d2bf..7561909 100644 --- a/data/blog.ts +++ b/data/blog.ts @@ -44,6 +44,7 @@ export type BlogPageData = { news: BlogNewsItem[]; articles: BlogArticleItem[]; categories: string[]; + selectedCategory: string; podcastGroups: BlogPodcastGroup[]; totalPages: number; currentPage: number; @@ -74,6 +75,10 @@ function sortByDateDesc(items: T[]) { }); } +function normalizeCategory(value: string) { + return value.trim().toLocaleLowerCase(); +} + function mapEpisodeToPodcastItem(episode: PodcastEpisode): BlogPodcastItem { return { id: `${episode.podcast}-${episode.slug}`, @@ -115,13 +120,12 @@ export async function getHomeBlogNews(limit = 3): Promise { })); } -export async function getBlogPageData(page = 1, pageSize = 12): Promise { +export async function getBlogPageData( + page = 1, + pageSize = 12, + selectedCategoryParam?: string, +): Promise { const articles = await getAllBlogArticles(); - const totalPages = Math.max(1, Math.ceil(Math.max(articles.length, 1) / pageSize)); - const currentPage = Math.min(Math.max(1, page), totalPages); - const start = (currentPage - 1) * pageSize; - const paginated = articles.slice(start, start + pageSize); - const categories = [ "All", ...new Set( @@ -130,11 +134,25 @@ export async function getBlogPageData(page = 1, pageSize = 12): Promise [normalizeCategory(category), category]), + ); + const requestedCategory = selectedCategoryParam?.trim(); + const selectedCategory = + (requestedCategory && categoryByNormalized.get(normalizeCategory(requestedCategory))) || "All"; + const filteredArticles = + selectedCategory === "All" + ? articles + : articles.filter((item) => normalizeCategory(item.category) === normalizeCategory(selectedCategory)); + const totalPages = Math.max(1, Math.ceil(Math.max(filteredArticles.length, 1) / pageSize)); + const currentPage = Math.min(Math.max(1, page), totalPages); + const start = (currentPage - 1) * pageSize; + const paginated = filteredArticles.slice(start, start + pageSize); const podcastCollections = await getPodcastCollections(); return { - news: articles.slice(0, 4).map((item) => ({ + news: filteredArticles.slice(0, 4).map((item) => ({ id: `blog-news-${item.slug}`, title: item.title, category: item.category, @@ -144,6 +162,7 @@ export async function getBlogPageData(page = 1, pageSize = 12): Promise