diff --git a/app/api/projects/search/route.ts b/app/api/projects/search/route.ts index f4fdc27..1689546 100644 --- a/app/api/projects/search/route.ts +++ b/app/api/projects/search/route.ts @@ -1,5 +1,5 @@ import { NextRequest, NextResponse } from 'next/server'; -import { prisma } from '@/lib/prisma'; +import { getProjects } from '@/lib/directus'; export async function GET(request: NextRequest) { try { @@ -7,56 +7,27 @@ export async function GET(request: NextRequest) { const slug = searchParams.get('slug'); const search = searchParams.get('search'); const category = searchParams.get('category'); + const locale = searchParams.get('locale') || 'en'; + // Use Directus instead of Prisma + const projects = await getProjects(locale, { + featured: undefined, + published: true, + category: category && category !== 'All' ? category : undefined, + search: search || undefined, + }); + + if (!projects) { + // Directus not available or no projects found + return NextResponse.json({ projects: [] }); + } + + // Filter by slug if provided (since Directus query doesn't support slug filter directly) if (slug) { - const project = await prisma.project.findFirst({ - where: { - published: true, - slug, - }, - orderBy: { createdAt: 'desc' }, - }); - + const project = projects.find(p => p.slug === slug); return NextResponse.json({ projects: project ? [project] : [] }); } - if (search) { - // General search - const projects = await prisma.project.findMany({ - where: { - published: true, - OR: [ - { title: { contains: search, mode: 'insensitive' } }, - { description: { contains: search, mode: 'insensitive' } }, - { tags: { hasSome: [search] } }, - { content: { contains: search, mode: 'insensitive' } } - ] - }, - orderBy: { createdAt: 'desc' } - }); - - return NextResponse.json({ projects }); - } - - if (category && category !== 'All') { - // Filter by category - const projects = await prisma.project.findMany({ - where: { - published: true, - category: category - }, - orderBy: { createdAt: 'desc' } - }); - - return NextResponse.json({ projects }); - } - - // Return all published projects if no specific search - const projects = await prisma.project.findMany({ - where: { published: true }, - orderBy: { createdAt: 'desc' } - }); - return NextResponse.json({ projects }); } catch (error) { console.error('Error searching projects:', error); diff --git a/scripts/add-example-projects.js b/scripts/add-example-projects.js new file mode 100644 index 0000000..ec51029 --- /dev/null +++ b/scripts/add-example-projects.js @@ -0,0 +1,178 @@ +#!/usr/bin/env node +/** + * Add Example Projects to Directus + * + * Creates 3 example projects in Directus CMS + * + * Usage: + * node scripts/add-example-projects.js + */ + +require('dotenv').config(); + +const DIRECTUS_URL = process.env.DIRECTUS_URL || 'https://cms.dk0.dev'; +const DIRECTUS_TOKEN = process.env.DIRECTUS_STATIC_TOKEN; + +if (!DIRECTUS_TOKEN) { + console.error('❌ Error: DIRECTUS_STATIC_TOKEN not found in .env'); + process.exit(1); +} + +async function directusRequest(endpoint, method = 'GET', body = null) { + const url = `${DIRECTUS_URL}/${endpoint}`; + const options = { + method, + headers: { + 'Authorization': `Bearer ${DIRECTUS_TOKEN}`, + 'Content-Type': 'application/json' + } + }; + + if (body) { + options.body = JSON.stringify(body); + } + + try { + const response = await fetch(url, options); + if (!response.ok) { + const text = await response.text(); + console.error(`HTTP ${response.status}: ${text}`); + return null; + } + return await response.json(); + } catch (error) { + console.error(`Error calling ${method} ${endpoint}:`, error.message); + return null; + } +} + +const exampleProjects = [ + { + slug: 'portfolio-website', + status: 'published', + featured: true, + category: 'Web Application', + difficulty: 'Advanced', + date: '2024', + github: 'https://github.com/denshooter/portfolio', + live: 'https://dk0.dev', + image_url: 'https://images.unsplash.com/photo-1460925895917-afdab827c52f?w=800', + tags: ['Next.js', 'React', 'TypeScript', 'Tailwind CSS'], + technologies: ['Next.js 14', 'TypeScript', 'Tailwind CSS', 'Directus', 'Docker'], + challenges: 'Building a performant, SEO-optimized portfolio with multilingual support', + lessons_learned: 'Learned about Next.js App Router, Server Components, and modern deployment strategies', + future_improvements: 'Add blog section, improve animations, add dark mode', + translations: [ + { + languages_code: 'en-US', + title: 'Portfolio Website', + description: 'A modern, performant portfolio website built with Next.js and Directus CMS', + content: '# Portfolio Website\n\nThis is my personal portfolio built with modern web technologies.\n\n## Features\n\n- 🚀 Fast and performant\n- 🌍 Multilingual (EN/DE)\n- 📱 Fully responsive\n- ♿ Accessible\n- 🎨 Beautiful design\n\n## Tech Stack\n\n- Next.js 14 with App Router\n- TypeScript\n- Tailwind CSS\n- Directus CMS\n- Docker deployment', + meta_description: 'Modern portfolio website showcasing my projects and skills', + keywords: 'portfolio, nextjs, react, typescript, web development' + }, + { + languages_code: 'de-DE', + title: 'Portfolio Website', + description: 'Eine moderne, performante Portfolio-Website mit Next.js und Directus CMS', + content: '# Portfolio Website\n\nDies ist mein persönliches Portfolio mit modernen Web-Technologien.\n\n## Features\n\n- 🚀 Schnell und performant\n- 🌍 Mehrsprachig (EN/DE)\n- 📱 Voll responsiv\n- ♿ Barrierefrei\n- 🎨 Schönes Design\n\n## Tech Stack\n\n- Next.js 14 mit App Router\n- TypeScript\n- Tailwind CSS\n- Directus CMS\n- Docker Deployment', + meta_description: 'Moderne Portfolio-Website mit meinen Projekten und Fähigkeiten', + keywords: 'portfolio, nextjs, react, typescript, webentwicklung' + } + ] + }, + { + slug: 'task-manager-app', + status: 'published', + featured: true, + category: 'Web Application', + difficulty: 'Intermediate', + date: '2023', + github: 'https://github.com/example/task-manager', + image_url: 'https://images.unsplash.com/photo-1484480974693-6ca0a78fb36b?w=800', + tags: ['React', 'Node.js', 'MongoDB', 'REST API'], + technologies: ['React', 'Node.js', 'Express', 'MongoDB', 'JWT'], + challenges: 'Implementing real-time updates and secure authentication', + lessons_learned: 'Learned about WebSockets, JWT authentication, and database optimization', + future_improvements: 'Add team collaboration features, mobile app, calendar integration', + translations: [ + { + languages_code: 'en-US', + title: 'Task Manager App', + description: 'A full-stack task management application with real-time updates', + content: '# Task Manager App\n\nA comprehensive task management solution for individuals and teams.\n\n## Features\n\n- ✅ Create and manage tasks\n- 🔔 Real-time notifications\n- 🔐 Secure authentication\n- 📊 Progress tracking\n- 🎨 Customizable categories\n\n## Implementation\n\nBuilt with React on the frontend and Node.js/Express on the backend. Uses MongoDB for data storage and JWT for authentication.', + meta_description: 'Full-stack task management application', + keywords: 'task manager, productivity, react, nodejs, mongodb' + }, + { + languages_code: 'de-DE', + title: 'Task Manager App', + description: 'Eine Full-Stack Aufgabenverwaltungs-App mit Echtzeit-Updates', + content: '# Task Manager App\n\nEine umfassende Aufgabenverwaltungslösung für Einzelpersonen und Teams.\n\n## Features\n\n- ✅ Aufgaben erstellen und verwalten\n- 🔔 Echtzeit-Benachrichtigungen\n- 🔐 Sichere Authentifizierung\n- 📊 Fortschrittsverfolgung\n- 🎨 Anpassbare Kategorien\n\n## Implementierung\n\nErstellt mit React im Frontend und Node.js/Express im Backend. Nutzt MongoDB für Datenspeicherung und JWT für Authentifizierung.', + meta_description: 'Full-Stack Aufgabenverwaltungs-Anwendung', + keywords: 'task manager, produktivität, react, nodejs, mongodb' + } + ] + }, + { + slug: 'weather-dashboard', + status: 'published', + featured: false, + category: 'Web Application', + difficulty: 'Beginner', + date: '2023', + live: 'https://weather-demo.example.com', + image_url: 'https://images.unsplash.com/photo-1504608524841-42fe6f032b4b?w=800', + tags: ['JavaScript', 'API', 'CSS', 'HTML'], + technologies: ['Vanilla JavaScript', 'OpenWeather API', 'CSS Grid', 'LocalStorage'], + challenges: 'Working with external APIs and handling async data', + lessons_learned: 'Learned about API integration, error handling, and responsive design', + future_improvements: 'Add weather forecasts, save favorite locations, add charts', + translations: [ + { + languages_code: 'en-US', + title: 'Weather Dashboard', + description: 'A simple weather dashboard showing current weather conditions', + content: '# Weather Dashboard\n\nA clean and simple weather dashboard for checking current conditions.\n\n## Features\n\n- 🌤️ Current weather data\n- 📍 Location search\n- 💾 Save favorite locations\n- 📱 Responsive design\n- 🎨 Clean UI\n\n## Technical Details\n\nBuilt with vanilla JavaScript and the OpenWeather API. Uses CSS Grid for layout and LocalStorage for saving user preferences.', + meta_description: 'Simple weather dashboard application', + keywords: 'weather, dashboard, javascript, api' + }, + { + languages_code: 'de-DE', + title: 'Wetter Dashboard', + description: 'Ein einfaches Wetter-Dashboard mit aktuellen Wetterbedingungen', + content: '# Wetter Dashboard\n\nEin übersichtliches Wetter-Dashboard zur Anzeige aktueller Bedingungen.\n\n## Features\n\n- 🌤️ Aktuelle Wetterdaten\n- 📍 Standortsuche\n- 💾 Favoriten speichern\n- 📱 Responsives Design\n- 🎨 Sauberes UI\n\n## Technische Details\n\nErstellt mit Vanilla JavaScript und der OpenWeather API. Nutzt CSS Grid für das Layout und LocalStorage zum Speichern von Benutzereinstellungen.', + meta_description: 'Einfache Wetter-Dashboard Anwendung', + keywords: 'wetter, dashboard, javascript, api' + } + ] + } +]; + +async function addProjects() { + console.log('\n📦 Adding Example Projects to Directus...\n'); + + for (const projectData of exampleProjects) { + console.log(`\n📁 Creating: ${projectData.translations[0].title}`); + + try { + const result = await directusRequest( + 'items/projects', + 'POST', + projectData + ); + + if (result) { + console.log(` ✅ Successfully created project: ${projectData.slug}`); + } else { + console.log(` ❌ Failed to create project: ${projectData.slug}`); + } + } catch (error) { + console.error(` ❌ Error creating project ${projectData.slug}:`, error.message); + } + } + + console.log('\n✅ Done!\n'); +} + +addProjects().catch(console.error);