feat(task-filters): enhance localization and UI for task filters

- Added new translation keys for task filter functionalities across multiple languages, improving user experience and accessibility.
- Updated the ImprovedTaskFilters component to utilize localized strings for search placeholders, loading states, and filter messages.
- Enhanced styling for filter buttons and dropdowns to ensure consistency in both light and dark modes.
- Introduced a description column in task management components, improving the display of task details.
This commit is contained in:
chamiakJ
2025-07-07 03:04:16 +05:30
parent 9a57413624
commit 01298928c7
11 changed files with 175 additions and 66 deletions

View File

@@ -55,5 +55,18 @@
"selectCategory": "Zgjidh një kategori", "selectCategory": "Zgjidh një kategori",
"pleaseEnterAName": "Ju lutemi vendosni një emër", "pleaseEnterAName": "Ju lutemi vendosni një emër",
"pleaseSelectACategory": "Ju lutemi zgjidhni një kategori", "pleaseSelectACategory": "Ju lutemi zgjidhni një kategori",
"create": "Krijo" "create": "Krijo",
"searchTasks": "Kërko detyrat...",
"searchPlaceholder": "Kërko...",
"fieldsText": "Fushat",
"loadingFilters": "Duke ngarkuar filtrat...",
"noOptionsFound": "Nuk u gjetën opsione",
"filtersActive": "filtra aktiv",
"filterActive": "filtër aktiv",
"clearAll": "Pastro të gjitha",
"clearing": "Duke pastruar...",
"cancel": "Anulo",
"search": "Kërko",
"groupedBy": "Grupuar sipas"
} }

View File

@@ -55,5 +55,18 @@
"selectCategory": "Kategorie auswählen", "selectCategory": "Kategorie auswählen",
"pleaseEnterAName": "Bitte geben Sie einen Namen ein", "pleaseEnterAName": "Bitte geben Sie einen Namen ein",
"pleaseSelectACategory": "Bitte wählen Sie eine Kategorie aus", "pleaseSelectACategory": "Bitte wählen Sie eine Kategorie aus",
"create": "Erstellen" "create": "Erstellen",
"searchTasks": "Aufgaben suchen...",
"searchPlaceholder": "Suchen...",
"fieldsText": "Felder",
"loadingFilters": "Filter werden geladen...",
"noOptionsFound": "Keine Optionen gefunden",
"filtersActive": "Filter aktiv",
"filterActive": "Filter aktiv",
"clearAll": "Alle löschen",
"clearing": "Löschen...",
"cancel": "Abbrechen",
"search": "Suchen",
"groupedBy": "Gruppiert nach"
} }

View File

@@ -55,5 +55,18 @@
"selectCategory": "Select a category", "selectCategory": "Select a category",
"pleaseEnterAName": "Please enter a name", "pleaseEnterAName": "Please enter a name",
"pleaseSelectACategory": "Please select a category", "pleaseSelectACategory": "Please select a category",
"create": "Create" "create": "Create",
"searchTasks": "Search tasks...",
"searchPlaceholder": "Search...",
"fieldsText": "Fields",
"loadingFilters": "Loading filters...",
"noOptionsFound": "No options found",
"filtersActive": "filters active",
"filterActive": "filter active",
"clearAll": "Clear all",
"clearing": "Clearing...",
"cancel": "Cancel",
"search": "Search",
"groupedBy": "Grouped by"
} }

View File

@@ -51,5 +51,18 @@
"selectCategory": "Seleccionar una categoría", "selectCategory": "Seleccionar una categoría",
"pleaseEnterAName": "Por favor, ingrese un nombre", "pleaseEnterAName": "Por favor, ingrese un nombre",
"pleaseSelectACategory": "Por favor, seleccione una categoría", "pleaseSelectACategory": "Por favor, seleccione una categoría",
"create": "Crear" "create": "Crear",
"searchTasks": "Buscar tareas...",
"searchPlaceholder": "Buscar...",
"fieldsText": "Campos",
"loadingFilters": "Cargando filtros...",
"noOptionsFound": "No se encontraron opciones",
"filtersActive": "filtros activos",
"filterActive": "filtro activo",
"clearAll": "Limpiar todo",
"clearing": "Limpiando...",
"cancel": "Cancelar",
"search": "Buscar",
"groupedBy": "Agrupado por"
} }

