Обновлены компоненты NoteEditor, NoteItem и NotesList для улучшения обработки сохранения заметок и добавления фокуса на сохраненные заметки. Изменены типы параметров функций и добавлена логика для плавного прокручивания к заметкам. Обновлен сервисный работник с новым ревизионным номером для кэширования.
This commit is contained in:
parent
06400d6e97
commit
05a9275253
@ -82,7 +82,7 @@ define(['./workbox-47da91e0'], (function (workbox) { 'use strict';
|
|||||||
"revision": "3ca0b8505b4bec776b69afdba2768812"
|
"revision": "3ca0b8505b4bec776b69afdba2768812"
|
||||||
}, {
|
}, {
|
||||||
"url": "/index.html",
|
"url": "/index.html",
|
||||||
"revision": "0.9eood2uf828"
|
"revision": "0.9t777mpmecg"
|
||||||
}], {
|
}], {
|
||||||
"ignoreURLParametersMatching": [/^utm_/, /^fbclid$/]
|
"ignoreURLParametersMatching": [/^utm_/, /^fbclid$/]
|
||||||
});
|
});
|
||||||
|
|||||||
@ -14,7 +14,7 @@ import { ImproveTextModal } from "./ImproveTextModal";
|
|||||||
import { extractTags } from "../../utils/markdown";
|
import { extractTags } from "../../utils/markdown";
|
||||||
|
|
||||||
interface NoteEditorProps {
|
interface NoteEditorProps {
|
||||||
onSave: () => void;
|
onSave: (noteId?: number | string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const NoteEditor: React.FC<NoteEditorProps> = ({ onSave }) => {
|
export const NoteEditor: React.FC<NoteEditorProps> = ({ onSave }) => {
|
||||||
@ -80,7 +80,7 @@ export const NoteEditor: React.FC<NoteEditorProps> = ({ onSave }) => {
|
|||||||
setContent("");
|
setContent("");
|
||||||
setImages([]);
|
setImages([]);
|
||||||
setFiles([]);
|
setFiles([]);
|
||||||
onSave();
|
onSave(note.id);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Ошибка сохранения заметки:", error);
|
console.error("Ошибка сохранения заметки:", error);
|
||||||
showNotification("Ошибка сохранения заметки", "error");
|
showNotification("Ошибка сохранения заметки", "error");
|
||||||
@ -106,7 +106,9 @@ export const NoteEditor: React.FC<NoteEditorProps> = ({ onSave }) => {
|
|||||||
console.error("Ошибка улучшения текста:", error);
|
console.error("Ошибка улучшения текста:", error);
|
||||||
setImproveError(true);
|
setImproveError(true);
|
||||||
setImproveErrorMessage(
|
setImproveErrorMessage(
|
||||||
error.response?.data?.error || error.message || "Ошибка улучшения текста"
|
error.response?.data?.error ||
|
||||||
|
error.message ||
|
||||||
|
"Ошибка улучшения текста"
|
||||||
);
|
);
|
||||||
} finally {
|
} finally {
|
||||||
setIsAiLoading(false);
|
setIsAiLoading(false);
|
||||||
@ -147,7 +149,10 @@ export const NoteEditor: React.FC<NoteEditorProps> = ({ onSave }) => {
|
|||||||
console.error("Детали ошибки:", error.response?.data);
|
console.error("Детали ошибки:", error.response?.data);
|
||||||
setTagsGenerationError(true);
|
setTagsGenerationError(true);
|
||||||
setShowTagsModal(false);
|
setShowTagsModal(false);
|
||||||
const errorMessage = error.response?.data?.error || error.message || "Ошибка генерации тегов";
|
const errorMessage =
|
||||||
|
error.response?.data?.error ||
|
||||||
|
error.message ||
|
||||||
|
"Ошибка генерации тегов";
|
||||||
showNotification(errorMessage, "error");
|
showNotification(errorMessage, "error");
|
||||||
} finally {
|
} finally {
|
||||||
setIsGeneratingTags(false);
|
setIsGeneratingTags(false);
|
||||||
@ -159,13 +164,19 @@ export const NoteEditor: React.FC<NoteEditorProps> = ({ onSave }) => {
|
|||||||
|
|
||||||
const existingTags = extractTags(content);
|
const existingTags = extractTags(content);
|
||||||
const tagsToAdd = tags
|
const tagsToAdd = tags
|
||||||
.filter((tag) => !existingTags.some((existing) => existing.toLowerCase() === tag.toLowerCase()))
|
.filter(
|
||||||
|
(tag) =>
|
||||||
|
!existingTags.some(
|
||||||
|
(existing) => existing.toLowerCase() === tag.toLowerCase()
|
||||||
|
)
|
||||||
|
)
|
||||||
.map((tag) => `#${tag}`)
|
.map((tag) => `#${tag}`)
|
||||||
.join(" ");
|
.join(" ");
|
||||||
|
|
||||||
if (tagsToAdd) {
|
if (tagsToAdd) {
|
||||||
// Добавляем теги в конец заметки
|
// Добавляем теги в конец заметки
|
||||||
const newContent = content.trim() + (content.trim() ? "\n\n" : "") + tagsToAdd;
|
const newContent =
|
||||||
|
content.trim() + (content.trim() ? "\n\n" : "") + tagsToAdd;
|
||||||
setContent(newContent);
|
setContent(newContent);
|
||||||
showNotification(`Добавлено тегов: ${tags.length}`, "success");
|
showNotification(`Добавлено тегов: ${tags.length}`, "success");
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -31,6 +31,7 @@ interface NoteItemProps {
|
|||||||
onReload: () => void;
|
onReload: () => void;
|
||||||
isSelected?: boolean;
|
isSelected?: boolean;
|
||||||
onSelect?: (id: number | string) => void;
|
onSelect?: (id: number | string) => void;
|
||||||
|
onFocusNote?: (id: number | string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const NoteItem: React.FC<NoteItemProps> = ({
|
export const NoteItem: React.FC<NoteItemProps> = ({
|
||||||
@ -41,6 +42,7 @@ export const NoteItem: React.FC<NoteItemProps> = ({
|
|||||||
onReload,
|
onReload,
|
||||||
isSelected = false,
|
isSelected = false,
|
||||||
onSelect,
|
onSelect,
|
||||||
|
onFocusNote,
|
||||||
}) => {
|
}) => {
|
||||||
const [isEditing, setIsEditing] = useState(false);
|
const [isEditing, setIsEditing] = useState(false);
|
||||||
const [editContent, setEditContent] = useState(note.content);
|
const [editContent, setEditContent] = useState(note.content);
|
||||||
@ -138,6 +140,13 @@ export const NoteItem: React.FC<NoteItemProps> = ({
|
|||||||
setDeletedImageIds([]);
|
setDeletedImageIds([]);
|
||||||
setDeletedFileIds([]);
|
setDeletedFileIds([]);
|
||||||
onReload();
|
onReload();
|
||||||
|
// Устанавливаем фокус на заметку после сохранения
|
||||||
|
if (onFocusNote) {
|
||||||
|
// Небольшая задержка для завершения обновления DOM
|
||||||
|
setTimeout(() => {
|
||||||
|
onFocusNote(note.id);
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Ошибка обновления заметки:", error);
|
console.error("Ошибка обновления заметки:", error);
|
||||||
showNotification("Ошибка обновления заметки", "error");
|
showNotification("Ошибка обновления заметки", "error");
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import { extractTags } from "../../utils/markdown";
|
|||||||
|
|
||||||
export interface NotesListRef {
|
export interface NotesListRef {
|
||||||
reloadNotes: () => void;
|
reloadNotes: () => void;
|
||||||
|
focusNote: (noteId: number | string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface NotesListProps {
|
interface NotesListProps {
|
||||||
@ -81,8 +82,34 @@ export const NotesList = forwardRef<NotesListRef, NotesListProps>(
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [userId, searchQuery, selectedDate, selectedTag]);
|
}, [userId, searchQuery, selectedDate, selectedTag]);
|
||||||
|
|
||||||
|
const focusNote = (noteId: number | string) => {
|
||||||
|
// Используем data-атрибут для поиска элемента заметки
|
||||||
|
const noteElement = document.querySelector(
|
||||||
|
`[data-note-id="${noteId}"]`
|
||||||
|
) as HTMLDivElement | null;
|
||||||
|
|
||||||
|
if (noteElement) {
|
||||||
|
// Прокручиваем к верхней части заметки
|
||||||
|
noteElement.scrollIntoView({ behavior: "smooth", block: "start", inline: "nearest" });
|
||||||
|
// Добавляем визуальное выделение на короткое время
|
||||||
|
// Очищаем предыдущий таймер, если он был установлен
|
||||||
|
const existingTimeout = (noteElement as any).__focusTimeout;
|
||||||
|
if (existingTimeout) {
|
||||||
|
clearTimeout(existingTimeout);
|
||||||
|
}
|
||||||
|
noteElement.style.transition = "box-shadow 0.3s ease";
|
||||||
|
noteElement.style.boxShadow = "0 0 0 3px rgba(33, 150, 243, 0.5)";
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
noteElement.style.boxShadow = "";
|
||||||
|
(noteElement as any).__focusTimeout = null;
|
||||||
|
}, 2000);
|
||||||
|
(noteElement as any).__focusTimeout = timeout;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
reloadNotes: loadNotes,
|
reloadNotes: loadNotes,
|
||||||
|
focusNote: focusNote,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const handleDelete = async (id: number | string) => {
|
const handleDelete = async (id: number | string) => {
|
||||||
@ -167,6 +194,7 @@ export const NotesList = forwardRef<NotesListRef, NotesListProps>(
|
|||||||
onReload={loadNotes}
|
onReload={loadNotes}
|
||||||
isSelected={selectedNoteIds.includes(note.id)}
|
isSelected={selectedNoteIds.includes(note.id)}
|
||||||
onSelect={onNoteSelect}
|
onSelect={onNoteSelect}
|
||||||
|
onFocusNote={focusNote}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -63,10 +63,32 @@ const NotesPage: React.FC = () => {
|
|||||||
|
|
||||||
const activeFilters = getActiveFilters();
|
const activeFilters = getActiveFilters();
|
||||||
|
|
||||||
const handleNoteSave = () => {
|
const handleNoteSave = (noteId?: number | string) => {
|
||||||
// Вызываем перезагрузку заметок после создания новой заметки
|
// Вызываем перезагрузку заметок после создания новой заметки
|
||||||
if (notesListRef.current) {
|
if (notesListRef.current) {
|
||||||
notesListRef.current.reloadNotes();
|
notesListRef.current.reloadNotes();
|
||||||
|
// Устанавливаем фокус на сохраненную заметку после небольшой задержки,
|
||||||
|
// чтобы дать время для перезагрузки и рендеринга заметок
|
||||||
|
if (noteId) {
|
||||||
|
let attempts = 0;
|
||||||
|
const maxAttempts = 15;
|
||||||
|
const attemptFocus = () => {
|
||||||
|
attempts++;
|
||||||
|
if (notesListRef.current) {
|
||||||
|
// Проверяем, есть ли элемент заметки в DOM
|
||||||
|
const noteElement = document.querySelector(
|
||||||
|
`[data-note-id="${noteId}"]`
|
||||||
|
);
|
||||||
|
if (noteElement || attempts >= maxAttempts) {
|
||||||
|
notesListRef.current.focusNote(noteId);
|
||||||
|
} else if (attempts < maxAttempts) {
|
||||||
|
// Пытаемся еще раз, если заметка еще не появилась в DOM
|
||||||
|
setTimeout(attemptFocus, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
setTimeout(attemptFocus, 200);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user