Обновление сборки и исходного кода

This commit is contained in:
root 2025-11-16 14:51:59 +07:00
parent 7d115e1845
commit 14b9165681
32 changed files with 2000 additions and 1234 deletions

View File

@ -19,7 +19,9 @@
"body-parser": "^2.2.0", "body-parser": "^2.2.0",
"codemirror": "^6.0.2", "codemirror": "^6.0.2",
"connect-sqlite3": "^0.9.16", "connect-sqlite3": "^0.9.16",
"cookie-parser": "^1.4.7",
"cors": "^2.8.5", "cors": "^2.8.5",
"csurf": "^1.11.0",
"dotenv": "^17.2.3", "dotenv": "^17.2.3",
"express": "^5.1.0", "express": "^5.1.0",
"express-rate-limit": "^8.1.0", "express-rate-limit": "^8.1.0",
@ -1713,6 +1715,25 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/cookie-parser": {
"version": "1.4.7",
"resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz",
"integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==",
"license": "MIT",
"dependencies": {
"cookie": "0.7.2",
"cookie-signature": "1.0.6"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/cookie-parser/node_modules/cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
"license": "MIT"
},
"node_modules/cookie-signature": { "node_modules/cookie-signature": {
"version": "1.2.2", "version": "1.2.2",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
@ -1738,6 +1759,100 @@
"resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
"integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==" "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g=="
}, },
"node_modules/csrf": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/csrf/-/csrf-3.1.0.tgz",
"integrity": "sha512-uTqEnCvWRk042asU6JtapDTcJeeailFy4ydOQS28bj1hcLnYRiqi8SsD2jS412AY1I/4qdOwWZun774iqywf9w==",
"license": "MIT",
"dependencies": {
"rndm": "1.2.0",
"tsscmp": "1.0.6",
"uid-safe": "2.1.5"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/csurf": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/csurf/-/csurf-1.11.0.tgz",
"integrity": "sha512-UCtehyEExKTxgiu8UHdGvHj4tnpE/Qctue03Giq5gPgMQ9cg/ciod5blZQ5a4uCEenNQjxyGuzygLdKUmee/bQ==",
"deprecated": "This package is archived and no longer maintained. For support, visit https://github.com/expressjs/express/discussions",
"license": "MIT",
"dependencies": {
"cookie": "0.4.0",
"cookie-signature": "1.0.6",
"csrf": "3.1.0",
"http-errors": "~1.7.3"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/csurf/node_modules/cookie": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
"integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/csurf/node_modules/cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
"license": "MIT"
},
"node_modules/csurf/node_modules/depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
"integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/csurf/node_modules/http-errors": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz",
"integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==",
"license": "MIT",
"dependencies": {
"depd": "~1.1.2",
"inherits": "2.0.4",
"setprototypeof": "1.1.1",
"statuses": ">= 1.5.0 < 2",
"toidentifier": "1.0.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/csurf/node_modules/setprototypeof": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
"integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==",
"license": "ISC"
},
"node_modules/csurf/node_modules/statuses": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
"integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/csurf/node_modules/toidentifier": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
"license": "MIT",
"engines": {
"node": ">=0.6"
}
},
"node_modules/data-uri-to-buffer": { "node_modules/data-uri-to-buffer": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
@ -1947,6 +2062,7 @@
"version": "5.1.0", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz",
"integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
"peer": true,
"dependencies": { "dependencies": {
"accepts": "^2.0.0", "accepts": "^2.0.0",
"body-parser": "^2.2.0", "body-parser": "^2.2.0",
@ -3437,6 +3553,12 @@
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/rndm": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/rndm/-/rndm-1.2.0.tgz",
"integrity": "sha512-fJhQQI5tLrQvYIYFpOnFinzv9dwmR7hRnUz1XqP3OJ1jIweTNOd6aTO4jwQSgcBSFUB+/KHJxuGneime+FdzOw==",
"license": "MIT"
},
"node_modules/router": { "node_modules/router": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
@ -3952,6 +4074,15 @@
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"node_modules/tsscmp": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz",
"integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==",
"license": "MIT",
"engines": {
"node": ">=0.6.x"
}
},
"node_modules/tunnel-agent": { "node_modules/tunnel-agent": {
"version": "0.6.0", "version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",

View File

@ -25,7 +25,9 @@
"body-parser": "^2.2.0", "body-parser": "^2.2.0",
"codemirror": "^6.0.2", "codemirror": "^6.0.2",
"connect-sqlite3": "^0.9.16", "connect-sqlite3": "^0.9.16",
"cookie-parser": "^1.4.7",
"cors": "^2.8.5", "cors": "^2.8.5",
"csurf": "^1.11.0",
"dotenv": "^17.2.3", "dotenv": "^17.2.3",
"express": "^5.1.0", "express": "^5.1.0",
"express-rate-limit": "^8.1.0", "express-rate-limit": "^8.1.0",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,69 +1,69 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="ru"> <html lang="ru">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta <meta
name="viewport" name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
/> />
<title>NoteJS - Система заметок</title> <title>NoteJS - Система заметок</title>
<!-- Предотвращение мерцания темы --> <!-- Предотвращение мерцания темы -->
<script> <script>
(function () { (function () {
try { try {
// Получаем сохраненную тему // Получаем сохраненную тему
const savedTheme = localStorage.getItem("theme"); const savedTheme = localStorage.getItem("theme");
// Получаем системные предпочтения // Получаем системные предпочтения
const systemPrefersDark = window.matchMedia( const systemPrefersDark = window.matchMedia(
"(prefers-color-scheme: dark)" "(prefers-color-scheme: dark)"
).matches; ).matches;
// Определяем тему: сохраненная или системная // Определяем тему: сохраненная или системная
const theme = savedTheme || (systemPrefersDark ? "dark" : "light"); const theme = savedTheme || (systemPrefersDark ? "dark" : "light");
// Функция для конвертации hex в RGB // Функция для конвертации hex в RGB
function hexToRgb(hex) { function hexToRgb(hex) {
const cleanHex = hex.replace("#", ""); const cleanHex = hex.replace("#", "");
const r = parseInt(cleanHex.substring(0, 2), 16); const r = parseInt(cleanHex.substring(0, 2), 16);
const g = parseInt(cleanHex.substring(2, 4), 16); const g = parseInt(cleanHex.substring(2, 4), 16);
const b = parseInt(cleanHex.substring(4, 6), 16); const b = parseInt(cleanHex.substring(4, 6), 16);
return `${r}, ${g}, ${b}`; return `${r}, ${g}, ${b}`;
} }
// Получаем и устанавливаем accentColor // Получаем и устанавливаем accentColor
const savedAccentColor = localStorage.getItem("accentColor"); const savedAccentColor = localStorage.getItem("accentColor");
const accentColor = savedAccentColor || "#007bff"; const accentColor = savedAccentColor || "#007bff";
// Устанавливаем тему и переменные до загрузки CSS // Устанавливаем тему и переменные до загрузки CSS
if (theme === "dark") { if (theme === "dark") {
document.documentElement.setAttribute("data-theme", "dark"); document.documentElement.setAttribute("data-theme", "dark");
} else { } else {
document.documentElement.setAttribute("data-theme", "light"); document.documentElement.setAttribute("data-theme", "light");
} }
// Устанавливаем CSS переменные для accent цвета // Устанавливаем CSS переменные для accent цвета
document.documentElement.style.setProperty("--accent-color", accentColor); document.documentElement.style.setProperty("--accent-color", accentColor);
document.documentElement.style.setProperty("--accent-color-rgb", hexToRgb(accentColor)); document.documentElement.style.setProperty("--accent-color-rgb", hexToRgb(accentColor));
// Устанавливаем цвет для meta theme-color // Устанавливаем цвет для meta theme-color
const themeColorMeta = document.querySelector('meta[name="theme-color"]'); const themeColorMeta = document.querySelector('meta[name="theme-color"]');
if (themeColorMeta) { if (themeColorMeta) {
themeColorMeta.setAttribute( themeColorMeta.setAttribute(
"content", "content",
theme === "dark" ? "#1a1a1a" : accentColor theme === "dark" ? "#1a1a1a" : accentColor
); );
} }
} catch (e) { } catch (e) {
// В случае ошибки устанавливаем светлую тему по умолчанию // В случае ошибки устанавливаем светлую тему по умолчанию
document.documentElement.setAttribute("data-theme", "light"); document.documentElement.setAttribute("data-theme", "light");
document.documentElement.style.setProperty("--accent-color", "#007bff"); document.documentElement.style.setProperty("--accent-color", "#007bff");
document.documentElement.style.setProperty("--accent-color-rgb", "0, 123, 255"); document.documentElement.style.setProperty("--accent-color-rgb", "0, 123, 255");
} }
})(); })();
</script> </script>
<!-- Критические стили темы для предотвращения flash эффекта --> <!-- Критические стили темы для предотвращения flash эффекта -->
<style> <style>
:root { :root {
--accent-color: #007bff; --accent-color: #007bff;
@ -89,94 +89,94 @@
color: var(--text-primary); color: var(--text-primary);
transition: background-color 0.3s ease, color 0.3s ease; transition: background-color 0.3s ease, color 0.3s ease;
} }
</style> </style>
<!-- PWA Meta Tags --> <!-- PWA Meta Tags -->
<meta <meta
name="description" name="description"
content="NoteJS - современная система заметок с поддержкой Markdown, изображений, тегов и календаря" content="NoteJS - современная система заметок с поддержкой Markdown, изображений, тегов и календаря"
/> />
<meta name="theme-color" content="#007bff" /> <meta name="theme-color" content="#007bff" />
<meta name="mobile-web-app-capable" content="yes" /> <meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-capable" content="yes" /> <meta name="apple-mobile-web-app-capable" content="yes" />
<meta <meta
name="apple-mobile-web-app-status-bar-style" name="apple-mobile-web-app-status-bar-style"
content="black-translucent" content="black-translucent"
/> />
<meta name="apple-mobile-web-app-title" content="NoteJS" /> <meta name="apple-mobile-web-app-title" content="NoteJS" />
<meta name="apple-touch-fullscreen" content="yes" /> <meta name="apple-touch-fullscreen" content="yes" />
<meta name="msapplication-TileColor" content="#007bff" /> <meta name="msapplication-TileColor" content="#007bff" />
<meta name="msapplication-config" content="/browserconfig.xml" /> <meta name="msapplication-config" content="/browserconfig.xml" />
<meta name="msapplication-TileImage" content="/icons/icon-144x144.png" /> <meta name="msapplication-TileImage" content="/icons/icon-144x144.png" />
<meta name="application-name" content="NoteJS" /> <meta name="application-name" content="NoteJS" />
<meta name="format-detection" content="telephone=no" /> <meta name="format-detection" content="telephone=no" />
<!-- Icons --> <!-- Icons -->
<link rel="icon" type="image/svg+xml" href="/icon.svg" /> <link rel="icon" type="image/svg+xml" href="/icon.svg" />
<link <link
rel="icon" rel="icon"
type="image/png" type="image/png"
sizes="32x32" sizes="32x32"
href="/icons/icon-32x32.png" href="/icons/icon-32x32.png"
/> />
<link <link
rel="icon" rel="icon"
type="image/png" type="image/png"
sizes="16x16" sizes="16x16"
href="/icons/icon-16x16.png" href="/icons/icon-16x16.png"
/> />
<link rel="apple-touch-icon" sizes="57x57" href="/icons/icon-48x48.png" /> <link rel="apple-touch-icon" sizes="57x57" href="/icons/icon-48x48.png" />
<link rel="apple-touch-icon" sizes="60x60" href="/icons/icon-48x48.png" /> <link rel="apple-touch-icon" sizes="60x60" href="/icons/icon-48x48.png" />
<link rel="apple-touch-icon" sizes="72x72" href="/icons/icon-72x72.png" /> <link rel="apple-touch-icon" sizes="72x72" href="/icons/icon-72x72.png" />
<link rel="apple-touch-icon" sizes="76x76" href="/icons/icon-72x72.png" /> <link rel="apple-touch-icon" sizes="76x76" href="/icons/icon-72x72.png" />
<link <link
rel="apple-touch-icon" rel="apple-touch-icon"
sizes="114x114" sizes="114x114"
href="/icons/icon-128x128.png" href="/icons/icon-128x128.png"
/> />
<link <link
rel="apple-touch-icon" rel="apple-touch-icon"
sizes="120x120" sizes="120x120"
href="/icons/icon-128x128.png" href="/icons/icon-128x128.png"
/> />
<link <link
rel="apple-touch-icon" rel="apple-touch-icon"
sizes="144x144" sizes="144x144"
href="/icons/icon-144x144.png" href="/icons/icon-144x144.png"
/> />
<link <link
rel="apple-touch-icon" rel="apple-touch-icon"
sizes="152x152" sizes="152x152"
href="/icons/icon-152x152.png" href="/icons/icon-152x152.png"
/> />
<link <link
rel="apple-touch-icon" rel="apple-touch-icon"
sizes="180x180" sizes="180x180"
href="/icons/icon-192x192.png" href="/icons/icon-192x192.png"
/> />
<link rel="mask-icon" href="/icon.svg" color="#007bff" /> <link rel="mask-icon" href="/icon.svg" color="#007bff" />
<!-- Manifest --> <!-- Manifest -->
<link rel="manifest" href="/manifest.json" /> <link rel="manifest" href="/manifest.json" />
<script type="module" crossorigin src="/assets/index-BLHAueVj.js"></script> <script type="module" crossorigin src="/assets/index-BeJxT3YH.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-PWucW8RD.css"> <link rel="stylesheet" crossorigin href="/assets/index-By_GFjEF.css">
<link rel="manifest" href="/manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="/registerSW.js"></script></head> <link rel="manifest" href="/manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="/registerSW.js"></script></head>
<body> <body>
<div id="root"> <div id="root">
<!-- Индикатор загрузки до монтирования React --> <!-- Индикатор загрузки до монтирования React -->
<div id="initial-loading" style=" <div id="initial-loading" style="
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
background-color: var(--bg-primary); background-color: var(--bg-primary);
color: var(--text-primary); color: var(--text-primary);
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
z-index: 9999; z-index: 9999;
"> ">
<style> <style>
#initial-loading-spinner { #initial-loading-spinner {
width: 50px; width: 50px;
@ -193,43 +193,43 @@
@keyframes initial-loading-spin { @keyframes initial-loading-spin {
to { transform: rotate(360deg); } to { transform: rotate(360deg); }
} }
</style> </style>
<div id="initial-loading-spinner"></div> <div id="initial-loading-spinner"></div>
</div> </div>
</div> </div>
<script> <script>
// Скрываем индикатор загрузки сразу после загрузки DOM // Скрываем индикатор загрузки сразу после загрузки DOM
// React удалит этот элемент при первом рендере через createRoot // React удалит этот элемент при первом рендере через createRoot
(function() { (function() {
// Используем MutationObserver для отслеживания изменений в #root // Используем MutationObserver для отслеживания изменений в #root
const observer = new MutationObserver(function(mutations) { const observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) { mutations.forEach(function(mutation) {
// Если React начал добавлять элементы в #root, удаляем индикатор // Если React начал добавлять элементы в #root, удаляем индикатор
if (mutation.addedNodes.length > 0) { if (mutation.addedNodes.length > 0) {
const loadingEl = document.getElementById('initial-loading'); const loadingEl = document.getElementById('initial-loading');
if (loadingEl && loadingEl.parentNode) { if (loadingEl && loadingEl.parentNode) {
loadingEl.parentNode.removeChild(loadingEl); loadingEl.parentNode.removeChild(loadingEl);
} }
observer.disconnect(); observer.disconnect();
} }
}); });
}); });
// Начинаем наблюдение за изменениями в #root // Начинаем наблюдение за изменениями в #root
const root = document.getElementById('root'); const root = document.getElementById('root');
if (root) { if (root) {
observer.observe(root, { childList: true, subtree: true }); observer.observe(root, { childList: true, subtree: true });
// Фолбэк: если через 2 секунды элемент все еще есть, удаляем вручную // Фолбэк: если через 2 секунды элемент все еще есть, удаляем вручную
setTimeout(function() { setTimeout(function() {
const loadingEl = document.getElementById('initial-loading'); const loadingEl = document.getElementById('initial-loading');
if (loadingEl && loadingEl.parentNode) { if (loadingEl && loadingEl.parentNode) {
loadingEl.parentNode.removeChild(loadingEl); loadingEl.parentNode.removeChild(loadingEl);
} }
observer.disconnect(); observer.disconnect();
}, 2000); }, 2000);
} }
})(); })();
</script> </script>
</body> </body>
</html> </html>

