auto-claude: subtask-1-2 - Create CategoryFilter component with category buttons/dropdown
Created CategoryFilter component with the following features: - Client component with 'use client' directive and framer-motion animations - Props: categories, selectedCategory, onCategoryChange, className - Uses lucide-react Tag icon - Responsive design: horizontal scrollable on mobile, grid layout on desktop - Active category highlighted with bg-[#697565] text-white - Includes 'All' option to clear filter - Follows established patterns from SearchBar and ContactForm - Consistent styling with bg-zinc-900/50 and border-zinc-800 - Smooth transitions and hover states Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,227 @@
|
|||||||
|
{
|
||||||
|
"base_commands": [
|
||||||
|
".",
|
||||||
|
"[",
|
||||||
|
"[[",
|
||||||
|
"ag",
|
||||||
|
"awk",
|
||||||
|
"basename",
|
||||||
|
"bash",
|
||||||
|
"bc",
|
||||||
|
"break",
|
||||||
|
"cat",
|
||||||
|
"cd",
|
||||||
|
"chmod",
|
||||||
|
"clear",
|
||||||
|
"cmp",
|
||||||
|
"column",
|
||||||
|
"comm",
|
||||||
|
"command",
|
||||||
|
"continue",
|
||||||
|
"cp",
|
||||||
|
"curl",
|
||||||
|
"cut",
|
||||||
|
"date",
|
||||||
|
"df",
|
||||||
|
"diff",
|
||||||
|
"dig",
|
||||||
|
"dirname",
|
||||||
|
"du",
|
||||||
|
"echo",
|
||||||
|
"egrep",
|
||||||
|
"env",
|
||||||
|
"eval",
|
||||||
|
"exec",
|
||||||
|
"exit",
|
||||||
|
"expand",
|
||||||
|
"export",
|
||||||
|
"expr",
|
||||||
|
"false",
|
||||||
|
"fd",
|
||||||
|
"fgrep",
|
||||||
|
"file",
|
||||||
|
"find",
|
||||||
|
"fmt",
|
||||||
|
"fold",
|
||||||
|
"gawk",
|
||||||
|
"gh",
|
||||||
|
"git",
|
||||||
|
"grep",
|
||||||
|
"gunzip",
|
||||||
|
"gzip",
|
||||||
|
"head",
|
||||||
|
"help",
|
||||||
|
"host",
|
||||||
|
"iconv",
|
||||||
|
"id",
|
||||||
|
"jobs",
|
||||||
|
"join",
|
||||||
|
"jq",
|
||||||
|
"kill",
|
||||||
|
"killall",
|
||||||
|
"less",
|
||||||
|
"let",
|
||||||
|
"ln",
|
||||||
|
"ls",
|
||||||
|
"lsof",
|
||||||
|
"man",
|
||||||
|
"mkdir",
|
||||||
|
"mktemp",
|
||||||
|
"more",
|
||||||
|
"mv",
|
||||||
|
"nl",
|
||||||
|
"paste",
|
||||||
|
"pgrep",
|
||||||
|
"ping",
|
||||||
|
"pkill",
|
||||||
|
"popd",
|
||||||
|
"printenv",
|
||||||
|
"printf",
|
||||||
|
"ps",
|
||||||
|
"pushd",
|
||||||
|
"pwd",
|
||||||
|
"read",
|
||||||
|
"readlink",
|
||||||
|
"realpath",
|
||||||
|
"reset",
|
||||||
|
"return",
|
||||||
|
"rev",
|
||||||
|
"rg",
|
||||||
|
"rm",
|
||||||
|
"rmdir",
|
||||||
|
"sed",
|
||||||
|
"seq",
|
||||||
|
"set",
|
||||||
|
"sh",
|
||||||
|
"shuf",
|
||||||
|
"sleep",
|
||||||
|
"sort",
|
||||||
|
"source",
|
||||||
|
"split",
|
||||||
|
"stat",
|
||||||
|
"tail",
|
||||||
|
"tar",
|
||||||
|
"tee",
|
||||||
|
"test",
|
||||||
|
"time",
|
||||||
|
"timeout",
|
||||||
|
"touch",
|
||||||
|
"tr",
|
||||||
|
"tree",
|
||||||
|
"true",
|
||||||
|
"type",
|
||||||
|
"uname",
|
||||||
|
"unexpand",
|
||||||
|
"uniq",
|
||||||
|
"unset",
|
||||||
|
"unzip",
|
||||||
|
"watch",
|
||||||
|
"wc",
|
||||||
|
"wget",
|
||||||
|
"whereis",
|
||||||
|
"which",
|
||||||
|
"whoami",
|
||||||
|
"xargs",
|
||||||
|
"yes",
|
||||||
|
"yq",
|
||||||
|
"zip",
|
||||||
|
"zsh"
|
||||||
|
],
|
||||||
|
"stack_commands": [
|
||||||
|
"ar",
|
||||||
|
"clang",
|
||||||
|
"clang++",
|
||||||
|
"cmake",
|
||||||
|
"composer",
|
||||||
|
"dive",
|
||||||
|
"docker",
|
||||||
|
"docker-buildx",
|
||||||
|
"docker-compose",
|
||||||
|
"dockerfile",
|
||||||
|
"eslint",
|
||||||
|
"g++",
|
||||||
|
"gcc",
|
||||||
|
"ipython",
|
||||||
|
"jupyter",
|
||||||
|
"ld",
|
||||||
|
"make",
|
||||||
|
"meson",
|
||||||
|
"next",
|
||||||
|
"ninja",
|
||||||
|
"nm",
|
||||||
|
"node",
|
||||||
|
"notebook",
|
||||||
|
"npm",
|
||||||
|
"npx",
|
||||||
|
"objdump",
|
||||||
|
"pdb",
|
||||||
|
"php",
|
||||||
|
"pip",
|
||||||
|
"pip3",
|
||||||
|
"pipx",
|
||||||
|
"pnpm",
|
||||||
|
"pnpx",
|
||||||
|
"pudb",
|
||||||
|
"python",
|
||||||
|
"python3",
|
||||||
|
"react-scripts",
|
||||||
|
"strip",
|
||||||
|
"ts-node",
|
||||||
|
"tsc",
|
||||||
|
"tsx",
|
||||||
|
"vitest"
|
||||||
|
],
|
||||||
|
"script_commands": [
|
||||||
|
"bun",
|
||||||
|
"npm",
|
||||||
|
"pnpm",
|
||||||
|
"yarn"
|
||||||
|
],
|
||||||
|
"custom_commands": [],
|
||||||
|
"detected_stack": {
|
||||||
|
"languages": [
|
||||||
|
"python",
|
||||||
|
"javascript",
|
||||||
|
"typescript",
|
||||||
|
"php",
|
||||||
|
"c"
|
||||||
|
],
|
||||||
|
"package_managers": [
|
||||||
|
"pnpm"
|
||||||
|
],
|
||||||
|
"frameworks": [
|
||||||
|
"nextjs",
|
||||||
|
"react",
|
||||||
|
"vitest",
|
||||||
|
"eslint"
|
||||||
|
],
|
||||||
|
"databases": [],
|
||||||
|
"infrastructure": [
|
||||||
|
"docker"
|
||||||
|
],
|
||||||
|
"cloud_providers": [],
|
||||||
|
"code_quality_tools": [],
|
||||||
|
"version_managers": []
|
||||||
|
},
|
||||||
|
"custom_scripts": {
|
||||||
|
"npm_scripts": [
|
||||||
|
"dev",
|
||||||
|
"build",
|
||||||
|
"start",
|
||||||
|
"lint",
|
||||||
|
"build:images",
|
||||||
|
"generate:images",
|
||||||
|
"generate:images:dry",
|
||||||
|
"test",
|
||||||
|
"test:coverage"
|
||||||
|
],
|
||||||
|
"make_targets": [],
|
||||||
|
"poetry_scripts": [],
|
||||||
|
"cargo_aliases": [],
|
||||||
|
"shell_scripts": []
|
||||||
|
},
|
||||||
|
"project_dir": "C:\\Users\\damja\\WebstormProjects\\Portfolio",
|
||||||
|
"created_at": "2026-01-22T15:28:38.237190",
|
||||||
|
"project_hash": "c4ad399e16be367eb4e6b076fe1d9ee3",
|
||||||
|
"inherited_from": "C:\\Users\\damja\\WebstormProjects\\Portfolio"
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"active": true,
|
||||||
|
"spec": "003-add-blog-search-and-category-filter",
|
||||||
|
"state": "building",
|
||||||
|
"subtasks": {
|
||||||
|
"completed": 1,
|
||||||
|
"total": 4,
|
||||||
|
"in_progress": 1,
|
||||||
|
"failed": 0
|
||||||
|
},
|
||||||
|
"phase": {
|
||||||
|
"current": "Blog Search and Filter Implementation",
|
||||||
|
"id": null,
|
||||||
|
"total": 4
|
||||||
|
},
|
||||||
|
"workers": {
|
||||||
|
"active": 0,
|
||||||
|
"max": 1
|
||||||
|
},
|
||||||
|
"session": {
|
||||||
|
"number": 3,
|
||||||
|
"started_at": "2026-01-25T02:31:36.044848"
|
||||||
|
},
|
||||||
|
"last_update": "2026-01-25T02:38:09.538183"
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
"sandbox": {
|
||||||
|
"enabled": true,
|
||||||
|
"autoAllowBashIfSandboxed": true
|
||||||
|
},
|
||||||
|
"permissions": {
|
||||||
|
"defaultMode": "acceptEdits",
|
||||||
|
"allow": [
|
||||||
|
"Read(./**)",
|
||||||
|
"Write(./**)",
|
||||||
|
"Edit(./**)",
|
||||||
|
"Glob(./**)",
|
||||||
|
"Grep(./**)",
|
||||||
|
"Read(C:\\Users\\damja\\WebstormProjects\\Portfolio\\.auto-claude\\worktrees\\tasks\\003-add-blog-search-and-category-filter/**)",
|
||||||
|
"Write(C:\\Users\\damja\\WebstormProjects\\Portfolio\\.auto-claude\\worktrees\\tasks\\003-add-blog-search-and-category-filter/**)",
|
||||||
|
"Edit(C:\\Users\\damja\\WebstormProjects\\Portfolio\\.auto-claude\\worktrees\\tasks\\003-add-blog-search-and-category-filter/**)",
|
||||||
|
"Glob(C:\\Users\\damja\\WebstormProjects\\Portfolio\\.auto-claude\\worktrees\\tasks\\003-add-blog-search-and-category-filter/**)",
|
||||||
|
"Grep(C:\\Users\\damja\\WebstormProjects\\Portfolio\\.auto-claude\\worktrees\\tasks\\003-add-blog-search-and-category-filter/**)",
|
||||||
|
"Read(C:\\Users\\damja\\WebstormProjects\\Portfolio\\.auto-claude\\worktrees\\tasks\\003-add-blog-search-and-category-filter\\.auto-claude\\specs\\003-add-blog-search-and-category-filter/**)",
|
||||||
|
"Write(C:\\Users\\damja\\WebstormProjects\\Portfolio\\.auto-claude\\worktrees\\tasks\\003-add-blog-search-and-category-filter\\.auto-claude\\specs\\003-add-blog-search-and-category-filter/**)",
|
||||||
|
"Edit(C:\\Users\\damja\\WebstormProjects\\Portfolio\\.auto-claude\\worktrees\\tasks\\003-add-blog-search-and-category-filter\\.auto-claude\\specs\\003-add-blog-search-and-category-filter/**)",
|
||||||
|
"Read(C:\\Users\\damja\\WebstormProjects\\Portfolio\\.auto-claude/**)",
|
||||||
|
"Write(C:\\Users\\damja\\WebstormProjects\\Portfolio\\.auto-claude/**)",
|
||||||
|
"Edit(C:\\Users\\damja\\WebstormProjects\\Portfolio\\.auto-claude/**)",
|
||||||
|
"Glob(C:\\Users\\damja\\WebstormProjects\\Portfolio\\.auto-claude/**)",
|
||||||
|
"Grep(C:\\Users\\damja\\WebstormProjects\\Portfolio\\.auto-claude/**)",
|
||||||
|
"Bash(*)",
|
||||||
|
"WebFetch(*)",
|
||||||
|
"WebSearch(*)",
|
||||||
|
"mcp__context7__resolve-library-id(*)",
|
||||||
|
"mcp__context7__get-library-docs(*)",
|
||||||
|
"mcp__graphiti-memory__search_nodes(*)",
|
||||||
|
"mcp__graphiti-memory__search_facts(*)",
|
||||||
|
"mcp__graphiti-memory__add_episode(*)",
|
||||||
|
"mcp__graphiti-memory__get_episodes(*)",
|
||||||
|
"mcp__graphiti-memory__get_entity_edge(*)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-1
@@ -81,4 +81,7 @@ supabase/.temp/
|
|||||||
.history/
|
.history/
|
||||||
|
|
||||||
# Source images (originals before optimization)
|
# Source images (originals before optimization)
|
||||||
source-images/
|
source-images/
|
||||||
|
|
||||||
|
# Auto Claude data directory
|
||||||
|
.auto-claude/
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Tag } from 'lucide-react';
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
|
interface CategoryFilterProps {
|
||||||
|
categories: string[];
|
||||||
|
selectedCategory: string | null;
|
||||||
|
onCategoryChange: (category: string | null) => void;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function CategoryFilter({
|
||||||
|
categories,
|
||||||
|
selectedCategory,
|
||||||
|
onCategoryChange,
|
||||||
|
className = ''
|
||||||
|
}: CategoryFilterProps) {
|
||||||
|
const allCategories = ['All', ...categories];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 10 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ delay: 0.1 }}
|
||||||
|
className={`${className}`}
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-3 mb-4">
|
||||||
|
<Tag className="h-5 w-5 text-zinc-400 flex-shrink-0" />
|
||||||
|
<h3 className="text-sm font-medium text-zinc-300">Filter by Category</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Mobile: Horizontal scrollable */}
|
||||||
|
<div className="md:hidden overflow-x-auto pb-2 -mx-4 px-4">
|
||||||
|
<div className="flex gap-2 min-w-max">
|
||||||
|
{allCategories.map((category) => {
|
||||||
|
const isActive = category === 'All'
|
||||||
|
? selectedCategory === null
|
||||||
|
: selectedCategory === category;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={category}
|
||||||
|
onClick={() => onCategoryChange(category === 'All' ? null : category)}
|
||||||
|
className={`px-4 py-2 rounded-lg text-sm font-medium transition-all whitespace-nowrap ${
|
||||||
|
isActive
|
||||||
|
? 'bg-[#697565] text-white'
|
||||||
|
: 'bg-zinc-900/50 text-zinc-400 border border-zinc-800 hover:bg-zinc-800/50 hover:text-white'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{category}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Desktop: Grid */}
|
||||||
|
<div className="hidden md:grid md:grid-cols-4 lg:grid-cols-6 gap-2">
|
||||||
|
{allCategories.map((category) => {
|
||||||
|
const isActive = category === 'All'
|
||||||
|
? selectedCategory === null
|
||||||
|
: selectedCategory === category;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={category}
|
||||||
|
onClick={() => onCategoryChange(category === 'All' ? null : category)}
|
||||||
|
className={`px-4 py-2 rounded-lg text-sm font-medium transition-all ${
|
||||||
|
isActive
|
||||||
|
? 'bg-[#697565] text-white'
|
||||||
|
: 'bg-zinc-900/50 text-zinc-400 border border-zinc-800 hover:bg-zinc-800/50 hover:text-white'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{category}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user