112 lines
3.5 KiB
TypeScript
112 lines
3.5 KiB
TypeScript
import { useNavigate } from 'react-router-dom';
|
||
import { cn } from '../../../lib/cn';
|
||
import { useAppSelector } from '../../../redux/hooks';
|
||
|
||
export interface ArticleItemProps {
|
||
id: number;
|
||
name: string;
|
||
tags: string[];
|
||
}
|
||
|
||
const ArticleItem: React.FC<ArticleItemProps> = ({ id, name, tags }) => {
|
||
const navigate = useNavigate();
|
||
|
||
const filterTags = useAppSelector(
|
||
(state) => state.store.articles.articleTagFilter,
|
||
);
|
||
const nameFilter = useAppSelector(
|
||
(state) => state.store.articles.filterName,
|
||
);
|
||
|
||
const highlightZ = (name: string, filter: string) => {
|
||
if (!filter) return name;
|
||
|
||
const s = filter.toLowerCase();
|
||
const t = name.toLowerCase();
|
||
const n = t.length;
|
||
const m = s.length;
|
||
|
||
const mark = Array(n).fill(false);
|
||
|
||
// Проходимся с конца и ставим отметки
|
||
for (let i = n - 1; i >= 0; i--) {
|
||
if (i + m <= n && t.slice(i, i + m) === s) {
|
||
for (let j = i; j < i + m; j++) {
|
||
if (mark[j]) break;
|
||
mark[j] = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
// === Формируем единые жёлтые блоки ===
|
||
const result: any[] = [];
|
||
let i = 0;
|
||
|
||
while (i < n) {
|
||
if (!mark[i]) {
|
||
// обычный символ
|
||
result.push(name[i]);
|
||
i++;
|
||
} else {
|
||
// начинаем жёлтый блок
|
||
let j = i;
|
||
while (j < n && mark[j]) j++;
|
||
|
||
const chunk = name.slice(i, j);
|
||
result.push(
|
||
<span
|
||
key={i}
|
||
className="bg-yellow-400 text-black rounded px-1"
|
||
>
|
||
{chunk}
|
||
</span>,
|
||
);
|
||
|
||
i = j;
|
||
}
|
||
}
|
||
|
||
return result;
|
||
};
|
||
|
||
return (
|
||
<div
|
||
className={cn(
|
||
'w-full relative rounded-[10px] text-liquid-white mb-[20px]',
|
||
// type == "first" ? "bg-liquid-lighter" : "bg-liquid-background",
|
||
'gap-[20px] px-[20px] py-[10px] box-border ',
|
||
'border-b-[1px] border-b-liquid-lighter cursor-pointer hover:bg-liquid-lighter transition-all duration-300',
|
||
)}
|
||
onClick={() => {
|
||
navigate(`/article/${id}`);
|
||
}}
|
||
>
|
||
<div className="h-[23px] flex ">
|
||
<div className="text-[18px] font-bold w-[60px] mr-[20px] flex items-center">
|
||
#{id}
|
||
</div>
|
||
<div className="text-[18px] font-bold flex items-center bg-red-400r">
|
||
{highlightZ(name, nameFilter)}
|
||
</div>
|
||
</div>
|
||
<div className="text-[14px] flex text-liquid-light gap-[10px] mt-[10px]">
|
||
{tags.map((v, i) => (
|
||
<div
|
||
key={i}
|
||
className={cn(
|
||
'rounded-full px-[16px] py-[8px] bg-liquid-lighter',
|
||
v == 'Sertificated' && 'text-liquid-green',
|
||
filterTags.includes(v) &&
|
||
'border-liquid-brightmain border-[1px] border-solid text-liquid-brightmain',
|
||
)}
|
||
>
|
||
{v}
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default ArticleItem;
|