Блоки кода как в Telegram: мессенджер-пузыри + редактор

- MdParser::code_block: Telegram-пузырь (bg #f5f5f7/#212121, header #e8e8ea/#2a2a2a, border-radius 12, shadow), lang badge uppercase, copy-кнопка '📋 Копировать' с hover/active (bg #ffffff/#333, border, radius 6, цвет #0088cc), JetBrains Mono 13px, line-height 1.5, tab-size 4
- EditorPanel TextArea: JetBrains Mono, tabStopDistance 32, авто-закрытие ()[]{}'"'<> (обёртка выделения, перепрыгивание), Tab→4 пробела / Shift+Tab снятие, Backspace удаление 4 пробелов как одного, Enter сохранение отступа (+4 для { [ ( : > и внутри скобок), тег-автозакрытие <div>→</div>, подсветка парной скобки (o ↔ m) с таймером 800мс
- Кнопка копирования: hover/active через inline style + toast 'Скопировано!', lastCopiedId
This commit is contained in:
2026-09-01 20:12:02 +03:00
parent afc15680e1
commit a24f782205
2 changed files with 265 additions and 14 deletions
+20 -12
View File
@@ -486,29 +486,37 @@ private:
m_impl->codeBlocks.insert(codeId, code);
}
// мессенджер-стиль: отдельный блок-рамка с закруглениями, без внешней границы, фон на весь блок
// Telegram-стиль: пузырь сообщения с кодом, как в мессенджере
QSettings s;
const bool isDark = s.value("ui/theme").toString() == "dark";
const QString bg = isDark ? "#2d333f" : "#f8f9fb";
const QString headerBg = isDark ? "#252a33" : "#eef1f3";
const QString headerText = isDark ? "#8b949e" : "#656d76";
// Telegram-like цвета: светлая — #f5f5f7, тёмная — #1a1a1a / #212121
const QString bg = isDark ? "#212121" : "#f5f5f7";
const QString headerBg = isDark ? "#2a2a2a" : "#e8e8ea";
const QString headerBorder = isDark ? "#333333" : "#d0d0d0";
const QString headerText = isDark ? "#8e8e93" : "#6d6d72";
const QString codeTextColor = isDark ? "#e0e0e0" : "#24292f";
const QString langDisplay = lang.isEmpty() ? "text" : esc(lang);
const QString cls = lang.isEmpty() ? QString() : QStringLiteral(" class=\"language-%1\"").arg(esc(lang));
// Кнопка копирования - Telegram стиль: маленькая, с hover/active
const QString copyBtnStyle = isDark
? "display:inline-block;background:#333333;color:#8e8e93;text-decoration:none;font-size:12px;padding:4px 10px;border-radius:6px;border:1px solid #404040;font-family: -apple-system, sans-serif;"
: "display:inline-block;background:#ffffff;color:#0088cc;text-decoration:none;font-size:12px;padding:4px 10px;border-radius:6px;border:1px solid #d0d0d0;font-family: -apple-system, sans-serif;";
const QString copyLink = codeId.isEmpty() ? QString()
: QStringLiteral("<a href=\"flora://copycode/%1\" style=\"color:#8b949e;text-decoration:none;font-size:14px\">📋</a>").arg(codeId);
: QStringLiteral("<a href=\"flora://copycode/%1\" style=\"%2\" title=\"Копировать\">📋 Копировать</a>").arg(codeId, copyBtnStyle);
// рамка как сообщение: фон на весь блок, закругления 12px, без бордера, overflow:hidden
// Пузырь как в Telegram: скругления 12px, тень, граница, header отделен
return QStringLiteral(
"<div style=\"background:%1;border-radius:12px;overflow:hidden;margin:16px 0\">"
"<div style=\"background:%2;padding:8px 14px\">"
"<div style=\"background:%1;border:1px solid %2;border-radius:12px;overflow:hidden;margin:16px 0;box-shadow:0 1px 2px rgba(0,0,0,0.08)\">"
"<div style=\"background:%3;padding:7px 12px;border-bottom:1px solid %2\">"
"<table width=\"100%\" cellspacing=\"0\" cellpadding=\"0\"><tr>"
"<td style=\"text-align:left;color:%3;font-size:11px\">%4</td>"
"<td style=\"text-align:right\">%5</td>"
"<td style=\"text-align:left;color:%4;font-size:11px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;\">%5</td>"
"<td style=\"text-align:right\">%6</td>"
"</tr></table>"
"</div>"
"<div style=\"background:%1;padding:14px\"><pre style=\"margin:0\"><code%7>%6</code></pre></div>"
"<div style=\"background:%1;padding:12px 14px;overflow-x:auto\"><pre style=\"margin:0;font-family:'JetBrains Mono','Fira Code','Menlo','Consolas',monospace;font-size:13px;line-height:1.5;tab-size:4;color:%7;white-space:pre-wrap;word-wrap:break-word\">"
"<code%9>%8</code></pre></div>"
"</div>"
).arg(bg, headerBg, headerText, langDisplay, copyLink, highlighted, cls);
).arg(bg, headerBorder, headerBg, headerText, langDisplay, copyLink, codeTextColor, highlighted, cls);
}
QString inlineAll(cmark_node *n)