diff --git a/backend/server.js b/backend/server.js index b93897a..e174b1e 100644 --- a/backend/server.js +++ b/backend/server.js @@ -502,6 +502,28 @@ function runMigrations() { ); } + // Проверяем существование колонки floating_toolbar_enabled + const hasFloatingToolbarEnabled = columns.some( + (col) => col.name === "floating_toolbar_enabled" + ); + if (!hasFloatingToolbarEnabled) { + db.run( + "ALTER TABLE users ADD COLUMN floating_toolbar_enabled INTEGER DEFAULT 1", + (err) => { + if (err) { + console.error( + "Ошибка добавления колонки floating_toolbar_enabled:", + err.message + ); + } else { + console.log( + "Колонка floating_toolbar_enabled добавлена в таблицу users" + ); + } + } + ); + } + // Проверяем существование колонки ai_enabled const hasAiEnabled = columns.some((col) => col.name === "ai_enabled"); if (!hasAiEnabled) { @@ -771,7 +793,7 @@ app.get("/api/user", requireApiAuth, (req, res) => { } const sql = - "SELECT username, email, avatar, accent_color, show_edit_date, colored_icons FROM users WHERE id = ?"; + "SELECT username, email, avatar, accent_color, show_edit_date, colored_icons, floating_toolbar_enabled FROM users WHERE id = ?"; db.get(sql, [req.session.userId], (err, user) => { if (err) { console.error("Ошибка получения данных пользователя:", err.message); @@ -1600,6 +1622,7 @@ app.put("/api/user/profile", requireApiAuth, async (req, res) => { accent_color, show_edit_date, colored_icons, + floating_toolbar_enabled, } = req.body; const userId = req.session.userId; @@ -1675,6 +1698,11 @@ app.put("/api/user/profile", requireApiAuth, async (req, res) => { params.push(colored_icons ? 1 : 0); } + if (floating_toolbar_enabled !== undefined) { + updateFields.push("floating_toolbar_enabled = ?"); + params.push(floating_toolbar_enabled ? 1 : 0); + } + if (newPassword) { const hashedPassword = await bcrypt.hash(newPassword, 10); updateFields.push("password = ?"); diff --git a/dev-dist/sw.js b/dev-dist/sw.js index 1a0abe6..79f7624 100644 --- a/dev-dist/sw.js +++ b/dev-dist/sw.js @@ -82,7 +82,7 @@ define(['./workbox-9dc17825'], (function (workbox) { 'use strict'; "revision": "3ca0b8505b4bec776b69afdba2768812" }, { "url": "index.html", - "revision": "0.b944c6vblpo" + "revision": "0.2vg2p27g3bg" }], {}); workbox.cleanupOutdatedCaches(); workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), { diff --git a/src/api/userApi.ts b/src/api/userApi.ts index 3655742..d940cc1 100644 --- a/src/api/userApi.ts +++ b/src/api/userApi.ts @@ -14,6 +14,7 @@ export const userApi = { accent_color?: string; show_edit_date?: boolean; colored_icons?: boolean; + floating_toolbar_enabled?: boolean; } ) => { const { data } = await axiosClient.put("/user/profile", profile); diff --git a/src/components/notes/NoteEditor.tsx b/src/components/notes/NoteEditor.tsx index bd8b398..a397e77 100644 --- a/src/components/notes/NoteEditor.tsx +++ b/src/components/notes/NoteEditor.tsx @@ -4,7 +4,7 @@ import { FloatingToolbar } from "./FloatingToolbar"; import { NotePreview } from "./NotePreview"; import { ImageUpload } from "./ImageUpload"; import { FileUpload } from "./FileUpload"; -import { useAppSelector, useAppDispatch } from "../../store/hooks"; +import { useAppSelector } from "../../store/hooks"; import { useNotification } from "../../hooks/useNotification"; import { offlineNotesApi } from "../../api/offlineNotesApi"; import { aiApi } from "../../api/aiApi"; @@ -31,7 +31,13 @@ export const NoteEditor: React.FC = ({ onSave }) => { const isPreviewMode = useAppSelector((state) => state.ui.isPreviewMode); const { showNotification } = useNotification(); const aiEnabled = useAppSelector((state) => state.profile.aiEnabled); - const dispatch = useAppDispatch(); + const user = useAppSelector((state) => state.profile.user); + + // Проверяем, включена ли плавающая панель + const floatingToolbarEnabled = + user?.floating_toolbar_enabled !== undefined + ? user.floating_toolbar_enabled === 1 + : true; const handleSave = async () => { if (!content.trim()) { @@ -684,7 +690,7 @@ export const NoteEditor: React.FC = ({ onSave }) => { // Обработчик выделения текста const handleSelection = useCallback(() => { - if (isPreviewMode) { + if (isPreviewMode || !floatingToolbarEnabled) { setShowFloatingToolbar(false); return; } @@ -709,7 +715,13 @@ export const NoteEditor: React.FC = ({ onSave }) => { setHasSelection(false); setActiveFormats({ bold: false, italic: false, strikethrough: false }); } - }, [isPreviewMode, content, getCursorPosition, getActiveFormats]); + }, [ + isPreviewMode, + content, + getCursorPosition, + getActiveFormats, + floatingToolbarEnabled, + ]); // Отслеживание выделения текста useEffect(() => { @@ -955,16 +967,18 @@ export const NoteEditor: React.FC = ({ onSave }) => { } }} /> - setShowFloatingToolbar(false)} - onInsertColor={insertColorMarkdown} - activeFormats={activeFormats} - hasSelection={hasSelection} - /> + {floatingToolbarEnabled && ( + setShowFloatingToolbar(false)} + onInsertColor={insertColorMarkdown} + activeFormats={activeFormats} + hasSelection={hasSelection} + /> + )} )} diff --git a/src/components/notes/NoteItem.tsx b/src/components/notes/NoteItem.tsx index 4311ae7..bae83ff 100644 --- a/src/components/notes/NoteItem.tsx +++ b/src/components/notes/NoteItem.tsx @@ -67,6 +67,12 @@ export const NoteItem: React.FC = ({ const { showNotification } = useNotification(); const dispatch = useAppDispatch(); useMarkdown({ onNoteUpdate: onReload }); // Инициализируем обработчики спойлеров, внешних ссылок и чекбоксов + + // Проверяем, включена ли плавающая панель + const floatingToolbarEnabled = + user?.floating_toolbar_enabled !== undefined + ? user.floating_toolbar_enabled === 1 + : true; const handleEdit = () => { setIsEditing(true); @@ -594,7 +600,7 @@ export const NoteItem: React.FC = ({ // Обработчик выделения текста const handleSelection = useCallback(() => { - if (localPreviewMode) { + if (localPreviewMode || !floatingToolbarEnabled) { setShowFloatingToolbar(false); return; } @@ -619,7 +625,7 @@ export const NoteItem: React.FC = ({ setHasSelection(false); setActiveFormats({ bold: false, italic: false, strikethrough: false }); } - }, [localPreviewMode, editContent, getCursorPosition, getActiveFormats]); + }, [localPreviewMode, editContent, getCursorPosition, getActiveFormats, floatingToolbarEnabled]); const handleImageButtonClick = () => { imageInputRef.current?.click(); @@ -1221,16 +1227,18 @@ export const NoteItem: React.FC = ({ } }} /> - setShowFloatingToolbar(false)} - onInsertColor={insertColorMarkdown} - activeFormats={activeFormats} - hasSelection={hasSelection} - /> + {floatingToolbarEnabled && ( + setShowFloatingToolbar(false)} + onInsertColor={insertColorMarkdown} + activeFormats={activeFormats} + hasSelection={hasSelection} + /> + )} )} diff --git a/src/pages/SettingsPage.tsx b/src/pages/SettingsPage.tsx index 157b8f2..48a0cda 100644 --- a/src/pages/SettingsPage.tsx +++ b/src/pages/SettingsPage.tsx @@ -46,6 +46,7 @@ const SettingsPage: React.FC = () => { const [selectedAccentColor, setSelectedAccentColor] = useState("#007bff"); const [showEditDate, setShowEditDate] = useState(true); const [coloredIcons, setColoredIcons] = useState(true); + const [floatingToolbarEnabled, setFloatingToolbarEnabled] = useState(true); // AI settings const [apiKey, setApiKey] = useState(""); @@ -134,6 +135,11 @@ const SettingsPage: React.FC = () => { : true; setColoredIcons(coloredIconsValue); updateColoredIconsClass(coloredIconsValue); + const floatingToolbarValue = + userData.floating_toolbar_enabled !== undefined + ? userData.floating_toolbar_enabled === 1 + : true; + setFloatingToolbarEnabled(floatingToolbarValue); // Загружаем AI настройки try { @@ -166,6 +172,7 @@ const SettingsPage: React.FC = () => { accent_color: selectedAccentColor, show_edit_date: showEditDate, colored_icons: coloredIcons, + floating_toolbar_enabled: floatingToolbarEnabled, }); dispatch(setAccentColorAction(selectedAccentColor)); setAccentColor(selectedAccentColor); @@ -672,6 +679,31 @@ const SettingsPage: React.FC = () => { +
+ +
+ diff --git a/src/types/user.ts b/src/types/user.ts index 8033656..bf9ee53 100644 --- a/src/types/user.ts +++ b/src/types/user.ts @@ -5,6 +5,7 @@ export interface User { accent_color: string; show_edit_date?: number; colored_icons?: number; + floating_toolbar_enabled?: number; } export interface AuthResponse {