Добавлен функционал для создания таблиц в компонент MarkdownToolbar. Реализованы модальные окна для ввода количества строк и столбцов, а также добавлены соответствующие стили для отображения таблиц в заметках. Обновлены обработчики событий для управления модальными окнами и валидации ввода. Улучшено взаимодействие с пользователем через фокусировку на полях ввода.
This commit is contained in:
parent
c4327d31d1
commit
9a1ee8629f
180
backend/public/assets/index-BLHAueVj.js
Normal file
180
backend/public/assets/index-BLHAueVj.js
Normal file
File diff suppressed because one or more lines are too long
19
backend/public/assets/index-PWucW8RD.css
Normal file
19
backend/public/assets/index-PWucW8RD.css
Normal file
File diff suppressed because one or more lines are too long
@ -158,8 +158,8 @@
|
||||
|
||||
<!-- Manifest -->
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<script type="module" crossorigin src="/assets/index-DgyuSC5D.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-caJGErnu.css">
|
||||
<script type="module" crossorigin src="/assets/index-BLHAueVj.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-PWucW8RD.css">
|
||||
<link rel="manifest" href="/manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="/registerSW.js"></script></head>
|
||||
<body>
|
||||
<div id="root">
|
||||
|
||||
@ -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} didn’t 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-caJGErnu.css",revision:"b5c1c05bdfd2d7b59a5d3e9caefed39e"},{url:"assets/index-DgyuSC5D.js",revision:"77a1bd3893cfacfb7a63395ad09f9145"},{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:"5609b5d50cef9e4061e094b7b8d3eb8f"},{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} didn’t 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")});
|
||||
|
||||
@ -82,7 +82,7 @@ define(['./workbox-47da91e0'], (function (workbox) { 'use strict';
|
||||
"revision": "3ca0b8505b4bec776b69afdba2768812"
|
||||
}, {
|
||||
"url": "/index.html",
|
||||
"revision": "0.dlpr89s9d7"
|
||||
"revision": "0.1kpib446v2o"
|
||||
}], {
|
||||
"ignoreURLParametersMatching": [/^utm_/, /^fbclid$/]
|
||||
});
|
||||
|
||||
@ -28,6 +28,10 @@ export const MarkdownToolbar: React.FC<MarkdownToolbarProps> = ({
|
||||
const [linkText, setLinkText] = useState("");
|
||||
const [linkUrl, setLinkUrl] = useState("");
|
||||
const linkTextInputRef = useRef<HTMLInputElement>(null);
|
||||
const [showTableModal, setShowTableModal] = useState(false);
|
||||
const [tableRows, setTableRows] = useState("2");
|
||||
const [tableCols, setTableCols] = useState("3");
|
||||
const tableRowsInputRef = useRef<HTMLInputElement>(null);
|
||||
const dispatch = useAppDispatch();
|
||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||
const buttonRef = useRef<HTMLButtonElement>(null);
|
||||
@ -140,6 +144,16 @@ export const MarkdownToolbar: React.FC<MarkdownToolbarProps> = ({
|
||||
}
|
||||
}, [showLinkModal]);
|
||||
|
||||
// Фокус на поле ввода строк при открытии модального окна таблицы
|
||||
useEffect(() => {
|
||||
if (showTableModal && tableRowsInputRef.current) {
|
||||
setTimeout(() => {
|
||||
tableRowsInputRef.current?.focus();
|
||||
tableRowsInputRef.current?.select();
|
||||
}, 100);
|
||||
}
|
||||
}, [showTableModal]);
|
||||
|
||||
// Обработка Escape для закрытия модального окна
|
||||
useEffect(() => {
|
||||
const handleEscape = (e: KeyboardEvent) => {
|
||||
@ -153,17 +167,22 @@ export const MarkdownToolbar: React.FC<MarkdownToolbarProps> = ({
|
||||
setLinkText("");
|
||||
setLinkUrl("");
|
||||
}
|
||||
if (showTableModal) {
|
||||
setShowTableModal(false);
|
||||
setTableRows("2");
|
||||
setTableCols("3");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (showCodeModal || showLinkModal) {
|
||||
if (showCodeModal || showLinkModal || showTableModal) {
|
||||
document.addEventListener("keydown", handleEscape);
|
||||
}
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("keydown", handleEscape);
|
||||
};
|
||||
}, [showCodeModal, showLinkModal]);
|
||||
}, [showCodeModal, showLinkModal, showTableModal]);
|
||||
|
||||
const handleCodeButtonClick = () => {
|
||||
setShowCodeModal(true);
|
||||
@ -234,6 +253,70 @@ export const MarkdownToolbar: React.FC<MarkdownToolbarProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
const handleTableButtonClick = () => {
|
||||
setShowTableModal(true);
|
||||
setTableRows("2");
|
||||
setTableCols("3");
|
||||
};
|
||||
|
||||
const generateTableMarkdown = (rows: number, cols: number): string => {
|
||||
// Генерируем заголовок
|
||||
const headerRow = "| " + Array(cols).fill("Заголовок").join(" | ") + " |\n";
|
||||
// Генерируем разделитель
|
||||
const separatorRow = "| " + Array(cols).fill("---").join(" | ") + " |\n";
|
||||
// Генерируем строки данных
|
||||
const dataRows = Array(rows)
|
||||
.fill("")
|
||||
.map(() => "| " + Array(cols).fill("Ячейка").join(" | ") + " |\n")
|
||||
.join("");
|
||||
|
||||
// Добавляем пустую строку перед таблицей для лучшей читаемости
|
||||
return "\n" + headerRow + separatorRow + dataRows;
|
||||
};
|
||||
|
||||
const handleTableModalConfirm = () => {
|
||||
const rows = parseInt(tableRows) || 2;
|
||||
const cols = parseInt(tableCols) || 3;
|
||||
|
||||
// Валидация: минимум 1, максимум 20 строк и 10 столбцов
|
||||
const validRows = Math.max(1, Math.min(20, rows));
|
||||
const validCols = Math.max(1, Math.min(10, cols));
|
||||
|
||||
const tableMarkdown = generateTableMarkdown(validRows, validCols);
|
||||
onInsert(tableMarkdown, "");
|
||||
|
||||
setShowTableModal(false);
|
||||
setTableRows("2");
|
||||
setTableCols("3");
|
||||
};
|
||||
|
||||
const handleTableModalClose = () => {
|
||||
setShowTableModal(false);
|
||||
setTableRows("2");
|
||||
setTableCols("3");
|
||||
};
|
||||
|
||||
const handleTableRowsKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
// Переход к полю столбцов
|
||||
const colsInput = document.querySelector(
|
||||
".table-modal-cols-input"
|
||||
) as HTMLInputElement;
|
||||
if (colsInput) {
|
||||
colsInput.focus();
|
||||
colsInput.select();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleTableColsKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
handleTableModalConfirm();
|
||||
}
|
||||
};
|
||||
|
||||
const buttons: Array<{
|
||||
id: string;
|
||||
icon: string;
|
||||
@ -401,6 +484,14 @@ export const MarkdownToolbar: React.FC<MarkdownToolbarProps> = ({
|
||||
<Icon icon="mdi:link" />
|
||||
</button>
|
||||
|
||||
<button
|
||||
className="btnMarkdown"
|
||||
onClick={handleTableButtonClick}
|
||||
title="Таблица"
|
||||
>
|
||||
<Icon icon="mdi:table" />
|
||||
</button>
|
||||
|
||||
<button
|
||||
className="btnMarkdown"
|
||||
onClick={() => onInsert("- [ ] ", "")}
|
||||
@ -539,6 +630,83 @@ export const MarkdownToolbar: React.FC<MarkdownToolbarProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Модальное окно для создания таблицы */}
|
||||
{showTableModal && (
|
||||
<div
|
||||
className="modal"
|
||||
style={{ display: "block" }}
|
||||
onClick={handleTableModalClose}
|
||||
>
|
||||
<div
|
||||
className="modal-content"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<div className="modal-header">
|
||||
<h3>Создать таблицу</h3>
|
||||
<span className="modal-close" onClick={handleTableModalClose}>
|
||||
×
|
||||
</span>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
<div style={{ marginBottom: "15px" }}>
|
||||
<label style={{ display: "block", marginBottom: "5px", fontWeight: "500" }}>
|
||||
Количество строк (1-20):
|
||||
</label>
|
||||
<input
|
||||
ref={tableRowsInputRef}
|
||||
type="number"
|
||||
className="modal-password-input"
|
||||
placeholder="2"
|
||||
min="1"
|
||||
max="20"
|
||||
value={tableRows}
|
||||
onChange={(e) => {
|
||||
const val = e.target.value;
|
||||
if (val === "" || (parseInt(val) >= 1 && parseInt(val) <= 20)) {
|
||||
setTableRows(val);
|
||||
}
|
||||
}}
|
||||
onKeyDown={handleTableRowsKeyDown}
|
||||
style={{ width: "100%" }}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label style={{ display: "block", marginBottom: "5px", fontWeight: "500" }}>
|
||||
Количество столбцов (1-10):
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
className="modal-password-input table-modal-cols-input"
|
||||
placeholder="3"
|
||||
min="1"
|
||||
max="10"
|
||||
value={tableCols}
|
||||
onChange={(e) => {
|
||||
const val = e.target.value;
|
||||
if (val === "" || (parseInt(val) >= 1 && parseInt(val) <= 10)) {
|
||||
setTableCols(val);
|
||||
}
|
||||
}}
|
||||
onKeyDown={handleTableColsKeyDown}
|
||||
style={{ width: "100%" }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="modal-footer">
|
||||
<button
|
||||
className="btn-primary"
|
||||
onClick={handleTableModalConfirm}
|
||||
>
|
||||
Вставить
|
||||
</button>
|
||||
<button className="btn-secondary" onClick={handleTableModalClose}>
|
||||
Отмена
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import React, { useState } from "react";
|
||||
import { Icon } from "@iconify/react";
|
||||
import { userApi } from "../../api/userApi";
|
||||
import { useNotification } from "../../hooks/useNotification";
|
||||
|
||||
@ -50,19 +50,19 @@ const LoginPage: React.FC = () => {
|
||||
const data = await authApi.login(username, password);
|
||||
console.log("Login response:", data);
|
||||
|
||||
if (data.success) {
|
||||
// Проверяем, требуется ли 2FA
|
||||
if (data.requires2FA) {
|
||||
setRequires2FA(true);
|
||||
showNotification("Введите код двухфакторной аутентификации", "info");
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
// Проверяем, требуется ли 2FA
|
||||
if (data.requires2FA) {
|
||||
setRequires2FA(true);
|
||||
showNotification("Введите код двухфакторной аутентификации", "info");
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Если 2FA не требуется, продолжаем как обычно
|
||||
// Если 2FA не требуется и аутентификация успешна, продолжаем как обычно
|
||||
if (data.authenticated) {
|
||||
await completeLogin();
|
||||
} else {
|
||||
showNotification(data.error || "Ошибка входа", "error");
|
||||
showNotification(data.message || "Ошибка входа", "error");
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error("Login error details:", error);
|
||||
|
||||
@ -1606,6 +1606,63 @@ textarea:focus {
|
||||
margin-left: -24px;
|
||||
}
|
||||
|
||||
/* Стили для таблиц в заметках */
|
||||
.textNote table {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 10px 0;
|
||||
background: var(--bg-secondary);
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 1px 3px var(--shadow-light);
|
||||
transition: background-color 0.3s ease, box-shadow 0.3s ease;
|
||||
table-layout: auto;
|
||||
}
|
||||
|
||||
.textNote th,
|
||||
.textNote td {
|
||||
padding: 8px 12px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid var(--border-primary);
|
||||
color: var(--text-primary);
|
||||
transition: color 0.3s ease, border-color 0.3s ease;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.textNote th {
|
||||
background: var(--bg-tertiary);
|
||||
font-weight: bold;
|
||||
color: var(--text-primary);
|
||||
transition: background-color 0.3s ease, color 0.3s ease;
|
||||
}
|
||||
|
||||
.textNote tr:hover {
|
||||
background: var(--bg-quaternary);
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
/* Стили для таблиц в темной теме */
|
||||
[data-theme="dark"] .textNote table {
|
||||
background: var(--bg-secondary);
|
||||
box-shadow: 0 1px 3px var(--shadow-light);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .textNote th {
|
||||
background: var(--bg-tertiary);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .textNote th,
|
||||
[data-theme="dark"] .textNote td {
|
||||
border-bottom-color: var(--border-primary);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .textNote tr:hover {
|
||||
background: var(--bg-quaternary);
|
||||
}
|
||||
|
||||
.notes-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
@ -3184,6 +3241,37 @@ textarea:focus {
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
/* Адаптация таблиц для мобильных устройств - обертка для горизонтальной прокрутки */
|
||||
.textNote table,
|
||||
.note-preview-content table {
|
||||
display: block;
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.textNote thead,
|
||||
.textNote tbody,
|
||||
.textNote tr,
|
||||
.note-preview-content thead,
|
||||
.note-preview-content tbody,
|
||||
.note-preview-content tr {
|
||||
display: table;
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.textNote th,
|
||||
.textNote td,
|
||||
.note-preview-content th,
|
||||
.note-preview-content td {
|
||||
min-width: 80px;
|
||||
white-space: normal;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
/* Адаптируем кнопку сохранения */
|
||||
.save-button-container {
|
||||
width: 100%;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user