Обновлены стили для компонента спойлеров, улучшена анимация и добавлены новые визуальные эффекты. Обновлен файл service worker с новой версией для кэширования. Оптимизирована логика рендеринга токенов в markdown, улучшена обработка вложенных элементов и ссылок.

This commit is contained in:
Fovway 2025-11-05 05:24:07 +07:00
parent e3b98ea8d3
commit 30f9daaec8
3 changed files with 74 additions and 61 deletions

View File

@ -82,7 +82,7 @@ define(['./workbox-9dc17825'], (function (workbox) { 'use strict';
"revision": "3ca0b8505b4bec776b69afdba2768812" "revision": "3ca0b8505b4bec776b69afdba2768812"
}, { }, {
"url": "index.html", "url": "index.html",
"revision": "0.nsn25edhihg" "revision": "0.b1jpidvaji"
}], {}); }], {});
workbox.cleanupOutdatedCaches(); workbox.cleanupOutdatedCaches();
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), { workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {

View File

@ -671,7 +671,8 @@ header {
/* Анимация пульсации для offline индикатора */ /* Анимация пульсации для offline индикатора */
@keyframes pulse { @keyframes pulse {
0%, 100% { 0%,
100% {
opacity: 1; opacity: 1;
transform: scale(1); transform: scale(1);
} }
@ -4409,7 +4410,7 @@ textarea:focus {
/* Стили для скрытого текста (спойлеров) */ /* Стили для скрытого текста (спойлеров) */
.spoiler { .spoiler {
background: linear-gradient(45deg, #f0f0f0, #e8e8e8); background: linear-gradient(45deg, rgba(var(--accent-color-rgb), 0.15), rgba(var(--accent-color-rgb), 0.25));
color: transparent; color: transparent;
cursor: pointer; cursor: pointer;
border-radius: 4px; border-radius: 4px;
@ -4417,11 +4418,15 @@ textarea:focus {
user-select: none; user-select: none;
transition: all 0.3s ease; transition: all 0.3s ease;
position: relative; position: relative;
border: 1px solid #ddd; display: inline-block;
vertical-align: baseline;
border: 1px solid rgba(var(--accent-color-rgb), 0.3);
font-weight: 500; font-weight: 500;
backdrop-filter: blur(2px); backdrop-filter: blur(2px);
-webkit-backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px);
text-shadow: 0 0 8px rgba(0, 0, 0, 0.3); text-shadow: 0 0 8px rgba(var(--accent-color-rgb), 0.3);
isolation: isolate;
z-index: 0;
} }
.spoiler::before { .spoiler::before {
@ -4431,27 +4436,30 @@ textarea:focus {
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
background: rgba(255, 255, 255, 0.8); background: rgba(var(--accent-color-rgb), 0.1);
border-radius: 4px; border-radius: 4px;
filter: blur(1px); filter: blur(1px);
z-index: -1; z-index: -1;
box-sizing: border-box;
pointer-events: none;
} }
.spoiler:hover { .spoiler:hover {
background: linear-gradient(45deg, #e8e8e8, #d8d8d8); background: linear-gradient(45deg, rgba(var(--accent-color-rgb), 0.25), rgba(var(--accent-color-rgb), 0.35));
transform: scale(1.02); transform: scale(1.02);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); box-shadow: 0 2px 8px rgba(var(--accent-color-rgb), 0.25);
border-color: rgba(var(--accent-color-rgb), 0.4);
} }
.spoiler:hover::before { .spoiler:hover::before {
background: rgba(255, 255, 255, 0.9); background: rgba(var(--accent-color-rgb), 0.15);
} }
.spoiler.revealed { .spoiler.revealed {
background: linear-gradient(45deg, #e8f5e8, #d4edda); background: linear-gradient(45deg, rgba(var(--accent-color-rgb), 0.15), rgba(var(--accent-color-rgb), 0.2));
color: #155724; color: var(--accent-color);
border-color: #c3e6cb; border-color: rgba(var(--accent-color-rgb), 0.4);
box-shadow: 0 0 0 2px rgba(40, 167, 69, 0.25); box-shadow: 0 0 0 2px rgba(var(--accent-color-rgb), 0.25);
text-shadow: none; text-shadow: none;
user-select: text; user-select: text;
-webkit-user-select: text; -webkit-user-select: text;
@ -4463,8 +4471,8 @@ textarea:focus {
} }
.spoiler.revealed:hover { .spoiler.revealed:hover {
background: linear-gradient(45deg, #d4edda, #c3e6cb); background: linear-gradient(45deg, rgba(var(--accent-color-rgb), 0.2), rgba(var(--accent-color-rgb), 0.25));
box-shadow: 0 0 0 2px rgba(40, 167, 69, 0.35); box-shadow: 0 0 0 2px rgba(var(--accent-color-rgb), 0.35);
} }
/* Стили для файлов */ /* Стили для файлов */

View File

@ -25,49 +25,54 @@ const spoilerExtension = {
// Функция для рендеринга вложенных токенов // Функция для рендеринга вложенных токенов
function renderTokens(tokens: any[], renderer: any): string { function renderTokens(tokens: any[], renderer: any): string {
return tokens.map((token) => { return tokens
// Используем кастомный renderer если он есть .map((token) => {
if (renderer[token.type]) { // Используем кастомный renderer если он есть
return renderer[token.type](token); if (renderer[token.type]) {
} return renderer[token.type](token);
// Fallback для встроенных типов токенов
if (token.type === 'text') {
return token.text || '';
}
if (token.type === 'strong') {
return `<strong>${renderTokens(token.tokens || [], renderer)}</strong>`;
}
if (token.type === 'em') {
return `<em>${renderTokens(token.tokens || [], renderer)}</em>`;
}
if (token.type === 'codespan') {
return `<code>${token.text || ''}</code>`;
}
if (token.type === 'del') {
return `<del>${renderTokens(token.tokens || [], renderer)}</del>`;
}
if (token.type === 'link') {
// Для ссылок используем кастомный renderer если доступен
if (renderer.link) {
return renderer.link(token);
} }
// Fallback для встроенных ссылок // Fallback для встроенных типов токенов
const href = token.href || ''; if (token.type === "text") {
const title = token.title ? ` title="${token.title}"` : ''; return token.text || "";
const text = token.tokens && token.tokens.length > 0
? renderTokens(token.tokens, renderer)
: (token.text || '');
return `<a href="${href}"${title}>${text}</a>`;
}
if (token.type === 'spoiler') {
// Для спойлеров используем кастомный renderer если доступен
if (renderer.spoiler) {
return renderer.spoiler(token);
} }
return `<span class="spoiler" title="Нажмите, чтобы показать">${token.text || ''}</span>`; if (token.type === "strong") {
} return `<strong>${renderTokens(token.tokens || [], renderer)}</strong>`;
return token.text || ''; }
}).join(''); if (token.type === "em") {
return `<em>${renderTokens(token.tokens || [], renderer)}</em>`;
}
if (token.type === "codespan") {
return `<code>${token.text || ""}</code>`;
}
if (token.type === "del") {
return `<del>${renderTokens(token.tokens || [], renderer)}</del>`;
}
if (token.type === "link") {
// Для ссылок используем кастомный renderer если доступен
if (renderer.link) {
return renderer.link(token);
}
// Fallback для встроенных ссылок
const href = token.href || "";
const title = token.title ? ` title="${token.title}"` : "";
const text =
token.tokens && token.tokens.length > 0
? renderTokens(token.tokens, renderer)
: token.text || "";
return `<a href="${href}"${title}>${text}</a>`;
}
if (token.type === "spoiler") {
// Для спойлеров используем кастомный renderer если доступен
if (renderer.spoiler) {
return renderer.spoiler(token);
}
return `<span class="spoiler" title="Нажмите, чтобы показать">${
token.text || ""
}</span>`;
}
return token.text || "";
})
.join("");
} }
// Кастомный renderer для внешних ссылок и чекбоксов // Кастомный renderer для внешних ссылок и чекбоксов
@ -75,9 +80,9 @@ const renderer: any = {
link(token: any) { link(token: any) {
const href = token.href; const href = token.href;
const title = token.title; const title = token.title;
// Правильно обрабатываем вложенные токены для форматирования внутри ссылок // Правильно обрабатываем вложенные токены для форматирования внутри ссылок
let text = ''; let text = "";
if (token.tokens && token.tokens.length > 0) { if (token.tokens && token.tokens.length > 0) {
text = renderTokens(token.tokens, this); text = renderTokens(token.tokens, this);
} else if (token.text) { } else if (token.text) {
@ -101,9 +106,9 @@ const renderer: any = {
listitem(token: any) { listitem(token: any) {
const task = token.task; const task = token.task;
const checked = token.checked; const checked = token.checked;
// Правильно обрабатываем вложенные токены для форматирования // Правильно обрабатываем вложенные токены для форматирования
let content = ''; let content = "";
if (token.tokens && token.tokens.length > 0) { if (token.tokens && token.tokens.length > 0) {
// Рендерим вложенные токены используя наш renderer // Рендерим вложенные токены используя наш renderer
content = renderTokens(token.tokens, this); content = renderTokens(token.tokens, this);
@ -174,7 +179,7 @@ export const extractTags = (content: string): string[] => {
const tag = match[1]; const tag = match[1];
// Проверяем, есть ли уже тег с таким же именем (регистронезависимо) // Проверяем, есть ли уже тег с таким же именем (регистронезависимо)
if (!tags.some(t => t.toLowerCase() === tag.toLowerCase())) { if (!tags.some((t) => t.toLowerCase() === tag.toLowerCase())) {
tags.push(tag); tags.push(tag);
} }
} }