View File

@@ -52,5 +52,18 @@
"selectCategory": "Selecionar uma categoria", "selectCategory": "Selecionar uma categoria",
"pleaseEnterAName": "Por favor, insira um nome", "pleaseEnterAName": "Por favor, insira um nome",
"pleaseSelectACategory": "Por favor, selecione uma categoria", "pleaseSelectACategory": "Por favor, selecione uma categoria",
"create": "Criar" "create": "Criar",
"searchTasks": "Pesquisar tarefas...",
"searchPlaceholder": "Pesquisar...",
"fieldsText": "Campos",
"loadingFilters": "Carregando filtros...",
"noOptionsFound": "Nenhuma opção encontrada",
"filtersActive": "filtros ativos",
"filterActive": "filtro ativo",
"clearAll": "Limpar tudo",
"clearing": "Limpando...",
"cancel": "Cancelar",
"search": "Pesquisar",
"groupedBy": "Agrupado por"
} }

View File

@@ -32,6 +32,12 @@ const SubtaskLoadingSkeleton: React.FC<SubtaskLoadingSkeletonProps> = ({ visible
<div className="h-4 w-32 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" /> <div className="h-4 w-32 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" />
</div> </div>
); );
case 'description':
return (
<div style={baseStyle} className="flex items-center px-2">
<div className="h-4 w-40 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" />
</div>
);
case 'status': case 'status':
return ( return (
<div style={baseStyle} className="flex items-center"> <div style={baseStyle} className="flex items-center">

View File

@@ -352,6 +352,24 @@ const TaskRow: React.FC<TaskRowProps> = memo(({ taskId, projectId, visibleColumn
</div> </div>
); );
case 'description':
return (
<div style={baseStyle} className="px-2">
<div
className="text-sm text-gray-600 dark:text-gray-400 truncate"
style={{
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
maxHeight: '24px',
lineHeight: '24px',
}}
title={task.description || ''}
dangerouslySetInnerHTML={{ __html: task.description || '' }}
/>
</div>
);
case 'status': case 'status':
return ( return (
<div style={baseStyle}> <div style={baseStyle}>

View File

@@ -93,6 +93,8 @@ const AddSubtaskRow: React.FC<AddSubtaskRowProps> = memo(({
return <div style={baseStyle} />; return <div style={baseStyle} />;
case 'taskKey': case 'taskKey':
return <div style={baseStyle} />; return <div style={baseStyle} />;
case 'description':
return <div style={baseStyle} />;
case 'title': case 'title':
return ( return (
<div className="flex items-center h-full" style={baseStyle}> <div className="flex items-center h-full" style={baseStyle}>

View File

@@ -92,6 +92,7 @@ const AddTaskRow: React.FC<AddTaskRowProps> = memo(({
case 'dragHandle': case 'dragHandle':
case 'checkbox': case 'checkbox':
case 'taskKey': case 'taskKey':
case 'description':
return <div style={baseStyle} />; return <div style={baseStyle} />;
case 'title': case 'title':
return ( return (

View File

@@ -17,6 +17,7 @@ export const BASE_COLUMNS = [
{ id: 'checkbox', label: '', width: '28px', isSticky: true, key: 'checkbox' }, { id: 'checkbox', label: '', width: '28px', isSticky: true, key: 'checkbox' },
{ id: 'taskKey', label: 'keyColumn', width: '100px', key: COLUMN_KEYS.KEY, minWidth: '100px', maxWidth: '150px' }, { id: 'taskKey', label: 'keyColumn', width: '100px', key: COLUMN_KEYS.KEY, minWidth: '100px', maxWidth: '150px' },
{ id: 'title', label: 'taskColumn', width: '470px', isSticky: true, key: COLUMN_KEYS.NAME }, { id: 'title', label: 'taskColumn', width: '470px', isSticky: true, key: COLUMN_KEYS.NAME },
{ id: 'description', label: 'descriptionColumn', width: '260px', key: COLUMN_KEYS.DESCRIPTION },
{ id: 'status', label: 'statusColumn', width: '120px', key: COLUMN_KEYS.STATUS }, { id: 'status', label: 'statusColumn', width: '120px', key: COLUMN_KEYS.STATUS },
{ id: 'assignees', label: 'assigneesColumn', width: '150px', key: COLUMN_KEYS.ASSIGNEES }, { id: 'assignees', label: 'assigneesColumn', width: '150px', key: COLUMN_KEYS.ASSIGNEES },
{ id: 'priority', label: 'priorityColumn', width: '120px', key: COLUMN_KEYS.PRIORITY }, { id: 'priority', label: 'priorityColumn', width: '120px', key: COLUMN_KEYS.PRIORITY },

View File

@@ -372,6 +372,7 @@ const FilterDropdown: React.FC<{
isDarkMode, isDarkMode,
className = '', className = '',
}) => { }) => {
const { t } = useTranslation('task-list-filters');
// Add permission checks for groupBy section // Add permission checks for groupBy section
const isOwnerOrAdmin = useAuthService().isOwnerOrAdmin(); const isOwnerOrAdmin = useAuthService().isOwnerOrAdmin();
const isProjectManager = useIsProjectManager(); const isProjectManager = useIsProjectManager();
@@ -447,7 +448,7 @@ const FilterDropdown: React.FC<{
selectedCount > 0 selectedCount > 0
? isDarkMode ? isDarkMode
? 'bg-gray-600 text-white border-gray-500' ? 'bg-gray-600 text-white border-gray-500'
: 'bg-blue-50 text-blue-800 border-blue-300 font-semibold' : 'bg-gray-200 text-gray-800 border-gray-300 font-semibold'
: `${themeClasses.buttonBg} ${themeClasses.buttonBorder} ${themeClasses.buttonText}` : `${themeClasses.buttonBg} ${themeClasses.buttonBorder} ${themeClasses.buttonText}`
} }
hover:shadow-sm focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 hover:shadow-sm focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2
@@ -458,7 +459,14 @@ const FilterDropdown: React.FC<{
> >
<IconComponent className="w-3.5 h-3.5" /> <IconComponent className="w-3.5 h-3.5" />
<span>{section.label}</span> <span>{section.label}</span>
{selectedCount > 0 && ( {/* Show selected option for single-select (group by) */}
{section.id === 'groupBy' && selectedCount > 0 && (
<span className={`text-xs ${isDarkMode ? 'text-gray-300' : 'text-gray-600'}`}>
{section.options.find(opt => opt.value === section.selectedValues[0])?.label}
</span>
)}
{/* Show count for multi-select filters */}
{section.id !== 'groupBy' && selectedCount > 0 && (
<span className="inline-flex items-center justify-center w-4 h-4 text-xs font-bold text-white bg-gray-500 rounded-full"> <span className="inline-flex items-center justify-center w-4 h-4 text-xs font-bold text-white bg-gray-500 rounded-full">
{selectedCount} {selectedCount}
</span> </span>
@@ -489,7 +497,7 @@ const FilterDropdown: React.FC<{
<input <input
value={searchTerm} value={searchTerm}
onChange={e => setSearchTerm(e.target.value)} onChange={e => setSearchTerm(e.target.value)}
placeholder={`Search ${section.label.toLowerCase()}...`} placeholder={`${t('searchPlaceholder')} ${section.label.toLowerCase()}...`}
className={`w-full pl-8 pr-2 py-1 rounded border focus:outline-none focus:ring-2 focus:ring-blue-500 transition-colors duration-150 ${ className={`w-full pl-8 pr-2 py-1 rounded border focus:outline-none focus:ring-2 focus:ring-blue-500 transition-colors duration-150 ${
isDarkMode isDarkMode
? 'bg-gray-700 text-gray-100 placeholder-gray-400 border-gray-600' ? 'bg-gray-700 text-gray-100 placeholder-gray-400 border-gray-600'
@@ -504,7 +512,7 @@ const FilterDropdown: React.FC<{
<div className="max-h-48 overflow-y-auto"> <div className="max-h-48 overflow-y-auto">
{filteredOptions.length === 0 ? ( {filteredOptions.length === 0 ? (
<div className={`p-2 text-xs text-center ${themeClasses.secondaryText}`}> <div className={`p-2 text-xs text-center ${themeClasses.secondaryText}`}>
No options found {t('noOptionsFound')}
</div> </div>
) : ( ) : (
<div className="p-0.5"> <div className="p-0.5">
@@ -522,12 +530,13 @@ const FilterDropdown: React.FC<{
isSelected isSelected
? isDarkMode ? isDarkMode
? 'bg-gray-600 text-white' ? 'bg-gray-600 text-white'
: 'bg-blue-50 text-blue-800 font-semibold' : 'bg-gray-200 text-gray-800 font-semibold'
: `${themeClasses.optionText} ${themeClasses.optionHover}` : `${themeClasses.optionText} ${themeClasses.optionHover}`
} }
`} `}
> >
{/* Checkbox/Radio indicator */} {/* Checkbox/Radio indicator - hide for group by */}
{section.id !== 'groupBy' && (
<div <div
className={` className={`
flex items-center justify-center w-3.5 h-3.5 border rounded flex items-center justify-center w-3.5 h-3.5 border rounded
@@ -540,6 +549,7 @@ const FilterDropdown: React.FC<{
> >
{isSelected && <CheckOutlined className="w-2.5 h-2.5" />} {isSelected && <CheckOutlined className="w-2.5 h-2.5" />}
</div> </div>
)}
{/* Color indicator */} {/* Color indicator */}
{option.color && ( {option.color && (
@@ -588,7 +598,8 @@ const SearchFilter: React.FC<{
placeholder?: string; placeholder?: string;
themeClasses: any; themeClasses: any;
className?: string; className?: string;
}> = ({ value, onChange, placeholder = 'Search tasks...', themeClasses, className = '' }) => { }> = ({ value, onChange, placeholder, themeClasses, className = '' }) => {
const { t } = useTranslation('task-list-filters');
const [isExpanded, setIsExpanded] = useState(false); const [isExpanded, setIsExpanded] = useState(false);
const [localValue, setLocalValue] = useState(value); const [localValue, setLocalValue] = useState(value);
const inputRef = useRef<HTMLInputElement>(null); const inputRef = useRef<HTMLInputElement>(null);
@@ -622,14 +633,14 @@ const SearchFilter: React.FC<{
{!isExpanded ? ( {!isExpanded ? (
<button <button
onClick={handleToggle} onClick={handleToggle}
className={`inline-flex items-center gap-1.5 px-2.5 py-1.5 text-xs font-medium rounded-md border transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 ${themeClasses.buttonBg} ${themeClasses.buttonBorder} ${themeClasses.buttonText} ${ className={`inline-flex items-center gap-1.5 px-2.5 py-1.5 text-xs font-medium rounded-md border transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 ${themeClasses.buttonBg} ${themeClasses.buttonBorder} ${themeClasses.buttonText} ${
themeClasses.containerBg === 'bg-gray-800' themeClasses.containerBg === 'bg-gray-800'
? 'focus:ring-offset-gray-900' ? 'focus:ring-offset-gray-900'
: 'focus:ring-offset-white' : 'focus:ring-offset-white'
}`} }`}
> >
<SearchOutlined className="w-3.5 h-3.5" /> <SearchOutlined className="w-3.5 h-3.5" />
<span>Search</span> <span>{t('search')}</span>
</button> </button>
) : ( ) : (
<form onSubmit={handleSubmit} className="flex items-center gap-1.5"> <form onSubmit={handleSubmit} className="flex items-center gap-1.5">
@@ -640,8 +651,8 @@ const SearchFilter: React.FC<{
type="text" type="text"
value={localValue} value={localValue}
onChange={e => setLocalValue(e.target.value)} onChange={e => setLocalValue(e.target.value)}
placeholder={placeholder} placeholder={placeholder || t('searchTasks')}
className={`w-full pr-4 pl-8 py-1 rounded border focus:outline-none focus:ring-2 focus:ring-blue-500 transition-colors duration-150 ${ className={`w-full pr-4 pl-8 py-1 rounded border focus:outline-none focus:ring-2 focus:ring-gray-500 transition-colors duration-150 ${
isDarkMode isDarkMode
? 'bg-gray-700 text-gray-100 placeholder-gray-400 border-gray-600' ? 'bg-gray-700 text-gray-100 placeholder-gray-400 border-gray-600'
: 'bg-white text-gray-900 placeholder-gray-400 border-gray-300' : 'bg-white text-gray-900 placeholder-gray-400 border-gray-300'
@@ -659,16 +670,20 @@ const SearchFilter: React.FC<{
</div> </div>
<button <button
type="submit" type="submit"
className="px-2.5 py-1.5 text-xs font-medium text-white bg-blue-500 rounded-md hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors duration-200" className={`px-2.5 py-1.5 text-xs font-medium rounded-md focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 transition-colors duration-200 ${
isDarkMode
? 'text-white bg-gray-600 hover:bg-gray-700'
: 'text-gray-800 bg-gray-200 hover:bg-gray-300'
}`}
> >
Search {t('search')}
</button> </button>
<button <button
type="button" type="button"
onClick={() => setIsExpanded(false)} onClick={() => setIsExpanded(false)}
className={`px-2.5 py-1.5 text-xs font-medium transition-colors duration-200 ${themeClasses.secondaryText} hover:${themeClasses.optionText}`} className={`px-2.5 py-1.5 text-xs font-medium transition-colors duration-200 ${themeClasses.secondaryText} hover:${themeClasses.optionText}`}
> >
Cancel {t('cancel')}
</button> </button>
</form> </form>
)} )}
@@ -682,6 +697,7 @@ const FieldsDropdown: React.FC<{ themeClasses: any; isDarkMode: boolean }> = ({
themeClasses, themeClasses,
isDarkMode, isDarkMode,
}) => { }) => {
const { t } = useTranslation('task-list-filters');
const dispatch = useDispatch(); const dispatch = useDispatch();
const fieldsRaw = useSelector((state: RootState) => state.taskManagementFields); const fieldsRaw = useSelector((state: RootState) => state.taskManagementFields);
const fields = Array.isArray(fieldsRaw) ? fieldsRaw : []; const fields = Array.isArray(fieldsRaw) ? fieldsRaw : [];
@@ -734,17 +750,17 @@ const FieldsDropdown: React.FC<{ themeClasses: any; isDarkMode: boolean }> = ({
visibleCount > 0 visibleCount > 0
? isDarkMode ? isDarkMode
? 'bg-gray-600 text-white border-gray-500' ? 'bg-gray-600 text-white border-gray-500'
: 'bg-blue-50 text-blue-800 border-blue-300 font-semibold' : 'bg-gray-200 text-gray-800 border-gray-300 font-semibold'
: `${themeClasses.buttonBg} ${themeClasses.buttonBorder} ${themeClasses.buttonText}` : `${themeClasses.buttonBg} ${themeClasses.buttonBorder} ${themeClasses.buttonText}`
} }
hover:shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 hover:shadow-sm focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2
${isDarkMode ? 'focus:ring-offset-gray-900' : 'focus:ring-offset-white'} ${isDarkMode ? 'focus:ring-offset-gray-900' : 'focus:ring-offset-white'}
`} `}
aria-expanded={open} aria-expanded={open}
aria-haspopup="true" aria-haspopup="true"
> >
<EyeOutlined className="w-3.5 h-3.5" /> <EyeOutlined className="w-3.5 h-3.5" />
<span>Fields</span> <span>{t('fieldsText')}</span>
{visibleCount > 0 && ( {visibleCount > 0 && (
<span <span
className={`inline-flex items-center justify-center w-4 h-4 text-xs font-bold ${isDarkMode ? 'text-white bg-gray-500' : 'text-gray-800 bg-gray-300'} rounded-full`} className={`inline-flex items-center justify-center w-4 h-4 text-xs font-bold ${isDarkMode ? 'text-white bg-gray-500' : 'text-gray-800 bg-gray-300'} rounded-full`}
@@ -766,7 +782,7 @@ const FieldsDropdown: React.FC<{ themeClasses: any; isDarkMode: boolean }> = ({
<div className="max-h-48 overflow-y-auto"> <div className="max-h-48 overflow-y-auto">
{sortedFields.length === 0 ? ( {sortedFields.length === 0 ? (
<div className={`p-2 text-xs text-center ${themeClasses.secondaryText}`}> <div className={`p-2 text-xs text-center ${themeClasses.secondaryText}`}>
No fields available {t('noOptionsFound')}
</div> </div>
) : ( ) : (
<div className="p-0.5"> <div className="p-0.5">
@@ -881,7 +897,7 @@ const ImprovedTaskFilters: React.FC<ImprovedTaskFiltersProps> = ({ position, cla
const { projectView } = useTabSearchParam(); const { projectView } = useTabSearchParam();
// Theme-aware class names - memoize to prevent unnecessary re-renders // Theme-aware class names - memoize to prevent unnecessary re-renders
// Using task list row colors for consistency: --task-bg-primary: #1f1f1f, --task-bg-secondary: #141414 // Using greyish colors for both dark and light modes
const themeClasses = useMemo( const themeClasses = useMemo(
() => ({ () => ({
containerBg: isDarkMode ? 'bg-[#1f1f1f]' : 'bg-white', containerBg: isDarkMode ? 'bg-[#1f1f1f]' : 'bg-white',
@@ -897,8 +913,8 @@ const ImprovedTaskFilters: React.FC<ImprovedTaskFiltersProps> = ({ position, cla
dividerBorder: isDarkMode ? 'border-[#404040]' : 'border-gray-200', dividerBorder: isDarkMode ? 'border-[#404040]' : 'border-gray-200',
pillBg: isDarkMode ? 'bg-[#141414]' : 'bg-gray-100', pillBg: isDarkMode ? 'bg-[#141414]' : 'bg-gray-100',
pillText: isDarkMode ? 'text-[#d9d9d9]' : 'text-gray-700', pillText: isDarkMode ? 'text-[#d9d9d9]' : 'text-gray-700',
pillActiveBg: isDarkMode ? 'bg-blue-600' : 'bg-blue-100', pillActiveBg: isDarkMode ? 'bg-gray-600' : 'bg-gray-200',
pillActiveText: isDarkMode ? 'text-white' : 'text-blue-800', pillActiveText: isDarkMode ? 'text-white' : 'text-gray-800',
searchBg: isDarkMode ? 'bg-[#141414]' : 'bg-gray-50', searchBg: isDarkMode ? 'bg-[#141414]' : 'bg-gray-50',
searchBorder: isDarkMode ? 'border-[#303030]' : 'border-gray-300', searchBorder: isDarkMode ? 'border-[#303030]' : 'border-gray-300',
searchText: isDarkMode ? 'text-[#d9d9d9]' : 'text-gray-900', searchText: isDarkMode ? 'text-[#d9d9d9]' : 'text-gray-900',
@@ -1199,8 +1215,8 @@ const ImprovedTaskFilters: React.FC<ImprovedTaskFiltersProps> = ({ position, cla
<div <div
className={`flex items-center gap-2 px-2.5 py-1.5 text-xs ${themeClasses.secondaryText}`} className={`flex items-center gap-2 px-2.5 py-1.5 text-xs ${themeClasses.secondaryText}`}
> >
<div className="animate-spin rounded-full h-3.5 w-3.5 border-b-2 border-blue-500"></div> <div className="animate-spin rounded-full h-3.5 w-3.5 border-b-2 border-gray-500"></div>
<span>Loading filters...</span> <span>{t('loadingFilters')}</span>
</div> </div>
)} )}
</div> </div>
@@ -1211,7 +1227,7 @@ const ImprovedTaskFilters: React.FC<ImprovedTaskFiltersProps> = ({ position, cla
{activeFiltersCount > 0 && ( {activeFiltersCount > 0 && (
<div className="flex items-center gap-1.5"> <div className="flex items-center gap-1.5">
<span className={`text-xs ${themeClasses.secondaryText}`}> <span className={`text-xs ${themeClasses.secondaryText}`}>
{activeFiltersCount} filter{activeFiltersCount !== 1 ? 's' : ''} active {activeFiltersCount} {activeFiltersCount !== 1 ? t('filtersActive') : t('filterActive')}
</span> </span>
<button <button
onClick={clearAllFilters} onClick={clearAllFilters}
@@ -1220,11 +1236,11 @@ const ImprovedTaskFilters: React.FC<ImprovedTaskFiltersProps> = ({ position, cla
clearingFilters clearingFilters
? 'text-gray-400 cursor-not-allowed' ? 'text-gray-400 cursor-not-allowed'
: isDarkMode : isDarkMode
? 'text-blue-400 hover:text-blue-300' ? 'text-gray-400 hover:text-gray-300'
: 'text-blue-600 hover:text-blue-700' : 'text-gray-600 hover:text-gray-700'
}`} }`}
> >
{clearingFilters ? 'Clearing...' : 'Clear all'} {clearingFilters ? t('clearing') : t('clearAll')}
</button> </button>
</div> </div>
)} )}
@@ -1236,13 +1252,13 @@ const ImprovedTaskFilters: React.FC<ImprovedTaskFiltersProps> = ({ position, cla
type="checkbox" type="checkbox"
checked={showArchived} checked={showArchived}
onChange={toggleArchived} onChange={toggleArchived}
className={`w-3.5 h-3.5 text-blue-600 rounded focus:ring-blue-500 transition-colors duration-150 ${ className={`w-3.5 h-3.5 text-gray-600 rounded focus:ring-gray-500 transition-colors duration-150 ${
isDarkMode isDarkMode
? 'border-[#303030] bg-[#141414] focus:ring-offset-gray-800' ? 'border-[#303030] bg-[#141414] focus:ring-offset-gray-800'
: 'border-gray-300 bg-white focus:ring-offset-white' : 'border-gray-300 bg-white focus:ring-offset-white'
}`} }`}
/> />
<span className={`text-xs ${themeClasses.optionText}`}>Show archived</span> <span className={`text-xs ${themeClasses.optionText}`}>{t('showArchivedText')}</span>
<InboxOutlined className={`w-3.5 h-3.5 ${themeClasses.secondaryText}`} /> <InboxOutlined className={`w-3.5 h-3.5 ${themeClasses.secondaryText}`} />
</label> </label>
)} )}
@@ -1285,7 +1301,7 @@ const ImprovedTaskFilters: React.FC<ImprovedTaskFiltersProps> = ({ position, cla
} }
}} }}
className={`ml-1 rounded-full p-0.5 transition-colors duration-150 ${ className={`ml-1 rounded-full p-0.5 transition-colors duration-150 ${
isDarkMode ? 'hover:bg-blue-800' : 'hover:bg-blue-200' isDarkMode ? 'hover:bg-gray-800' : 'hover:bg-gray-200'
}`} }`}
> >
<CloseOutlined className="w-2.5 h-2.5" /> <CloseOutlined className="w-2.5 h-2.5" />