Initial commit - WhyRating Engine (Google Reviews Scraper)
This commit is contained in:
111
web/components/taxonomy/TreeNode.tsx
Normal file
111
web/components/taxonomy/TreeNode.tsx
Normal file
@@ -0,0 +1,111 @@
|
||||
'use client';
|
||||
|
||||
import { ChevronRight, ChevronDown } from 'lucide-react';
|
||||
import { DOMAIN_TEXT_COLORS } from '@/lib/taxonomy/types';
|
||||
|
||||
interface TreeNodeProps {
|
||||
code: string;
|
||||
name: string;
|
||||
count?: number;
|
||||
isExpanded?: boolean;
|
||||
isSelected?: boolean;
|
||||
isLeaf?: boolean;
|
||||
level: 'domain' | 'category' | 'subcode';
|
||||
domainKey: string;
|
||||
onToggle?: () => void;
|
||||
onClick?: () => void;
|
||||
searchMatch?: boolean;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export default function TreeNode({
|
||||
code,
|
||||
name,
|
||||
count,
|
||||
isExpanded = false,
|
||||
isSelected = false,
|
||||
isLeaf = false,
|
||||
level,
|
||||
domainKey,
|
||||
onToggle,
|
||||
onClick,
|
||||
searchMatch = false,
|
||||
children,
|
||||
}: TreeNodeProps) {
|
||||
const textColor = DOMAIN_TEXT_COLORS[domainKey] || 'text-gray-400';
|
||||
|
||||
const handleClick = (e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
if (isLeaf) {
|
||||
onClick?.();
|
||||
} else {
|
||||
onToggle?.();
|
||||
}
|
||||
};
|
||||
|
||||
const handleChevronClick = (e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
onToggle?.();
|
||||
};
|
||||
|
||||
const getPadding = () => {
|
||||
switch (level) {
|
||||
case 'domain':
|
||||
return 'pl-2';
|
||||
case 'category':
|
||||
return 'pl-6';
|
||||
case 'subcode':
|
||||
return 'pl-10';
|
||||
default:
|
||||
return 'pl-2';
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
onClick={handleClick}
|
||||
className={`
|
||||
flex items-center gap-2 py-1.5 px-2 rounded cursor-pointer transition-colors
|
||||
${getPadding()}
|
||||
${isSelected ? 'bg-gray-700' : 'hover:bg-gray-800/50'}
|
||||
${searchMatch ? 'ring-1 ring-yellow-500/50' : ''}
|
||||
`}
|
||||
>
|
||||
{/* Expand/Collapse Icon */}
|
||||
{!isLeaf ? (
|
||||
<button
|
||||
onClick={handleChevronClick}
|
||||
className="w-4 h-4 flex items-center justify-center text-gray-500 hover:text-gray-300"
|
||||
>
|
||||
{isExpanded ? (
|
||||
<ChevronDown className="w-4 h-4" />
|
||||
) : (
|
||||
<ChevronRight className="w-4 h-4" />
|
||||
)}
|
||||
</button>
|
||||
) : (
|
||||
<span className="w-4 h-4 flex items-center justify-center text-gray-600">
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-current" />
|
||||
</span>
|
||||
)}
|
||||
|
||||
{/* Code */}
|
||||
<span className={`font-mono text-sm ${textColor}`}>{code}</span>
|
||||
|
||||
{/* Name */}
|
||||
<span className="text-sm text-gray-300 truncate flex-1">{name}</span>
|
||||
|
||||
{/* Count Badge */}
|
||||
{count !== undefined && (
|
||||
<span className="text-xs text-gray-500 bg-gray-800 px-1.5 py-0.5 rounded">
|
||||
{count}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Children (expanded content) */}
|
||||
{isExpanded && children && <div>{children}</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user