Skip to content

feat(blog): add category filtering and navigation#1990

Merged
ComputelessComputer merged 1 commit intomainfrom
feat/add-blog-category-filtering
Nov 29, 2025
Merged

feat(blog): add category filtering and navigation#1990
ComputelessComputer merged 1 commit intomainfrom
feat/add-blog-category-filtering

Conversation

@ComputelessComputer
Copy link
Collaborator

No description provided.

@netlify
Copy link

netlify bot commented Nov 29, 2025

Deploy Preview for hyprnote ready!

Name Link
🔨 Latest commit c7c58de
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote/deploys/692a92c5a515ed000808fcb0
😎 Deploy Preview https://deploy-preview-1990--hyprnote.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link

netlify bot commented Nov 29, 2025

Deploy Preview for hyprnote-storybook ready!

Name Link
🔨 Latest commit c7c58de
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote-storybook/deploys/692a92c54fc117000860ad89
😎 Deploy Preview https://deploy-preview-1990--hyprnote-storybook.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 29, 2025

📝 Walkthrough

Walkthrough

This PR adds category filtering functionality to the blog by introducing a category field to the articles schema and implementing search parameter validation, category-based filtering logic, and responsive UI sections for category navigation with article counts.

Changes

Cohort / File(s) Summary
Schema Updates
apps/web/content-collections.ts
Added optional category enum field to articles collection schema with values: "Case Study", "Hyprnote Weekly", "Productivity Hack", and "Engineering"
Blog Category Filtering
apps/web/src/routes/_view/blog/index.tsx
Integrated route search validation to normalize category parameters; implemented category filtering logic with useMemo for computed filtered articles; introduced new internal components (MobileCategoriesSection, DesktopSidebar) for responsive category navigation with counts; updated ArticleListItem, MostRecentFeaturedCard, and OtherFeaturedCard to display category badges; added FeaturedSection and AllArticlesSection with category-aware titles and filtering

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–25 minutes

  • Route validation logic — Verify validateSearch correctly normalizes search parameters and handles edge cases
  • Filtering implementation — Review useMemo dependency array, selectedCategory logic, and "featured" special case handling
  • New components — Ensure MobileCategoriesSection and DesktopSidebar are properly responsive and handle category selection callbacks correctly
  • Component prop updates — Confirm ArticleListItem, card components, and AllArticlesSection correctly receive and render category metadata

Possibly related PRs

Suggested reviewers

  • yujonglee

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description check ❓ Inconclusive No pull request description was provided by the author; the PR contains only a title with no descriptive content. Add a description explaining the purpose of category filtering, its benefits, and any relevant context for reviewers.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(blog): add category filtering and navigation' directly and accurately summarizes the main changes in the changeset, which adds category filtering infrastructure and navigation to the blog.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/add-blog-category-filtering

Comment @coderabbitai help to get the list of available commands and usage tips.

@ComputelessComputer ComputelessComputer merged commit 662da6b into main Nov 29, 2025
10 of 11 checks passed
@ComputelessComputer ComputelessComputer deleted the feat/add-blog-category-filtering branch November 29, 2025 06:31
@argos-ci
Copy link

argos-ci bot commented Nov 29, 2025

The latest updates on your projects. Learn more about Argos notifications ↗︎

Build Status Details Updated (UTC)
web (Inspect) ⚠️ Changes detected (Review) 2 changed Nov 29, 2025, 6:32 AM

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
apps/web/src/routes/_view/blog/index.tsx (3)

18-27: Consider deriving CATEGORIES from the schema to avoid duplication.

The CATEGORIES constant duplicates the enum values defined in content-collections.ts. If the schema enum changes, this array must be updated manually, risking drift.

You could export the category values from the schema or use the generated types:

// Option 1: Import from content-collections if available
import { allArticles } from "content-collections";

// Derive categories from actual article data
const CATEGORIES = [...new Set(allArticles.map(a => a.category).filter(Boolean))] as const;

Alternatively, define a shared constant that both the schema and this file import.


31-36: Consider validating category against known values.

The validateSearch accepts any string for category. An invalid category (e.g., ?category=invalid) will result in showing zero articles with no user feedback.

 validateSearch: (search: Record<string, unknown>): BlogSearch => {
+  const validCategories = ["featured", ...CATEGORIES];
+  const category = typeof search.category === "string" ? search.category : undefined;
   return {
-    category:
-      typeof search.category === "string" ? search.category : undefined,
+    category: category && validCategories.includes(category) ? category : undefined,
   };
 },

62-66: Memoize sortedArticles to prevent unnecessary recalculations.

sortedArticles creates a new array reference on every render, causing articlesByCategory and filteredArticles to recompute even when publishedArticles hasn't changed.

-  const sortedArticles = [...publishedArticles].sort((a, b) => {
-    const aDate = a.updated || a.created;
-    const bDate = b.updated || b.created;
-    return new Date(bDate).getTime() - new Date(aDate).getTime();
-  });
+  const sortedArticles = useMemo(() => {
+    return [...publishedArticles].sort((a, b) => {
+      const aDate = a.updated || a.created;
+      const bDate = b.updated || b.created;
+      return new Date(bDate).getTime() - new Date(aDate).getTime();
+    });
+  }, [publishedArticles]);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 753bb61 and c7c58de.

📒 Files selected for processing (2)
  • apps/web/content-collections.ts (1 hunks)
  • apps/web/src/routes/_view/blog/index.tsx (11 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Agent implementations should use TypeScript and follow the established architectural patterns defined in the agent framework
Agent communication should use defined message protocols and interfaces

Files:

  • apps/web/content-collections.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Avoid creating a bunch of types/interfaces if they are not shared. Especially for function props, just inline them instead.
Never do manual state management for form/mutation. Use useForm (from tanstack-form) and useQuery/useMutation (from tanstack-query) instead for 99% of cases. Avoid patterns like setError.
If there are many classNames with conditional logic, use cn (import from @hypr/utils). It is similar to clsx. Always pass an array and split by logical grouping.
Use motion/react instead of framer-motion.

Files:

  • apps/web/content-collections.ts
  • apps/web/src/routes/_view/blog/index.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Redirect rules - hyprnote
  • GitHub Check: Header rules - hyprnote
  • GitHub Check: Pages changed - hyprnote
  • GitHub Check: fmt
  • GitHub Check: ci (macos, macos-14)
🔇 Additional comments (9)
apps/web/content-collections.ts (1)

50-57: LGTM!

The optional category enum field is well-defined and aligns with the CATEGORIES constant in the blog route component. Making it optional is appropriate for backward compatibility with existing articles.

apps/web/src/routes/_view/blog/index.tsx (8)

159-214: LGTM!

Clean implementation of the mobile category navigation. Good use of cn with arrays for conditional styling as per coding guidelines, and proper responsive design with horizontal scrolling.


216-289: LGTM!

Well-structured desktop sidebar component with proper sticky positioning, category counts, and consistent styling patterns using cn with arrays.


291-329: LGTM!

Clean featured section implementation with appropriate grid layout and separation between the most recent featured article and others.


331-359: LGTM!

The AllArticlesSection correctly derives the title from selectedCategory and renders the filtered article list appropriately.


370-442: LGTM!

Well-implemented featured card with appropriate image loading state management and conditional category badge rendering.


444-538: LGTM!

Consistent implementation with MostRecentFeaturedCard, with appropriate responsive layout adjustments for the smaller card variant.


540-616: LGTM!

Clean article list item implementation with appropriate responsive design for both mobile and desktop views, including conditional category badge rendering.


618-652: LGTM!

Clean, reusable image component with proper loading state handling and early return for missing sources.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant