From af6d4c9f4dfa412a32b0eccbf8f89697f86d5b4c Mon Sep 17 00:00:00 2001 From: Poyraz Avsever Date: Fri, 10 Apr 2026 09:23:43 +0300 Subject: [PATCH] feat: implement data management panel and blog data utilities --- app/content/page.tsx | 9 +- apps/data-panel/main.cjs | 106 ------------ apps/data-panel/preload.cjs | 5 - apps/data-panel/renderer/app.js | 134 +--------------- apps/data-panel/renderer/configs.js | 5 - apps/data-panel/renderer/index.html | 73 --------- components/blog-content.tsx | 34 ---- components/content-content.tsx | 151 +----------------- .../2026-03-07-conversations-with-builders.md | 15 -- .../2026-02-23-stable-frontend-systems.md | 9 -- data/blog.ts | 42 ----- data/content-types.ts | 11 -- lib/command-palette-links.ts | 6 +- lib/content-page.ts | 65 +------- 14 files changed, 10 insertions(+), 655 deletions(-) delete mode 100644 content/podcasts/masa-basi/2026-03-07-conversations-with-builders.md delete mode 100644 content/podcasts/yazilim/2026-02-23-stable-frontend-systems.md delete mode 100644 data/content-types.ts diff --git a/app/content/page.tsx b/app/content/page.tsx index a986c02..2dde554 100644 --- a/app/content/page.tsx +++ b/app/content/page.tsx @@ -1,17 +1,12 @@ import { ContentContent } from "@/components/content-content"; import { YOUTUBE_VIDEO_LINKS } from "@/data/youtube-videos"; -import { getPdfNotes, getPodcastCollections } from "@/lib/content-page"; +import { getPdfNotes } from "@/lib/content-page"; export default async function ContentPage() { - const [{ yazilim, masaBasi }, pdfFiles] = await Promise.all([ - getPodcastCollections(), - getPdfNotes(), - ]); + const pdfFiles = await getPdfNotes(); return ( diff --git a/apps/data-panel/main.cjs b/apps/data-panel/main.cjs index 989c9cc..a2256fe 100644 --- a/apps/data-panel/main.cjs +++ b/apps/data-panel/main.cjs @@ -34,7 +34,6 @@ let WORKSPACE_ROOT = resolveWorkspaceRoot(); let DATA_DIR = path.join(WORKSPACE_ROOT, "data"); let PUBLIC_DIR = path.join(WORKSPACE_ROOT, "public"); let BLOG_CONTENT_DIR = path.join(WORKSPACE_ROOT, "content", "blog"); -let PODCAST_CONTENT_DIR = path.join(WORKSPACE_ROOT, "content", "podcasts"); let SNIPPETS_CONTENT_DIR = path.join(WORKSPACE_ROOT, "content", "snippets"); function setWorkspaceRoot(nextRoot) { @@ -42,7 +41,6 @@ function setWorkspaceRoot(nextRoot) { DATA_DIR = path.join(WORKSPACE_ROOT, "data"); PUBLIC_DIR = path.join(WORKSPACE_ROOT, "public"); BLOG_CONTENT_DIR = path.join(WORKSPACE_ROOT, "content", "blog"); - PODCAST_CONTENT_DIR = path.join(WORKSPACE_ROOT, "content", "podcasts"); SNIPPETS_CONTENT_DIR = path.join(WORKSPACE_ROOT, "content", "snippets"); } @@ -60,7 +58,6 @@ async function ensureWorkspaceStructure() { { label: "data", target: DATA_DIR }, { label: "public", target: PUBLIC_DIR }, { label: "content/blog", target: BLOG_CONTENT_DIR }, - { label: "content/podcasts", target: PODCAST_CONTENT_DIR }, { label: "content/snippets", target: SNIPPETS_CONTENT_DIR }, ]; @@ -131,18 +128,6 @@ function validateBlogSlug(slug) { return normalized; } -function validatePodcastKind(kind) { - const normalized = String(kind || "") - .trim() - .toLowerCase(); - - if (normalized !== "yazilim" && normalized !== "masa-basi") { - throw new Error("Podcast kind must be one of: yazilim, masa-basi"); - } - - return normalized; -} - function runGit(args) { return new Promise((resolve, reject) => { execFile("git", args, { cwd: WORKSPACE_ROOT }, (error, stdout, stderr) => { @@ -497,94 +482,6 @@ async function deleteBlogBySlug(slug) { return { ok: true }; } -function mapMarkdownToPodcast(kind, fileName, raw) { - const parsed = matter(raw); - const slug = fileName.replace(/\.md$/i, ""); - - return { - slug, - title: String(parsed.data.title || slug), - date: String(parsed.data.date || ""), - youtubeUrl: String(parsed.data.youtubeUrl || ""), - spotifyUrl: String(parsed.data.spotifyUrl || ""), - podcast: kind, - markdown: String(parsed.content || "").trim(), - }; -} - -async function listPodcastEpisodes(kind) { - const safeKind = validatePodcastKind(kind); - const podcastDir = assertSafePath(PODCAST_CONTENT_DIR, path.join(PODCAST_CONTENT_DIR, safeKind)); - - await fs.mkdir(podcastDir, { recursive: true }); - const files = await fs.readdir(podcastDir, { withFileTypes: true }); - const markdownFiles = files - .filter((item) => item.isFile() && item.name.endsWith(".md")) - .map((item) => item.name) - .sort((a, b) => b.localeCompare(a)); - - const episodes = await Promise.all( - markdownFiles.map(async (fileName) => { - const target = assertSafePath(podcastDir, path.join(podcastDir, fileName)); - const raw = await fs.readFile(target, "utf8"); - return mapMarkdownToPodcast(safeKind, fileName, raw); - }), - ); - - return episodes; -} - -async function upsertPodcastEpisode(kind, { originalSlug, episode }) { - const safeKind = validatePodcastKind(kind); - if (!episode || typeof episode !== "object") { - throw new Error("Episode payload is invalid."); - } - - const slug = validateBlogSlug(episode.slug); - const previousSlug = originalSlug ? validateBlogSlug(originalSlug) : null; - - const frontmatter = { - title: String(episode.title || slug), - date: String(episode.date || ""), - youtubeUrl: String(episode.youtubeUrl || ""), - spotifyUrl: String(episode.spotifyUrl || ""), - podcast: safeKind, - }; - - const markdownBody = String(episode.markdown || "").trim(); - const raw = matter.stringify(markdownBody ? `${markdownBody}\n` : "", frontmatter); - - const podcastDir = assertSafePath(PODCAST_CONTENT_DIR, path.join(PODCAST_CONTENT_DIR, safeKind)); - await fs.mkdir(podcastDir, { recursive: true }); - - const nextPath = assertSafePath(podcastDir, path.join(podcastDir, `${slug}.md`)); - const previousPath = - previousSlug && previousSlug !== slug - ? assertSafePath(podcastDir, path.join(podcastDir, `${previousSlug}.md`)) - : null; - - await fs.writeFile(nextPath, raw, "utf8"); - - if (previousPath) { - try { - await fs.unlink(previousPath); - } catch { - // ignore missing previous file - } - } - - return { ok: true, slug }; -} - -async function deletePodcastEpisode(kind, slug) { - const safeKind = validatePodcastKind(kind); - const normalized = validateBlogSlug(slug); - const podcastDir = assertSafePath(PODCAST_CONTENT_DIR, path.join(PODCAST_CONTENT_DIR, safeKind)); - const target = assertSafePath(podcastDir, path.join(podcastDir, `${normalized}.md`)); - await fs.unlink(target); - return { ok: true }; -} - function mapMarkdownToSnippet(fileName, raw) { const parsed = matter(raw); const slug = fileName.replace(/\.md$/i, ""); @@ -824,9 +721,6 @@ ipcMain.handle("data:delete", async (_, fileName) => deleteDataFile(fileName)); ipcMain.handle("blog:list", async () => listBlogs()); ipcMain.handle("blog:upsert", async (_, payload) => upsertBlog(payload)); ipcMain.handle("blog:delete", async (_, slug) => deleteBlogBySlug(slug)); -ipcMain.handle("podcast:list", async (_, kind) => listPodcastEpisodes(kind)); -ipcMain.handle("podcast:upsert", async (_, payload) => upsertPodcastEpisode(payload.kind, payload)); -ipcMain.handle("podcast:delete", async (_, payload) => deletePodcastEpisode(payload.kind, payload.slug)); ipcMain.handle("snippet:list", async () => listSnippets()); ipcMain.handle("snippet:upsert", async (_, payload) => upsertSnippet(payload)); diff --git a/apps/data-panel/preload.cjs b/apps/data-panel/preload.cjs index 3827c5a..0809679 100644 --- a/apps/data-panel/preload.cjs +++ b/apps/data-panel/preload.cjs @@ -15,11 +15,6 @@ contextBridge.exposeInMainWorld("panelAPI", { upsert: (payload) => ipcRenderer.invoke("blog:upsert", payload), delete: (slug) => ipcRenderer.invoke("blog:delete", slug), }, - podcast: { - list: (kind) => ipcRenderer.invoke("podcast:list", kind), - upsert: (payload) => ipcRenderer.invoke("podcast:upsert", payload), - delete: (payload) => ipcRenderer.invoke("podcast:delete", payload), - }, snippet: { list: () => ipcRenderer.invoke("snippet:list"), upsert: (payload) => ipcRenderer.invoke("snippet:upsert", payload), diff --git a/apps/data-panel/renderer/app.js b/apps/data-panel/renderer/app.js index b1a9ab0..c4f9a2e 100644 --- a/apps/data-panel/renderer/app.js +++ b/apps/data-panel/renderer/app.js @@ -1,5 +1,5 @@ -import { BLOG_CATEGORIES, COLLECTION_CONFIGS, PODCAST_LABELS } from "./configs.js"; +import { BLOG_CATEGORIES, COLLECTION_CONFIGS } from "./configs.js"; const state = { activeTab: "blog", @@ -15,12 +15,6 @@ const state = { editingIndex: null, formInputs: {}, }, - podcast: { - kind: "yazilim", - episodes: [], - selectedSlug: "", - originalSlug: "", - }, }; const el = { @@ -28,7 +22,6 @@ const el = { panels: { blog: document.getElementById("tab-blog"), collection: document.getElementById("tab-collection"), - podcast: document.getElementById("tab-podcast"), media: document.getElementById("tab-media"), publish: document.getElementById("tab-publish"), }, @@ -56,19 +49,6 @@ const el = { collectionEditorTitle: document.getElementById("collection-editor-title"), collectionHelper: document.getElementById("collection-helper"), collectionFormGrid: document.getElementById("collection-form-grid"), - podcastSidebarTitle: document.getElementById("podcast-sidebar-title"), - podcastCardList: document.getElementById("podcast-card-list"), - refreshPodcastFiles: document.getElementById("refresh-podcast-files"), - newPodcastFile: document.getElementById("new-podcast-file"), - deletePodcastFile: document.getElementById("delete-podcast-file"), - podcastEditorTitle: document.getElementById("podcast-editor-title"), - podcastSlug: document.getElementById("podcast-slug"), - podcastTitle: document.getElementById("podcast-title"), - podcastDate: document.getElementById("podcast-date"), - podcastYoutubeUrl: document.getElementById("podcast-youtube-url"), - podcastSpotifyUrl: document.getElementById("podcast-spotify-url"), - podcastEditor: document.getElementById("podcast-editor"), - savePodcastFile: document.getElementById("save-podcast-file"), folderSelect: document.getElementById("folder-select"), newFolder: document.getElementById("new-folder"), createFolder: document.getElementById("create-folder"), @@ -95,17 +75,13 @@ function getCollectionConfig(key = state.collection.key) { function setActiveTab(tab, options = {}) { state.activeTab = tab; if (tab === "collection" && options.collectionKey) state.collection.key = options.collectionKey; - if (tab === "podcast" && options.podcastKind) state.podcast.kind = options.podcastKind; for (const button of el.tabs) { const buttonTab = button.dataset.tab; const isCollection = buttonTab === "collection"; - const isPodcast = buttonTab === "podcast"; const isActive = isCollection ? tab === "collection" && button.dataset.collectionKey === state.collection.key - : isPodcast - ? tab === "podcast" && button.dataset.podcastKind === state.podcast.kind - : buttonTab === tab; + : buttonTab === tab; button.classList.toggle("active", isActive); } @@ -116,10 +92,6 @@ function setActiveTab(tab, options = {}) { if (tab === "collection") { void loadCollection(state.collection.key).catch((error) => notify(String(error.message || error))); } - - if (tab === "podcast") { - void loadPodcastFiles(state.podcast.kind).catch((error) => notify(String(error.message || error))); - } } function emptyBlogDraft() { @@ -273,98 +245,6 @@ async function removeBlogFile(slugArg) { notify("Blog post deleted."); } -function emptyPodcastDraft(kind = state.podcast.kind) { - return { slug: "", title: "", date: "", youtubeUrl: "", spotifyUrl: "", podcast: kind, markdown: "" }; -} - -function fillPodcastForm(episode) { - const draft = episode || emptyPodcastDraft(); - el.podcastSlug.value = draft.slug || ""; - el.podcastTitle.value = draft.title || ""; - el.podcastDate.value = draft.date || ""; - el.podcastYoutubeUrl.value = draft.youtubeUrl || ""; - el.podcastSpotifyUrl.value = draft.spotifyUrl || ""; - el.podcastEditor.value = draft.markdown || ""; -} - -function selectPodcast(slug) { - const episode = state.podcast.episodes.find((item) => item.slug === slug); - if (!episode) return; - state.podcast.selectedSlug = slug; - state.podcast.originalSlug = slug; - el.podcastEditorTitle.textContent = `Edit Episode: ${slug}`; - fillPodcastForm(episode); - renderPostCards(el.podcastCardList, state.podcast.episodes, state.podcast.selectedSlug, selectPodcast, (value) => void removePodcastFile(value)); -} -function createPodcastFile() { - state.podcast.selectedSlug = ""; - state.podcast.originalSlug = ""; - el.podcastEditorTitle.textContent = `Create Episode (${PODCAST_LABELS[state.podcast.kind] || state.podcast.kind})`; - fillPodcastForm(emptyPodcastDraft(state.podcast.kind)); - renderPostCards(el.podcastCardList, state.podcast.episodes, state.podcast.selectedSlug, selectPodcast, (slug) => void removePodcastFile(slug)); -} - -async function loadPodcastFiles(kind = state.podcast.kind) { - state.podcast.kind = kind; - state.podcast.episodes = await window.panelAPI.podcast.list(kind); - el.podcastSidebarTitle.textContent = PODCAST_LABELS[kind] || "Podcast"; - renderPostCards(el.podcastCardList, state.podcast.episodes, state.podcast.selectedSlug, selectPodcast, (value) => void removePodcastFile(value)); - - const selected = state.podcast.episodes.find((item) => item.slug === state.podcast.selectedSlug); - if (selected) { - selectPodcast(selected.slug); - } else if (state.podcast.episodes.length > 0) { - selectPodcast(state.podcast.episodes[0].slug); - } else { - createPodcastFile(); - } -} - -function currentPodcastDraft() { - return { - slug: el.podcastSlug.value.trim(), - title: el.podcastTitle.value.trim(), - date: el.podcastDate.value.trim(), - youtubeUrl: el.podcastYoutubeUrl.value.trim(), - spotifyUrl: el.podcastSpotifyUrl.value.trim(), - podcast: state.podcast.kind, - markdown: el.podcastEditor.value, - }; -} - -async function savePodcastFile() { - const episode = currentPodcastDraft(); - if (!episode.slug || !episode.title) { - notify("Slug and title are required."); - return; - } - - const result = await window.panelAPI.podcast.upsert({ - kind: state.podcast.kind, - originalSlug: state.podcast.originalSlug || undefined, - episode, - }); - - await loadPodcastFiles(state.podcast.kind); - state.podcast.selectedSlug = result.slug; - state.podcast.originalSlug = result.slug; - selectPodcast(result.slug); - notify(`Saved podcast episode: ${result.slug}`); -} - -async function removePodcastFile(slugArg) { - const targetSlug = slugArg || state.podcast.selectedSlug; - if (!targetSlug) return; - if (!window.confirm(`Delete podcast episode ${targetSlug}?`)) return; - - await window.panelAPI.podcast.delete({ kind: state.podcast.kind, slug: targetSlug }); - state.podcast.selectedSlug = ""; - state.podcast.originalSlug = ""; - createPodcastFile(); - await loadPodcastFiles(state.podcast.kind); - notify("Podcast episode deleted."); -} - function deserializeCollectionItem(config, rawItem) { if (typeof config.deserializeItem === "function") return config.deserializeItem(rawItem); if (rawItem && typeof rawItem === "object" && !Array.isArray(rawItem)) return { ...rawItem }; @@ -706,10 +586,6 @@ function bindEvents() { setActiveTab("collection", { collectionKey: button.dataset.collectionKey }); return; } - if (tab === "podcast") { - setActiveTab("podcast", { podcastKind: button.dataset.podcastKind }); - return; - } setActiveTab(tab); }); } @@ -726,11 +602,6 @@ function bindEvents() { el.deleteCollectionItem.addEventListener("click", () => void removeCollectionItem().catch((error) => notify(String(error.message || error)))); el.saveCollectionItem.addEventListener("click", () => void saveCollectionItem().catch((error) => notify(String(error.message || error)))); - el.refreshPodcastFiles.addEventListener("click", () => void loadPodcastFiles(state.podcast.kind).catch((error) => notify(String(error.message || error)))); - el.newPodcastFile.addEventListener("click", () => createPodcastFile()); - el.deletePodcastFile.addEventListener("click", () => void removePodcastFile().catch((error) => notify(String(error.message || error)))); - el.savePodcastFile.addEventListener("click", () => void savePodcastFile().catch((error) => notify(String(error.message || error)))); - el.folderSelect.addEventListener("change", () => { state.selectedFolder = el.folderSelect.value; void loadMediaFiles(); @@ -748,7 +619,6 @@ async function init() { await loadBlogFiles(); if (!state.selectedBlogSlug) createBlogFile(); await loadCollection(state.collection.key); - await loadPodcastFiles(state.podcast.kind); await loadMediaFolders(); await refreshPublishStatus(); setActiveTab("blog"); diff --git a/apps/data-panel/renderer/configs.js b/apps/data-panel/renderer/configs.js index a08d4ba..1fc465a 100644 --- a/apps/data-panel/renderer/configs.js +++ b/apps/data-panel/renderer/configs.js @@ -482,8 +482,3 @@ export const COLLECTION_CONFIGS = { }), }, }; - -export const PODCAST_LABELS = { - yazilim: "Podcast Yazilim", - "masa-basi": "Podcast Masa Basi", -}; diff --git a/apps/data-panel/renderer/index.html b/apps/data-panel/renderer/index.html index ca7480c..c042022 100644 --- a/apps/data-panel/renderer/index.html +++ b/apps/data-panel/renderer/index.html @@ -26,13 +26,6 @@ data-collection-key="announcement" > Announcement - - - - -
- - - -
-
-

Create Episode

-
- - -
-
- -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
-
- - -
diff --git a/components/blog-content.tsx b/components/blog-content.tsx index 09dd4b6..942f2a7 100644 --- a/components/blog-content.tsx +++ b/components/blog-content.tsx @@ -82,40 +82,6 @@ export function BlogContent({ data }: BlogContentProps) { ))}
- - - Podcast İçerikleri -
- {data.podcastGroups.map((group) => ( - -
- - {group.title} - - - Tümünü Gör - -
- -
- {group.items.map((episode) => ( -
- - {episode.title} - - - {episode.date} - -
- ))} -
-
- ))} -
-
diff --git a/components/content-content.tsx b/components/content-content.tsx index 943a1be..2dbfa38 100644 --- a/components/content-content.tsx +++ b/components/content-content.tsx @@ -1,28 +1,15 @@ "use client"; import { useEffect, useMemo, useRef, useState } from "react"; -import Link from "next/link"; -import ReactMarkdown from "react-markdown"; -import remarkGfm from "remark-gfm"; -import { Icon } from "@iconify/react"; -import { Badge, Button, Card, Typography } from "poyraz-ui/atoms"; -import { Modal, ModalContent, ModalTitle, Sheet, SheetContent, SheetTitle } from "poyraz-ui/molecules"; -import type { PodcastEpisode } from "@/data/content-types"; +import { Button, Card, Typography } from "poyraz-ui/atoms"; +import { Modal, ModalContent, ModalTitle } from "poyraz-ui/molecules"; import { getYoutubeEmbedUrl } from "@/lib/youtube"; type ContentContentProps = { - yazilimEpisodes: PodcastEpisode[]; - masaBasiEpisodes: PodcastEpisode[]; youtubeLinks: readonly string[]; pdfFiles: string[]; }; -function getPodcastLabel(podcast: PodcastEpisode["podcast"]) { - if (podcast === "yazilim") return "Yazılım"; - if (podcast === "masa-basi") return "Masa Başı"; - return podcast; -} - function PdfFirstPagePreview({ src, title }: { src: string; title: string }) { const canvasRef = useRef(null); const [failed, setFailed] = useState(false); @@ -103,57 +90,10 @@ function PdfFirstPagePreview({ src, title }: { src: string; title: string }) { ); } -function PodcastColumn({ - title, - subtitle, - episodes, - onOpenEpisode, -}: { - title: string; - subtitle: string; - episodes: PodcastEpisode[]; - onOpenEpisode: (episode: PodcastEpisode) => void; -}) { - return ( - - - {title} - - - {subtitle} - - -
- {episodes.slice(0, 3).map((episode) => ( - - ))} -
-
- ); -} - export function ContentContent({ - yazilimEpisodes, - masaBasiEpisodes, youtubeLinks, pdfFiles, }: ContentContentProps) { - const [selectedEpisode, setSelectedEpisode] = useState(null); - const [sheetOpen, setSheetOpen] = useState(false); const [pdfModalOpen, setPdfModalOpen] = useState(false); const [activePdfIndex, setActivePdfIndex] = useState(0); @@ -169,11 +109,6 @@ export function ContentContent({ [youtubeLinks], ); - const openEpisode = (episode: PodcastEpisode) => { - setSelectedEpisode(episode); - setSheetOpen(true); - }; - const openPdfModal = (index: number) => { setActivePdfIndex(index); setPdfModalOpen(true); @@ -181,21 +116,6 @@ export function ContentContent({ return (
-
- - -
-
Son YouTube Videoları @@ -247,73 +167,6 @@ export function ContentContent({
- - -
- {selectedEpisode?.title ?? "Bölüm"} - {selectedEpisode ? ( - - {selectedEpisode.date} - - ) : null} -
- -
- {selectedEpisode ? ( - <> -
- {getPodcastLabel(selectedEpisode.podcast)} -
- -
- - - YouTube - - - - Spotify - -
- - - ( - - {children} - - ), - p: ({ children }) => ( - - {children} - - ), - li: ({ children }) => ( -
  • {children}
  • - ), - }} - > - {selectedEpisode.markdown} -
    -
    - - ) : null} -
    -
    -
    - {activePdf ? activePdf.replace(/\.pdf$/i, "") : "PDF Notu"} diff --git a/content/podcasts/masa-basi/2026-03-07-conversations-with-builders.md b/content/podcasts/masa-basi/2026-03-07-conversations-with-builders.md deleted file mode 100644 index 36ad400..0000000 --- a/content/podcasts/masa-basi/2026-03-07-conversations-with-builders.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: "Poyraz ile Masa Başı Yakında Başlıyor" -date: "2026-03-07" -youtubeUrl: "https://youtube.com/@poyrazavsever" -spotifyUrl: "https://open.spotify.com/show/placeholder-masabasi" -podcast: "masa-basi" ---- - -## Durum - -Poyraz ile Masa Başı serisi henüz başlamadı. - -## Not - -İlk bölüm yayınlandığında bu alandaki içerik güncellenecek. diff --git a/content/podcasts/yazilim/2026-02-23-stable-frontend-systems.md b/content/podcasts/yazilim/2026-02-23-stable-frontend-systems.md deleted file mode 100644 index f950e3c..0000000 --- a/content/podcasts/yazilim/2026-02-23-stable-frontend-systems.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: "Poyraz ile yazılım'a dair yakında başlıyor." -date: "2026-02-23" -youtubeUrl: "https://www.youtube.com/watch?v=XWUeVzf0t6Y&t=2s" -spotifyUrl: "https://open.spotify.com/show/placeholder-yazilim" -podcast: "yazilim" ---- - -## Poyraz ile yazılım'a dair yakında başlıyor. diff --git a/data/blog.ts b/data/blog.ts index cb5f537..a387b00 100644 --- a/data/blog.ts +++ b/data/blog.ts @@ -1,8 +1,6 @@ import "server-only"; import { listBlogDetails } from "@/data/blog-detail"; -import type { PodcastEpisode } from "@/data/content-types"; -import { getPodcastCollections } from "@/lib/content-page"; export type BlogNewsItem = { id: string; @@ -26,26 +24,11 @@ export type BlogArticleItem = { author: string; }; -export type BlogPodcastItem = { - id: string; - title: string; - date: string; - href: string; -}; - -export type BlogPodcastGroup = { - id: "yazilim" | "masa-basi"; - title: string; - href: string; - items: BlogPodcastItem[]; -}; - export type BlogPageData = { news: BlogNewsItem[]; articles: BlogArticleItem[]; categories: string[]; selectedCategory: string; - podcastGroups: BlogPodcastGroup[]; totalPages: number; currentPage: number; }; @@ -80,15 +63,6 @@ function normalizeCategory(value: string) { return value.trim().toLocaleLowerCase(); } -function mapEpisodeToPodcastItem(episode: PodcastEpisode): BlogPodcastItem { - return { - id: `${episode.podcast}-${episode.slug}`, - title: episode.title, - date: episode.date, - href: "/content", - }; -} - export async function getAllBlogArticles(): Promise { const posts = await listBlogDetails(); @@ -143,8 +117,6 @@ export async function getBlogPageData( const start = (currentPage - 1) * pageSize; const paginated = filteredArticles.slice(start, start + pageSize); - const podcastCollections = await getPodcastCollections(); - return { news: articles.slice(0, 4).map((item) => ({ id: `blog-news-${item.slug}`, @@ -159,19 +131,5 @@ export async function getBlogPageData( selectedCategory, totalPages, currentPage, - podcastGroups: [ - { - id: "yazilim", - title: "Poyraz ile Yazılım", - href: "/content", - items: podcastCollections.yazilim.slice(0, 4).map(mapEpisodeToPodcastItem), - }, - { - id: "masa-basi", - title: "Poyraz ile Masa Başı", - href: "/content", - items: podcastCollections.masaBasi.slice(0, 4).map(mapEpisodeToPodcastItem), - }, - ], }; } diff --git a/data/content-types.ts b/data/content-types.ts deleted file mode 100644 index ca1f1b6..0000000 --- a/data/content-types.ts +++ /dev/null @@ -1,11 +0,0 @@ -export type PodcastKind = "yazilim" | "masa-basi"; - -export type PodcastEpisode = { - slug: string; - title: string; - date: string; - youtubeUrl: string; - spotifyUrl: string; - podcast: PodcastKind; - markdown: string; -}; diff --git a/lib/command-palette-links.ts b/lib/command-palette-links.ts index a4f530e..2c73c67 100644 --- a/lib/command-palette-links.ts +++ b/lib/command-palette-links.ts @@ -61,10 +61,10 @@ const blogItems: CommandPaletteItem[] = [ }, { id: "blog-content-page", - label: "Podcast ve İçerikler", + label: "Video ve Notlar", href: "/content", - icon: "mdi:microphone-outline", - keywords: ["podcast", "yazılım", "masa başı", "içerik", "content"], + icon: "mdi:video-outline", + keywords: ["video", "youtube", "not", "pdf", "içerik", "content"], }, ]; diff --git a/lib/content-page.ts b/lib/content-page.ts index b196651..8654417 100644 --- a/lib/content-page.ts +++ b/lib/content-page.ts @@ -1,71 +1,8 @@ -import { readdir, readFile } from "node:fs/promises"; +import { readdir } from "node:fs/promises"; import path from "node:path"; -import matter from "gray-matter"; -import type { PodcastEpisode, PodcastKind } from "@/data/content-types"; -type EpisodeFrontmatter = { - title: string; - date: string; - youtubeUrl: string; - spotifyUrl: string; - podcast: PodcastKind; -}; - -const PODCAST_DIR = path.join(process.cwd(), "content", "podcasts"); const PDF_DIR = path.join(process.cwd(), "public", "pdf"); -function sortEpisodesByDateDesc(episodes: PodcastEpisode[]) { - return [...episodes].sort((a, b) => { - const aTime = Number(new Date(a.date)); - const bTime = Number(new Date(b.date)); - - if (!Number.isNaN(aTime) && !Number.isNaN(bTime)) { - return bTime - aTime; - } - - return a.title.localeCompare(b.title); - }); -} - -async function readPodcastEpisodes(kind: PodcastKind): Promise { - const folder = path.join(PODCAST_DIR, kind); - const files = await readdir(folder); - const mdFiles = files.filter((file) => file.endsWith(".md")); - - const episodes = await Promise.all( - mdFiles.map(async (file) => { - const fullPath = path.join(folder, file); - const raw = await readFile(fullPath, "utf8"); - const parsed = matter(raw); - const data = parsed.data as Partial; - - return { - slug: file.replace(/\.md$/, ""), - title: data.title ?? "Başlıksız Bölüm", - date: data.date ?? "1970-01-01", - youtubeUrl: data.youtubeUrl ?? "", - spotifyUrl: data.spotifyUrl ?? "", - podcast: data.podcast ?? kind, - markdown: parsed.content.trim(), - } satisfies PodcastEpisode; - }), - ); - - return sortEpisodesByDateDesc(episodes); -} - -export async function getPodcastCollections() { - const [yazilim, masaBasi] = await Promise.all([ - readPodcastEpisodes("yazilim"), - readPodcastEpisodes("masa-basi"), - ]); - - return { - yazilim, - masaBasi, - }; -} - export async function getPdfNotes() { const files = await readdir(PDF_DIR); const pdfFiles = files.filter((file) => file.toLowerCase().endsWith(".pdf"));