Загрузить файлы в «/»

This commit is contained in:
Fovway 2025-03-23 05:47:46 +00:00
commit 4c09eb9710
5 changed files with 339 additions and 0 deletions

BIN
TeletactileRus.ttf Normal file

Binary file not shown.

247
app.js Normal file
View 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
View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB