w-funnel/src/components/ui/MarkupText/MarkupText.tsx
gofnnp 90126bbf3b special-offer
add special offer page
2025-10-10 19:57:46 +04:00

104 lines
3.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React from "react";
import { parseTextMarkup, hasTextMarkup, type TextMarkupSegment } from "@/lib/text-markup";
import { cn } from "@/lib/utils";
interface MarkupTextProps {
children: string;
className?: string;
as?: keyof React.JSX.IntrinsicElements;
boldClassName?: string;
strikeClassName?: string;
}
/**
* Компонент для рендеринга текста с разметкой **bold** и ~~strike~~
*
* Примеры использования:
* <MarkupText>Добро пожаловать в **WitLab**!</MarkupText>
* <MarkupText as="h1">**50%** скидка только сегодня</MarkupText>
* <MarkupText boldClassName="text-primary">Ваш **идеальный партнер** найден!</MarkupText>
*/
export function MarkupText({
children,
className,
as: Component = "span",
boldClassName = "font-bold",
strikeClassName = "line-through"
}: MarkupTextProps) {
// Если текста нет, возвращаем пустой элемент
if (!children || typeof children !== 'string') {
return React.createElement(Component as string, { className }, children);
}
// Если нет разметки, возвращаем обычный текст
if (!hasTextMarkup(children)) {
return React.createElement(Component as string, { className }, children);
}
// Парсим разметку и рендерим сегменты
const segments = parseTextMarkup(children);
return React.createElement(
Component as string,
{ className },
segments.map((segment: TextMarkupSegment, index: number) => {
if (segment.type === 'bold') {
return React.createElement(
'strong',
{
key: index,
className: cn(boldClassName)
},
segment.content
);
}
if (segment.type === 'strike') {
return React.createElement(
'span',
{
key: index,
className: cn(strikeClassName)
},
segment.content
);
}
return React.createElement(
React.Fragment,
{ key: index },
segment.content
);
})
);
}
/**
* Хук для проверки наличия разметки в тексте
*/
export function useHasMarkup(text: string): boolean {
return React.useMemo(() => hasTextMarkup(text), [text]);
}
/**
* Компонент для превью разметки в админке
*/
export function MarkupPreview({ text }: { text: string }) {
return (
<div className="space-y-2">
<div className="text-xs font-medium text-muted-foreground">
Превью:
</div>
<div className="p-3 bg-muted/30 rounded-lg border">
<MarkupText className="text-sm">
{text}
</MarkupText>
</div>
{hasTextMarkup(text) && (
<div className="text-xs text-blue-600 bg-blue-50 border border-blue-200 rounded p-2">
💡 <strong>Разметка обнаружена:</strong> Текст в **двойных звездочках** жирный, в ~~двойных тильдах~~ зачёркнутый.
</div>
)}
</div>
);
}