Add feature label component

This commit is contained in:
Andras Schmelczer 2026-02-07 13:25:11 +00:00
parent c91561d7fe
commit 392f73467b
3 changed files with 45 additions and 11 deletions

View file

@ -10,6 +10,7 @@ import { groupFeaturesByCategory } from '../lib/features';
import InfoPopup from './InfoPopup'; import InfoPopup from './InfoPopup';
import { FeatureInfoPopup } from './FeatureInfoPopup'; import { FeatureInfoPopup } from './FeatureInfoPopup';
import { FeatureActions } from './FeatureIcons'; import { FeatureActions } from './FeatureIcons';
import { FeatureLabel } from './ui/FeatureLabel';
interface FiltersProps { interface FiltersProps {
features: FeatureMeta[]; features: FeatureMeta[];
@ -91,7 +92,7 @@ function FeatureBrowser({
className="flex items-start justify-between px-3 py-1.5 hover:bg-teal-50 dark:hover:bg-teal-900/30 dark:text-warm-300" className="flex items-start justify-between px-3 py-1.5 hover:bg-teal-50 dark:hover:bg-teal-900/30 dark:text-warm-300"
> >
<div className="min-w-0 mr-2"> <div className="min-w-0 mr-2">
<span className="text-sm truncate block">{f.name}</span> <FeatureLabel feature={f} onShowInfo={setInfoFeature} size="sm" />
{f.description && ( {f.description && (
<span className="text-xs text-warm-400 dark:text-warm-500 truncate block"> <span className="text-xs text-warm-400 dark:text-warm-500 truncate block">
{f.description} {f.description}
@ -102,7 +103,6 @@ function FeatureBrowser({
feature={f} feature={f}
isPinned={isPinned} isPinned={isPinned}
onTogglePin={onTogglePin} onTogglePin={onTogglePin}
onShowInfo={setInfoFeature}
onAdd={onAddFilter} onAdd={onAddFilter}
/> />
</div> </div>
@ -232,12 +232,11 @@ export default memo(function Filters({
className={`space-y-1 p-3 rounded ${pinnedFeature === feature.name ? 'ring-2 ring-teal-400 bg-teal-50/50 dark:bg-teal-900/20' : ''}`} className={`space-y-1 p-3 rounded ${pinnedFeature === feature.name ? 'ring-2 ring-teal-400 bg-teal-50/50 dark:bg-teal-900/20' : ''}`}
> >
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<Label>{feature.name}</Label> <FeatureLabel feature={feature} onShowInfo={setActiveInfoFeature} size="sm" />
<FeatureActions <FeatureActions
feature={feature} feature={feature}
isPinned={pinnedFeature === feature.name} isPinned={pinnedFeature === feature.name}
onTogglePin={onTogglePin} onTogglePin={onTogglePin}
onShowInfo={setActiveInfoFeature}
onRemove={onRemoveFilter} onRemove={onRemoveFilter}
/> />
</div> </div>
@ -281,15 +280,16 @@ export default memo(function Filters({
className={`space-y-1 p-3 rounded ${isActive ? 'ring-2 ring-teal-400 bg-teal-50 dark:bg-teal-900/30' : isPinned ? 'ring-2 ring-teal-400 bg-teal-50/50 dark:bg-teal-900/20' : ''}`} className={`space-y-1 p-3 rounded ${isActive ? 'ring-2 ring-teal-400 bg-teal-50 dark:bg-teal-900/30' : isPinned ? 'ring-2 ring-teal-400 bg-teal-50/50 dark:bg-teal-900/20' : ''}`}
> >
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<Label> <div className="flex items-center gap-1 min-w-0">
{feature.name}: {formatFilterValue(displayValue[0])} -{' '} <FeatureLabel feature={feature} onShowInfo={setActiveInfoFeature} size="sm" />
{formatFilterValue(displayValue[1])} <span className="text-sm text-warm-500 dark:text-warm-400">
</Label> {formatFilterValue(displayValue[0])} - {formatFilterValue(displayValue[1])}
</span>
</div>
<FeatureActions <FeatureActions
feature={feature} feature={feature}
isPinned={isPinned} isPinned={isPinned}
onTogglePin={onTogglePin} onTogglePin={onTogglePin}
onShowInfo={setActiveInfoFeature}
onRemove={onRemoveFilter} onRemove={onRemoveFilter}
/> />
</div> </div>

View file

@ -0,0 +1,35 @@
import type { FeatureMeta } from '../../types';
import { InfoIcon } from './icons';
interface FeatureLabelProps {
feature: FeatureMeta;
onShowInfo?: (feature: FeatureMeta) => void;
className?: string;
size?: 'xs' | 'sm';
}
export function FeatureLabel({
feature,
onShowInfo,
className = '',
size = 'xs',
}: FeatureLabelProps) {
const textClass = size === 'sm' ? 'text-sm' : 'text-xs';
return (
<div className={`flex items-center gap-1 min-w-0 ${className}`}>
<span className={`${textClass} text-warm-700 dark:text-warm-300 truncate`}>
{feature.name}
</span>
{feature.detail && onShowInfo && (
<button
onClick={() => onShowInfo(feature)}
className="p-1 -m-0.5 rounded text-warm-400 hover:text-warm-700 dark:hover:text-warm-300 hover:bg-warm-100 dark:hover:bg-warm-700 shrink-0"
title="Feature info"
>
<InfoIcon className="w-3.5 h-3.5" />
</button>
)}
</div>
);
}

View file

@ -5,7 +5,7 @@ interface TabButtonProps {
onClick: () => void; onClick: () => void;
} }
export function TabButton({ label, count, isActive, onClick }: TabButtonProps) { export function TabButton({ label, isActive, onClick }: TabButtonProps) {
return ( return (
<button <button
className={`flex-1 p-3 ${ className={`flex-1 p-3 ${
@ -16,7 +16,6 @@ export function TabButton({ label, count, isActive, onClick }: TabButtonProps) {
onClick={onClick} onClick={onClick}
> >
{label} {label}
{count !== undefined && count > 0 && ` (${count})`}
</button> </button>
); );
} }