Archived
switched to approuter
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
'use client';
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import PostCard from '@/components/PostCard';
|
||||
import SearchBar from '@/components/SearchBar';
|
||||
import { PostMetadata } from '@/types';
|
||||
|
||||
interface SearchClientProps {
|
||||
allPosts: PostMetadata[];
|
||||
}
|
||||
|
||||
export default function SearchClient({ allPosts }: SearchClientProps) {
|
||||
const searchParams = useSearchParams();
|
||||
const query = searchParams.get('q') || '';
|
||||
const [searchResults, setSearchResults] = useState<PostMetadata[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!query.trim()) {
|
||||
setSearchResults([]);
|
||||
return;
|
||||
}
|
||||
|
||||
const searchTerms = query.toLowerCase().trim().split(/\s+/);
|
||||
|
||||
const filteredPosts = allPosts.filter(post => {
|
||||
const titleMatch = searchTerms.some(term =>
|
||||
post.title.toLowerCase().includes(term)
|
||||
);
|
||||
|
||||
const excerptMatch = searchTerms.some(term =>
|
||||
post.excerpt.toLowerCase().includes(term)
|
||||
);
|
||||
|
||||
const tagMatch = post.tags.some(tag =>
|
||||
searchTerms.some(term => tag.toLowerCase().includes(term))
|
||||
);
|
||||
|
||||
return titleMatch || excerptMatch || tagMatch;
|
||||
});
|
||||
|
||||
setSearchResults(filteredPosts);
|
||||
}, [query, allPosts]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="mb-8">
|
||||
<SearchBar />
|
||||
</div>
|
||||
|
||||
{query.trim() ? (
|
||||
<>
|
||||
<p className="mb-8 text-primary-600">
|
||||
{searchResults.length} {searchResults.length === 1 ? 'result' : 'results'} for "{query}"
|
||||
</p>
|
||||
|
||||
{searchResults.length > 0 ? (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{searchResults.map(post => (
|
||||
<PostCard key={post.id} post={post} />
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="bg-white rounded-lg shadow-sm p-8 border border-primary-200 text-center">
|
||||
<p className="text-xl text-primary-600 mb-4">No results found for "{query}"</p>
|
||||
<p className="text-primary-500">Try using different keywords or browse all posts.</p>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<div className="bg-white rounded-lg shadow-sm p-8 border border-primary-200">
|
||||
<p className="text-xl text-primary-600 mb-4 text-center">Enter a search term to find posts</p>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import React from 'react';
|
||||
import { getSortedPostsData } from '@/lib/markdown';
|
||||
import { PostMetadata } from '@/types';
|
||||
import { generateMetadata as createMetadata } from '@/components/Metadata';
|
||||
import type { Metadata } from 'next';
|
||||
import SearchClient from './SearchClient';
|
||||
|
||||
export async function generateMetadata(): Promise<Metadata> {
|
||||
return createMetadata({
|
||||
title: 'Search Posts',
|
||||
description: 'Search through all posts on Confessions of Grace by title, content, or tags.',
|
||||
url: 'https://confessionsofgrace.com/search',
|
||||
type: 'website'
|
||||
});
|
||||
}
|
||||
|
||||
async function getAllPosts(): Promise<PostMetadata[]> {
|
||||
return getSortedPostsData();
|
||||
}
|
||||
|
||||
export default async function SearchPage() {
|
||||
const allPosts = await getAllPosts();
|
||||
|
||||
return (
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<h1 className="text-3xl md:text-4xl font-bold mb-6">Search Results</h1>
|
||||
<SearchClient allPosts={allPosts} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user