@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
JavaScript
;
"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))) }))] }));
}