View File

@ -1 +1 @@
if(!self.define){let e,n={};const i=(i,c)=>(i=new URL(i+".js",c).href,n[i]||new Promise(n=>{if("document"in self){const e=document.createElement("script");e.src=i,e.onload=n,document.head.appendChild(e)}else e=i,importScripts(i),n()}).then(()=>{let e=n[i];if(!e)throw new Error(`Module ${i} didnt register its module`);return e}));self.define=(c,s)=>{const o=e||("document"in self?document.currentScript.src:"")||location.href;if(n[o])return;let a={};const r=e=>i(e,o),d={module:{uri:o},exports:a,require:r};n[o]=Promise.all(c.map(e=>d[e]||r(e))).then(e=>(s(...e),a))}}define(["./workbox-40c80ae4"],function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"assets/index-BLHAueVj.js",revision:"a554119eeb8e2517fbf5b56f3056f821"},{url:"assets/index-PWucW8RD.css",revision:"d9c0b2036bfdcfb70738c2c7fc47cd92"},{url:"icon.svg",revision:"537ae73d8f9e90e6a01816aa6d527d16"},{url:"icons/icon-128x128.png",revision:"fa71db17e345406d5f7d847f88c65ac4"},{url:"icons/icon-144x144.png",revision:"e790ff42758ea1a2a46eb84201630757"},{url:"icons/icon-152x152.png",revision:"88f2400f6617a32cc9cd62c70fb49a05"},{url:"icons/icon-16x16.png",revision:"101c13808e9fd0956f247bc446a8ac1e"},{url:"icons/icon-192x192.png",revision:"7d86d2d2ada99d7cee015dff0fdcb497"},{url:"icons/icon-32x32.png",revision:"22ee5d42535bc339ab0e19cb496378a5"},{url:"icons/icon-384x384.png",revision:"c601fa602952a903389e5e8f8a699617"},{url:"icons/icon-48x48.png",revision:"cfdd3bebd931375f2e0277d638ec8781"},{url:"icons/icon-512x512.png",revision:"8731edef999b9e7deba310d72a739925"},{url:"icons/icon-72x72.png",revision:"6b3cb1b2537ec91921698260a9c2f47c"},{url:"icons/icon-96x96.png",revision:"7efd757a81217207d981de88ef199d86"},{url:"index.html",revision:"9a7779e0b82393809d2b49570f7f35a0"},{url:"logo.svg",revision:"11616ede8898b4c24203e331b3ec6dc3"},{url:"registerSW.js",revision:"1872c500de691dce40960bb85481de07"},{url:"icon.svg",revision:"537ae73d8f9e90e6a01816aa6d527d16"},{url:"icons/icon-192x192.png",revision:"7d86d2d2ada99d7cee015dff0fdcb497"},{url:"icons/icon-512x512.png",revision:"8731edef999b9e7deba310d72a739925"},{url:"icons/icon-72x72.png",revision:"6b3cb1b2537ec91921698260a9c2f47c"},{url:"icons/icon-96x96.png",revision:"7efd757a81217207d981de88ef199d86"},{url:"icons/icon-128x128.png",revision:"fa71db17e345406d5f7d847f88c65ac4"},{url:"icons/icon-144x144.png",revision:"e790ff42758ea1a2a46eb84201630757"},{url:"icons/icon-152x152.png",revision:"88f2400f6617a32cc9cd62c70fb49a05"},{url:"icons/icon-384x384.png",revision:"c601fa602952a903389e5e8f8a699617"},{url:"manifest.webmanifest",revision:"1c071cadebd7a1b0dc1eeb0270e73fb8"}],{ignoreURLParametersMatching:[/^utm_/,/^fbclid$/]}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("/index.html"),{denylist:[/^\/api/,/^\/uploads/]})),e.registerRoute(({request:e})=>"navigate"===e.mode,new e.CacheFirst({cacheName:"pages-cache",plugins:[new e.ExpirationPlugin({maxEntries:10,maxAgeSeconds:604800}),new e.CacheableResponsePlugin({statuses:[0,200]})]}),"GET"),e.registerRoute(/\.html$/,new e.CacheFirst({cacheName:"html-cache",plugins:[new e.ExpirationPlugin({maxEntries:10,maxAgeSeconds:604800}),new e.CacheableResponsePlugin({statuses:[0,200]})]}),"GET"),e.registerRoute(/^https:\/\/api\./,new e.NetworkFirst({cacheName:"api-cache",plugins:[new e.ExpirationPlugin({maxEntries:50,maxAgeSeconds:3600})]}),"GET"),e.registerRoute(/\/api\//,new e.NetworkFirst({cacheName:"api-cache-local",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:100,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/uploads\//,new e.CacheFirst({cacheName:"uploads-cache",plugins:[new e.ExpirationPlugin({maxEntries:200,maxAgeSeconds:2592e3})]}),"GET"),e.registerRoute(/\.(?:png|jpg|jpeg|svg|gif|webp)$/,new e.CacheFirst({cacheName:"images-cache",plugins:[new e.ExpirationPlugin({maxEntries:100,maxAgeSeconds:2592e3})]}),"GET")}); if(!self.define){let e,n={};const i=(i,c)=>(i=new URL(i+".js",c).href,n[i]||new Promise(n=>{if("document"in self){const e=document.createElement("script");e.src=i,e.onload=n,document.head.appendChild(e)}else e=i,importScripts(i),n()}).then(()=>{let e=n[i];if(!e)throw new Error(`Module ${i} didnt register its module`);return e}));self.define=(c,s)=>{const a=e||("document"in self?document.currentScript.src:"")||location.href;if(n[a])return;let o={};const d=e=>i(e,a),r={module:{uri:a},exports:o,require:d};n[a]=Promise.all(c.map(e=>r[e]||d(e))).then(e=>(s(...e),o))}}define(["./workbox-40c80ae4"],function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"assets/index-BeJxT3YH.js",revision:"f4507ca84a94231fa281c54bfb94d3fc"},{url:"assets/index-By_GFjEF.css",revision:"1d226b81e7336346ecda1ed5c10970a1"},{url:"icon.svg",revision:"0ec61aab261526d4c491e887a6f3374e"},{url:"icons/icon-128x128.png",revision:"fa71db17e345406d5f7d847f88c65ac4"},{url:"icons/icon-144x144.png",revision:"e790ff42758ea1a2a46eb84201630757"},{url:"icons/icon-152x152.png",revision:"88f2400f6617a32cc9cd62c70fb49a05"},{url:"icons/icon-16x16.png",revision:"101c13808e9fd0956f247bc446a8ac1e"},{url:"icons/icon-192x192.png",revision:"7d86d2d2ada99d7cee015dff0fdcb497"},{url:"icons/icon-32x32.png",revision:"22ee5d42535bc339ab0e19cb496378a5"},{url:"icons/icon-384x384.png",revision:"c601fa602952a903389e5e8f8a699617"},{url:"icons/icon-48x48.png",revision:"cfdd3bebd931375f2e0277d638ec8781"},{url:"icons/icon-512x512.png",revision:"8731edef999b9e7deba310d72a739925"},{url:"icons/icon-72x72.png",revision:"6b3cb1b2537ec91921698260a9c2f47c"},{url:"icons/icon-96x96.png",revision:"7efd757a81217207d981de88ef199d86"},{url:"index.html",revision:"375addd678296759444d1a44942d49aa"},{url:"logo.svg",revision:"5962d0d24d9cd26cd8aaff9cb6f54a5a"},{url:"registerSW.js",revision:"1872c500de691dce40960bb85481de07"},{url:"icon.svg",revision:"0ec61aab261526d4c491e887a6f3374e"},{url:"icons/icon-192x192.png",revision:"7d86d2d2ada99d7cee015dff0fdcb497"},{url:"icons/icon-512x512.png",revision:"8731edef999b9e7deba310d72a739925"},{url:"icons/icon-72x72.png",revision:"6b3cb1b2537ec91921698260a9c2f47c"},{url:"icons/icon-96x96.png",revision:"7efd757a81217207d981de88ef199d86"},{url:"icons/icon-128x128.png",revision:"fa71db17e345406d5f7d847f88c65ac4"},{url:"icons/icon-144x144.png",revision:"e790ff42758ea1a2a46eb84201630757"},{url:"icons/icon-152x152.png",revision:"88f2400f6617a32cc9cd62c70fb49a05"},{url:"icons/icon-384x384.png",revision:"c601fa602952a903389e5e8f8a699617"},{url:"manifest.webmanifest",revision:"1c071cadebd7a1b0dc1eeb0270e73fb8"}],{ignoreURLParametersMatching:[/^utm_/,/^fbclid$/]}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("/index.html"),{denylist:[/^\/api/,/^\/uploads/]})),e.registerRoute(({request:e})=>"navigate"===e.mode,new e.CacheFirst({cacheName:"pages-cache",plugins:[new e.ExpirationPlugin({maxEntries:10,maxAgeSeconds:604800}),new e.CacheableResponsePlugin({statuses:[0,200]})]}),"GET"),e.registerRoute(/\.html$/,new e.CacheFirst({cacheName:"html-cache",plugins:[new e.ExpirationPlugin({maxEntries:10,maxAgeSeconds:604800}),new e.CacheableResponsePlugin({statuses:[0,200]})]}),"GET"),e.registerRoute(/^https:\/\/api\./,new e.NetworkFirst({cacheName:"api-cache",plugins:[new e.ExpirationPlugin({maxEntries:50,maxAgeSeconds:3600})]}),"GET"),e.registerRoute(/\/api\//,new e.NetworkFirst({cacheName:"api-cache-local",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:100,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/uploads\//,new e.CacheFirst({cacheName:"uploads-cache",plugins:[new e.ExpirationPlugin({maxEntries:200,maxAgeSeconds:2592e3})]}),"GET"),e.registerRoute(/\.(?:png|jpg|jpeg|svg|gif|webp)$/,new e.CacheFirst({cacheName:"images-cache",plugins:[new e.ExpirationPlugin({maxEntries:100,maxAgeSeconds:2592e3})]}),"GET")});

File diff suppressed because one or more lines are too long

18
package-lock.json generated
View File

@ -68,6 +68,7 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.27.1", "@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.5", "@babel/generator": "^7.28.5",
@ -2672,6 +2673,7 @@
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.26.tgz", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.26.tgz",
"integrity": "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==", "integrity": "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==",
"devOptional": true, "devOptional": true,
"peer": true,
"dependencies": { "dependencies": {
"@types/prop-types": "*", "@types/prop-types": "*",
"csstype": "^3.0.2" "csstype": "^3.0.2"
@ -2749,6 +2751,7 @@
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz",
"integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "6.21.0", "@typescript-eslint/scope-manager": "6.21.0",
"@typescript-eslint/types": "6.21.0", "@typescript-eslint/types": "6.21.0",
@ -2930,6 +2933,7 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true, "dev": true,
"peer": true,
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
}, },
@ -3195,6 +3199,7 @@
"url": "https://github.com/sponsors/ai" "url": "https://github.com/sponsors/ai"
} }
], ],
"peer": true,
"dependencies": { "dependencies": {
"baseline-browser-mapping": "^2.8.19", "baseline-browser-mapping": "^2.8.19",
"caniuse-lite": "^1.0.30001751", "caniuse-lite": "^1.0.30001751",
@ -3860,6 +3865,7 @@
"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1", "@eslint-community/regexpp": "^4.6.1",
@ -5743,6 +5749,7 @@
"version": "18.3.1", "version": "18.3.1",
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
"peer": true,
"dependencies": { "dependencies": {
"loose-envify": "^1.1.0" "loose-envify": "^1.1.0"
}, },
@ -5754,6 +5761,7 @@
"version": "18.3.1", "version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
"peer": true,
"dependencies": { "dependencies": {
"loose-envify": "^1.1.0", "loose-envify": "^1.1.0",
"scheduler": "^0.23.2" "scheduler": "^0.23.2"
@ -5766,6 +5774,7 @@
"version": "7.65.0", "version": "7.65.0",
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.65.0.tgz", "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.65.0.tgz",
"integrity": "sha512-xtOzDz063WcXvGWaHgLNrNzlsdFgtUWcb32E6WFaGTd7kPZG3EeDusjdZfUsPwKCKVXy1ZlntifaHZ4l8pAsmw==", "integrity": "sha512-xtOzDz063WcXvGWaHgLNrNzlsdFgtUWcb32E6WFaGTd7kPZG3EeDusjdZfUsPwKCKVXy1ZlntifaHZ4l8pAsmw==",
"peer": true,
"engines": { "engines": {
"node": ">=18.0.0" "node": ">=18.0.0"
}, },
@ -5781,6 +5790,7 @@
"version": "9.2.0", "version": "9.2.0",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
"integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
"peer": true,
"dependencies": { "dependencies": {
"@types/use-sync-external-store": "^0.0.6", "@types/use-sync-external-store": "^0.0.6",
"use-sync-external-store": "^1.4.0" "use-sync-external-store": "^1.4.0"
@ -5841,7 +5851,8 @@
"node_modules/redux": { "node_modules/redux": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
"peer": true
}, },
"node_modules/redux-thunk": { "node_modules/redux-thunk": {
"version": "3.1.0", "version": "3.1.0",
@ -6637,6 +6648,7 @@
"resolved": "https://registry.npmjs.org/terser/-/terser-5.44.0.tgz", "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.0.tgz",
"integrity": "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==", "integrity": "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"@jridgewell/source-map": "^0.3.3", "@jridgewell/source-map": "^0.3.3",
"acorn": "^8.15.0", "acorn": "^8.15.0",
@ -6807,6 +6819,7 @@
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true, "dev": true,
"peer": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
@ -6956,6 +6969,7 @@
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz",
"integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"esbuild": "^0.21.3", "esbuild": "^0.21.3",
"postcss": "^8.4.43", "postcss": "^8.4.43",
@ -7308,6 +7322,7 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"fast-deep-equal": "^3.1.3", "fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1", "fast-uri": "^3.0.1",
@ -7348,6 +7363,7 @@
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz",
"integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==",
"dev": true, "dev": true,
"peer": true,
"bin": { "bin": {
"rollup": "dist/bin/rollup" "rollup": "dist/bin/rollup"
}, },

View File

@ -143,14 +143,14 @@ export const GenerateTagsModal: React.FC<GenerateTagsModalProps> = ({
<button <button
className="btn-secondary" className="btn-secondary"
onClick={handleSelectAll} onClick={handleSelectAll}
style={{ fontSize: "12px", padding: "5px 10px", flex: "1 1 auto", minWidth: "100px" }} style={{ fontSize: "12px", padding: "5px 10px", flex: "1 1 auto", minWidth: "100px", textAlign: "center", justifyContent: "center" }}
> >
Выбрать все Выбрать все
</button> </button>
<button <button
className="btn-secondary" className="btn-secondary"
onClick={handleDeselectAll} onClick={handleDeselectAll}
style={{ fontSize: "12px", padding: "5px 10px", flex: "1 1 auto", minWidth: "100px" }} style={{ fontSize: "12px", padding: "5px 10px", flex: "1 1 auto", minWidth: "100px", textAlign: "center", justifyContent: "center" }}
> >
Снять все Снять все
</button> </button>

View File

@ -838,14 +838,15 @@ export const NoteEditor: React.FC<NoteEditorProps> = ({ onSave }) => {
// Предотвращаем появление контекстного меню браузера при выделении текста // Предотвращаем появление контекстного меню браузера при выделении текста
// Но разрешаем его, если редактор пустой (чтобы можно было вставить текст) // Но разрешаем его, если редактор пустой (чтобы можно было вставить текст)
// или если плавающая панель отключена
const handleContextMenu = (e: MouseEvent) => { const handleContextMenu = (e: MouseEvent) => {
const target = e.target as HTMLElement; const target = e.target as HTMLElement;
// Проверяем, что событие происходит в textarea // Проверяем, что событие происходит в textarea
if (target === textarea || textarea.contains(target)) { if (target === textarea || textarea.contains(target)) {
const hasText = textarea.value.trim().length > 0; const hasText = textarea.value.trim().length > 0;
const hasSelection = textarea.selectionStart !== textarea.selectionEnd; const hasSelection = textarea.selectionStart !== textarea.selectionEnd;
// Блокируем браузерное меню только если есть текст И есть выделение // Блокируем браузерное меню только если есть текст И есть выделение И плавающая панель включена
if (hasText && hasSelection) { if (floatingToolbarEnabled && hasText && hasSelection) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
} }
@ -1048,13 +1049,14 @@ export const NoteEditor: React.FC<NoteEditorProps> = ({ onSave }) => {
onContextMenu={(e) => { onContextMenu={(e) => {
// Предотвращаем появление контекстного меню браузера при выделении текста // Предотвращаем появление контекстного меню браузера при выделении текста
// Но разрешаем его, если редактор пустой (чтобы можно было вставить текст) // Но разрешаем его, если редактор пустой (чтобы можно было вставить текст)
// или если плавающая панель отключена
const textarea = textareaRef.current; const textarea = textareaRef.current;
if (textarea) { if (textarea) {
const hasText = textarea.value.trim().length > 0; const hasText = textarea.value.trim().length > 0;
const hasSelection = const hasSelection =
textarea.selectionStart !== textarea.selectionEnd; textarea.selectionStart !== textarea.selectionEnd;
// Блокируем браузерное меню только если есть текст И есть выделение // Блокируем браузерное меню только если есть текст И есть выделение И плавающая панель включена
if (hasText && hasSelection) { if (floatingToolbarEnabled && hasText && hasSelection) {
e.preventDefault(); e.preventDefault();
} }
} }

View File

@ -995,14 +995,15 @@ export const NoteItem: React.FC<NoteItemProps> = ({
// Предотвращаем появление контекстного меню браузера при выделении текста // Предотвращаем появление контекстного меню браузера при выделении текста
// Но разрешаем его, если редактор пустой (чтобы можно было вставить текст) // Но разрешаем его, если редактор пустой (чтобы можно было вставить текст)
// или если плавающая панель отключена
const handleContextMenu = (e: MouseEvent) => { const handleContextMenu = (e: MouseEvent) => {
const target = e.target as HTMLElement; const target = e.target as HTMLElement;
// Проверяем, что событие происходит в textarea // Проверяем, что событие происходит в textarea
if (target === textarea || textarea.contains(target)) { if (target === textarea || textarea.contains(target)) {
const hasText = textarea.value.trim().length > 0; const hasText = textarea.value.trim().length > 0;
const hasSelection = textarea.selectionStart !== textarea.selectionEnd; const hasSelection = textarea.selectionStart !== textarea.selectionEnd;
// Блокируем браузерное меню только если есть текст И есть выделение // Блокируем браузерное меню только если есть текст И есть выделение И плавающая панель включена
if (hasText && hasSelection) { if (floatingToolbarEnabled && hasText && hasSelection) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
} }
@ -1349,13 +1350,14 @@ export const NoteItem: React.FC<NoteItemProps> = ({
onContextMenu={(e) => { onContextMenu={(e) => {
// Предотвращаем появление контекстного меню браузера при выделении текста // Предотвращаем появление контекстного меню браузера при выделении текста
// Но разрешаем его, если редактор пустой (чтобы можно было вставить текст) // Но разрешаем его, если редактор пустой (чтобы можно было вставить текст)
// или если плавающая панель отключена
const textarea = editTextareaRef.current; const textarea = editTextareaRef.current;
if (textarea) { if (textarea) {
const hasText = textarea.value.trim().length > 0; const hasText = textarea.value.trim().length > 0;
const hasSelection = const hasSelection =
textarea.selectionStart !== textarea.selectionEnd; textarea.selectionStart !== textarea.selectionEnd;
// Блокируем браузерное меню только если есть текст И есть выделение // Блокируем браузерное меню только если есть текст И есть выделение И плавающая панель включена
if (hasText && hasSelection) { if (floatingToolbarEnabled && hasText && hasSelection) {
e.preventDefault(); e.preventDefault();
} }
} }

View File

@ -260,7 +260,7 @@ export const TwoFactorSetup: React.FC<TwoFactorSetupProps> = ({
className="btnSave" className="btnSave"
onClick={handleEnable} onClick={handleEnable}
disabled={isLoading || verificationCode.length !== 6} disabled={isLoading || verificationCode.length !== 6}
style={{ flex: "1 1 auto", minWidth: "120px" }} style={{ flex: "1 1 auto", minWidth: "120px", textAlign: "center", justifyContent: "center" }}
> >
{isLoading ? "Включение..." : "Включить 2FA"} {isLoading ? "Включение..." : "Включить 2FA"}
</button> </button>
@ -271,7 +271,7 @@ export const TwoFactorSetup: React.FC<TwoFactorSetupProps> = ({
setVerificationCode(""); setVerificationCode("");
}} }}
disabled={isLoading} disabled={isLoading}
style={{ flex: "1 1 auto", minWidth: "100px" }} style={{ flex: "1 1 auto", minWidth: "100px", textAlign: "center", justifyContent: "center" }}
> >
Отмена Отмена
</button> </button>
@ -312,7 +312,7 @@ export const TwoFactorSetup: React.FC<TwoFactorSetupProps> = ({
className="btnSave" className="btnSave"
onClick={handleGenerateBackupCodes} onClick={handleGenerateBackupCodes}
disabled={isGeneratingBackupCodes} disabled={isGeneratingBackupCodes}
style={{ flex: "1 1 auto", minWidth: "200px" }} style={{ flex: "1 1 auto", minWidth: "200px", textAlign: "center", justifyContent: "center" }}
> >
{isGeneratingBackupCodes ? ( {isGeneratingBackupCodes ? (
<> <>
@ -327,7 +327,7 @@ export const TwoFactorSetup: React.FC<TwoFactorSetupProps> = ({
<button <button
className="btn-danger" className="btn-danger"
onClick={() => setShowDisableModal(true)} onClick={() => setShowDisableModal(true)}
style={{ flex: "1 1 auto", minWidth: "140px" }} style={{ flex: "1 1 auto", minWidth: "140px", textAlign: "center", justifyContent: "center" }}
> >
<Icon icon="mdi:shield-off" /> Отключить 2FA <Icon icon="mdi:shield-off" /> Отключить 2FA
</button> </button>

View File

@ -277,7 +277,7 @@ const LoginPage: React.FC = () => {
type="submit" type="submit"
className="btnSave" className="btnSave"
disabled={isLoading || !twoFactorCode.trim()} disabled={isLoading || !twoFactorCode.trim()}
style={{ flex: "1 1 auto", minWidth: "120px" }} style={{ flex: "1 1 auto", minWidth: "120px", textAlign: "center", justifyContent: "center" }}
> >
{isLoading ? "Проверка..." : "Продолжить"} {isLoading ? "Проверка..." : "Продолжить"}
</button> </button>
@ -286,7 +286,7 @@ const LoginPage: React.FC = () => {
className="btn-danger" className="btn-danger"
onClick={handleBack} onClick={handleBack}
disabled={isLoading} disabled={isLoading}
style={{ flex: "1 1 auto", minWidth: "100px" }} style={{ flex: "1 1 auto", minWidth: "100px", textAlign: "center", justifyContent: "center" }}
> >
Назад Назад
</button> </button>

View File

@ -513,7 +513,7 @@ const ProfilePage: React.FC = () => {
<div <div
style={{ style={{
display: "flex", display: "flex",
alignItems: "center", flexDirection: "column",
gap: "10px", gap: "10px",
}} }}
> >
@ -522,13 +522,14 @@ const ProfilePage: React.FC = () => {
readOnly readOnly
value={publicProfileLink} value={publicProfileLink}
style={{ style={{
flex: 1,
padding: "8px", padding: "8px",
border: "1px solid var(--border-secondary, #ddd)", border: "1px solid var(--border-secondary, #ddd)",
borderRadius: "4px", borderRadius: "4px",
fontSize: "14px", fontSize: "14px",
backgroundColor: "var(--bg-secondary, #fff)", backgroundColor: "var(--bg-secondary, #fff)",
color: "var(--text-primary, #333)", color: "var(--text-primary, #333)",
width: "100%",
boxSizing: "border-box",
}} }}
/> />
<button <button
@ -537,6 +538,7 @@ const ProfilePage: React.FC = () => {
style={{ style={{
padding: "8px 15px", padding: "8px 15px",
whiteSpace: "nowrap", whiteSpace: "nowrap",
alignSelf: "center",
}} }}
> >
<Icon icon="mdi:content-copy" /> Копировать <Icon icon="mdi:content-copy" /> Копировать