Блоки кода как в Telegram (скрин): тёмно-синий пузырь #3b5a7a, время и галочки
- Bubble: background #3b5a7a (как на скрине #2e4d6a), radius 12, padding 10/14/6, max-width 88%, shadow, язык uppercase #8a9ba8 10px слева, кнопка 📋 справа (rgba 0.15, radius 12, border 0.2)
- Код: контейнер rgba(0,0,0,0.18) radius 8, padding 10/12, JetBrains Mono 13px/1.45/tab-size 4, color #fff, подсветка форсирована тёмной темой (highlight(...,true) -> Breeze Dark)
- Время: QTime::currentTime hh:mm + ✓✓ #5eb1f6 внизу справа, как в сообщении ТГ (20:31 ✓✓)
- Сохранено автовыравнивание/скобки/отступы из предыдущего коммита (Tab 4 пробела, Enter сохраняет indent, Backspace удаляет 4, авто-закрытие ()[]{}''""<> и </tag>)
This commit is contained in:
+33
-32
@@ -23,6 +23,7 @@
|
||||
#include <QGuiApplication>
|
||||
#include <QImageReader>
|
||||
#include <QSettings>
|
||||
#include <QTime>
|
||||
#include <QUrl>
|
||||
|
||||
using KSyntaxHighlighting::AbstractHighlighter;
|
||||
@@ -194,7 +195,7 @@ public:
|
||||
m_segments.append(seg);
|
||||
}
|
||||
|
||||
QString highlight(const QString &code, const QString &lang)
|
||||
QString highlight(const QString &code, const QString &lang, bool forceDark = false)
|
||||
{
|
||||
m_segments.clear();
|
||||
Definition def = m_repo->definitionForName(lang);
|
||||
@@ -203,10 +204,11 @@ public:
|
||||
setDefinition(def);
|
||||
// Выбираем тему подсветки в зависимости от темы приложения (тёмная/светлая)
|
||||
Theme chosen = m_repo->defaultTheme();
|
||||
// Попытка получить тему из настроек (ui/theme)
|
||||
// Попытка получить тему из настроек (ui/theme) или форсировать тёмную для пузырей
|
||||
{
|
||||
QSettings s;
|
||||
if (s.value("ui/theme").toString() == "dark") {
|
||||
bool wantDark = forceDark || s.value("ui/theme").toString() == "dark";
|
||||
if (wantDark) {
|
||||
for (auto t : m_repo->themes()) {
|
||||
if (t.name().contains("dark", Qt::CaseInsensitive) || t.name().contains("Dark")) {
|
||||
chosen = t;
|
||||
@@ -476,47 +478,46 @@ private:
|
||||
const char *info = cmark_node_get_fence_info(n);
|
||||
const QString lang = normalizeLang(QString::fromUtf8(info ? info : ""));
|
||||
const QString code = QString::fromUtf8(cmark_node_get_literal(n));
|
||||
CodeHighlighter hl(m_repo);
|
||||
const QString highlighted = hl.highlight(code, lang);
|
||||
|
||||
// сохраняем оригинал для копирования
|
||||
// Telegram-стиль как на скрине: тёмно-синий пузырь (#2e4d6a) с кодом, время и галочки внизу справа
|
||||
// Сохраняем оригинал для копирования
|
||||
QString codeId;
|
||||
if (m_impl) {
|
||||
codeId = QStringLiteral("code_%1").arg(m_impl->codeCounter++);
|
||||
m_impl->codeBlocks.insert(codeId, code);
|
||||
}
|
||||
|
||||
// Telegram-стиль: пузырь сообщения с кодом, как в мессенджере
|
||||
QSettings s;
|
||||
const bool isDark = s.value("ui/theme").toString() == "dark";
|
||||
// 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";
|
||||
// Форсируем тёмную тему подсветки для контраста на синем фоне Telegram-пузыря
|
||||
CodeHighlighter hl(m_repo);
|
||||
const QString highlighted = hl.highlight(code, lang, true);
|
||||
// Переопределяем lang после highlight (highlight уже сделал)
|
||||
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=\"%2\" title=\"Копировать\">📋 Копировать</a>").arg(codeId, copyBtnStyle);
|
||||
|
||||
// Пузырь как в Telegram: скругления 12px, тень, граница, header отделен
|
||||
// Время как в Telegram — текущее время рендера (можно заменить на lastModified)
|
||||
const QString timeStr = QTime::currentTime().toString("hh:mm");
|
||||
// Telegram bubble: #3a5068 или #2e4d6a, скругления 12, тень, max-width 85%
|
||||
const QString bubbleBg = "#3b5a7a"; // тёмно-синий как на скрине #2e4d6a → #3b5a7a чуть светлее
|
||||
const QString codeColor = "#ffffff";
|
||||
// Кнопка копирования — в правом верхнем углу пузыря, как в ТГ при наведении
|
||||
// Делаем её заметной: полупрозрачная, скруглённая, с hover/active через CSS
|
||||
const QString copyLink = codeId.isEmpty() ? QString()
|
||||
: QStringLiteral("<a href=\"flora://copycode/%1\" style=\"display:inline-block;background:rgba(255,255,255,0.15);color:#ffffff;text-decoration:none;font-size:12px;padding:3px 8px;border-radius:12px;border:1px solid rgba(255,255,255,0.2);font-family:-apple-system,sans-serif;\" title=\"Копировать\">📋</a>").arg(codeId);
|
||||
|
||||
// Пузырь Telegram: используем таблицу для совместимости с QTextDocument (не поддерживает position:absolute)
|
||||
// Верхняя строка — язык слева и кнопка справа, средняя — код, нижняя — время и галочки справа
|
||||
return QStringLiteral(
|
||||
"<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:%4;font-size:11px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;\">%5</td>"
|
||||
"<td style=\"text-align:right\">%6</td>"
|
||||
"<div style=\"background:%1;border-radius:12px;padding:10px 14px 6px 14px;margin:12px 0;max-width:88%%;box-shadow:0 1px 2px rgba(0,0,0,0.15)\">"
|
||||
"<table width=\"100%%\" cellspacing=\"0\" cellpadding=\"0\" style=\"margin-bottom:6px\">"
|
||||
"<tr>"
|
||||
"<td style=\"text-align:left;color:#8a9ba8;font-size:10px;font-weight:600;letter-spacing:0.4px;text-transform:uppercase;opacity:0.9\">%2</td>"
|
||||
"<td style=\"text-align:right\">%3</td>"
|
||||
"</tr></table>"
|
||||
"<div style=\"background:rgba(0,0,0,0.18);border-radius:8px;padding:10px 12px;margin:6px 0 8px 0\">"
|
||||
"<pre style=\"margin:0;font-family:'JetBrains Mono','Fira Code','Menlo',Consolas,monospace;font-size:13px;line-height:1.45;tab-size:4;color:%4;white-space:pre-wrap;word-wrap:break-word\">"
|
||||
"<code%6>%5</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 style=\"text-align:right;color:#8a9ba8;font-size:11px;margin-top:2px;opacity:0.95\">%7 <span style=\"color:#5eb1f6\">✓✓</span></div>"
|
||||
"</div>"
|
||||
).arg(bg, headerBorder, headerBg, headerText, langDisplay, copyLink, codeTextColor, highlighted, cls);
|
||||
).arg(bubbleBg, langDisplay, copyLink, codeColor, highlighted, cls, timeStr);
|
||||
}
|
||||
|
||||
QString inlineAll(cmark_node *n)
|
||||
|
||||
Reference in New Issue
Block a user