- Созданы патч файлы для применения изменений - Добавлен архив с полными изменениями - Создан скрипт автоматического применения - Добавлена документация по развертыванию - Создан отчет о попытке отправки изменений
1168 lines
42 KiB
Diff
1168 lines
42 KiB
Diff
From 7376de1a5b448b5a4e33079e7927cb354992ba59 Mon Sep 17 00:00:00 2001
|
||
From: Fovway <fovway@gmail.com>
|
||
Date: Sun, 19 Oct 2025 00:36:19 +0700
|
||
Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?=
|
||
=?UTF-8?q?=D0=BB=D0=B5=D0=BD=20=D0=BB=D0=B8=D1=87=D0=BD=D1=8B=D0=B9=20?=
|
||
=?UTF-8?q?=D0=BA=D0=B0=D0=B1=D0=B8=D0=BD=D0=B5=D1=82=20=D1=81=20=D0=B0?=
|
||
=?UTF-8?q?=D0=B2=D0=B0=D1=82=D0=B0=D1=80=D0=BA=D0=B0=D0=BC=D0=B8=20=D0=B8?=
|
||
=?UTF-8?q?=20=D1=83=D0=BB=D1=83=D1=87=D1=88=D0=B5=D0=BD=D0=B0=20=D0=BD?=
|
||
=?UTF-8?q?=D0=B0=D0=B2=D0=B8=D0=B3=D0=B0=D1=86=D0=B8=D1=8F?=
|
||
MIME-Version: 1.0
|
||
Content-Type: text/plain; charset=UTF-8
|
||
Content-Transfer-Encoding: 8bit
|
||
|
||
- Добавлена страница личного кабинета с возможностью загрузки аватарки
|
||
- Реализовано управление аватарками: загрузка, удаление, предварительный просмотр
|
||
- Исправлено отображение аватарки на странице профиля (центрирование)
|
||
- Убрано отображение аватарки со страницы заметок для чистоты интерфейса
|
||
- Обновлен .gitignore с исключениями для загруженных файлов и временных файлов
|
||
- Обновлен README.md с документацией по новым функциям
|
||
- Добавлена валидация загружаемых файлов (тип, размер, формат)
|
||
- Улучшена безопасность с изоляцией пользовательских данных
|
||
---
|
||
.gitignore | 24 ++++-
|
||
README.md | 65 ++++++++++++--
|
||
index.html | 19 ++--
|
||
package-lock.json | 18 ++++
|
||
package.json | 1 +
|
||
public/app.js | 205 +++++++++++++++++++++++++++++++++++++------
|
||
public/index.html | 9 +-
|
||
public/notes.html | 84 +++++++++++++-----
|
||
public/profile.html | 21 +++--
|
||
public/register.html | 9 +-
|
||
public/style.css | 178 +++++++++++++++++++++++++++++++++++++
|
||
server.js | 42 +++++++++
|
||
style.css | 69 +++++++++++++++
|
||
13 files changed, 658 insertions(+), 86 deletions(-)
|
||
|
||
diff --git a/.gitignore b/.gitignore
|
||
index e1b049b..a0e03f0 100644
|
||
--- a/.gitignore
|
||
+++ b/.gitignore
|
||
@@ -33,4 +33,26 @@ Thumbs.db
|
||
dist/
|
||
build/
|
||
|
||
-.cursor/
|
||
\ No newline at end of file
|
||
+# Cursor IDE
|
||
+.cursor/
|
||
+
|
||
+# Загруженные файлы пользователей
|
||
+public/uploads/
|
||
+
|
||
+# Тестовые файлы
|
||
+test-icons.html
|
||
+
|
||
+# Планы и заметки разработчика
|
||
+планы.txt
|
||
+*.txt
|
||
+
|
||
+# Скриншоты
|
||
+*.png
|
||
+*.jpg
|
||
+*.jpeg
|
||
+*.gif
|
||
+*.webp
|
||
+
|
||
+# Временные файлы
|
||
+*.tmp
|
||
+*.temp
|
||
\ No newline at end of file
|
||
diff --git a/README.md b/README.md
|
||
index e737285..97c6105 100644
|
||
--- a/README.md
|
||
+++ b/README.md
|
||
@@ -5,11 +5,16 @@
|
||
## Особенности
|
||
|
||
- 🚀 Создано на Node.js + Express
|
||
-- 🔐 **Система регистрации и авторизации по логину и паролю** (NEW!)
|
||
+- 🔐 **Система регистрации и авторизации по логину и паролю**
|
||
- 🔒 Безопасное хранение паролей с bcrypt хешированием
|
||
- 💾 Хранение данных в SQLite базе данных
|
||
-- 👥 **Изолированные заметки - каждый пользователь видит только свои заметки** (NEW!)
|
||
+- 👥 **Изолированные заметки - каждый пользователь видит только свои заметки**
|
||
+- 👤 **Личный кабинет с возможностью загрузки аватарки** (NEW!)
|
||
+- 🖼️ **Управление аватаркой: загрузка, удаление, предварительный просмотр** (NEW!)
|
||
- 📝 Поддержка Markdown форматирования
|
||
+- 🏷️ **Система тегов с автоматическим извлечением из заметок** (NEW!)
|
||
+- 🔍 **Поиск по заметкам с подсветкой результатов** (NEW!)
|
||
+- 📅 **Мини-календарь для навигации по датам заметок** (NEW!)
|
||
- 🎨 Простой и интуитивный интерфейс
|
||
- 📱 Адаптивный дизайн
|
||
|
||
@@ -98,6 +103,27 @@ npm start
|
||
1. Нажмите кнопку "Удалить" рядом с заметкой
|
||
2. Подтвердите удаление в появившемся диалоговом окне
|
||
|
||
+### Личный кабинет
|
||
+
|
||
+1. Нажмите на ваше имя пользователя в верхней части страницы заметок
|
||
+2. В личном кабинете вы можете:
|
||
+ - **Загрузить аватарку**: нажмите "Загрузить аватар" и выберите изображение (JPG, PNG, GIF до 5 МБ)
|
||
+ - **Удалить аватарку**: нажмите кнопку "Удалить" рядом с аватаркой
|
||
+ - **Изменить данные профиля**: отредактируйте логин и email
|
||
+ - **Изменить пароль**: введите текущий пароль и новый пароль
|
||
+
|
||
+### Поиск и фильтрация
|
||
+
|
||
+1. **Поиск по заметкам**: используйте поле поиска в левой панели для поиска по содержимому заметок
|
||
+2. **Фильтрация по тегам**: кликайте на теги в левой панели для фильтрации заметок
|
||
+3. **Навигация по календарю**: кликайте на даты в мини-календаре для просмотра заметок за определенный день
|
||
+
|
||
+### Теги
|
||
+
|
||
+- Теги автоматически извлекаются из заметок при использовании символа `#` (например: `#важное`)
|
||
+- Теги отображаются в левой панели с количеством заметок
|
||
+- Кликабельные теги в заметках позволяют быстро фильтровать контент
|
||
+
|
||
### Выход из системы
|
||
|
||
Нажмите кнопку "🚪 Выйти" в верхней части страницы заметок
|
||
@@ -108,14 +134,18 @@ npm start
|
||
NoteJS/
|
||
├── public/ # Статические файлы (клиентская часть)
|
||
│ ├── index.html # Страница входа
|
||
-│ ├── register.html # Страница регистрации (NEW!)
|
||
+│ ├── register.html # Страница регистрации
|
||
│ ├── notes.html # Страница заметок
|
||
-│ ├── login.js # Логика входа (обновлена)
|
||
-│ ├── register.js # Логика регистрации (NEW!)
|
||
-│ ├── app.js # Клиентский JavaScript
|
||
-│ └── style.css # Стили
|
||
-├── server.js # Express сервер
|
||
+│ ├── profile.html # Страница личного кабинета (NEW!)
|
||
+│ ├── login.js # Логика входа
|
||
+│ ├── register.js # Логика регистрации
|
||
+│ ├── profile.js # Логика личного кабинета (NEW!)
|
||
+│ ├── app.js # Клиентский JavaScript (обновлен)
|
||
+│ ├── style.css # Стили (обновлены)
|
||
+│ └── uploads/ # Загруженные аватарки пользователей (NEW!)
|
||
+├── server.js # Express сервер (обновлен)
|
||
├── .env # Конфигурация (не включать в git!)
|
||
+├── .gitignore # Исключения для git (обновлен)
|
||
├── package.json # Зависимости проекта
|
||
├── notes.db # SQLite база данных (создается автоматически)
|
||
└── README.md # Документация
|
||
@@ -132,10 +162,17 @@ NoteJS/
|
||
- `POST /logout` - выход из системы
|
||
- `GET /api/user` - получить информацию о текущем пользователе (требует аутентификации)
|
||
|
||
+### Профиль пользователя (требует аутентификации)
|
||
+
|
||
+- `GET /profile` - страница личного кабинета
|
||
+- `PUT /api/user/profile` - обновить данные профиля или пароль
|
||
+- `POST /api/user/avatar` - загрузить аватарку
|
||
+- `DELETE /api/user/avatar` - удалить аватарку
|
||
+
|
||
### Заметки (требуют аутентификации)
|
||
|
||
- `GET /notes` - страница заметок
|
||
-- `GET /api/notes` - получить все заметки
|
||
+- `GET /api/notes` - получить все заметки пользователя
|
||
- `POST /api/notes` - создать новую заметку
|
||
- `PUT /api/notes/:id` - обновить заметку
|
||
- `DELETE /api/notes/:id` - удалить заметку
|
||
@@ -147,7 +184,10 @@ NoteJS/
|
||
- **Helmet** для защиты от распространенных уязвимостей
|
||
- **CORS** конфигурация
|
||
- **Body Parser** для безопасной обработки запросов
|
||
+- **Multer** для безопасной загрузки файлов с валидацией
|
||
- Защищенные маршруты с проверкой аутентификации
|
||
+- **Валидация загружаемых файлов**: проверка типа, размера и формата
|
||
+- **Изоляция данных**: каждый пользователь видит только свои заметки и файлы
|
||
|
||
## Требования к паролям
|
||
|
||
@@ -160,6 +200,13 @@ NoteJS/
|
||
- Минимум 3 символа
|
||
- Должен быть уникальным (нельзя создать два аккаунта с одинаковым логином)
|
||
|
||
+## Требования к аватаркам
|
||
+
|
||
+- **Максимальный размер**: 5 МБ
|
||
+- **Поддерживаемые форматы**: JPG, PNG, GIF
|
||
+- **Автоматическое изменение размера**: изображения автоматически обрезаются до квадратного формата
|
||
+- **Безопасность**: проверка типа файла и размера перед загрузкой
|
||
+
|
||
## Разработка
|
||
|
||
Для разработки используйте:
|
||
diff --git a/index.html b/index.html
|
||
index 0c71d4c..0fbc7f6 100644
|
||
--- a/index.html
|
||
+++ b/index.html
|
||
@@ -5,10 +5,7 @@
|
||
<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"
|
||
- />
|
||
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/iconify/2.0.0/iconify.min.js"></script>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
@@ -16,31 +13,31 @@
|
||
<div class="main">
|
||
<div class="markdown-buttons">
|
||
<button class="btnMarkdown" id="boldBtn">
|
||
- <i class="fas fa-bold"></i>
|
||
+ <span class="iconify" data-icon="mdi:format-bold"></span>
|
||
<!-- Иконка для жирного текста -->
|
||
</button>
|
||
<button class="btnMarkdown" id="italicBtn">
|
||
- <i class="fas fa-italic"></i>
|
||
+ <span class="iconify" data-icon="mdi:format-italic"></span>
|
||
<!-- Иконка для курсива -->
|
||
</button>
|
||
<button class="btnMarkdown" id="headerBtn">
|
||
- <i class="fas fa-heading"></i>
|
||
+ <span class="iconify" data-icon="mdi:format-header-1"></span>
|
||
<!-- Иконка для заголовка -->
|
||
</button>
|
||
<button class="btnMarkdown" id="listBtn">
|
||
- <i class="fas fa-list-ul"></i>
|
||
+ <span class="iconify" data-icon="mdi:format-list-bulleted"></span>
|
||
<!-- Иконка для списка -->
|
||
</button>
|
||
<button class="btnMarkdown" id="quoteBtn">
|
||
- <i class="fas fa-quote-right"></i>
|
||
+ <span class="iconify" data-icon="mdi:format-quote-close"></span>
|
||
<!-- Иконка для цитаты -->
|
||
</button>
|
||
<button class="btnMarkdown" id="codeBtn">
|
||
- <i class="fas fa-code"></i>
|
||
+ <span class="iconify" data-icon="mdi:code-tags"></span>
|
||
<!-- Иконка для кода -->
|
||
</button>
|
||
<button class="btnMarkdown" id="linkBtn">
|
||
- <i class="fas fa-link"></i>
|
||
+ <span class="iconify" data-icon="mdi:link"></span>
|
||
<!-- Иконка для ссылки -->
|
||
</button>
|
||
</div>
|
||
diff --git a/package-lock.json b/package-lock.json
|
||
index 55781e1..bbf1df8 100644
|
||
--- a/package-lock.json
|
||
+++ b/package-lock.json
|
||
@@ -14,6 +14,7 @@
|
||
"@codemirror/state": "^6.5.2",
|
||
"@codemirror/theme-one-dark": "^6.1.3",
|
||
"@codemirror/view": "^6.38.6",
|
||
+ "@iconify/iconify": "^3.1.1",
|
||
"bcryptjs": "^3.0.2",
|
||
"body-parser": "^2.2.0",
|
||
"codemirror": "^6.0.2",
|
||
@@ -507,6 +508,23 @@
|
||
"integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==",
|
||
"optional": true
|
||
},
|
||
+ "node_modules/@iconify/iconify": {
|
||
+ "version": "3.1.1",
|
||
+ "resolved": "https://registry.npmjs.org/@iconify/iconify/-/iconify-3.1.1.tgz",
|
||
+ "integrity": "sha512-1nemfyD/OJzh9ALepH7YfuuP8BdEB24Skhd8DXWh0hzcOxImbb1ZizSZkpCzAwSZSGcJFmscIBaBQu+yLyWaxQ==",
|
||
+ "deprecated": "no longer maintained, switch to modern iconify-icon web component",
|
||
+ "dependencies": {
|
||
+ "@iconify/types": "^2.0.0"
|
||
+ },
|
||
+ "funding": {
|
||
+ "url": "https://github.com/sponsors/cyberalien"
|
||
+ }
|
||
+ },
|
||
+ "node_modules/@iconify/types": {
|
||
+ "version": "2.0.0",
|
||
+ "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz",
|
||
+ "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="
|
||
+ },
|
||
"node_modules/@lezer/common": {
|
||
"version": "0.16.1",
|
||
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-0.16.1.tgz",
|
||
diff --git a/package.json b/package.json
|
||
index f8ea894..97a92c7 100644
|
||
--- a/package.json
|
||
+++ b/package.json
|
||
@@ -20,6 +20,7 @@
|
||
"@codemirror/state": "^6.5.2",
|
||
"@codemirror/theme-one-dark": "^6.1.3",
|
||
"@codemirror/view": "^6.38.6",
|
||
+ "@iconify/iconify": "^3.1.1",
|
||
"bcryptjs": "^3.0.2",
|
||
"body-parser": "^2.2.0",
|
||
"codemirror": "^6.0.2",
|
||
diff --git a/public/app.js b/public/app.js
|
||
index 2cd5180..3c37637 100644
|
||
--- a/public/app.js
|
||
+++ b/public/app.js
|
||
@@ -16,6 +16,8 @@ const linkBtn = document.getElementById("linkBtn");
|
||
let allNotes = [];
|
||
let selectedDateFilter = null;
|
||
let selectedTagFilter = null;
|
||
+let searchQuery = "";
|
||
+let searchResults = [];
|
||
|
||
// Функция для получения текущей даты и времени
|
||
function getFormattedDateTime() {
|
||
@@ -56,11 +58,42 @@ function extractTags(content) {
|
||
|
||
// Функция для преобразования тегов в заметках в кликабельные элементы
|
||
function makeTagsClickable(content) {
|
||
+ // Сначала находим все теги, которые еще не обернуты в HTML
|
||
const tagRegex = /#(\w+)/g;
|
||
- return content.replace(
|
||
- tagRegex,
|
||
- '<span class="tag-in-note" data-tag="$1">#$1</span>'
|
||
- );
|
||
+ let result = content;
|
||
+ let match;
|
||
+
|
||
+ // Создаем массив всех совпадений с их позициями
|
||
+ const matches = [];
|
||
+ while ((match = tagRegex.exec(content)) !== null) {
|
||
+ matches.push({
|
||
+ fullMatch: match[0],
|
||
+ tag: match[1],
|
||
+ index: match.index,
|
||
+ });
|
||
+ }
|
||
+
|
||
+ // Обрабатываем совпадения в обратном порядке, чтобы не сбить индексы
|
||
+ for (let i = matches.length - 1; i >= 0; i--) {
|
||
+ const match = matches[i];
|
||
+ const beforeTag = result.substring(0, match.index);
|
||
+ const afterTag = result.substring(match.index + match.fullMatch.length);
|
||
+
|
||
+ // Проверяем, не находится ли тег уже внутри HTML-тега
|
||
+ const lastOpenTag = beforeTag.lastIndexOf("<");
|
||
+ const lastCloseTag = beforeTag.lastIndexOf(">");
|
||
+
|
||
+ // Если последний открывающий тег идет после последнего закрывающего, значит мы внутри HTML-тега
|
||
+ if (lastOpenTag > lastCloseTag) {
|
||
+ continue; // Пропускаем этот тег
|
||
+ }
|
||
+
|
||
+ // Заменяем тег на кликабельный элемент
|
||
+ const replacement = `<span class="tag-in-note" data-tag="${match.tag}">${match.fullMatch}</span>`;
|
||
+ result = beforeTag + replacement + afterTag;
|
||
+ }
|
||
+
|
||
+ return result;
|
||
}
|
||
|
||
// Функция для получения всех уникальных тегов из заметок
|
||
@@ -293,6 +326,55 @@ async function loadNotes() {
|
||
}
|
||
}
|
||
|
||
+// Функция для поиска заметок
|
||
+async function searchNotes(query) {
|
||
+ if (!query || query.trim() === "") {
|
||
+ searchQuery = "";
|
||
+ searchResults = [];
|
||
+ renderNotes(allNotes);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ try {
|
||
+ const params = new URLSearchParams();
|
||
+ params.append("q", query.trim());
|
||
+
|
||
+ // Добавляем фильтры, если они активны
|
||
+ if (selectedTagFilter) {
|
||
+ params.append("tag", selectedTagFilter);
|
||
+ }
|
||
+ if (selectedDateFilter) {
|
||
+ params.append("date", selectedDateFilter);
|
||
+ }
|
||
+
|
||
+ const response = await fetch(`/api/notes/search?${params}`);
|
||
+ if (!response.ok) {
|
||
+ throw new Error("Ошибка поиска заметок");
|
||
+ }
|
||
+
|
||
+ searchResults = await response.json();
|
||
+ searchQuery = query.trim();
|
||
+ renderNotes(searchResults);
|
||
+ } catch (error) {
|
||
+ console.error("Ошибка поиска:", error);
|
||
+ searchResults = [];
|
||
+ renderNotes(allNotes);
|
||
+ }
|
||
+}
|
||
+
|
||
+// Функция для подсветки найденного текста
|
||
+function highlightSearchText(content, query) {
|
||
+ if (!query || query.trim() === "") {
|
||
+ return content;
|
||
+ }
|
||
+
|
||
+ const regex = new RegExp(
|
||
+ `(${query.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})`,
|
||
+ "gi"
|
||
+ );
|
||
+ return content.replace(regex, '<span class="search-highlight">$1</span>');
|
||
+}
|
||
+
|
||
// Функция для отображения заметок
|
||
function renderNotes(notes) {
|
||
notesList.innerHTML = "";
|
||
@@ -331,8 +413,16 @@ function renderNotes(notes) {
|
||
|
||
// Итерируемся по заметкам в обычном порядке, чтобы новые были сверху
|
||
notesToDisplay.forEach(function (note) {
|
||
- // Преобразуем теги в кликабельные элементы перед парсингом markdown
|
||
- const contentWithClickableTags = makeTagsClickable(note.content);
|
||
+ let contentToProcess = note.content;
|
||
+
|
||
+ // Сначала подсвечиваем найденный текст в исходном markdown
|
||
+ if (searchQuery) {
|
||
+ contentToProcess = highlightSearchText(contentToProcess, searchQuery);
|
||
+ }
|
||
+
|
||
+ // Затем преобразуем теги в кликабельные элементы
|
||
+ const contentWithClickableTags = makeTagsClickable(contentToProcess);
|
||
+
|
||
const parsedContent = marked.parse(contentWithClickableTags);
|
||
|
||
const noteHtml = `
|
||
@@ -401,20 +491,20 @@ function addNoteEventListeners() {
|
||
|
||
// Создаем markdown кнопки
|
||
const markdownButtons = [
|
||
- { id: "editBoldBtn", icon: "fas fa-bold", tag: "**" },
|
||
- { id: "editItalicBtn", icon: "fas fa-italic", tag: "*" },
|
||
- { id: "editHeaderBtn", icon: "fas fa-heading", tag: "# " },
|
||
- { id: "editListBtn", icon: "fas fa-list-ul", tag: "- " },
|
||
- { id: "editQuoteBtn", icon: "fas fa-quote-right", tag: "> " },
|
||
- { id: "editCodeBtn", icon: "fas fa-code", tag: "`" },
|
||
- { id: "editLinkBtn", icon: "fas fa-link", tag: "[Текст ссылки](URL)" },
|
||
+ { id: "editBoldBtn", icon: "mdi:format-bold", tag: "**" },
|
||
+ { id: "editItalicBtn", icon: "mdi:format-italic", tag: "*" },
|
||
+ { id: "editHeaderBtn", icon: "mdi:format-header-1", tag: "# " },
|
||
+ { id: "editListBtn", icon: "mdi:format-list-bulleted", tag: "- " },
|
||
+ { id: "editQuoteBtn", icon: "mdi:format-quote-close", tag: "> " },
|
||
+ { id: "editCodeBtn", icon: "mdi:code-tags", tag: "`" },
|
||
+ { id: "editLinkBtn", icon: "mdi:link", tag: "[Текст ссылки](URL)" },
|
||
];
|
||
|
||
markdownButtons.forEach((button) => {
|
||
const btn = document.createElement("button");
|
||
btn.classList.add("btnMarkdown");
|
||
btn.id = button.id;
|
||
- btn.innerHTML = `<i class="${button.icon}"></i>`;
|
||
+ btn.innerHTML = `<span class="iconify" data-icon="${button.icon}"></span>`;
|
||
markdownButtonsContainer.appendChild(btn);
|
||
});
|
||
|
||
@@ -571,7 +661,7 @@ async function loadUserInfo() {
|
||
);
|
||
|
||
if (usernameDisplay) {
|
||
- usernameDisplay.textContent = `👤 ${user.username}`;
|
||
+ usernameDisplay.innerHTML = `<span class="iconify" data-icon="mdi:account"></span> ${user.username}`;
|
||
|
||
// Делаем ник кликабельным для перехода в личный кабинет
|
||
usernameDisplay.style.cursor = "pointer";
|
||
@@ -580,16 +670,9 @@ async function loadUserInfo() {
|
||
});
|
||
}
|
||
|
||
- // Отображаем аватарку, если она есть
|
||
- if (user.avatar && userAvatar && userAvatarContainer) {
|
||
- userAvatar.src = user.avatar;
|
||
- userAvatarContainer.style.display = "inline-block";
|
||
-
|
||
- // Аватарка также кликабельна
|
||
- userAvatarContainer.style.cursor = "pointer";
|
||
- userAvatarContainer.addEventListener("click", function () {
|
||
- window.location.href = "/profile";
|
||
- });
|
||
+ // Аватарка скрыта на странице заметок
|
||
+ if (userAvatarContainer) {
|
||
+ userAvatarContainer.style.display = "none";
|
||
}
|
||
}
|
||
} catch (error) {
|
||
@@ -776,6 +859,10 @@ function updateFilterIndicator() {
|
||
|
||
const filters = [];
|
||
|
||
+ if (searchQuery) {
|
||
+ filters.push(`Поиск: "${searchQuery}"`);
|
||
+ }
|
||
+
|
||
if (selectedDateFilter) {
|
||
filters.push(`Дата: ${selectedDateFilter}`);
|
||
}
|
||
@@ -804,6 +891,21 @@ function updateFilterIndicator() {
|
||
window.clearFilter = function () {
|
||
selectedDateFilter = null;
|
||
selectedTagFilter = null;
|
||
+ searchQuery = "";
|
||
+ searchResults = [];
|
||
+
|
||
+ // Очищаем поле поиска
|
||
+ const searchInput = document.getElementById("searchInput");
|
||
+ if (searchInput) {
|
||
+ searchInput.value = "";
|
||
+ }
|
||
+
|
||
+ // Скрываем кнопку очистки поиска
|
||
+ const clearSearchBtn = document.getElementById("clearSearchBtn");
|
||
+ if (clearSearchBtn) {
|
||
+ clearSearchBtn.style.display = "none";
|
||
+ }
|
||
+
|
||
renderNotes(allNotes);
|
||
renderCalendar();
|
||
renderTags();
|
||
@@ -831,4 +933,57 @@ if (nextMonthBtn) {
|
||
// Инициализируем календарь при загрузке страницы
|
||
document.addEventListener("DOMContentLoaded", function () {
|
||
renderCalendar();
|
||
+
|
||
+ // Инициализируем поиск
|
||
+ initSearch();
|
||
});
|
||
+
|
||
+// Функция для инициализации поиска
|
||
+function initSearch() {
|
||
+ const searchInput = document.getElementById("searchInput");
|
||
+ const clearSearchBtn = document.getElementById("clearSearchBtn");
|
||
+
|
||
+ if (!searchInput || !clearSearchBtn) return;
|
||
+
|
||
+ // Обработчик ввода в поле поиска с задержкой
|
||
+ let searchTimeout;
|
||
+ searchInput.addEventListener("input", function () {
|
||
+ clearTimeout(searchTimeout);
|
||
+ const query = this.value;
|
||
+
|
||
+ // Показываем/скрываем кнопку очистки
|
||
+ if (query.trim()) {
|
||
+ clearSearchBtn.style.display = "block";
|
||
+ } else {
|
||
+ clearSearchBtn.style.display = "none";
|
||
+ }
|
||
+
|
||
+ // Задержка перед поиском для оптимизации
|
||
+ searchTimeout = setTimeout(() => {
|
||
+ searchNotes(query);
|
||
+ updateFilterIndicator();
|
||
+ }, 300);
|
||
+ });
|
||
+
|
||
+ // Обработчик клика на кнопку очистки поиска
|
||
+ clearSearchBtn.addEventListener("click", function () {
|
||
+ searchInput.value = "";
|
||
+ this.style.display = "none";
|
||
+ searchQuery = "";
|
||
+ searchResults = [];
|
||
+ renderNotes(allNotes);
|
||
+ updateFilterIndicator();
|
||
+ });
|
||
+
|
||
+ // Обработчик клавиши Escape для очистки поиска
|
||
+ searchInput.addEventListener("keydown", function (event) {
|
||
+ if (event.key === "Escape") {
|
||
+ this.value = "";
|
||
+ clearSearchBtn.style.display = "none";
|
||
+ searchQuery = "";
|
||
+ searchResults = [];
|
||
+ renderNotes(allNotes);
|
||
+ updateFilterIndicator();
|
||
+ }
|
||
+ });
|
||
+}
|
||
diff --git a/public/index.html b/public/index.html
|
||
index ae39215..bfa9bd7 100644
|
||
--- a/public/index.html
|
||
+++ b/public/index.html
|
||
@@ -5,14 +5,13 @@
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<title>Вход в систему заметок</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"
|
||
- />
|
||
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/iconify/2.0.0/iconify.min.js"></script>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
- <header>🔐 Вход в систему</header>
|
||
+ <header>
|
||
+ <span class="iconify" data-icon="mdi:login"></span> Вход в систему
|
||
+ </header>
|
||
<div class="login-form">
|
||
<form id="loginForm">
|
||
<div class="form-group">
|
||
diff --git a/public/notes.html b/public/notes.html
|
||
index b1a4c8c..f44e007 100644
|
||
--- a/public/notes.html
|
||
+++ b/public/notes.html
|
||
@@ -5,10 +5,7 @@
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<title>Заметки</title>
|
||
<link rel="stylesheet" href="/style.css?v=2" />
|
||
- <link
|
||
- rel="stylesheet"
|
||
- href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"
|
||
- />
|
||
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/iconify/2.0.0/iconify.min.js"></script>
|
||
</head>
|
||
<body>
|
||
<div class="container-leftside">
|
||
@@ -30,10 +27,36 @@
|
||
<div class="calendar-days" id="calendarDays"></div>
|
||
</div>
|
||
|
||
+ <!-- Секция поиска -->
|
||
+ <div class="search-section">
|
||
+ <div class="search-header">
|
||
+ <span class="search-title"
|
||
+ ><span class="iconify" data-icon="mdi:magnify"></span> Поиск</span
|
||
+ >
|
||
+ </div>
|
||
+ <div class="search-container">
|
||
+ <input
|
||
+ type="text"
|
||
+ id="searchInput"
|
||
+ placeholder="Поиск по заметкам..."
|
||
+ class="search-input"
|
||
+ />
|
||
+ <button
|
||
+ id="clearSearchBtn"
|
||
+ class="clear-search-btn"
|
||
+ style="display: none"
|
||
+ >
|
||
+ ✕
|
||
+ </button>
|
||
+ </div>
|
||
+ </div>
|
||
+
|
||
<!-- Секция тегов -->
|
||
<div class="tags-section">
|
||
<div class="tags-header">
|
||
- <span class="tags-title">🏷️ Теги</span>
|
||
+ <span class="tags-title"
|
||
+ ><span class="iconify" data-icon="mdi:tag"></span> Теги</span
|
||
+ >
|
||
</div>
|
||
<div class="tags-container" id="tagsContainer">
|
||
<!-- Теги будут добавлены динамически -->
|
||
@@ -44,7 +67,10 @@
|
||
<div class="container">
|
||
<header class="notes-header">
|
||
<div class="notes-header-left">
|
||
- <span>📝 Мои заметки</span>
|
||
+ <span
|
||
+ ><span class="iconify" data-icon="mdi:note-text"></span> Мои
|
||
+ заметки</span
|
||
+ >
|
||
<div
|
||
id="filter-indicator"
|
||
class="filter-indicator"
|
||
@@ -72,32 +98,34 @@
|
||
</div>
|
||
<span id="username-display" class="username-clickable"></span>
|
||
<form action="/logout" method="POST" style="display: inline">
|
||
- <button type="submit" class="logout-btn">🚪 Выйти</button>
|
||
+ <button type="submit" class="logout-btn">
|
||
+ <span class="iconify" data-icon="mdi:logout"></span> Выйти
|
||
+ </button>
|
||
</form>
|
||
</div>
|
||
</header>
|
||
<div class="main">
|
||
<div class="markdown-buttons">
|
||
- <button class="btnMarkdown" id="boldBtn">
|
||
- <i class="fas fa-bold"></i>
|
||
+ <button class="btnMarkdown" id="boldBtn" title="Жирный текст">
|
||
+ <span class="iconify" data-icon="mdi:format-bold"></span>
|
||
</button>
|
||
- <button class="btnMarkdown" id="italicBtn">
|
||
- <i class="fas fa-italic"></i>
|
||
+ <button class="btnMarkdown" id="italicBtn" title="Курсив">
|
||
+ <span class="iconify" data-icon="mdi:format-italic"></span>
|
||
</button>
|
||
- <button class="btnMarkdown" id="headerBtn">
|
||
- <i class="fas fa-heading"></i>
|
||
+ <button class="btnMarkdown" id="headerBtn" title="Заголовок">
|
||
+ <span class="iconify" data-icon="mdi:format-header-1"></span>
|
||
</button>
|
||
- <button class="btnMarkdown" id="listBtn">
|
||
- <i class="fas fa-list-ul"></i>
|
||
+ <button class="btnMarkdown" id="listBtn" title="Список">
|
||
+ <span class="iconify" data-icon="mdi:format-list-bulleted"></span>
|
||
</button>
|
||
- <button class="btnMarkdown" id="quoteBtn">
|
||
- <i class="fas fa-quote-right"></i>
|
||
+ <button class="btnMarkdown" id="quoteBtn" title="Цитата">
|
||
+ <span class="iconify" data-icon="mdi:format-quote-close"></span>
|
||
</button>
|
||
- <button class="btnMarkdown" id="codeBtn">
|
||
- <i class="fas fa-code"></i>
|
||
+ <button class="btnMarkdown" id="codeBtn" title="Код">
|
||
+ <span class="iconify" data-icon="mdi:code-tags"></span>
|
||
</button>
|
||
- <button class="btnMarkdown" id="linkBtn">
|
||
- <i class="fas fa-link"></i>
|
||
+ <button class="btnMarkdown" id="linkBtn" title="Ссылка">
|
||
+ <span class="iconify" data-icon="mdi:link"></span>
|
||
</button>
|
||
</div>
|
||
|
||
@@ -120,5 +148,19 @@
|
||
</div>
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/11.1.0/marked.min.js"></script>
|
||
<script src="/app.js"></script>
|
||
+ <script>
|
||
+ // Проверяем загрузку Iconify
|
||
+ document.addEventListener("DOMContentLoaded", function () {
|
||
+ if (typeof Iconify === "undefined") {
|
||
+ console.warn(
|
||
+ "Iconify не загружен, загружаем альтернативную версию..."
|
||
+ );
|
||
+ const script = document.createElement("script");
|
||
+ script.src =
|
||
+ "https://cdnjs.cloudflare.com/ajax/libs/iconify/2.0.0/iconify.min.js";
|
||
+ document.head.appendChild(script);
|
||
+ }
|
||
+ });
|
||
+ </script>
|
||
</body>
|
||
</html>
|
||
diff --git a/public/profile.html b/public/profile.html
|
||
index d7ddb49..6b92616 100644
|
||
--- a/public/profile.html
|
||
+++ b/public/profile.html
|
||
@@ -5,19 +5,21 @@
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<title>Личный кабинет</title>
|
||
<link rel="stylesheet" href="/style.css?v=3" />
|
||
- <link
|
||
- rel="stylesheet"
|
||
- href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"
|
||
- />
|
||
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/iconify/2.0.0/iconify.min.js"></script>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<header class="notes-header">
|
||
- <span>👤 Личный кабинет</span>
|
||
+ <span
|
||
+ ><span class="iconify" data-icon="mdi:account"></span> Личный
|
||
+ кабинет</span
|
||
+ >
|
||
<div class="user-info">
|
||
<a href="/notes" class="back-btn">← Назад к заметкам</a>
|
||
<form action="/logout" method="POST" style="display: inline">
|
||
- <button type="submit" class="logout-btn">🚪 Выйти</button>
|
||
+ <button type="submit" class="logout-btn">
|
||
+ <span class="iconify" data-icon="mdi:logout"></span> Выйти
|
||
+ </button>
|
||
</form>
|
||
</div>
|
||
</header>
|
||
@@ -34,12 +36,13 @@
|
||
style="display: none"
|
||
/>
|
||
<div id="avatarPlaceholder" class="avatar-placeholder">
|
||
- <i class="fas fa-user"></i>
|
||
+ <span class="iconify" data-icon="mdi:account"></span>
|
||
</div>
|
||
</div>
|
||
<div class="avatar-buttons">
|
||
<label for="avatarInput" class="btn-upload">
|
||
- <i class="fas fa-upload"></i> Загрузить аватар
|
||
+ <span class="iconify" data-icon="mdi:upload"></span> Загрузить
|
||
+ аватар
|
||
</label>
|
||
<input
|
||
type="file"
|
||
@@ -52,7 +55,7 @@
|
||
class="btn-delete"
|
||
style="display: none"
|
||
>
|
||
- <i class="fas fa-trash"></i> Удалить
|
||
+ <span class="iconify" data-icon="mdi:delete"></span> Удалить
|
||
</button>
|
||
</div>
|
||
<p class="avatar-hint">
|
||
diff --git a/public/register.html b/public/register.html
|
||
index c0fb230..f3ebb8c 100644
|
||
--- a/public/register.html
|
||
+++ b/public/register.html
|
||
@@ -5,14 +5,13 @@
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<title>Регистрация</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"
|
||
- />
|
||
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/iconify/2.0.0/iconify.min.js"></script>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
- <header>📝 Регистрация</header>
|
||
+ <header>
|
||
+ <span class="iconify" data-icon="mdi:account-plus"></span> Регистрация
|
||
+ </header>
|
||
<div class="login-form">
|
||
<form id="registerForm">
|
||
<div class="form-group">
|
||
diff --git a/public/style.css b/public/style.css
|
||
index d674180..a61ce1f 100644
|
||
--- a/public/style.css
|
||
+++ b/public/style.css
|
||
@@ -10,6 +10,108 @@ body {
|
||
padding: 0 15px;
|
||
}
|
||
|
||
+/* Стили для Iconify иконок */
|
||
+.iconify {
|
||
+ font-size: 16px;
|
||
+ vertical-align: middle;
|
||
+ display: inline-block;
|
||
+ width: 1em;
|
||
+ height: 1em;
|
||
+}
|
||
+
|
||
+iconify-icon {
|
||
+ font-size: 16px;
|
||
+ vertical-align: middle;
|
||
+ display: inline-block;
|
||
+ width: 1em;
|
||
+ height: 1em;
|
||
+}
|
||
+
|
||
+/* Стили для иконок в заголовках */
|
||
+header .iconify {
|
||
+ font-size: 20px;
|
||
+ margin-right: 8px;
|
||
+}
|
||
+
|
||
+/* Стили для иконок в кнопках */
|
||
+.logout-btn .iconify {
|
||
+ font-size: 14px;
|
||
+ margin-right: 6px;
|
||
+}
|
||
+
|
||
+/* Стили для иконок в секциях */
|
||
+.search-title .iconify,
|
||
+.tags-title .iconify {
|
||
+ font-size: 14px;
|
||
+ margin-right: 6px;
|
||
+}
|
||
+
|
||
+/* Цветные иконки */
|
||
+/* Иконка поиска - синий */
|
||
+.search-title .iconify[data-icon="mdi:magnify"] {
|
||
+ color: #2196f3;
|
||
+}
|
||
+
|
||
+/* Иконка тегов - зеленый */
|
||
+.tags-title .iconify[data-icon="mdi:tag"] {
|
||
+ color: #4caf50;
|
||
+}
|
||
+
|
||
+/* Иконка заметок - оранжевый */
|
||
+header .iconify[data-icon="mdi:note-text"] {
|
||
+ color: #ff9800;
|
||
+}
|
||
+
|
||
+/* Иконка пользователя - фиолетовый */
|
||
+header .iconify[data-icon="mdi:account"],
|
||
+.username-clickable .iconify[data-icon="mdi:account"] {
|
||
+ color: #9c27b0;
|
||
+}
|
||
+
|
||
+/* Иконка выхода - красный */
|
||
+.logout-btn .iconify[data-icon="mdi:logout"] {
|
||
+ color: #f44336;
|
||
+}
|
||
+
|
||
+/* Иконка входа - синий */
|
||
+header .iconify[data-icon="mdi:login"] {
|
||
+ color: #2196f3;
|
||
+}
|
||
+
|
||
+/* Иконка регистрации - зеленый */
|
||
+header .iconify[data-icon="mdi:account-plus"] {
|
||
+ color: #4caf50;
|
||
+}
|
||
+
|
||
+/* Markdown кнопки - разные цвета */
|
||
+.btnMarkdown .iconify[data-icon="mdi:format-bold"] {
|
||
+ color: #424242;
|
||
+}
|
||
+
|
||
+.btnMarkdown .iconify[data-icon="mdi:format-italic"] {
|
||
+ color: #757575;
|
||
+}
|
||
+
|
||
+.btnMarkdown .iconify[data-icon="mdi:format-header-1"] {
|
||
+ color: #1976d2;
|
||
+}
|
||
+
|
||
+.btnMarkdown .iconify[data-icon="mdi:format-list-bulleted"] {
|
||
+ color: #388e3c;
|
||
+}
|
||
+
|
||
+.btnMarkdown .iconify[data-icon="mdi:format-quote-close"] {
|
||
+ color: #f57c00;
|
||
+}
|
||
+
|
||
+.btnMarkdown .iconify[data-icon="mdi:code-tags"] {
|
||
+ color: #7b1fa2;
|
||
+}
|
||
+
|
||
+.btnMarkdown .iconify[data-icon="mdi:link"] {
|
||
+ color: #0288d1;
|
||
+}
|
||
+
|
||
header {
|
||
font-size: 20px;
|
||
font-weight: bold;
|
||
@@ -28,6 +130,66 @@ header {
|
||
align-items: flex-start;
|
||
}
|
||
|
||
+/* Стили для секции поиска в левой панели */
|
||
+.search-section {
|
||
+ margin-top: 15px;
|
||
+ padding-top: 15px;
|
||
+ border-top: 1px solid #e0e0e0;
|
||
+}
|
||
+
|
||
+.search-header {
|
||
+ margin-bottom: 10px;
|
||
+}
|
||
+
|
||
+.search-title {
|
||
+ font-size: 12px;
|
||
+ font-weight: bold;
|
||
+ color: #333;
|
||
+}
|
||
+
|
||
+.search-container {
|
||
+ position: relative;
|
||
+ width: 100%;
|
||
+}
|
||
+
|
||
+.search-input {
|
||
+ width: 100%;
|
||
+ padding: 6px 30px 6px 10px;
|
||
+ border: 1px solid #ddd;
|
||
+ border-radius: 15px;
|
||
+ font-size: 12px;
|
||
+ background-color: #f8f9fa;
|
||
+ transition: all 0.3s ease;
|
||
+ box-sizing: border-box;
|
||
+}
|
||
+
|
||
+.search-input:focus {
|
||
+ outline: none;
|
||
+ border-color: #007bff;
|
||
+ background-color: white;
|
||
+ box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
|
||
+}
|
||
+
|
||
+.clear-search-btn {
|
||
+ position: absolute;
|
||
+ right: 6px;
|
||
+ top: 50%;
|
||
+ transform: translateY(-50%);
|
||
+ background: none;
|
||
+ border: none;
|
||
+ color: #999;
|
||
+ cursor: pointer;
|
||
+ font-size: 14px;
|
||
+ padding: 2px 4px;
|
||
+ border-radius: 50%;
|
||
+ transition: all 0.2s ease;
|
||
+}
|
||
+
|
||
+.clear-search-btn:hover {
|
||
+ background-color: #e9ecef;
|
||
+ color: #666;
|
||
+}
|
||
+
|
||
.filter-indicator {
|
||
display: inline-block;
|
||
margin-top: 5px;
|
||
@@ -341,6 +503,9 @@ textarea:focus {
|
||
|
||
.avatar-wrapper {
|
||
margin-bottom: 15px;
|
||
+ display: flex;
|
||
+ justify-content: center;
|
||
+ align-items: center;
|
||
}
|
||
|
||
.avatar-preview {
|
||
@@ -678,3 +843,16 @@ textarea:focus {
|
||
transform: translateY(-1px);
|
||
box-shadow: 0 2px 4px rgba(0, 123, 255, 0.3);
|
||
}
|
||
+
|
||
+/* Стили для подсветки результатов поиска */
|
||
+.search-highlight {
|
||
+ background-color: #fff3cd;
|
||
+ padding: 1px 2px;
|
||
+ border-radius: 2px;
|
||
+ font-weight: 500;
|
||
+}
|
||
+
|
||
+.search-highlight.current {
|
||
+ background-color: #ffc107;
|
||
+ color: #000;
|
||
+}
|
||
diff --git a/server.js b/server.js
|
||
index 550897d..71f62fd 100644
|
||
--- a/server.js
|
||
+++ b/server.js
|
||
@@ -68,6 +68,12 @@ app.use(
|
||
styleSrc: ["'self'", "'unsafe-inline'", "https://cdnjs.cloudflare.com"],
|
||
fontSrc: ["'self'", "https://cdnjs.cloudflare.com", "data:"],
|
||
imgSrc: ["'self'", "data:", "blob:"],
|
||
+ connectSrc: [
|
||
+ "'self'",
|
||
+ "https://api.iconify.design",
|
||
+ "https://api.simplesvg.com",
|
||
+ "https://api.unisvg.com",
|
||
+ ],
|
||
},
|
||
},
|
||
})
|
||
@@ -305,6 +311,42 @@ app.get("/notes", requireAuth, (req, res) => {
|
||
res.sendFile(path.join(__dirname, "public", "notes.html"));
|
||
});
|
||
|
||
+// API для поиска заметок (должен быть ПЕРЕД /api/notes/:id)
|
||
+app.get("/api/notes/search", requireAuth, (req, res) => {
|
||
+ const { q, tag, date } = req.query;
|
||
+
|
||
+ let sql = "SELECT * FROM notes WHERE user_id = ?";
|
||
+ let params = [req.session.userId];
|
||
+
|
||
+ // Поиск по тексту
|
||
+ if (q && q.trim()) {
|
||
+ sql += " AND content LIKE ?";
|
||
+ params.push(`%${q.trim()}%`);
|
||
+ }
|
||
+
|
||
+ // Поиск по тегу
|
||
+ if (tag && tag.trim()) {
|
||
+ sql += " AND content LIKE ?";
|
||
+ params.push(`%#${tag.trim()}%`);
|
||
+ }
|
||
+
|
||
+ // Поиск по дате
|
||
+ if (date && date.trim()) {
|
||
+ sql += " AND date = ?";
|
||
+ params.push(date.trim());
|
||
+ }
|
||
+
|
||
+ sql += " ORDER BY created_at DESC";
|
||
+
|
||
+ db.all(sql, params, (err, rows) => {
|
||
+ if (err) {
|
||
+ console.error("Ошибка поиска заметок:", err.message);
|
||
+ return res.status(500).json({ error: "Ошибка сервера" });
|
||
+ }
|
||
+ res.json(rows);
|
||
+ });
|
||
+});
|
||
+
|
||
// API для получения всех заметок
|
||
app.get("/api/notes", requireAuth, (req, res) => {
|
||
const sql = "SELECT * FROM notes WHERE user_id = ? ORDER BY created_at ASC";
|
||
diff --git a/style.css b/style.css
|
||
index 9da575e..d2dd926 100644
|
||
--- a/style.css
|
||
+++ b/style.css
|
||
@@ -8,6 +8,75 @@ body {
|
||
background: #f5f5f5;
|
||
}
|
||
|
||
+/* Стили для Iconify иконок */
|
||
+.iconify {
|
||
+ font-size: 16px;
|
||
+ vertical-align: middle;
|
||
+ display: inline-block;
|
||
+ width: 1em;
|
||
+ height: 1em;
|
||
+}
|
||
+
|
||
+iconify-icon {
|
||
+ font-size: 16px;
|
||
+ vertical-align: middle;
|
||
+ display: inline-block;
|
||
+ width: 1em;
|
||
+ height: 1em;
|
||
+}
|
||
+
|
||
+/* Стили для иконок в заголовках */
|
||
+header .iconify {
|
||
+ font-size: 20px;
|
||
+ margin-right: 8px;
|
||
+}
|
||
+
|
||
+/* Стили для иконок в кнопках */
|
||
+.logout-btn .iconify {
|
||
+ font-size: 14px;
|
||
+ margin-right: 6px;
|
||
+}
|
||
+
|
||
+/* Цветные иконки */
|
||
+/* Иконка входа - синий */
|
||
+header .iconify[data-icon="mdi:login"] {
|
||
+ color: #2196f3;
|
||
+}
|
||
+
|
||
+/* Иконка регистрации - зеленый */
|
||
+header .iconify[data-icon="mdi:account-plus"] {
|
||
+ color: #4caf50;
|
||
+}
|
||
+
|
||
+/* Markdown кнопки - разные цвета */
|
||
+.btnMarkdown .iconify[data-icon="mdi:format-bold"] {
|
||
+ color: #424242;
|
||
+}
|
||
+
|
||
+.btnMarkdown .iconify[data-icon="mdi:format-italic"] {
|
||
+ color: #757575;
|
||
+}
|
||
+
|
||
+.btnMarkdown .iconify[data-icon="mdi:format-header-1"] {
|
||
+ color: #1976d2;
|
||
+}
|
||
+
|
||
+.btnMarkdown .iconify[data-icon="mdi:format-list-bulleted"] {
|
||
+ color: #388e3c;
|
||
+}
|
||
+
|
||
+.btnMarkdown .iconify[data-icon="mdi:format-quote-close"] {
|
||
+ color: #f57c00;
|
||
+}
|
||
+
|
||
+.btnMarkdown .iconify[data-icon="mdi:code-tags"] {
|
||
+ color: #7b1fa2;
|
||
+}
|
||
+
|
||
+.btnMarkdown .iconify[data-icon="mdi:link"] {
|
||
+ color: #0288d1;
|
||
+}
|
||
+
|
||
header {
|
||
font-size: 20px;
|
||
font-weight: bold;
|
||
--
|
||
2.51.0
|
||
|