UNPKG

@asgerami/zemenay-blog

Version:

Plug-and-play blog system for Next.js - Get a fully functional blog running in minutes with zero configuration

104 lines (103 loc) 7.16 kB
"use strict"; "use client"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.BlogList = BlogList; const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = __importDefault(require("react")); const SearchBar_1 = require("./SearchBar"); const CategoryTag_1 = require("./CategoryTag"); const FilterControls_1 = require("./FilterControls"); const LoadingStates_1 = require("./LoadingStates"); const categories_1 = require("../lib/categories"); function BlogList({ className = "", limit, onPostClick, showSearch = true, searchPlaceholder = "Search posts...", }) { const [allPosts, setAllPosts] = react_1.default.useState([]); const [filteredPosts, setFilteredPosts] = react_1.default.useState([]); const [categories, setCategories] = react_1.default.useState([]); const [tags, setTags] = react_1.default.useState([]); const [loading, setLoading] = react_1.default.useState(true); const [error, setError] = react_1.default.useState(null); const [searchQuery, setSearchQuery] = react_1.default.useState(""); const [selectedCategory, setSelectedCategory] = react_1.default.useState(""); const [selectedTags, setSelectedTags] = react_1.default.useState([]); // Fetch all posts with categories and tags react_1.default.useEffect(() => { async function fetchData() { try { // Fetch posts with categories and tags const posts = await (0, categories_1.fetchPostsWithCategoriesAndTags)(); setAllPosts(posts); setFilteredPosts(posts); // Fetch all categories and tags for filtering const [categoriesData, tagsData] = await Promise.all([ (0, categories_1.fetchCategories)(), (0, categories_1.fetchTags)(), ]); setCategories(categoriesData); setTags(tagsData); } catch (err) { setError(err instanceof Error ? err.message : "Failed to fetch posts"); } finally { setLoading(false); } } fetchData(); }, []); // Filter posts when search query, category, or tags change react_1.default.useEffect(() => { let filtered = [...allPosts]; // Apply search filter if (searchQuery.trim()) { const query = searchQuery.toLowerCase(); filtered = filtered.filter((post) => post.title.toLowerCase().includes(query) || post.content.toLowerCase().includes(query)); } // Apply category filter if (selectedCategory) { filtered = (0, categories_1.filterPostsByCategory)(filtered, selectedCategory); } // Apply tag filters if (selectedTags.length > 0) { filtered = filtered.filter((post) => selectedTags.some((tagSlug) => { var _a; return (_a = post.tags) === null || _a === void 0 ? void 0 : _a.some((tag) => tag.slug === tagSlug); })); } setFilteredPosts(filtered); }, [searchQuery, allPosts, selectedCategory, selectedTags]); // Apply limit to final posts const posts = react_1.default.useMemo(() => { if (limit && !searchQuery.trim()) { return filteredPosts.slice(0, limit); } return filteredPosts; }, [filteredPosts, limit, searchQuery]); if (loading) { return (0, jsx_runtime_1.jsx)(LoadingStates_1.BlogListSkeleton, { className: className }); } if (error) { return ((0, jsx_runtime_1.jsx)(LoadingStates_1.FadeIn, { children: (0, jsx_runtime_1.jsx)("div", { className: `zemenay-blog-list ${className}`, children: (0, jsx_runtime_1.jsxs)("div", { className: "error", children: ["Error: ", error] }) }) })); } // Handle category selection const handleCategoryClick = (category) => { setSelectedCategory(selectedCategory === category.slug ? "" : category.slug); }; // Handle tag selection const handleTagClick = (tag) => { setSelectedTags((prev) => prev.includes(tag.slug) ? prev.filter((t) => t !== tag.slug) : [...prev, tag.slug]); }; // Clear all filters const clearFilters = () => { setSelectedCategory(""); setSelectedTags([]); setSearchQuery(""); }; const hasActiveFilters = selectedCategory || selectedTags.length > 0 || searchQuery.trim(); return ((0, jsx_runtime_1.jsxs)("div", { className: `zemenay-blog-list ${className}`, children: [showSearch && ((0, jsx_runtime_1.jsx)(LoadingStates_1.FadeIn, { delay: 100, children: (0, jsx_runtime_1.jsx)(SearchBar_1.SearchWithFilters, { searchQuery: searchQuery, onSearchChange: setSearchQuery, loading: false, totalResults: filteredPosts.length, hasSearched: searchQuery.trim().length > 0, placeholder: searchPlaceholder, categories: categories, tags: tags, selectedCategory: selectedCategory, selectedTags: selectedTags, onCategoryClick: handleCategoryClick, onTagClick: handleTagClick, onClearFilters: clearFilters }) })), hasActiveFilters && ((0, jsx_runtime_1.jsx)(LoadingStates_1.SlideIn, { direction: "down", delay: 200, children: (0, jsx_runtime_1.jsx)(FilterControls_1.ActiveFiltersBar, { categories: categories, tags: tags, selectedCategory: selectedCategory, selectedTags: selectedTags, onCategoryClick: handleCategoryClick, onTagClick: handleTagClick, onClearFilters: clearFilters }) })), posts.length === 0 && hasActiveFilters && ((0, jsx_runtime_1.jsx)("div", { className: "empty", children: "No posts found with the current filters." })), posts.length === 0 && !hasActiveFilters && ((0, jsx_runtime_1.jsx)("div", { className: "empty", children: "No posts found." })), posts.length > 0 && ((0, jsx_runtime_1.jsx)("div", { className: "stagger-animation", children: posts.map((post, index) => ((0, jsx_runtime_1.jsx)(LoadingStates_1.SlideIn, { direction: "up", delay: index * 100 + 300, children: (0, jsx_runtime_1.jsxs)("article", { className: `blog-post-preview pulse-on-hover smooth-transition ${hasActiveFilters ? "search-result" : ""}`, children: [(0, jsx_runtime_1.jsx)("h2", { className: "post-title", onClick: () => { console.log("Clicking post with slug:", post.slug); onPostClick === null || onPostClick === void 0 ? void 0 : onPostClick(post.slug); }, style: { cursor: onPostClick ? "pointer" : "default" }, children: post.title }), (0, jsx_runtime_1.jsx)(CategoryTag_1.PostCategoriesTags, { post: post, onCategoryClick: handleCategoryClick, onTagClick: handleTagClick }), (0, jsx_runtime_1.jsx)("div", { className: "post-meta", children: (0, jsx_runtime_1.jsx)("time", { dateTime: post.created_at, children: new Date(post.created_at).toLocaleDateString() }) }), (0, jsx_runtime_1.jsxs)("div", { className: "post-excerpt", children: [post.content.substring(0, 200), post.content.length > 200 && "..."] })] }) }, post.id))) }))] })); }