commit 4c09eb97102058f11dd2ba7c1d3b3462644b1aab Author: Fovway Date: Sun Mar 23 05:47:46 2025 +0000 Загрузить файлы в «/» diff --git a/TeletactileRus.ttf b/TeletactileRus.ttf new file mode 100644 index 0000000..e361f72 Binary files /dev/null and b/TeletactileRus.ttf differ diff --git a/app.js b/app.js new file mode 100644 index 0000000..67e53d0 --- /dev/null +++ b/app.js @@ -0,0 +1,247 @@ +const textInput = document.querySelector(".textInput"); +const btnSave = document.querySelector(".btnSave"); +const notes = document.querySelector(".notes-container"); + +// Получаем кнопки +const boldBtn = document.getElementById("boldBtn"); +const italicBtn = document.getElementById("italicBtn"); +const headerBtn = document.getElementById("headerBtn"); +const listBtn = document.getElementById("listBtn"); +const quoteBtn = document.getElementById("quoteBtn"); +const codeBtn = document.getElementById("codeBtn"); +const linkBtn = document.getElementById("linkBtn"); + +function getFormattedDateTime() { + let now = new Date(); + let day = String(now.getDate()).padStart(2, "0"); + let month = String(now.getMonth() + 1).padStart(2, "0"); + let year = now.getFullYear(); + let hours = String(now.getHours()).padStart(2, "0"); + let minutes = String(now.getMinutes()).padStart(2, "0"); + + return { + date: `${day}.${month}.${year}`, + time: `${hours}:${minutes}`, + }; +} + +// Сохранить заметки в localStorage +function saveNotesToLocalStorage(notesArr) { + localStorage.setItem("notes", JSON.stringify(notesArr)); +} + +// Получить заметки из localStorage +function getNotesFromLocalStorage() { + return JSON.parse(localStorage.getItem("notes")) || []; +} + +// Обновить функцию renderNotes +function renderNotes() { + const notesArr = getNotesFromLocalStorage(); + notes.innerHTML = ""; // Очищаем контейнер перед рендерингом + + notesArr.forEach(function (content, index) { + const noteHtml = ` +
+
+ ${content.date} ${content.time} +
Редактировать
+
Удалить
+
+
${marked.parse(content.content)}
+
+ `; + notes.insertAdjacentHTML("afterbegin", noteHtml); + }); + + deleteNote(); + editNote(); +} + +// Обновить функцию saveNote +function saveNote() { + btnSave.addEventListener("click", function () { + if (textInput.value.trim() !== "") { + let { date, time } = getFormattedDateTime(); + + const note = { + content: textInput.value, + date: date, + time: time, + }; + + const notesArr = getNotesFromLocalStorage(); + notesArr.push(note); + saveNotesToLocalStorage(notesArr); + + textInput.value = ""; + textInput.style.height = "auto"; // Сбрасываем размер текстового поля + renderNotes(); + } + }); +} + +// Обновить функцию deleteNote +function deleteNote() { + document.querySelectorAll("#deleteBtn").forEach((btn) => { + btn.addEventListener("click", function (event) { + let index = event.target.dataset.index; + const notesArr = getNotesFromLocalStorage(); + notesArr.splice(index, 1); + saveNotesToLocalStorage(notesArr); + renderNotes(); + }); + }); +} + +// Обновить функцию editNote +function editNote() { + document.querySelectorAll("#editBtn").forEach((btn) => { + btn.addEventListener("click", function (event) { + let index = event.target.dataset.index; + let noteContainer = event.target.closest("#note"); + let noteContent = noteContainer.querySelector(".textNote"); + + // Создаем textarea с уже существующим классом textInput + let textarea = document.createElement("textarea"); + textarea.classList.add("textInput"); + textarea.value = noteContent.textContent; + + // Привязываем авторасширение к textarea для редактирования + textarea.addEventListener("input", function () { + autoExpandTextarea(textarea); + }); + autoExpandTextarea(textarea); + + // Кнопка сохранить + let saveEditBtn = document.createElement("button"); + saveEditBtn.textContent = "Сохранить"; + saveEditBtn.classList.add("btnSave"); + + // Очищаем текущий контент и вставляем textarea и кнопку сохранить + noteContent.innerHTML = ""; + noteContent.appendChild(textarea); + noteContent.appendChild(saveEditBtn); + + saveEditBtn.addEventListener("click", function () { + if (textarea.value.trim() !== "") { + let { date, time } = getFormattedDateTime(); + const notesArr = getNotesFromLocalStorage(); + notesArr[index] = { + content: textarea.value, + date: date, + time: time, + }; + saveNotesToLocalStorage(notesArr); + renderNotes(); + } + }); + }); + }); +} + +// Функция для авторасширения текстового поля +function autoExpandTextarea(textarea) { + textarea.style.height = "auto"; + textarea.style.height = textarea.scrollHeight + "px"; +} + +// Привязываем авторасширение к текстовому полю для создания заметки +textInput.addEventListener("input", function () { + autoExpandTextarea(textInput); +}); + +// Изначально запускаем для установки правильной высоты +autoExpandTextarea(textInput); + +function insertMarkdown(tag) { + const start = textInput.selectionStart; + const end = textInput.selectionEnd; + const text = textInput.value; + + const before = text.substring(0, start); + const selected = text.substring(start, end); + const after = text.substring(end); + + if (selected.startsWith(tag) && selected.endsWith(tag)) { + // Если теги уже есть, удаляем их + textInput.value = `${before}${selected.slice( + tag.length, + -tag.length + )}${after}`; + textInput.setSelectionRange(start, end - 2 * tag.length); + } else if (selected.trim() === "") { + // Если текст не выделен + if (tag === "[Текст ссылки](URL)") { + // Для ссылок создаем шаблон с двумя кавычками + textInput.value = `${before}[Текст ссылки](URL)${after}`; + const cursorPosition = start + 1; // Помещаем курсор внутрь текста ссылки + textInput.setSelectionRange(cursorPosition, cursorPosition + 12); + } else if (tag === "- " || tag === "> " || tag === "# ") { + // Для списка, цитаты и заголовка помещаем курсор после `- `, `> ` или `# ` + textInput.value = `${before}${tag}${after}`; + const cursorPosition = start + tag.length; + textInput.setSelectionRange(cursorPosition, cursorPosition); + } else { + // Для остальных типов создаем два тега + textInput.value = `${before}${tag}${tag}${after}`; + const cursorPosition = start + tag.length; + textInput.setSelectionRange(cursorPosition, cursorPosition); + } + } else { + // Если текст выделен + if (tag === "[Текст ссылки](URL)") { + // Для ссылок используем выделенный текст вместо "Текст ссылки" + textInput.value = `${before}[${selected}](URL)${after}`; + const cursorPosition = start + selected.length + 3; // Помещаем курсор в URL + textInput.setSelectionRange(cursorPosition, cursorPosition + 3); + } else if (tag === "- " || tag === "> " || tag === "# ") { + // Для списка, цитаты и заголовка добавляем `- `, `> ` или `# ` перед выделенным текстом + textInput.value = `${before}${tag}${selected}${after}`; + const cursorPosition = start + tag.length + selected.length; + textInput.setSelectionRange(cursorPosition, cursorPosition); + } else { + // Для остальных типов оборачиваем выделенный текст + textInput.value = `${before}${tag}${selected}${tag}${after}`; + const cursorPosition = start + tag.length + selected.length + tag.length; + textInput.setSelectionRange(cursorPosition, cursorPosition); + } + } + + textInput.focus(); +} + +// Обработчики для кнопок +boldBtn.addEventListener("click", function () { + insertMarkdown("**"); // Вставляем жирный текст +}); + +italicBtn.addEventListener("click", function () { + insertMarkdown("*"); // Вставляем курсив +}); + +headerBtn.addEventListener("click", function () { + insertMarkdown("# "); // Вставляем заголовок +}); + +listBtn.addEventListener("click", function () { + insertMarkdown("- "); // Вставляем элемент списка +}); + +quoteBtn.addEventListener("click", function () { + insertMarkdown("> "); // Вставляем цитату +}); + +codeBtn.addEventListener("click", function () { + insertMarkdown("`"); // Вставляем код +}); + +linkBtn.addEventListener("click", function () { + insertMarkdown("[Текст ссылки](URL)"); // Вставляем ссылку +}); + +// Удалено дублирование добавления кнопок Markdown в окно сохранения заметки +// Кнопки уже добавлены в HTML (index.html), поэтому их повторное создание не требуется + +renderNotes(); +saveNote(); diff --git a/index.html b/index.html new file mode 100644 index 0000000..9d38e84 --- /dev/null +++ b/index.html @@ -0,0 +1,72 @@ + + + + + + Document + + + + +
+
Заметки
+
+
+ + + + + + + +
+ + + +
+
+
+
+
+
+
+
+
+
+
+ + + + + diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..129f529 --- /dev/null +++ b/manifest.json @@ -0,0 +1,20 @@ +{ + "name": "Fov Notes", + "short_name": "Notes", + "start_url": "/", + "display": "standalone", + "background_color": "#ffffff", + "theme_color": "#000000", + "icons": [ + { + "src": "project.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "project.png", + "sizes": "512x512", + "type": "image/png" + } + ] +} diff --git a/project.png b/project.png new file mode 100644 index 0000000..a89e28a Binary files /dev/null and b/project.png differ