Загрузить файлы в «/»
This commit is contained in:
commit
4c09eb9710
BIN
TeletactileRus.ttf
Normal file
BIN
TeletactileRus.ttf
Normal file
Binary file not shown.
247
app.js
Normal file
247
app.js
Normal file
@ -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 = `
|
||||||
|
<div id="note" class="container">
|
||||||
|
<div class="date">
|
||||||
|
${content.date} ${content.time}
|
||||||
|
<div id="editBtn" class="notesHeaderBtn" data-index="${index}">Редактировать</div>
|
||||||
|
<div id="deleteBtn" class="notesHeaderBtn" data-index="${index}">Удалить</div>
|
||||||
|
</div>
|
||||||
|
<div class="textNote">${marked.parse(content.content)}</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
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();
|
||||||
72
index.html
Normal file
72
index.html
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Document</title>
|
||||||
|
<link rel="stylesheet" href="style.css" />
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"
|
||||||
|
/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<header>Заметки</header>
|
||||||
|
<div class="main">
|
||||||
|
<div class="markdown-buttons">
|
||||||
|
<button class="btnMarkdown" id="boldBtn">
|
||||||
|
<i class="fas fa-bold"></i>
|
||||||
|
<!-- Иконка для жирного текста -->
|
||||||
|
</button>
|
||||||
|
<button class="btnMarkdown" id="italicBtn">
|
||||||
|
<i class="fas fa-italic"></i>
|
||||||
|
<!-- Иконка для курсива -->
|
||||||
|
</button>
|
||||||
|
<button class="btnMarkdown" id="headerBtn">
|
||||||
|
<i class="fas fa-heading"></i>
|
||||||
|
<!-- Иконка для заголовка -->
|
||||||
|
</button>
|
||||||
|
<button class="btnMarkdown" id="listBtn">
|
||||||
|
<i class="fas fa-list-ul"></i>
|
||||||
|
<!-- Иконка для списка -->
|
||||||
|
</button>
|
||||||
|
<button class="btnMarkdown" id="quoteBtn">
|
||||||
|
<i class="fas fa-quote-right"></i>
|
||||||
|
<!-- Иконка для цитаты -->
|
||||||
|
</button>
|
||||||
|
<button class="btnMarkdown" id="codeBtn">
|
||||||
|
<i class="fas fa-code"></i>
|
||||||
|
<!-- Иконка для кода -->
|
||||||
|
</button>
|
||||||
|
<button class="btnMarkdown" id="linkBtn">
|
||||||
|
<i class="fas fa-link"></i>
|
||||||
|
<!-- Иконка для ссылки -->
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<textarea
|
||||||
|
class="textInput"
|
||||||
|
name=""
|
||||||
|
id=""
|
||||||
|
placeholder="Ваша заметка..."
|
||||||
|
></textarea>
|
||||||
|
<button class="btnSave">Сохранить</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="notes-container">
|
||||||
|
<div id="note" class="container">
|
||||||
|
<div class="date">
|
||||||
|
<div class="notesHeaderBtn"></div>
|
||||||
|
<div class="notesHeaderBtn"></div>
|
||||||
|
</div>
|
||||||
|
<div class="textNote"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
<p>Создатель: <span>Fovway</span></p>
|
||||||
|
</div>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/11.1.0/marked.min.js"></script>
|
||||||
|
<script src="app.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
20
manifest.json
Normal file
20
manifest.json
Normal file
@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
project.png
Normal file
BIN
project.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
Loading…
x
Reference in New Issue
Block a user