PathLogs UI
Русский

Components

Markdown

Limited markup with no dependencies and no raw HTML.

Limited Markdown for text that users write: task descriptions, comments, notes. No dependencies and no raw HTML.

Example

Что сделано

Переписали разбор входящих заявок: теперь они попадают сразу в колонку проекта, а не в общий список.

  • проверка домена отправителя
  • склейка дублей по теме письма
  • X-Request-Id в каждом ответе

Осталось решить, что делать с письмами без темы.

Подробности — в описании задачи.

What is supported

md
# Heading           (levels 1–3)
**bold** *italic* ~~strikethrough~~ `code`

- bulleted list
1. numbered list

> a quote

---

[a link](https://example.com)

```ts
a code block
```

Heading levels stop at three, and the heading itself renders as a paragraph in a large face: user text has no business interfering with the page's heading structure or breaking its layout.

Safety

<script>alert(1)</script> — остаётся текстом.

[Опасная ссылка](javascript:alert(1)) — ссылкой не становится.

Обычная ссылка — становится.

Images are deliberately absent: they let someone pull a reader's IP to a third-party server, and they break list layout.

Mentions

A list of known names highlights @mentions in the text:

tsx
<Markdown text={comment.body} mentions={project.members.map((m) => m.name)} />

Names are sorted from longest to shortest: otherwise «@John» would swallow the start of «@John Smith», and the mention would fall apart into a highlight plus a tail of text. Special characters in names are escaped — a name with a dot does not become «any character».

The parser, separately

text*string

The source text.

mentionsstring[]

Names to highlight as @mentions.

classNamestring

Extra classes for the container.

The grammar is available without React too — for a table of contents or search:

tsx
import { parseBlocks, parseInline, parseInlineWithMentions } from "@toimetdev/pathlogs-core";

parseBlocks("# Heading\n\ntext");
// [{ kind: "h", level: 1, text: "Heading" }, { kind: "p", lines: ["text"] }]

parseInline("**bold**");
// [{ kind: "strong", children: [{ kind: "text", text: "bold" }] }]